293 lines
7.4 KiB
Markdown
293 lines
7.4 KiB
Markdown
# NetBird Deployment
|
|
|
|
Self-hosted NetBird VPN with embedded IdP (no external SSO required).
|
|
|
|
## Quick Start
|
|
|
|
```bash
|
|
cd ansible/deployments/netbird
|
|
|
|
# 1. Generate secrets
|
|
./generate-vault.sh
|
|
ansible-vault encrypt group_vars/vault.yml
|
|
|
|
# 2. Deploy
|
|
ansible-playbook playbook-ssl.yml -i inventory.yml --ask-vault-pass
|
|
|
|
# 3. Create admin (manual - see below)
|
|
|
|
# 4. Create PAT (manual - see below)
|
|
|
|
# 5. Provision groups and users
|
|
ansible-playbook setup-groups.yml -i inventory.yml --ask-vault-pass
|
|
ansible-playbook setup-users.yml -i inventory.yml --ask-vault-pass
|
|
```
|
|
|
|
## Prerequisites
|
|
|
|
- Ubuntu 22.04+ VPS with public IP
|
|
- Ports 80, 443, 3478 (TCP/UDP) open
|
|
- Ansible 2.14+
|
|
|
|
## Deployment Modes
|
|
|
|
| Playbook | Use Case |
|
|
| --------------------- | ------------------------------------------------------------------------ |
|
|
| `playbook-ssl-ip.yml` | HTTPS with self-signed cert on IP (recommended for isolated deployments) |
|
|
| `playbook-ssl.yml` | HTTPS with Let's Encrypt (requires domain) |
|
|
| `playbook-no-ssl.yml` | HTTP only (not recommended) |
|
|
|
|
## Full Workflow
|
|
|
|
### Step 1: Configure Inventory
|
|
|
|
Edit `inventory.yml`:
|
|
|
|
```yaml
|
|
all:
|
|
children:
|
|
netbird_servers:
|
|
hosts:
|
|
netbird-vps:
|
|
ansible_host: YOUR_SERVER_IP
|
|
ansible_user: root
|
|
ansible_python_interpreter: /usr/bin/python3
|
|
```
|
|
|
|
### Step 2: Generate Secrets
|
|
|
|
```bash
|
|
./generate-vault.sh
|
|
ansible-vault encrypt group_vars/vault.yml
|
|
```
|
|
|
|
This creates:
|
|
|
|
- `vault_turn_password` - TURN server authentication
|
|
- `vault_relay_secret` - Relay server secret
|
|
- `vault_encryption_key` - Embedded IdP encryption (BACK THIS UP!)
|
|
- `vault_admin_password` - Initial admin password
|
|
- `vault_netbird_service_pat` - Leave empty for now
|
|
|
|
### Step 3: Deploy NetBird
|
|
|
|
```bash
|
|
ansible-playbook playbook-ssl-ip.yml -i inventory.yml --ask-vault-pass
|
|
```
|
|
|
|
Wait for deployment to complete. Dashboard will be available at `https://YOUR_IP`.
|
|
|
|
### Step 4: Create Admin User (Manual)
|
|
|
|
1. Open `https://YOUR_IP` in browser (accept certificate warning)
|
|
2. Create admin account:
|
|
- **Email**: `admin@achilles.local` (from `group_vars/netbird_servers.yml`)
|
|
- **Password**: Use `vault_admin_password` from vault
|
|
|
|
```bash
|
|
# View password
|
|
ansible-vault view group_vars/vault.yml | grep vault_admin_password
|
|
```
|
|
|
|
### Step 5: Create Service User & PAT (Manual)
|
|
|
|
After logging in as admin:
|
|
|
|
1. Go to **Team** → **Service Users**
|
|
2. Click **Create Service User**
|
|
- Name: `Automation Service`
|
|
- Role: `Admin`
|
|
3. Click on the created service user
|
|
4. Click **Create Token**
|
|
- Name: `ansible-automation`
|
|
- Expiration: 365 days
|
|
5. **Copy the token** (shown only once!)
|
|
|
|
### Step 6: Store PAT in Vault
|
|
|
|
```bash
|
|
ansible-vault edit group_vars/vault.yml
|
|
```
|
|
|
|
Set:
|
|
|
|
```yaml
|
|
vault_netbird_service_pat: "nbp_xxxxxxxxxxxxxxxxxxxx"
|
|
```
|
|
|
|
### Step 7: Create Groups
|
|
|
|
```bash
|
|
ansible-playbook setup-groups.yml -i inventory.yml --ask-vault-pass
|
|
```
|
|
|
|
This creates:
|
|
|
|
- Battalion groups: `battalion-1-pilots`, `battalion-1-ground-stations`, etc.
|
|
- Dev team group: `dev-team`
|
|
- Setup keys for each group
|
|
- Access policies (battalion isolation + dev access)
|
|
|
|
### Step 8: Provision Users
|
|
|
|
Edit `group_vars/netbird_servers.yml` to define users:
|
|
|
|
```yaml
|
|
netbird_users:
|
|
# Dev team (full access)
|
|
- email: "vlad.stus@achilles.local"
|
|
name: "Vlad Stus"
|
|
role: "admin"
|
|
auto_groups:
|
|
- "dev-team"
|
|
|
|
# Battalion users
|
|
- email: "pilot1.bat1@achilles.local"
|
|
name: "Pilot One B1"
|
|
role: "user"
|
|
battalion: "battalion-1"
|
|
type: "pilot"
|
|
|
|
- email: "gs-operator1.bat1@achilles.local"
|
|
name: "GS Operator One B1"
|
|
role: "user"
|
|
battalion: "battalion-1"
|
|
type: "ground-station"
|
|
```
|
|
|
|
Then run:
|
|
|
|
```bash
|
|
ansible-playbook setup-users.yml -i inventory.yml --ask-vault-pass
|
|
```
|
|
|
|
**Dry run** (preview without creating):
|
|
|
|
```bash
|
|
ansible-playbook setup-users.yml -i inventory.yml --ask-vault-pass -e "dry_run=true"
|
|
```
|
|
|
|
Credentials are saved to `files/credentials/users-YYYY-MM-DD.yml`.
|
|
|
|
## User Roles
|
|
|
|
| Role | Permissions |
|
|
| ------- | ------------------------------------------ |
|
|
| `owner` | Full control, can delete account |
|
|
| `admin` | Manage users, groups, policies, setup keys |
|
|
| `user` | Connect peers, view own peers |
|
|
|
|
## User Types (for battalion assignment)
|
|
|
|
| Type | Auto-Group |
|
|
| ---------------- | ----------------------------- |
|
|
| `pilot` | `{battalion}-pilots` |
|
|
| `ground-station` | `{battalion}-ground-stations` |
|
|
|
|
## Backup & Restore
|
|
|
|
**Create backup** (downloads to `~/achilles-backups/netbird/`):
|
|
|
|
```bash
|
|
ansible-playbook backup.yml -i inventory.yml
|
|
```
|
|
|
|
**Restore latest backup**:
|
|
|
|
```bash
|
|
ansible-playbook restore.yml -i inventory.yml
|
|
```
|
|
|
|
**Restore specific backup**:
|
|
|
|
```bash
|
|
ansible-playbook restore.yml -i inventory.yml -e "backup_file=netbird-backup-20250116T120000.tar.gz"
|
|
```
|
|
|
|
Backups include:
|
|
|
|
- Management SQLite database (peers, routes, policies, users)
|
|
- Configuration files (docker-compose.yml, Caddyfile, etc.)
|
|
|
|
## Cleanup
|
|
|
|
**Soft cleanup** (stop containers, keep data):
|
|
|
|
```bash
|
|
ansible-playbook cleanup-soft.yml -i inventory.yml
|
|
```
|
|
|
|
**Full cleanup** (remove everything including data):
|
|
|
|
```bash
|
|
ansible-playbook cleanup-full.yml -i inventory.yml
|
|
```
|
|
|
|
## Connecting Peers
|
|
|
|
After provisioning, users connect with:
|
|
|
|
```bash
|
|
# Using setup key (for automated deployments)
|
|
netbird up --management-url https://YOUR_IP --setup-key SETUP_KEY
|
|
|
|
# Using user credentials (interactive)
|
|
netbird up --management-url https://YOUR_IP
|
|
# Then login with email/password in browser
|
|
```
|
|
|
|
## File Structure
|
|
|
|
```
|
|
ansible/deployments/netbird/
|
|
├── backup.yml # Backup management DB and config
|
|
├── cleanup-full.yml # Remove everything
|
|
├── cleanup-soft.yml # Stop containers only
|
|
├── generate-vault.sh # Generate random secrets
|
|
├── group_vars/
|
|
│ ├── netbird_servers.yml # Main configuration
|
|
│ ├── vault.yml # Encrypted secrets
|
|
│ └── vault.yml.example # Template for vault
|
|
├── inventory.yml # Server inventory
|
|
├── playbook-no-ssl.yml # HTTP deployment
|
|
├── playbook-ssl-ip.yml # HTTPS with self-signed (IP)
|
|
├── playbook-ssl.yml # HTTPS with Let's Encrypt
|
|
├── restore.yml # Restore from backup
|
|
├── setup-bootstrap.yml # Bootstrap admin (if API available)
|
|
├── setup-groups.yml # Create groups, keys, policies
|
|
├── setup-users.yml # Provision users
|
|
├── templates/ # Jinja2 templates
|
|
└── files/
|
|
└── credentials/ # Generated user passwords (gitignored)
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
### Certificate Warning
|
|
|
|
Expected for SSL-IP mode. Accept the self-signed certificate in your browser.
|
|
|
|
### "Unauthenticated" after login
|
|
|
|
JWKS race condition bug in NetBird. Wait 30 seconds and try again, or restart the management container:
|
|
|
|
```bash
|
|
ssh root@YOUR_IP "cd /opt/netbird && docker compose restart management"
|
|
```
|
|
|
|
### API returns 404 on /api/instance/setup
|
|
|
|
The bootstrap API isn't exposed in all NetBird versions. Create admin manually in the dashboard.
|
|
|
|
### View logs
|
|
|
|
```bash
|
|
ssh root@YOUR_IP "cd /opt/netbird && docker compose logs -f"
|
|
```
|
|
|
|
### Check container status
|
|
|
|
```bash
|
|
ssh root@YOUR_IP "cd /opt/netbird && docker compose ps"
|
|
```
|