Set up Pangolin Zero Trust VPN for private networks

Pangolin Zero-Trust VPN Guide

Complete setup guide for private resource access with real-world examples.


What is Pangolin VPN?

Pangolin 1.13+ introduces Zero-Trust Network Access (ZTNA). Access private resources like SSH, RDP, databases, and entire network ranges through desktop clients on Windows, macOS, and Linux.

This works alongside browser-based reverse proxy. Both use the same Newt site connector.

Key difference from traditional VPN:

  • Traditional VPN: Connect to network β†’ access everything
  • Pangolin: Connect to network β†’ access only what you’re allowed to

Key Concepts

Component Description
Site A remote network with Newt installed. Creates secure tunnel to Pangolin server.
Newt Site connector. Install on any machine in your remote network. No public IP needed.
Private Resource A specific host or network range accessible through the VPN tunnel.
Host Resource Single IP address (e.g., 192.168.1.100)
CIDR Resource Network range (e.g., 10.0.0.0/24 exposes all IPs in that range)
DNS Alias Friendly hostname (e.g., immich.internal) that resolves over the tunnel.
Pangolin Client Desktop app (Windows/Mac/Linux) that connects you to private resources.

Prerequisites

  1. Pangolin server running (v1.13.0 or later)
  2. A Pangolin user account
  3. A machine in your remote network for Newt
  4. Pangolin client downloaded on your laptop/desktop

Step 1: Create a Site

A site represents a remote network. You only need one Newt per network.

  1. Log into Pangolin dashboard
  2. Go to Sites β†’ Add Site
  3. Enter a name (e.g., β€œHome Lab”, β€œOffice Network”)
  4. Select Newt Tunnel (default)
  5. Choose install method: Docker Compose or Binary
  6. Copy the generated credentials
  7. Click Create Site

Docker Compose Example

services:
  newt:
    image: fosrl/newt
    restart: unless-stopped
    environment:
      - PANGOLIN_ENDPOINT=https://your-pangolin-server.com
      - NEWT_ID=your-newt-id
      - NEWT_SECRET=your-newt-secret

Add Newt to Existing Stack

You can add Newt to any existing docker-compose.yml:

services:
  # Your existing services
  immich-server:
    image: ghcr.io/immich-app/immich-server:release
    # ... immich config

  jellyfin:
    image: jellyfin/jellyfin
    # ... jellyfin config

  # Add Newt to the same stack
  newt:
    image: fosrl/newt
    restart: unless-stopped
    environment:
      - PANGOLIN_ENDPOINT=https://pangolin.yourdomain.com
      - NEWT_ID=abc123
      - NEWT_SECRET=xyz789

Step 2: Create Private Resources

Resources define what you can access through the tunnel.

  1. Go to Resources β†’ Private
  2. Click Add Resource
  3. Enter a name (e.g., β€œImmich”, β€œJellyfin”)
  4. Select the site connector
  5. Choose mode: Host or CIDR
  6. Enter destination IP
  7. (Optional) Add DNS alias
  8. Assign users/roles with access
  9. Click Create Resource

Host vs CIDR Mode

Host Mode CIDR Mode
Single IP address Full network range
Example: 192.168.1.100 Example: 192.168.1.0/24
Use for: specific servers Use for: access entire subnet
More secure (least privilege) More convenient (broader access)

Step 3: Install Pangolin Client

macOS

  1. Download .dmg from Downloads | Pangolin
  2. Open and drag to Applications
  3. Launch Pangolin from Applications
  4. Click Open System Settings when prompted
  5. Enable Pangolin under Network Extensions
  6. Click Allow for VPN configuration
  7. Enter your Mac password

Windows

  1. Download .msi from Downloads | Pangolin
  2. Run installer
  3. Launch from Start menu
  4. Find icon in system tray (bottom right)

Linux (CLI)

curl -fsSL https://pangolin.net/install.sh | sh

Note: Linux may require root privileges for TUN interface creation.


Step 4: Connect to Resources

  1. Click Pangolin icon (menu bar on Mac, system tray on Windows)
  2. Click Login
  3. Select Self-Hosted or Pangolin Cloud
  4. Enter your server URL (for self-hosted)
  5. Browser opens β†’ log in with your Pangolin account
  6. Verify the authentication code matches
  7. Click Continue and authorize
  8. Select your organization (if multiple)
  9. Click Connect

Status indicator: Orange = connected. Now access your resources using their IPs or DNS aliases.


Real-World Examples

Example 1: Immich (Photo Management)

Setup: Immich running at 192.168.1.50:2283

