Connecting a TP-Link Omada Controller to Powerlynx (self-hosted, RADIUS captive portal)

This guide shows how to use a TP-Link Omada Wi-Fi deployment (EAP access points behind a self-hosted Omada Software Controller) as a Powerlynx captive-portal NAS, using the RADIUS + External Web Portal flow.

How it works, in one paragraph: the Omada controller — not each individual EAP — is the RADIUS client and the CoA/PoD (UDP 3799) receiver. A client that joins the hotspot SSID is redirected to the Powerlynx splash page. After the user logs in/pays, Powerlynx auto-POSTs the client’s browser back to the controller’s /portal/radius/browserauth endpoint, and the controller then performs the RADIUS exchange (auth + accounting) with Powerlynx over a WireGuard tunnel.

:information_source: Important:This configuration only works with an on-premise / self-hosted Omada controller.
On Omada Cloud it does not work — the cloud controller cannot receive RADIUS PoD or CoA (UDP 3799) from Powerlynx, so remote disconnect and dynamic authorization are impossible there. Use a self-hosted Software Controller (or a self-hosted hardware controller).

:information_source: Note:This guide uses no TP-Link gateway (ER-series) device. The Ubuntu server that runs the Omada Software Controller also fills the “gateway” role — it terminates the WireGuard tunnel to Powerlynx and is the RADIUS client and the CoA/PoD (UDP 3799) receiver. You only need that server plus a TP-Link EAP; no Omada router/gateway is involved.


1. Architecture / topology

Traffic and control chain:

Wi-Fi client → TP-Link EAP (SSID) → self-hosted Omada Controller → WireGuard → Powerlynx
                                     (RADIUS client + UDP 3799 listener)
  • The controller is the RADIUS client (sends Access-Request / accounting) and the UDP 3799 listener that receives Disconnect (PoD) requests from Powerlynx.
  • The WireGuard tunnel terminates at the operating-system level on the controller host (wg-quick), not via Omada’s built-in WireGuard. Omada’s WireGuard is a GATEWAY/ER-series-only feature and does nothing on a Software Controller.
  • Powerlynx does not provide Internet access. It is the control plane only — RADIUS auth/accounting and the captive-portal splash page. Client Internet is provided by the site’s own gateway / uplink (a separate router). The WireGuard tunnel carries only the RADIUS/CoA control traffic between the controller and Powerlynx — never user data.


2. Prerequisites

Requirement Detail
Host OS Linux — Ubuntu 16.04 / 18.04 / 20.04 / 22.04 / 24.04, or Debian 8–12 (64-bit). Windows is also supported.
Java OpenJDK 17+ (64-bit) for controller v5.15.20 and above (earlier builds use Java 8+).
MongoDB Up to MongoDB 8 for v5.15.20+ (up to v7 for 5.14.20+).
jsvc Apache Commons Daemon (jsvc) — v1.0.15 recommended with OpenJDK 17.
Controller Omada Software Controller, v5 line (this guide uses the 5.15.x release; the current shipping line is v6.2.x, so pick 5.15.x under “Previous Version” on the download page).
Access point A TP-Link Omada EAP (e.g. EAP225 v3+).
Static/Dynamic IP IP for the controller host — EAP adoption and RADIUS config reference it by IP.
Powerlynx A Powerlynx Location and a hotspot already created.

For host hardware sizing and the full requirement matrix, follow TP-Link’s official install guide (see References).


3. Install the Omada controller

Install the Omada Software Controller (v5 line) on the Ubuntu host. Official download and install links are in the References section at the end.

# 1. OpenJDK 17 + jsvc
sudo apt update
sudo apt install -y openjdk-17-jre-headless jsvc curl gnupg

# 2. MongoDB 8.0
curl -fsSL https://www.mongodb.org/static/pgp/server-8.0.asc | \
  sudo gpg -o /usr/share/keyrings/mongodb-server-8.0.gpg --dearmor
echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/8.0 multiverse" | \
  sudo tee /etc/apt/sources.list.d/mongodb-org-8.0.list
sudo apt update && sudo apt install -y mongodb-org

# 3. Install the controller .deb (download from the official page — see References)
sudo dpkg -i omada_v5.15.24.19_linux_x64_*.deb
# If dpkg complains about the jsvc version:
#   sudo dpkg --ignore-depends=jsvc -i omada_v5.15.24.19_linux_x64_*.deb

# 4. Start
sudo tpeap start
tpeap status

Then open the UI at https://<controller-ip>:8043 and run the setup wizard: create the admin account, create a site, and skip Omada Cloud access (this is an on-prem setup).

:information_source: Important: The first start can take several minutes, and the web ports (8043/8088) only bind at the very end of startup. If nmap shows them “closed” while the service reports “running”, it is still starting — watch logs/server.log until the ports open.

Verify the install

java -version                          # OpenJDK 17
sudo tpeap status                      # "Omada Controller is running"
sudo ss -tlnp | grep -E '8043|8088'    # web ports listening = startup finished

Firewall ports

If the host runs a firewall, open these (controller v5.x):

Port Purpose
TCP 8043 / 8088 HTTPS / HTTP management + captive portal
TCP 8843 HTTPS captive portal
UDP 29810 EAP discovery
TCP 29811–29814 device adoption / management / firmware
TCP 29815–29816 device data / remote CLI (v5.9+)

For the Powerlynx side of the tunnel also allow:

Direction Port Purpose
Controller → Powerlynx (outbound) UDP 1812 / 1813 RADIUS auth / accounting
Powerlynx → Controller (inbound) UDP 3799 PoD (disconnect)


4. Adopt the EAP and create the WLAN (SSID)

  1. Power up the EAP on the same L2 network as the controller; it appears under Devices.
  2. Adopt it and wait for status CONNECTED.
  3. Create a WLAN / SSID for the hotspot (Settings → Wireless Networks → WLAN) and set its name — this lab uses Power-TPLink. For a lab, Open or WPA-Personal both work; production hotspots normally use an Open SSID so the captive portal can intercept unauthenticated clients. The Portal (section 7) is then applied to this WLAN.

:information_source: Important:The SSID name must match on both sides. Powerlynx decides which Location and Splash Page a session belongs to by the SSID name (not by RADIUS realm/domain).
The WLAN name set on the Omada EAP (here Power-TPLink) must be entered exactly as the SSID on the Powerlynx side — on the Location and its Splash Page. If the names differ, the session will not map to the correct splash page / location.


5. WireGuard tunnel (controller host ↔ Powerlynx)

The tunnel runs at the OS level on the Ubuntu host.

Install WireGuard on the host:

sudo apt update && sudo apt install -y wireguard
  1. When you create the WireGuard hotspot in Powerlynx (Location → Hotspots → Add, then the Configuration step), set Connection type = Wireguard, click Generate Wireguard keys, enter the Radius secret, and finish the wizard. Generating shows the client private key — copy it now for the Ubuntu side.

:information_source: Note: The client private key is shown only at generation time; afterwards Powerlynx displays only the client PUBLIC key. You only ever need to Generate once. “Regenerate keys” is for re-keying later and is destructive — it issues a new pair and drops the existing peer, so the host would have to be reconfigured with the new key.

  1. Take the server endpoint and server public key from the generated router script
    (the .rsc Powerlynx produces).
  2. Create /etc/wireguard/wg0.conf on the Ubuntu host:
[Interface]
PrivateKey = <client-private-key-from-regenerate>
Address    = <controller-tunnel-ip>/32

[Peer]
PublicKey  = lPYDyIwk5X4tyUMNT9ny/nyPSyHwk31mzm2ahOH7iV0=
Endpoint   = 139.84.237.27:433
AllowedIPs = 172.16.0.1/32
PersistentKeepalive = 15
  1. Bring it up, enable it on boot, and verify:
sudo wg-quick up wg0                   # start the tunnel now
sudo systemctl enable wg-quick@wg0     # start automatically on boot
systemctl status wg-quick@wg0.service  # should be "active (exited)"
sudo wg show                           # peer, latest handshake, transfer counters
ping -c4 <powerlynx-tunnel-ip>         # confirm connectivity through the tunnel

A successful ping to the Powerlynx tunnel address confirms the tunnel is up:

wireguard-ping


6. Powerlynx hotspot configuration

On the Powerlynx hotspot (Location → hotspot):

Field Value
NAS type TP-Link (cloud)
Connection type WireGuard
NAS IP <controller-tunnel-ip> (the controller’s WireGuard address)
RADIUS secret <your-radius-secret>


7. Omada Portal + RADIUS profile

This is the critical configuration. In the controller: Settings → Authentication → Portal and Settings → Profiles → RADIUS Profile.

Portal

Setting Value Note
Authentication Type RADIUS Server Do not pick “External Portal Server” — that is the deprecated controller-API flow Powerlynx does not use.
External Web Portal URL https://yourpowerlynxdomain.app/redirect-flow Your Powerlynx portal’s redirect-flow URL — replace yourpowerlynxdomain.app with your own Powerlynx domain.
Disconnect Requests Enabled Enables the PoD listener.
Receiver Port 3799
Authentication Mode PAP CHAP as fallback.

RADIUS Profile

Setting Value Note
Authentication Server 172.16.0.1:1812 By IP, not hostname — a hostname silently breaks accounting.
Accounting Server 172.16.0.1:1813 Same — by IP.
Auth / Accounting / CoA password <your-radius-secret> Exactly the hotspot’s RADIUS secret, all three fields.
Accounting Enabled
Interim Update Interval 300 s (production) / 60 s (lab) Must stay under Powerlynx accounting_interval × factor — see section 8.


