Skip to content

Commit 243c1af

Browse files
authored
Combined setup migration docs (#619)
1 parent 31a9949 commit 243c1af

File tree

3 files changed

+265
-2
lines changed

3 files changed

+265
-2
lines changed

src/components/NavigationDocs.jsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,9 @@ export const docsNavigation = [
615615
title: 'Coturn to Embedded STUN',
616616
href: '/selfhosted/migration/coturn-to-stun-migration',
617617
},
618+
{ title: 'Combined Container Setup',
619+
href: '/selfhosted/migration/combined-container'
620+
},
618621
{
619622
title: 'Enable Reverse Proxy',
620623
href: '/selfhosted/migration/enable-reverse-proxy',
@@ -869,4 +872,4 @@ function NavigationGroup({ group, className, hasChildren }) {
869872
</div>
870873
</li>
871874
)
872-
}
875+
}
Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
import {Note, Warning, Success} from "@/components/mdx"
2+
3+
export const description = 'Migrate your self-hosted NetBird deployment from the old 5-container setup to the new combined container architecture using the migrate.sh script.'
4+
5+
# Migration Guide: Combined Container Setup
6+
7+
This guide walks you through migrating a pre-v0.65.0 NetBird self-hosted deployment from the old 5-container architecture (dashboard, signal, relay, management, coturn) to the new 2-container combined setup (Traefik + `netbird-server`). The migration is handled by the `migrate.sh` script, which automates detection, backup, configuration generation, and (for Caddy-based setups) the full cutover.
8+
9+
<Note>
10+
**Who is this guide for?** This migration guide is for users who:
11+
- Have an existing self-hosted deployment running the **old 5-container setup** (separate dashboard, signal, relay, management, and coturn containers)
12+
- Are using the **embedded IdP (Dex)** for authentication
13+
- Want to move to the combined `netbird-server` container for a simpler, more maintainable deployment
14+
</Note>
15+
16+
<Warning>
17+
The migration script **exits with an error** if it detects an external identity provider (Auth0, Keycloak, Okta, Zitadel, Google Workspace, Microsoft Entra ID, etc.). If you are using an external IdP, do not run this script. Instead, follow the [self-hosting quickstart](/selfhosted/selfhosted-quickstart) for a fresh installation.
18+
</Warning>
19+
20+
## Overview of changes
21+
22+
### What's new
23+
24+
- **Combined `netbird-server` container** - management, signal, relay, and the embedded STUN server all run in a single container, replacing four separate services
25+
- **Traefik reverse proxy** (for Caddy-based setups) - replaces the embedded Caddy with Traefik v3.6, handling TLS termination via Let's Encrypt and routing for gRPC, WebSocket, and HTTP traffic
26+
- **Unified `config.yaml`** - a single configuration file replaces the combination of `management.json`, `setup.env`, and multiple environment files
27+
- **Simplified Docker Compose** - the stack goes from 5+ services down to 2 (Traefik + `netbird-server`) or 3 (with dashboard)
28+
29+
### What's removed
30+
31+
- **Separate signal, relay, management, and coturn containers** - consolidated into `netbird-server`
32+
- **Embedded Caddy** - replaced by Traefik (for setups that previously used Caddy)
33+
- **turnserver.conf** - STUN is now built into the combined server
34+
- **management.json** - replaced by `config.yaml` (the management container reads the new format)
35+
36+
## Prerequisites
37+
38+
Before running the migration, ensure you have:
39+
40+
- **Docker** with **Docker Compose** (v2 plugin or standalone `docker-compose`)
41+
- **jq**, **openssl**, and **curl** installed on the host
42+
- **Embedded IdP (Dex)** - the script only supports embedded IdP setups. External IdP deployments are not supported.
43+
- **Root or sudo access** to the machine running your NetBird deployment
44+
- A brief **maintenance window** - peers will need to reconnect after migration
45+
46+
## How the script works
47+
48+
The script runs through four phases automatically:
49+
50+
**Phase 0 - Detection:** The script locates your installation directory (checking `$PWD`, `/opt/netbird`, and `/opt/wiretrustee`), validates the old setup by looking for `management.json` and `docker-compose.yml`, and detects your reverse proxy type (embedded Caddy, Traefik, or external), IdP type, Docker volumes, domain, store engine (SQLite/PostgreSQL/MySQL), encryption key, and relay secret. If `config.yaml` already exists, the script exits - it assumes you have already migrated.
51+
52+
**Phase 1 - Backup:** A timestamped backup directory (e.g., `backup-20260217-143000`) is created containing copies of `docker-compose.yml`, `management.json`, `setup.env`, `base.setup.env`, `turnserver.conf`, `dashboard.env`, and the `artifacts/` directory if it exists. The script also records Docker volume and container state, and generates a `rollback.sh` script for reverting.
53+
54+
**Phase 2 - Configuration generation:** The script generates three files:
55+
- `config.yaml` - the combined server configuration (server settings, auth, store config, reverse proxy settings)
56+
- `dashboard.env` - dashboard environment variables for the embedded IdP
57+
- `docker-compose.yml` - the new Docker Compose file (format depends on your proxy type, see below)
58+
59+
**Phase 3 - Apply:** For Caddy-based setups, the script stops the old containers, starts the new ones, waits for health checks (OIDC endpoint and healthcheck endpoint), and runs verification. For external proxy setups, the script only generates configuration files - you handle the cutover manually.
60+
61+
### Migration modes
62+
63+
The script operates in one of two modes depending on your detected reverse proxy:
64+
65+
**Automatic (embedded Caddy setups).** If your old deployment uses the embedded Caddy proxy (the default from `configure.sh` or `getting-started.sh`), the script performs the full migration end-to-end. It stops old containers, generates a Traefik-based `docker-compose.yml`, and starts the new stack. The generated compose file creates a Docker network (`172.30.0.0/24`) with Traefik at `172.30.0.10`, and reuses your existing management volume if detected.
66+
67+
**Manual (external proxy setups).** If your deployment uses a custom or external reverse proxy (Nginx, HAProxy, etc.), the script generates the configuration files but does **not** stop or start any containers. You must handle the cutover yourself, including updating your proxy routing rules.
68+
69+
## Migration steps
70+
71+
### Step 1: Download the script
72+
73+
```bash
74+
curl -fsSL https://github.com/netbirdio/netbird/raw/main/infrastructure_files/migrate.sh -o migrate.sh
75+
chmod +x migrate.sh
76+
```
77+
78+
### Step 2: Run the migration
79+
80+
If your NetBird installation is in the current directory:
81+
82+
```bash
83+
./migrate.sh
84+
```
85+
86+
If your installation is in a different directory:
87+
88+
```bash
89+
./migrate.sh --install-dir /opt/netbird
90+
```
91+
92+
The script will display a summary of what it detected and ask for confirmation before making changes.
93+
94+
For automation or CI pipelines, use the `--non-interactive` flag to skip confirmation prompts:
95+
96+
```bash
97+
./migrate.sh --install-dir /opt/netbird --non-interactive
98+
```
99+
100+
### Step 3: Verify the migration (Caddy setups)
101+
102+
For Caddy-based setups, the script automatically verifies the migration by checking:
103+
1. That the expected containers are running
104+
2. That the OIDC endpoint (`https://your-domain/oauth2/.well-known/openid-configuration`) returns HTTP 200
105+
3. That the management API (`https://your-domain/api/accounts`) is responding
106+
107+
After the script completes, confirm everything is working:
108+
109+
```bash
110+
# Check running containers
111+
cd /opt/netbird # or your install directory
112+
docker compose ps
113+
114+
# Check logs
115+
docker compose logs -f netbird-server
116+
117+
# Open the dashboard
118+
# https://your-domain
119+
```
120+
121+
<Success>
122+
If all three verification checks pass and you can access the dashboard, the migration is complete. Your peers, networks, routes, and access policies are preserved in the database. Clients should reconnect automatically - if they do not, run `netbird down && netbird up` on the client.
123+
</Success>
124+
125+
### Step 3: Complete the cutover (external proxy setups)
126+
127+
For external proxy setups, the script generates the configuration files but leaves the actual cutover to you. After the script finishes, follow these steps:
128+
129+
**1. Stop the old containers:**
130+
131+
```bash
132+
cd /opt/netbird # or your install directory
133+
docker compose down
134+
```
135+
136+
**2. Start the new containers:**
137+
138+
```bash
139+
docker compose up -d
140+
```
141+
142+
**3. Update your reverse proxy routing.** The new setup exposes the dashboard at `127.0.0.1:8080` and the combined server at `127.0.0.1:8081`. Configure your reverse proxy to route traffic as follows:
143+
144+
| Path pattern | Backend | Protocol |
145+
|---|---|---|
146+
| `/signalexchange.SignalExchange/*` | `127.0.0.1:8081` | gRPC (h2c) |
147+
| `/management.ManagementService/*` | `127.0.0.1:8081` | gRPC (h2c) |
148+
| `/relay*`, `/ws-proxy/*` | `127.0.0.1:8081` | WebSocket |
149+
| `/api/*`, `/oauth2/*` | `127.0.0.1:8081` | HTTP |
150+
| `/*` (catch-all) | `127.0.0.1:8080` | HTTP (dashboard) |
151+
152+
<Note>
153+
The gRPC routes require HTTP/2 cleartext (h2c) support in your reverse proxy. Ensure your proxy is configured to forward these paths using h2c, not standard HTTP/1.1.
154+
</Note>
155+
156+
**4. Verify the services are healthy:**
157+
158+
```bash
159+
# Check containers
160+
docker compose ps
161+
162+
# Check OIDC endpoint
163+
curl -sk https://your-domain/oauth2/.well-known/openid-configuration
164+
165+
# Check management API (expect HTTP 401 - means it's running)
166+
curl -sk -o /dev/null -w '%{http_code}' https://your-domain/api/accounts
167+
```
168+
169+
## CLI reference
170+
171+
| Flag | Description |
172+
|---|---|
173+
| `--install-dir DIR` | Path to the existing NetBird installation directory. If not specified, the script checks `$PWD`, `/opt/netbird`, and `/opt/wiretrustee`, or prompts interactively. |
174+
| `--non-interactive` | Skip all confirmation prompts. Useful for automation and CI pipelines. |
175+
| `-h`, `--help` | Display usage information and exit. |
176+
177+
## Troubleshooting
178+
179+
### Script exits with "External IdP detected"
180+
181+
The migration script only supports deployments using the embedded IdP (Dex). If your setup uses an external identity provider, you need to perform a fresh installation instead. See the [self-hosting quickstart](/selfhosted/selfhosted-quickstart).
182+
183+
### Script exits with "config.yaml already exists"
184+
185+
This means the installation directory already contains a `config.yaml` file, which indicates a previous migration or a newer installation. If you want to re-run the migration, remove or rename the existing `config.yaml` first:
186+
187+
```bash
188+
mv config.yaml config.yaml.bak
189+
```
190+
191+
### Script cannot detect the installation directory
192+
193+
If the script cannot find `management.json` in any of the default locations (`$PWD`, `/opt/netbird`, `/opt/wiretrustee`), use the `--install-dir` flag to specify the path explicitly:
194+
195+
```bash
196+
./migrate.sh --install-dir /path/to/your/netbird
197+
```
198+
199+
### Health check times out after migration
200+
201+
If the health check times out but containers are running, the services may still be starting. Check the logs for errors:
202+
203+
```bash
204+
docker compose logs netbird-server
205+
docker compose logs traefik
206+
```
207+
208+
Common causes include:
209+
- DNS for your domain not pointing to the server
210+
- Ports 80 and 443 not open or blocked by a firewall
211+
- Let's Encrypt rate limits (if you have requested many certificates recently)
212+
213+
### Clients cannot connect after migration
214+
215+
Peers should reconnect automatically after the migration. If they do not:
216+
217+
```bash
218+
# On each client
219+
netbird down && netbird up
220+
```
221+
222+
If connections still fail, verify that port `3478/udp` (STUN) is open and that your domain resolves correctly.
223+
224+
## Rollback procedure
225+
226+
The script creates a complete backup before making any changes. To revert to your previous setup:
227+
228+
```bash
229+
# Run the generated rollback script
230+
bash /opt/netbird/backup-YYYYMMDD-HHMMSS/rollback.sh
231+
```
232+
233+
The rollback script stops the new containers, restores all backed-up configuration files (`docker-compose.yml`, `management.json`, `setup.env`, `dashboard.env`, etc.), removes the generated `config.yaml`, and restarts the old containers.
234+
235+
You can also rollback manually:
236+
237+
```bash
238+
# Stop new containers
239+
docker compose down
240+
241+
# Restore backed-up files
242+
cp backup-YYYYMMDD-HHMMSS/docker-compose.yml .
243+
cp backup-YYYYMMDD-HHMMSS/management.json .
244+
cp backup-YYYYMMDD-HHMMSS/setup.env . 2>/dev/null
245+
cp backup-YYYYMMDD-HHMMSS/dashboard.env . 2>/dev/null
246+
247+
# Remove new config
248+
rm -f config.yaml
249+
250+
# Start old containers
251+
docker compose up -d
252+
```
253+
254+
## Additional resources
255+
256+
- [Self-Hosting Quickstart](/selfhosted/selfhosted-quickstart) - fresh installation guide for new deployments
257+
- [Enable Reverse Proxy](/selfhosted/migration/enable-reverse-proxy) - after migrating to the combined container setup with Traefik, follow this guide to add the NetBird Reverse Proxy service
258+
- [Authentication and IdPs](/selfhosted/identity-providers) - configuring identity providers for self-hosted deployments
259+
- [Configuration Files](/selfhosted/configuration-files) - reference for all configuration files in a self-hosted deployment
260+
- [migrate.sh source](https://github.com/netbirdio/netbird/blob/main/infrastructure_files/migrate.sh) - the migration script on GitHub

src/pages/selfhosted/migration/enable-reverse-proxy.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -487,4 +487,4 @@ docker exec -it netbird-management /go/bin/netbird-mgmt token revoke <token-id>
487487
- [Reverse Proxy feature documentation](/manage/reverse-proxy) - full overview of services, targets, domains, and authentication
488488
- [Custom Domains](/manage/reverse-proxy/custom-domains) - use your own domain names for reverse proxy services
489489
- [Reverse Proxy configuration reference](/selfhosted/configuration-files#reverse-proxy-configuration) - all proxy environment variables and options
490-
- [Self-Hosting Quickstart](/selfhosted/selfhosted-quickstart) - getting started with self-hosted NetBird
490+
- [Self-Hosting Quickstart](/selfhosted/selfhosted-quickstart) - getting started with self-hosted NetBird

0 commit comments

Comments
 (0)