UniFi Gateway Emulator 
A Python 3 daemon that emulates a Ubiquiti UniFi Gateway (UGW3) to a UniFi Controller. This allows non-Ubiquiti routers (OpenWRT, OPNSense, pfSense, or any Linux/FreeBSD router) to appear in the UniFi Controller UI and report network statistics.
How It Works
The daemon runs alongside your non-Ubiquiti router and periodically sends "inform" packets to your UniFi Controller — the same binary protocol that real UniFi devices use. The controller sees a UGW3 gateway and displays its stats (interfaces, traffic, connected clients, routes, etc.) in the dashboard.
Your UniFi APs, switches, and other devices continue connecting to the controller normally. This project fills the "gateway" slot so the controller has a complete view of your network topology.
┌──────────────────┐ inform (HTTP POST) ┌───────────────────┐
│ This Daemon │ ─────────────────────────► │ UniFi Controller │
│ (emulates UGW3) │ │ │
└────────┬─────────┘ │ Sees complete │
│ reads stats from │ network topology │
┌────────▼─────────┐ │ │
│ Your Router │ UniFi APs/Switches ──► │ │
│ (OPNSense/etc) │ also inform normally └───────────────────┘
└──────────────────┘
Requirements
- A running UniFi Controller (self-hosted or Cloud Key)
- Network access from the daemon to the controller's
/informendpoint
Installation
Debian / Ubuntu (apt)
curl -fsSL https://amd989.github.io/unifi-gateway/setup-apt.sh | sudo bash
sudo apt install unifi-gateway
RHEL / Rocky / Fedora (dnf)
curl -fsSL https://amd989.github.io/unifi-gateway/setup-rpm.sh | sudo bash
sudo dnf install unifi-gateway
OpenWRT
The OpenWRT packages ship pure Python source and depend on python3, python3-psutil, and python3-pycryptodome from the OpenWRT feeds — keeping the package tiny for flash-constrained devices.
# Auto-detects apk (25.12+) or opkg (older)
curl -fsSL https://amd989.github.io/unifi-gateway/setup-openwrt.sh | sh
Then install with whichever package manager your version uses:
# OpenWRT 25.12+ (apk)
apk add unifi-gateway
# OpenWRT pre-25.12 (opkg)
opkg install unifi-gateway
FreeBSD / OPNSense / pfSense (pkg)
curl -fsSL https://amd989.github.io/unifi-gateway/setup-pkg.sh | sudo sh
sudo pkg install unifi-gateway
Docker
docker pull ghcr.io/amd989/unifi-gateway:latest
docker compose up -d
See the Docker section below for details.
Standalone Binaries
Pre-built binaries are also available from Releases if you prefer manual installation.
| Platform | Binary |
|---|---|
| Linux x86_64 | unifi-gateway-linux-amd64 |
| Linux ARM64 | unifi-gateway-linux-arm64 |
| Linux ARMv7 | unifi-gateway-linux-armhf |
| FreeBSD x86_64 | unifi-gateway-freebsd-amd64 |
From Source
pip install -r requirements.txt
Quick Start
1. Install dependencies
pip install -r requirements.txt
2. Configure
Copy the sample config and edit it:
cp conf/unifi-gateway.sample.conf conf/unifi-gateway.conf
Edit conf/unifi-gateway.conf:
[gateway]
# Map UniFi logical ports to your real system interfaces
ports = [ { "ifname": "eth0", "name": "WAN", "type": "wan", "realif": "eth0" }, { "ifname": "eth1", "name": "LAN", "type": "lan", "realif": "br-lan" } ]
# Your LAN-side IP and MAC (how the controller identifies this device)
lan_ip = 192.168.1.1
lan_mac = aa:bb:cc:dd:ee:ff
The realif values must match your actual system interface names (check with ip link on Linux or ifconfig on FreeBSD).
3. Adopt to controller
python unifi_gateway.py set-adopt -s http://your-controller:8080/inform
The first run sends a discovery inform. Go to the UniFi Controller UI, find the new "USG" device, and click Adopt. Then run set-adopt again to complete the handshake:
python unifi_gateway.py set-adopt -s http://your-controller:8080/inform
4. Run
# Foreground (recommended for initial testing)
python unifi_gateway.py run
# Background daemon (Linux only)
python unifi_gateway.py start
# Stop / restart
python unifi_gateway.py stop
python unifi_gateway.py restart
Platform Setup
OpenWRT
The daemon works with OpenWRT's default dnsmasq DHCP server. Typical interface mapping:
ports = [ { "ifname": "eth0", "name": "WAN", "type": "wan", "realif": "eth0" }, { "ifname": "eth1", "name": "LAN", "type": "lan", "realif": "br-lan" } ]
DHCP leases are auto-detected at /tmp/dhcp.leases.
OPNSense (FreeBSD)
The daemon auto-detects FreeBSD and uses arp -an for the neighbor table, netstat -rn for routing. It supports KEA DHCP (OPNSense's default DHCP server) with auto-detection of the lease file at /var/db/kea/kea-leases4.csv.
Typical interface mapping (check your interfaces with ifconfig):
ports = [ { "ifname": "eth0", "name": "WAN", "type": "wan", "realif": "vmx0" }, { "ifname": "eth1", "name": "LAN", "type": "lan", "realif": "vmx1" } ]
dhcp_lease_file = /var/db/kea/kea-leases4.csv
dhcp_lease_format = kea
Recommended setup using a Python virtual environment:
python3 -m venv /opt/unifi-gateway/venv
/opt/unifi-gateway/venv/bin/pip install -r requirements.txt
/opt/unifi-gateway/venv/bin/python unifi_gateway.py set-adopt -s http://your-controller:8080/inform
/opt/unifi-gateway/venv/bin/python unifi_gateway.py run
pfSense (FreeBSD)
Same as OPNSense but uses ISC dhcpd instead of KEA:
dhcp_lease_file = /var/dhcpd/var/db/dhcpd.leases
dhcp_lease_format = isc
Generic Linux (Debian, Ubuntu, etc.)
Works out of the box. Uses /proc/net/dev for multicast counters, /proc/net/route for default gateway, and /etc/resolv.conf for nameservers.
Docker
Build and run
docker build -t unifi-gateway .
docker run -d --name unifi-gateway --network host \
-v $(pwd)/conf:/app/conf \
unifi-gateway
Docker Compose
docker compose up -d
For automatic adoption on first start, set the UNIFI_ADOPT_URL environment variable in docker-compose.yml:
environment:
- UNIFI_ADOPT_URL=http://your-controller:8080/inform
Note: network_mode: host is required so the daemon can read the host's real network interfaces. This only works on Linux — Docker Desktop on Windows/macOS does not support host networking.
Service Management
Packages automatically install and enable the service. After configuring, just start it:
| Platform | Start | Logs |
|---|---|---|
| systemd (Debian/Ubuntu/RHEL) | sudo systemctl start unifi-gateway |
journalctl -u unifi-gateway -f |
| rc.d (FreeBSD/OPNSense) | sudo service unifi_gateway start |
tail -f /var/log/unifi-gateway.log |
| procd (OpenWRT) | /etc/init.d/unifi-gateway start |
logread -e unifi-gateway |
Updates are handled by your package manager: apt upgrade, dnf upgrade, opkg upgrade, apk upgrade, or pkg upgrade.
Configuration Reference
Environment Variables
| Variable | Default | Description |
|---|---|---|
UNIFI_GW_CONFIG |
conf/unifi-gateway.conf |
Path to config file |
UNIFI_GW_LOG_LEVEL |
DEBUG |
Log level (DEBUG, INFO, WARNING, ERROR) |
UNIFI_GW_LOG_FILE |
(stderr) | Log to file instead of stderr |
UNIFI_ADOPT_URL |
(none) | Controller inform URL for automatic adoption on start |
UNIFI_ADOPT_KEY |
(none) | Auth key for auto-adoption (optional, rarely needed) |
Config File (conf/unifi-gateway.conf)
[global]
| Key | Default | Description |
|---|---|---|
pid_file |
unifi-gateway.pid |
PID file path for daemon mode |
disable_broadcast |
True |
Disable UDP multicast discovery |
[gateway]
| Key | Default | Description |
|---|---|---|
ports |
(required) | JSON list mapping UniFi ports to real interfaces |
lan_ip |
(required) | LAN IP address |
lan_mac |
(required) | LAN MAC address |
firmware |
4.4.18.5052168 |
Reported firmware version |
device |
UGW3 |
Device model string |
device_display |
UniFi-Gateway-3 |
Display name |
use_aes_gcm |
False |
Use AES-GCM encryption (set by controller) |
hostname |
(auto-detected) | Override reported hostname |
dhcp_lease_file |
(auto-detected) | Path to DHCP lease file |
dhcp_lease_format |
dnsmasq |
Lease format: dnsmasq, isc, or kea |
ping_target |
ping.ubnt.com |
Host for latency measurement |
speedtest_file |
./speedtest.json |
Path to speedtest results JSON |
platform |
UNIFI-GW |
Platform string in discovery broadcasts |
[provisioned]
Populated automatically by the controller after adoption. Do not edit manually.
Speed Test
The controller can trigger speed tests. Install speedtest-cli for this to work:
pip install speedtest-cli
Results are saved to speedtest.json and reported in the next inform cycle.
Architecture
| Module | Purpose |
|---|---|
unifi_gateway.py |
Entry point, inform loop, controller response handling, adoption |
unifi_protocol.py |
TNBU binary protocol: AES-CBC/GCM encryption, zlib/snappy compression, JSON payload construction |
datacollector.py |
Cross-platform data collection via psutil (Linux + FreeBSD), with platform-specific fallbacks |
tools.py |
Helper functions for building if_table and network_table structures |
tlv.py |
TLV encoding for UDP discovery packets |
daemon.py |
Unix daemon (double-fork, PID file) |
License
MIT — see LICENSE.
Acknowledgments
This project builds upon and was inspired by:
- stephanlascar/unifi-gateway — original UniFi Gateway emulator
- qvr/unifi-gateway — Python 3 port, FreeBSD support, AES-GCM encryption
Protocol documentation: