Fix Slow or Bursty Speed in Pangolin When Using Newt Tunnels

Guide: Fix Slow or Bursty Speed in Pangolin When Using Newt Tunnels

Many users have problems with slow speeds or “bursty” behavior (fast at first, then stalls or buffering) when using Newt sites in Pangolin. This happens a lot with streaming videos, big file downloads, or long connections. Short connections or low-speed flows are usually fine.

The main reasons from the discussion:

  • Newt runs in user space, so it can be slower under heavy load.
  • Problems with how packets are split (fragmentation) and MTU settings cause stalls.
  • Other things like Docker overhead can make it worse.

The best fix that worked for many users is to switch to a Basic WireGuard Site. This uses the normal kernel WireGuard, which is faster and more stable for big data flows.

Here is a step-by-step guide to set it up. Follow carefully.

Step 1: Create a Basic WireGuard Site in Pangolin

  • Go to your Pangolin dashboard.

  • Create a new Site and choose Basic WireGuard type (not Newt).

  • Pangolin will give you a WireGuard config file (like wg0.conf).

  • On your home network (where your services run), set up WireGuard on a gateway. This can be:

    • A Linux host machine
    • A VM
    • An LXC container
    • Or a Docker container (see special notes below if using a container as the peer)
  • Bring up the tunnel: wg-quick up wg0 (or the file name given).

  • Check if it connects: wg show

    • You should see a handshake and data transfer.
  • Note: On the Pangolin server side, the WireGuard interface (wg0) often runs inside the gerbil Docker container. You can check it with:

    docker exec -it gerbil ip -br addr
    
    • Look for wg0 with an IP like 100.89.x.x/24.

Step 2: Point Your Resource to the WireGuard Peer IP

  • In Pangolin, edit your resource (the service you want to access).
  • Set the Target/Upstream to the WireGuard IP of your home gateway peer, not your local LAN IP.
    • Example: https://100.89.x.x:PORT (use the peer IP from your config).
  • Do NOT use your home LAN IP like 192.168.x.x directly.

Step 3: Set Up Routing and Rules on Your Home WireGuard Peer

  • Edit the WireGuard config file on your peer (/etc/wireguard/wg0.conf or wherever you saved it).
  • Add these lines (replace placeholders):
    • <WG_PEER_IP_CIDR>: Your WireGuard IP with subnet, like 100.89.x.x/32
    • <TARGET_IP>: The real LAN IP of your service (or Docker host IP if service is in Docker)
    • <PORT>: The port your service uses
    • eth0: Your main network interface (change if different; in Docker, it might be different – see below)
[Interface]
Address = <WG_PEER_IP_CIDR>
PrivateKey = your_private_key_here
MTU = 1280   # Important! Keeps it low to avoid problems

PostUp = sysctl -w net.ipv4.ip_forward=1
PostUp = iptables -t nat -A PREROUTING -i %i -p tcp --dport <PORT> -j DNAT --to-destination <TARGET_IP>:<PORT>
PostUp = iptables -t nat -A POSTROUTING -o eth0 -p tcp -d <TARGET_IP> --dport <PORT> -j MASQUERADE
PostUp = iptables -A FORWARD -i %i -o eth0 -p tcp -d <TARGET_IP> --dport <PORT> -j ACCEPT
PostUp = iptables -A FORWARD -i eth0 -o %i -p tcp -s <TARGET_IP> --sport <PORT> -j ACCEPT

# This fixes the stall problem
PostUp = iptables -t mangle -A FORWARD -i %i -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
PostUp = iptables -t mangle -A FORWARD -o %i -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu

# Cleanup when WireGuard stops
PostDown = iptables -t nat -D PREROUTING -i %i -p tcp --dport <PORT> -j DNAT --to-destination <TARGET_IP>:<PORT>
PostDown = iptables -t nat -D POSTROUTING -o eth0 -p tcp -d <TARGET_IP> --dport <PORT> -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -o eth0 -p tcp -d <TARGET_IP> --dport <PORT> -j ACCEPT
PostDown = iptables -D FORWARD -i eth0 -o %i -p tcp -s <TARGET_IP> --sport <PORT> -j ACCEPT
PostDown = iptables -t mangle -D FORWARD -i %i -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
PostDown = iptables -t mangle -D FORWARD -o %i -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
  • Save and restart: wg-quick down wg0 && wg-quick up wg0