Resource Configuration:

  • Name: Immich
  • Mode: Host
  • Destination: 192.168.1.50
  • DNS Alias: immich.home

Access after connecting:

http://immich.home:2283
# or
http://192.168.1.50:2283

Use case: Access your photo library from anywhere without exposing it to the internet.


Example 2: Jellyfin / Plex (Media Server)

Setup: Jellyfin at 192.168.1.51:8096

Resource Configuration:

  • Name: Jellyfin
  • Mode: Host
  • Destination: 192.168.1.51
  • DNS Alias: jellyfin.home

Access:

http://jellyfin.home:8096

For Plex: Same setup, port 32400

http://plex.home:32400/web

Example 3: Home Assistant

Setup: Home Assistant at 192.168.1.52:8123

Resource Configuration:

  • Name: Home Assistant
  • Mode: Host
  • Destination: 192.168.1.52
  • DNS Alias: ha.home

Access:

http://ha.home:8123

Bonus: Control your smart home from anywhere without cloud dependency.


Example 4: Nextcloud

Setup: Nextcloud at 192.168.1.53:443 (HTTPS)

Resource Configuration:

  • Name: Nextcloud
  • Mode: Host
  • Destination: 192.168.1.53
  • DNS Alias: nextcloud.home

Access:

https://nextcloud.home

Example 5: Vaultwarden (Password Manager)

Setup: Vaultwarden at 192.168.1.54:8080

Resource Configuration:

  • Name: Vaultwarden
  • Mode: Host
  • Destination: 192.168.1.54
  • DNS Alias: vault.home

Access:

http://vault.home:8080

Security note: Keep your password manager private. No public exposure needed.


Example 6: Proxmox / TrueNAS Management

Setup:

  • Proxmox at 192.168.1.10:8006
  • TrueNAS at 192.168.1.11:443

Resource Configuration (Proxmox):

  • Name: Proxmox
  • Mode: Host
  • Destination: 192.168.1.10
  • DNS Alias: proxmox.home

Resource Configuration (TrueNAS):

  • Name: TrueNAS
  • Mode: Host
  • Destination: 192.168.1.11
  • DNS Alias: truenas.home

Access:

https://proxmox.home:8006
https://truenas.home

Example 7: Grafana + Prometheus Monitoring Stack

Setup:

  • Grafana at 192.168.1.60:3000
  • Prometheus at 192.168.1.60:9090

Resource Configuration:

  • Name: Monitoring
  • Mode: Host
  • Destination: 192.168.1.60
  • DNS Alias: monitoring.home

Access:

http://monitoring.home:3000  # Grafana
http://monitoring.home:9090  # Prometheus

Example 8: Paperless-ngx (Document Management)

Setup: Paperless at 192.168.1.55:8000

Resource Configuration:

  • Name: Paperless
  • Mode: Host
  • Destination: 192.168.1.55
  • DNS Alias: paperless.home

Access:

http://paperless.home:8000

Example 9: Gitea / Forgejo (Git Server)

Setup: Gitea at 192.168.1.56:3000 (Web) and :22 (SSH)

Resource Configuration:

  • Name: Gitea
  • Mode: Host
  • Destination: 192.168.1.56
  • DNS Alias: git.home

Access:

# Web interface
http://git.home:3000

# Git clone via SSH
git clone git@192.168.1.56:username/repo.git

Example 10: Pi-hole / AdGuard DNS

Setup: Pi-hole at 192.168.1.2:80 (Admin) and :53 (DNS)

Resource Configuration:

  • Name: Pi-hole
  • Mode: Host
  • Destination: 192.168.1.2
  • DNS Alias: pihole.home

Access:

# Admin panel
http://pihole.home/admin

# Use as DNS (in your device settings)
DNS Server: 192.168.1.2

Example 11: SSH to Multiple Servers

Setup: Multiple servers in your network

Option A: Individual Host Resources

Server 1: 192.168.1.100 β†’ ssh.server1.home
Server 2: 192.168.1.101 β†’ ssh.server2.home
Server 3: 192.168.1.102 β†’ ssh.server3.home

Option B: CIDR for entire network

  • Mode: CIDR
  • Destination: 192.168.1.0/24

Access:

# With individual resources
ssh user@ssh.server1.home

# With CIDR
ssh user@192.168.1.100
ssh user@192.168.1.101
ssh user@192.168.1.102

Key point: One Newt can reach all machines on its network. No need to install anything on target servers.


Example 12: Database Access

Setup:

  • PostgreSQL at 192.168.1.70:5432
  • MySQL at 192.168.1.71:3306
  • Redis at 192.168.1.72:6379

Resource Configuration (each):

  • Mode: Host
  • Add DNS alias for each

Access:

# PostgreSQL
psql -h postgres.home -p 5432 -U myuser -d mydb

# MySQL
mysql -h mysql.home -P 3306 -u myuser -p

# Redis
redis-cli -h redis.home -p 6379

Use case: Connect database tools (DBeaver, TablePlus, DataGrip) to remote databases.


Example 13: Minecraft / Game Servers

Setup: Minecraft server at 192.168.1.80:25565

Resource Configuration:

  • Name: Minecraft
  • Mode: Host
  • Destination: 192.168.1.80
  • DNS Alias: mc.home

Access: In Minecraft client, connect to:

mc.home:25565
# or
192.168.1.80:25565

Works with: Valheim, Terraria, Factorio, any game server.


Example 14: NAS File Access (SMB/NFS)

Setup: Synology/QNAP NAS at 192.168.1.5

Resource Configuration:

  • Name: NAS
  • Mode: Host
  • Destination: 192.168.1.5
  • DNS Alias: nas.home

Access:

# SMB (Windows/Mac)
\\nas.home\share
# or
smb://nas.home/share

# NFS (Linux)
mount -t nfs nas.home:/volume1/share /mnt/nas

Ports involved: SMB (445), NFS (2049), AFP (548)


Example 15: Development Environment

Setup: Full dev stack on 192.168.1.90

  • VS Code Server: :8443
  • Node app: :3000
  • API server: :8080
  • MongoDB: :27017

Resource Configuration:

  • Name: Dev Server
  • Mode: Host
  • Destination: 192.168.1.90
  • DNS Alias: dev.home

Access:

https://dev.home:8443     # VS Code
http://dev.home:3000      # Frontend
http://dev.home:8080      # API
mongodb://dev.home:27017  # Database

Example 16: Entire Home Lab with CIDR

Setup: All services on 10.0.0.0/24 network

Resource Configuration:

  • Name: Home Lab
  • Mode: CIDR
  • Destination: 10.0.0.0/24

Access everything:

http://10.0.0.50:2283   # Immich
http://10.0.0.51:8096   # Jellyfin
http://10.0.0.52:8123   # Home Assistant
https://10.0.0.10:8006  # Proxmox
ssh user@10.0.0.100     # Any server

Trade-off: Convenient but less granular access control.


Example 17: Docker Host Access

Setup: Docker running on 192.168.1.200

  • Portainer: :9443
  • Traefik Dashboard: :8080
  • Docker API: :2375

Resource Configuration:

  • Name: Docker Host
  • Mode: Host
  • Destination: 192.168.1.200
  • DNS Alias: docker.home

Access:

https://docker.home:9443  # Portainer
http://docker.home:8080   # Traefik

Docker CLI remote access:

export DOCKER_HOST=tcp://docker.home:2375
docker ps

Example 18: Arr Stack (Sonarr, Radarr, etc.)

Setup: Media automation on 192.168.1.85

  • Sonarr: :8989
  • Radarr: :7878
  • Prowlarr: :9696
  • qBittorrent: :8080

Resource Configuration:

  • Name: Arr Stack
  • Mode: Host
  • Destination: 192.168.1.85
  • DNS Alias: arr.home

Access:

http://arr.home:8989   # Sonarr
http://arr.home:7878   # Radarr
http://arr.home:9696   # Prowlarr
http://arr.home:8080   # qBittorrent

Example 19: Uptime Kuma + Monitoring

Setup:

  • Uptime Kuma at 192.168.1.95:3001
  • Dozzle (Docker logs) at 192.168.1.95:8080

Resource Configuration:

  • Name: Monitoring Tools
  • Mode: Host
  • Destination: 192.168.1.95
  • DNS Alias: status.home

Access:

http://status.home:3001  # Uptime Kuma
http://status.home:8080  # Dozzle

Example 20: Audiobookshelf / Kavita

Setup:

  • Audiobookshelf at 192.168.1.88:13378
  • Kavita at 192.168.1.88:5000

Resource Configuration:

  • Name: Books
  • Mode: Host
  • Destination: 192.168.1.88
  • DNS Alias: books.home

Access:

http://books.home:13378  # Audiobookshelf
http://books.home:5000   # Kavita

Multi-Site Setup

Scenario: Home + Office + Cloud VPS

Site 1: Home Lab (192.168.1.0/24)
  └── Newt on 192.168.1.5

Site 2: Office (10.0.0.0/24)
  └── Newt on 10.0.0.10

Site 3: Cloud VPS (172.16.0.0/24)
  └── Newt on 172.16.0.1

