A self-hosted control plane for Nebula overlay networks
- Networks & nodes — Create networks, manage nodes, IP allocation, and certificates
- Web UI — React dashboard with OIDC (e.g. Keycloak) or dev token authentication
- Device client (ncclient) —
pip install nebula-commanderfor enroll and run; see client/README.md and ncclient documentation
- PayPal and Venmo
- More to come
Implemented
- Network creation
- Certificate generation
- config.yaml generation
- Basic firewall group rules
- Node management
- Audit logging
- Basic invitation system
- User management system
Planned (v0.2.0)
- Exit nodes
- Magic DNS implementation
- Client UI via web interface
- Stabilize client
Pre-built images are published to GitHub Container Registry. Full details: docker/README.md.
cd docker
cp .env.example .env
cp -r env.d.example env.d
# Edit env.d/backend: set JWT secret, ENCRYPTION_KEY, etc.
docker compose pull
docker compose up -dThe app is available at http://localhost (or your configured port). For OIDC with Keycloak:
docker compose -f docker-compose.yml -f docker-compose-keycloak.yml up -dImport the module and enable the service. See nix/module.nix for options and Server Installation: NixOS for more detail.
services.nebula-commander.enable = true;
# Optional: services.nebula-commander.jwtSecretFile = "/run/secrets/nebula-commander-jwt";
# Optional: services.nebula-commander.debug = false;For HTTPS and a custom domain, put a reverse proxy (nginx, Traefik, Caddy) in front. Example nginx:
server {
listen 443 ssl http2;
server_name nebula.example.com;
ssl_certificate /etc/ssl/certs/nebula.example.com.crt;
ssl_certificate_key /etc/ssl/private/nebula.example.com.key;
location / {
proxy_pass http://localhost:80;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}See docker/README.md § Reverse Proxy for more.
Backend
python -m venv .venv
source .venv/bin/activate # or .venv\Scripts\activate on Windows
pip install -r backend/requirements.txt
export NEBULA_COMMANDER_DATABASE_URL="sqlite+aiosqlite:///./backend/db.sqlite"
export NEBULA_COMMANDER_CERT_STORE_PATH="./backend/certs"
# Required: encryption key. Generate once:
# python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
export NEBULA_COMMANDER_ENCRYPTION_KEY="your-fernet-key-here"
export DEBUG=true
python -m uvicorn backend.main:app --reload --port 8081Frontend
cd frontend && npm install && npm run devOpen http://localhost:5173 (dev token when backend is in debug mode). See Development: Setup for more.
- Secrets — Use
NEBULA_COMMANDER_JWT_SECRET_FILEandNEBULA_COMMANDER_ENCRYPTION_KEY_FILE(or env from a secrets manager) instead of inline env. - HTTPS — Serve via a reverse proxy with TLS; set
NEBULA_COMMANDER_PUBLIC_URLto your public URL. - OIDC — Use Keycloak (or another OIDC provider) instead of dev tokens; configure
OIDC_ISSUER_URL,OIDC_CLIENT_ID, and client secret. - CORS — Set
NEBULA_COMMANDER_CORS_ORIGINSto your front-end origin(s). - Backups — Back up the data volume (SQLite and cert store) regularly. See docker/README.md § Data Persistence.
- Upgrades — For encryption-at-rest migration from older deployments, see notes/SECURITY_UPGRADES.md.
Env prefix: NEBULA_COMMANDER_. Key options: DATABASE_URL, CERT_STORE_PATH, ENCRYPTION_KEY or ENCRYPTION_KEY_FILE (required), JWT_SECRET_KEY or JWT_SECRET_FILE, OIDC_ISSUER_URL, OIDC_CLIENT_ID, DEBUG. Full list and examples: docker/env.d.example/backend and Server Configuration.
Base path /api. OpenAPI at /api/docs when the backend is running.
Contributions welcome; prefer small, focused PRs.
See LICENSE.md. Backend and frontend: MIT. Client (ncclient): GPLv3 or later.