[{"data":1,"prerenderedAt":210},["ShallowReactive",2],{"seo-verification":3,"blog-pangolin-vps-expose-service-behind-nat-en":6},{"google":4,"bing":5},"EycwPY2XMyTkVzas3n1ygeNJFGAH513qrMjfDljzsMQ","",{"key":7,"data":8},"blog-pangolin-vps-expose-service-behind-nat-en",{"id":9,"slug":10,"slugs":11,"title":15,"excerpt":16,"readTime":17,"views":18,"isPinned":19,"publishedAt":20,"updatedAt":21,"category":22,"categories":27,"featuredImage":29,"bgImage":30,"posterImage":31,"relatedSolution":32,"intro":34,"sections":35,"ctaTitle":148,"ctaBody":149,"ctaButton":150,"ctaUrl":151,"relatedPosts":152},357,"pangolin-vps-expose-service-behind-nat",{"fr":12,"en":10,"ar":13,"es":14},"deployer-pangolin-reverse-tunnel-vps","pangolin-vps-nat","pangolin-vps-exponer-servicio-detras-de-nat","Pangolin on VPS: expose a service behind NAT without open ports","Deploy Pangolin and Gerbil on a VPS to create a self-hosted WireGuard relay. Expose any service behind NAT without inbound ports or third-party SaaS.",11,0,false,"2026-09-17T00:00:00+00:00","2026-09-17T14:09:37+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":25},3,"Deployment","deploiement","bg-success\u002F10 text-success",[28],{"id":23,"name":24,"slug":25,"color":26,"icon":25},null,"\u002Fblog\u002Fcovers\u002Fbg.svg","\u002Fblog\u002Fcovers\u002Fdeployer-pangolin-reverse-tunnel-vps-poster.svg",{"categorySlug":33,"appSlug":29},"networking-vpn","You have a service running on a NAS, a Raspberry Pi, or a local VM, and you want it reachable from the Internet — without opening a port on your router, without a static IP, and without handing your traffic over to a third-party SaaS. Pangolin, paired with Gerbil, solves exactly this: a WireGuard relay you operate yourself on a VPS, with automatic HTTPS and a web interface to manage everything.",[36,40,50,53,56,75,90,99,103,106,145],{"type":37,"title":38,"body":39},"h2","The problem: exposing a service behind NAT","Most residential and corporate connections place your machines behind a NAT: no inbound port is reachable from the outside without explicitly configuring your router. And even when that configuration is possible, it opens a direct path into your local network.\n\nReal-world scenarios are common: a Synology NAS running Nextcloud you want to share with clients, a homelab under Proxmox hosting a dozen services, a Raspberry Pi running home automation, or a local development VM you want to test from outside. In all these cases, the usual solution — port forwarding — has two problems: it depends on the router, and it opens a direct path into your private network.\n\nCommon alternatives each have their limits: **Cloudflare Tunnel** passes all your traffic through Cloudflare's servers, raising privacy questions and creating a dependency on their infrastructure. **Tailscale\u002FHeadscale** builds a mesh network between your machines, which is excellent for point-to-point access — but is not designed to publicly expose an HTTP(S) service with a dedicated subdomain. **Pangolin** occupies a different space: a self-hosted WireGuard relay, with certificate and subdomain management, that you control entirely from your VPS.",{"type":41,"title":42,"items":43},"ul","What Pangolin brings over the alternatives",[44,45,46,47,48,49],"**Fully self-hosted** — your traffic only transits through your VPS, no third party sees your application traffic.","**No inbound port required** — the connection is initiated from the origin machine to the VPS (outbound), NAT is never an obstacle.","**Automatic HTTPS via Let's Encrypt** — Pangolin manages certificates for each exposed subdomain, no manual intervention.","**Built-in web interface** — add tunnels, manage resources and users from a web panel, no config files to edit.","**End-to-end WireGuard encryption** — the tunnel between the origin machine and the VPS is encrypted at the transport layer, independently of application HTTPS.","**Multi-site** — a single Pangolin instance on the VPS can relay dozens of services from different machines, under distinct subdomains.",{"type":37,"title":51,"body":52},"Architecture: VPS relay, Gerbil and Newt","Pangolin relies on three components that split responsibilities:\n\n```\n[Origin machine]                   [ServOrbit VPS]              [Internet]\n  service:8080                      Pangolin (orchestration)\n  newt (client)  ←─WireGuard UDP─→  Gerbil  (WG tunnel)    ←─HTTPS──→  visitor\n                                    Traefik (reverse proxy)\n```\n\n**Pangolin** is the control plane: it manages tunnels, subdomains, certificates and users via a REST API and a web interface. It runs on the VPS.\n\n**Gerbil** is the server-side WireGuard peer. It opens a UDP port, establishes tunnels with clients, and routes incoming traffic to exposed services. It also runs on the VPS, alongside Pangolin.\n\n**Newt** is the lightweight client that runs on the origin machine (NAS, Pi, local VM). It contacts Gerbil on the WireGuard UDP port, keeps the tunnel active, and forwards received traffic to the local service on the configured port.\n\nThe concrete flow: a visitor arrives at `nextcloud.yourdomain.com` → Traefik (managed by Pangolin) receives the HTTPS request → forwards it via Gerbil through the active WireGuard tunnel → Newt receives it and relays it to `localhost:8080` on the origin machine. The service responds via the same path in reverse.",{"type":37,"title":54,"body":55},"Prerequisites","On the VPS side:\n- **VPS with root access and a dedicated IPv4** — the `{{vps.start.name}}` plan is enough to get started (1 vCPU, 1 GB RAM for light loads, 2 GB recommended for multiple active tunnels).\n- **Ubuntu 22.04 or 24.04** (Debian 12 also works).\n- **A free UDP port** for WireGuard (default 51820, configurable).\n- **A domain name** with DNS management access — you will need to create a wildcard A record `*.yourdomain.com` pointing to the VPS IP.\n- Docker and Docker Compose installed (`apt install docker.io docker-compose-plugin`).\n\nOn the origin machine side:\n- A Linux machine (Raspberry Pi, NAS running DSM 7+, Proxmox VM, physical server) with outbound UDP access to the WireGuard port on the VPS — most ISPs allow this.\n- A service listening on a local port (Nextcloud, Gitea, Home Assistant, etc.).\n\n**Current version:** Pangolin `1.23.0` (released September 16, 2026).",{"type":57,"title":58,"steps":59},"steps","Deploying Pangolin and Gerbil on the VPS",[60,63,66,69,72],{"title":61,"body":62},"Prepare the VPS and open the WireGuard port","Connect as root to the VPS and install Docker if not already present:\n\n```bash\napt update && apt install -y docker.io docker-compose-plugin ufw\n```\n\nOpen the UDP port for WireGuard (default 51820) and ensure HTTP\u002FHTTPS ports are accessible:\n\n```bash\nufw allow 80\u002Ftcp\nufw allow 443\u002Ftcp\nufw allow 51820\u002Fudp\nufw enable\n```\n\nTo restrict access to the admin panel (default port 3000), limit it to your IP:\n\n```bash\nufw allow from YOUR_IP to any port 3000\n```",{"title":64,"body":65},"Create the docker-compose.yml file","Create a working directory and the configuration file:\n\n```bash\nmkdir -p \u002Fopt\u002Fpangolin && cd \u002Fopt\u002Fpangolin\n```\n\nCreate `docker-compose.yml` with the following content:\n\n```bash\ncat > docker-compose.yml \u003C\u003C'EOF'\nservices:\n  pangolin:\n    image: fosrl\u002Fpangolin:1.23.0\n    container_name: pangolin\n    restart: unless-stopped\n    volumes:\n      - .\u002Fconfig:\u002Fapp\u002Fconfig\n      - .\u002Fdata:\u002Fapp\u002Fdata\n    ports:\n      - \"3000:3000\"\n    networks:\n      - pangolin_net\n\n  gerbil:\n    image: fosrl\u002Fgerbil:latest\n    container_name: gerbil\n    restart: unless-stopped\n    cap_add:\n      - NET_ADMIN\n    volumes:\n      - .\u002Fdata:\u002Fvar\u002Flib\u002Fgerbil\n    ports:\n      - \"51820:51820\u002Fudp\"\n    networks:\n      - pangolin_net\n    depends_on:\n      - pangolin\n\nnetworks:\n  pangolin_net:\n    driver: bridge\nEOF\n```\n\nAdjust the `pangolin` image version number to the latest release available on GitHub.",{"title":67,"body":68},"Configure Pangolin and start the stack","Create the configuration directory and a minimal `config.yml`:\n\n```bash\nmkdir -p \u002Fopt\u002Fpangolin\u002Fconfig\ncat > \u002Fopt\u002Fpangolin\u002Fconfig\u002Fconfig.yml \u003C\u003C'EOF'\napp:\n  base_domain: yourdomain.com\n  admin_email: admin@yourdomain.com\n  port: 3000\n\nwireguard:\n  port: 51820\n  subnet: 10.0.0.0\u002F24\n\nacme:\n  enabled: true\n  staging: false\nEOF\n```\n\nReplace `yourdomain.com` with your actual domain. Start the stack:\n\n```bash\ncd \u002Fopt\u002Fpangolin && docker compose up -d\ndocker compose logs -f pangolin\n```\n\nPangolin generates an admin password on first start — note it from the logs. The web interface is available at `http:\u002F\u002FVPS_IP:3000`.",{"title":70,"body":71},"Configure the wildcard DNS record","In your DNS zone, create a wildcard A record pointing to the VPS IP:\n\n```\n*.yourdomain.com  →  A  →  VPS_IP\n```\n\nOn Cloudflare, create this record with the proxy **disabled** (DNS-only, grey cloud) so that Let's Encrypt certificates can be issued correctly via the HTTP-01 challenge used by Pangolin.",{"title":73,"body":74},"Create a systemd unit for automatic restart","Docker with `restart: unless-stopped` is generally sufficient, but if you prefer a dedicated systemd unit:\n\n```bash\ncat > \u002Fetc\u002Fsystemd\u002Fsystem\u002Fpangolin.service \u003C\u003C'EOF'\n[Unit]\nDescription=Pangolin reverse tunnel stack\nAfter=docker.service\nRequires=docker.service\n\n[Service]\nType=oneshot\nRemainAfterExit=yes\nWorkingDirectory=\u002Fopt\u002Fpangolin\nExecStart=\u002Fusr\u002Fbin\u002Fdocker compose up -d\nExecStop=\u002Fusr\u002Fbin\u002Fdocker compose down\n\n[Install]\nWantedBy=multi-user.target\nEOF\n\nsystemctl daemon-reload\nsystemctl enable pangolin\n```",{"type":57,"title":76,"steps":77},"Adding a tunnel with Newt on the origin machine",[78,81,84,87],{"title":79,"body":80},"Create a tunnel in the Pangolin interface","Log into the Pangolin web interface at `http:\u002F\u002FVPS_IP:3000` with your admin credentials. Go to **Sites → Add site**, give it a name (e.g. `homelab`) and note the generated **site token**. Then under **Resources → Add resource**, choose the site, enter the desired subdomain (`nextcloud.yourdomain.com`) and the local port of the origin machine (e.g. `8080`).",{"title":82,"body":83},"Install Newt on the origin machine","On the machine hosting your service, download the Newt binary for your architecture:\n\n```bash\n# Linux x86_64\ncurl -Lo \u002Fusr\u002Flocal\u002Fbin\u002Fnewt \\\n  https:\u002F\u002Fgithub.com\u002Ffosrl\u002Fnewt\u002Freleases\u002Flatest\u002Fdownload\u002Fnewt-linux-amd64\nchmod +x \u002Fusr\u002Flocal\u002Fbin\u002Fnewt\n```\n\nFor a Raspberry Pi (ARM64):\n\n```bash\ncurl -Lo \u002Fusr\u002Flocal\u002Fbin\u002Fnewt \\\n  https:\u002F\u002Fgithub.com\u002Ffosrl\u002Fnewt\u002Freleases\u002Flatest\u002Fdownload\u002Fnewt-linux-arm64\nchmod +x \u002Fusr\u002Flocal\u002Fbin\u002Fnewt\n```",{"title":85,"body":86},"Configure and start Newt","Launch Newt with the site token retrieved in the previous step:\n\n```bash\nnewt \\\n  --server https:\u002F\u002Fyourdomain.com:3000 \\\n  --token YOUR_SITE_TOKEN \\\n  --target localhost:8080\n```\n\nFor automatic startup, create a systemd unit:\n\n```bash\ncat > \u002Fetc\u002Fsystemd\u002Fsystem\u002Fnewt.service \u003C\u003C'EOF'\n[Unit]\nDescription=Newt WireGuard tunnel client\nAfter=network.target\n\n[Service]\nExecStart=\u002Fusr\u002Flocal\u002Fbin\u002Fnewt \\\n  --server https:\u002F\u002Fyourdomain.com:3000 \\\n  --token YOUR_SITE_TOKEN \\\n  --target localhost:8080\nRestart=always\nRestartSec=5\n\n[Install]\nWantedBy=multi-user.target\nEOF\n\nsystemctl daemon-reload\nsystemctl enable --now newt\n```",{"title":88,"body":89},"Verify end-to-end connectivity","On the VPS, verify that the WireGuard tunnel is established:\n\n```bash\ndocker exec gerbil wg show\n```\n\nYou should see a peer with a recent `latest handshake`. From any browser or command line:\n\n```bash\ncurl -I https:\u002F\u002Fnextcloud.yourdomain.com\n```\n\nExpected response: `HTTP\u002F2 200` (or your service's login page). The Let's Encrypt certificate is issued automatically on first access.",{"type":57,"title":91,"steps":92},"Exposing a service: Nextcloud behind NAT example",[93,96],{"title":94,"body":95},"Configure Nextcloud to accept the proxy domain","Nextcloud blocks requests from undeclared domains. Add the public domain to `config.php`:\n\n```bash\n# From the origin machine, in the Nextcloud directory\nnano config\u002Fconfig.php\n```\n\nAdd to the `trusted_domains` array:\n\n```\n'trusted_domains' =>\n  array (\n    0 => 'localhost',\n    1 => 'nextcloud.yourdomain.com',\n  ),\n'overwritehost' => 'nextcloud.yourdomain.com',\n'overwriteprotocol' => 'https',\n```",{"title":97,"body":98},"Verify public access and certificate","Wait 30 to 60 seconds after first access for Let's Encrypt to issue the certificate, then:\n\n```bash\ncurl -v https:\u002F\u002Fnextcloud.yourdomain.com 2>&1 | grep -E 'subject|issuer|HTTP'\n```\n\nThe certificate is signed by Let's Encrypt and the public URL is now accessible from any network, with no open ports on the local network side.",{"type":100,"title":101,"body":102},"tip","Security: tokens, rotation and access control","**Site token rotation** — generate a new token from the Pangolin interface and update the Newt systemd unit on the origin machine. The old token is immediately invalidated. Schedule this rotation every 90 days or on any personnel change with access to the origin machine.\n\n**IP allowlisting in Pangolin** — for each exposed resource, you can define an IP allowlist under **Resources → Access Policy**. Useful for restricting access to your backoffice or internal tools to your office IP range.\n\n**Authenticated access** — Pangolin supports OIDC providers (Authentik, Keycloak, Zitadel) to add an authentication layer in front of any exposed resource, without modifying the application behind the tunnel.\n\n**Restrict the admin port** — Pangolin's port 3000 must not be publicly accessible. Restrict it to your IP with `ufw allow from YOUR_IP to any port 3000 && ufw deny 3000`.",{"type":37,"title":104,"body":105},"Troubleshooting","**Tunnel won't establish — UDP blocked by ISP.** Some ISPs filter outbound UDP on non-standard ports. Test from the origin machine: `nc -u -v VPS_IP 51820`. If the connection is refused, change the WireGuard port in `config.yml` to 443 (UDP) or 53 (UDP) — these ports pass almost universally. Update `ufw` on the VPS accordingly.\n\n**MTU mismatch — latency or random disconnects.** WireGuard adds encapsulation overhead (roughly 60 bytes). If your service transfers large files and you observe disconnects, reduce the WireGuard interface MTU in Gerbil's configuration: `mtu = 1380` is a safe value on most links.\n\n**Service unreachable despite active tunnel.** First verify that the local service listens on `0.0.0.0` and not only on `127.0.0.1`: `ss -tlnp | grep 8080`. Then confirm that the port configured in Pangolin matches the actual service port. Finally, check Newt's logs: `journalctl -u newt -f`.\n\n**Let's Encrypt certificate not issued.** Pangolin uses the HTTP-01 challenge, which requires port 80 on the VPS to be reachable from the Internet. Check that `ufw allow 80\u002Ftcp` is active and no other service holds port 80 (`ss -tlnp | grep :80`). On Cloudflare, make sure the wildcard record is DNS-only (grey cloud).\n\n**Pangolin interface unreachable after reboot.** If Docker restarts before the network is available, Pangolin may start without a network interface. Add `network-online.target` to the systemd dependency, or simply rerun `docker compose up -d` from `\u002Fopt\u002Fpangolin`.",{"type":107,"title":108,"headers":109,"rows":114},"comparison","Pangolin vs Cloudflare Tunnel vs Tailscale\u002FHeadscale",[110,111,112,113],"Criterion","Pangolin + Gerbil","Cloudflare Tunnel","Tailscale \u002F Headscale",[115,120,125,130,135,140],[116,117,118,119],"Hosting","Self-hosted on your VPS","Cloudflare SaaS","SaaS (Tailscale) or self-hosted (Headscale)",[121,122,123,124],"Cost","VPS cost only","Free up to certain thresholds, then subscription","Free (personal use), team subscription",[126,127,128,129],"E2E encryption","WireGuard between machine and VPS, HTTPS to visitor","TLS to Cloudflare servers (decrypted in transit)","WireGuard between all nodes (full mesh)",[131,132,133,134],"Public HTTP exposure","Yes, with automatic HTTPS and custom subdomains","Yes, with certificates managed by Cloudflare","Not natively designed (requires an additional reverse proxy)",[136,137,138,139],"Admin complexity","Medium — a Docker stack to maintain, a web interface","Low — connector is a single binary, everything managed by Cloudflare","Low (Tailscale) to Medium (self-hosted Headscale)",[141,142,143,144],"Traffic privacy","Traffic visible only on your VPS","Traffic decrypted by Cloudflare on their servers","Encrypted mesh traffic, never centralized",{"type":37,"title":146,"body":147},"Going further","Pangolin 1.23.0 introduces support for high availability in the Enterprise edition and multi-admin server management — features useful once your infrastructure grows beyond personal use.\n\nTo expose non-HTTP services (private SSH, databases, application UDP protocols), Pangolin now supports **private TCP\u002FUDP resources** accessible via the Newt client — without exposing them publicly on a URL, but making them reachable within your WireGuard network.\n\nIf your need is different — coordinating access between multiple machines without public exposure — \u003Ca href=\"\u002Fblog\u002Fself-host-headscale-tailscale-vps\">Headscale on VPS\u003C\u002Fa> is the right tool. For exposure without an intermediate VPS using Cloudflare's infrastructure, \u003Ca href=\"\u002Fblog\u002Fcloudflare-tunnel-exposer-application-vps\">Cloudflare Tunnel\u003C\u002Fa> remains the simplest option. And to lay the groundwork for network encryption on a VPS, the \u003Ca href=\"\u002Fblog\u002Finstaller-wireguard-vps\">WireGuard on VPS\u003C\u002Fa> guide covers native WireGuard interface installation and configuration.","A VPS with root access and a dedicated IPv4","Pangolin and Gerbil need an open UDP port and a dedicated IPv4 to listen for incoming WireGuard connections. ServOrbit VPS plans provide both, with your choice of OS and full root access.","View Cloud VPS plans","\u002Fvps-cloud",[153,170,192],{"id":154,"slug":155,"slugs":156,"title":160,"excerpt":161,"readTime":162,"views":163,"isPinned":19,"publishedAt":164,"updatedAt":165,"category":166,"categories":167,"featuredImage":29,"bgImage":30,"posterImage":169,"relatedSolution":29},248,"cloudflare-tunnel-expose-a-vps-app-without-opening-ports",{"fr":157,"en":155,"ar":158,"es":159},"cloudflare-tunnel-exposer-application-vps","نفق-كلاود-فلير-عرض-تطبيق-vps-بدون-فتح-منافذ","cloudflare-tunnel-exponer-app-vps-sin-abrir-puertos","Cloudflare Tunnel: expose a VPS app without opening ports","Expose an application on your VPS via a Cloudflare Tunnel without opening any inbound port. Full guide with cloudflared, Docker Compose and a systemd service.",10,1,"2026-08-12T00:00:00+00:00","2026-09-07T11:26:10+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":25},[168],{"id":23,"name":24,"slug":25,"color":26,"icon":25},"\u002Fblog\u002Fcovers\u002Fcloudflare-tunnel-exposer-application-vps-poster.svg",{"id":171,"slug":172,"slugs":173,"title":177,"excerpt":178,"readTime":179,"views":163,"isPinned":19,"publishedAt":180,"updatedAt":165,"category":181,"categories":187,"featuredImage":29,"bgImage":30,"posterImage":189,"relatedSolution":190},164,"self-host-headscale-on-a-vps-your-own-tailscale-control-server",{"fr":174,"en":172,"ar":175,"es":176},"self-host-headscale-tailscale-vps","استضافة-headscale-على-vps-خادم-تحكم-tailscale-خاص-بك","auto-alojar-headscale-en-un-vps-servidor-tailscale","Self-Host Headscale on a VPS: Your Own Tailscale Control Server","Replace Tailscale's cloud control server with Headscale on your own VPS — unlimited users, full WireGuard mesh networking, magic DNS and ACLs, with no SaaS dependency.",6,"2026-07-05T00:00:00+00:00",{"id":182,"name":183,"slug":184,"color":185,"icon":186},8,"Security & Monitoring","securite-monitoring","bg-rose-500\u002F10 text-rose-400","security",[188],{"id":182,"name":183,"slug":184,"color":185,"icon":186},"\u002Fblog\u002Fcovers\u002Fself-host-headscale-tailscale-vps-poster.svg",{"categorySlug":33,"appSlug":191},"headscale",{"id":193,"slug":194,"slugs":195,"title":199,"excerpt":200,"readTime":201,"views":18,"isPinned":19,"publishedAt":202,"updatedAt":165,"category":203,"categories":204,"featuredImage":29,"bgImage":30,"posterImage":206,"relatedSolution":207},141,"wireguard-on-a-vps-a-fast-lean-and-private-vpn",{"fr":196,"en":194,"ar":197,"es":198},"installer-wireguard-vps","wireguard-على-خادم-vps-شبكة-vpn-سريعة-ومبسطة-وخاصة","wireguard-en-un-vps-vpn-rapido-y-privado","WireGuard on a VPS: a fast, lean and private VPN","Deploy WireGuard on a ServOrbit VPS: fast tunnels, readable configuration, client QR codes and private remote access.",4,"2026-02-04T00:00:00+00:00",{"id":182,"name":183,"slug":184,"color":185,"icon":186},[205],{"id":182,"name":183,"slug":184,"color":185,"icon":186},"\u002Fblog\u002Fcovers\u002Finstaller-wireguard-vps-poster.svg",{"categorySlug":208,"appSlug":209},"securite","wireguard-server",1789664981262]