Skip to content

Gluetun VPN

Kheopsian edited this page Jul 29, 2026 · 6 revisions

Gluetun (VPN)

Running Hydra behind a VPN with gluetun is the fiddliest supported setup, so it gets its own page. Two things make it special:

  1. The forwarded port rotates. Providers like Proton/PIA hand you a single port-forward that changes on every reconnect. Hydra rebinds its listen port hot (no restart — torrents and live peers stay up), but something has to push the new port to it on each rotation.
  2. One forwarded port serves one engine. race and hoard are two processes and cannot share one inbound TCP port. This drives the topology.

The golden rule

One forwarded port = one engine. Never point a single VPN port-forward at both race and hoard.

Simple setup — one engine behind gluetun

Hydra shares gluetun's network namespace (network_mode: service:gluetun), so its UI/API and the VPN egress all live in the tunnel. gluetun runs its UP_COMMAND inside its own container on every (re)negotiation; the most portable way to reach Hydra from there is its HTTP API on 127.0.0.1:8199 (same namespace).

services:
  gluetun:
    image: qmcgaw/gluetun
    cap_add: [NET_ADMIN]
    ports:
      - "8199:8199"          # Hydra UI, exposed through the tunnel container
    environment:
      - VPN_SERVICE_PROVIDER=protonvpn
      - VPN_PORT_FORWARDING=on
      - HYDRA_API_KEY=change-me           # your [daemon] api_key
      # Reach a qBittorrent / service on your LAN (e.g. the import wizard):
      - FIREWALL_OUTBOUND_SUBNETS=192.168.1.0/24
      # Pushed to Hydra on every port (re)negotiation. {{PORTS}} is gluetun's.
      - |
        VPN_PORT_FORWARDING_UP_COMMAND=/bin/sh -c 'wget -qO- --header="X-Api-Key: $${HYDRA_API_KEY}" --header="Content-Type: application/json" --post-data="{\"port\":{{PORTS}}}" http://127.0.0.1:8199/api/hoard/listen-port'

  hydra:
    image: ghcr.io/kheopsian/hydra:latest
    network_mode: "service:gluetun"
    depends_on: [gluetun]
    volumes:
      - ./config:/config
      - /path/to/data:/data

The HTTP endpoint is POST /api/{race,hoard}/listen-port {"port":N} — point the UP_COMMAND at race or hoard depending on which engine lives here.

⚠️ The exact UP_COMMAND depends on your gluetun version and provider. If your gluetun image lacks wget, use curl, or write the port to a file and have a small watcher call the API. Validate it against a known-good VPN setup before trusting it in production.

Full inbound on both engines (single-port VPN)

Because one port serves one engine, to keep inbound on both race and hoard over a single-port VPN, split them:

  • a --front-only controller (the UI/aggregator), and
  • one --agent-only engine per gluetun, each getting its own forwarded port.

Each agent runs in its own gluetun; its UP_COMMAND pushes that tunnel's port to that agent's engine, and the front aggregates and drives them from one UI. See Deployment Topologies.

An --agent-only node has no HTTP API, so the HTTP recipe above doesn't apply to it. Push the port with the CLI inside the agent container (hydra set-listen-port /config/<engine>.sock <port>), driven off gluetun's forwarded-port file (a small watcher) rather than gluetun's UP_COMMAND (which runs in the gluetun container, where the hydra binary isn't present).

Gotchas

  • LAN is unreachable by default. Inside the tunnel, localhost is the VPN namespace, not your host, and your LAN is firewalled off. To let Hydra reach a LAN service (e.g. a qBittorrent for the import wizard) set FIREWALL_OUTBOUND_SUBNETS=192.168.x.0/24 (exact name, plural, with the mask) on the gluetun service, then up -d. Use the service's LAN IP, not localhost.
  • Don't cram two engines behind one tunnel — see the golden rule.
  • The listen port in default.toml is only a placeholder behind gluetun; the real one is pushed on each rotation. Don't rely on it being fixed.
  • Expose the UI through gluetun, not the Hydra service — map 8199:8199 on the gluetun container (Hydra has no ports of its own in network_mode: service:gluetun).

See also Networking Modes (the non-VPN options) and Deployment Topologies.

Clone this wiki locally