Skip to content

Instantly share code, notes, and snippets.

@proofrock
Created November 6, 2025 08:36
Show Gist options
  • Select an option

  • Save proofrock/55c7338336eb69e2713f9597f9a7c646 to your computer and use it in GitHub Desktop.

Select an option

Save proofrock/55c7338336eb69e2713f9597f9a7c646 to your computer and use it in GitHub Desktop.
IP filtering for Pangolin console, with HaProxy
This adds IP filtering for the Pangolin console; it will work normally for the Pangolin resources, but access to the console will be restricted to connections coming from a given IP.
I tested it with the following versions; it should work with several other too.
- Pangolin 1.12.1
- Gerbil 1.2.2
- Traefik 3.5.4
- Badger 1.2.1
Things to replace in the instructions below:
- base URL of the console (below, look for `pan.example.com`)
- IP address to allow (below, look for `123.456.789.123`)
## Step 1 - install haproxy and configure gerbil
1. Edit the `docker-compose.yaml` you already have, adding the `haproxy` service and disabling port 80/443 for `gerbil`.
```yaml
services:
haproxy:
image: haproxy:alpine
container_name: haproxy
networks:
- default
ports:
- "80:80"
- "443:443"
volumes:
- ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro
restart: unless-stopped
[...]
gerbil:
[...]
ports:
- 51820:51820/udp
# Commented out as they're managed by haproxy
# - 443:443 # Port for traefik because of the network_mode
# - 80:80 # Port for traefik because of the network_mode
[...]
```
# Step 2 - enable proxy protocol for `traefik`
1. Get the internal CIDR of the `pangolin` (also called `default`) subnet in Pangolin
```bash
#> docker network inspect pangolin | grep Subnet
"Subnet": "172.18.0.0/16",
```
2. Edit the `traefik` config file, `config/traefik/traefik_config.yml`:
```yaml
[...]
entryPoints:
web:
address: ":80"
proxyProtocol: # Add this block
trustedIPs:
- "172.18.0.0/16"
websecure:
address: ":443"
proxyProtocol: # Add this block
trustedIPs:
- "172.18.0.0/16"
[...]
```
## Step 3 - define the `haproxy.cfg` config file for `haproxy`
1. Put this in the same path as `docker-compose.yaml` and replace the placeholder values (`pan.example.com` and `123.456.789.123`) in the `acl` lines
```
global
log stdout format raw local0
maxconn 4096
defaults
log global
mode tcp
option tcplog
timeout connect 5s
timeout client 50s
timeout server 50s
frontend http_in
bind *:80
mode tcp
default_backend pangolin_http
frontend https_in
bind *:443
mode tcp
tcp-request inspect-delay 5s
# Define ACLs
acl is_ip_limited req.ssl_sni -i pan.example.com
acl allowed_ip src 123.456.789.123
# Block limited endpoint unless from allowed IP
tcp-request content reject if is_ip_limited !allowed_ip
# Else accept SSL traffic
tcp-request content accept if { req_ssl_hello_type 1 }
default_backend pangolin_https
backend pangolin_http
mode tcp
server pangolin gerbil:80 send-proxy-v2 check
backend pangolin_https
mode tcp
server pangolin gerbil:443 send-proxy-v2 check
```
## Step 4 - apply everything
```bash
#> docker compose pull
#> docker compose up -d
#> docker restart traefik
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment