From 5cd67d5c0263d7619e34f82433a44d3b1a3e4dde Mon Sep 17 00:00:00 2001 From: Brandon Hopkins Date: Wed, 22 Apr 2026 07:15:11 -0700 Subject: [PATCH 1/2] Crowdsec Updates --- src/pages/manage/reverse-proxy/access-logs.mdx | 2 +- src/pages/manage/reverse-proxy/authentication.mdx | 2 +- src/pages/selfhosted/migration/enable-reverse-proxy.mdx | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/pages/manage/reverse-proxy/access-logs.mdx b/src/pages/manage/reverse-proxy/access-logs.mdx index 2fc6a217..508b721e 100644 --- a/src/pages/manage/reverse-proxy/access-logs.mdx +++ b/src/pages/manage/reverse-proxy/access-logs.mdx @@ -73,7 +73,7 @@ The following deny reasons can appear for both HTTP and L4 services: All CrowdSec decision types (ban, captcha, throttle) result in a connection denial in enforce mode. The proxy does not serve captcha challenges or apply rate limiting: the decision type is recorded for informational purposes only. -When CrowdSec is in **observe** mode, the verdict appears in the log metadata but the deny reason field is empty (the connection is allowed). This lets you audit what CrowdSec would block without affecting traffic. +When CrowdSec is in **observe** mode, the verdict appears in the log metadata but the deny reason field is empty (the connection is allowed). In the dashboard, these entries render with an observe-mode badge on the reason cell and show the underlying decision type (ban, captcha, throttle, unavailable) on hover. This lets you audit what CrowdSec would block without affecting traffic. For a self-test workflow, see [Testing the integration](/selfhosted/maintenance/crowdsec#testing-the-integration). ## Use cases diff --git a/src/pages/manage/reverse-proxy/authentication.mdx b/src/pages/manage/reverse-proxy/authentication.mdx index 55602621..511411c6 100644 --- a/src/pages/manage/reverse-proxy/authentication.mdx +++ b/src/pages/manage/reverse-proxy/authentication.mdx @@ -182,7 +182,7 @@ CrowdSec operates in one of three modes per service: |------|----------| | **Off** | CrowdSec checks are disabled for this service (default). | | **Enforce** | Connections from flagged IPs are denied immediately. If the CrowdSec bouncer has not completed its initial sync, all connections are denied (fail-closed). | -| **Observe** | Connections from flagged IPs are logged in [access logs](/manage/reverse-proxy/access-logs) but not blocked. Use this to evaluate the impact before switching to enforce. | +| **Observe** | Connections from flagged IPs are logged in [access logs](/manage/reverse-proxy/access-logs) with an observe-mode badge but not blocked. Use this to evaluate the impact before switching to enforce. See [Reviewing observe-mode verdicts](/selfhosted/maintenance/crowdsec#reviewing-observe-mode-verdicts) for how to audit them. | CrowdSec decisions include different remediation types (ban, captcha, throttle). The proxy treats all types as connection denials in enforce mode: there is no captcha challenge or rate limiting. The specific decision type is recorded in the [access logs](/manage/reverse-proxy/access-logs) so you can distinguish between them when reviewing traffic. diff --git a/src/pages/selfhosted/migration/enable-reverse-proxy.mdx b/src/pages/selfhosted/migration/enable-reverse-proxy.mdx index a145573f..3a53e8d5 100644 --- a/src/pages/selfhosted/migration/enable-reverse-proxy.mdx +++ b/src/pages/selfhosted/migration/enable-reverse-proxy.mdx @@ -349,7 +349,9 @@ You should see `CrowdSec bouncer synced initial decisions` once the LAPI connect #### 7d. Enable per service -CrowdSec must be enabled individually on each service through the dashboard under **Access Control > Access Restrictions**. Set the CrowdSec mode to **enforce** or **observe**. +CrowdSec must be enabled individually on each service through the dashboard under **Access Control**. Set the CrowdSec mode to **enforce** or **observe**. + +![CrowdSec IP Reputation Overview](/docs-static/img/selfhosted/maintenance/crowdsec-overview.png) In **enforce** mode, if the bouncer has not completed its initial sync with the LAPI, all connections to that service will be denied. This is by design (fail-closed). If you want to avoid this during initial rollout, start with **observe** mode. From 8c244f759092abf6d0d48c7cc54b15171dbcd8b6 Mon Sep 17 00:00:00 2001 From: Brandon Hopkins Date: Mon, 27 Apr 2026 13:24:57 -0700 Subject: [PATCH 2/2] Improve Traefik docs --- .../selfhosted/external-reverse-proxy.mdx | 35 ++++++++++ src/pages/selfhosted/troubleshooting.mdx | 69 +++++++++++++++++++ 2 files changed, 104 insertions(+) diff --git a/src/pages/selfhosted/external-reverse-proxy.mdx b/src/pages/selfhosted/external-reverse-proxy.mdx index 818b9da0..41404a56 100644 --- a/src/pages/selfhosted/external-reverse-proxy.mdx +++ b/src/pages/selfhosted/external-reverse-proxy.mdx @@ -35,6 +35,41 @@ The script will generate the appropriate configuration files and provide setup i This option is only available during initial setup with `getting-started.sh`. For existing deployments, use the manual configuration templates below. +### Using the script with an existing Traefik (Option 1) + +If you select option `[1]` (Existing Traefik), the script generates a Docker Compose file with Traefik labels for the dashboard and netbird-server containers. It does not run Traefik for you. Your existing Traefik instance handles TLS termination, certificate issuance, and routing. + +#### Before you run the script + +Make sure these are in place first: + +- Traefik is already running on the same host +- Traefik joins a Docker network you can attach the NetBird containers to +- Traefik has an HTTPS entrypoint configured (default: `websecure`) +- Traefik has a working certificate resolver (Let's Encrypt or otherwise) +- Your domain (e.g. `netbird.example.com`) resolves to the host's public IP +- Ports 80 and 443 on the host are reachable from the internet + +If your cert resolver isn't working before you start, NetBird won't magically fix it. Test that Traefik can issue certs for any other service first. + +#### What the script will ask you + +When you choose option 1, the script prompts for three things: + +| Prompt | What to enter | +|--------|---------------| +| External network | The Docker network name your Traefik is on (e.g. `proxy`) | +| HTTPS entrypoint name | Your Traefik HTTPS entrypoint (default: `websecure`) | +| Certificate resolver name | Your cert resolver name (e.g. `letsencrypt`). Leave empty if you handle TLS some other way | + +#### What the script does + +After you answer the prompts, the script writes a `docker-compose.yml` with the right Traefik labels, brings up the dashboard and netbird-server containers, and waits for the server to become reachable through your Traefik instance. + +The readiness check probes `https://your-domain/oauth2/.well-known/openid-configuration` through the proxy. The script auto-detects your Traefik container (any container running a Traefik image with ports 80 and 443 published) so it can pull diagnostic logs if something goes wrong. + +If the wait check hangs, see [Installation Script Issues](/selfhosted/troubleshooting#installation-script-issues) for the common causes. + ### Existing Deployments For existing NetBird installations, use the configuration templates in the sections below to manually configure your reverse proxy. diff --git a/src/pages/selfhosted/troubleshooting.mdx b/src/pages/selfhosted/troubleshooting.mdx index bf0d6d90..94d18150 100644 --- a/src/pages/selfhosted/troubleshooting.mdx +++ b/src/pages/selfhosted/troubleshooting.mdx @@ -66,6 +66,75 @@ This page will help with various issues when self-hosting NetBird. - Check that the SSO flow completes successfully (user should land on Dashboard) - Review Management logs for any token validation errors +## Installation Script Issues + +### Script hangs on "Waiting for NetBird server to become ready" + +**Problem**: The `getting-started.sh` script stays on the wait line for several minutes, even though netbird-server itself looks healthy in `docker ps`. + +The wait check probes the OIDC endpoint through your reverse proxy, so a healthy server alone isn't enough. Something on the path from the public internet to netbird-server is broken. Check these in order: + +**1. DNS** + +Confirm your domain points at the host: + +```bash +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 will never succeed. + +**2. Cert issuance** + +For options 0 (built-in Traefik) and 1 (existing Traefik), check that a real cert was issued: + +```bash +curl -vI https://netbird.example.com 2>&1 | grep -E "subject|issuer" +``` + +If you see a self-signed or default cert, ACME hasn't completed. Check Traefik logs for ACME errors. Common causes: port 80 not reachable from the internet, DNS not propagated yet, or Let's Encrypt rate limit hit. + +**3. Traefik can talk to the Docker socket (option 1 only)** + +Traefik discovers NetBird containers via Docker labels. If the Docker socket is mounted but Traefik can't read it (old SDK, wrong path, permission denied), routes never get created. Check Traefik logs for errors like `client version is too old` or `permission denied while trying to connect to the Docker daemon socket`. + +**4. Network membership matches (option 1 only)** + +Confirm the Traefik container and NetBird containers are actually on the same Docker network: + +```bash +docker network inspect | grep -A 2 Containers +``` + +You should see both Traefik and the NetBird containers listed. + +**5. Routing works end to end** + +If the four above look fine, test the full path manually: + +```bash +curl -k https://netbird.example.com/oauth2/.well-known/openid-configuration +``` + +A valid response is JSON containing `"issuer"`. Anything else (empty body, 404, 502, connection refused) tells you where to dig further: 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. + +You can let the script keep waiting while you debug. As soon as the probe succeeds, the script will continue. If you'd rather start over, kill it with Ctrl+C, run `docker compose down -v`, fix the issue, and re-run. + +### Script fails on existing installation check + +**Problem**: The script exits immediately with a message about generated files already existing. + +**Solution**: This is intentional and protects you from overwriting a working setup. To start fresh: + +```bash +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 +``` + +Then re-run the script. Be aware this removes all NetBird data including users and peers. + ## Debugging TURN connections In the case that the peer-to-peer connection is not an option then the peer will use the TURN server for the secure connection establishment. If the connection is not possible even with TURN (Relay),