A replicated RADIUS server for Java — accounting and authentication — built on Aeron Cluster.
radiusward answers an Accounting-Request only after the record is durably committed on a majority of a three-node cluster (fsync on), so an acknowledged accounting record survives the loss of any single node. Duplicate and retransmitted requests — including retries that arrive through another gateway after a failover — are recognised and answered without being counted twice.
Access-Requests are decided by the gateways from identity stores (users file, SQL, LDAP/Active Directory, Netlogon); what must be shared between gateways — simultaneous-use counts, SIM sequence numbers — lives in the same replicated state.
Status: Phase 5 complete — authentication with PAP, CHAP, MS-CHAP and the EAP methods below, RadSec, DTLS and TCP, proxying, CoA/Disconnect, policies and pools; EAP-SIM, EAP-AKA and EAP-AKA′ with local SIM keys. Phases 0–3: replicated accounting, container image, durability proven on Linux with simulated power loss of all members, partitions, full disks and overload (2M sessions in 1 GiB per member), a crashed leader replaced in ~2.2 s without NAS retransmissions, export to PostgreSQL. Phase 4: a Helm chart and systemd units, members that reseed themselves after a lost disk, a continuous backup that restores a lost quorum, and 500k sessions under leader kills, partitions and node drains on Kubernetes without a lost request (report); deployment guides for Kubernetes, Amazon ECS on Graviton and bare metal; published test reports and weekly benchmarks. Next: more sinks (Phase 3b) — see the roadmap.
- Accounting: acknowledged only after the commit; deduplication of retransmissions across gateways; Accounting-On/Off; idle sessions closed; export to PostgreSQL, JSON-lines files, or forwarded to other RADIUS servers (docs/accounting-contract.md).
- Authentication methods: PAP, CHAP, MS-CHAPv1/v2, EAP-MD5, EAP-TLS, PEAP (MS-CHAPv2, GTC, TLS inside, crypto binding), TTLS (PAP, CHAP, MS-CHAP, EAP inside), TEAP, EAP-pwd, EAP-SIM, EAP-AKA, EAP-AKA′ (pseudonyms and fast re-authentication); TOTP as a second factor; stored passwords from cleartext to bcrypt, SHA-crypt, yescrypt and NT hashes.
- Identity stores: users file, SQL (
radchecklayout), LDAP/Active Directory, Active Directory over Netlogon (pure Java); plug-in API for more. - Transports: UDP over IPv4 and IPv6, RadSec (RADIUS over TLS), RADIUS over DTLS and over TCP; NAS entries by address, network or client certificate, or looked up in SQL on demand.
- Policy: check and reply items, groups, Simultaneous-Use across all gateways, login times, expiry, usage counters, IPv4 and IPv6 address pools, Chargeable-User-Identity, a small rule layer.
- Proxying: realms to pools of home servers over UDP, TLS, TCP or DTLS with failover and load balancing, RFC 7585 discovery, per-realm rewriting, inner-tunnel proxying, CoA relay.
- CoA and Disconnect: by user or session through an HTTP API, disconnect-oldest for Simultaneous-Use.
- Operations: Prometheus metrics with five Grafana dashboards and alert rules (monitoring), per-request traces, an authentication log, delayed rejects, configuration reload on SIGHUP; public multi-arch container images, a Helm chart and systemd units.
- Recovery: a member that lost its disk reseeds itself from the others
(ADR 0063);
cluster-backupkeeps a continuous backup outside the cluster, andcluster-restoreorcluster.restore.frombrings back a cluster that lost its quorum (backup).
NAS ──UDP/TLS/DTLS/TCP──▶ gateway A ─┐ ┌──▶ sink: PostgreSQL
gateway B ─┼─▶ Aeron Cluster ──────┼──▶ sink: JSON files
│ │ (3 nodes, Raft, └──▶ sink: RADIUS forwarding
│ │ fsync, dedup,
│ │ shared auth state)
Accounting-Response ◀────────┼───────┘ only after commit
Access-Accept/Reject ◀── identity stores (file, SQL, LDAP/AD, Netlogon) · home servers (proxying)
- Gateways (stateless, NIO): own the sockets, validate and authenticate packets, extract the hot attributes without allocating, forward accounting to the cluster and reply after commit; decide Access-Requests on worker threads from the identity stores.
- Cluster (Aeron Cluster, 3 nodes): replicated, fsynced log; per-session deduplication; snapshots; the shared state of authentication (reservations, sequence numbers).
- Exporter (inside every member): tails the committed log into pluggable sinks — PostgreSQL, JSON files and RADIUS forwarding built in, more on the roadmap.
Test reports of the integration, end-to-end, fault-injection and Kubernetes suites, and the benchmarks: radiusward.github.io/radiusward-server.
scripts/bench.py raises the request rate step by step until p99 latency passes 500 ms or a request is lost, for
accounting, authentication and a mix, kills the leader under load and runs the JMH suite
(docs/testing/benchmarks.md, ADR 0066). It runs weekly
on a GitHub runner and the results are published. On a
shared 4-vCPU runner, where three members, two gateways and the load generators share the CPUs — a lower bound — it
carried 3,731 accounting requests/s (each replicated to three members with fsync), at least 15,053
Access-Requests/s (every step up to 16,000/s passed) and 6,821/s mixed, and a leader killed under load lost
nothing. The hot path alone handles about 1.3 million packets/s on one core (JMH). The ceilings per profile on AWS,
with the generators on their own machines, are measured with scripts/bench-aws.sh.
Details: docs/architecture.md · what an ACK guarantees: docs/accounting-contract.md · decisions: docs/adr · every setting: docs/configuration.md.
./mvnw -q install -DskipTests && docker build -f deploy/docker/Dockerfile -t radiusward:dev .
docker compose -f deploy/compose/compose.yaml up -d --wait # 3 members + 2 gateways, fsync on
docker compose -f deploy/compose/compose.yaml run --rm tools acct --server gateway-a:1813 \
--secret testing123 --status start --session-id abc123
deploy/compose/demo-failover.sh # kill -9 the leader under load, nothing lostReleased images (public, amd64 and arm64): ghcr.io/radiusward/radiusward-server
(docs/operations/docker.md); a backup profile in compose runs the continuous backup.
helm install radiusward deploy/helm/radiusward -n radius --create-namespace -f my-values.yamlThree members and two gateways, each gateway with its own address for the NAS's primary and secondary server — docs/operations/kubernetes.md. The chart also runs the continuous backup and ships the dashboards and alert rules; it is tested nightly on kind under load (leader killed, members and gateways rolled, a volume replaced, a lost quorum restored). On Amazon ECS: docs/operations/aws-ecs.md with example CloudFormation and Terraform templates for Graviton in deploy/aws. On plain hosts with systemd: docs/operations/bare-metal.md. Restoring after a lost quorum: docs/operations/backup.md.
Requirements: JDK 25+.
./mvnw verify # build + unit/integration tests (~1 min)
scripts/run-local.sh start # 3 cluster members + 2 gateways as separate JVMs
scripts/run-local.sh wait-ready && scripts/run-local.sh status
java -jar tools/radclient/target/radclient.jar acct --server 127.0.0.1:1813 --secret testing123 \
--status start --session-id abc123 --user alice --vendor cisco
scripts/run-local.sh demo-failover # load through both gateways, kill -9 the leader, nothing lost
./mvnw -Pe2e verify # end-to-end tests against real processes
scripts/linux-tests.sh # fault injection in containers (needs Docker; nightly in CI)More in docs/operations/local-cluster.md and docs/configuration.md.
gateway.auth.enabled = true
auth.stores = local
auth.store.local.type = file
auth.store.local.path = /etc/radiusward/users # alice Cleartext-Password := "secret"
auth.store.local.mschap = true # MS-CHAPv2 (PEAP) from Cleartext-Password
auth.eap.methods = peap, ttls, tls
auth.eap.tls.certificate = /etc/radiusward/server.pem
auth.eap.tls.key = /etc/radiusward/server.key
auth.eap.tls.ca = /etc/radiusward/ca.pemStores, methods, RadSec, proxying and policies: docs/configuration.md.
| Module | What it is |
|---|---|
protocol |
SBE messages between gateways, cluster and tools |
common |
configuration, profiles, management HTTP server, non-blocking logging |
cluster-service |
deterministic accounting state machine (dedup, sessions, snapshots) |
cluster-node |
launches a cluster member; seeding, continuous backup and restore |
gateway |
RADIUS gateway: accounting, authentication, EAP, RadSec/DTLS/TCP, proxying, CoA |
export-api |
sink plug-in API, canonical attribute encoding, migration runner |
exporter |
exports the committed log to sinks (lease, state-machine reducer) |
sinks/postgres |
PostgreSQL sink |
sinks/file |
JSON-lines sink |
sinks/radius |
forwards accounting of proxied realms to their home servers |
auth-api |
identity store plug-in API |
stores/file |
users-file identity store |
stores/sql |
SQL identity store (radcheck schema) |
stores/ldap |
LDAP/Active Directory identity store and bind verifier |
verifiers/netlogon |
Active Directory over Netlogon, pure Java (MS-CHAPv1/v2, PAP) |
distribution |
the runnable radiusward.jar |
radius-dictionary |
FreeRADIUS-format dictionary parser and attribute tree |
radius-dictionary-freeradius |
Bundled FreeRADIUS dictionaries (CC BY 4.0) |
radius-codegen |
Generates constants and the hot-attribute extractor |
radius-codec |
Zero-allocation RADIUS packet codec |
tools/radclient |
Command-line test client: accounting and Access-Requests (PAP, CHAP, MS-CHAPv2), replays, decoding, load |
tools/admin-cli |
replicated state, sinks and export checks, resync, CoA/Disconnect, state versions |
testing/test-harness |
in-JVM local cluster, dev mode |
testing/e2e-tests |
end-to-end tests against real processes (-Pe2e) |
testing/linux-tests |
fault injection in containers: power loss, partitions, full disk, overload (-Plinux) |
testing/benchmarks |
JMH benchmarks |
testing/coverage |
Aggregate coverage over unit + integration tests, module floors (-Pcoverage) |
testing/test-images |
the prebuilt public test images (ghcr.io/radiusward/radiusward-test-images), built locally when not published |
testing/interop-debs |
the interop tests' server packages as .deb files for CI |
testing/eapol-test |
wpa_supplicant's eapol_test with its SIM/USIM simulator, for the EAP interop tests |
testing/radsec-client |
radsecproxy and clients for the RadSec and DTLS interop tests |
testing/samba-ad |
Samba AD domain controller for the LDAP and Netlogon tests |
All 190+ vendors in the bundled FreeRADIUS dictionaries are decoded. Cisco, Juniper (Junos 2636 and
ERX/Unisphere 4874 for MX subscriber management), MikroTik, Huawei, Meraki and Ruckus additionally
have generated accessors, deduplication profiles (Phase 1)
and test fixtures; Aruba, Ubiquiti UniFi, Open-Mesh and MikroTik hotspots have test fixtures too. Operators can add or override dictionaries in /etc/radiusward/dictionary.d/
(docs/dictionaries.md).
Apache License 2.0 — see LICENSE and NOTICE.
The RADIUS dictionary files in radius-dictionary-freeradius come from the
FreeRADIUS project and are licensed under the
Creative Commons Attribution 4.0 International License (CC BY 4.0).
Copyright The FreeRADIUS Server project and contributors. Source commit and the one change made are
recorded in NOTICE and THIRD-PARTY-LICENSES.md.