# The home seeder, behind a VPN, with no way around it (release 21 D4b). # # SEEDER_WG_CONF=/abs/path/to/wg0.conf \ # docker compose -f docker-compose.yml -f docker-compose.seeder.yml --profile seeder up -d # # `archilyzer seed` is the peer of last resort for the sites' playable # torrents (settings.seeder; SETTINGS.md): it seeds a torrent only while no # other seeder has it. Every byte it uploads leaves through the tunnel below. # # THE KILL SWITCH IS THE CONSTRUCTION, not a setting: # # * `seeder-vpn` is gluetun: a WireGuard client whose firewall drops every # packet that is not in the tunnel (or to the tunnel's own endpoint). Tunnel # down = no network, never the home connection. # * `seeder` and `tracker` have NO network of their own: `network_mode: # service:seeder-vpn` puts them in that container's network namespace, so # the only interfaces they can see are the tunnel and loopback (plus # gluetun's own, which its firewall closes). WebRTC gathers ICE candidates # from what it can see, so a browser peer is never offered the home address. # * Neither publishes a port. Inbound connections (a browser or a desktop # client dialing the seeder, a browser reaching the tracker) need the VPN # provider's port forwarding — gluetun's FIREWALL_VPN_INPUT_PORTS. Whether # to rely on that, or on a TURN relay, is the operator's ruling (the plan's # "risk to measure first"); nothing here opens one by default. # * `seeder.bindInterface` in settings.json (e.g. "tun0" or "wg0", whatever # gluetun names it) makes `archilyzer seed` refuse to start, and stop every # torrent, while that interface is gone — the same rule, a second time, in # the app. # # THE WIREGUARD CONFIG IS YOURS. `SEEDER_WG_CONF` is the absolute path of a # wg-quick file from your VPN provider (an [Interface] with your PrivateKey and # Address, a [Peer] with the endpoint). There is no default and nothing here # invents one: compose refuses to start the profile without it. It is mounted # read-only and never copied into an image. # # `archilyzer doctor` compares the seeder's egress IP with the host's and fails # if they match ("seeder" section); it says "seeder not configured" while # settings.seeder.sites is empty. services: seeder-vpn: profiles: [seeder] # Pinned. gluetun's firewall — always on in v3, there is no switch for it — # is what makes the tunnel the only way out of this namespace. image: qmcgaw/gluetun:v3.41.3 restart: unless-stopped cap_add: [NET_ADMIN] devices: - /dev/net/tun:/dev/net/tun environment: VPN_SERVICE_PROVIDER: custom VPN_TYPE: wireguard WIREGUARD_CONF_SECRETFILE: /gluetun/wireguard/wg0.conf # Inbound through the tunnel, when the provider forwards a port to you: # the seeder's torrent port and the tracker's. Empty = none. FIREWALL_VPN_INPUT_PORTS: ${SEEDER_VPN_INPUT_PORTS:-} TZ: ${TZ:-UTC} volumes: - ${SEEDER_WG_CONF:?set SEEDER_WG_CONF to your VPN provider's wg-quick file}:/gluetun/wireguard/wg0.conf:ro # The app image (docker-compose.yml's), run as `archilyzer seed`. YAML # anchors do not cross files, so the few keys it needs are spelled here. seeder: image: archilyzer:${ARCHILYZER_TAG:-local} profiles: [seeder] restart: unless-stopped command: ["pnpm", "--silent", "archilyzer", "seed"] network_mode: service:seeder-vpn depends_on: seeder-vpn: condition: service_healthy env_file: - path: .env required: false environment: TRANSCRIPTS_DIR: /data/transcripts SETTINGS_FILE: /data/config/settings.json volumes: # Read-only: the seeder reads site.json, the playable manifests and the # copies; it writes nothing to the corpus. A playable root on another # drive (beside a saved-video store moved off the corpus volume) needs # its own read-only bind mount at the same absolute path, in a # docker-compose.override.yml. - corpus:/data/transcripts:ro - config:/data/config:ro # The pilot's self-hosted tracker (WebSocket + HTTP), in the same namespace, # so its announces and its address are the tunnel's too. TLS (wss://) is # whatever terminates in front of the forwarded port. tracker: image: archilyzer:${ARCHILYZER_TAG:-local} profiles: [seeder] restart: unless-stopped command: ["pnpm", "--silent", "archilyzer", "tracker", "--host", "0.0.0.0", "--port", "${SEEDER_TRACKER_PORT:-8000}"] network_mode: service:seeder-vpn depends_on: seeder-vpn: condition: service_healthy env_file: - path: .env required: false environment: TRANSCRIPTS_DIR: /data/transcripts SETTINGS_FILE: /data/config/settings.json volumes: # It reads the playable manifests to know which infohashes it tracks. - corpus:/data/transcripts:ro - config:/data/config:ro