--- type: reference description: "Gluetun is a lightweight VPN client container." tags: - dankclaw - gluetun timestamp: 2026-08-28 --- # Gluetun Gluetun is a lightweight VPN client container. It connects to a VPN provider (WireGuard or OpenVPN) and shares that tunnel with other containers that attach to its network namespace. **Host:** Dankclaw — **Tunnel:** WireGuard (`VPN type: wireguard`, journal 2026-10-18) to ProtonVPN US-WA per `dankclaw/searxng/quadlet/gluetun.container:6` — **Exit:** `149.22.88.19`, United States, Washington, Seattle (`journalctl --user -u gluetun`, `[ip getter]`, 2026-10-18; the journal never names the provider, so the provider attribution is the repo's) — **Docs:** https://github.com/qdm12/gluetun ## Facts (from research, primary source) | Item | Value | |------|-------| | Image | `docker.io/qmcgaw/gluetun:latest` (`dankclaw/searxng/quadlet/gluetun.container:19`; live 2026-10-18). Tagged `:latest`, so a redeploy can move the version — pin it deliberately if that ever matters. | | Capabilities | `NET_ADMIN` required (`dankclaw/searxng/quadlet/gluetun.container:20`) | | Device | `/dev/net/tun:/dev/net/tun` (`dankclaw/searxng/quadlet/gluetun.container:21`) | | Ports published | Two, both on this container because it owns the netns: `8081 → 8080` (SearXNG) and `8082 → 8085` (Marreta) (`dankclaw/searxng/quadlet/gluetun.container:31-32`; `podman inspect gluetun --format '{{json .NetworkSettings.Ports}}'` and `ss -ltnp` 2026-10-18). Neither consumer container publishes anything. | | Tunnel check | the `tun0` interface exists — the boot config dump logs `Network interface: tun0` (`journalctl --user -u gluetun` 2026-10-18). The control server listens on `:8000` **inside the netns only** (`.NetworkSettings.Ports` shows `"8000/tcp": null`, 2026-10-18), so nothing on the host can reach it. | ## Required Environment ```yaml environment: VPN_SERVICE_PROVIDER: "${VPN_SERVICE_PROVIDER}" # e.g. mullvad, protonvpn VPN_TYPE: wireguard WIREGUARD_PRIVATE_KEY: "${WIREGUARD_PRIVATE_KEY}" # from .env, never committed ``` - `VPN_TYPE` default is `openvpn`; WireGuard preferred when the provider supports it (https://github.com/qdm12/gluetun-wiki/blob/main/setup/options/vpn.md). This deployment runs WireGuard (`WIREGUARD_*` variables, `dankclaw/searxng/quadlet/gluetun.container:24-30`). - Provider-specific variables come from the Gluetun wiki (https://github.com/qdm12/gluetun-wiki); set them in `.env`. ## Optional DNS (from research) | Variable | Default | Purpose | |----------|---------|---------| | `DNS_UPSTREAM_RESOLVER_TYPE` | `dot` | DNS over TLS | | `DNS_UPSTREAM_RESOLVERS` | `cloudflare` | upstream DoT providers | | `DNS_CACHING` | `on` | cache queries | | `BLOCK_MALICIOUS` | `on` | block malicious hostnames | Names and defaults match the upstream wiki (https://github.com/qdm12/gluetun-wiki/blob/main/setup/options/dns.md); live confirmation 2026-10-18: `[dns] ready and using DNS server with dot upstream resolvers` and `[dns] downloading hostnames and IP block lists`. Warning from the wiki: do NOT set `DNS_UPSTREAM_PLAIN_ADDRESSES` to a LAN/bridge address — DNS queries leak out of the tunnel. ## Attaching a Container Three units reuse gluetun's network namespace — SearXNG and both Marreta containers: ```ini [Container] ContainerName=searxng Network=gluetun.container ``` `Network=gluetun.container` also adds a systemd dependency on gluetun, so the consumer starts after the tunnel (`dankclaw/searxng/quadlet/searxng.container:13-18`, `dankclaw/marreta/quadlet/marreta.container:29-34`, `dankclaw/marreta/quadlet/marreta-browser.container:20-25`). Live 2026-10-18 all three report `HostConfig.NetworkMode=container:03a75714…`, which is gluetun's own container id (`podman inspect gluetun --format '{{.Id}}'`) — one netns, four containers, ports published only by gluetun. ## Boot Persistence gluetun runs as the `gluetun` quadlet unit (see [[SearXNG]] for the full trio). It sets `WantedBy=default.target` and `Restart=always` (`dankclaw/searxng/quadlet/gluetun.container:37,39-40`) and user linger is on, so the tunnel starts at boot — live 2026-10-18 `systemctl --user is-enabled gluetun` → `generated`, `is-active` → `active`, `NRestarts=0` since the 01:25 boot. The WireGuard credentials live in `/opt/searxng/.env` (mode 0600 — `-rw------- dank:dank`, `ls -l` 2026-10-18). Deploy with `scripts/deploy.sh dankclaw --service gluetun` (`scripts/deploy-remote.sh:596-597`); `scripts/deploy-searxng-quadlet.sh dankclaw` is a compatibility wrapper that now forwards to `deploy.sh --service searxng`, so it does **not** deploy the tunnel. ## Verify the Tunnel ```bash podman exec gluetun curl -s ifconfig.me ``` The returned IP must differ from the host IP. A read-only alternative is the journal: gluetun logs its own egress at start, and on 2026-10-18 it logged `[ip getter] Public IP address is 149.22.88.19 (United States, Washington, Seattle …)` — not the host's address. ## Gotchas - The container that holds the published port must be the one with the ports mapping (gluetun) — searxng, marreta and marreta_browser publish nothing of their own (`dankclaw/searxng/quadlet/searxng.container` and `dankclaw/marreta/quadlet/*.container` have no `PublishPort=`; `ss -ltnp` 2026-10-18 shows only gluetun's rootlessport on 8081/8082). - `Restart=always` on gluetun (`dankclaw/searxng/quadlet/gluetun.container:37`) so the tunnel reconnects after VPN drops. - When gluetun restarts, attached containers inherit the new network state; searxng may need a restart to re-resolve DNS. - The gluetun health-check probe cannot open ICMP sockets: it logs `listening for ICMP packets: not permitted: you can try adding NET_RAW capability to resolve this; permanently falling back to plain DNS` (journal 2026-10-18). The unit grants `NET_ADMIN` only; the fallback works, so this is expected noise, not a fault. ## See Also - [[SearXNG]] — the consumer of the tunnel - [[Dankclaw Stack]] - Knowledge base: [[SearXNG]]