A common pitfall in environments where Windows server is used for radius authentication is that Microsoft network policy server (NPS) does currently not support device based authentication for Azure AD joined devices. NPS always checks for the existence of a corresponding computer object in AD. For my home setup and lab I wanted to build a radius solution to enable 802.1x authentication on my Wi-Fi network.


This post describes my setup and does not cover prerequisites like certification authority, certificate revocation and client certificate deployment via SCEP. Furthermore you should be familiar with docker, network topics, dns and Intune.

Available solutions

Well known commercial Network Access Control (NAC) solutions like CISCO ISE or Aruba Clearpass often ship with an integrated RADIUS server and the possibility to configure wheter LDAP lookups for computer accounts should happen. Important is, that the solution supports certificate revocation checks either via CRLs or OCSP to ensure network access is blocked when a client certificate is revoked.

For my home and lab setup I wanted to leverage a free or open source solution and decided to use freeRADIUS, probably the most popular open source radius server. freeRADIUS supports EAP-TLS for 802.1x authentication out of the box and is well documented. Additionally, I was looking for a solution that can be deployed to both locallly in my network (e.g. on a raspberry pi) and also to PaaS offerings like Azure.


Because I very like the idea of docker being able to separate configurations from the actual runtime environment I decided that I want to approach the freeRADIUS deployment with docker which allows me to basically deploy the solution anywhere (raspberry pi, developer workstation, Azure container instance, remote linux server).

I actually did the deployment of this solution twice, once with my on-premises CA based on ADCS with NDES server for my lab and another based on SCEPman cloud CA where I run the free community edition (see Azure Marketplace offer).

The complete architecture with SCEPman looks like this for my environment:


The required freeRADIUS server configuration is actually quite simple and only consists of the following high level tasks:

  • Get a certificate (clients will validate the server certificate during EAP-TLS)
  • Configure EAP(-TLS) freeRADIUS module
  • Add my access points as radius clients

Fortunately freeRADIUS is providing official docker images, therefore only custom configurations need to be copied into the image before starting a container and providing a port mapping to forward traffic from the docker host into the freeRADIUS container.


You can find all mentioned configuration files as a GitHub template to easily deploy the solution:

Link to GitHub Repo (nicolonsky/AAD-FreeRadius-802.1x){: .btn .btn–primary}


  • Docker host & client to build and run the image (can be any kind of linux server or PaaS offering)
  • Certification authority that deploys client certificates (ADCS or Cloud based like SCEPMan)
    • Revocation information is accessible via OCSP responder
    • Clients certificate deployment via SCEP
    • For Microsoft based OCSP responders nonce support must be enabled


The following steps describe the setup of freeRADIUS with docker. The setup can either be done with an Active Directory Certificate Services (ADCS) based certification authority or with a self-signed certificate for the freeRADIUS server.

Server certificate

When you run ADCS you can issue your server certificate from your internal CA. Alternatively you can issue a self-signed certificate. The SCEPman enterprise edition also support certificate manager to issue server certificates.

Certificate template (ADCS)

When using ADCS create a new certificate template to request for the freeRADIUS server, alternatively you can also use your existing template for NPS.

  • Duplicate “Web Server” template
  • General:
    • Display name: nicolonsky RADIUS
    • Compatibility: Raise both CA and recipient to Server 2016
  • Issuance Requirements: check require certificate manager approval
  • Subject Name
    • Supply in the request
  • Extensions
    • Application policies: Client Authentication, Server authentication
  • Cryptography:
    • Provider category: Key Storage Provider
    • Request must use one of the following providers: Microsoft Software Key Storage Provider
    • Request hash: SHA256
  • Mark template as issuable: Manage -> New certificate template to issue

Request certificate (ADCS)

To enroll the previously created certificate template on the internal CA the following steps are required to create a certificate signing request (CSR) and issue the certificate:

  • Request a new certificate: openssl req -new -sha256 -newkey rsa:2048 -nodes -keyout raddb/certs/server.pem -days 365 -out request.csr
    • Make sure to choose a suitable server name during the CSR prompts, I’ve chosen: radius.intra.nicolonsky.ch
  • Submit CSR to Issuing CA
    • Submit request (from a domain joined machine) and remember the request id: certreq -attrib "CertificateTemplate:nicolonskyRADIUSServer" -submit "C:\temp\request.csr"
    • Confirm the certificate request
    • Retrieve issued certificate: certreq -retrieve 24
    • Append certificate contents (export as base64 encoded) to: raddb/certs/server.pem

If you are using a non unix system you can easily find the openssl binaries within the git scm installation folder to create your certificate request. {: .notice–info}

Issue self-signed certificate

A self signed certificate can be issued with:

openssl req -x509 -new -sha256 -newkey rsa:2048 -nodes -keyout raddb/certs/server.pem -days 365 -out raddb/certs/server.pem

If you choose this approach make sure to distribute the certificate via Intune as trusted certificate to your endpoints.

Gather Issuing CA certificate

  • When SCEPMan is your CA for client certificates: use the SCEPMan CA certificate
  • When ADCS is your CA for client certificates: export the CA certificate
  • Copy base64 certificate of your issuing CA(s) to: raddb/certs/ca.pem

Add RADIUS clients

  • Add your radius clients to: raddb/clients.conf and make sure to generate a strong shared secret - you will configure this on your access points or Wi-Fi management solution:
client access-point-mgmt-network {
 ipaddr  =
 shortname = LAB
 secret  = <RADIUS Shared Secret>

Update OCSP responder URL

  • Update the URL to match your OCSP responder: raddb/mods-enabled/eap (L#706)
ocsp {
        #  If the OCSP Responder address is not extracted from
        #  the certificate, the URL can be defined here.
        url = "https://<OCSP-Responder-URL>/ocsp"

Build and run your docker images

Because the github repos contains a docker-compose and Dockerfile we can automatically build the image (basically just copying config) and sping up a container - that’s awesome, isn’t it?

  • docker compose build
  • docker compose up -d

Creating a Wi-Fi network with 802.1x authentication

On my unifi router I added a new RADIUS Profile (I also added the accounting parts, this is not necessary, though):

Unifi RADIUS Profile

  • Created a lab network and corresponding Wi-Fi SSID with WP2 Enterprise authentication.

Unifi Wi-Fi SSID

Intune config

  • I distributed the self-signed certificate of the RADIUS server via Intune as trusted certificate
    • For the ADCS based deployment the root and issuing CA certificates need to be deployed anyway to allow issuance of certificates for SCEP clients
  • Deployed the Wi-Fi profile for my previously created lab SSID/Network.
    • Intune Wi-Fi config

Additional configuration

  • Create a DNS record that points to the docker host (A or CNAME): radius.nicolonsky.ch [needs to match certificate CN or SAN] and also the configured server name of the Wi-Fi profile


To test the radius functionality you can also extend your docker-compose file to launch the freeRADIUS server in foreground mode by adding:

command: radiusd -X

This prints all client connection requests and server activity to the console.

During testing and for troubleshooting during the operation it can be helpful to connect into the docker container to view the logs:

  • Connect into container: docker exec -it aad-freeradius-8021x-radius-1 bin/bash
  • View Radius logs: tail opt/var/log/radius/radius.log


The freeRADIUS deployment with docker provides a quick and robust way to deploy a radius server with capabilities to authenticate Azure AD joined devices. The setup can be further enhanced by forwarding logs via syslog to a central syslog server and even be ingested into Microsoft sentinel.

Sources and furhter reading

Articles and docs that helped me to “develop” and build this solution: