# PocketID + Pangolin + Netbird ( work in progress )

**URL:** <https://forum.hhf.technology/t/pocketid-pangolin-netbird-work-in-progress/3128>\
**Category:** Guides & Tutorials\
**Tags:** pocketid, netbird, pangolin\
**Created:** [July 20, 2025, 12:27pm UTC](https://forum.hhf.technology/t/pocketid-pangolin-netbird-work-in-progress/3128 "2025-07-20T12:27:07Z")\
**Posts on this page:** 17\
**Page:** 1

<div class="post-metadata">

**Author:** ![LeonvanHeerden](https://forum.hhf.technology/user_avatar/forum.hhf.technology/leonvanheerden/32/949_2.png) [@LeonvanHeerden](https://forum.hhf.technology/u/LeonvanHeerden)\
**Post date:** [July 20, 2025, 12:27pm UTC](https://forum.hhf.technology/t/pocketid-pangolin-netbird-work-in-progress/3128/1 "2025-07-20T12:27:07Z")

</div>

I was stuck trying the get Nebird working with Pangolin and traefik.

Writing this post allowed me to get some of the basic stuff to work:

- Netbird Docker container
- Pocket Id as the IDP for Netbird (Already working with pangolin)
- Netbird dashboard with Packet ID authentication
- Client connection on internal LAN with Packet ID authentication.

[https://np.p.example.com](https://np.p.example.com) now works for the dashboard.

\*\* To Do:\*\*

- Client relay support through Traefik

- First Client Peer to Peer config.

- First Network config.

- Figure out if the `configure.sh` script can be modified to support this config.

- Is it possible to access the netbird container ports without exposing them or redirecting them to other ports.

- Use the docker hostnames to references the Traefik endpoints internally.

**FIXED** : Authentication of a client installation works, but I get an error on the return to the Dashboard.  
`Invalid callback URL, it might be necessary for an admin to fix this.`  
This is displayed on the Pocket authentication page.  
In your Pcket-ID Client config, make sure that the callback is `http://localhost:53000`. NOT `HTTPS`.

**Are you using NetBird Cloud?**  
Self-host NetBird’s control plane.  
Hosted in a local Docker instance separate from Traefik/Pangolin.

**NetBird version**

0.51.1

**Is any other VPN software installed?**

No

**Debug output**

To help us resolve the problem, please attach the following anonymized status output

```
netbird status -dA

```

!! I am still trying to figure out how to do this with the `docker compose ` installation since there is no shell to connect to and I don’t know in which folder the netbird is running from.

Create and upload a debug bundle, and share the returned file key:

```
netbird debug for 1m -AS -U

```

!! I am still trying to figure out how to do this with the `docker compose ` installation since there is no shell to connect to and I don’t know in which folder the netbird is running from.

**Additional context**

I have attempted to follow the instructions:

- Pocket ID as IDP help · Issue #3295 · netbirdio/netbird [https://github.com/netbirdio/netbird/issues/3295](https://github.com/netbirdio/netbird/issues/3295)

- [Request failed with status code 401 (Authentik) · Issue #2941 · netbirdio/netbird · GitHub](https://github.com/netbirdio/netbird/issues/2941#issuecomment-2499011383)

- Stuck on loading screen on “/peers” (Authentik) · Issue #3007 · netbirdio/netbird [Stuck on loading screen on "/peers" (Authentik) · Issue #3007 · netbirdio/netbird · GitHub](https://github.com/netbirdio/netbird/issues/3007)

- A few posts directed to this page, the comment to the post seems to tbe the only part left: [deleted by user] : r/selfhosted [Reddit - The heart of the internet](https://www.reddit.com/r/selfhosted/comments/xpju6p/comment/iu85hqy/?utm_source=share&utm_medium=web2x&context=3)

- NetBird | Integration | Authelia [https://www.authelia.com/integration/openid-connect/clients/netbird/](https://www.authelia.com/integration/openid-connect/netbird/)

- New Relay public thread - Q&A and Issues discussions · Issue #2566 · netbirdio/netbird [New Relay public thread - Q&A and Issues discussions · Issue #2566 · netbirdio/netbird · GitHub](https://github.com/netbirdio/netbird/issues/2566)

## management.json

`RELAY-Secret-Password`=32char random value

`OICD-Client-ID`=PocketID OICD Client ID  
`OICD-Secret-ID`=PocketID OICD Client Password  
`TURN-Secret-Password`=A selfdefines password that also needs to be set int he `turnserver.conf`. The config will be line this: `user=self:TURN-Secret-Password`  
**FIXED1 Relay now working**  
The below address didn’t match the config in Traefik. It should be:  
`rels://nb.p.example.com:443/relay`. Internally 33080 was used, but since Traefik is now handling the traffic, the external details should be exposed.

```auto

    "Relay": {
        "Addresses": [
            "rels://nb.p.example.com:33080"

```

```JSON
{
    "Stuns": [
        {
            "Proto": "udp",
            "URI": "stun:nb.p.example.com:3478",
            "Username": "",
            "Password": ""
        }
    ],
    "TURNConfig": {
        "TimeBasedCredentials": false,
        "CredentialsTTL": "12h0m0s",
        "Secret": "secret",
        "Turns": [
            {
                "Proto": "udp",
                "URI": "turn:nb.p.example.com:3478",
                "Username": "self",
                "Password": "TURN-Secret-Password"
            }
        ]
    },
    "Relay": {
        "Addresses": [
            "rels://nb.p.example.com:443/relay"
        ],
        "CredentialsTTL": "24h0m0s",
        "Secret": "RELAY-Secret-Password"
    },
    "Signal": {
        "Proto": "https",
        "URI": "nb.p.example.com:443",
        "Username": "",
        "Password": null
    },
    "Datadir": "/var/lib/netbird/",
    "DataStoreEncryptionKey": "Oxx-ENC-KEY-xk=",
    "HttpConfig": {
        "LetsEncryptDomain": "",
        "CertFile": "",
        "CertKey": "",
        "AuthAudience": "OICD-Client-ID",
        "AuthIssuer": "https://pocket.p.example.com",
        "AuthUserIDClaim": "",
        "AuthKeysLocation": "https://pocket.p.example.com/.well-known/jwks.json",
        "OIDCConfigEndpoint": "https://pocket.p.example.com/.well-known/openid-configuration",
        "IdpSignKeyRefreshEnabled": false,
        "ExtraAuthAudience": ""
    },
    "IdpManagerConfig": {
        "ManagerType": "none",
        "ClientConfig": {
            "Issuer": "https://pocket.p.example.com",
            "TokenEndpoint": "https://pocket.p.example.com/api/oidc/token",
            "ClientID": "OICD-Client-ID",
            "ClientSecret": "",
            "GrantType": "client_credentials"
        },
        "ExtraConfig": {},
        "Auth0ClientCredentials": null,
        "AzureClientCredentials": null,
        "KeycloakClientCredentials": null,
        "ZitadelClientCredentials": null
    },
    "DeviceAuthorizationFlow": {
        "Provider": "hosted",
        "ProviderConfig": {
            "ClientID": "OICD-Client-ID",
            "ClientSecret": "",
            "Domain": "pocket.p.example.com",
            "Audience": "",
            "TokenEndpoint": "https://pocket.p.example.com/api/oidc/token",
            "DeviceAuthEndpoint": "https://pocket.p.example.com/api/oidc/device/authorize",
            "AuthorizationEndpoint": "",
            "Scope": "openid",
            "UseIDToken": false,
            "RedirectURLs": null,
            "DisablePromptLogin": false,
            "LoginFlag": 0
        }
    },
    "PKCEAuthorizationFlow": {
        "ProviderConfig": {
            "ClientID": "OICD-Client-ID",
            "ClientSecret": "OICD-Secret-ID",
            "Domain": "",
            "Audience": "",
            "TokenEndpoint": "https://pocket.p.example.com/api/oidc/token",
            "DeviceAuthEndpoint": "",
            "AuthorizationEndpoint": "https://pocket.p.example.com/authorize",
            "Scope": "openid profile email",
            "UseIDToken": true,
            "RedirectURLs": [
                "http://localhost:53000"
            ],
            "DisablePromptLogin": false,
            "LoginFlag": 0
        }
    },
    "StoreConfig": {
        "Engine": "sqlite"
    },
    "ReverseProxy": {
        "TrustedHTTPProxies": [],
        "TrustedHTTPProxiesCount": 0,
        "TrustedPeers": [
            "0.0.0.0/0"
        ]
    },
    "DisableDefaultPolicy": false
}

```

## compose.yaml

- I changed all the ports that are 443 and 80 to available ports. Traefik is already running on those ports and I needed to redirect from Traefik to these ports. There probably is a way for Traefik to access the containers without them being exposed. Will look into that.
- I changed all the volumes to folders that are store in the docker compose folder to allow easier backup and checking files.
- Lets Encrypt has been disabled since I am using Pangolin that handles the cert management. I talk to all the services internally on HTTP
- FIXED1: `NB_EXPOSED_ADDRESS=rels://nb.p.example.com:33080/relay` should match the Traefik and `management.json` config:  
`NB_EXPOSED_ADDRESS=rels://nb.p.example.com:443/relay`

```yaml
services:
  # UI dashboard
  dashboard:
    image: netbirdio/dashboard:latest
    restart: unless-stopped
    ports:
      - 8093:80
      - 8094:443
    environment:
      # Endpoints
      - NETBIRD_MGMT_API_ENDPOINT=https://nb.p.example.com:443
      - NETBIRD_MGMT_GRPC_API_ENDPOINT=https://nb.p.example.com:443
      # OIDC
      - AUTH_AUDIENCE=OICD-Client-ID
      - AUTH_CLIENT_ID=OICD-Client-ID
      - AUTH_CLIENT_SECRET=OICD-Secret-ID
      - AUTH_AUTHORITY=https://pocket.p.example.com
      - USE_AUTH0=false
      - AUTH_SUPPORTED_SCOPES=openid profile email
      - AUTH_REDIRECT_URI=
      - AUTH_SILENT_REDIRECT_URI=
      - NETBIRD_TOKEN_SOURCE=accessToken
      # SSL
      # - NGINX_SSL_PORT=443
      # Letsencrypt
      - LETSENCRYPT_DOMAIN=
      - LETSENCRYPT_EMAIL=
    volumes:
      # - ./netbird-letsencrypt:/etc/letsencrypt/
      - ./config/letsencrypt:/etc/letsencrypt/
    logging:
      driver: json-file
      options:
        max-size: 500m
        max-file: "2"
  # Signal
  signal:
    image: netbirdio/signal:latest
    restart: unless-stopped
    volumes:
      #- netbird-signal:/var/lib/netbird
      - ./config/signal:/var/lib/netbird
    ports:
      # - 443:80
      - 8095:80
    # # port and command for Let's Encrypt validation
    # - 443:443
    # command: ["--letsencrypt-domain", "", "--log-file", "console"]
    logging:
      driver: json-file
      options:
        max-size: 500m
        max-file: "2"
  # Relay
  relay:
    image: netbirdio/relay:latest
    restart: unless-stopped
    environment:
      - NB_LOG_LEVEL=debug
      - NB_LISTEN_ADDRESS=:33080
      - NB_EXPOSED_ADDRESS=rels://nb.p.example.com:443/relay
      - NB_AUTH_SECRET=RELAY-Secret-Password
    ports:
      - 33080:33080
    logging:
      driver: json-file
      options:
        max-size: 500m
        max-file: "2"
  # Management
  management:
    image: netbirdio/management:latest
    restart: unless-stopped
    depends_on:
      - dashboard
    volumes:
      # - netbird-mgmt:/var/lib/netbird
      # - netbird-letsencrypt:/etc/letsencrypt:ro
      # - ./management.json:/etc/netbird/management.json

      - ./config/mgmt:/var/lib/netbird
      - ./config/letsencrypt:/etc/letsencrypt:ro
      - ./config/management.json:/etc/netbird/management.json
    ports:
      - 8096:80 #API port
    # # command for Let's Encrypt validation without dashboard container
    # command: ["--letsencrypt-domain", "", "--log-file", "console"]
    command:
      - --port
      - "80"
      - --log-file
      - console
      - --log-level
      - info
      - --disable-anonymous-metrics=true
      - --single-account-mode-domain=nb.p.example.com
      - --dns-domain=netbird.selfhosted
    logging:
      driver: json-file
      options:
        max-size: 500m
        max-file: "2"
    environment:
      - NETBIRD_STORE_ENGINE_POSTGRES_DSN=
      - NETBIRD_STORE_ENGINE_MYSQL_DSN=
  # Coturn
  coturn:
    image: coturn/coturn:latest
    restart: unless-stopped
    #domainname: nb.p.example.com # only needed when TLS is enabled
    volumes:
      - ./config/turnserver.conf:/etc/turnserver.conf:ro
    # - ./privkey.pem:/etc/coturn/private/privkey.pem:ro
    # - ./cert.pem:/etc/coturn/certs/cert.pem:ro
    network_mode: host
    command:
      - -c /etc/turnserver.conf
    logging:
      driver: json-file
      options:
        max-size: 500m
        max-file: "2"

# volumes:
# netbird-mgmt:
# netbird-signal:
# netbird-letsencrypt:

```

## Traefik config

- I added the following router code to handle the direct incoming connections that are not supported by the Pangolin front end.
- I need to get the internal DNS lookups for the hosts to work so that I don’t have to use the internal IPs of the host.

```yaml
http:
  routers:
###################################################
# Netbird #########################################
###################################################

    netbird-dashboard:
      rule: "Host(`nb.p.example.com`)"
      service: netbird-dashboard
      entryPoints: 
        - websecure      
      tls:
        certResolver: letsencrypt
    
    # Netbird Relay router 
    netbird-relay-rtr:
      rule: "Host(`nb.p.example.com`) && PathPrefix(`/relay`)"
      service: netbird-relay-service
      entryPoints:
        - websecure
      tls:
        certResolver: letsencrypt

    netbird-signal:
      rule: "Host(`nb.p.example.com`) && PathPrefix(`/signalexchange.SignalExchange/`)"
      service: netbird-signal-service
      entryPoints:
        - websecure
      tls:
        certResolver: letsencrypt

    netbird-api:
      rule: "Host(`nb.p.example.com`) && (PathPrefix(`/api`) || PathPrefix(`/oidc/callback`))"
      service: netbird-api-service
      entryPoints:
        - websecure
      tls:
        certResolver: letsencrypt

    netbird-management:
      rule: "Host(`nb.p.example.com`) && PathPrefix(`/management.ManagementService/`)"
      service: netbird-management-service
      entryPoints:
        - websecure
      tls:
        certResolver: letsencrypt

  services:
    
 # Netbird services
    netbird-dashboard:
      loadBalancer:
        passHostHeader: true
        servers:
# - url: "http://netbird-dashboard:80" # Default Netbird service
          - url: "http://192.168.1.9:8093" # Default Netbird service          

    netbird-relay-service:
      loadBalancer:
        servers:
          #- url: "http://netbird-relay:33080" # Netbird Relay service 
          - url: "https://192.168.1.9:33080" # Netbird Relay service 

    netbird-signal-service:
      loadBalancer:
        servers:
          #- url: "h2c://netbird-signal:10000"
          - url: "h2c://192.168.1.9:8095"

    netbird-api-service:
      loadBalancer:
        servers:
          #- url: "http://netbird-management:80"
          - url: "http://192.168.1.9:8096"

    netbird-management-service:
      loadBalancer:
        servers:
          #- url: "h2c://netbird-management:80"
          - url: "h2c://192.168.1.9:8096"

```

Edit:

FIXED1 : RELAYs fixed. Marked the two locations fixed with `FIXED1`.

---

<div class="post-metadata">

**Author:** ![xXAzazelXx](https://forum.hhf.technology/user_avatar/forum.hhf.technology/xxazazelxx/32/3006_2.png) [@xXAzazelXx](https://forum.hhf.technology/u/xXAzazelXx)\
**Post date:** [August 11, 2025, 1:30am UTC](https://forum.hhf.technology/t/pocketid-pangolin-netbird-work-in-progress/3128/2 "2025-08-11T01:30:48Z")

</div>

Good luck!  
If you ever get the whole feature set working it would be amazing

---

<div class="post-metadata">

**Author:** ![hhf.technoloy](https://forum.hhf.technology/user_avatar/forum.hhf.technology/hhf.technoloy/32/68_2.png) [@hhf.technoloy](https://forum.hhf.technology/u/hhf.technoloy)\
**Post date:** [August 11, 2025, 2:08am UTC](https://forum.hhf.technology/t/pocketid-pangolin-netbird-work-in-progress/3128/3 "2025-08-11T02:08:52Z")

</div>

@xXAzazelXx @LeonvanHeerden got it working. will publish share it with @LeonvanHeerden and he will publish it soon

---

<div class="post-metadata">

**Author:** ![LeonvanHeerden](https://forum.hhf.technology/user_avatar/forum.hhf.technology/leonvanheerden/32/949_2.png) [@LeonvanHeerden](https://forum.hhf.technology/u/LeonvanHeerden)\
**Post date:** [August 11, 2025, 3:52pm UTC](https://forum.hhf.technology/t/pocketid-pangolin-netbird-work-in-progress/3128/4 "2025-08-11T15:52:03Z")

</div>

Yes, I am running it with Pocket ID at home.

Still want to do some cleanup of the old configs on my side, but it works great.

I can Authenticate on my Windows PC with Pocket-ID, when connecting to Netbird from the Windows Client desktop client.

---

<div class="post-metadata">

**Author:** ![xXAzazelXx](https://forum.hhf.technology/user_avatar/forum.hhf.technology/xxazazelxx/32/3006_2.png) [@xXAzazelXx](https://forum.hhf.technology/u/xXAzazelXx)\
**Post date:** [August 12, 2025, 8:01am UTC](https://forum.hhf.technology/t/pocketid-pangolin-netbird-work-in-progress/3128/5 "2025-08-12T08:01:36Z")

</div>

could you please share a guide on how you got the both running on the same VPS?

---

<div class="post-metadata">

**Author:** ![orkopaede\_78157\_9796](https://forum.hhf.technology/letter_avatar_proxy/v4/letter/o/74df32/32.png) [@orkopaede\_78157\_9796](https://forum.hhf.technology/u/orkopaede_78157_9796)\
**Post date:** [October 23, 2025, 11:38am UTC](https://forum.hhf.technology/t/pocketid-pangolin-netbird-work-in-progress/3128/6 "2025-10-23T11:38:37Z")

</div>

Hi, I tried that too, but unfortunately failed miserably. I was hoping I could simply put a haproxy or nginx in front of it and use SNI inspection or http to forward the traffic to the appropriate backends, while letting the rest just pass by, but… well… I’m afraid this is all beyond my capabilities. Do you plan on completing the guide? Otherwise, I’d just try it based on the current description. Thank you very much.

---

<div class="post-metadata">

**Author:** ![LeonvanHeerden](https://forum.hhf.technology/user_avatar/forum.hhf.technology/leonvanheerden/32/949_2.png) [@LeonvanHeerden](https://forum.hhf.technology/u/LeonvanHeerden)\
**Post date:** [October 29, 2025, 9:43pm UTC](https://forum.hhf.technology/t/pocketid-pangolin-netbird-work-in-progress/3128/7 "2025-10-29T21:43:45Z")

</div>

Sorry, have not tried this on a VPS.

---

<div class="post-metadata">

**Author:** ![LeonvanHeerden](https://forum.hhf.technology/user_avatar/forum.hhf.technology/leonvanheerden/32/949_2.png) [@LeonvanHeerden](https://forum.hhf.technology/u/LeonvanHeerden)\
**Post date:** [October 29, 2025, 9:47pm UTC](https://forum.hhf.technology/t/pocketid-pangolin-netbird-work-in-progress/3128/8 "2025-10-29T21:47:46Z")

</div>

this is basically what the Traefik config is doing here.

Based on the FQDN where it connected too, the traffic is sent to the appropriate back-end IP and port.

The Routers in the Traefik config, is the inspection part, that then directs the FQDN and path to a service entry. The Service entry directs the traffic the configured URLs.

---

<div class="post-metadata">

**Author:** ![orkopaede\_78157\_9796](https://forum.hhf.technology/letter_avatar_proxy/v4/letter/o/74df32/32.png) [@orkopaede\_78157\_9796](https://forum.hhf.technology/u/orkopaede_78157_9796)\
**Post date:** [November 20, 2025, 10:17am UTC](https://forum.hhf.technology/t/pocketid-pangolin-netbird-work-in-progress/3128/9 "2025-11-20T10:17:42Z")

</div>

Thanks for your feedback and explanation. I actually got it working now, but I’m not sure if my setup is “good.” The functions seem to be there, but is there something else I might run into problems with later? Here’s a brief overview of what I did and my haproxy.cfg file. I installed both applications one after the other in separate folders and got them running independently behind the haproxy. Then I combined both Compose files into one and extended my haproxy accordingly. What I overlooked during the first attempt was that there were connections (e.g., “Management” container “.well-known/openid-configuration”) that connected to port 443, but apparently without SNI? So I forwarded these connections, and then it worked.

```nginx
global
    maxconn 2048
    nbthread 1
    hard-stop-after 15m
    daemon
    tune.ssl.default-dh-param 2048

defaults
    log global
    mode tcp
    timeout connect 30s
    timeout client 30s
    timeout server 30s

# FRONTEND HTTPS

frontend Front-https
    bind *:6443
    mode tcp

    # Allow time for TLS ClientHello inspection
    tcp-request inspect-delay 5s
    tcp-request content accept if { req_ssl_hello_type 1 }

    # Detect SNI
    acl NB_domain req_ssl_sni -i netbird.mydomain.com

    # Detect missing SNI
    acl missing_sni req_ssl_sni -m str ""

    # Routing
    use_backend NB_nosni if missing_sni
    use_backend NB_domain-https if NB_domain

    # Fallback backend (SAFER: PG)
    default_backend PG_domain-https

# FRONTEND HTTP

frontend Front-http
    bind *:6080
    mode http

    acl NB_domain hdr(host) -i netbird.mydomain.com

    use_backend NB_domain-http if NB_domain

    default_backend PG_domain-http

# BACKEND – NetBird HTTPS

backend NB_domain-https
    mode tcp

    # TLS stickiness
    stick-table type binary len 32 size 30k expire 30m

    acl clienthello req_ssl_hello_type 1
    acl serverhello rep_ssl_hello_type 2

    tcp-request inspect-delay 5s
    tcp-request content accept if clienthello
    tcp-response content accept if serverhello

    stick on payload_lv(43,1) if clienthello
    stick store-response payload_lv(43,1) if serverhello

    server caddy caddy:443 check inter 1000

# BACKEND – NetBird HTTPS NO SNI

backend NB_nosni
    mode tcp
    server caddy caddy:443 check inter 1000

# BACKEND – Pangolin HTTPS

backend PG_domain-https
    mode tcp

    stick-table type binary len 32 size 30k expire 30m

    acl clienthello req_ssl_hello_type 1
    acl serverhello rep_ssl_hello_type 2

    tcp-request inspect-delay 5s
    tcp-request content accept if clienthello
    tcp-response content accept if serverhello

    stick on payload_lv(43,1) if clienthello
    stick store-response payload_lv(43,1) if serverhello

    server gerbil gerbil:443 check inter 1000

# BACKENDS – HTTP

backend NB_domain-http
    mode http
    server caddy caddy:80 check inter 1000

backend PG_domain-http
    mode http
    server gerbil gerbil:80 check inter 1000

```

```dockerfile
services:
  # -------------------------------------------
  # PANGOLIN
  # -------------------------------------------
  pangolin:
    image: docker.io/fosrl/pangolin:1.11.1
    container_name: pangolin
    restart: unless-stopped
    networks:
      - pangolin
    volumes:
      - ./pangolin/config:/app/config
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3001/api/v1/"]
      interval: "10s"
      timeout: "10s"
      retries: 15

  gerbil:
    image: docker.io/fosrl/gerbil:1.2.2
    container_name: gerbil
    restart: unless-stopped
    networks:
      - pangolin
    depends_on:
      pangolin:
        condition: service_healthy
    command:
      - --reachableAt=http://gerbil:3004
      - --generateAndSaveKeyTo=/var/config/key
      - --remoteConfig=http://pangolin:3001/api/v1/
    volumes:
      - ./pangolin/config/:/var/config
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    ports:
      - 61820:61820/udp
      - 21820:21820/udp
      - 7443:443
      - 7080:80
      #- 5349:5349
      #- 5349:5249/udp

  traefik:
    image: docker.io/traefik:v3.5
    container_name: traefik
    restart: unless-stopped

    network_mode: service:gerbil # Ports appear on the gerbil service

    depends_on:
      pangolin:
        condition: service_healthy
    command:
      - --configFile=/etc/traefik/traefik_config.yml
    volumes:
      - ./pangolin/config/traefik:/etc/traefik:ro # Volume to store the Traefik configuration
      - ./pangolin/config/letsencrypt:/letsencrypt # Volume to store the Let's Encrypt certificates
      - ./pangolin/config/traefik/logs:/var/log/traefik # Volume to store Traefik logs

  # -------------------------------------------
  # NETBIRD
  # -------------------------------------------

  # Caddy reverse proxy
  caddy:
    image: caddy
    container_name: caddy
    restart: unless-stopped
    networks:
      - netbird
    ports:
      - '9443:443'
      - '443:443/udp'
      - '9080:80'
    volumes:
      - netbird_caddy_data:/data
      - ./netbird/Caddyfile:/etc/caddy/Caddyfile
    logging:
      driver: "json-file"
      options:
        max-size: "500m"
        max-file: "2"

  # UI dashboard
  dashboard:
    image: netbirdio/dashboard:latest
    container_name: dashboard
    restart: unless-stopped
    networks:
      - netbird
    env_file:
      - ./netbird/dashboard.env
    logging:
      driver: "json-file"
      options:
        max-size: "500m"
        max-file: "2"

  # Signal
  signal:
    image: netbirdio/signal:latest
    container_name: signal
    restart: unless-stopped
    networks:
      - netbird
    logging:
      driver: "json-file"
      options:
        max-size: "500m"
        max-file: "2"

  # Relay
  relay:
    image: netbirdio/relay:latest
    container_name: relay
    restart: unless-stopped
    networks:
      - netbird
    env_file:
      - ./netbird/relay.env
    logging:
      driver: "json-file"
      options:
        max-size: "500m"
        max-file: "2"

  # Management
  management:
    image: netbirdio/management:latest
    container_name: management
    restart: unless-stopped
    networks:
      - netbird
    volumes:
      - netbird_management:/var/lib/netbird
      - ./netbird/management.json:/etc/netbird/management.json
    command: [
      "--port", "80",
      "--log-file", "console",
      "--log-level", "info",
      "--disable-anonymous-metrics=false",
      "--single-account-mode-domain=netbird.selfhosted",
      "--dns-domain=netbird.selfhosted",
      "--idp-sign-key-refresh-enabled",
    ]
    logging:
      driver: "json-file"
      options:
        max-size: "500m"
        max-file: "2"

  # Coturn, AKA relay server
  coturn:
    image: coturn/coturn
    container_name: coturn
    restart: unless-stopped
    #domainname: netbird.relay.selfhosted
    volumes:
      - ./netbird/turnserver.conf:/etc/turnserver.conf:ro
    network_mode: host
    command:
      - -c /etc/turnserver.conf
    logging:
      driver: "json-file"
      options:
        max-size: "500m"
        max-file: "2"

  # Zitadel - identity provider
  zitadel:
    restart: 'always'
    container_name: zitadel
    networks:
      - netbird
    image: 'ghcr.io/zitadel/zitadel:v2.64.1'
    command: 'start-from-init --masterkeyFromEnv --tlsMode external'
    env_file:
      - ./netbird/zitadel.env
    depends_on:
      zdb:
        condition: 'service_healthy'
    volumes:
      - ./netbird/machinekey:/machinekey
      - netbird_zitadel_certs:/zdb-certs:ro
    logging:
      driver: "json-file"
      options:
        max-size: "500m"
        max-file: "2"

  # Postgres for Zitadel
  zdb:
    restart: 'always'
    container_name: zdb
    networks:
      - netbird
    image: 'postgres:16-alpine'
    env_file:
      - ./netbird/zdb.env
    volumes:
      - netbird_zdb_data:/var/lib/postgresql/data:rw
    healthcheck:
      test: ["CMD-SHELL", "pg_isready", "-d", "db_prod"]
      interval: 5s
      timeout: 60s
      retries: 10
      start_period: 5s
    logging:
      driver: "json-file"
      options:
        max-size: "500m"
        max-file: "2"

  # -------------------------------------------
  # ROUTER
  # -------------------------------------------
  haproxy:
    image: haproxy:3.0
    container_name: haproxy
    restart: unless-stopped
    ports:
      - "80:6080"
      - "443:6443"
    volumes:
      - ./router/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro
    networks:
      - pangolin
      - netbird

volumes:
  netbird_zdb_data:
    external: true
    name: netbird_netbird_zdb_data
  netbird_management:
    external: true
    name: netbird_netbird_management
  netbird_caddy_data:
    external: true
    name: netbird_netbird_caddy_data
  netbird_zitadel_certs:
    external: true
    name: netbird_netbird_zitadel_certs

networks:
  netbird:
    driver: bridge
    name: netbird
  pangolin:
    driver: bridge
    name: pangolin

```

---

<div class="post-metadata">

**Author:** ![codewhiz](https://forum.hhf.technology/user_avatar/forum.hhf.technology/codewhiz/32/2365_2.png) [@codewhiz](https://forum.hhf.technology/u/codewhiz)\
**Post date:** [January 8, 2026, 9:58pm UTC](https://forum.hhf.technology/t/pocketid-pangolin-netbird-work-in-progress/3128/11 "2026-01-08T21:58:24Z")

</div>

There’s a new version of netbird which doesn’t require any IDP. Things have changed - [Release v0.62.0 · netbirdio/netbird · GitHub](https://github.com/netbirdio/netbird/releases/tag/v0.62.0)  
Haven’t tested yet tho

**Update** :  
Successfully installed Netbird under Pangolin through newt in Netbird’s docker compose file. Super Clean. Sign up and login works.  
**Problem** - But unable to connect my devices. Maybe I’ve configured the urls incorrectly

 ![screenshot-2026-01-09_03-25-25](https://forum-cdn.hhf.technology/original/2X/6/6b7cd9d00dbb99f7023b2b3645568c55ab4e3db3.jpeg)  
Request Logs shows everything fine. No idea what I missed in copying Caddyfile. Maybe it has something to do with this - [Configuration for your reverse-proxy](https://docs.netbird.io/selfhosted/selfhosted-guide#configuration-for-your-reverse-proxy)

 ![screenshot-2026-01-09_03-15-43](https://forum-cdn.hhf.technology/original/2X/7/7709ea1388065d028ed9b7f47ddda89f058b622c.jpeg)

Btw, here are steps I took to install this -

1. [Install Netbird](https://docs.netbird.io/selfhosted/selfhosted-quickstart) in ~/netbirdX/ folder with [x.example.com](http://x.example.com) pointing to netbird vps

2. Run `docker compose down` on the installed netbird stack in netbirdX folder

3. Copy ~/netbirdX/ folder’s content into ~/netbirdY/ folder with command `sudo cp -R ~/netbirdX/ ~/netbirdY/`

4. Applied few tweaks to compose file in netbirdY folder which you can find [here](https://gist.github.com/codewhizz/a7b9eaf93178e9ecef521bf1faf7ab95)  
Changes to note -

5. Change domain names in dashboard.env, management.json and relay.env from [x.example.com](http://x.example.com) to [y.example.com](http://y.example.com) and run `docker compose up -d` in netbirdY folder

6. Create new resource at [y.example.com](http://y.example.com) in Pangolin for Netbird with the rules similar to the ones in Caddyfile from netbirdY folder. Check my attachment above, to see how it looks after creation.

7. Disable Authentication for now (with rules would be good way tho)  
Now when you go to [y.example.com](http://y.example.com), it should work

Let me know if connecting devices works for anyone. That is as far I can get. Or If anyone has some solution, please share. Thank you 🙂

---

<div class="post-metadata">

**Author:** ![Selmaks](https://forum.hhf.technology/user_avatar/forum.hhf.technology/selmaks/32/2857_2.png) [@Selmaks](https://forum.hhf.technology/u/Selmaks)\
**Post date:** [January 12, 2026, 10:24am UTC](https://forum.hhf.technology/t/pocketid-pangolin-netbird-work-in-progress/3128/12 "2026-01-12T10:24:10Z")

</div>

Is your netbird running on the same vps as pangolin?

I setup Netbird 0.62 on the same instance as pangolin but I am not running it in pangolin like you. I am tempted to try now though.

I set it up similar with the installer, I let the the installer create the compose and env files I removed the caddy info from the compose file and added the services to the pangolin / traefik network ( not the best setup I guess?).

Everything seems to be working

This is my my netbird.yaml for traefik.

```auto
http:
  routers:
    netbird-dashboard:
      rule: "Host(`netbird.domain.com`)"
      service: netbird-dashboard
      entryPoints:
        - websecure
      tls:
        certResolver: letsencrypt

    netbird-oauth:
      rule: "Host(`netbird.domain.com`) && PathPrefix(`/oauth2`)"
      service: netbird-api-service
      entryPoints:
        - websecure
      tls:
        certResolver: letsencrypt
    netbird-relay-rtr:
      rule: "Host(`netbird.domain.com`) && PathPrefix(`/relay`)"
      service: netbird-relay-service
      entryPoints:
        - websecure
      tls:
        certResolver: letsencrypt
    netbird-signal:
      rule: "Host(`netbird.domain.com`) && PathPrefix(`/signalexchange.SignalExchange/`)"
      service: netbird-signal-service
      entryPoints:
        - websecure
      tls:
        certResolver: letsencrypt
    netbird-api:
      rule: "Host(`netbird.domain.com`) && (PathPrefix(`/api`) || PathPrefix(`/oidc/callback`))"
      service: netbird-api-service
      entryPoints:
        - websecure
      tls:
        certResolver: letsencrypt
    netbird-management:
      rule: "Host(`netbird.domain.com`) && PathPrefix(`/management.ManagementService/`)"
      service: netbird-management-service
      entryPoints:
        - websecure
      tls:
        certResolver: letsencrypt
  services:
    netbird-dashboard:
      loadBalancer:
        passHostHeader: true
        servers:
          - url: "http://netbird-dashboard-1:80"

    netbird-relay-service:
      loadBalancer:
        servers:
          - url: "http://netbird-relay-1:33080"

    netbird-signal-service:
      loadBalancer:
        servers:
          - url: "h2c://netbird-signal-1:10000"

    netbird-api-service:
      loadBalancer:
        servers:
          - url: "http://netbird-management-1:33073"

    netbird-management-service:
      loadBalancer:
        servers:
          - url: "h2c://netbird-management-1:33073"

```

I did noticed your service ports are different to mine.

---

<div class="post-metadata">

**Author:** ![codewhiz](https://forum.hhf.technology/user_avatar/forum.hhf.technology/codewhiz/32/2365_2.png) [@codewhiz](https://forum.hhf.technology/u/codewhiz)\
**Post date:** [January 12, 2026, 10:40am UTC](https://forum.hhf.technology/t/pocketid-pangolin-netbird-work-in-progress/3128/13 "2026-01-12T10:40:10Z")

</div>

Oh great! But no, I’m running pangolin and netbird on different instances. I can’t run both on same instance. Because I have each instance with 1 GB RAM only.

> [@Selmaks](#):
>
> I did noticed your service ports are different to mine.

I think that could be because they recently changed how we could expose ports I guess. I am not expert in this. Just copied their caddy configuration from their latest Quick start setup guide installation.

Btw, the procedure I shared above is not working for connecting devices, which makes it useless. Only dashboard viewing is working though. That is how far I could get.

So, I’m back to caddy setup using official way for now. But if someone gets it working, it would be great to run Netbird under Pangolin with 2 different machines.

---

<div class="post-metadata">

**Author:** ![hhf.technoloy](https://forum.hhf.technology/user_avatar/forum.hhf.technology/hhf.technoloy/32/68_2.png) [@hhf.technoloy](https://forum.hhf.technology/u/hhf.technoloy)\
**Post date:** [January 12, 2026, 12:04pm UTC](https://forum.hhf.technology/t/pocketid-pangolin-netbird-work-in-progress/3128/14 "2026-01-12T12:04:12Z")

</div>

i have it working. will post it soon

---

<div class="post-metadata">

**Author:** ![Selmaks](https://forum.hhf.technology/user_avatar/forum.hhf.technology/selmaks/32/2857_2.png) [@Selmaks](https://forum.hhf.technology/u/Selmaks)\
**Post date:** [January 12, 2026, 11:02pm UTC](https://forum.hhf.technology/t/pocketid-pangolin-netbird-work-in-progress/3128/15 "2026-01-12T23:02:28Z")

</div>

> [@codewhiz](#):
>
> I think that could be because they recently changed how we could expose ports I guess

I am just using the default, I know there is an issues with the signal port mapping being changed atm. [Signal service connection issue - incorrect port mapping](https://github.com/netbirdio/netbird/issues/4762)

I had this problem when I first setup Netbird on another server. This time around I left everyting as default.

> [@hhf.technoloy](#):
>
> i have it working. will post it soon

Awesome

---

<div class="post-metadata">

**Author:** ![codewhiz](https://forum.hhf.technology/user_avatar/forum.hhf.technology/codewhiz/32/2365_2.png) [@codewhiz](https://forum.hhf.technology/u/codewhiz)\
**Post date:** [February 13, 2026, 12:47pm UTC](https://forum.hhf.technology/t/pocketid-pangolin-netbird-work-in-progress/3128/16 "2026-02-13T12:47:32Z")

</div>

Hey @Selmaks, got it working, check it out here - [NetBird + Pangolin (Pangolin as reverse proxy for NetBird) Setup Guide](https://forum.hhf.technology/t/netbird-pangolin-pangolin-as-reverse-proxy-for-netbird-setup-guide/4274)

---

<div class="post-metadata">

**Author:** ![hhf.technoloy](https://forum.hhf.technology/user_avatar/forum.hhf.technology/hhf.technoloy/32/68_2.png) [@hhf.technoloy](https://forum.hhf.technology/u/hhf.technoloy)\
**Post date:** [February 13, 2026, 2:19pm UTC](https://forum.hhf.technology/t/pocketid-pangolin-netbird-work-in-progress/3128/17 "2026-02-13T14:19:39Z")

</div>

@codewhiz I have pinned your post.

New discussion on [NetBird + Pangolin (Pangolin as reverse proxy for NetBird) Setup Guide](https://forum.hhf.technology/t/netbird-pangolin-pangolin-as-reverse-proxy-for-netbird-setup-guide/4274)

Locking this thread

---

<div class="post-metadata">

**Author:** ![hhf.technoloy](https://forum.hhf.technology/user_avatar/forum.hhf.technology/hhf.technoloy/32/68_2.png) [@hhf.technoloy](https://forum.hhf.technology/u/hhf.technoloy)\
**Post date:** [February 13, 2026, 2:21pm UTC](https://forum.hhf.technology/t/pocketid-pangolin-netbird-work-in-progress/3128/18 "2026-02-13T14:21:38Z")

</div>


