
Ein modernes und elegantes Dashboard zur Visualisierung und Analyse von Netzwerkverkehr.
Neko Master
Sehen Sie Ihren Netzwerkverkehr klar.
Echtzeit-Überwachung · Verkehrsprüfung · Multi-Gateway-Unterstützung
English | 中文
[!IMPORTANT] Haftungsausschluss
Dieses Projekt ist ein Werkzeug zur Verkehrsanalyse und Visualisierung für lokale Gateway-Umgebungen.
Es bietet keinen Netzwerkzugangsdienst, kein Proxy-Abonnement und keine netzwerkübergreifende Konnektivität. Alle Daten werden aus der eigenen Netzwerkumgebung des Nutzers gesammelt.
Dieses Projekt ist unter der MIT-Lizenz quelloffen. Wir übernehmen keine Verantwortung für jegliche Konsequenzen, die sich aus der Nutzung dieser Software ergeben. Bitte verwenden Sie sie in Übereinstimmung mit den geltenden Gesetzen und Vorschriften.
Neko (ねこ) bedeutet Katze auf Japanisch. Ausgesprochen /ˈneɪkoʊ/ (NEH-ko).
Wie eine Katze beobachtet Neko Master den Netzwerkverkehr ruhig und präzise. Es ist ein leichtgewichtiges Analyse-Dashboard, das für moderne Gateway-Umgebungen entwickelt wurde.
Die im Repository integrierte
docker-compose.ymlmappt standardmäßig3000/3001/3002. Die Szenarien A/B unten sind minimale Vorlagen für gängige Bereitstellungen.
services: neko-master: image: foru17/neko-master:latest container_name: neko-master restart: unless-stopped ports: - "3000:3000" # Web UI volumes: - ./data:/app/data # Local MMDB (optional, files should be downloaded into ./geoip) - ./geoip:/app/data/geoip:ro environment: - NODE_ENV=production - DB_PATH=/app/data/stats.db - COOKIE_SECRET=${COOKIE_SECRET}
> Empfohlen in `.env` (gleiches Verzeichnis wie `docker-compose.yml`):
> `COOKIE_SECRET=<mindestens 32-Byte-Zufallszeichenkette>` (generieren mit `openssl rand -hex 32`)
> Dieser Modus ist vollständig upgrade-kompatibel und funktioniert sofort einsatzbereit.
> Wenn WS nicht geroutet wird, fällt die App automatisch auf HTTP-Polling zurück.
#### Szenario B: Echtzeit-WebSocket (empfohlen mit Reverse-Proxy)```yaml
services:
neko-master:
image: foru17/neko-master:latest
container_name: neko-master
restart: unless-stopped
ports:
- "3000:3000" # Web UI
- "3002:3002" # WebSocket (for Nginx / Tunnel forwarding)
volumes:
- ./data:/app/data
# Local MMDB (optional, files should be downloaded into ./geoip)
- ./geoip:/app/data/geoip:ro
environment:
- NODE_ENV=production
- DB_PATH=/app/data/stats.db
- COOKIE_SECRET=${COOKIE_SECRET}
Dann führe aus:```bash docker compose up -d
Öffne <http://localhost:3000>, um zu starten.
Wenn du die im Repository enthaltene Compose-Datei verwendest (Standard `3000/3001/3002`), führe denselben Befehl aus.
### Option 2: Docker Run```bash
# Generate a fixed cookie secret first (for session persistence)
export COOKIE_SECRET="$(openssl rand -hex 32)"
git clone https://github.com/soth-ai/soth.git
cd soth
cargo build --release
The compiled binary will be available at target/release/soth.
cargo install soth-cli
docker pull sothai/soth:latest
docker run -it --rm -p 8080:8080 -p 8443:8443 sothai/soth:latest
soth cert generate --ca --output ./certs
This creates ca.crt and ca.key in the ./certs directory.
soth proxy start --port 8080 --ca-cert ./certs/ca.crt --ca-key ./certs/ca.key
Set your HTTP proxy to http://localhost:8080 and install ca.crt as a trusted root certificate.
soth rule add --name "block-ads" --pattern "*.doubleclick.net" --action block
Soth is configured via a soth.toml file. Below is a complete example:
[proxy]
listen = "0.0.0.0:8080"
tls_listen = "0.0.0.0:8443"
ca_cert = "./certs/ca.crt"
ca_key = "./certs/ca.key"
[proxy.upstream]
timeout = 30
max_connections = 1000
[logging]
level = "info"
format = "json"
output = "./logs/soth.log"
[rules]
directory = "./rules"
hot_reload = true
[store]
backend = "sqlite"
path = "./data/soth.db"
[observe]
metrics_enabled = true
metrics_port = 9090
tracing_enabled = true
Rules define how Soth handles intercepted traffic. Each rule consists of a matcher and one or more actions.
name: "block-ads"
description: "Block known advertising domains"
enabled: true
priority: 100
match:
host:
- "*.doubleclick.net"
- "*.googlesyndication.com"
method:
- GET
- POST
action:
type: block
status: 403
body: "Blocked by Soth"
Rules are evaluated in order of priority (highest first). The first matching rule wins. If no rule matches, the request is allowed by default.
soth cert generate --ca --output ./certs --common-name "Soth CA" --validity 3650
soth cert generate --host "example.com" --ca-cert ./certs/ca.crt --ca-key ./certs/ca.key --output ./certs
soth cert list --directory ./certs
soth cert revoke --serial "1234567890" --ca-cert ./certs/ca.crt --ca-key ./certs/ca.key
Soth exposes Prometheus metrics on the configured metrics port (default 9090).
Soth supports distributed tracing via OpenTelemetry. Configure the OTLP endpoint:
[observe]
tracing_enabled = true
otlp_endpoint = "http://localhost:4317"
Logs are emitted in JSON or text format. Example JSON log entry:
{
"timestamp": "2024-01-15T10:30:00Z",
"level": "info",
"message": "Request intercepted",
"method": "GET",
"host": "example.com",
"path": "/api/users",
"status": 200,
"duration_ms": 45
}
The Soth SDK allows you to build custom rules and plugins in Rust.
use soth_sdk::{Rule, Request, Action, Result};
pub struct BlockUserAgent;
impl Rule for BlockUserAgent {
fn name(&self) -> &str {
"block-user-agent"
}
fn matches(&self, req: &Request) -> bool {
req.headers
.get("user-agent")
.map(|ua| ua.contains("curl"))
.unwrap_or(false)
}
fn action(&self) -> Action {
Action::Block {
status: 403,
body: Some("Blocked by Soth SDK".to_string()),
}
}
}
use soth_sdk::{Plugin, Context, Result};
pub struct MyPlugin;
#[async_trait::async_trait]
impl Plugin for MyPlugin {
async fn on_request(&self, ctx: &mut Context) -> Result<()> {
ctx.log_info("Processing request");
Ok(())
}
async fn on_response(&self, ctx: &mut Context) -> Result<()> {
ctx.log_info("Processing response");
Ok(())
}
}
Soth is built as a modular system of crates:
┌─────────────────────────────────────────┐
│ soth-cli │
│ (Command-line interface) │
└─────────────────┬───────────────────────┘
│
┌─────────────────▼───────────────────────┐
│ soth-proxy │
│ (Proxy server binary) │
└─────────────────┬───────────────────────┘
│
┌─────────────────▼───────────────────────┐
│ soth-mitm │
│ (MITM proxy library) │
└─────────────────┬───────────────────────┘
│
┌─────────────────▼───────────────────────┐
│ soth-core │
│ (Core types and traits) │
└─────────────────────────────────────────┘
Contributions are welcome! Please read the contributing guide before submitting a pull request.
git clone https://github.com/soth-ai/soth.git
cd soth
cargo build
cargo test
cargo test --all-features
Soth uses rustfmt and clippy. Run the following before committing:
cargo fmt --all
cargo clippy --all-targets --all-features -- -D warnings
Soth is released under the MIT License.
Soth is intended for legitimate security testing, research, and educational purposes only. Users are responsible for complying with all applicable laws and regulations. The authors assume no liability for misuse of this software.```bash
docker run -d
--name neko-master
-p 3000:3000
-v $(pwd)/data:/app/data
-e COOKIE_SECRET="$COOKIE_SECRET"
--restart unless-stopped
foru17/neko-master:latest
docker run -d
--name neko-master
-p 3000:3000
-p 3002:3002
-v $(pwd)/data:/app/data
-e COOKIE_SECRET="$COOKIE_SECRET"
--restart unless-stopped
foru17/neko-master:latest
Öffne <http://localhost:3000>, um zu starten.
> Das Frontend verwendet standardmäßig `/api` mit gleichem Ursprung, daher ist Port 3001 extern normalerweise nicht erforderlich.
> Für Echtzeit-WS muss dein Reverse-Proxy/Tunnel Port `3002` erreichen können. Falls nicht, fällt die App auf ~5s HTTP-Polling zurück.
> Bei `docker run` ändere die externen Ports direkt über `-p`-Mappings.
> Nur wenn du direkten WS-Zugriff verwendest (kein Reverse-Proxy) und der externe WS-Port nicht `3002` ist, übergib zusätzlich `-e WS_EXTERNAL_PORT=<external-ws-port>`.
>
> Lokaler MMDB-Lookup-Modus (optional): mounte `-v $(pwd)/geoip:/app/data/geoip:ro`,
> wechsle dann die Quelle auf Local in `Settings -> Preferences -> IP Lookup Source`.
### Option 3: Ein-Klick-Skript
Erkennt automatisch Portkonflikte und konfiguriert alles:```bash
# Using curl
curl -fsSL https://raw.githubusercontent.com/foru17/neko-master/main/setup.sh | bash
# Or using wget
wget -qO- https://raw.githubusercontent.com/foru17/neko-master/main/setup.sh | bash
Das Skript wird automatisch:
docker-compose.yml herunterladengit clone https://github.com/foru17/neko-master.git cd neko-master
pnpm install
cp apps/collector/.env.example apps/collector/.env
pnpm dev
Öffne <http://localhost:3000> zur Konfiguration.
> Im Quellmodus: Der Collector lauscht auf `3001/3002`, das Web lauscht standardmäßig auf `3000`.
> Wenn du `API_PORT` geändert hast (nicht 3001), setze `API_URL` entsprechend (zum Beispiel `API_URL=http://localhost:4001`), damit das Web-`/api`-Rewrite auf die korrekte API zeigt.
> `apps/collector/.env.local` hat Vorrang vor `apps/collector/.env`.
## 🤖 Agent-Bereitstellung
Verwende den Agent-Modus, wenn du einen zentralisierten Neko Master-Dienst und mehrere entfernte Geräte (OpenWrt, Linux, macOS) möchtest, die lokale Gateway-Daten sammeln. Der Agent läuft in der Nähe des Gateways, ruft Daten ab und meldet sie an das Panel — das Panel verbindet sich nie direkt mit dem Gateway.
Unterstützte Gateway-Typen: **Clash / Mihomo** (WebSocket-Echtzeit) und **Surge v5+** (HTTP-Polling).
### Schnellinstallation (UI-generierter Befehl)
1. Gehe im Dashboard zu `Settings → Backends`, füge ein `Agent`-Backend hinzu, wähle den Gateway-Typ aus
2. Klicke auf **"View Agent Script"** und kopiere den einzeiligen Installationsbefehl, führe ihn dann auf dem Zielhost aus:```bash
# Clash / Mihomo gateway example
curl -fsSL https://raw.githubusercontent.com/foru17/neko-master/main/apps/agent/install.sh \
| env NEKO_SERVER='http://your-panel:3000' \
NEKO_BACKEND_ID='1' \
NEKO_BACKEND_TOKEN='ag_xxx' \
NEKO_GATEWAY_TYPE='clash' \
NEKO_GATEWAY_URL='http://127.0.0.1:9090' \
sh
# Surge gateway example
curl -fsSL https://raw.githubusercontent.com/foru17/neko-master/main/apps/agent/install.sh \
| env NEKO_SERVER='http://your-panel:3000' \
NEKO_BACKEND_ID='2' \
NEKO_BACKEND_TOKEN='ag_yyy' \
NEKO_GATEWAY_TYPE='surge' \
NEKO_GATEWAY_URL='http://127.0.0.1:9091' \
sh
Nach der Installation verwaltest du Instanzen mit nekoagent:```bash
nekoagent list # list all instances
nekoagent status # check running state
nekoagent logs # tail live logs
nekoagent restart # restart
nekoagent upgrade # global upgrade (CLI + binary)
> Das Skript erkennt automatisch eine vorhandene Installation — wenn `neko-agent` bereits vorhanden ist, wird nur die neue Instanz hinzugefügt, ohne erneut herunterzuladen.
> Mehrere Instanzen können auf demselben Host ausgeführt werden (unterschiedlicher `NEKO_INSTANCE_NAME`), die jeweils auf ein anderes Gateway verweisen.
### Agent-Dokumentation
- [Übersicht](https://github.com/foru17/neko-master/blob/main/docs/agent/overview.en.md): Architektur, Vergleich Direct vs. Agent, Sicherheitsmodell
- [Schnellstart](https://github.com/foru17/neko-master/blob/main/docs/agent/quick-start.en.md): End-to-End-Einrichtung von der UI bis zum laufenden Agent
- [Installationsanleitung](https://github.com/foru17/neko-master/blob/main/docs/agent/install.en.md): Installationsmethoden, systemd / launchd Autostart
- [Konfiguration](https://github.com/foru17/neko-master/blob/main/docs/agent/config.en.md): vollständige Referenz zu Flags und Umgebungsvariablen
- [Release-Ablauf](https://github.com/foru17/neko-master/blob/main/docs/agent/release.en.md): Versionierung und Kompatibilitätsrichtlinie
- [Fehlerbehebung](https://github.com/foru17/neko-master/blob/main/docs/agent/troubleshooting.en.md): häufige Fehler und Lösungen
## 📖 Erste Verwendung

### Clash / Mihomo verbinden
1. Öffne <http://localhost:3000>
2. Beim ersten Besuch erscheint der Dialog **Gateway-Konfiguration**
3. Gib die Verbindungsinformationen für dein Netzwerk-Gateway (z. B. OpenClash) ein:
- **Name**: Benutzerdefinierter Name (z. B. „Home Gateway")
- **Typ**: Wähle `Clash / Mihomo`
- **Host**: Backend-Adresse des Gateways (z. B. `192.168.101.1`)
- **Port**: Backend-Port des Gateways (z. B. `9090`)
- **Token**: Ausfüllen, wenn Secret konfiguriert ist, andernfalls leer lassen
4. Klicke auf „Add Backend", um zu speichern
5. Das System beginnt automatisch mit dem Sammeln und Analysieren von Verkehrsdaten
> 💡 **Gateway-Adresse ermitteln**: Gehe zu deinem Gateway-Kontrollpanel (z. B. OpenClash) → Aktiviere „External Control" → Kopiere die API-Adresse
### Surge verbinden

Neko Master unterstützt die Verbindung mit Surge-Gateways für vollständige Regelketten-Visualisierung und Verkehrsanalyse.
#### 1. Surge HTTP API aktivieren
Aktiviere die HTTP-Remote-API in deiner Surge-Konfiguration:```ini
[General]
http-api = 127.0.0.1:9091
http-api-tls = false
http-api-web-dashboard = true
Konfiguration über die grafische Oberfläche von Surge:
Settings → General → HTTP Remote API9091Surge192.168.1.1 oder 127.0.0.1)9091)💡 Hinweis: Surge verwendet HTTP-Polling zum Abrufen von Daten (im Vergleich zum WebSocket-Echtzeitstream von Clash), mit einer Datenaktualisierungsverzögerung von etwa 2 Sekunden.
Wenn der Fehler "port already in use" angezeigt wird, gibt es folgende Lösungen:
Erstelle eine .env-Datei im selben Verzeichnis wie docker-compose.yml:```env
WEB_EXTERNAL_PORT=8080 # Change Web UI port
API_EXTERNAL_PORT=8081 # Change API port
WS_EXTERNAL_PORT=8082 # Change WebSocket external port (only for direct access)
COOKIE_SECRET=your-long-random-secret # Strongly recommended to keep fixed
Dann neu starten:```bash
docker compose down
docker compose up -d
Now access http://localhost:8080
ports:
> Hinweis: Wenn Sie direkten WS-Zugriff verwenden (kein Reverse-Proxy) und der externe WS-Port nicht `3002` ist, setzen Sie `WS_EXTERNAL_PORT=<external-ws-port>`.
### Lösung 3: Ein-Klick-Skript verwenden```bash
curl -fsSL https://raw.githubusercontent.com/foru17/neko-master/main/setup.sh | bash
Das Skript erkennt automatisch verfügbare Ports und schlägt sie vor.
runtime-config.API_URL → NEXT_PUBLIC_API_URL → Same-Origin /api/api serverseitiges Rewrite-Ziel: API_URL (Standard http://localhost:3001, angewendet in Next.js-Rewrites)runtime-config.WS_URL → NEXT_PUBLIC_WS_URL → automatische Kandidaten (wenn runtime-config.WS_PORT gesetzt ist, wird der direkte Port bevorzugt; andernfalls wird zuerst /_cm_ws versucht)runtime-config.WS_PORT (aus WS_EXTERNAL_PORT) → NEXT_PUBLIC_WS_PORT → 3002NODE_ENV=production DB_PATH=/app/data/stats.db COOKIE_SECRET=<at least 32-byte random string>
Verwende `openssl rand -hex 32`, um `COOKIE_SECRET` zu generieren.
Zusätzliche Empfehlungen:
1. Binde persistenten Speicher ein (zum Beispiel `./data:/app/data`), um Daten- und Secret-Verlust zu vermeiden.
2. Wenn du direkten WS-Zugriff verwendest und der externe WS-Port nicht `3002` ist, setze `WS_EXTERNAL_PORT` entsprechend.
3. Wenn sich der API-Port/die API-Adresse im Quell-Deployment ändert, aktualisiere auch `API_URL`.
4. Für lokale MMDB-Lookups binde `./geoip:/app/data/geoip:ro` ein und wechsle die Quelle unter `Settings -> Preferences -> IP Lookup Source`.
5. MMDB-Dateien sind groß und nicht im Image enthalten. Lade sie herunter und lege sie in `./geoip` mit festen Namen ab:
`GeoLite2-City.mmdb`, `GeoLite2-ASN.mmdb` (erforderlich) und `GeoLite2-Country.mmdb` (optional).
Empfohlene Quelle: <https://github.com/P3TERX/GeoLite.mmdb>.
> Erweiterte Agent-Details (Installation, Konfiguration, Release, Kompatibilität) werden unter `docs/agent/*` gepflegt.
## 🗄️ ClickHouse (Optional)
SQLite ist die Standard-Speicher-Engine von Neko Master und funktioniert gut für die meisten Benutzer.
Erwäge die Aktivierung von ClickHouse, wenn du Folgendes benötigst:
- Sehr große Datensätze (Hunderttausende von Domain-/IP-Einträgen)
- Schnelle Aggregationsabfragen über lange Zeiträume (≥ 7 Tage)
- Trennung von historischen Statistiken von der Konfigurations-/Metadaten-Speicherung
> ClickHouse ist vollständig optional. SQLite bleibt unabhängig davon, ob ClickHouse aktiviert ist, der Konfigurations- und Metadatenspeicher.
### Architekturübersicht
Wenn ClickHouse aktiviert ist, wechselt das System in den **Dual-Write-Modus**:```
BatchBuffer.flush()
│
├──→ SQLite (config / metadata, always written)
└──→ ClickHouse (stats traffic data, dual-write)
└── Buffer tables → SummingMergeTree async merge
Die Quelle für das Lesen wird durch STATS_QUERY_SOURCE gesteuert (Standard: sqlite).
Die im Repository integrierte docker-compose.yml enthält bereits einen ClickHouse-Dienst, der durch
profiles: [clickhouse] gesteuert wird, sodass er standardmäßig nicht startet. Führen Sie vom Repository-Stammverzeichnis aus Folgendes aus:```bash
docker compose --profile clickhouse up -d
> ClickHouse-Daten werden in `./data/clickhouse` persistiert, getrennt vom Haupt-Datenverzeichnis der App.
Wenn Sie eine **benutzerdefinierte `docker-compose.yml`** verwenden (wie in Szenario A/B oben), fügen Sie den ClickHouse-Serviceblock manuell hinzu:```yaml
services:
neko-master:
# ... your existing config ...
environment:
# append to existing environment section:
- CH_ENABLED=${CH_ENABLED:-0}
- CH_HOST=${CH_HOST:-clickhouse}
- CH_PORT=${CH_PORT:-8123}
- CH_DATABASE=${CH_DATABASE:-neko_master}
- CH_USER=${CH_USER:-neko}
- CH_PASSWORD=${CH_PASSWORD:-neko_master}
- CH_WRITE_ENABLED=${CH_WRITE_ENABLED:-0}
- STATS_QUERY_SOURCE=${STATS_QUERY_SOURCE:-sqlite}
networks:
- neko-master-network
clickhouse:
image: clickhouse/clickhouse-server:24.8
container_name: neko-master-clickhouse
restart: unless-stopped
profiles: ["clickhouse"]
ports:
- "${CH_EXTERNAL_HTTP_PORT:-8123}:8123"
- "${CH_EXTERNAL_NATIVE_PORT:-9000}:9000"
volumes:
- ./data/clickhouse:/var/lib/clickhouse
environment:
- CLICKHOUSE_DB=${CH_DATABASE:-neko_master}
- CLICKHOUSE_USER=${CH_USER:-neko}
- CLICKHOUSE_PASSWORD=${CH_PASSWORD:-neko_master}
- CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT=1
networks:
- neko-master-network
healthcheck:
test: ["CMD-SHELL", "wget -q --spider http://127.0.0.1:8123/ping || exit 1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
networks:
neko-master-network:
driver: bridge
Fügen Sie Folgendes zu Ihrer .env hinzu (im selben Verzeichnis wie docker-compose.yml):```env
CH_ENABLED=1
CH_WRITE_ENABLED=1
STATS_QUERY_SOURCE=auto
CH_HOST=clickhouse CH_PORT=8123 CH_DATABASE=neko_master CH_USER=neko CH_PASSWORD=neko_master
Neustart:```bash
docker compose --profile clickhouse up -d
Health & Fallback: Nach
CH_UNHEALTHY_THRESHOLDaufeinanderfolgenden Schreibfehlern markiert das System ClickHouse automatisch als fehlerhaft und setzt SQLite-Schreibvorgänge fort – selbst wennCH_ONLY_MODE=1gesetzt ist. Sobald sich ClickHouse erholt, wird es wieder als fehlerfrei markiert und protokolliert.
Upgrade von einer reinen SQLite-Version? Ihre Daten sind sicher. Die SQLite-Datei (
./data/stats.db) bleibt vollständig erhalten. Hier ist der empfohlene schrittweise Migrationspfad:
CH_ENABLED=1 CH_WRITE_ENABLED=1 STATS_QUERY_SOURCE=sqlite # Keep reading from SQLite while CH accumulates data
Starten Sie und beobachten Sie die `[ClickHouse Writer]`-Logs, um erfolgreiche Schreibvorgänge zu bestätigen.
#### Phase 2: Lesequelle wechseln```env
STATS_QUERY_SOURCE=auto # Smart routing: recent data from CH, historical from SQLite
# or
STATS_QUERY_SOURCE=clickhouse # Force all reads to ClickHouse
Um historische SQLite-Statistiken nach ClickHouse zu verschieben:```bash
./scripts/ch-migrate-docker.sh
./scripts/ch-migrate-docker.sh --append
./scripts/ch-migrate-docker.sh --from 2026-02-01T00:00:00Z --to 2026-02-20T00:00:00Z
#### Phase 4 (optional): Nur-CH-Modus
Sobald ClickHouse stabil läuft, stoppen Sie die SQLite-Statistik-Schreibvorgänge:```env
CH_ONLY_MODE=1
Selbst mit
CH_ONLY_MODE=1fällt das System automatisch auf SQLite-Schreibvorgänge zurück, wenn ClickHouse fehlerhaft wird – kein Datenverlust.
Sie können jederzeit vollständig zurückrollen:```env CH_ENABLED=0 CH_WRITE_ENABLED=0 CH_ONLY_MODE=0 STATS_QUERY_SOURCE=sqlite
Neustart, und alles kehrt in den reinen SQLite-Modus zurück. Historische Daten bleiben intakt.
---
## 🌐 Reverse Proxy & Tunnel
Empfohlener Ansatz: Web und WS unter derselben Domain belassen, mit Pfad-Routing:
`/` → `3000`, `/_cm_ws` → `3002`.
### Nginx Standardbeispiel```nginx
server {
listen 443 ssl http2;
server_name neko.example.com;
location / {
proxy_pass http://<neko-master-host>:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location ^~ /_cm_ws {
proxy_pass http://<neko-master-host>:3002;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 86400;
proxy_send_timeout 86400;
proxy_buffering off;
}
}
Optionale Env-Überschreibung:```env
### Cloudflare Tunnel Standardbeispiel
`~/.cloudflared/config.yml`:```yaml
tunnel: <your-tunnel-name-or-id>
credentials-file: /path/to/<credentials>.json
ingress:
- hostname: neko.example.com
path: /_cm_ws*
service: http://localhost:3002
- hostname: neko.example.com
path: /*
service: http://localhost:3000
- service: http_status:404
Ausführen:```bash cloudflared tunnel --config ~/.cloudflared/config.yml run
Für Zero Trust Dashboard-verwaltete Routen (Token-Modus) konfigurieren Sie dieselben zwei Routen und halten Sie `/_cm_ws*` über `/*`.
### Wichtige Hinweise
1. Verwenden Sie nicht `ws` (ohne führenden Schrägstrich) als WS-Pfad; dies kann zu einer Überübereinstimmung führen und `/_next/static/...` → `426 Upgrade Required` verursachen
2. Die WS-Route muss über dem Catch-all `/*` liegen
3. `NEXT_PUBLIC_WS_URL` ist standardmäßig optional; bei Anpassung Frontend/Container nach Änderungen neu starten
4. Die alleinige Zuordnung von `3000` funktioniert weiterhin, fällt jedoch auf HTTP-Polling (~5s) zurück, mit geringerer Echtzeit-Reaktionsfähigkeit
5. `beacon.min.js`-Fehler (Cloudflare-Analytics-Skript) stehen typischerweise nicht im Zusammenhang mit dem API-/WS-Datenfluss der App
6. In den meisten Setups ist keine zusätzliche `/api`-Reverse-Proxy-Regel erforderlich; das Frontend verwendet same-origin `/api` und die App übernimmt die interne Weiterleitung an `3001`
> Hinweis: `/_next/static/... 426 Upgrade Required` ist häufig in **fehlkonfigurierten Reverse-Proxy-/Tunnel**-Setups anzutreffen; es ist ungewöhnlich bei direktem lokalem Zugriff ohne Proxy.
### Multi-Architektur-Unterstützung
Docker-Images unterstützen sowohl `linux/amd64` als auch `linux/arm64`.
### Datenpersistenz
Daten werden in `/app/data` innerhalb des Containers gespeichert. Mounten Sie es auf den Host, um Datenverlust zu verhindern:```yaml
volumes:
- ./data:/app/data
docker compose pull docker compose up -d
## 🔐 Authentifizierung & Sicherheit
Neko Master unterstützt Zugriffsauthentifizierung zum Schutz der Dashboard-Daten.
### Produktions-Sicherheitsgrundlage
1. Setzen Sie ein festes `COOKIE_SECRET` (andernfalls können Sitzungen nach einem Neustart ungültig werden).
2. Lassen Sie `FORCE_ACCESS_CONTROL_OFF=true` im Normalbetrieb nicht aktiviert.
3. Verwenden Sie `SHOWCASE_SITE_MODE=true` nur für öffentliche Demo-Umgebungen (Schreibvorgänge sind eingeschränkt).
Beispiel:```env
COOKIE_SECRET=<at least 32-byte random string>
# FORCE_ACCESS_CONTROL_OFF=false
# SHOWCASE_SITE_MODE=false
Wenn Sie das Token vergessen haben, setzen Sie vorübergehend FORCE_ACCESS_CONTROL_OFF=true, um den Notfallmodus zu aktivieren.
docker-compose.yml hinzu: ```yaml
environment:
3000:3000 exposed laufen?A: Ja. Kernfunktionen funktionieren weiterhin.
Wenn WS nicht geroutet wird, fällt die App automatisch auf HTTP-Polling zurück.
Für das vollständige Echtzeit-Erlebnis route /_cm_ws auf 3002.
A: Erstelle/aktualisiere .env (gleiches Verzeichnis wie docker-compose.yml):```env
WEB_EXTERNAL_PORT=8080
API_EXTERNAL_PORT=8081
WS_EXTERNAL_PORT=8082
Dann neu starten:```bash
docker compose down
docker compose up -d
A: Normalerweise, weil COOKIE_SECRET nicht festgelegt ist oder das Datenverzeichnis nicht persistent gespeichert wird.
COOKIE_SECRET./data:/app/data einA: Erstelle ./geoip in deinem Projektverzeichnis (empfohlen auf derselben Ebene wie docker-compose.yml) und platziere dann:
GeoLite2-City.mmdb (erforderlich)GeoLite2-ASN.mmdb (erforderlich)GeoLite2-Country.mmdb (optional)Empfohlene Quelle: https://github.com/P3TERX/GeoLite.mmdb.
Im Container ist der feste Suchpfad /app/data/geoip, also behalte:
./geoip:/app/data/geoip:ro. Zum späteren Aktualisieren ersetze einfach die Dateien im Host-./geoip.
A: Prüfe:
A: Zuerst sichern:```bash cp -r ./data ./data-backup-$(date +%Y%m%d)
Wiederherstellen:```bash
docker compose down
cp -r ./data-backup-YYYYMMDD/. ./data/
docker compose up -d
Wenn du die Tiefe des Systemdesigns schnell verstehen möchtest, lies in dieser Reihenfolge:
RealtimeStore-Merge-Strategie und WS-PushVollständiger Dokumentationsindex: docs/README.md
Diese Dokumentation behandelt das Kerndesign von Erfassung, Aggregation, Caching, Realtime-Push und Multi-Backend-Verwaltung.
Dieses Projekt verwendet GitHub Issue Templates (Bug / Feature / Support).
Bitte gib mindestens an:
COOKIE_SECRET=***)docker logs, Browser-Konsole, Netzwerkfehler)neko-master/ ├── docker-compose.yml # Docker Compose config ├── Dockerfile # Docker image build ├── setup.sh # One-click setup script ├── docker-start.sh # Docker container startup script ├── start.sh # Source code dev startup script ├── docs/ # Documentation (see docs/README.md) │ ├── README.md # Documentation index (English default) │ ├── README.zh.md # Documentation index (Chinese) │ ├── README.en.md # Documentation index (English mirror) │ ├── architecture.md # System architecture (Chinese) │ ├── architecture.en.md # System architecture (English) │ ├── release-checklist.md │ ├── agent/ # Agent docs (bilingual) │ │ ├── overview.md / overview.en.md │ │ ├── quick-start.md / quick-start.en.md │ │ ├── install.md / install.en.md │ │ ├── config.md / config.en.md │ │ ├── release.md / release.en.md │ │ └── troubleshooting.md / troubleshooting.en.md │ ├── research/ # Research reports │ └── dev/ # Internal development docs ├── assets/ # Screenshots and icons ├── apps/ │ ├── collector/ # Data collection service (Node.js + WebSocket) │ ├── agent/ # Agent daemon (Go) │ └── web/ # Next.js frontend app └── packages/ └── shared/ # Shared types and utilities
## 🛠️ Tech-Stack
- **Frontend**: [Next.js 16](https://nextjs.org/) + [React 19](https://react.dev/) + [TypeScript](https://www.typescriptlang.org/)
- **Styling**: [Tailwind CSS](https://tailwindcss.com/) + [shadcn/ui](https://ui.shadcn.com/)
- **Diagramme**: [Recharts](https://recharts.org/)
- **i18n**: [next-intl](https://next-intl-docs.vercel.app/)
- **Backend**: [Node.js](https://nodejs.org/) + [Fastify](https://www.fastify.io/) + WebSocket
- **Datenbank**: [SQLite](https://www.sqlite.org/) ([better-sqlite3](https://github.com/WiseLibs/better-sqlite3)) + [ClickHouse](https://clickhouse.com/) (optional)
- **Build**: [pnpm](https://pnpm.io/) + [Turborepo](https://turbo.build/)
## 🤝 Mitwirken
Beiträge sind willkommen!
- 🐛 [Bug melden](https://github.com/foru17/neko-master/issues/new)
- 💡 [Feature vorschlagen](https://github.com/foru17/neko-master/issues/new)
- 🔧 [Code beitragen](https://github.com/foru17/neko-master/pulls)
Bevor du einen PR öffnest, lies [CONTRIBUTING.md](https://github.com/foru17/neko-master/blob/main/CONTRIBUTING.md) (Workflow, Checks, i18n/Dark-Mode-Anforderungen).
**Entwickelst du mit einem KI-Coding-Tool?** (Claude Code, Copilot, Cursor, Codex, ...) Verweise es auf [AGENTS.md](https://github.com/foru17/neko-master/blob/main/AGENTS.md) — Konventionen, zentrale Verträge und die Projektübersicht — sowie auf die aufgabenspezifischen Workflow-Anleitungen in [`.claude/skills/`](https://github.com/foru17/neko-master/blob/main/.claude/skills). Claude Code erkennt beides automatisch.
## 📄 Lizenz
[MIT](https://github.com/foru17/neko-master/blob/main/LICENSE) © [foru17](https://github.com/foru17)
---
## ⭐ Star-Verlauf
[](https://www.star-history.com/#foru17/neko-master&type=date&legend=top-left)
---
<p align="center">
<sub>Made with ❤️ by <a href="https://github.com/foru17">@foru17</a></sub><br>
<sub>Wenn dir dieses Projekt hilft, zieh bitte in Betracht, ihm einen ⭐ zu geben</sub>
</p>
|
|
|
|
| Funktion | Beschreibung |
|---|
| 📊 Echtzeit-Überwachung | Echtzeit-Erfassung via WebSocket mit Millisekunden-Latenz |
| 📈 Trendanalyse | Mehrdimensionale Verkehrstrends: 30min / 1h / 24h |
| 🌐 Domain-Analyse | Verkehr, zugehörige IPs und Verbindungsanzahl pro Domain anzeigen |
| 🗺️ IP-Analyse | ASN, Geolokalisierung und Anzeige zugehöriger Domains |
| 🚀 Proxy-Statistiken | Verkehrsverteilung und Verbindungsanzahl pro Proxy-Knoten |
| 📱 PWA-Unterstützung | Als Desktop-App für native Erfahrung installieren |
| 🌙 Dunkelmodus | Unterstützung für Hell / Dunkel / System-Theme |
| 🌍 i18n-Unterstützung | Nahtloses Umschalten zwischen Englisch / Chinesisch |
| 🔄 Multi-Backend | Mehrere OpenClash-Backend-Instanzen gleichzeitig überwachen |
| Crate | Description | Version |
|---|
soth-mitm | MITM proxy library with certificate generation, HTTP/2, WebSocket, and SSE interception | 0.1.0 |
soth-proxy | Standalone MITM proxy binary with rule engine and CLI | 0.1.0 |
soth-cli | Unified CLI for proxy, rules, and certificate management | 0.1.0 |
soth-core | Core types, traits, and error handling | 0.1.0 |
soth-observe | Observability: metrics, tracing, and structured logging | 0.1.0 |
soth-store | Persistent storage for rules, certificates, and traffic logs | 0.1.0 |
soth-bus | Event bus for inter-crate communication | 0.1.0 |
soth-sdk | SDK for building custom rules and plugins | 0.1.0 |
| Section | Key | Type | Default | Description |
|---|
proxy | listen | string | 0.0.0.0:8080 | HTTP listen address |
proxy | tls_listen | string | 0.0.0.0:8443 | HTTPS listen address |
proxy | ca_cert | string | - | Path to CA certificate |
proxy | ca_key | string | - | Path to CA private key |
proxy.upstream | timeout | integer | 30 | Upstream timeout in seconds |
proxy.upstream | max_connections | integer | 1000 | Maximum upstream connections |
logging | level | string | info | Log level (trace, debug, info, warn, error) |
logging | format | string | json | Log format (json, text) |
logging | output | string | stdout | Log output path |
rules | directory | string | ./rules | Rules directory |
rules | hot_reload | boolean | true | Enable hot reload of rules |
store | backend | string | sqlite | Storage backend (sqlite, postgres) |
store | path | string | ./data/soth.db | Storage path or connection string |
observe | metrics_enabled | boolean | true | Enable Prometheus metrics |
observe | metrics_port | integer | 9090 | Metrics HTTP port |
observe | tracing_enabled | boolean | true | Enable distributed tracing |
| Matcher | Description | Example |
|---|
host | Match request hostname (glob or regex) | *.example.com |
path | Match request path | /api/* |
method | Match HTTP method | GET, POST |
header | Match request header | User-Agent: *curl* |
body | Match request body (regex) | password=\w+ |
query | Match query parameter | token=* |
ip | Match client IP (CIDR) | 192.168.1.0/24 |
| Action | Description | Parameters |
|---|
block | Block the request | status, body |
allow | Allow the request | - |
redirect | Redirect to another URL | url, status |
modify | Modify request/response | headers, body |
inject | Inject content into response | content, position |
log | Log the request | level, message |
script | Execute a Lua script | path |
| Metric | Type | Description |
|---|
soth_requests_total | counter | Total number of requests |
soth_requests_blocked_total | counter | Total number of blocked requests |
soth_request_duration_seconds | histogram | Request duration in seconds |
soth_active_connections | gauge | Number of active connections |
soth_upstream_errors_total | counter | Total number of upstream errors |
soth_certificates_generated_total | counter | Total number of certificates generated |
| Port | Zweck | Extern erforderlich | Beschreibung |
|---|
| 3000 | Web-UI | ✅ | Frontend-Einstiegspunkt |
| 3001 | API | Optional | Frontend verwendet standardmäßig Same-Origin /api; normalerweise keine öffentliche Freigabe nötig (Standard-Compose mappt ihn) |
| 3002 | WebSocket | Optional | Echtzeit-Push-Endpunkt; empfohlen nur für Reverse-Proxy-/Tunnel-Weiterleitung (Standard-Compose mappt ihn) |
| Variable | Standard | Zweck | Wann setzen |
|---|
WEB_PORT | 3000 | Web-Listen-Port (innerhalb des Containers) | Normalerweise unverändert |
API_PORT | 3001 | API-Listen-Port (innerhalb des Containers) | Normalerweise unverändert |
COLLECTOR_WS_PORT | 3002 | WS-Listen-Port (innerhalb des Containers) | Normalerweise unverändert |
DB_PATH | /app/data/stats.db | SQLite-Datenpfad | Benutzerdefinierter Datenpfad |
WEB_EXTERNAL_PORT | 3000 | Externes Web-Port-Mapping in docker-compose.yml | Externer Web-Port geändert |
API_EXTERNAL_PORT | 3001 | Externes API-Port-Mapping in docker-compose.yml | Direkter externer API-Zugriff erforderlich |
WS_EXTERNAL_PORT | 3002 | Externes WS-Port-Mapping in docker-compose.yml; wird auch zur direkten WS-Port-Ableitung verwendet | Direkter WS-Zugriff ohne Proxy und externer WS-Port geändert |
NEXT_PUBLIC_API_URL | leer | Frontend-API-Basis-URL überschreiben (z. B. https://api.example.com) | API ist nicht Same-Origin /api |
NEXT_PUBLIC_WS_URL | leer | Frontend-WS-URL überschreiben (absolute URL oder /custom_ws) | Benutzerdefinierter WS-Pfad/-Domain |
NEXT_PUBLIC_WS_PORT | 3002 | WS-Direktverbindungs-Fallback-Port (nur zur Build-Zeit — das Setzen zur Docker-Laufzeit hat keine Wirkung; stattdessen WS_EXTERNAL_PORT verwenden) | Nur für benutzerdefinierte Source-Builds |
API_URL | http://localhost:3001 | Next.js /api-Rewrite-Ziel (hauptsächlich Source-/benutzerdefinierte Builds) | API-Listen-Adresse geändert |
COOKIE_SECRET | automatisch generiert | Cookie-Signierungsgeheimnis; wenn nicht festgelegt, können Sitzungen nach einem Neustart ungültig werden, wenn das Datenverzeichnis nicht persistiert wird | In der Produktion dringend empfohlen |
GEOIP_LOOKUP_PROVIDER | online | IP-Geolokalisierungsquelle (online / local) | Standardmäßig lokale MMDB-Suche |
GEOIP_ONLINE_API_URL | https://api.ipinfo.es/ipinfo | Online-IP-Geolokalisierungs-API-Endpunkt (muss mit dem ipinfo.my-Antwortschema kompatibel sein) | Nur setzen, wenn Sie einen kompatiblen Endpunkt bereitstellen |
FORCE_ACCESS_CONTROL_OFF | false | Zugriffskontrolle zwangsweise deaktivieren (Notfallwiederherstellung) | Nur vorübergehend verwenden, wenn das Token verloren geht |
SHOWCASE_SITE_MODE | false | Schreibgeschützter Showcase-Modus (blockiert sensible Schreibvorgänge) | Nur für öffentliche Demo-Seiten |
| Variable | Standard | Beschreibung |
|---|
FLUSH_INTERVAL_MS | 30000 | Puffer-Flush-Intervall für Collector-Schreibvorgänge |
FLUSH_MAX_BUFFER_SIZE | 5000 | Maximale Puffereinträge vor vorzeitigem Flush |
REALTIME_MAX_MINUTES | 180 | Echtzeit-In-Memory-Fenstergröße (Minuten) |
REALTIME_RANGE_END_TOLERANCE_MS | 120000 | Endzeit-Toleranz für Bereichsabfragen |
SURGE_POLICY_SYNC_INTERVAL_MS | 600000 | Surge-Richtlinien-Synchronisierungsintervall |
DB_RANGE_QUERY_CACHE_TTL_MS | 8000 | TTL für Bereichsabfrage-Cache |
DB_HISTORICAL_QUERY_CACHE_TTL_MS | 300000 | TTL für historischen Abfrage-Cache |
DB_RANGE_QUERY_CACHE_MAX_ENTRIES | 1024 | Maximale Einträge im Bereichsabfrage-Cache |
DB_RANGE_QUERY_CACHE_DISABLED | leer | Auf 1 setzen, um den Bereichsabfrage-Cache zu deaktivieren |
DEBUG_SURGE | false | Surge-Collector-Debug-Logs aktivieren (true) |
NEXT_PUBLIC_WS_URL normalerweise unnötig, es sei denn, Sie verwenden einen benutzerdefinierten WS-Pfad/-Domain| Variable | Standard | Beschreibung |
|---|
CH_ENABLED | 0 | ClickHouse-Verbindung aktivieren (1 zum Aktivieren) |
CH_WRITE_ENABLED | 0 | Dual-Write aktivieren (erfordert CH_ENABLED=1) |
CH_ONLY_MODE | 0 | Wenn CH fehlerfrei ist, SQLite-Statistik-Schreibvorgänge überspringen (CH-Only-Modus) |
CH_HOST | clickhouse | ClickHouse-Hostadresse |
CH_PORT | 8123 | ClickHouse-HTTP-Port |
CH_DATABASE | neko_master | Datenbankname |
CH_USER | neko | Benutzername |
CH_PASSWORD | neko_master | Passwort |
CH_SECURE | 0 | HTTPS-Verbindung verwenden |
CH_REQUIRED | 0 | Start verweigern, wenn CH nicht verfügbar ist |
CH_AUTO_CREATE_TABLES | 1 | Tabellen beim ersten Start automatisch erstellen |
CH_WRITE_MAX_PENDING_BATCHES | 200 | Maximale ausstehende Schreib-Batches |
CH_UNHEALTHY_THRESHOLD | 5 | Aufeinanderfolgende Fehler, bevor als fehlerhaft markiert wird (automatischer Fallback auf SQLite) |
STATS_QUERY_SOURCE | sqlite | Lesequelle: sqlite / auto / clickhouse |
CH_COMPARE_ENABLED | 0 | SQLite ↔ ClickHouse-Konsistenzprüfung aktivieren |
CH_EXTERNAL_HTTP_PORT | 8123 | Externer ClickHouse-HTTP-Port (Compose-Mapping) |
CH_EXTERNAL_NATIVE_PORT | 9000 | Externer ClickHouse-Native-Port (Compose-Mapping) |