If You Are Using a WireGuard Sidecar Container as the Peer

Some users run the WireGuard peer inside a Docker container (called a “sidecar” setup). This is common if your services are in Docker.

  • Run a lightweight WireGuard container with NET_ADMIN capability.
  • Example using a popular image like linuxserver/wireguard or a simple one:
    docker run -d \
      --name=wg-peer \
      --cap-add=NET_ADMIN \
      --cap-add=NET_RAW \
      -v /path/to/wg0.conf:/config/wg0.conf \
      -e PUID=1000 -e PGID=1000 \
      linuxserver/wireguard
    
  • Or use wg-quick in a custom container.
  • Important changes:
    • The outgoing interface (%o) may not be “eth0”. Check inside the container: ip link
    • Replace “eth0” in PostUp/PostDown with the correct one (often “eth0” still works, but test).
    • For forwarding to work, the container needs access to the host network or Docker network.
    • Best option: Use --network=host for the WireGuard container so it can forward to your services easily.
    • If services are in other containers, use Docker networks or host networking.
    • iptables rules go inside the container (add them to the config as shown).

This container setup works like a VM/LXC but inside Docker. Test the rules carefully.

Step 4: Make It Start Automatically

  • If on host/VM/LXC: systemctl enable --now wg-quick@wg0
  • If in Docker: Use --restart unless-stopped in your docker run/compose.

Step 5: Check Everything Works

  • MTU should stay at 1280:
    • Run: ip -d link show wg0 | grep mtu (or inside container: docker exec …)
    • If it changes to 1420, stalls may come back.
  • Check rules:
    • iptables -t nat -S | grep <PORT>
    • iptables -t mangle -S | grep TCPMSS
  • Test your service through Pangolin. Speeds should be steady, no bursts or stalls.

Extra Tips

  • If you have many services, add more DNAT lines for each port.
  • This setup uses kernel WireGuard, so it handles high speeds better than Newt.
  • If you still have issues, check your VPS bandwidth, ISP, or try a different VPS location.
  • Newt may get better in future updates, but this fix works well now.

This should give you smooth, fast access. The sidecar container option is great if you already use Docker a lot. If you need help with a specific part, ask!

So is this also possible within unifi? I’ve allready a wireguard server running there and can also connect to peers.

I saw this reddit post seems to me a viable option as well.

1 Like

Yes I have it running since last week with no issues.
Just make sure you have it on a seperate vlan so if vps gets compromised your home firewall is not affected.

1 Like

Oke thanks. Is the reddit post a good example as in the firewall rules?

Create firewall and NAT rules in UniFi

I used the new firewall interface in the UniFi Policy Engine. You’ll need three rules:

Rule 1 — Firewall allow

Path: Policy Engine → Firewall → Create Policy

Name: Allow_WG_HTTP

Source Zone: External → IP → Specific → (use the IP shown in AllowedIPs — in my case 100.89.128.1/32)

Port: Any

Action: Allow

Destination Zone: Internal → Any → Port: Any

Enable Auto Allow Return Traffic.

Leave other settings default and save.

Rule 2 — DNAT (port forward into LAN host)

Path: Policy Engine → NAT → Create New

Name: WG_HTTP_

Type: Destination NAT

Interface/VPN Tunnel: select your WireGuard client

Translated IP: the LAN host you’re trying to reach (e.g. 192.168.8.19)

Translated Port: the service port on that host (e.g. 80)

Protocol: TCP (or TCP/UDP if needed)

Source: Any → Port: Any

Destination: Any → Port: (choose an unused port — this is what you’ll connect to via the WireGuard client, e.g. 8080)

Save with default

1 Like

Deployment Structure with Separate VLAN for All Services

All services run on hosts in isolated Exposed VLAN (DMZ style). No hosts in Main LAN except trusted devices.

