Files
routstr-core/docs/provider/deployment.md
T
Jeroen Ubbink 52742a6a04 docs: align onboarding with UI-managed secrets
The admin password is generated and logged on first start and the nsec is
set from the admin UI; ADMIN_PASSWORD/NSEC in .env are only a legacy seed.
Update the README, quickstart, configuration, and deployment docs to match,
and drop the unused ADMIN_KEY environment variable.
2026-07-23 10:51:21 +02:00

6.0 KiB

Deployment

Production deployment guide for Routstr Provider nodes.

All-in-One Docker Image (Preferred)

The easiest way to deploy Routstr is using the all-in-one Docker image from Docker Hub, which includes both the FastAPI backend and the Next.js admin dashboard in a single container.

Quick Start

docker run -d \
  --name routstr \
  -p 8000:8000 \
  -v routstr-data:/app/data \
  -e DATABASE_URL="sqlite:////app/data/routstr.db" \
  9qeklajc/routstr:latest

Access your node:

Docker Compose Setup

Create docker-compose.yml:

version: '3.8'

services:
  routstr:
    image: 9qeklajc/routstr:latest
    container_name: routstr
    restart: unless-stopped
    ports:
      - "8000:8000"
    volumes:
      - routstr-data:/app/data
    environment:
      DATABASE_URL: "sqlite:////app/data/routstr.db"
      LOG_LEVEL: "info"

volumes:
  routstr-data:

Start it:

docker compose up -d

For production, use Docker Compose with persistent storage and optional Tor support.

Use the included compose.yml for a flexible setup that handles both the UI and the node execution. This is useful for development or when you want to manage Tor as a separate service.

docker compose up -d

This will:

  1. Build the UI: Compiles the frontend and copies it to a shared volume.
  2. Start Routstr: Runs the Python node, mounting the built UI.
  3. Start Tor: Provides anonymous access via a .onion address.

With Tor (Anonymous Access)

Add Tor to serve your node as a hidden service—no port forwarding needed.

services:
  routstr:
    image: ghcr.io/routstr/proxy:latest
    container_name: routstr
    restart: unless-stopped
    ports:
      - "8000:8000"
    volumes:
      - ./data:/app/data
      - ./logs:/app/logs
    environment:
      - TOR_PROXY_URL=socks5://tor:9050
      # Keep the database (and the key file generated beside it) on the volume.
      - DATABASE_URL=sqlite:////app/data/routstr.db
    depends_on:
      - tor

  tor:
    image: ghcr.io/hundehausen/tor-hidden-service:latest
    container_name: tor
    restart: unless-stopped
    volumes:
      - ./tor-data:/var/lib/tor
    environment:
      - HS_ROUTER=routstr:8000:80

After starting, find your .onion address:

docker exec tor cat /var/lib/tor/hidden_service/hostname

See Tor Support for details.


Pre-Configuration (Optional)

While everything can be configured via the dashboard, you can pre-configure settings with environment variables for automated deployments.

Using Environment Variables

services:
  routstr:
    image: ghcr.io/routstr/proxy:latest
    environment:
      # Pre-configure upstream (optional)
      - UPSTREAM_BASE_URL=https://api.openai.com/v1
      - UPSTREAM_API_KEY=sk-proj-...
      
      # The admin password is generated and logged once on first start; set
      # ADMIN_PASSWORD here only as a legacy seed for an existing deployment.
      
      # Node identity
      - NAME=My Provider Node
      - DESCRIPTION=Fast GPT-4 access via Lightning
      
      # Lightning withdrawals
      - RECEIVE_LN_ADDRESS=me@walletofsatoshi.com

      # Keep the database (and the key file generated beside it) on the volume.
      - DATABASE_URL=sqlite:////app/data/routstr.db
    volumes:
      - ./data:/app/data

Using an .env File

services:
  routstr:
    image: ghcr.io/routstr/proxy:latest
    env_file:
      - .env
    volumes:
      - ./data:/app/data

Example .env:

UPSTREAM_BASE_URL=https://api.openai.com/v1
UPSTREAM_API_KEY=sk-proj-...
# Keep the database (and the key file generated beside it) on the mounted volume.
DATABASE_URL=sqlite:////app/data/routstr.db
# Encrypts node secrets at rest. Optional — if unset, a key is generated next to
# your database (on the same volume) and its file is named once for backup. Set
# it explicitly to manage the key yourself.
ROUTSTR_SECRET_KEY=
NAME=My Provider Node
RECEIVE_LN_ADDRESS=me@walletofsatoshi.com

!!! note "Secret key persistence" If you leave ROUTSTR_SECRET_KEY unset, the node generates one and stores it as routstr_secret.key next to your database, so it persists on the same volume as your data — just include that volume in your backups. For stronger isolation (keeping the key off the data volume), set ROUTSTR_SECRET_KEY from a secrets manager instead.

See Configuration for all available options.


Persistence

Point DATABASE_URL inside /app/data (as the examples above do) so everything Routstr persists lands on the mounted volume:

Path Contents
routstr.db SQLite database (settings, API keys, sessions)
routstr_secret.key Auto-generated master key, written beside the database when ROUTSTR_SECRET_KEY is unset
.wallet/ Cashu wallet data (your Bitcoin!)

!!! warning "Back Up Your Data" The ./data volume contains your wallet. Losing it means losing funds. Back up regularly.


Reverse Proxy (Optional)

For custom domains and SSL, use a reverse proxy like Caddy or nginx.

Caddy Example

api.yournode.com {
    reverse_proxy localhost:8000
}

nginx Example

server {
    listen 443 ssl;
    server_name api.yournode.com;
    
    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;
    
    location / {
        proxy_pass http://localhost:8000;
        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-Real-IP $remote_addr;
    }
}

Updates

Pull the latest image and restart:

docker compose pull
docker compose up -d

Building from Source

Using Docker Compose

The easiest way to build everything from source:

docker compose build

Individual Components

If you prefer building the node only (requires manual UI build first):

docker build -t routstr-node .