- radius
- Server configuration
- Basic server configuration
- RadSec (RADIUS over TLS) server configuration
- RADIUS/1.1 (RFC 9765)
- Generic ALPN compatibility
- Backend response authentication
- Proxying mode
- Calling the proxy backend
- PEAP inner EAP proxying
- Modifying requests and replies
- Logging proxy attributes
- Server parameters
- Connect parameters
- Backend parameters
radius
This backend sends RADIUS requests to external RADIUS servers. It supports two modes of operation:
- Proxying mode: Forwards the incoming RADIUS request to another RADIUS server. The proxy request and reply are derived from the original request context.
- Query mode: Sends independent RADIUS requests that you construct within the execution context. This allows issuing RADIUS requests from any protocol handler, not just RADIUS.
Server configuration
Both modes share the same server configuration. Define one or more target servers within the backend block.
Basic server configuration
backends {
radius "RADIUS_BACKEND" {
# Server selection strategy (optional)
# round-robin = distribute requests across healthy servers
# hash-balance = route the same key to the same preferred server
# fallback = try next healthy server if first does not respond
# no-fallback = do not try next server if first does not respond
server-selection round-robin;
server "radius1.example.org" {
# Required unless this is a strict RADIUS/1.1 TLS backend
secret "ExampleSecret";
# Request timeout (supports duration units: ms, s, m, h)
timeout 7s;
# Number of times to retry a timed out request
retries 0;
# Enable periodical health detection
# status true;
# Connection pool settings (optional)
connections {
# Maximum number of connections to open
# max 10;
# Keep one connection warm for fast failover and restart recovery
# With UDP, this binds a local UDP socket for sending packets.
# It does not establish a remote connection.
min 1;
}
connect {
# Transport protocol: udp, tcp, or tls
protocol udp;
# Server IP address
ip 203.0.113.111;
# Alternatively, use hostname instead of ip
#host "radius1.example.org";
# Optional DNS and TCP connection deadlines
#dns-timeout 5s;
#connection-timeout 5s;
# Destination port
port 1812;
# Optional: socket buffer size in bytes
#buffer 1048576;
}
}
# Additional servers for redundancy
server "radius2.example.org" {
secret "ExampleSecret";
timeout 7s;
retries 0;
connections {
min 1;
}
# status true; # default
connect {
protocol udp;
ip 203.0.113.112;
port 1812;
}
}
}
}
RadSec (RADIUS over TLS) server configuration
For TLS connections, add a tls block inside the connect block.
RADIUS/1.1 (RFC 9765)
The following example enables both registered RADIUS ALPN profiles and prefers RADIUS/1.1:
backends {
radius "RADSEC_BACKEND" {
server "radsec.example.org" {
secret "radsec";
timeout 60s;
status true;
connections {
min 1;
}
connect {
protocol tls;
host "radsec.example.org";
port 2083;
tls {
# TLS negotiation deadline after the TCP connection succeeds
handshake-timeout 5s;
# Offer RADIUS/1.1 and RADIUS/1.0, preferring 1.1
radius_versions 1.0, 1.1;
# Client certificate for mutual TLS
certificate "RADSEC_CLIENT_CERT";
certificate_key "RADSEC_CLIENT_KEY";
# CA certificate to validate server
server_ca_certificate "RADSEC_SERVER_CA";
# Optional: custom certificate verification
@verification {
if any {
cert.subject_alt.dns != "radsec.example.org";
} then {
reject;
} else {
accept;
}
}
}
}
}
}
}
The radius_versions TLS setting controls the RADIUS packet profiles offered
with ALPN. It accepts none, 1.0, 1.1, or 1.0, 1.1. When omitted,
Radiator enables only the radius/1.0 profile for compatibility with
existing configurations. Configure radius_versions 1.0, 1.1; to enable both
profiles and prefer RADIUS/1.1. Use radius_versions none; for a RADIUS/1.0
peer that does not use ALPN.
RFC 9765 specifies 1.0, 1.1 as the default for implementations that support
both profiles. Radiator intentionally uses RADIUS/1.0 as a backward
compatibility exception. This prevents an upgrade from changing packet
encoding and validation for an existing backend. Configure 1.1 or
1.0, 1.1 to opt the backend into RFC 9765 behavior.
Any policy that enables RADIUS/1.1 requires TLS 1.3 and mutual TLS. Configure
both certificate and certificate_key for the backend client identity.
Radiator rejects an enabled RADIUS/1.1 policy without both settings and
restricts the connection to TLS 1.3. RADIUS/1.1 packets use the negotiated
Token field, omit Message-Authenticator, and carry attributes such as
User-Password and Tunnel-Password using their underlying dictionary data types
instead of the RADIUS/1.0 shared-secret transforms. The configured secret
may be omitted when protocol tls; is combined with exactly
radius_versions 1.1;. It remains required whenever the backend can use
RADIUS/1.0, including mixed version policies, omitted radius_versions,
radius_versions none;, the backward-compatible generic alpn_protocol
setting, UDP or TCP transports, and reverse backends.
Radiator supports RFC 9765 over TLS only. RADIUS/1.1 over DTLS is not supported.
Radiator rejects an outgoing RADIUS/1.1 request that contains CHAP-Password
without CHAP-Challenge. When proxy forwarding fails, Radiator returns a
proxy-specific Protocol-Error to an incoming RADIUS/1.1 client.
When both versions are enabled, Radiator does not resume backend TLS sessions. This prevents a resumed session from changing its negotiated RADIUS version. RADIUS/1.1-only backends can resume TLS sessions according to the configured TLS 1.3 ticket settings.
Generic ALPN compatibility
The generic alpn_protocol setting remains available for compatibility with
custom ALPN configurations; non-standard names use the RADIUS/1.0 packet
profile. A RADIUS peer that omits ALPN is also accepted as RADIUS/1.0 when this
older generic setting is used. Configure radius_versions when the peer must
negotiate a registered RADIUS ALPN profile. Do not configure both
radius_versions and alpn_protocol in the same TLS block. Each
alpn_protocol value must contain between 1 and 255 bytes, and duplicate
values are not allowed.
Backend response authentication
Set
require_message_authenticator true
to require Message-Authenticator in supported RADIUS/1.0 responses from the
backend. Accounting-Response and replies to Status-Server probes are exempt.
The default is false for compatibility with existing upstream servers. This
setting does not apply to RADIUS/1.1.
Proxying mode
In proxying mode, the backend forwards the incoming RADIUS request to the configured server. Use this mode when you want to relay requests to another RADIUS server.
Dictionary-unknown attributes are dropped by default. Set
proxy_unknown_attributes true
only when a peer requires private attributes that cannot be defined in the
dictionary.
When an Accounting-Request contains Acct-Delay-Time, Radiator adds the time
spent in the proxy to the received value before each attempt. Retries are
rebuilt with fresh correlation and authenticator values so the updated delay
is covered by packet authentication.
Calling the proxy backend
Call the backend directly by name in a handler pipeline:
aaa {
policy "DEFAULT" {
handler "PROXY" {
@execute {
backend "RADIUS_BACKEND";
}
}
}
}
PEAP inner EAP proxying
Call a RADIUS backend directly from an eap-peap @authentication block to
proxy the complete inner EAP conversation. Radiator terminates the PEAP TLS
tunnel. The upstream RADIUS server handles the inner EAP method. This mode is
specific to PEAP; EAP-TTLS uses its existing inner attribute and nested method
conversion.
backends {
radius "INNER_EAP_RADIUS" {
challenge-timeout 30s;
@pre-proxying {
if all {
root.eap.identity == "anonymous@example.com";
eap.identity == "user@example.com";
} then {
modify {
radiusproxy.request.attr.User-Name = aaa.identity.name;
radiusproxy.request.attr.NAS-Identifier = "peap-proxy";
}
}
}
server "upstream.example.com" {
secret "shared-secret";
connect {
protocol udp;
ip 192.0.2.10;
port 1812;
}
}
}
}
aaa {
policy "PEAP" {
handler "TERMINATE-PEAP" {
@execute {
eap {
eap-peap {
tls {
certificate_key "EAP_SERVER_KEY";
certificate "EAP_SERVER_CERT";
require_client_certificate false;
}
@authentication {
backend "INNER_EAP_RADIUS";
}
}
}
}
}
}
}
The proxy request contains the complete inner packet in EAP-Message.
Radiator maps the inner EAP identity to User-Name before @pre-proxying
runs. You can translate radiusproxy.request.attr.User-Name for upstream
routing or lookup without changing the identity inside EAP-Message.
Radiator sends an upstream Access-Challenge EAP request back through the PEAP
tunnel. It automatically returns the challenge State attributes in later
Access-Requests. Each Access-Challenge must contain exactly one complete
EAP-Request. Radiator restores its upstream EAP Identifier when PEAP header
compression omits that field from the peer response.
An Access-Accept may omit EAP-Success, and an Access-Reject may omit EAP-Failure. Radiator forwards an included terminal EAP packet only when its result and Identifier match the completed inner exchange. It ignores an invalid or contradictory terminal EAP packet and bases the access decision on the RADIUS response Code, as required by RFC 3579. An Access-Accept may provide MPPE keys without EAP-Message. It must include both MS-MPPE-Recv-Key and MS-MPPE-Send-Key when either key is present. Radiator imports the pair for PEAP key derivation and cryptobinding. Configure a protected RADIUS transport when the inner method or added attributes require transport confidentiality.
Inside @pre-proxying, use root.eap.identity for the outer identity,
eap.identity for the tunneled identity, and aaa.identity for the writable
inner working identity. See EAP identity layers.
Modifying requests and replies
Use @pre-proxying and @post-proxying blocks within the backend configuration to filter or modify attributes:
backends {
radius "RADIUS_PROXY" {
# Modify request before sending to upstream server
@pre-proxying {
# Remove attributes from the proxy request
filter {
Tunnel-Type;
Tunnel-Medium-Type;
Tunnel-Private-Group-ID;
}
# Add or modify attributes
modify {
radiusproxy.request.attr.Operator-Name = "4EXAMPLE_COM:FI";
}
# Copy specific attributes from the original request
copy {
User-Name;
User-Password;
}
}
# Modify reply before returning to client
@post-proxying {
filter {
Tunnel-Type;
Tunnel-Medium-Type;
Tunnel-Private-Group-ID;
}
copy {
Reply-Message;
}
}
server "radius1.example.org" {
# ... server configuration ...
}
}
}
The copy and filter actions handle protected dictionary attributes
according to both packet profiles. They decode a RADIUS/1.0 protected value
with the source shared secret and re-protect it for a RADIUS/1.0 destination.
RADIUS/1.1 carries the underlying value and relies on TLS protection. This
allows selected User-Password, Tunnel-Password, and other protected
attributes to cross RADIUS/1.0 and RADIUS/1.1 boundaries. Comparison rules use
the decoded logical value. A protection or conversion error fails the action
instead of silently removing the attribute. See the copy
and filter action references.
Logging proxy attributes
Use the bare radiusproxy.request.attrs and radiusproxy.reply.attrs accessors to log all proxy request or reply attributes as a JSON array of {name, value} objects. This is useful for logging all proxied attributes in @pre-proxying and @post-proxying hooks without enumerating each attribute individually.
backends {
radius "UPSTREAM" {
@pre-proxying {
copy {
User-Name;
User-Password;
Service-Type;
cisco-avpair;
}
log "PROXY_LOG" {
json {
"Request-Code" "%{radiusproxy.request.code}";
"Request-Attributes" radiusproxy.request.attrs;
}
}
}
@post-proxying {
copy {
Class;
Cisco-AVPair;
}
log "PROXY_LOG" {
json {
"Reply-Code" "%{radiusproxy.reply.code}";
"Reply-Attributes" radiusproxy.reply.attrs;
}
}
}
}
}
The logged JSON output contains all attributes as an array:
{
"Request-Code": "Access-Request",
"Request-Attributes": [
{ "name": "user-name", "value": "mikem" },
{ "name": "service-type", "value": "framed-user" }
]
}
Server parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
secret | string | conditional | RADIUS shared secret. May be omitted only for a forward TLS backend configured with exactly radius_versions 1.1;. |
timeout | duration | 3s | Request timeout |
retries | integer | 2 | Number of UDP retransmission attempts after a request timeout. TCP and TLS do not retransmit on an open connection. |
connection-status { ... } | block | - | Configure active Status-Server monitoring independently for each connection. |
status | boolean | false | Compatibility syntax for enabling Status-Server polling with default settings. |
max-incoming-packet-size | integer | 4096 | Largest packet accepted from the backend. |
max-outgoing-packet-size | integer | 4096 | Largest packet constructed and sent to the backend. |
nas_identifier | string | - | NAS-Identifier string included in outgoing Status-Server packets |
connections { ... } | block | - | Connection pool settings. Use max, min, window, idle-timeout, and selection inside it. |
priority | integer | 0 | Server priority for fallback selection (lower = higher priority). When servers have equal priority, they are tried in alphabetical order by server name. |
Connect parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
protocol | enum | (required) | Transport protocol: udp, tcp, or tls |
ip | IP address | - | Server IP address (use either ip or host) |
host | string | - | Server hostname (use either ip or host) |
port | integer | (required) | Destination port |
local-ip | IP address | - | Source IP address |
local-port | integer | - | Fixed source port; requires connections { max 1; } |
buffer | integer | 1048576 | Requested receive and send socket buffer size in bytes |
keepalive | block | - | TCP keepalive settings for TCP and TLS connections |
Backend parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
server-selection | enum | fallback | Server selection strategy: fallback, round-robin, hash-balance, least-connections, or no-fallback |
See Backend Load Balancing for syntax, field selection, multi-round behavior, and failover details.
- radius
- Server configuration
- Basic server configuration
- RadSec (RADIUS over TLS) server configuration
- RADIUS/1.1 (RFC 9765)
- Generic ALPN compatibility
- Backend response authentication
- Proxying mode
- Calling the proxy backend
- PEAP inner EAP proxying
- Modifying requests and replies
- Logging proxy attributes
- Server parameters
- Connect parameters
- Backend parameters