1. Network Setup

  • Main LAN: VLAN 1, 192.168.1.0/24 (devices, IoT if separate)
  • Exposed VLAN: New network
    • Name: Exposed_Services
    • VLAN ID: 20 (example)
    • Subnet: 192.168.20.0/24
    • Gateway: UniFi gateway
    • DHCP: Enable
    • All self-hosted services here (Docker host, Proxmox, TrueNAS, etc.)
    • Hosts get IP e.g. 192.168.20.10-50

Block inter-VLAN by default.

2. WireGuard Client (Pangolin)

Same import.
Peer IP: e.g. 100.89.128.1/32 (AllowedIPs)

Incoming traffic from External zone.

3. DNAT Rules (Policy Engine > NAT > Destination NAT)

One rule per service needed from remote.

Interface: Your WG tunnel

Source: Any (or peer /32)

Protocol: TCP (most cases; UDP for some)

Destination Port: High unique external (50000+ range, avoid overlap)

Translated IP: Service host in Exposed VLAN (e.g. 192.168.20.50)

Translated Port: Internal default

Recommended External Ports (high to hide; change if conflict)

Service Internal Port Suggested External Port Protocol Notes
Immich 2283 50283 TCP Web UI
Jellyfin 8096 508096 TCP
Plex 32400 532400 TCP Avoid if direct share
Home Assistant 8123 508123 TCP
Nextcloud 443 50443 TCP HTTPS
Vaultwarden 8080 508080 TCP
Proxmox 8006 58006 TCP Web UI
TrueNAS 443 50444 TCP HTTPS
Grafana 3000 503000 TCP
Portainer 9443 59443 TCP HTTPS
Pi-hole 80 50080 TCP Web; DNS UDP 53 separate if needed
Paperless-ngx 8000 508000 TCP
Gitea 3000 503001 TCP
Sonarr 8989 58989 TCP
Radarr 7878 57878 TCP
PostgreSQL 5432 Block or 55432 if remote TCP Avoid expose DB
MySQL 3306 Block or 53306 TCP Avoid
Redis 6379 Block TCP Internal only
SSH 22 Block or 50022 TCP High risk
SMB 445 Block TCP High risk
RDP 3389 Block TCP High risk

Important: Block databases (PostgreSQL, MySQL, Redis), SSH, SMB, RDP from remote unless critical. Use only internal or add auth.

Create only needed DNAT. DNAT allows init from tunnel, stateful return.

4. Firewall Rules (Policy Engine > Firewall)

No broad allow External to Internal/Exposed.

Stateful handles return.

Isolation rules:

  • Policy: Exposed to Main LAN

    • Source Zone: Exposed
    • Dest Zone: Main/Internal
    • Action: Drop
    • High priority
  • If need Main access Exposed (management): Specific allow Main to Exposed, ports (e.g. SSH 22 from Main IPs)

No extra allow needed for WG → Exposed (DNAT triggers).

5. ATMS Exceptions

Enable IDS/IPS High.

Add exceptions:

  • Source: Peer IP /32
  • Dest Ports: All your external DNAT ports
  • Or Dest: Exposed subnet

6. my Recommendations

  • Put all services behind reverse proxy (Traefik/Nginx) in Exposed VLAN if possible. Expose only proxy ports.
  • No Traffic Routes on WG.
  • Test: From Pangolin client, reach only DNAT external ports → services. All else block.
  • Monitor traffic on peer IP.

This minimal exposure. Only explicit services reachable via tunnel. Adjust ports as needed.

1 Like

do we still need all the PostUp and PostDown lines in the config when using unifi wireguard setup?

I don’t need it in my unifi fiber router

I managed to create one page using the Wireguard tunnel. This resulted in noticeable differences in performance. Following up on this success, I wanted to create another such page. Unfortunately, creating another tunnel also changed the IP address of the previous tunnel. Instead of

Address = 100.89.128.24/30
ListenPort = 51820
PrivateKey = ••••••••••••••••••••••••••••••••••••••••••••

the address

Address = 100.89.128.28/30
ListenPort = 51820
PrivateKey = ••••••••••••••••••••••••••••••••••••••••••••

After that, both tunnels stopped working. After making a few changes, I managed to restore one of the tunnels.

Does anyone know how to run two parallel tunnels?