Reverse Tunneled Proxy with Pangolin

Pangolin is a self-hosted tunneled reverse proxy management server with identity and access management, designed to securely expose private resources through encrypted WireGuard tunnels running in user space. With Pangolin, you retain full control over your infrastructure while providing a user-friendly and feature-rich solution for managing proxies, authentication, and access, and simplifying complex network setups, all with a clean and simple dashboard web UI.

Table of Contents

Requirements

Setup will be using Docker, please look for alternative method in the official documentation. (This is just a log for my setup, and I’m pretty sure no one is reading this except me haha)

  • VPS with public IP
  • Local Server
  • Domain

DNS Setup

Make sure to add this two record.

1yourdomain.com   A   Auto    YourPublicIP
2*.yourdomain.com   A   Auto    yourPublicIP

VPS Setup

Before the installation, make sure no application is using port 80 and 443. You can check using `netstat -tulpn'.

1root@engago:~# netstat -tulpn | grep 443
2tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN      3314824/docker-prox
3tcp6       0      0 :::443                  :::*                    LISTEN      3314829/docker-prox
4root@engago:~# netstat -tulpn | grep 80
5tcp        0      0 0.0.0.0:993             0.0.0.0:*               LISTEN      3314780/docker-prox
6tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      3314803/docker-prox
7tcp6       0      0 :::80                   :::*                    LISTEN      331480

Download the installer.

1curl -fsSL https://static.pangolin.net/get-installer.sh | bash

Execute the installer with root privileges:

1sudo ./installer
 1Welcome to the Pangolin installer!
 2This installer will help you set up Pangolin on your server.
 3
 4Please make sure you have the following prerequisites:
 5- Open TCP ports 80 and 443 and UDP ports 51820 and 21820 on your VPS and firewall.
 6
 7Lets get started!
 8
 9=== Basic Configuration ===
10Do you want to install the Enterprise version of Pangolin? The EE is free for personal use or for businesses making less than 100k USD annually. (yes/no): no
11Enter your base domain (no subdomain e.g. example.com): yourdomain.com
12Enter the domain for the Pangolin dashboard (default: pangolin.yourdomain.com): 
13Enter email for Let's Encrypt certificates: youremail.com
14Do you want to use Gerbil to allow tunneled connections (yes/no) (default: yes): yes
15
16=== Email Configuration ===
17Enable email functionality (SMTP) (yes/no) (default: no): no
18
19=== Advanced Configuration ===
20Is your server IPv6 capable? (yes/no) (default: yes): no
21Do you want to download the MaxMind GeoLite2 database for geoblocking functionality? (yes/no) (default: yes): yes
22
23=== Generating Configuration Files ===
24
25Configuration files created successfully!
26
27=== Downloading MaxMind Database ===
28Downloading MaxMind GeoLite2 Country database...
29  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
30                                 Dload  Upload   Total   Spent    Left  Speed
31  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
32100 4797k  100 4797k    0     0  3140k      0  0:00:01  0:00:01 --:--:-- 3140k
33tar: GeoLite2-Country_20260116/GeoLite2-Country.mmdb: Cannot change ownership to uid 0, gid 0: Operation not permitted
34tar: GeoLite2-Country_20260116/COPYRIGHT.txt: Cannot change ownership to uid 0, gid 0: Operation not permitted
35tar: GeoLite2-Country_20260116/LICENSE.txt: Cannot change ownership to uid 0, gid 0: Operation not permitted
36tar: GeoLite2-Country_20260116: Cannot change ownership to uid 0, gid 0: Operation not permitted
37tar: Exiting with failure status due to previous errors
38Error downloading MaxMind database: failed to extract GeoLite2 database: exit status 2
39You can download it manually later if needed.
40
41=== Starting installation ===
42Would you like to install and start the containers? (yes/no) (default: yes): yes
43Would you like to run Pangolin as Docker or Podman containers? (default: docker): 
44Would you like to configure ports >= 80 as unprivileged ports? This enables docker containers to listen on low-range ports.
45Pangolin will experience startup issues if this is not configured, because it needs to listen on port 80/443 by default.
46The installer is about to execute "echo 'net.ipv4.ip_unprivileged_port_start=80' >> /etc/sysctl.conf && sysctl -p". Approve? (yes/no) (default: yes): yes
47net.ipv4.ip_unprivileged_port_start = 80

This will create three docker container.

1docker ps
2
3CONTAINER ID   IMAGE                                          COMMAND                  CREATED        STATUS                PORTS 
4
55a7d2951ae5c   traefik:v3.6                                   "/entrypoint.sh --co…"   6 days ago     Up 2 days                                                                                                                                                                                                                       traefik
623b823c4971c   fosrl/gerbil:1.3.0                             "/entrypoint.sh --re…"   6 days ago     Up 2 days             0.0.0.0:80->80/tcp, [::]:80->80/tcp, 0.0.0.0:21820->21820/udp, [::]:21820->21820/udp, 0.0.0.0:443->443/tcp, [::]:443->443/tcp, 0.0.0.0:51820->51820/udp, [::]:51820->51820/udp                            gerbil
718d7560ce63e   fosrl/pangolin:ee-1.14.1                       "docker-entrypoint.s…"   6 days ago     Up 2 days (healthy)                                                                                                                                                                                                             pangolin
87ead48db901e   ghcr.io/mcbtaguiad/sipup-luna-web:main         "/bin/ash /docker-en…"   6 days ago     Up 2 days (healthy)   8000/tcp

Wait for the container to fully initialized and then visit the subdomain of pangolin container, in our case we set to default pangolin.yourdomain.com. Go with the account creation and you are set. Will discuss later how to add site and resources that will be tunneled.

Local Server Setup

Now we need to add this server to using pangoling client Newt. Navigate to your pangolin dashboard and go to site, then click add site - add name for this site. For this example we will be using docker, on the Operating System option - click on Docker. Copy the content for the compose.yml, as we will be modifying it for it to work on docker network (using docker dns) and not needing to expose is using ip and port. With this method, we can set application to be not exposed outside and it will just be directly tunneled to the pangolin proxy.

imagen

Create a docker network.

1docker network create pangolin-proxy

Now create the compose file for Newt container, add docker network.

compose.yml

 1services:
 2  newt:
 3    image: fosrl/newt
 4    container_name: newt
 5    restart: unless-stopped
 6    environment:
 7      - PANGOLIN_ENDPOINT=https://pangolin.yourdomain.com
 8      - NEWT_ID=w030vjt04d336nl
 9      - NEWT_SECRET=719t1lksdk9ma7j3nlldh0zy7atr8f42aal9ag1u5eg1zt0u5q
10    networks:
11      - pangolin-proxy
12networks:
13  pangolin-proxy:
14    name: pangolin-proxy
15    external: true

Run the container. Now everytime you are running an application that you want to expose or tunnel to the pangolin proxy, make sure to add the network section. Check the example applicatin below.

 1services:
 2  jellyfin:
 3    image: jellyfin/jellyfin
 4    container_name: jellyfin
 5    ports:
 6      - 8096:8096/tcp
 7      - 7359:7359/udp
 8    volumes:
 9      - /config:/config
10      - type: bind
11        source:/media
12        target: /media
13    restart: unless-stopped
14    networks:
15      - pangolin
16networks:
17  pangolin:
18    name: pangolin
19    external: true

We mention that we will not be using the IP and Port when we are gonna tunnel the application, we can utilized the built-in DNS of docker. Like in kubernetes using services, in here the DNS record for the application will be the container_name we set. To check use docker ps.

1CONTAINER ID   IMAGE                                                            COMMAND                  CREATED        STATUS                  PORTS 
2d815bd083d62   jellyfin/jellyfin                                                "/jellyfin/jellyfin"     30 hours ago   Up 30 hours (healthy)   0.0.0.0:7359->7359/udp, [::]:7359->7359/udp, 0.0.0.0:8096->8096/tcp, [::]:8096->8096/tcp   jellyfin

Adding Resources

Now for the exciting part (kidding). Navigate to resources and click on public then add resources. Set the subdomain you preffer and set the target to the Site added earlier. Like we discussed earlier, in our example it can be set to IP or just the DNS (jellyfin) and port is 8096. Create resources, additional config would be if you want your application to have extra layer of security, Pangolin has a feature to use SSO (login first) to secure the web application. This can be configured in the resources section.

imagen