mirror of
https://github.com/netbirdio/netbird.git
synced 2026-05-20 23:59:55 +00:00
Two follow-ups to the WebTransport/ALPN-mux landing:
Deployment templates publish UDP alongside TCP for the relay so the
single ALPN-multiplexed socket can serve raw QUIC and WebTransport
clients on the same port as the existing WebSocket transport.
- docker-compose.yml.tmpl: adds the matching `/udp` mapping; the relay
was already binding both stacks, the host port just wasn't published.
- docker-compose.yml.tmpl.traefik: WebTransport is the awkward case —
Traefik can't proxy WT sessions, so the relay container now publishes
UDP/443 directly and obtains its own Let's Encrypt cert (separate
volume), while the TCP /relay route stays behind Traefik unchanged so
WS-only clients keep working.
Management server learned to advertise per-relay transport hints:
- Config gains an optional `Endpoints []{URL, Transports}` block on the
Relay section, mirrored to clients as RelayConfig.endpoints.
- `Addresses` is still emitted as RelayConfig.urls so older agents keep
working unchanged.
- A single BuildRelayConfigProto helper is the only place that builds
the proto, called from both toNetbirdConfig and the token push paths.
The GeoDNS case is operator-asserted, not probed: a single URL fans out
to several physical relays, and the Transports list must already be the
intersection of what every backend supports. Documented on the config
struct — if any backend behind a hostname can't speak h3, the operator
drops "wt" from that hostname's list and no client tries it there.
150 lines
6.0 KiB
Plaintext
150 lines
6.0 KiB
Plaintext
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:$NETBIRD_DASHBOARD_TAG
|
|
environment:
|
|
# Endpoints
|
|
- NETBIRD_MGMT_API_ENDPOINT=$NETBIRD_MGMT_API_ENDPOINT
|
|
- NETBIRD_MGMT_GRPC_API_ENDPOINT=$NETBIRD_MGMT_API_ENDPOINT
|
|
# OIDC
|
|
- AUTH_AUDIENCE=$NETBIRD_DASH_AUTH_AUDIENCE
|
|
- AUTH_CLIENT_ID=$NETBIRD_AUTH_CLIENT_ID
|
|
- AUTH_CLIENT_SECRET=$NETBIRD_AUTH_CLIENT_SECRET
|
|
- AUTH_AUTHORITY=$NETBIRD_AUTH_AUTHORITY
|
|
- USE_AUTH0=$NETBIRD_USE_AUTH0
|
|
- AUTH_SUPPORTED_SCOPES=$NETBIRD_AUTH_SUPPORTED_SCOPES
|
|
- AUTH_REDIRECT_URI=$NETBIRD_AUTH_REDIRECT_URI
|
|
- AUTH_SILENT_REDIRECT_URI=$NETBIRD_AUTH_SILENT_REDIRECT_URI
|
|
- NETBIRD_TOKEN_SOURCE=$NETBIRD_TOKEN_SOURCE
|
|
# SSL
|
|
- NGINX_SSL_PORT=443
|
|
# Letsencrypt
|
|
- LETSENCRYPT_DOMAIN=$NETBIRD_LETSENCRYPT_DOMAIN
|
|
- LETSENCRYPT_EMAIL=$NETBIRD_LETSENCRYPT_EMAIL
|
|
volumes:
|
|
- $LETSENCRYPT_VOLUMENAME:/etc/letsencrypt/
|
|
labels:
|
|
- traefik.enable=true
|
|
- traefik.http.routers.netbird-dashboard.rule=Host(`$NETBIRD_DOMAIN`)
|
|
- traefik.http.services.netbird-dashboard.loadbalancer.server.port=80
|
|
|
|
# Signal
|
|
signal:
|
|
<<: *default
|
|
image: netbirdio/signal:$NETBIRD_SIGNAL_TAG
|
|
volumes:
|
|
- $SIGNAL_VOLUMENAME:/var/lib/netbird
|
|
labels:
|
|
- traefik.enable=true
|
|
- traefik.http.routers.netbird-wsproxy-signal.rule=Host(`$NETBIRD_DOMAIN`) && PathPrefix(`/ws-proxy/signal`)
|
|
- traefik.http.routers.netbird-wsproxy-signal.service=netbird-wsproxy-signal
|
|
- traefik.http.services.netbird-wsproxy-signal.loadbalancer.server.port=80
|
|
- traefik.http.routers.netbird-signal.rule=Host(`$NETBIRD_DOMAIN`) && PathPrefix(`/signalexchange.SignalExchange/`)
|
|
- traefik.http.routers.netbird-signal.service=netbird-signal
|
|
- traefik.http.services.netbird-signal.loadbalancer.server.port=10000
|
|
- traefik.http.services.netbird-signal.loadbalancer.server.scheme=h2c
|
|
|
|
# Relay
|
|
#
|
|
# Traefik fronts the TCP/WebSocket side of the relay on port 443 via the HTTP
|
|
# router below — this gives us WS over TLS that traverses any HTTP proxy.
|
|
#
|
|
# WebTransport (h3) and raw QUIC require direct UDP termination on the relay
|
|
# itself: Traefik does not proxy WebTransport sessions, and tunnelling the
|
|
# h3 stream end-to-end through a reverse proxy defeats the point. The relay
|
|
# therefore publishes UDP/443 on the host directly and terminates TLS for
|
|
# both ALPNs ("nb-quic" and "h3") on a single socket via ALPN multiplexing.
|
|
#
|
|
# The relay obtains its own Let's Encrypt certificate (NB_LETSENCRYPT_*
|
|
# below) since Traefik's certificate store is not shared with the container.
|
|
# The cert is bound to NETBIRD_RELAY_DOMAIN — point this at the same FQDN
|
|
# clients use to dial the relay.
|
|
#
|
|
# If a deployment can't open UDP/443 to the host (firewall, k8s without
|
|
# hostPort, etc.), leave it unmapped: native clients fall back to raw QUIC
|
|
# over WS and browser clients fall back to WS. Drop "quic"/"wt" from the
|
|
# management Relays config in that case so clients don't waste a handshake.
|
|
relay:
|
|
<<: *default
|
|
image: netbirdio/relay:$NETBIRD_RELAY_TAG
|
|
environment:
|
|
- NB_LOG_LEVEL=info
|
|
- NB_LISTEN_ADDRESS=:443
|
|
- NB_EXPOSED_ADDRESS=$NETBIRD_RELAY_ENDPOINT
|
|
- NB_LETSENCRYPT_DOMAINS=$NETBIRD_RELAY_DOMAIN
|
|
- NB_LETSENCRYPT_EMAIL=$NETBIRD_LETSENCRYPT_EMAIL
|
|
- NB_LETSENCRYPT_DATA_DIR=/var/lib/netbird-relay
|
|
# todo: change to a secure secret
|
|
- NB_AUTH_SECRET=$NETBIRD_RELAY_AUTH_SECRET
|
|
volumes:
|
|
- $RELAY_LE_VOLUMENAME:/var/lib/netbird-relay
|
|
ports:
|
|
# Direct UDP exposure for QUIC + WebTransport (bypasses Traefik).
|
|
- 443:443/udp
|
|
labels:
|
|
# The TCP WS path stays behind Traefik so the existing /relay route keeps
|
|
# working for clients that can't open UDP/443.
|
|
- traefik.enable=true
|
|
- traefik.http.routers.netbird-relay.rule=Host(`$NETBIRD_DOMAIN`) && PathPrefix(`/relay`)
|
|
- traefik.http.services.netbird-relay.loadbalancer.server.port=443
|
|
|
|
# Management
|
|
management:
|
|
<<: *default
|
|
image: netbirdio/management:$NETBIRD_MANAGEMENT_TAG
|
|
depends_on:
|
|
- dashboard
|
|
volumes:
|
|
- $MGMT_VOLUMENAME:/var/lib/netbird
|
|
- $LETSENCRYPT_VOLUMENAME:/etc/letsencrypt:ro
|
|
- ./management.json:/etc/netbird/management.json
|
|
command: [
|
|
"--port", "33073",
|
|
"--log-file", "console",
|
|
"--log-level", "info",
|
|
"--disable-anonymous-metrics=$NETBIRD_DISABLE_ANONYMOUS_METRICS",
|
|
"--single-account-mode-domain=$NETBIRD_MGMT_SINGLE_ACCOUNT_MODE_DOMAIN",
|
|
"--dns-domain=$NETBIRD_MGMT_DNS_DOMAIN"
|
|
]
|
|
labels:
|
|
- traefik.enable=true
|
|
- traefik.http.routers.netbird-api.rule=Host(`$NETBIRD_DOMAIN`) && PathPrefix(`/api`)
|
|
- traefik.http.routers.netbird-api.service=netbird-api
|
|
- traefik.http.services.netbird-api.loadbalancer.server.port=33073
|
|
- traefik.http.routers.netbird-wsproxy-mgmt.rule=Host(`$NETBIRD_DOMAIN`) && PathPrefix(`/ws-proxy/management`)
|
|
- traefik.http.routers.netbird-wsproxy-mgmt.service=netbird-wsproxy-mgmt
|
|
- traefik.http.services.netbird-wsproxy-mgmt.loadbalancer.server.port=33073
|
|
- traefik.http.routers.netbird-management.rule=Host(`$NETBIRD_DOMAIN`) && PathPrefix(`/management.ManagementService/`)
|
|
- traefik.http.routers.netbird-management.service=netbird-management
|
|
- traefik.http.services.netbird-management.loadbalancer.server.port=33073
|
|
- traefik.http.services.netbird-management.loadbalancer.server.scheme=h2c
|
|
environment:
|
|
- NETBIRD_STORE_ENGINE_POSTGRES_DSN=$NETBIRD_STORE_ENGINE_POSTGRES_DSN
|
|
- NETBIRD_STORE_ENGINE_MYSQL_DSN=$NETBIRD_STORE_ENGINE_MYSQL_DSN
|
|
|
|
# Coturn
|
|
coturn:
|
|
<<: *default
|
|
image: coturn/coturn:$COTURN_TAG
|
|
domainname: $TURN_DOMAIN
|
|
volumes:
|
|
- ./turnserver.conf:/etc/turnserver.conf:ro
|
|
network_mode: host
|
|
command:
|
|
- -c /etc/turnserver.conf
|
|
|
|
volumes:
|
|
$MGMT_VOLUMENAME:
|
|
$SIGNAL_VOLUMENAME:
|
|
$LETSENCRYPT_VOLUMENAME:
|
|
$RELAY_LE_VOLUMENAME:
|