# 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" ```