Sign inSign up

azinchen/nordvpn-wg

By azinchen

•Updated 8 days ago

Image
0

10K+

azinchen/nordvpn-wg repository overview

logo

⁠NordVPN WireGuard Docker Container

GitHub release GitHub release date GitHub build
GitHub stars GitHub forks Open issues GitHub last commit
Docker pulls Docker stars Docker image size
Multi-arch

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.

⁠✨ Key Features

  • 🚀 Easy Setup — Route any container through the VPN with --net=container:vpn
  • ⚡ NordLynx (WireGuard) — Fast, modern tunnel to NordVPN's WireGuard servers
  • 🔑 Token-Based Setup — One access token; the key is fetched for you (details⁠)
  • 🌍 Smart Server Selection — Filter by country, city, group, or hostname (details⁠)
  • ⚖️ Load Balancing — Prefers the least-loaded servers across locations
  • 🔄 Auto-Reconnection — Scheduled server rotation and health checks (details⁠)
  • 🛡️ Kill Switch — Default-deny firewall: no VPN, no traffic (details⁠)
  • 🏠 Local/LAN Access — Open specific CIDRs with NETWORK (details⁠)
  • 🧭 Custom DNS — Tunnel DNS by default; override with DNS (details⁠)
  • 📵 IPv6 Firewall — IPv6 chains default to DROP (details⁠)
  • 🧱 iptables Compatibility — Auto-selects the nft or legacy backend (details⁠)
  • 🧬 Userspace Fallback — wireguard-go when the kernel lacks WireGuard (details⁠)
  • 🚪 VPN Gateway Mode — Route downstream subnets via FORWARD_FROM (details⁠)

📖 Full documentation on the Wiki⁠ — configuration guides, examples, troubleshooting, FAQ, and architecture.


⁠Quick Start

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

⁠Requirements
  • Docker with --cap-add=NET_ADMIN and --sysctl net.ipv4.conf.all.src_valid_mark=1 (or privileged: true)
  • A Linux kernel with WireGuard support — 5.6+ (built in) or the wireguard module loaded on the host. On kernels without the module, the container automatically falls back to userspace WireGuard (wireguard-go); that fallback additionally requires --device /dev/net/tun (not needed when the kernel module is available) and is slower than kernel WireGuard.
  • A NordVPN access token (not your regular account login)
⁠Getting a Token
  1. Log into your Nord Account Dashboard⁠
  2. Click NordVPN → Manual setup and complete verification
  3. Generate a new access token and copy it
  4. Pass it as TOKEN — the container reads your NordLynx (WireGuard) key from the NordVPN API on every connect

Note: 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.

⁠Docker Compose Example

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⁠

⁠Environment Variables

List values (countries, cities, CIDRs, URLs, IPs) accept ; or , as separators; whitespace around separators is ignored.

⁠Credentials

NordVPN access token — see Getting a Token⁠ above.

VariableDetails
TOKENRequired — NordVPN access token; used to fetch your WireGuard key from the API.
⁠Server Selection

Pick which servers to connect to; filters combine to narrow the pool. See Server Selection⁠.

VariableDetails
COUNTRYFilter by countries: names, codes, IDs, or server hostnames (list⁠).
CITYFilter by cities: names, IDs, or server hostnames (list⁠).
GROUPFilter by server group (list⁠, details⁠).
RANDOM_TOPRandomize top N servers. Default: 0
⁠Tunnel & DNS

DNS resolution through the tunnel. See Custom DNS⁠.

VariableDetails
DNSDNS servers written to resolv.conf (resolution goes through the tunnel). Default: 103.86.96.100;103.86.99.100
⁠Reconnection & Health Monitoring

Rotate servers on a schedule and verify the tunnel actually works. See Automatic Reconnection⁠.

VariableDetails
RECREATE_VPN_CRONServer switching schedule (cron). Default: disabled
CHECK_CONNECTION_CRONHealth monitoring schedule (cron). Default: disabled
CHECK_CONNECTION_URLURLs to test connectivity. Default: https://www.google.com
CHECK_CONNECTION_ATTEMPTSConnection test retry count. Default: 5
CHECK_CONNECTION_ATTEMPT_INTERVALSeconds between retries. Default: 10
HEALTHCHECK_ENABLEDEnable the Docker HEALTHCHECK probe (checks wg0 + connectivity via CHECK_CONNECTION_URL). When false, the container always reports healthy. Default: false
⁠Local Network & VPN Gateway

Open the kill‑switch firewall for LAN access and downstream routing. See Local Network Access⁠ and VPN Gateway Mode⁠.

VariableDetails
NETWORKLAN/inter‑container CIDRs to allow. Default: none
FORWARD_FROMDownstream CIDRs allowed to route OUT through the tunnel (gateway mode). Traffic must arrive already SNATed into these nets. Default: none
GATEWAY_DNSDNS interception for FORWARD_FROM clients: redirect (DNAT port 53 to the VPN resolvers from DNS, through the tunnel), local (DNAT port 53 to this container, for a co‑located resolver such as AdGuard Home), forward (DNAT port 53 to GATEWAY_DNS_SERVER, reached directly over the uplink — not through the tunnel), off. Default: off
GATEWAY_DNS_SERVERExternal IPv4 resolver(s) for GATEWAY_DNS=forward (e.g. an AdGuard Home on your LAN). With a list, the first resolver answering a DNS probe at startup is used. Default: none
TTL_SETRewrite the TTL of traffic leaving through the tunnel (e.g. 64); normalizes the value the VPN exit sees and hides every hop behind this container from client traceroutes (details⁠). Integer 1–255. Default: unset
TTL_INCIncrement the TTL of traffic arriving on eth0 (e.g. 1), cancelling this container's own decrement so it disappears from client traceroutes (details⁠). Needs FORWARD_FROM. Integer 1–255. Default: unset
⁠Advanced

Low‑level settings; the defaults work for most setups.

VariableDetails
NORDVPNAPI_IPAPI bootstrap IPs. Default: 104.16.208.203;104.19.159.190
NETWORK_DIAGNOSTIC_ENABLEDEnable network diagnostics on connect (details⁠). Default: false
ALLOW_MISSING_IPTABLES_RULESTolerate failures applying wg-quick's anti-leak iptables rules — needed on hosts whose kernel lacks the required netfilter modules (e.g. Synology DSM), where the tunnel would otherwise be torn down. The container's own default-DROP kill switch stays active. See Firewall Backends⁠. Default: false

⁠Issues

If you have any problems with or questions about this image, please contact me through a GitHub issue⁠ or email⁠.

Check the Troubleshooting⁠ and FAQ⁠ wiki pages first.

Tag summary

Content type

Image

Digest

sha256:5b0eb3820…

Size

16.2 MB

Last updated

8 days ago

docker pull azinchen/nordvpn-wg