14 — NAS Management¶
Overview¶
A NAS (Network Access Server) is the physical router or layer-3 device at the edge of the ISP network that terminates PPPoE sessions and sends authentication/accounting requests to FreeRADIUS. In PyroRadius, every customer is assigned to exactly one NAS. The NAS table stores connection credentials so the application can interact with routers directly (via RouterOS API or SNMP) and so FreeRADIUS knows which devices are authorized clients.
What a NAS Does in an ISP Network¶
Customer Router
│
│ PPPoE dial (username/password)
▼
NAS Device (MikroTik / Cisco / Juniper)
│
│ RADIUS Access-Request (username, password, NAS-IP-Address)
▼
FreeRADIUS Server
│
│ checks radcheck table:
│ username matches? password matches? status active?
│
│ RADIUS Access-Accept (Framed-IP-Address, Mikrotik-Rate-Limit, …)
▼
NAS assigns IP, applies rate limit
│
│ RADIUS Accounting-Start (session-id, NAS-IP, Framed-IP)
▼
FreeRADIUS logs to radacct table
FreeRADIUS identifies the NAS by matching the NAS-IP-Address attribute in the RADIUS packet against nasname in the nas table (and against clients.conf). If the NAS IP is not in both places, FreeRADIUS will reject the request as coming from an unauthorized client.
NAS Table Structure¶
Table: nas
| Column | Type | Description |
|---|---|---|
id |
bigint PK | Auto-increment primary key |
nasname |
varchar | IP address of the NAS device (must match NAS-IP-Address in RADIUS packets) |
shortname |
varchar | Human-readable label (e.g. "Tower-A-MikroTik") |
type |
varchar | Device type: mikrotik, cisco, juniper, other |
ports |
int | Number of ports (informational; used by some RADIUS policies) |
community |
varchar | SNMP community string (for SNMP-based monitoring) |
description |
text | Free-text description |
status |
enum | active / inactive |
api_user |
varchar | RouterOS API username (MikroTik only) |
api_password |
varchar | RouterOS API password (encrypted at rest) |
api_port |
int | RouterOS API port (default: 8728) |
device_class |
varchar | Optional classification (e.g. "core", "distribution", "access") |
created_at |
timestamp | |
updated_at |
timestamp |
Key Constraints¶
nasnamemust be globally unique — FreeRADIUS uses it as the lookup key.api_passwordis stored encrypted using Laravel'sCrypt::encrypt(). Never stored plain text.status = inactivedoes not prevent FreeRADIUS from accepting packets (that is controlled byclients.conf); it only hides the NAS from active-use dropdowns in the UI.
NAS Types¶
| Type | Description | API Support | SNMP Support |
|---|---|---|---|
mikrotik |
MikroTik RouterOS device | Yes — RouterOS API port 8728 | Yes — IF-MIB SNMP |
cisco |
Cisco IOS/IOS-XE routers | No (read-only via SNMP) | Yes |
juniper |
Juniper JunOS devices | No | Yes |
other |
Any other RADIUS client | No | Optional |
For non-MikroTik NAS types, api_user, api_password, and api_port are not used. Live traffic and session management features are MikroTik-only.
How NAS is Used in RADIUS¶
clients.conf (FreeRADIUS side)¶
For each NAS in the nas table (status=active), there must be a corresponding entry in FreeRADIUS's clients.conf:
client Tower-A-MikroTik {
ipaddr = 192.168.1.1 # must match nasname
secret = your_shared_secret
shortname = Tower-A
nas_type = other # or mikrotik if using vendor-specific attrs
}
Without this entry, FreeRADIUS drops the RADIUS packet and authentication fails for all customers on that NAS.
nasname Matching¶
The NAS sends NAS-IP-Address = 192.168.1.1 in every RADIUS packet. FreeRADIUS looks up this IP in clients.conf to validate the client and find the shared secret. PyroRadius's nas.nasname field must be the same IP.
Customer-to-NAS Assignment¶
When a customer authenticates:
1. PPPoE connect comes in to NAS at IP 192.168.1.1.
2. NAS sends RADIUS Access-Request with NAS-IP-Address = 192.168.1.1.
3. FreeRADIUS accepts the request (client validated).
4. FreeRADIUS checks radcheck for the username.
5. FreeRADIUS checks radusergroup for group membership, fetches radgroupreply for rate limits.
6. FreeRADIUS returns Access-Accept.
PyroRadius stores customer.nas_id to know which NAS a customer belongs to, primarily for:
- UI grouping (list customers by NAS)
- Live traffic monitoring (which router to query)
- Session kick (which router to send disconnect to)
- Dealer NAS filtering (dealers only see NAS assigned to them)
Dealer NAS Pivot¶
Table: dealer_nas
| Column | Type | Description |
|---|---|---|
dealer_id |
bigint FK | References users.id |
nas_id |
bigint FK | References nas.id |
When a dealer creates a customer, the NAS dropdown is filtered to show only NAS entries in this pivot for their dealer ID. Admin assigns NAS to dealers via the Dealer edit page → NAS tab.
If a dealer has no NAS assigned, they cannot create customers (no valid NAS to select).
NAS Health Monitoring¶
PollNasPorts Command¶
php artisan nas:poll-ports
Scheduled to run periodically (every 5 minutes). For each active NAS:
1. Performs SNMP walk on IF-MIB::ifHCInOctets and IF-MIB::ifHCOutOctets.
2. Reads interface names from IF-MIB::ifDescr.
3. Stores readings in nas_port_readings table.
nas_port_readings Table¶
| Column | Type | Description |
|---|---|---|
id |
bigint PK | |
nas_id |
bigint FK | Which NAS |
port_name |
varchar | Interface name (e.g. ether1, pppoe-out1) |
in_octets |
bigint | Total bytes in (counter, not delta) |
out_octets |
bigint | Total bytes out |
recorded_at |
timestamp | When this reading was taken |
Deltas are calculated in the UI by comparing consecutive readings from this table.
PruneNasPorts Command¶
php artisan nas:prune-ports
Deletes nas_port_readings entries older than 7 days. Runs daily via scheduler to prevent table bloat.
NAS Status Indicator¶
The NAS list in the UI shows a status indicator for each NAS: - Green — last successful SNMP poll within 10 minutes - Yellow — last successful poll 10–30 minutes ago - Red — no successful poll in 30+ minutes (possible outage) - Grey — NAS is inactive (manually disabled)
NAS API Fields (MikroTik)¶
| Field | Default | Notes |
|---|---|---|
api_user |
— | RouterOS user with api and read permissions at minimum; write required for session kick |
api_password |
— | Stored encrypted; decrypted only when building RouterOS API connection |
api_port |
8728 | Standard RouterOS API port; API-SSL uses 8729 (not currently used) |
Creating the RouterOS API User¶
On the MikroTik device:
/user group add name=radius-api policy=api,read,write,sensitive
/user add name=pyroradius password=YourStrongPassword group=radius-api
The write policy is required to execute /ppp/active/remove for session kicks.
SNMP Configuration¶
Community String¶
nas.community stores the SNMP v2c community string. Default on most devices is public, but this should be changed to a private string in production.
What PyroRadius Reads via SNMP¶
| MIB | OID | Purpose |
|---|---|---|
IF-MIB::ifDescr |
1.3.6.1.2.1.2.2.1.2 | Interface names |
IF-MIB::ifHCInOctets |
1.3.6.1.2.1.31.1.1.1.6 | High-capacity bytes in (64-bit counter) |
IF-MIB::ifHCOutOctets |
1.3.6.1.2.1.31.1.1.1.10 | High-capacity bytes out |
IF-MIB::ifOperStatus |
1.3.6.1.2.1.2.2.1.8 | Interface up/down status |
SNMP is used as a fallback for live traffic when the RouterOS API is unavailable or the NAS is non-MikroTik.
SNMP Version¶
Currently SNMP v2c only. v3 (with authentication and encryption) is not yet implemented.
NasController CRUD Reference¶
| Method | Route | Description |
|---|---|---|
index() |
GET /nas | Paginated NAS list with status indicators |
create() |
GET /nas/create | Show create form |
store() |
POST /nas | Validate + persist NAS record |
show() |
GET /nas/{id} | NAS detail: config, port readings, customers on this NAS |
edit() |
GET /nas/{id}/edit | Edit form pre-populated |
update() |
PUT /nas/{id} | Update NAS record; re-encrypt api_password if changed |
destroy() |
DELETE /nas/{id} | Delete NAS (blocked if customers are assigned) |
poll() |
POST /nas/{id}/poll | Trigger immediate SNMP poll for this NAS |
testConnection() |
POST /nas/{id}/test | Test RouterOS API connectivity and return version string |
Adding a New NAS — Step-by-Step¶
Step 1: Configure the MikroTik Device¶
# Enable RADIUS client on MikroTik
/radius add service=ppp,dhcp address=<FreeRADIUS-IP> secret=<shared_secret> timeout=3s
# Enable PPP RADIUS authentication
/ppp aaa set use-radius=yes
# Create API user for PyroRadius
/user group add name=pyroradius-api policy=api,read,write,sensitive
/user add name=pyroradius password=<api_password> group=pyroradius-api
Step 2: Add to FreeRADIUS clients.conf¶
On the FreeRADIUS server:
client <nas_shortname> {
ipaddr = <nas_ip>
secret = <same_shared_secret_as_mikrotik>
nas_type = other
}
Reload FreeRADIUS: systemctl reload freeradius
Step 3: Add NAS in PyroRadius¶
- Navigate to Settings → NAS → Add NAS.
- Fill in:
- NAS Name (IP address — must match device IP exactly)
- Short Name
- Type:
mikrotik - SNMP Community: (your community string)
- API User: pyroradius
- API Password: (will be encrypted on save)
- API Port: 8728
- Status: Active
- Save.
Step 4: Assign NAS to Dealers¶
- Go to Users → select dealer → NAS tab.
- Check the new NAS.
- Save.
Dealers can now select this NAS when creating customers.
Step 5: Verify¶
- Click "Test Connection" on the NAS detail page — should return RouterOS version.
- Click "Poll Now" — should populate port readings.
- Create a test customer on this NAS and verify PPPoE authentication works.
Common NAS Issues¶
| Symptom | Likely Cause | Fix |
|---|---|---|
| Customers can't authenticate | NAS IP not in clients.conf | Add to clients.conf and reload FreeRADIUS |
| Wrong IP in nasname | NAS IP changed (DHCP) | Use static IP on NAS, update nasname field |
| API test fails | Firewall blocking port 8728 | Allow 8728 from app server IP on MikroTik |
| SNMP poll fails | Community string mismatch | Verify NAS SNMP config and community field |
| Session kick fails | API user missing write policy | Add write policy to API user group on MikroTik |
Related Models¶
Nas→hasManyCustomerNas→hasManyNasPortReadingNas→belongsToManyUser (via dealer_nas)