light-ss-pool is a pool manager for light-ss instances, enabling management of multiple shadowsocks proxies through subscription URLs, providing unified monitoring, control, and configuration management.
We spawn light-ss as separate processes rather than importing it as a library or using external process managers.
Stability & Isolation:
- Fault isolation: If one light-ss instance crashes, others continue running
- Risk mitigation: Memory leaks or crashes in light-ss won't affect pool manager
- Stability: light-ss may have undiscovered bugs - process isolation protects the pool
Operational Benefits:
- Debugging: Can inspect, attach debuggers to individual processes using standard tools (ps, htop, gdb, strace)
- Resource monitoring: Use OS tools to monitor each instance independently
- Independent updates: Can update light-ss binary without rebuilding light-ss-pool
- Operational flexibility: Can forcibly kill hung processes, test new versions on subset of instances
- Different versions: Could even run different light-ss versions simultaneously if needed
Production Proven:
- Battle-tested approach used by nginx, php-fpm, gunicorn, supervisor, etc.
- Industry standard for managing pools of worker processes
Higher memory overhead:
- Each process has its own memory space
- Worth it for the stability and isolation benefits
IPC via REST API:
- Communication through light-ss management API rather than direct function calls
- Clean, well-defined interface that's already implemented
- Slightly higher latency (negligible for management operations)
Slower startup:
- Process spawning takes longer than goroutine creation
- Acceptable for proxy pool use case (not hot path)
┌─────────────────────────────────────────────────────────────────┐
│ light-ss-pool │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ REST API │ │ CLI Client │ │ Daemon │ │
│ │ Server │ │ (lspc) │ │ Manager │ │
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │ │
│ └──────────────────┴──────────────────┘ │
│ │ │
│ ┌────────▼────────┐ │
│ │ Pool Manager │ │
│ │ │ │
│ │ - Instance Map │ │
│ │ - Lifecycle │ │
│ │ - Monitor │ │
│ └────────┬────────┘ │
│ │ │
│ ┌──────────────────┼──────────────────┐ │
│ │ │ │ │
│ ┌────▼─────┐ ┌────▼─────┐ ┌────▼─────┐ │
│ │Instance 1│ │Instance 2│ │Instance N│ │
│ │ │ │ │ │ │ │
│ │ PID:1001 │ │ PID:1002 │ │ PID:100N │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │
└─────────┼──────────────────┼──────────────────┼─────────────────┘
│ │ │
┌─────▼──────┐ ┌─────▼──────┐ ┌─────▼──────┐
│ light-ss │ │ light-ss │ │ light-ss │
│ Process │ │ Process │ │ Process │
│ │ │ │ │ │
│ Port:10801 │ │ Port:10802 │ │ Port:1080N │
│ API :18090 │ │ API :18091 │ │ API :1809N │
└────────────┘ └────────────┘ └────────────┘
Responsibilities:
- Spawn and manage light-ss processes
- Track instance state (Running, Stopped, Crashed)
- Monitor instance health via API calls
- Handle instance lifecycle (start, stop, restart, reload)
- Coordinate subscription updates
- Aggregate statistics from all instances
Does NOT:
- Handle proxy traffic (data plane is in light-ss processes)
- Directly manage shadowsocks connections
- Parse proxy protocols (delegated to light-ss)
Responsibilities:
- Spawn light-ss process with
exec.Command - Track process PID and state
- Generate instance-specific config files
- Communicate with light-ss via REST API
- Monitor process health
- Handle graceful shutdown and forced kill
- Track restart attempts and backoff
Communication:
- Uses light-ss management API (HTTP/JSON)
- Health checks:
GET /health - Statistics:
GET /stats - Speed test:
GET /speedtest - Hot reload:
POST /reload
Responsibilities:
- Fetch subscription URLs (HTTP GET)
- Auto-detect format (Base64 vs Clash YAML)
- Parse shadowsocks configurations
- Update instance configs in storage
- Schedule periodic updates
- Handle update failures gracefully
Does NOT:
- Automatically restart instances (user must manually restart)
- Modify running instances (only updates stored config)
Responsibilities:
- Persist pool configuration
- Persist instance configurations
- Persist subscription definitions
- Load configuration on pool startup
- Atomic writes to prevent corruption
Format:
- YAML files for human readability
- JSON support for programmatic access
- File-based (no database dependency)
1. Pool Manager receives start request
2. Generate unique ID if needed
3. Allocate unique ports (proxy + API)
4. Create instance-specific config file
5. Spawn light-ss process: light-ss start -c <config>
6. Store PID and process handle
7. Wait for health check to pass
8. Mark instance as Running
9. Start health monitoring
1. Pool Manager receives stop request
2. Call light-ss API: POST /stop (graceful)
3. Wait up to 10 seconds for graceful shutdown
4. If still running, send SIGTERM
5. Wait up to 5 seconds
6. If still running, send SIGKILL (forced)
7. Clean up config file (optional)
8. Mark instance as Stopped
9. Stop health monitoring
1. Health monitor detects failure
2. Mark instance as Crashed
3. Log crash event with context
4. If auto_restart enabled:
a. Check restart count vs max_retries
b. Apply backoff delay
c. Attempt restart
d. Increment restart count
5. If max retries exceeded:
a. Mark instance as Failed
b. Alert operator (log)
c. Require manual intervention
- Proxy ports: 10800-11799 (1000 instances max)
- API ports: 18090-19089 (1000 instances max)
- Pool maintains port allocation map
- When creating instance, find next available port pair
- Check for conflicts before spawning process
- Release ports when instance is removed
- Persist allocations across pool restarts
Default locations (current working directory):
./config.yaml # Pool configuration
./data/
├── instances.yaml # Instance definitions (managed by pool - use CLI only)
├── subscriptions.yaml # Subscription URLs (managed by pool - use CLI only)
└── instances/ # Per-instance light-ss configs (auto-generated - don't edit)
├── instance-001.yaml
├── instance-002.yaml
└── instance-00N.yaml
| File | Purpose | How to Modify |
|---|---|---|
instances.yaml |
Source of truth for all instances | Use CLI only (lspc inst update/add/delete) |
subscriptions.yaml |
Source of truth for subscriptions | Use CLI only (lspc subs update/add/delete) |
instances/*.yaml |
Auto-generated light-ss configs | Never edit (regenerated automatically) |
Why CLI-only?
- ✅ Pool validates all changes
- ✅ Maintains consistency between files
- ✅ Auto-regenerates light-ss configs
- ✅ Prevents corruption and conflicts
Update Flow:
User: lspc inst update instance-001 --name "New Name"
↓
1. Pool validates input
2. Pool updates instances.yaml
3. Pool regenerates data/instances/instance-001.yaml
4. If running: reload or restart instance
Custom locations (via flags):
light-ss-pool start --config /path/to/config.yaml --data-dir /path/to/dataWhat goes in config.yaml (Pool Configuration):
- Pool server settings (API listen address, port)
- Authentication token for pool API
- light-ss binary path (where to find light-ss executable)
- Data storage path (where to store instances.yaml, subscriptions.yaml)
- Monitoring settings (health check interval, auto-restart policy defaults)
- Logging configuration (level, format, file path)
- Port allocation ranges (for auto-assigning ports to instances)
- Daemon settings (PID file location, Unix socket path)
What goes in instances.yaml (Instance Configurations):
- All shadowsocks server configurations
- Per-instance proxy ports and API ports
- Per-instance enable/disable status
- Per-instance auto-restart settings
- Instance metadata (name, tags, source)
What goes in subscriptions.yaml (Subscription Definitions):
- Subscription URLs
- Update intervals
- Last update timestamps
1. Pool starts, loads config.yaml from:
- Path specified by --config flag, or
- ./config.yaml (current directory), or
- ~/.config/light-ss-pool/config.yaml (fallback)
2. Loads data files from data directory:
- instances.yaml (instance definitions)
- subscriptions.yaml (subscription URLs)
3. For each enabled instance:
a. Generate instance-specific light-ss config from template
b. Write to data/instances/<id>.yaml
c. Spawn light-ss with: light-ss start -c data/instances/<id>.yaml
4. Monitor and manage spawned processes
1. Command-line flags (highest priority)
2. Environment variables
3. Config file (config.yaml)
4. Default values (lowest priority)
Example:
# Override config file location
light-ss-pool start --config /etc/light-ss-pool/config.yaml
# Override data directory
light-ss-pool start --data-dir /var/lib/light-ss-pool
# Override API listen address
light-ss-pool start --listen 0.0.0.0:9090
# Override log level
light-ss-pool start --log-level debug- Each light-ss process runs with same user as pool
- No privilege separation between instances
- OS-level process isolation provides security boundary
- Resource limits can be applied per-process via ulimit/cgroups
- Pool API requires bearer token (optional)
- light-ss instance APIs are localhost-only by default
- Unix socket option for CLI (better than TCP)
- Config files should be chmod 600 (contain passwords)
- Shadowsocks passwords stored in config files
- Config files not exposed via API
- Passwords sanitized in API responses
- No credential caching in memory beyond config
All APIs use /api/ prefix (no versioning).
The pool itself needs management capabilities:
# Pool lifecycle
GET /api/pool/status - Pool status and health
GET /api/pool/health - Pool health check
GET /api/pool/version - Pool version info
GET /api/pool/stats - Aggregate statistics
POST /api/pool/reload - Reload pool configuration
POST /api/pool/shutdown - Graceful shutdown
# Configuration management
GET /api/pool/config - Get current pool config (sanitized)
POST /api/pool/config/update - Update pool config
POST /api/pool/config/reload - Reload config from file
POST /api/pool/config/validate - Validate config file
# Bulk operations
POST /api/inst/start-all - Start all enabled instances
POST /api/inst/stop-all - Stop all running instances
POST /api/inst/restart-all - Restart all running instances
POST /api/inst/speedtest-all - Speed test all instances
# Logs and diagnostics
GET /api/pool/logs - Get pool logs
GET /api/pool/debug/info - Debug information
GET /api/pool/debug/pids - All process PIDs
GET /api/pool/debug/ports - Port allocations
GET /api/pool/metrics - Prometheus metrics (future)
# Pool status and management
lspc pool status - Show pool status
lspc pool reload - Reload pool config
lspc pool shutdown - Graceful shutdown
lspc pool restart - Restart pool daemon (via systemd)
# Configuration management
lspc config show - Show current pool config
lspc config edit - Edit config file
lspc config reload - Reload from file
lspc config validate - Validate config file
lspc config path - Show config file path
# Logs
lspc logs - Show pool logs
lspc logs -f - Follow pool logs
lspc logs --instance <id> - Show instance logs
lspc logs --tail 100 - Show last 100 lines
# Diagnostics
lspc debug info - Show debug information
lspc debug pids - Show all process PIDs
lspc debug ports - Show port allocationsAll instance lifecycle and monitoring operations:
# Instance list and query
GET /api/inst - List all instances
GET /api/inst?state=running - List only running instances
GET /api/inst?enabled=true - List only enabled instances
GET /api/inst/:id - Get instance details
GET /api/inst/:id/config - Get instance configuration
# Instance CRUD
POST /api/inst/add - Create instance
POST /api/inst/:id/update - Update instance (name, enabled, auto_restart)
POST /api/inst/:id/delete - Delete instance
POST /api/inst/:id/enable - Enable instance
POST /api/inst/:id/disable - Disable instance
# Instance lifecycle - single
POST /api/inst/:id/start - Start instance
POST /api/inst/:id/stop - Stop instance
POST /api/inst/:id/restart - Restart instance
POST /api/inst/:id/reload - Hot reload config
# Instance monitoring
GET /api/inst/:id/health - Health check instance
GET /api/inst/:id/stats - Get instance statistics
GET /api/inst/:id/logs - Get instance logs
POST /api/inst/:id/speedtest - Run speed test
# List and query
lspc inst list - List all instances
lspc inst list --active - List running instances only
lspc inst list --enabled - List enabled instances only
lspc inst show <id> - Show instance details
lspc inst config <id> - Get instance configuration
# CRUD operations
lspc inst create -f <file> - Create new instance
lspc inst update <id> --name <name> - Update instance name
lspc inst delete <id> - Delete instance
lspc inst enable <id> - Enable instance
lspc inst disable <id> - Disable instance
# Lifecycle - single instance
lspc inst start <id> - Start instance
lspc inst stop <id> - Stop instance
lspc inst restart <id> - Restart instance
lspc inst reload <id> - Hot reload config
# Lifecycle - bulk operations
lspc inst start-all - Start all enabled instances
lspc inst stop-all - Stop all running instances
lspc inst restart-all - Restart all running instances
# Monitoring
lspc inst health <id> - Check instance health
lspc inst stats <id> - Get instance statistics
lspc inst logs <id> - Get instance logs# Subscription list and query
GET /api/subs - List all subscriptions
GET /api/subs/:id - Get subscription details
# Subscription CRUD
POST /api/subs/add - Add subscription
POST /api/subs/:id/update - Update subscription (name, url, interval)
POST /api/subs/:id/delete - Remove subscription
POST /api/subs/:id/enable - Enable subscription
POST /api/subs/:id/disable - Disable subscription
# Subscription operations
POST /api/subs/:id/fetch - Fetch subscription now
POST /api/subs/:id/generate - Generate instances from subscription
POST /api/subs/fetch-all - Fetch all subscriptions
POST /api/subs/generate-all - Generate instances from all
# List and query
lspc subs list - List all subscriptions
lspc subs show <id> - Show subscription details
# CRUD operations
lspc subs add --name <name> --url <url> [--interval <seconds>] - Add subscription
lspc subs update <id> [--name <name>] [--url <url>] [--interval <seconds>] - Update subscription
lspc subs delete <id> - Remove subscription
lspc subs enable <id> - Enable subscription
lspc subs disable <id> - Disable subscription
# Operations
lspc subs fetch <id> - Fetch specific subscription
lspc subs fetch --all - Fetch all subscriptions
lspc subs generate <id> - Generate instances from specific
lspc subs generate --all - Generate instances from all# Speed test operations
POST /api/inst/:id/speedtest - Run speed test on instance
POST /api/inst/speedtest-all - Run speed test on all instances
GET /api/speedtest/results - List all speed test results
GET /api/speedtest/results/:id - Get speed test result for instance
# Speed test operations
lspc speedtest <id> - Test specific instance
lspc speedtest --all - Test all instances
lspc speedtest list - List all test results
lspc speedtest show <id> - Show result for instanceEvery 30 seconds (configurable):
1. Check process is still running (PID exists)
2. Call light-ss API: GET /health
3. If both pass: instance is healthy
4. If either fails: mark as unhealthy, trigger restart logic
Pool aggregates stats from all instances:
- Total/active connections per instance
- Bytes sent/received per instance
- Current speeds (up/down)
- Uptime per instance
- Restart count per instance
- Health status
On-demand or scheduled:
1. Pool calls instance API: GET /speedtest?duration=10
2. light-ss performs speed test through SS connection
3. Results returned: download speed, latency
4. Pool stores results for comparison
5. Can rank instances by speed for load balancing
# Start pool in background
light-ss-pool start --daemon
# Pool runs in background with PID file
# Logs to file or syslog
# CLI communicates via REST API[Unit]
Description=Light SS Pool Manager
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/light-ss-pool start
Restart=on-failure
User=light-ss-pool
[Install]
WantedBy=multi-user.targetFROM golang:1.22 AS builder
# Build light-ss and light-ss-pool
FROM alpine:latest
# Copy binaries
# Run pool as PID 1
# Instances run as child processes- Supports up to 1000 instances (port range limit)
- All instances on same machine
- Single pool manager process
- Distributed pool across multiple machines
- Load balancing across instances
- Automatic failover
- Geographic distribution
- Central management API for multiple pools
- All light-ss instances continue running
- Pool state lost (in-memory)
- On restart:
- Load config from files
- Discover running instances (via PID files or ps)
- Reconnect to existing processes
- Resume monitoring
- Other instances unaffected
- Pool detects via health check
- Auto-restart if enabled
- User notified via logs
- Stats preserved until restart
- Cannot write new configs
- Existing instances continue running
- New instances cannot start
- Alert operator
- Graceful degradation
- Subscription updates fail (logged)
- Instance API calls timeout (marked unhealthy)
- Proxy traffic unaffected (direct in light-ss)
- Pool continues managing what it can
- Separation of Concerns: Pool manages processes, light-ss handles proxying
- Fail Independently: One instance failure doesn't affect others
- Debuggable: Use standard tools, clear logs, visible processes
- Recoverable: Pool and instances can restart independently
- Observable: Health, stats, logs available via API
- Simple: Avoid premature optimization, clear code over clever code
- Testable: Process-based makes integration testing straightforward