Declarative UniFi network controller in Rust — TOML config, git-synced, SurrealDB state, OpenTelemetry observability.
| Crate | Purpose |
|---|---|
vereinigen-protocol |
AES-CBC/GCM crypto, packet parsing, inform headers |
vereinigen-config |
TOML config loading + validation |
vereinigen-generator |
USG/USW/UAP system_cfg + mgmt_cfg generators |
vereinigen (controller) |
axum HTTP server, 3-phase inform, auto-adopt, discovery, provision, OTel, IPC, sync, firmware |
vereinigen-db |
SurrealDB embedded device state |
vereinigen-ipc |
Unix socket transport for CLI |
vereinigen-sync |
gix-based git config sync with diff detection |
vereinigen-cli |
CLI management tool |
vereinigen-mock-device |
Test device simulator |
vereinigen-unf |
.unf backup decryptor + TOML converter |
# Development shell
nix develop
# Build
cargo build
# Run tests
cargo test
# Run controller
cargo run --bin vereinigen -- \
--config-dir /etc/vereinigen/config \
--db-dir /var/lib/vereinigen/db \
--listen 0.0.0.0:8080
# CLI
cargo run --bin vereinigen-cli -- --socket /run/vereinigen.sock listThe controller automatically discovers and adopts UniFi devices on the local subnet:
-
SSH subnet scan — Every 60 seconds, the controller does a parallel TCP connect sweep to port 22 on all 254 hosts in the /24 subnet (~500ms). For each responsive host, it tries SSH with
ubnt/ubntcredentials and runssyswrapper.sh set-informto point the device at the controller. -
UDP discovery — Broadcasts and unicasts discovery responses on UDP 10001 every 30 seconds, telling listening devices where the controller is.
-
Auto-adopt — When an unknown device sends its first inform, the controller auto-creates a device config (model, serial, firmware), generates a unique authkey, and sends an adoption setparam with mgmt_cfg containing the new key.
-
Provisioning — On subsequent informs, if the device's cfgversion doesn't match the expected hash, the controller sends a full system_cfg + mgmt_cfg setparam. The device applies the config and comes online.
No manual intervention needed — plug in a device and it gets adopted within 60 seconds.
config/
├── settings.toml # Country, timezone, NTP, SSH, LED
├── site.toml # Site name and description
├── wireless.toml # SSID definitions (name, security, passphrase)
├── networks.toml # Network subnets, VLANs, DHCP
├── firewall.toml # Firewall groups and rules
├── approved-macs.toml # Pre-approved device MAC addresses
└── devices/ # Auto-created device configs (one .toml per MAC)
└── d8-b3-70-cc-89-0a.toml
[[ssid]]
name = "MyNetwork"
security = "wpa2"
passphrase = "secretpassword"
hide_ssid = falsePre-approve devices so they're adopted immediately on first inform:
macs = [
"fc:ec:da:43:19:cd",
]Unknown devices (not in approved-macs or devices/) are also auto-adopted when they send an inform after being SSH-provisioned.
When a device is auto-adopted, a TOML file is created in devices/:
[device]
name = "UAP-AC-Mesh"
model = "U7MSH"
type = "uap"
mac = "d8:b3:70:cc:89:0a"
authkey = "<generated-hex-key>"
aes_gcm = true
[device.network]The controller implements the UniFi inform protocol with three phases:
| Phase | Condition | Response |
|---|---|---|
| Adoption | New device, first contact | setparam with mgmt_cfg (new authkey + controller URL) |
| Provisioning | Known device, cfgversion mismatch | setparam with full system_cfg + mgmt_cfg |
| Heartbeat | Known device, cfgversion match | Minimal noop response |
Encryption: AES-CBC or AES-GCM depending on device support. GCM is detected from the inform packet header flags and used for responses automatically.
The controller watches the config directory for changes. Edit any TOML file and it's picked up within 30 seconds — the cfgversion hash changes, triggering re-provisioning on the next inform cycle. No restart needed.
{
inputs.vereinigen.url = "github:YAAMBerlin/vereinigen";
outputs = { nixpkgs, vereinigen, ... }: {
nixosConfigurations.myhost = nixpkgs.lib.nixosSystem {
modules = [
vereinigen.nixosModules.vereinigen
{
services.vereinigen = {
enable = true;
configDir = "/etc/vereinigen/config";
configRepo = "https://github.com/org/network-config.git";
};
}
];
};
};
}cargo run --bin vereinigen-unf -- --input backup.unf --output ./configProprietary — YAAMBerlin