Clients fail to connect on self hosted server - possibly signal certificate issue following #4644?
Attempted to deploy a new server on a VPS this morning (version 0.59.12, Azure as IdP and Let's Encrypt certs which I've obtained on host using certbot myself). Although I can authenticate ok and clients get registered, clients then fail to connect to the network:
Client log:
2025-11-06T12:26:50Z INFO ./caller_not_available:0: 2025/11/06 12:26:50 WARNING: [core] [Channel #116 SubChannel #117]grpc: addrConn.createTransport failed to connect to {Addr: "<SERVER IP>:33073", ServerName: "vpn.<SERVER DOMAIN>:33073", BalancerAttributes: {"<%!p(pickfirstleaf.managedByPickfirstKeyType={})>": "<%!p(bool=true)>" }}. Err: connection error: desc = "transport: Error while dialing: nbnet.NewDialer().DialContext: dial tcp <SERVER IP>:33073: connectex: No connection could be made because the target machine actively refused it."
I've modified the docker-compose.yml to change volumes from netbird-letsencrypt to /etc/netbird for dashboard, signal, and management containers. Otherwise it's the standard docker-compose as generated, following the Netbird self hosted guide for Azure IdP
Certificates appear to work correctly for dashboard at least, as I can successfully log in and I can see the "offline" client, but certs are not working with signal container. Initially signal logs showing it couldn't find the certs due to certs on docker host being symbolically linked, but even if I address this, client connection still fails. This is the output from the signal container:
2025-11-06T09:42:39Z INFO signal/cmd/run.go:236: setting up TLS with custom certificates.
2025-11-06T09:42:39Z INFO signal/cmd/run.go:150: running HTTPS server with WebSocket proxy: [::]:443
2025-11-06T09:42:39Z INFO signal/cmd/run.go:161: running gRPC backward compatibility server: [::]:10000
2025-11-06T09:42:39Z INFO signal/cmd/run.go:164: signal server version 0.59.12
2025-11-06T09:42:39Z INFO signal/cmd/run.go:165: started Signal Service
2025-11-06T09:42:39Z INFO signal/cmd/run.go:111: running metrics server: :9090/metrics
Using exactly the same setup/config, works fine using 0.59.8 so I believe this is an issue introduced by "[signal] Fix HTTP/WebSocket proxy not using custom certificates #4644" (https://github.com/netbirdio/netbird/pull/4644)
Full docker-compose.yml:
x-default: &default
restart: 'unless-stopped'
logging:
driver: 'json-file'
options:
max-size: '500m'
max-file: '2'
services:
# UI dashboard
dashboard:
<<: *default
image: netbirdio/dashboard:latest
ports:
- 80:80
- 443:443
environment:
# Endpoints
- NETBIRD_MGMT_API_ENDPOINT=https://vpn.<SERVER DOMAIN>:33073
- NETBIRD_MGMT_GRPC_API_ENDPOINT=https://vpn.<SERVER DOMAIN>:33073
# OIDC
- AUTH_AUDIENCE=<APP ID>
- AUTH_CLIENT_ID=<APP ID>
- AUTH_CLIENT_SECRET=
- AUTH_AUTHORITY=https://login.microsoftonline.com/<TENANT ID>/v2.0
- USE_AUTH0=false
- AUTH_SUPPORTED_SCOPES=openid profile email offline_access User.Read api://<APP ID>/api
- AUTH_REDIRECT_URI=/auth
- AUTH_SILENT_REDIRECT_URI=/silent-auth
- NETBIRD_TOKEN_SOURCE=idToken
# SSL
- NGINX_SSL_PORT=443
# Letsencrypt
- LETSENCRYPT_DOMAIN=vpn.<SERVER DOMAIN>
- LETSENCRYPT_EMAIL=<MY EMAIL>
volumes:
- /etc/letsencrypt:/etc/letsencrypt/
# Signal
signal:
<<: *default
image: netbirdio/signal:latest
depends_on:
- dashboard
volumes:
- netbird-signal:/var/lib/netbird
- /etc/letsencrypt:/etc/letsencrypt:ro
ports:
- 10000:80
# # port and command for Let's Encrypt validation
# - 443:443
# command: ["--letsencrypt-domain", "vpn.<SERVER DOMAIN>", "--log-file", "console"]
command: [
"--cert-file", "/etc/letsencrypt/live/vpn.<SERVER DOMAIN>/fullchain.pem",
"--cert-key", "/etc/letsencrypt/live/vpn.<SERVER DOMAIN>/privkey.pem",
"--log-file", "console"
]
# Relay
relay:
<<: *default
image: netbirdio/relay:latest
environment:
- NB_LOG_LEVEL=info
- NB_LISTEN_ADDRESS=:33080
- NB_EXPOSED_ADDRESS=rel://vpn.<SERVER DOMAIN>:33080
# todo: change to a secure secret
- NB_AUTH_SECRET=<SECRET>
ports:
- 33080:33080
# Management
management:
<<: *default
image: netbirdio/management:latest
depends_on:
- dashboard
volumes:
- netbird-mgmt:/var/lib/netbird
- netbird-letsencrypt:/etc/letsencrypt:ro
- ./management.json:/etc/netbird/management.json
ports:
- 33073:443 #API port
# # command for Let's Encrypt validation without dashboard container
# command: ["--letsencrypt-domain", "vpn.<SERVER DOMAIN>", "--log-file", "console"]
command: [
"--port", "443",
"--log-file", "console",
"--log-level", "info",
"--disable-anonymous-metrics=false",
"--single-account-mode-domain=remotevpn.<SERVER DOMAIN>",
"--dns-domain=netbird.selfhosted"
]
environment:
- NETBIRD_STORE_ENGINE_POSTGRES_DSN=
- NETBIRD_STORE_ENGINE_MYSQL_DSN=
# Coturn
coturn:
<<: *default
image: coturn/coturn:latest
#domainname: vpn.<SERVER DOMAIN> # only needed when TLS is enabled
volumes:
- ./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
volumes:
netbird-mgmt:
netbird-signal:
netbird-letsencrypt:
pinging @bcmmbaga . Thanks in advance!
I too am having this problem. I deployed a new Netbird instance this month and ran into this with my first client. After troubleshooting, it looks like the docker port is mapping 10000 to port 80 inside the container, but I do not see anything listening inside the container on port 80.
root@myhost:~/netbird/infrastructure_files/artifacts# docker compose exec signal sh
/ # netstat -antlp
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.1:6060 0.0.0.0:* LISTEN 1/netbird-signal
tcp 0 0 127.0.0.11:39981 0.0.0.0:* LISTEN -
tcp 0 0 :::10000 :::* LISTEN 1/netbird-signal
tcp 0 0 :::9090 :::* LISTEN 1/netbird-signal
tcp 0 0 :::443 :::* LISTEN 1/netbird-signal
/ #
root@myhost:~/netbird/infrastructure_files/artifacts# docker compose port signal 80
0.0.0.0:10000
I did update my netbird repository to the latest tag & re-ran configure.sh just in case the docker-compose template file had been updated.
I setup a self-hosted netbird this week, and finally got to connecting a client today and ran into this problem, which brought me here.
But, this thread was super helpful:
root@myhost:~/netbird/infrastructure_files/artifacts# docker compose port signal 80 0.0.0.0:10000
Thank you for your investigation and sharing this, @welbow ! This was the key to resolving this for me.
- First, I ran
docker compose down - Then I edited
docker-compose.yml- under the signal section, changed the ports configuration from
- 10000:80to- 10000:10000
- under the signal section, changed the ports configuration from
- Then I ran
docker compose up - dand tested again and it all worked!
So that is the key. I won't have time to submit any changes or pull requests or anything this weekend, but I wanted to report back that making this change worked for me.
Thank you, thank you!
@davidpryke Thank you sir, that fixed my problem as well. Netbird should update their repo!
Hello @fishboy25uk @welbow @davidpryke @wbarnard81!
Are you guys running with lets encrypt (https) enabled? If so, that might be the issue with port 80 hardcoded. If the certs are set then the signal goes for https/443 instead of 80, causing this mismatch of ports.
But port 10000 will always work due to a fallback for old client versions that rely on it for grpc.
I wonder if you can test the same scenario you are trying to achieve, but with port 443 hardcoded in the place of 10000. If that works it will confirm this point of having the setup based on TLS/HTTPS that causes signal to listen on port 443.
Then we can figure out a way to handle the internal container port dinamically.
The port 443 is suggested on this PR -> https://github.com/netbirdio/netbird/pull/4763
Are you guys running with lets encrypt (https) enabled?
I am indeed running with LE certs per the Advanced install guide in the docs.