RADIUS Server Setup
ProxPanel ships its own RADIUS server — there is no FreeRADIUS underneath. The server is written in Go, lives in internal/radius/ (server.go, coa.go, ha.go), and runs in a dedicated container (proisp-radius) listening on UDP ports 1812 and 1813.
This page covers the ports it exposes, how to register a Network Access Server (NAS) so packets are accepted, the authentication methods supported, and the accounting interim-update mechanism that drives quota tracking.
Ports exposed
Section titled “Ports exposed”| Port | Direction | Purpose | Notes |
|---|---|---|---|
| UDP 1812 | NAS to ProxPanel | Authentication (Access-Request, Access-Accept, Access-Reject) | Standard RFC-2865 port. |
| UDP 1813 | NAS to ProxPanel | Accounting (Accounting-Request Start / Interim-Update / Stop) | Standard RFC-2866 port. |
| UDP 3799 or 1700 | ProxPanel to NAS | Change-of-Authorization and Disconnect (RFC-3576 / 5176) | 3799 is RFC-default; 1700 is the MikroTik default — see CoA & Disconnect. |
The first two ports listen on 0.0.0.0 inside the RADIUS container (docker-compose.yml uses network_mode: host so the container binds the host’s UDP sockets directly).
CoA is outbound — ProxPanel originates the packet to the NAS, not the other way around. The NAS only needs to allow inbound UDP on its CoA port from the ProxPanel server’s IP.
How packets are accepted
Section titled “How packets are accepted”When a UDP packet arrives on 1812 or 1813, the server does this (server.go: GetSecret):
- Reads the source IP.
- Looks it up in the in-memory
secretsmap (loaded fromnas_deviceson startup and refreshed on demand). - If found, uses the shared secret to decode and authenticate the RADIUS packet.
- If not found in standard mode, logs
unknown NAS: x.x.x.xand drops the packet.
There is no global RADIUS secret in standard installations. Each NAS has its own. (SaaS mode runs an additional shared-secret path for tenant routers — that’s covered in Generic RADIUS and the SaaS docs.)
This is the single most common cause of “MikroTik says RADIUS timeout”:
Registering a NAS
Section titled “Registering a NAS”A NAS must exist in the nas_devices table before any RADIUS packets from it will be accepted.
- In the panel, go to NAS / Routers in the sidebar and click Add NAS.
- Fill in:
- Name — a human label, e.g.
BNG-Beirut-01. - IP address — the interface IP the router will SOURCE RADIUS packets from. Not the router’s WAN IP, not the management IP — the actual outgoing IP for UDP 1812/1813 (
/ip address printon RouterOS). - RADIUS secret — any string up to 100 characters. The same value goes in the router’s
/radius addcommand. - CoA port — 1700 for MikroTik default, 3799 for RFC-default, or whatever you configured.
- API username / password (MikroTik only) — for IP pool auto-import, torch, and dynamic queue management.
- Name — a human label, e.g.
- Save. The radius container picks up the change within seconds (it polls
nas_devicesperiodically), or you can restart it:docker restart proxpanel-radius. - Verify the load:
docker logs proxpanel-radius 2>&1 | grep "Loaded"— you should seeLoaded N NAS secretswith N increased by 1.
Without this step the radius server log will fill with unknown NAS: x.x.x.x and your subscribers will not authenticate.
Supported authentication methods
Section titled “Supported authentication methods”| Method | Wire format | RFC | Notes |
|---|---|---|---|
| PAP | Cleartext password in User-Password (encrypted under the shared secret) | RFC-2865 | Required for some non-MikroTik NAS. The subscriber’s password is stored encrypted (AES-256-GCM, license-derived key) and decrypted in memory at auth time. |
| CHAP | CHAP-Password + CHAP-Challenge | RFC-1994 | Rarely used but accepted. |
| MS-CHAPv2 | MS-CHAP-Challenge + MS-CHAP2-Response (vendor MS attrs) | RFC-2759 | The default for MikroTik PPPoE. ProxPanel implements the NT-hash dance natively in server.go so no external mschap_v2 library is needed. |
| EAP / TTLS / TLS | — | RFC-3748 | Not currently supported. WPA2-Enterprise wireless is on the roadmap. |
For MikroTik PPPoE, MS-CHAPv2 is what you want — leave the router’s PPP profile at its default. Plain PAP works but exposes the password to anyone who can sniff between the router and the panel, even though the channel is “encrypted” under the RADIUS shared secret (the encryption uses MD5 and is trivially broken with a known secret).
Authentication flow
Section titled “Authentication flow”NAS ProxPanel RADIUS | | | Access-Request (User-Name + creds) ----> | | | 1. Look up subscriber by username | | 2. Decrypt stored password | | 3. Validate (PAP / CHAP / MS-CHAPv2) | | 4. Check is_active, expiry_date | | 5. Check MAC binding (if set) | | 6. Build reply: Mikrotik-Rate-Limit, | | Framed-IP-Address (if assigned), | | Framed-Pool (if Service has one), | | Acct-Interim-Interval | <---- Access-Accept + attributes | | |The reply attributes are assembled per subscriber. The most common ones:
| Attribute | Source | Effect on MikroTik |
|---|---|---|
Mikrotik-Rate-Limit | Service’s download_speed_str / upload_speed_str (normalized to 1200k/2000k) | Creates the dynamic simple queue. |
Framed-IP-Address | Subscriber’s static IP or radreply entry or pool-allocated IP | Becomes the user’s PPPoE IP. |
Framed-Pool | Service’s pool_name (if set, no Framed-IP-Address) | Tells MikroTik to assign from this pool. |
Acct-Interim-Interval | radius_interim_update_seconds system preference (default 30 s) | How often the router sends Interim-Update accounting. |
Idle-Timeout | Service’s idle_timeout if set | Disconnect after N seconds of idle. |
Session-Timeout | Computed from expiry_date if hard-cut enabled | Force disconnect at end of plan. |
Accounting + interim updates
Section titled “Accounting + interim updates”The accounting socket (UDP 1813) receives:
- Acct-Start — when the PPPoE session comes up. Creates a row in
radacct. - Acct-Interim-Update — every N seconds (default 30) while the session is up. Updates
radacct.acctupdatetimeand bytes counters. - Acct-Stop — when the session ends. Sets
radacct.acctstoptimeand the final byte counters.
Interim updates are what makes the Stale Session Cleanup and the dashboard’s online-count work — a session with no interim update for more than 30 minutes is presumed dead and closed automatically.
Asynchronous logging
Section titled “Asynchronous logging”Every accepted or rejected RADIUS event is logged to the radius_logs table. To avoid spawning a goroutine per packet (which would OOM the box at 30 K subscribers), the server uses a fixed 8-worker pool draining a 4096-event channel (server.go: initRadiusLogWorkers). If the queue is full — your DB is slow — events are dropped, not blocked. A drop counter (radiusLogDropped) increments so you can spot the problem.
This means radius_logs is a best-effort observability surface, not a billing log. Bytes are billed from radacct.
Common troubleshooting recipes
Section titled “Common troubleshooting recipes””MikroTik says RADIUS timeout”
Section titled “”MikroTik says RADIUS timeout””docker logs proxpanel-radius 2>&1 | grep -i "unknown NAS"— if you see your router’s source IP here, register it.- Confirm the secret matches — RouterOS stores it masked; if you’re not sure, retype it on both sides.
- Confirm the router is sourcing from the IP you registered: on RouterOS,
/tool sniffer quick interface=ether1 port=1812. The first packet shows the source IP. - Confirm UDP 1812/1813 reach the panel server:
nc -uvz <panel-ip> 1812from the router shell, ortcpdump -ni any port 1812on the panel.
”Auth works but bytes never appear”
Section titled “”Auth works but bytes never appear””- Confirm accounting is also enabled on the router. On MikroTik:
/radius print detailmust showaccounting=yes. - Confirm accounting packets reach the panel:
tcpdump -ni any port 1813. - Look in
radacctfor the username:SELECT * FROM radacct WHERE username='...' ORDER BY acctstarttime DESC LIMIT 5;— if rows exist butacctupdatetimedoesn’t advance, the router is sending Start/Stop but not Interim — check the router’s accounting interval.
Related pages
Section titled “Related pages”- MikroTik Integration — RouterOS-side configuration to talk to this server.
- Generic RADIUS (Cisco / Juniper / Huawei) — using ProxPanel with non-MikroTik BNGs.
- CoA & Disconnect — mid-session changes via RFC-3576.
- IP Pool Management — how
Framed-PoolandFramed-IP-Addressare reconciled. - Stale Session Cleanup — what happens to interim updates that stop arriving.