Run VansRouter in a container. Published images:
- GHCR:
ghcr.io/Vanszs/VansRouter - Docker Hub:
vanszs/vansrouter
Multi-platform linux/amd64 + linux/arm64.
docker run -d \
-p 20128:20128 \
-v "$HOME/.9router:/app/data" \
-e DATA_DIR=/app/data \
--name vansrouter \
ghcr.io/Vanszs/VansRouter:latestApp listens on port 20128. Open: http://localhost:20128
docker logs -f vansrouter # view logs
docker stop vansrouter # stop
docker start vansrouter # start again
docker rm -f vansrouter # remove-v "$HOME/.9router:/app/data" \
-e DATA_DIR=/app/dataWithout DATA_DIR, the app falls back to ~/.9router/ (macOS/Linux) or %APPDATA%\9router\ (Windows). In the container, DATA_DIR=/app/data makes the bind mount work.
Data layout under $DATA_DIR/:
$DATA_DIR/
├── db/
│ ├── data.sqlite # main SQLite database
│ └── backups/ # auto backups
└── ... # certs, logs, runtime configs
Host path: $HOME/.9router/db/data.sqlite
Container path: /app/data/db/data.sqlite
Production requirements:
- Run one VansRouter process per SQLite file. Multiple containers/processes with separate local volumes do not share proxy-pool fitness state.
- If scaling horizontally, provide a shared database/backend for routing state before enabling multiple app instances.
- Keep the persistent volume name
vansrouter-data; renaming it creates a new empty database volume. - Production requires a native SQLite driver. The
sql.jsfallback is single-process development fallback only.
docker run -d \
-p 20128:20128 \
-v "$HOME/.9router:/app/data" \
-e DATA_DIR=/app/data \
-e PORT=20128 \
-e HOSTNAME=0.0.0.0 \
-e DEBUG=true \
--name vansrouter \
ghcr.io/Vanszs/VansRouter:latestHeadroom is an optional sidecar service for tool-history safety and advanced request processing.
Use the provided docker-compose.yml:
# Copy and customize environment
cp .env.example .env
nano .env
# Start both services
docker compose up -dCreate your own docker-compose.yml:
services:
vansrouter:
image: ghcr.io/Vanszs/VansRouter:latest
container_name: vansrouter
restart: always
ports:
- "20128:20128"
volumes:
- vansrouter-data:/app/data
env_file:
- .env
environment:
DATA_DIR: /app/data
PORT: "20128"
HOSTNAME: "0.0.0.0"
NODE_ENV: production
HEADROOM_URL: http://headroom:8787
depends_on:
- headroom
headroom:
image: ghcr.io/chopratejas/headroom:latest
container_name: headroom
restart: always
ports:
- "8787:8787"
volumes:
vansrouter-data:
name: vansrouter-dataRun Headroom independently:
In the dashboard, open Endpoint → Token Saver → Headroom, confirm the URL is http://headroom:8787, recheck status, then enable Headroom.
If Headroom runs on the Docker host instead of as a sidecar, use http://host.docker.internal:8787 on macOS/Windows. On Linux, add --add-host=host.docker.internal:host-gateway or the equivalent compose extra_hosts entry.
docker pull ghcr.io/Vanszs/VansRouter:latest
docker rm -f vansrouter
# re-run the quick start commanddocker build -t vansrouter .
docker run --rm -p 20128:20128 \
-v "$HOME/.9router:/app/data" \
-e DATA_DIR=/app/data \
vansrouterPush a git tag v* → GitHub Actions builds multi-platform (amd64+arm64) and pushes to:
ghcr.io/Vanszs/VansRouter:v{version}+:latestvanszs/vansrouter:v{version}+:latest
# Use scripts/release.js (recommended)
node scripts/release.js "Release title" "Notes"
# Or manually
git tag v0.7.x && git push origin v0.7.xWorkflow: .github/workflows/release.yml