NordVPN WireGuard (NordLynx) client in Docker: fail-closed kill switch, gateway mode, token auth
10K+
WireGuard (NordLynx) client docker container that routes other containers' traffic through NordVPN servers automatically.
Prefer OpenVPN? This has a sibling project, azinchen/nordvpn — the same auto-routing NordVPN container over OpenVPN (including XOR traffic obfuscation). Both share the same configuration model and feature set.
--net=container:vpnTOKEN and the container fetches your WireGuard key itself (details)NETWORK=... (details)DNS=... (details)wg-quick to it (details)wireguard-go when the kernel lacks WireGuard (details)FORWARD_FROM (details)TTL_SET / TTL_INC hide cascade hops from client traceroutes (details)HEALTHCHECK reports tunnel state to Docker (details)status.json status file (details)📖 Full documentation on the Wiki — configuration guides, examples, troubleshooting, FAQ, and architecture.
docker run -d --name vpn \
--cap-add=NET_ADMIN \
--sysctl net.ipv4.conf.all.src_valid_mark=1 \
-e TOKEN=your_nordvpn_token_here \
azinchen/nordvpn-wg
Route other containers through VPN:
docker run --net=container:vpn -d your/application
Also available from GitHub Container Registry: ghcr.io/azinchen/nordvpn-wg
TOKEN — the container reads your NordLynx (WireGuard) key from the NordVPN API on every connectNote: The token is different from your regular NordVPN login. It is used only to fetch your WireGuard key; the key lives only in the container-private WireGuard config (root-owned, mode 0600), is removed when the service stops, and is re-fetched on every connect — it is never logged and never stored in the image or a volume. See the wiki for the API one-liner if you prefer to inspect it yourself.
services:
vpn:
image: azinchen/nordvpn-wg:latest
cap_add:
- NET_ADMIN
sysctls:
- net.ipv4.conf.all.src_valid_mark=1
environment:
- TOKEN=your_nordvpn_token_here
- COUNTRY=United States;CA
- RANDOM_TOP=10
- RECREATE_VPN_CRON=0 */6 * * *
- NETWORK=192.168.1.0/24
ports:
- "8080:80" # host:container — use your app's listening port
restart: unless-stopped
app:
image: nginx:alpine
network_mode: "service:vpn"
depends_on:
- vpn
restart: unless-stopped
More examples: Docker Compose · Docker Run
Grouped by feature; every variable is one line here — the linked wiki pages have the full descriptions. List values (countries, cities, CIDRs, URLs, IPs) accept ; or , as separators; whitespace around separators is ignored.
| Variable | Default | Description |
|---|---|---|
TOKEN | — (required) | NordVPN access token; your WireGuard key is fetched from the NordVPN API on every connect (how to get one). |
| Variable | Default | Description |
|---|---|---|
COUNTRY | — | Countries to pick servers from: names, codes, IDs, or specific server hostnames (list). |
CITY | — | Cities: names, IDs, or specific server hostnames (list). |
GROUP | — | Server group, e.g. legacy_p2p or legacy_double_vpn (list, details). |
RANDOM_TOP | 0 | Shuffle the top N servers of the filtered pool before picking one. |
| Variable | Default | Description |
|---|---|---|
DNS | 103.86.96.100;103.86.99.100 | Resolvers written to resolv.conf after the tunnel comes up; resolution goes through the tunnel. |
| Variable | Default | Description |
|---|---|---|
RECREATE_VPN_CRON | (disabled) | Cron schedule for switching to a new server, e.g. 0 */6 * * *. |
CHECK_CONNECTION_CRON | (disabled) | Cron schedule for the connectivity check that reconnects on failure. |
CHECK_CONNECTION_URL | https://www.google.com | URL(s) probed through the tunnel by the check and by the Docker HEALTHCHECK. |
CHECK_CONNECTION_ATTEMPTS | 5 | Failed attempts before the check declares the tunnel dead and reconnects. |
CHECK_CONNECTION_ATTEMPT_INTERVAL | 10 | Seconds between attempts. |
HEALTHCHECK_ENABLED | false | true = the Docker HEALTHCHECK probes wg0 and CHECK_CONNECTION_URL instead of always reporting healthy (details). |
| Variable | Default | Description |
|---|---|---|
NETWORK | — | LAN / inter-container IPv4 CIDRs allowed to bypass the tunnel (routes + firewall), e.g. 192.168.1.0/24. |
| Variable | Default | Description |
|---|---|---|
FORWARD_FROM | — | Downstream IPv4 CIDRs allowed to route out through the tunnel; traffic must arrive already SNATed into these nets. |
GATEWAY_DNS | off | Client DNS interception for FORWARD_FROM sources: redirect (the DNS resolvers, through the tunnel) | local (co-located resolver) | forward (GATEWAY_DNS_SERVER) | off (details). |
GATEWAY_DNS_SERVER | — | External IPv4 resolver(s) for GATEWAY_DNS=forward, reached directly over the uplink, not through the tunnel; the first one answering a probe at startup is used. |
TTL_SET | (unset) | Rewrite the TTL of traffic leaving through the tunnel (1–255, e.g. 64); hides every hop behind this container from client traceroutes (details). |
TTL_INC | (unset) | Add to the TTL of traffic arriving on eth0 (1–255, e.g. 1) so this container disappears from client traceroutes; needs FORWARD_FROM (details). |
| Variable | Default | Description |
|---|---|---|
NETWORK_DIAGNOSTIC_ENABLED | false | Run the built-in network diagnostic after every connect (details). |
NORDVPNAPI_IP | 104.16.208.203;104.19.159.190 | IPs used for all NordVPN API access (no DNS involved); each also gets a host route out eth0 so the API stays reachable with the tunnel down. |
ALLOW_MISSING_IPTABLES_RULES | false | Tolerate failures applying wg-quick's anti-leak iptables rules on kernels lacking the netfilter modules (e.g. Synology DSM); the container's own kill switch stays active (details). |
--cap-add=NET_ADMIN and --sysctl net.ipv4.conf.all.src_valid_mark=1 (or privileged: true) — see Permissionswireguard module); without it the container falls back to userspace wireguard-go, which additionally needs --device /dev/net/tun and is slower (details)net.ipv4.ip_forward=1 on this container and on the downstream one (details)If you have any problems with or questions about this image, please open a GitHub issue.
Check the Troubleshooting and FAQ wiki pages first. For how the container works under the hood, see Architecture and Internals.
Content type
Image
Digest
sha256:860b8771e…
Size
16.2 MB
Last updated
9 days ago
docker pull azinchen/nordvpn-wg