Secure NordVPN gateway container with auto reconnect and killswitch.
4.6K
βΉοΈ Under the hood: Based on NordVPN Linux Client 4.6.0
A stable, self-healing, and intelligent Docker container that turns your host into a secure NordVPN gateway for other containers and your entire LAN. It supports WireGuard server integration, DNS over VPN via AdGuard Home, and SOCKS5 / HTTP proxies, all routed through NordVPN.
VPN_AUTO_CONNECT=best sends burst pings (0.2s interval) to recommended servers. It strictly filters for 0% packet loss and selects the target with the lowest average latency.SPEED_TEST_URL) to accurately measure high-speed lines where TCP slow-start distorts results.103.86.96.100) is enforced to prevent leaks.Since all services share the VPN network stack, they are accessible via the Gateway IP (not localhost).
| Service | Port | Description | Usage Example |
|---|---|---|---|
| SOCKS5 Proxy | 1080 | Secure proxy for browsers/apps. | curl -x socks5h://GATEWAY_IP:1080 ipinfo.io |
| HTTP Proxy | 8118 | Privoxy HTTP proxy with ad-blocking. | curl -x http://GATEWAY_IP:8118 ipinfo.io |
| AdGuard Home | 80 / 3000 | DNS Server & Web Interface. | Open http://GATEWAY_IP:80 (or 3000 for setup) |
| WireGuard | 51820 | UDP Port for VPN Clients (wg-easy). | Configure in Router Port Forwarding. |
| wg-easy UI | 51821 | WireGuard Web Admin UI. | Open http://WG_SERVER_IP:51821 (Note: Has its own IP) |
Instead of manually writing complex YAML, you can use the visual generator: π boingbasti/nordvpn-gateway-configuratorβ
It provides: β UI selection of gateway mode (Simple vs. Advanced) β Gigabit Support (100MB Speedtest option) β Dual Routing Hooks (LAN Access vs. Strict Isolation) β Automatic calculation of routing rules
Run locally:
docker run -d \
--name nordvpn-config-gen \
-p 8080:80 \
boingbasti/nordvpn-gateway-configurator:latest
Then visit: http://localhost:8080β
Creates a SOCKS5 proxy routed fully through the VPN. No special network setup required.
services:
vpn:
image: boingbasti/nordvpn-gateway:latest
container_name: nordvpn
cap_add:
- NET_ADMIN
- NET_RAW
devices:
- /dev/net/tun
volumes:
- ./nordvpn_token.txt:/run/secrets/nordvpn_token:ro
- /etc/localtime:/etc/localtime:ro
environment:
- VPN_TECHNOLOGY=NordLynx
- VPN_COUNTRY=Germany
- VPN_AUTO_CONNECT=best
- KILLSWITCH=on
restart: unless-stopped
socks5:
image: boingbasti/nordvpn-socks5:latest
container_name: nordvpn-socks5
network_mode: "service:vpn"
depends_on:
- vpn
environment:
- PROXY_PORT=1080
- ALLOWED_IPS=192.168.1.0/24
restart: unless-stopped
1. Create the network once:
docker network create -d macvlan \
--subnet=192.168.1.0/24 \
--gateway=192.168.1.1 \
-o parent=eth0 \
vpn_gateway_net
2. Compose:
services:
vpn:
image: boingbasti/nordvpn-gateway:latest
container_name: nordvpn-gateway
networks:
vpn_gateway_net:
ipv4_address: 192.168.1.100
cap_add:
- NET_ADMIN
- NET_RAW
devices:
- /dev/net/tun
volumes:
- ./nordvpn_token.txt:/run/secrets/nordvpn_token:ro
- /etc/localtime:/etc/localtime:ro
environment:
- VPN_COUNTRY=Germany
- VPN_AUTO_CONNECT=best
- KILLSWITCH=on
- ALLOWLIST_SUBNET=192.168.1.0/24
- VPN_MTU=auto
sysctls:
- net.ipv4.ip_forward=1
restart: unless-stopped
networks:
vpn_gateway_net:
external: true
Includes: Gateway + WireGuard Server (wg-easy) + AdGuard Home + Proxies.
services:
vpn:
image: boingbasti/nordvpn-gateway:latest
container_name: nordvpn
networks:
vpn_gateway_net:
ipv4_address: 192.168.1.100
stop_grace_period: 45s
cap_add: [NET_ADMIN, NET_RAW]
devices: [/dev/net/tun]
volumes:
- ./nordvpn_token.txt:/run/secrets/nordvpn_token:ro
- /etc/localtime:/etc/localtime:ro
environment:
- VPN_COUNTRY=Germany
- VPN_AUTO_CONNECT=best
- KILLSWITCH=on
- ALLOWLIST_SUBNET=192.168.1.0/24,10.10.10.0/24
- VPN_MTU=auto
# WireGuard Bypass
- WIREGUARD_BYPASS=on
- WIREGUARD_SERVER_IP=192.168.1.200
- WIREGUARD_SUBNET=10.10.10.0/24
sysctls:
- net.ipv4.ip_forward=1
- net.ipv6.conf.all.disable_ipv6=1
- net.ipv6.conf.default.disable_ipv6=1
restart: unless-stopped
wg-easy:
image: ghcr.io/wg-easy/wg-easy:15
container_name: wg-easy
networks:
vpn_gateway_net:
ipv4_address: 192.168.1.200
depends_on: [vpn]
cap_add: [NET_ADMIN, SYS_MODULE]
volumes:
- ./wg-easy-config:/etc/wireguard
- /lib/modules:/lib/modules:ro
environment:
- DISABLE_IPV6=true
- INSECURE=true
sysctls:
- net.ipv6.conf.all.disable_ipv6=1
restart: unless-stopped
socks5:
image: boingbasti/nordvpn-socks5:latest
network_mode: "service:vpn"
depends_on: [vpn]
environment:
- PROXY_PORT=1080
- ALLOWED_IPS=192.168.1.0/24
restart: unless-stopped
privoxy:
image: boingbasti/nordvpn-privoxy:latest
network_mode: "service:vpn"
depends_on: [vpn]
restart: unless-stopped
adguardhome:
image: adguard/adguardhome:latest
network_mode: "service:vpn"
depends_on: [vpn]
volumes:
- ./adguard-work:/opt/adguardhome/work
- ./adguard-config:/opt/adguardhome/conf
restart: unless-stopped
networks:
vpn_gateway_net:
external: true
| Variable | Default | Description |
|---|---|---|
NORDVPN_TOKEN | required | Auth token (use secret mount if possible). |
VPN_COUNTRY | Germany | Target region. |
VPN_GROUP | p2p | Server group. Use standard for normal servers. |
VPN_SERVER | (unset) | Specific server (e.g. de1234). Overrides group. |
VPN_TECHNOLOGY | NordLynx | NordLynx or OpenVPN. |
PROTOCOL | (unset) | udp / tcp (OpenVPN only). |
CONNECT_TIMEOUT | 60 | Connection timeout in seconds. |
| Variable | Default | Example | Description |
|---|---|---|---|
ALLOWLIST_SUBNET | (unset) | 192.168.1.0/24,10.10.10.0/24 | Subnets allowed to route through VPN. |
VPN_MTU | auto | 1360 | Auto binary MTU detection or fixed value. |
| Variable | Default | Example | Description |
|---|---|---|---|
THREAT_PROTECTION_LITE | off | on | Enables DNS-based blocking of ads & threats. |
KILLSWITCH | on | on | Drop all non-VPN traffic to prevent leaks. |
LAN_DISCOVERY | off | on | Allow access to local network devices while killswitch is active. Alternative to ALLOWLIST_SUBNET for simple setups. |
POST_QUANTUM | on | off | Enable/disable post-quantum encryption support. |
| Variable | Default | Example | Description |
|---|---|---|---|
WIREGUARD_BYPASS | off | on | Enable routing exception for WG handshake. |
WIREGUARD_SERVER_IP | (unset) | 192.168.179.229 | LAN IP of WireGuard server. |
WIREGUARD_SUBNET | (unset) | 10.10.10.0/24 | Client subnet behind wg-easy. |
SHOW_WGHOOKS | off | on | Display suggested PostUp/PostDown hooks. |
| Variable | Default | Example | Description |
|---|---|---|---|
VPN_AUTO_CONNECT | off | best | Select best server by latency & quality. |
VPN_BEST_SERVER_CHECK_INTERVAL | 30 | 15 | Minutes between bestβserver refresh. |
VPN_SPEED_CHECK_INTERVAL | 0 | 60 | Minutes between throughput checks. |
VPN_MIN_SPEED | 5 | 20 | Minimum Mbit/s before rotating to next candidate. |
SPEED_TEST_URL | http://cachefly.cachefly.net/10mb.test | http://cachefly.../100mb.test | URL for speed tests. Use 100MB file for Gigabit lines. |
CHECK_INTERVAL | 60 | 30 | Loop check frequency (seconds). |
RETRY_COUNT | 2 | 3 | Retry attempts before reconnect. |
RETRY_DELAY | 2 | 2 | Seconds between retries. |
VPN_REFRESH | 0 | 1440 | Forces periodic reconnect to rotate public IP. |
| Variable | Default | Example | Description |
|---|---|---|---|
LOG_STATUS_INTERVAL | 0 | 60 | Minutes between status logs (0=disabled). |
DEBUG | off | on | Enable verbose logging. |
SPEED_TEST_URL to a 100MB file (e.g., Cachefly or Hetzner) and increase VPN_SPEED_CHECK_INTERVAL to 60 min to save traffic.VPN_AUTO_CONNECT=off. This lets NordVPN load-balancing decide instead of relying purely on ping.-o parent=eth0 adjusted to your host.WIREGUARD_BYPASS=on and verify WIREGUARD_SERVER_IP.MIT
Content type
Image
Digest
sha256:a8ec3bfe8β¦
Size
98.1 MB
Last updated
4 days ago
docker pull boingbasti/nordvpn-gateway