80/443 for Traefik HTTPS, 51820/UDP for Newt WireGuard tunnel
wg-easy
51820/UDP, 51821/TCP
UDP/TCP
51820 is WireGuard VPN, 51821 is wg-easy web UI
Since Pangolin also uses 51820/UDP for its own WireGuard tunnels, you must remap wg-easy’s WireGuard port to avoid conflicts (e.g., 51830/udp in gerbil/traefik).
3. Docker Network Setup
To let Pangolin and wg-easy talk without exposing raw ports, attach them to a shared Docker network.
which is `pangolin` network
4. Example docker-compose.yml
Here’s a minimal stack for wg-easy alongside Pangolin:
volumes:
etc_wireguard:
networks:
pangolin:
external: true # use Pangolin's existing network
services:
wg-easy:
image: ghcr.io/wg-easy/wg-easy:15
container_name: wg-easy
cap_add:
- NET_ADMIN
- SYS_MODULE
environment:
- WG_HOST=vpn.development.hhf.technology
# Run this in the container to get which interface: `ip route get 8.8.8.8 | awk '{print $5}'`
- WG_DEVICE=eth0
- WG_PORT=51830
- PORT=51821
- DISABLE_IPV6=true
- WG_ALLOWED_IPS=0.0.0.0/0, 1.1.1.1/32
- LANG=en
- WG_PERSISTENT_KEEPALIVE=25
- UI_TRAFFIC_STATS=true
- UI_CHART_TYPE=1
expose:
- "51830/udp" # Exposes UDP port
- "51821/tcp" # Exposes TCP port
volumes:
- ./etc_wireguard:/etc/wireguard
- ./lib/modules:/lib/modules:ro
restart: unless-stopped
sysctls:
- net.ipv4.ip_forward=1
- net.ipv4.conf.all.src_valid_mark=1
# - net.ipv6.conf.all.disable_ipv6=0
- net.ipv6.conf.all.forwarding=1
- net.ipv6.conf.default.forwarding=1
networks:
- pangolin
5. Exposing wg-easy via Pangolin
Step A: Add wg-easy to Pangolin’s network
If Pangolin is already running, attach wg-easy to the same external network (pangolin).
docker network connect pangolin wg-easy
Step B: Create a Local Site in Pangolin
Go to Sites → Add Site → Local
Name: wg-local
Step C: Add Resources
Web UI (HTTPS via Traefik)
Resource → Add Resource
Target: http://wg-easy:51821
Subdomain: vpn.example.com
Method: http
Enable TLS (Let’s Encrypt auto certs via Traefik).
yes it will still work, then you will have to put port reference in traefik.
services:
traefik:
image: traefik:v3.0 # Or your desired Traefik version
container_name: traefik
ports:
- "80:80"
- "443:443"
- "8080:8080" # Traefik Dashboard
- "51820:51820/udp" # Custom UDP port
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik_dynamic:/etc/traefik/dynamic # Mount the dynamic config directory
networks:
- pangolin
networks:
pangolin:
external: true # Or define it here if not already existing
UDP port change not required because there is no gerbil. you can use default wg-eazy ports
Do you mean I should change the pangolin compost file so that it exposes on another port (eg: - 51830:51820/udp) ?
Won’t that mess up the connection currently established by the newt on my homelab ?
Can’t I simply set wg-easy to listen on 51830 ? This will be set in the configurations generated for the clients and shouldn’t be problematic (although not standard for wireguard but who cares ?).
I mean:
volumes:
etc_wireguard:
networks:
pangolin:
external: true # use Pangolin's existing network
services:
wg-easy:
image: ghcr.io/wg-easy/wg-easy:15
container_name: wg-easy
cap_add:
- NET_ADMIN
- SYS_MODULE
environment:
- WG_HOST=vpn.example.com # your domain
- PASSWORD=supersecurepassword # UI password
- WG_PORT=51830 # WireGuard port set to 51830 to avoid conflict with gerbil
- WG_DEFAULT_DNS=1.1.1.1
volumes:
- etc_wireguard:/etc/wireguard
- /lib/modules:/lib/modules:ro
expose:
- "51830/udp" # WireGuard VPN (51530 to avoid conflict with gerbil)
- "51821/tcp" # Web UI (local only, proxied via Pangolin)
restart: unless-stopped
sysctls:
- net.ipv4.ip_forward=1
- net.ipv4.conf.all.src_valid_mark=1
- net.ipv6.conf.all.disable_ipv6=0
- net.ipv6.conf.all.forwarding=1
- net.ipv6.conf.default.forwarding=1
networks:
- pangolin
Thanks for the very detailed guide. I’ve tried your suggested setup, but wireguard client can’t access internet. I’ve opened port 51830/udp on Oracle VPS.
So far I’ve tried these setup combinations:
WG_PORT=51820, expose 51820/udp; pangolin resource: TCP public 51830 –> wg-easy 51820: no internet (using your suggested setup)
WG_PORT=51830, expose 51830/udp; pangolin resource: TCP public 51830 –> wg-easy 51830: no internet
WG_PORT=51830, ports 51830:51830/udp; pangolin resource: TCP public 51830 –> wg-easy 51830: working with internet access.
I’m not sure why your suggested setup doesn’t work for me.
I had to comment out all the environment variables before the wg-easy container wanted to start. with these variables, I always got an error message about migrating from v14 to v15
This guide assumes you are installing WireGuard on a VPS for optimal performance. Although installation on a home network via newt is possible, it may result in slower speeds.
A common use case is running WireGuard alongside Pangolin, which is the scenario this guide has followed
Port Configuration to Avoid Conflicts
If you are running this setup on a VPS, you will likely have Gerbil installed as well. Both Gerbil and WireGuard use the same default network ports, which can cause a conflict. To resolve this, you must change the WireGuard port to 51830/UDP.
An eg. configuration is provided above in the guide, along with a link to a comprehensive guide on adding TCP/UDP resources to your server in pangolin.
Thanks. Everything is working with docker compose above. It is just different from your guide in two parts:
for port 51830, just ‘expose’ it in docker compose + create raw UDP resources with public port 51830 and directs to local site wg-easy (container name) 51830 (container port), doesn’t work for me. I have to map the port to host and don’t need to create UDP resource on Pangolin.