8. Recommended RADIUS attributes (Powerlynx NAS type “TP-Link (cloud)”)

Set these on the Powerlynx NAS-type attribute templates. These values are what make rate limiting, session time, accounting direction, and disconnect actually work with Omada.

Group Attribute Recommended value Why
Rate limit WISPr-Bandwidth-Max-Up {{ mul .tx_rate_limit 1024 }} Upload cap (kbps → bps).
Rate limit WISPr-Bandwidth-Max-Down {{ mul .rx_rate_limit 1024 }} Download cap (kbps → bps).
Rate limit Session-Timeout {{ .time_left }} Per-voucher remaining time.
PoD User-Name {{ .mac }} Identifies the client to disconnect.
PoD Calling-Station-Id See note below upper
Accounting Invert accounting ON See below.

:information_source: Important:The Calling-Station-Id line is what makes PoD work. Omada matches disconnects by a MAC in UPPERCASE with HYPHENS (e.g. AA-BB-CC-DD-EE-FF).
Powerlynx’s plain {{ .mac }} renders lowercase-with-colons, which Omada will not match — the disconnect is silently ignored with no ACK.
Use {{ .mac | upper | replace ":" "-" }} so the value matches Omada’s own format.

Invert accounting (ON): Omada is RFC-standard — Acct-Input = upload,
Acct-Output = download. With Invert accounting ON, Powerlynx maps these to the correct download/upload direction in its UI.

Interim Update interval (important coupling). Powerlynx force-closes a session if no accounting update arrives within accounting_interval × factor (the Powerlynx NAS-type fields). So the invariant is:

Omada Interim Update interval < Powerlynx accounting_interval × factor

  • Production (recommended): a 300 s interim interval is a common Wi-Fi / captive-portal
    choice — it keeps volume/time accounting reasonably current without flooding the RADIUS
    server. (RFC 2869 sets the floor at ≥ 60 s and suggests ≥ 600 s; 300 s is the usual hotspot
    compromise for tighter quota accuracy, and 600 s is fine if you prefer strict RFC alignment.)
    To use 300 s safely, set the Powerlynx NAS-type Accounting interval = 300 and
    factor = 2 (a 600 s closer window), and Omada’s Interim Update Interval = 300 s.


9. Verify

On the controller host, capture RADIUS traffic on the tunnel interface:

sudo radsniff -i wg0 -p 1812 -x           # captures 1812/1813/3799
# or, for disconnect only:
sudo tcpdump -ni wg0 -vv 'udp port 3799'

Checklist:

Phase Expect
Auth Access-RequestAccess-Accept. User-Name = MAC (no separator, uppercase); Calling-Station-Id = MAC upper-hyphen; NAS-IP-Address = <controller-tunnel-ip>.
Accounting StartInterim (at your configured interval) → Stop; download/upload direction correct with Invert ON.
PoD / disconnect Trigger the disconnect from Powerlynx early in the session (so a Session-Timeout expiry cannot be mistaken for a successful kick). Success = a Disconnect-Request (carrying Calling-Station-Id in upper-hyphen) → Disconnect-ACK → client dropped with an Acct-Stop cause that is not Session-Timeout.

:information_source: Important: The presence of the Disconnect-ACK packet is the definitive success signal for PoD. If you see a Disconnect-Request but no ACK, re-check the Calling-Station-Id format (section 8).

Where to see authorized / online devices

  • Powerlynx — the top-level Sessions page (and the Location’s sessions view) lists live/online sessions for the hotspot: client MAC, plan/voucher, data used, start and expiry.
  • Omada controllerClients shows the device as AUTHORIZED (auth type Radius - …); Hotspot Management → Authorized Clients shows per-client download/upload, start and expiration time, and status.


10. Limitations & gotchas

  • CoA-Request is NOT supported by Omada — it returns CoA-NAK (Error-Cause “Unsupported-Attribute”). Only Disconnect/PoD works. Anything that would rely on a mid-session CoA (changing rate/time, trial→paid promotion) will not take effect on Omada; it requires disconnect + re-authentication instead.
  • Trial Sessions are not currently usable with the TP-Link Omada NAS type. With Trial sessions enabled (Config → Captive portal → Trial sessions), the trial flow does not work on Omada — the client is authorized and then immediately dropped (Session-Timeout = 0, lands on the status page with no Internet). Leave Trial sessions disabled for locations served by a TP-Link Omada hotspot, and use vouchers instead.
  • Omada’s built-in WireGuard is gateway-only — it does nothing on a Software Controller. Terminate WireGuard at the OS level on the controller host (wg-quick).
  • RADIUS servers must be set by IP, not hostname — a hostname silently breaks accounting.
  • Omada Cloud has no working CoA/PoD endpoint — a self-hosted controller is required for disconnect to function.

References

Official TP-Link / Omada documentation (the tp-link.com FAQ/download links redirect to the Omada docs site support.omadanetworks.com; both resolve):