Skip to content

Repository files navigation

Inspector

中文

Table of Contents

Traffic observability web UI for GOST tunnel/proxy nodes. Consumes records published by GOST nodes via Redis Pub/Sub and stores them in MongoDB for querying and live streaming.

Docker

# Pull
docker pull gogost/inspector

# Run (mount your config)
docker run -v $PWD/inspector.yaml:/etc/inspector.yaml -p 18000:18000 gogost/inspector

# Build locally
docker build -t gogost/inspector .

Quick start

# Build web frontend
npm --prefix web run build

# Build Go binary
go build

# Run with config
./inspector -C inspector.yaml

# Open http://localhost:18000

Configuration

addr: :18000
requireClientID: false
noFilterClientID: "*"
db:
  mongo:
    uri: mongodb://localhost:27017
    db: gost
    timeout: 10s
    maxPoolSize: 100
    debug: false
  redis:
    addr: localhost:6379
    db: 0
    username:
    password:
    poolSize: 10
    debug: false
log:
  level: info       # debug, info, warn, error
  format: json      # json or text
  output:           # file path, empty = stderr
  rotation:
    maxSize: 100    # MB per file
    maxAge: 0       # days to retain
    maxBackups: 0   # files to retain
    localTime: false
    compress: false
profiling:
  addr:             # pprof listen address (e.g. :6060)

Config is loaded from -C <path>, ./inspector.yaml, or /etc/inspector.yaml.

Fields

Path Default Description
addr :8000 HTTP listen address
requireClientID false Reject query/tail requests without client_id
noFilterClientID — Value for client_id that bypasses filtering (e.g. "*" for admin view)
db.mongo.uri — MongoDB connection URI
db.mongo.db — MongoDB database name
db.mongo.timeout 10s MongoDB operation timeout
db.mongo.maxPoolSize 100 MongoDB connection pool size
db.mongo.debug false Log all MongoDB queries
db.redis.addr — Redis address
db.redis.db 0 Redis database number
db.redis.username — Redis username (ACL)
db.redis.password — Redis password
db.redis.poolSize 10 Redis connection pool size
db.redis.debug false Log all Redis commands
log.level info Log level: debug, info, warn, error
log.format json Log format: json or text
log.output — Log output file path; empty = stderr
log.rotation.maxSize 100 Rotate when log reaches this many MB
log.rotation.maxAge 0 Days to retain old log files (0 = forever)
log.rotation.maxBackups 0 Max old log files to retain (0 = all)
log.rotation.localTime false Use local time in rotated filenames
log.rotation.compress false Compress rotated files with gzip
profiling.addr — pprof listen address (e.g. :6060); disabled if empty

Data Pipeline

Inspector is the consumer side of a three-component pipeline:

GOST node → HTTP POST → gost-plugins recorder → MongoDB (persistence)
                                              → Redis Pub/Sub (live stream) → Inspector

Inspector does not receive traffic directly from GOST nodes. The gost-plugins/recorder plugin is a standalone HTTP service that sits between GOST and the databases. Each GOST node is configured to post traffic records to the recorder plugin, which then fans them out to MongoDB (for historical queries) and Redis Pub/Sub (for live streaming via WebSocket).

Running the recorder plugin

# Start the recorder plugin (separate process)
gost-plugins recorder \
  --addr :8000 \
  --mongo.uri mongodb://localhost:27017 \
  --mongo.db gost \
  --redis.addr localhost:6379
Flag Default Description
--addr :8000 HTTP listen address
--mongo.uri — MongoDB URI (e.g. mongodb://127.0.0.1:27017); disabled if empty
--mongo.db gost MongoDB database name
--loki.url — Loki push URL (e.g. http://localhost:3100/loki/api/v1/push); disabled if empty
--loki.id gost Loki tenant ID (sent as X-Scope-OrgId header)
--redis.addr — Redis address; disabled if empty
--redis.db 0 Redis database number
--redis.username — Redis username (ACL)
--redis.password — Redis password
--timeout 10s Connection timeout for MongoDB and Loki

Configuring GOST nodes to use the recorder

Recorder configuration has two levels in GOST YAML:

1. Top-level recorders — defines the backend that connects to the gost-plugins recorder HTTP service:

recorders:
  - name: recorder-0
    http:
      url: http://127.0.0.1:8000   # gost-plugins recorder address
      timeout: 1s

2. Service-level recorders — references the named recorder with a record pattern (sibling of handler, not nested under it):

services:
  - name: my-service
    addr: :8080
    recorders:
      - name: recorder-0
        record: recorder.service.handler
        metadata:
          http.body: true               # capture HTTP request/response bodies
          http.maxBodySize: 512         # max body size per record (KB)
    handler:
      type: http
    listener:
      type: tcp

The record field controls what events are captured. Common values:

Value Records
recorder.service.handler Handler-level events (connection start, end, error)
recorder.service.handler.tcp TCP-level I/O events
recorder.service.handler.tcp.connector Connector-level events

The clientID field in the GOST service config (if set) flows through to Inspector as a filterable field — use different clientID values per node or per service to distinguish traffic sources in the Inspector UI.

Required infrastructure

  • MongoDB — stores historical records (Inspector queries this directly)
  • Redis — Pub/Sub channel for live record streaming (Inspector subscribes to gost:pubsub:recorder:<clientID>)
  • gost-plugins recorder — bridges GOST nodes to MongoDB and Redis

Startup order

  1. MongoDB + Redis
  2. gost-plugins recorder
  3. GOST nodes (with recorder plugin config)
  4. inspector

API

Method Path Description
GET /liveness Health check
GET /api/records/query Query historical records
GET /api/records/:id Single record detail (includes full req/res bodies)
WebSocket /api/records/tail Stream live records

GET /api/records/query

Param Type Description
client_id string Filter by client identifier
service string Filter by service name
sid string Filter by session ID
type string Filter by traffic type: http, websocket, tls, dns
start int64 Start time (Unix timestamp)
end int64 End time (Unix timestamp)
before string Cursor — hex ObjectID, returns records older than this ID
after string Cursor — hex ObjectID, returns records newer than this ID
limit int Max records (default 100, max 200)

Response includes data.before / data.after cursor hex strings for pagination.

WebSocket /api/records/tail

Param Type Description
client_id string Client identifier (required if requireClientID is set)
type string Filter by traffic type: http, websocket, tls, dns
service string Filter by service name
sid string Filter by session ID

Architecture

  • Go backend — Gin HTTP server serving both API and embedded SPA
  • React + TypeScript + Tailwind frontend — separate views for HTTP, WebSocket, TLS, and DNS traffic
  • MongoDB — persistent record storage (collection: recorders)
  • Redis Pub/Sub — live record streaming

The web UI is embedded into the Go binary via embed.FS — a single static binary with no external assets.

MongoDB Indexes

The recorders collection expects the following indexes, managed by scripts/recorders-indexes.js:

// 30-day TTL — removes records older than 30 days
db.recorders.createIndex({ time: -1 }, { expireAfterSeconds: 2592000 })

// Filter by type, sorted by time descending
db.recorders.createIndex({ type: 1, _id: -1 })

// Filter by service + type, sorted by time descending
db.recorders.createIndex({ service: 1, type: 1, _id: -1 })

// Filter by client + type, sorted by time descending
db.recorders.createIndex({ clientid: 1, type: 1, _id: -1 })

// Filter by session + type, sorted by time descending
db.recorders.createIndex({ sid: 1, type: 1, _id: -1 })

Run the script to reconcile:

mongosh "mongodb://<host>:<port>/<db>" scripts/recorders-indexes.js

About

Traffic observability web UI for GOST tunnel/proxy nodes

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages