Installation script issues

Updated

Problems running the self-hosted getting-started.sh script. For other areas, start from Troubleshooting.

Script hangs on "Waiting for NetBird server to become ready"

Symptom: The getting-started.sh script stays on the wait line for several minutes, even though netbird-server looks healthy in docker ps.

What the wait checks depends on the reverse proxy option you picked:

  • Options 0 and 1 (Traefik): the script probes the OIDC endpoint at your public hostname through your reverse proxy, so a healthy server alone isn't enough. Something on the path to netbird-server is broken. The probe runs from the installation host itself, so first run the curl in step 5 below from both that host and a machine outside your network. If only the host fails, the host can't reach its own public address (some NAT setups don't support this), and external clients may be fine. Otherwise, work through the causes below.
  • Options 2 to 5 (Nginx, Nginx Proxy Manager, Caddy, other): the script probes netbird-server directly on http://127.0.0.1:8081, with no proxy in the path. A hang here means netbird-server itself isn't healthy, so start with docker compose logs netbird-server.

After about two minutes of waiting, the script prints Taking too long. Checking logs... followed by the last 20 log lines from netbird-server, and from Traefik when the script can find its container. Read that output first; it often names the problem.

Check these likely causes in order, most common first:

1. DNS doesn't point at the host

dig +short netbird.example.com

The result should be the public IP of the VM running NetBird. If it's empty or wrong, the cert challenge can't complete and the probe never succeeds.

2. The certificate didn't issue

For options 0 (built-in Traefik) and 1 (existing Traefik), check that a real cert was issued:

curl -vI https://netbird.example.com 2>&1 | grep -E "subject|issuer"

A self-signed or default cert means ACME hasn't completed. Check Traefik logs for ACME errors. Common causes: TCP/443 not reachable from the internet, DNS not propagated yet, or a Let's Encrypt rate limit. The built-in Traefik (option 0) validates with the TLS-ALPN-01 challenge on port 443, so port 80 doesn't affect issuance. With option 1, the challenge depends on your Traefik's certificate resolver.

3. Traefik can't read the Docker socket (option 1 only)

Traefik discovers NetBird containers via Docker labels. If the socket is mounted but unreadable (old SDK, wrong path, permission denied), routes never get created. Check Traefik logs for client version is too old or permission denied while trying to connect to the Docker daemon socket.

4. Traefik and NetBird aren't on the same network (option 1 only)

docker network inspect <your-network-name> | grep -A 2 Containers

You should see both Traefik and the NetBird containers listed.

5. Routing fails end to end

If the four above look fine, test the full path manually:

curl -k https://netbird.example.com/oauth2/.well-known/openid-configuration

A valid response is JSON containing "issuer". Anything else points to where to dig: 502 means Traefik can't reach netbird-server, 404 means the labels aren't matched, connection refused means you're not hitting Traefik at all.

Confirm: The probe succeeds and the script continues on its own. You can leave it waiting while you debug. To start over instead, stop it with Ctrl+C, remove the generated files as shown in Script fails on existing installation check, fix the issue, and re-run. docker compose down -v on its own leaves config.yaml behind, and the script refuses to run while that file exists.

Script fails on existing installation check

Symptom: The script exits immediately with a message about generated files already existing.

Cause: This is intentional, and protects a working setup from being overwritten.

Fix: To start fresh (this removes all NetBird data, including users and peers):

docker compose down --volumes
rm -f docker-compose.yml dashboard.env config.yaml proxy.env \
      traefik-dynamic.yaml nginx-netbird.conf caddyfile-netbird.txt \
      npm-advanced-config.txt
rm -rf crowdsec/

Confirm: Re-run the script; it proceeds past the existing-installation check and starts provisioning.