Setup:

  1. Create 3 sites in Pangolin
  2. Install Newt on one machine per network
  3. Create resources for each site
  4. Connect with client β†’ access all sites

Result: One VPN connection gives you access to resources across all networks.


Access Control

User-Based Access

  • Add specific users to a resource
  • Only those users can access when connected
  • Example: Only give database access to developers

Role-Based Access

  • Create roles (e.g., β€œDevelopers”, β€œFamily”, β€œGuests”)
  • Assign roles to resources
  • All users with that role get access

Example setup:

Role: Family
  └── Immich, Jellyfin, Nextcloud

Role: Developers  
  └── All above + SSH, Databases, Portainer

Role: Guests
  └── Jellyfin only

Network Topology

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Your Laptop    β”‚     β”‚  Pangolin Server  β”‚
β”‚  (Client App)   │◄───►│  (Cloud/Self-host)β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                  β”‚
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β–Ό                           β–Ό
          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
          β”‚   Home Site     β”‚         β”‚   Office Site   β”‚
          β”‚  (Newt running) β”‚         β”‚  (Newt running) β”‚
          β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜         β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                   β”‚                           β”‚
     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”            β”‚
     β–Ό             β–Ό             β–Ό            β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Immich β”‚   β”‚Jellyfinβ”‚   β”‚  NAS   β”‚   β”‚Dev Servers β”‚
β”‚10.0.0.5β”‚   β”‚10.0.0.6β”‚   β”‚10.0.0.7β”‚   β”‚ 10.1.0.x   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Troubleshooting

Site shows β€œOffline”

  • Check if Newt container/process is running
  • Verify PANGOLIN_ENDPOINT, NEWT_ID, NEWT_SECRET are correct
  • Check firewall allows outbound connections
  • Check Docker logs: docker logs newt

