services: bitcoin: # Bitcoin Knots — Luke Dashjr's fork of Core, stricter mempool policy # Image is unofficial but built from reproducible Knots binaries (bitcoinknots.org) # For max sovereignty: build from source and replace this image with your own # To swap implementations: change image + datadir volume path, nothing else image: bitcoinknots/bitcoin:29.3.knots20260210 container_name: bitcoin restart: unless-stopped volumes: - bitcoin_data:/home/bitcoin/.bitcoin ports: - "8333:8333" networks: - node-net healthcheck: test: ["CMD", "bitcoin-cli", "-datadir=/home/bitcoin/.bitcoin", "getblockchaininfo"] interval: 60s timeout: 10s retries: 5 start_period: 30s lnd: image: lightningnetwork/lnd:v0.18.3-beta container_name: lnd restart: unless-stopped depends_on: bitcoin: condition: service_healthy volumes: - lnd_data:/root/.lnd ports: - "9735:9735" networks: - node-net healthcheck: test: ["CMD", "lncli", "--network=mainnet", "state"] interval: 30s timeout: 10s retries: 10 start_period: 60s lnbits: image: lnbits/lnbits:latest container_name: lnbits restart: unless-stopped depends_on: lnd: condition: service_started ports: - "127.0.0.1:5000:5000" volumes: - lnbits_data:/app/data - lnd_data:/lnd:ro environment: - LNBITS_DATA_FOLDER=/app/data - LNBITS_BACKEND_WALLET_CLASS=LndRestWallet - LND_REST_ENDPOINT=https://lnd:8080 - LND_REST_CERT=/lnd/tls.cert - LND_REST_MACAROON=/lnd/data/chain/bitcoin/mainnet/invoice.macaroon - LNBITS_SITE_TITLE=Timmy Node - LNBITS_SITE_TAGLINE=Lightning AI Agent Infrastructure - UVICORN_HOST=0.0.0.0 - UVICORN_PORT=5000 networks: - node-net # ── Nostr relay ────────────────────────────────────────────────────────────── relay-policy: # Write-policy sidecar: receives strfry plugin decisions, forwards to API server. # Started before strfry so the plugin script can immediately reach it. build: context: ./relay-policy dockerfile: Dockerfile container_name: relay-policy restart: unless-stopped environment: - PORT=3080 # Base URL of the Timmy API server (no trailing slash). # Example: https://alexanderwhitestone.com - RELAY_API_URL=${RELAY_API_URL:-} # Shared secret — must match RELAY_POLICY_SECRET in the API server's env. - RELAY_POLICY_SECRET=${RELAY_POLICY_SECRET:-} networks: - node-net healthcheck: test: ["CMD", "wget", "-qO-", "http://localhost:3080/health"] interval: 15s timeout: 5s retries: 3 start_period: 10s strfry: # strfry — high-performance Nostr relay written in C++. # All inbound events pass through the relay-policy sidecar before storage. image: ghcr.io/hoytech/strfry:latest container_name: strfry restart: unless-stopped depends_on: relay-policy: condition: service_healthy volumes: - strfry_data:/data/strfry-db - ./strfry.conf:/etc/strfry.conf:ro # Plugin bridge script: reads events from strfry stdin, calls relay-policy HTTP. - ./relay-policy/plugin.sh:/usr/local/bin/relay-policy-plugin:ro ports: - "7777:7777" command: ["strfry", "--config=/etc/strfry.conf", "relay"] networks: - node-net healthcheck: test: ["CMD", "sh", "-c", "echo >/dev/tcp/localhost/7777"] interval: 30s timeout: 5s retries: 5 start_period: 15s networks: node-net: driver: bridge volumes: bitcoin_data: driver: local driver_opts: type: none o: bind device: /data/bitcoin lnd_data: driver: local driver_opts: type: none o: bind device: /data/lnd lnbits_data: driver: local driver_opts: type: none o: bind device: /data/lnbits strfry_data: # Persistent event database — survives container restarts and upgrades. # Operator must create /data/strfry on the VPS before first launch: # mkdir -p /data/strfry && chmod 700 /data/strfry driver: local driver_opts: type: none o: bind device: /data/strfry