FreeRADIUS Docker container based on Ubuntu 22.04.5 LTS, specifically optimized for Internet Service Providers (ISPs).
Note
This container is production-ready and includes advanced features like CoA relay, SQL read-only mode, and real-time debugging capabilities.
- π Quick Start
- βοΈ Environment Variables
- π Configuration Reloading API
- ποΈ Database Configuration
- π Status Server
- π CoA Relay
- π οΈ Debugging
- π Examples
# Basic setup with MySQL
docker run -d \
-p 1812:1812/udp \
-p 1813:1813/udp \
-e SQL_ENABLE=true \
-e MYSQL_HOST=mysql-server \
-e MYSQL_PASSWORD=your-password \
ghcr.io/ict-solutions-dev/freeradius:edge-freeradius3.2.8Tip
For production deployments, always use specific version tags instead of edge.
| Variable | Default | Type | Description |
|---|---|---|---|
SQL_ENABLE |
false |
boolean | Enable MySQL support |
SQL_READ_ONLY |
false |
boolean | Enable read-only mode (no accounting/post-auth) |
MYSQL_INIT |
false |
boolean | Initialize MySQL schema on first run |
MYSQL_HOST |
mysql |
string | MySQL server hostname |
MYSQL_PORT |
3306 |
integer | MySQL server port |
MYSQL_DATABASE |
radius |
string | MySQL database name |
MYSQL_USER |
radius |
string | MySQL username |
MYSQL_PASSWORD |
radpass |
string | MySQL user password |
Warning
Always use strong passwords for MYSQL_PASSWORD in production environments.
[!INFO] When
SQL_ENABLE_RO=trueandMYSQL_HOST_ROis configured, the container automatically creates a separatesql_romodule inmods-available/and enables it inmods-enabled/.
| Variable | Default | Type | Description |
|---|---|---|---|
SQL_ENABLE_RO |
false |
boolean | Enable secondary read-only MySQL support |
MYSQL_HOST_RO |
mysql-ro |
string | Read-only MySQL server hostname |
MYSQL_PORT_RO |
3306 |
integer | Read-only MySQL server port |
MYSQL_DATABASE_RO |
radius_ro |
string | Read-only MySQL database name |
MYSQL_USER_RO |
radius_ro |
string | Read-only MySQL username |
MYSQL_PASSWORD_RO |
radpass_ro |
string | Read-only MySQL user password |
When enabled, the following automated configuration occurs:
- π Module Creation: Copies
sqltosql_roinmods-available/ - π·οΈ Module Naming: Changes module declaration from
sql {tosql_ro { - ποΈ Database Configuration: Sets MySQL dialect and driver
- π Security Setup: Disables TLS configuration for simplified setup
- π Connection Parameters: Configures read-only database connection
- π₯ Client Reading: Optionally enables NAS client reading from RO database
- β
Module Activation: Creates symbolic link in
mods-enabled/
Database Connection Setup:
# Connection parameters are automatically configured
- #server = "localhost"
+ server = "{MYSQL_HOST_RO}"
- #port = 3306
+ port = "{MYSQL_PORT_RO}"
- #login = "radius"
+ login = "{MYSQL_USER_RO}"
- #password = "radpass"
+ password = "{MYSQL_PASSWORD_RO}"
- radius_db="radius"
+ radius_db="{MYSQL_DATABASE_RO}"TLS Configuration (Disabled):
# TLS is automatically disabled for simplified setup
- ca_file = "/etc/ssl/certs/my_ca.crt"
+ # ca_file = "/etc/ssl/certs/my_ca.crt"
- tls_required = yes
+ tls_required = noClient Reading (Optional):
# Enable reading RADIUS clients from read-only database
SQL_READ_CLIENTS_RO=true# When SQL_READ_CLIENTS_RO=true
- #read_clients = yes
+ read_clients = yes- π Read-Only Replicas: Connect to MySQL read replicas for load distribution
- π Monitoring Systems: Separate monitoring queries from production writes
- π Geographic Distribution: Use local read replicas in different regions
- βοΈ Load Balancing: Distribute read operations across multiple database instances
- π Security Segregation: Limit write access while maintaining read capabilities
# Enable primary SQL with write access
SQL_ENABLE=true
MYSQL_HOST=mysql-primary
MYSQL_USER=radius_write
MYSQL_PASSWORD=write_password
# Enable secondary read-only SQL
SQL_ENABLE_RO=true
MYSQL_HOST_RO=mysql-replica
MYSQL_USER_RO=radius_readonly
MYSQL_PASSWORD_RO=readonly_password
MYSQL_DATABASE_RO=radius_replica
# Optional: Read NAS clients from read-only database
SQL_READ_CLIENTS_RO=true
# Use read-only module for authorize section
SQL_ENABLE_RO_AUTH=trueWarning
Ensure the read-only database user has SELECT permissions on required tables (radcheck, radreply, radgroupcheck, radgroupreply, radusergroup, and optionally nas).
Tip
The sql_ro module can be used alongside the primary sql module, allowing you to route different operations to different database instances for optimal performance.
| Variable | Default | Type | Description |
|---|---|---|---|
SQL_COUNTER_ENABLE |
false |
boolean | Enable sqlcounter module |
SQL_READ_CLIENTS |
false |
boolean | Read RADIUS clients from database ('nas' table) |
SQL_READ_CLIENTS_RO |
false |
boolean | Read RADIUS clients from read-only database |
SQL_ENABLE_RO_AUTH |
false |
boolean | Use sql_ro for authorize section |
SQL_IPPOOL_ENABLE |
false |
boolean | Enable sqlippool module |
CUSTOM_MYSQL_QUERIES_POST_AUTH |
false |
boolean | Enable custom post-auth SQL queries |
| Variable | Default | Type | Description |
|---|---|---|---|
DEFAULT_CLIENT_ENABLE |
false |
boolean | Add default RADIUS client for container subnet |
DEFAULT_CLIENT_SECRET |
testing123 |
string | Secret for default RADIUS client |
DEFAULT_CLIENT_SHORTNAME |
DOCKER NET |
string | Short name for default RADIUS client |
| Variable | Default | Type | Description |
|---|---|---|---|
RADDEBUG_ENABLE |
false |
boolean | Enable raddebug control socket |
STATUS_ENABLE |
false |
boolean | Enable status virtual server |
STATUS_INTERFACE |
eth0 |
string | Interface for status server |
STATUS_USE_ALL_INTERFACES |
false |
boolean | Listen on all interfaces (0.0.0.0) |
STATUS_CLIENT |
admin |
string | Status client name |
STATUS_SECRET |
adminsecret |
string | Status client secret |
| Variable | Default | Type | Description |
|---|---|---|---|
COA_RELAY_ENABLE |
false |
boolean | Enable CoA relay |
COA_RELAY_INTERFACE |
eth0 |
string | Interface for CoA relay |
COA_RELAY_USE_ALL_INTERFACES |
false |
boolean | Listen on all interfaces (0.0.0.0) |
COA_RELAY_DISABLE_LEGACY_ATTRIBUTES |
false |
boolean | Disable Event-Timestamp and Message-Authenticator |
COA_RELAY_PACKET_DST_PORT |
3799 |
integer | CoA relay destination port |
COA_RELAY_NAS_IP_n |
- | string | NAS IP for CoA relay (n = 1,2,...) |
COA_RELAY_NAS_PORT_n |
3799 |
integer | NAS port for CoA relay (n = 1,2,...) |
COA_RELAY_NAS_SECRET_n |
- | string | NAS secret for CoA relay (n = 1,2,...) |
| Variable | Default | Type | Description |
|---|---|---|---|
CONTROL_ENABLE |
false |
boolean | Enable control API endpoint |
CONTROL_PORT |
18120 |
integer | TCP port for control server |
CONTROL_TOKEN |
secret123 |
string | Authentication token for control server |
| Variable | Default | Type | Description |
|---|---|---|---|
DISABLE_PPP_VJ_COMPRESSION |
false |
boolean | Disable PPP Van Jacobson TCP/IP header compression |
EAP_USE_TUNNELED_REPLY |
false |
boolean | Enable EAP tunneled reply |
Important
The REST API allows for runtime configuration reloading without container restart.
- Endpoint:
/restart - Method:
POST - Port:
18120(configurable viaCONTROL_PORT) - Authentication: Bearer token required
Authorization: Bearer your-control-token| Status | Description |
|---|---|
π’ 200 |
Configuration successfully reloaded |
π΄ 401 |
Invalid authentication token |
π‘ 405 |
Method not allowed (only POST supported) |
π΄ 500 |
Internal server error |
Using curl:
curl -X POST http://localhost:18120/restart \
-H "Authorization: Bearer testing123"Using httpie:
http POST localhost:18120/restart \
"Authorization: Bearer testing123"- β Validates authentication token
- π Sends SIGHUP to FreeRADIUS process
- π€ Returns success/failure response
Caution
Ensure the control token is kept secure and not exposed in logs or environment variable dumps.
Note
Read-only mode is perfect for monitoring setups, load balancing, and security-conscious deployments.
When enabled, FreeRADIUS operates in read-only mode:
- β Authentication queries: Enabled (SELECT operations)
- β
NAS clients: Read from database (
nastable) - β Accounting: Disabled (no INSERT into
radacct) - β Post-auth logging: Disabled (no INSERT into
radpostauth)
Use cases:
- π Monitoring setups: Authentication without logging
- βοΈ Load balancing: Multiple read-only instances
- π Security: Prevent accidental data modification
# Enable SQL with read-only access
SQL_ENABLE=true
SQL_READ_ONLY=true
MYSQL_HOST=mysql-server
MYSQL_USER=radius_readonly
MYSQL_PASSWORD=readonly_passWarning
When SQL_READ_ONLY=true, the SQL_COUNTER_ENABLE and SQL_IPPOOL_ENABLE options are ignored as they require write access.
Control automatic RADIUS client creation:
# Enable automatic addition of default client
DEFAULT_CLIENT_ENABLE=true
DEFAULT_CLIENT_SECRET=mysecret123
DEFAULT_CLIENT_SHORTNAME="K8S CLUSTER"Environment-specific examples:
- π³ Docker Compose:
DEFAULT_CLIENT_SHORTNAME="DOCKER NET" - βΈοΈ Kubernetes:
DEFAULT_CLIENT_SHORTNAME="K8S CLUSTER" - π₯οΈ Host Network:
DEFAULT_CLIENT_SHORTNAME="HOST NET"
Tip
If DEFAULT_CLIENT_ENABLE=false, you must manage clients manually in the database.
Enable monitoring and statistics collection:
STATUS_ENABLE=true
STATUS_INTERFACE=eth0
STATUS_CLIENT=exporter
STATUS_SECRET=adminsecret1When STATUS_ENABLE=true, the following configuration is applied:
server status {
listen {
type = status
- ipaddr = 127.0.0.1
+ ipaddr = {$RADIUS_CONTAINER_IP}
port = 18121
}
#
# We recommend that you list ONLY management clients here.
# i.e. NOT your NASes or Access Points, and for an ISP,
# DEFINITELY not any RADIUS servers that are proxying packets
# to you.
#
# If you do NOT list a client here, then any client that is
# globally defined (i.e. all of them) will be able to query
# these statistics.
#
# Do you really want your partners seeing the internal details
# of what your RADIUS server is doing?
#
- client admin {
+ client {$STATUS_CLIENT} {
- ipaddr = 127.0.0.1
+ ipaddr = 0.0.0.0
- secret = adminsecret
+ secret = {$STATUS_SECRET}
}
#
# Simple authorize section. The "Autz-Type Status-Server"
# section will work here, too. See "raddb/sites-available/default".
authorize {
ok
# respond to the Status-Server request.
Autz-Type Status-Server {
ok
}
}
}[!SECURITY] List only management clients for status queries. Avoid exposing internal statistics to NAS devices or partners.
Note
CoA (Change of Authorization) relay simplifies session management across multiple NAS devices.
The CoA relay virtual server:
- π₯ Receives CoA/Disconnect requests with minimal identification
- π Looks up full session data in the database
- π€ Forwards complete requests to appropriate NAS devices
- Request Reception: CoA/Disconnect-Request received
- Database Lookup: Search
radaccttable for active sessions - Session Identification: Find NAS and session details
- Request Forwarding: Send complete request to target NAS
- π― Simplified Scripting: Single request to FreeRADIUS handles multiple NAS devices
- π Auto-Discovery: Automatic session lookup by username
- π Multi-NAS Support: Route requests to correct NAS automatically
Disconnect specific session:
echo 'Acct-Session-Id = "769df3 312343"' | \
radclient 127.0.0.1 disconnect testing123CoA update for all user sessions:
cat <<EOF | radclient 127.0.0.1 coa testing123
User-Name = bob
Cisco-AVPair = "subscriber:sub-qos-policy-out=q_out_uncapped"
EOFImportant
Configure the detail writer module in mods-enabled for CoA relay to function properly.
# Enable raddebug support
RADDEBUG_ENABLE=true# Start debug capture (10 seconds default)
raddebug
# Extended debug capture (30 seconds)
raddebug -t 30
# Capture to file
raddebug > /var/log/freeradius/debug/radius_debug.logTip
Debug output is displayed in real-time and automatically cleaned up when finished.
Disable Van Jacobson compression for Cisco ASR BRAS compatibility:
DISABLE_PPP_VJ_COMPRESSION=trueEffect:
DEFAULT Framed-Protocol == PPP
- Framed-Protocol = PPP,
- Framed-Compression = Van-Jacobson-TCP-IP
+ Framed-Protocol = PPP
+ #Framed-Compression = Van-Jacobson-TCP-IPExtend the MySQL schema for enhanced logging:
- Database Schema Update:
ALTER TABLE radpostauth
ADD COLUMN reply_message varchar(255) DEFAULT NULL AFTER reply,
ADD COLUMN nasipaddress varchar(15) DEFAULT NULL AFTER reply_message;- Enable Custom Queries:
CUSTOM_MYSQL_QUERIES_POST_AUTH=true[!INFO] This automatically updates the query configuration to include Reply-Message and NAS-IP-Address in post-auth logging.
echo "User-Name = pppoe@example.com,User-Password = simulate" | \
radclient -x -s '127.0.0.1' auth testing123echo "User-Name = pppoe@example.com" | \
radclient -x -s '127.0.0.1' disconnect testing123echo "User-Name = pppoe@example.com,Framed-IP-Address = 100.64.0.107" | \
radclient -x -s '127.0.0.1' coa testing123echo 'User-Name = "pppoe@example.com",Cisco-Service-Info = "QD;1048576000;196608000;393216000;U;104857600;19660800;39321600"' | \
radclient -x -s '127.0.0.1' coa testing123Tip
Built with β€οΈ for ISP environments