Client won’t connect

  • Ensure VPN configuration is allowed (system settings)
  • Try restarting the Pangolin client
  • Check your server URL is correct (include https://)
  • On Mac: Check System Settings β†’ Network Extensions

Can’t reach resource

  • Verify resource IP is correct
  • Check you have access (user/role assigned)
  • Confirm Newt can reach the target IP on the local network
  • Test from Newt host: ping 192.168.1.50
  • For CIDR: make sure IP is within the defined range

DNS alias not resolving

  • Ensure client is connected (status shows orange)
  • Try using IP address directly to test connectivity
  • Flush local DNS cache:
    # macOS
    sudo dscacheutil -flushcache
    
    # Windows
    ipconfig /flushdns
    
    # Linux
    sudo systemd-resolve --flush-caches
    

Slow connection

  • Check if NAT hole punching succeeded (direct connection)
  • Relay mode is slower but more reliable
  • Check network quality on both ends

Quick Reference

Action How To
Add new site Sites β†’ Add Site β†’ Copy credentials β†’ Run Newt
Add resource Resources β†’ Private β†’ Add Resource
Grant access Edit resource β†’ Add users/roles
Check site status Sites page β†’ Look for β€œOnline” status
Switch organization Client menu β†’ Select different org
View connection status Client icon β†’ Orange = connected

Common Port Reference

Service Default Port
Immich 2283
Jellyfin 8096
Plex 32400
Home Assistant 8123
Nextcloud 443
Vaultwarden 8080
Proxmox 8006
TrueNAS 443
Grafana 3000
Portainer 9443
Pi-hole 80
Paperless-ngx 8000
Gitea 3000
Sonarr 8989
Radarr 7878
PostgreSQL 5432
MySQL 3306
Redis 6379
SSH 22
SMB 445
RDP 3389

Best Practices

  1. Use Host mode for specific services - More secure, explicit access
  2. Use CIDR for dev/test environments - Convenience over granularity
  3. Set DNS aliases - Easier to remember than IPs
  4. Create roles - Manage access at scale
  5. One Newt per network - Don’t install on every machine
  6. Keep Newt updated - docker pull fosrl/newt regularly
  7. Document your resources - Use clear naming conventions

5 Likes

Thank you for your work!
I’ve also seen a video of pangolin, this goes into way more detail, I will definitly try this soon.

1 Like

Hey there, thank you for your guide, maybe you have an idea for my specific setup. Right now I do use newt to connect my VPS and my homelab. The VPS side has complete access to my homelab network, like your guide, so far so good.

But my homelab is running komodo core. Right now, the komodo periphery agent, which allows me to control pangolin docker stack on the VPS is connected over the VPSs internet IP, which of course forces me to open a port. Since my homelabs IP is dynamic i have the port open to the whole internet, which sucks. I’m now trying to get the β€œreverse” connection of your guide working. But I’m starting to think that this isn’t intended? The VPS itself, isn’t reachable from any of my homelab clients. I played around with the –native option of newt, where it creates a tun device so I can actually use ip routes to reach the VPS, but I still cant get a connection the the specific port komodo agent is using going. Do you have any idea for this particular setup? Is it possible with the new version of pangolin?

1 Like

Thanks a lot for the detailed guide. I was having some trouble trying to set up, and didn’t know why.

I have identified my mistakes, and it works as expected now.

1 Like

This will be fantastic if they can get a iOS & Android app out. A lot of my remote access needs are on mobile. Any idea if that’s in the works?

1 Like

I have a different solution till they come out with this feature. Will post here soon.

Question:

Would it be possible to host a pangolin instance on a vps (e.g. hetzner) without a domain pointing to it - and with the new VPN features in pangolin, connect to the private ressources directly with client←→server tunnels?

If i combine this maybe with a free oracle vps - i have no costs at all.

Basically having a self hosted pangolin VPN relay Server, thats easy to setup and maintain for me(beginner). And not having the need of a public domain, maybe having pangolin dashboard on tailscale.

Yes, that is confusing, why not using tailscale in the first place. For me its because of trying to experiment with pangolin and loving the self host aspect of it and for me headscale was not that easy to setup now.

Nope, not possible. Instead used an alternative solution. Like wgeasy or similar.
Then internal you can have your own dns server for your names.

1 Like

I got this working by the was - I’m using pangolin now for every connection between my homelab and the VPS , even for SSH.

Newt Runs with –native and IP routes do the rest. I can go into details if anyone cares.

Share it here , it’s your forum, no restriction, don’t have to wait for someone to ask. Pen it down

So, this is the way I set things up:

(I wanted to post a picture here but I can’t)

htt ps://i.imgur .com/H0B55MM.png

Pangolin is running on my Rootserver. My homelab is set up as a site via Newt, the VPS is set up as a machine via Olm (I used olm because it creates a network device by itself, another site would also be possible, it doesn’t really matter, because even if this isn’t a site you can still expose services from the VPS via their 100.90.128.xxx IP later on) And: you totally do not need a third server to do this, VPS ←→ Homelab is the same procedure.

This is basically the normal setup that allows Pangolin to connect to the homelab, but not the homelab to anything on the Rootserver or the VPS. I basically use the VPS for monitoring (Pulse Monitor, Ntfy for notifications), so it needs connections both ways.

What I changed to make this work:

First I installed Olm on the Rootserver too, so the server itself is part of the network, I added it as a machine in Pangolin.

In Pangolin you need to add 2 Remote subnets (CIDR) under private resources, first the IP range of your homelab ( for me that’s 192.168.178.0/24) and the IP range of your Pangolin Network (for me that’s 100.90.128.0/24)

Now the magic:

Newt on the homelab is running inside a dedicated Proxmox LXC with the – native startup command. The container needs access to the tun device, so Newt can create it’s own newt network adapter:

# on the host: 
nano /etc/pve/lxc/NUMBER-OF-YOUR-LXC.conf 

#then add this at the end, restart the container

lxc.cgroup2.devices.allow: c 10:200 rwm
lxc.mount.entry: /dev/net/tun dev/net/tun none bind,create=file

This is important because you need this adapter for IP routing. If you also enable IP forwarding, IP Masquerading in the container running newt and add IP routes where needed, you can ping both ways perfectly fine:

sysctl -w net.ipv4.ip_forward=1
#install iptables if not installed already
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

These setting aren’t persistent. If you want them to survive a reboot you need to do the following:

#For the iptables, after you set them once you can just

apt install iptables-persistent

#On package install this saves the current iptables and makes them persistent.

#For the ip forwarding:

nano /etc/sysctl.d/99-ipforward.conf

#there you enter:

net.ipv4.ip_forward = 1

Now the only thing left to do is add the IP routes for the containers, that need to have a direct connection to the VPS or Rootserver:

ip route add 100.90.128.0/24 via 192.168.178.124

this is my example. In this case, 192.168.178.124 is the IP of my LXC running Newt. This just tells the container or the Proxmox host, or whereever you enter this, that it should route any traffic to the 100.90.128.0/24 network throught the container running Newt. You can now ping your devices within this network.

Keep in mind that this IP route isn’t persistent either, find out what network manager you are using because the way to make them persistent depends on the network manager.

If you install Pangolin VPN Client on any PC now, it is also able to ping all of these devices directly. Now this is a perfect 100% selfhosted VPN network, that can talk in all directions. Whoever reads this, just hit me up if you have any questions.

1 Like