Describe the problem
Hello all! I’ve just joined the NetBird self-hosted club after hearing about the introduction of the reverse proxy feature. I’m having some difficulties (probably due to some misunderstandings about the architecture). I don’t want to make this too long but I feel there’s a lot of context, thanks in advance!
So I have a homelab on a Raspberry Pi running a variety of typical services. Jellyfin, Pi-Hole, Immich, etc. Previously, I used Nginx as the proxy manager and NetBird cloud to VPN to my services when away from home. Now I am trying to transition to self-hosting NetBird as a proxy manager and making the services available publicly, lowering the barrier of entry for friends and family looking for something that “just works”. The way I have it set up now is with an old laptop running Arch. The NetBird instance is running in a VM on it (also Arch) which through several layers of firewalls is completely locked down from the rest of my LAN, but ports 80, 443, and 3478/udp are forwarded to it on my router (my best attempt at a VLAN substitution). I am using two domains managed by Cloudflare, andin addition to the management server, also have a NetBird client running so it can connect to the rest of my LAN as a peer, so it can use NetBird IPs and I can block requests to the local subnet.
Setting all that up was a pain, but the real issue I’m having is that when I create a service that points to a peer and port, the certificate is never issued. I’ve tried a couple of different ways of doing ssl: Letting the proxy handle it, letting the netbird-server handle it, downloading certificates from cloudflare and pointing to them. I’m not entirely sure where to start anymore. What’s the best way to go about this?
Are you using NetBird Cloud?
No, I am self-hosting.
NetBird version
0.65.3
Is any other VPN software installed?
No
Debug output
Compose.yml
services:
# Traefik reverse proxy (automatic TLS via Let's Encrypt)
traefik:
image: traefik:v3.6
container_name: netbird-traefik
restart: unless-stopped
networks:
netbird:
ipv4_address: 172.30.0.10
command:
# Logging
- "--log.level=INFO"
- "--accesslog=true"
# Docker provider
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--providers.docker.network=netbird"
# Entrypoints
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--entrypoints.websecure.allowACMEByPass=true"
# Disable timeouts for long-lived gRPC streams
- "--entrypoints.websecure.transport.respondingTimeouts.readTimeout=0"
- "--entrypoints.websecure.transport.respondingTimeouts.writeTimeout=0"
- "--entrypoints.websecure.transport.respondingTimeouts.idleTimeout=0"
# HTTP to HTTPS redirect
- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
- "--entrypoints.web.http.redirections.entrypoint.scheme=https"
# Let's Encrypt ACME
- "--certificatesresolvers.letsencrypt.acme.email=example@gmail.com"
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
- "--certificatesresolvers.letsencrypt.acme.tlschallenge=true"
# gRPC transport settings
- "--serverstransport.forwardingtimeouts.responseheadertimeout=0s"
- "--serverstransport.forwardingtimeouts.idleconntimeout=0s"
- "--providers.file.filename=/etc/traefik/dynamic.yaml"
ports:
- '443:443/tcp'
- '443:443/udp'
- '80:80'
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./netbird_traefik_letsencrypt:/letsencrypt
- ./traefik-dynamic.yaml:/etc/traefik/dynamic.yaml:ro
logging:
driver: "json-file"
options:
max-size: "500m"
max-file: "2"
# UI dashboard
dashboard:
image: netbirdio/dashboard:latest
container_name: netbird-dashboard
restart: unless-stopped
networks: [netbird]
env_file:
- ./dashboard.env
labels:
- traefik.enable=true
- traefik.http.routers.netbird-dashboard.rule=Host(`netbird.domain1.com`)
- traefik.http.routers.netbird-dashboard.entrypoints=websecure
- traefik.http.routers.netbird-dashboard.tls=true
- traefik.http.routers.netbird-dashboard.tls.certresolver=letsencrypt
- traefik.http.routers.netbird-dashboard.service=dashboard
- traefik.http.routers.netbird-dashboard.priority=1
- traefik.http.services.dashboard.loadbalancer.server.port=80
logging:
driver: "json-file"
options:
max-size: "500m"
max-file: "2"
# Combined server (Management + Signal + Relay + STUN)
netbird-server:
image: netbirdio/netbird-server:latest
container_name: netbird-server
restart: unless-stopped
networks: [netbird]
ports:
- '3478:3478/udp'
volumes:
- ./netbird_data:/var/lib/netbird
- ./config.yaml:/etc/netbird/config.yaml
command: ["--config", "/etc/netbird/config.yaml"]
labels:
- traefik.enable=true
# gRPC router (needs h2c backend for HTTP/2 cleartext)
- traefik.http.routers.netbird-grpc.rule=Host(`netbird.domain1.com`) && (PathPrefix(`/signalexchange.SignalExchange/`) || PathPrefix(`/management.ManagementService/`) || PathPrefix(`/management.ProxyService/`))
- traefik.http.routers.netbird-grpc.entrypoints=websecure
- traefik.http.routers.netbird-grpc.tls=true
- traefik.http.routers.netbird-grpc.tls.certresolver=letsencrypt
- traefik.http.routers.netbird-grpc.service=netbird-server-h2c
- traefik.http.routers.netbird-grpc.priority=1000 #100
# Backend router (relay, WebSocket, API, OAuth2)
- traefik.http.routers.netbird-backend.rule=Host(`netbird.domain1.com`) && (PathPrefix(`/relay`) || PathPrefix(`/ws-proxy/`) || PathPrefix(`/api`) || PathPrefix(`/oauth2`))
- traefik.http.routers.netbird-backend.entrypoints=websecure
- traefik.http.routers.netbird-backend.tls=true
- traefik.http.routers.netbird-backend.tls.certresolver=letsencrypt
- traefik.http.routers.netbird-backend.service=netbird-server
- traefik.http.routers.netbird-backend.priority=100
# Services
- traefik.http.services.netbird-server.loadbalancer.server.port=80
- traefik.http.services.netbird-server-h2c.loadbalancer.server.port=80
- traefik.http.services.netbird-server-h2c.loadbalancer.server.scheme=h2c
logging:
driver: "json-file"
options:
max-size: "500m"
max-file: "2"
# NetBird Proxy - exposes internal resources to the internet
proxy:
image: netbirdio/reverse-proxy:latest
container_name: netbird-proxy
ports:
- 51820:51820/udp
restart: unless-stopped
networks: [netbird]
depends_on:
- netbird-server
env_file:
- ./proxy.env
volumes:
- ./netbird_proxy_certs:/certs
- ./netbird_proxy_data:/var/lib/netbird
- ./wireguard:/var/run/wireguard
labels:
# TCP passthrough for any unmatched domain (proxy handles its own TLS)
- traefik.enable=true
- traefik.tcp.routers.proxy-passthrough.entrypoints=websecure
- traefik.tcp.routers.proxy-passthrough.rule=HostSNI(`*`)
- traefik.tcp.routers.proxy-passthrough.tls.passthrough=true
- traefik.tcp.routers.proxy-passthrough.service=proxy-tls
- traefik.tcp.routers.proxy-passthrough.priority=1
- traefik.tcp.services.proxy-tls.loadbalancer.server.port=8443
- traefik.tcp.services.proxy-tls.loadbalancer.serverstransport=pp-v2@file
logging:
driver: "json-file"
options:
max-size: "500m"
max-file: "2"
volumes:
netbird_data:
netbird_traefik_letsencrypt:
netbird_proxy_certs:
networks:
netbird:
name: netbird
driver: bridge
ipam:
config:
- subnet: 172.30.0.0/24
gateway: 172.30.0.1
proxy.env
NB_PROXY_TOKEN=nbx_<redacted>
NB_PROXY_MANAGEMENT_ADDRESS=https://netbird.domain1.com
NB_PROXY_DOMAIN=proxy-domain.online
NB_PROXY_ADDRESS=:8443
NB_PROXY_ACME_CERTIFICATES=false
NB_LOG_LEVEL=debug
NB_PROXY_ACME_CHALLENGE_TYPE=tls-alpn-01
NB_PROXY_CERTIFICATE_DIRECTORY=/certs
NB_PROXY_ALLOW_INSECURE=true
NB_PROXY_CERTIFICATE_FILE=tls.crt
NB_PROXY_CERTIFICATE_KEY_FILE=tls.key
Docker proxy log
netbird-proxy | 2026-02-24T05:52:07.015Z WARN [peer: <redacted>] client/internal/peer/worker_ice.go:160: ICE Agent is not initialized yet
netbird-proxy | 2026-02-24T05:52:07.015Z WARN [peer: <redacted>] client/internal/peer/worker_ice.go:160: ICE Agent is not initialized yet
netbird-proxy | 2026-02-24T05:54:15.403Z WARN client/internal/peer/guard/ice_monitor.go:65: Failed to check ICE changes: wait for gathering timed out
netbird-proxy | 2026-02-24T05:55:39.488Z WARN [peer: <redacted>] client/internal/peer/worker_ice.go:160: ICE Agent is not initialized yet
Screenshots
Additional context
Add any other context about the problem here.
Have you tried these troubleshooting steps?
- Reviewed client troubleshooting (if applicable)
- Checked for newer NetBird versions
- Searched for similar issues on GitHub (including closed ones)
- Restarted the NetBird client
- Disabled other VPN software
- Checked firewall settings
