OPNsense Hub is an MVP for enrolling OPNsense firewalls into a central dashboard with a short-lived OTP, establishing a WireGuard tunnel, and opening the firewall UI through a read-only reverse proxy path.
Important: the Hub dashboard/control plane does not modify firewall configuration, restore backups, reboot firewalls, or store OPNsense admin passwords. The only firewall-side configuration change is performed by the OPNsense plugin on that firewall to create its own WireGuard client tunnel.
OPNsense Hub is an independent project. It is not affiliated with, endorsed by, or sponsored by Deciso B.V. or the OPNsense project unless explicitly stated by those parties.
See docs/architecture.md.
This project is licensed under the BSD 2-Clause License. See LICENSE.
Third-party dependency, container image, font, icon, and trademark notices are tracked in:
THIRD_PARTY_NOTICES.mddocs/licensing.mddocs/release-compliance-checklist.md
dashboard/
app/ FastAPI dashboard/API
migrations/ SQL schema
tests/ Unit tests
Dockerfile
requirements.txt
net-mgmt/os-opnsensehub/ OPNsense plugin scaffold
docs/ Architecture, security, licensing, compliance, test plan
deploy/ Reverse proxy examples
docker-compose.yml
.env.example
- Dashboard login with seeded initial admin.
- Company/group creation.
- Company-scoped RBAC model in the database.
- Short-lived single-use OTP enrollment codes stored hashed.
- Device enrollment endpoint using WireGuard public key.
- Device tokens stored hashed; heartbeat uses bearer token auth.
- Automatic Hub WireGuard server bootstrap and peer restore on container startup.
/32-only WireGuard routes for firewall web UI access; customer LAN subnets are never routed.- WireGuard peer add/remove wrapper with public-key/IP validation.
- Firewall revoke flow invalidates device token and removes WireGuard peer.
- Audit logs for login, company creation, enrollment, revoke, and proxy access.
- Server-rendered dashboard with an Ephemeral-Link-inspired style.
- Side-menu settings area for adding companies, managing users, branding, email settings, Microsoft 365, and Local AD configuration.
- OPNsense plugin scaffold with MVC, configd actions, and backend scripts.
cp .env.example .env
docker compose up --buildOpen:
http://localhost:8083
Default login comes from .env:
INITIAL_ADMIN_EMAIL=admin@example.com
INITIAL_ADMIN_PASSWORD=change-me
By default, the app container automatically configures the Hub WireGuard server interface on startup. It generates and persists the Hub server private key under the opnsense_hub_wg Docker volume, renders /etc/wireguard/wg0.conf, brings up wg0, exposes UDP 51820, and restores enrolled peers from the database.
cd /home/alberto/Projects/OPNsense-Hub
cp .env.example .env
docker compose config
docker compose up --buildOPNsense Hub is a management overlay for opening each firewall's own web UI. It is not a site-to-site VPN router and does not route customer LANs.
The opnsense-hub-api container configures WireGuard automatically when WG_DRY_RUN=false:
- Generates
/etc/wireguard/server.keyif it does not exist. - Derives the Hub server public key from that private key.
- Renders
/etc/wireguard/wg0.confusingHUB_WG_ADDRESSandHUB_WG_LISTEN_PORT. - Runs
wg-quick up /etc/wireguard/wg0.confwhenwg0is not already running. - Restores all non-revoked device peers from the database on startup.
- Adds each newly enrolled firewall as a
/32peer.
AllowedIPs are intentionally narrow:
- Hub side peer route:
firewall_tunnel_ip/32 - Firewall side peer route:
hub_tunnel_ip/32
Do not add customer LAN networks such as 192.168.1.0/24 to WireGuard AllowedIPs. Many companies can use the same LAN subnet without conflict because the Hub only connects to each firewall's unique tunnel IP.
The server private key is persisted in the opnsense_hub_wg Docker volume. Back up this volume securely; losing it requires re-enrolling devices or carefully rotating WireGuard keys.
Set HUB_WG_ENDPOINT to the public UDP endpoint that OPNsense firewalls can reach, for example hub.example.com:51820, and ensure UDP 51820 is allowed through the host firewall/security group.
For UI-only development without WireGuard privileges, set WG_DRY_RUN=true.
These commands assume an OPNsense ports/plugins build environment. Verify against current OPNsense plugin conventions for your target OPNsense release.
cd /usr/plugins/net-mgmt/os-opnsensehub
make package
pkg install /usr/obj/usr/plugins/net-mgmt/os-opnsensehub/*.pkg
service configd restartFor quick development copy testing on a lab firewall:
scp -r net-mgmt/os-opnsensehub/src/opnsense/* root@firewall:/usr/local/opnsense/
ssh root@firewall 'chmod +x /usr/local/opnsense/scripts/OPNsense/OPNsenseHub/*.py && service configd restart'Then open:
Services > OPNsense Hub
- Log in to Hub.
- Create a company.
- Open the company and click
Generate enrollment OTP. - In OPNsense, go to
Services > OPNsense Hub. - Enter the HTTPS Hub URL and OTP.
- Click
Connect. - The firewall should appear in the company firewalls table.
Auth:
POST /api/v1/auth/loginPOST /api/v1/auth/logoutGET /api/v1/auth/me
Companies:
GET /api/v1/companiesPOST /api/v1/companiesGET /api/v1/companies/{company_id}
Enrollment:
POST /api/v1/companies/{company_id}/enrollment-codesPOST /api/v1/enroll
Devices:
GET /api/v1/companies/{company_id}/devicesGET /api/v1/devices/{device_id}POST /api/v1/devices/{device_id}/heartbeatPOST /api/v1/devices/{device_id}/revoke
Proxy:
GET/POST/PUT/PATCH/DELETE /proxy/devices/{device_id}/{path:path}
cd dashboard
python -m pytest
python -m compileall app
cd ..
docker compose config
docker compose build- The FastAPI proxy is intentionally simple. For production, consider Caddy/Nginx with a signed internal auth check or a hardened streaming proxy.
- OPNsense plugin service integration may require adjustment for the exact installed WireGuard plugin/version.
- MFA fields exist, but MFA is not implemented yet.
- Email and Microsoft Graph client secrets entered in the settings UI are not shown back in forms and are never logged, but they are currently stored in the database without application-level encryption. Use restrictive database access and backups until encrypted-at-rest integration secrets are implemented.