FreeRADIUS Setup Guide (RHEL/CentOS + Debian/Ubuntu)¶
Condensed reference for installing, configuring, and testing FreeRADIUS with LDAP backend and proxying to Windows/AD RADIUS servers. All example secrets, IPs, and domains below are placeholders — replace before use.
1. Install¶
RHEL/CentOS:
yum -y install freeradius freeradius-utils freeradius-mysql freeradius-ldap freeradius-client
Debian/Ubuntu:
sudo apt install freeradius
2. Core Config — radiusd.conf¶
Key settings (defaults mostly fine to leave as-is):
security {
allow_core_dumps = no
max_attributes = 200
status_server = yes
}
proxy_requests = yes
$INCLUDE proxy.conf
$INCLUDE clients.conf
thread pool {
start_servers = 5
max_servers = 32
min_spare_servers = 3
max_spare_servers = 10
}
log {
destination = files
file = ${logdir}/radius.log
auth = yes
auth_badpass = no # keep 'no' outside of debugging — logs plaintext-adjacent failures otherwise
auth_goodpass = no
}
Security note:
auth_badpass/auth_goodpassshould staynoin production. Only flip toyestemporarily while debugging auth issues, then revert.
3. Proxying to Upstream (e.g. Windows AD/NPS) RADIUS Servers¶
Define home servers and a pool, then map a realm to that pool:
# proxy.conf
home_server hs1_<server_ip_1> {
type = auth+acct
ipaddr = <server_ip_1>
port = 1645
secret = <shared_secret> # coordinate with the Windows RADIUS admin
}
home_server hs2_<server_ip_2> {
type = auth+acct
ipaddr = <server_ip_2>
port = 1645
secret = <shared_secret>
}
home_server_pool pool_<hostname> {
type = fail-over # or load-balancing
home_server = <server_ip_1>
home_server = <server_ip_2>
}
realm <your_domain> {
pool = pool_<hostname>
nostrip
}
Naming convention used:
- Home servers: hs1_<ip>, hs2_<ip>
- Pool: pool_<hostname>
The shared secret and this FreeRADIUS server's IP need to be provided to the upstream Windows RADIUS/NPS administrator so both sides agree.
4. LDAP Backend — mods-available/ldap¶
ldap {
server = "localhost"
base_dn = "<dc=example,dc=local>"
update {
control:Password-With-Header += 'userPassword'
}
user {
base_dn = "${..base_dn}"
filter = "(uid=%{%{Stripped-User-Name}:-%{User-Name}})"
}
group {
base_dn = "${..base_dn}"
filter = "(objectClass=posixGroup)"
membership_attribute = "memberOf"
}
client {
base_dn = "${..base_dn}"
filter = '(objectClass=frClient)'
attribute {
identifier = 'radiusClientIdentifier'
secret = 'radiusClientSecret'
}
}
accounting {
reference = "%{tolower:type.%{Acct-Status-Type}}"
type {
start { update { description := "Online at %S" } }
interim-update { update { description := "Last seen at %S" } }
stop { update { description := "Offline at %S" } }
}
}
post-auth {
update { description := "Authenticated at %S" }
}
options {
chase_referrals = yes
rebind = yes
timeout = 10
timelimit = 3
}
tls {
# start_tls = yes
# ca_file = ${certdir}/cacert.pem
# certificate_file = /path/to/radius.crt
# private_key_file = /path/to/radius.key
}
pool {
start = 5
min = 4
max = ${thread[pool].max_servers}
spare = 3
}
}
Related: OpenLDAP install/config is a prerequisite for the above — see separate OpenLDAP notes.
5. Clients — clients.conf¶
Register hosts allowed to send RADIUS requests to this server:
client localhost {
ipaddr = 127.0.0.1
secret = <secret>
require_message_authenticator = no
nastype = other
}
client <friendly-name> {
ipaddr = <client_ip>
secret = <secret>
require_message_authenticator = no
nastype = other
}
6. Test Users (local, non-LDAP)¶
Useful for isolating whether an issue is FreeRADIUS-side vs. LDAP/AD-side.
# /etc/raddb/users or /etc/freeradius/users
"<testuser>" Cleartext-Password := "<testpass>"
Framed-IP-Address = 127.0.0.1,
Reply-Message = "Hello, %{User-Name}"
DEFAULT Framed-Protocol == PPP
Framed-Protocol = PPP,
Framed-Compression = Van-Jacobson-TCP-IP
For VLAN assignment via RADIUS (e.g. WPA2-Enterprise):
"<testuser>" Cleartext-Password := "<testpass>"
Tunnel-Type = VLAN,
Tunnel-Medium-Type = IEEE-802,
Tunnel-Private-Group-ID = "<vlan_id>"
7. Start / Enable¶
systemctl enable radiusd # RHEL/CentOS
systemctl start radiusd
# or on Debian/Ubuntu
service freeradius start
8. Testing¶
Debug mode¶
systemctl stop radiusd # or: service freeradius stop
radiusd -X # or: freeradius -X
Local test¶
radtest <user> '<password>' 127.0.0.1 1812 <shared_secret>
Expect rad_recv: Access-Accept on success. Confirm in the log:
tail -F /var/log/radius/radius.log
# Auth: Login OK: [<user>/<user>] (from client localhost port 1812)
Proxied test (to upstream/AD realm)¶
radtest <user>@<realm> '<AD_password>' 127.0.0.1 1645 <shared_secret>
A successful response returns standard attributes (Framed-Protocol, Service-Type, Class, etc.) — presence of Access-Accept confirms the proxy chain and realm suffix stripping/matching are working correctly.
Packet capture (optional deep debug)¶
tcpdump -i <iface> udp port 1812 or udp port 1645
Confirms the Access-Request is actually leaving with the expected username/attributes.
9. WPA2-Enterprise (802.1X) — Not Yet Documented¶
Two sections remain outstanding from the original notes and need to be written up: - Configuring the wireless controller/AP for WPA2-Enterprise (RADIUS server IP, shared secret, port) - Configuring wireless clients (EAP method, trust anchor / CA cert for the RADIUS server)
10. Troubleshooting¶
Home server marked "zombie" / no response:
Marking home server <ip> port 1645 as zombie (it looks like it is dead).
radclient: no response from server for ID <n> socket <n>
Usually a network-reachability issue between the FreeRADIUS box and the upstream RADIUS server — confirm the relevant UDP ports (1812/1813 or 1645/1646) are open, and engage the network team if not.
Notes on This Version¶
- All example secrets (
testing123, etc.), real IPs, internal domain names, and email addresses from the original notes have been replaced with placeholders. - Default FreeRADIUS test secret is conventionally
testing123— fine for local/lab testing, but confirm it's changed before any client-facing or production use. - Optional related component: a Drupal RADIUS client module was referenced in the original notes for web-app integration — worth a separate write-up if that's still in use, since it's unrelated to the core RADIUS/LDAP setup above.