Ubuntu 18.04 + FreeRadius v3 (WiFi Authentication)

Ubuntu 18.04 comes with FreeRadius version 3 so there is no need to add a PPA. Simply install FreeRadius and it’s dependencies.

sudo apt install freeradius freeradius-mysql freeradius-utils mariadb-server php-common php-gd php-curl php-mysql make

Then configure a database for FreeRadius.

Set a mysql root password (if you haven’t done so already):

mysqladmin -u root password NEWPASSWORD

Log in to MariaDB as root:

mysql -u root -p

You should now see the MariaDB prompt:

MariaDB [(none)]>

Enter these commands one at a time (pressing ENTER after each one) to create and configure the FreeRadius database:
Note:password” should be replaced by the actual password you want to set for the database!

GRANT ALL ON radiusdb.* TO radius@localhost IDENTIFIED BY "password";

Import the FreeRadius MySQL database schema with the following command:

mysql -u root -p radiusdb < /etc/freeradius/3.0/mods-config/sql/main/mysql/schema.sql

You will be prompted for the radiusdb password which you set earlier.
Create a symbolic link for sql module:

ln -s /etc/freeradius/3.0/mods-available/sql /etc/freeradius/3.0/mods-enabled/

You can check to see if the FreeRadius database is setup correctly like this:

mysql -u root -p
use radiusdb;
show tables;

You should see the following:

| Tables_in_radiusdb |
| nas                |
| radacct            |
| radcheck           |
| radgroupcheck      |
| radgroupreply      |
| radpostauth        |
| radreply           |
| radusergroup       |

Exit MariaDB:


Next, edit this config:

nano /etc/freeradius/3.0/mods-enabled/sql

… and change the following information as shown:
Note:password” should be replaced by the actual password you set for the database!

sql {
driver = "rlm_sql_mysql"
dialect = "mysql"

# Connection info:
server = "localhost"
port = 3306
login = "radius"
password = "password"

# Database table configuration for everything except Oracle
radius_db = "radiusdb"

read_clients = yes
client_table = "nas"

Save and close the file.
Change the ownership permissions of the file:

chgrp -h freerad /etc/freeradius/3.0/mods-available/sql
chown -R freerad:freerad /etc/freeradius/3.0/mods-enabled/sql

Restart the FreeRadius service and check the status:

service freeradius restart
service freeradius status

You should see something like this:

● freeradius.service - FreeRADIUS multi-protocol policy server
   Loaded: loaded (/lib/systemd/system/freeradius.service; enabled; vendor preset: enabled)
   Active: active (running) since Thu 2019-10-31 12:34:42 CET; 1 day 3h ago
     Docs: man:radiusd(8)
 Main PID: 3822 (freeradius)
    Tasks: 6 (limit: 2318)
   CGroup: /system.slice/freeradius.service
           └─3822 /usr/sbin/freeradius

Time to configure FreeRadius

Credits: Much of the following is taken from previous work done with https://www.ossramblings.com on the subject.

The following is the configuration which has been working for me for years in a business environment.

Disable proxy feature and enable extra logging info:

nano /etc/freeradius/3.0/radiusd.conf

Set the following:

proxy_requests = no
# $INCLUDE proxy.conf

Save and close file.
Tell FreeRadius about your WAP (Wireless Access Point) by editing this file:

nano /etc/freeradius/3.0/clients.conf

… with information which looks like this:

#  Define RADIUS clients (usually a NAS, Access Point, etc.).
client mywap {
        ipaddr =
        secret = myRandomP@55w05D
        require_message_authenticator = yes

Each WAP you have will need to have it’s own client entry, so if you have multiple it would look something like this:

#  Define RADIUS clients (usually a NAS, Access Point, etc.).
client mywap1 {
        ipaddr =
        secret = myRandomP@55w05D
        require_message_authenticator = yes

client mywap2 {
        ipaddr =
        secret = myRandomP@55w05D
        require_message_authenticator = yes

When you configure the “WPA2-Enterprise” options on your WAP, you’ll enter the IP address of your Radius server, and this password.

Configure EAP-TLS

I personally like to keep the original config files, so I rename them to .orig like so:

mv /etc/freeradius/3.0/mods-available/eap /etc/freeradius/3.0/mods-available/eap.orig

Then I make a new config:

nano /etc/freeradius/3.0/mods-available/eap

… and dump this in:
Note: The “myserverkeypassword” will need to match the password you use when generating the server’s keys later.

# Example /etc/freeradius/mods-available/eap file
eap {
        default_eap_type = tls
        timer_expire = 60
        ignore_unknown_eap_types = no
        cisco_accounting_username_bug = no
        max_sessions = 4096
        tls {
                certdir = ${confdir}/certs
                cadir = ${confdir}/certs
                private_key_password = "myserverkeypassword"
                private_key_file = ${certdir}/server.key
                certificate_file = ${certdir}/server.pem
                ca_path = ${cadir}
                ca_file = ${cadir}/ca.pem
                dh_file = ${certdir}/dh
                random_file = /dev/urandom
                cipher_list = "HIGH"
                make_cert_command = "${certdir}/bootstrap"
                ecdh_curve = "prime256v1"
                cache {
                        enable = no # Optionally enable
                        lifetime = 24 # hours
                        max_entries = 255
                verify {
                        tmpdir = /tmp/radiusd
                        client = "/usr/bin/openssl verify -CAfile ${..ca_file} %{TLS-Client-Cert-Filename}"
                ocsp {
                        enable = no # optionally enable
                        override_cert_url = yes
                        url = ""
        ttls {
                default_eap_type = md5
                copy_request_to_tunnel = no
                use_tunneled_reply = no
                virtual_server = "inner-tunnel"

Server configuration

Remove the default server configs:

rm /etc/freeradius/sites-enabled/*

Create a new server config:
Note: Replace “mynetwork” with whatever you want to call it.

nano /etc/freeradius/3.0/sites-available/"mynetwork"

… with the following contents:

server {
    listen {
        type = auth
        port = 1812
        ipaddr = *
    authorize {
        eap {
                ok = return
    authenticate {
    preacct {
    accounting {
        # unix
        # exec
    session {
    post-auth {
        # exec
        Post-Auth-Type REJECT {
    pre-proxy {
    post-proxy {

Link that to the sites-enabled directory:

cd /etc/freeradius/3.0/sites-enabled/
ln -s ../sites-available/"mynetwork" ./"mynetwork"


rm /etc/freeradius/3.0/certs/*
cp /usr/share/doc/freeradius/examples/certs/* /etc/freeradius/3.0/certs/
nano /etc/freeradius/3.0/certs/ca.cnf

Change the following options:
Note: Edit the lines under the certificate_authority section to match what your certificate should say about you, and change “mycapassword” (the CA password) to yours.

default_days = 1825
default_bits = 4096
input_password = "mycapassword"
output_password = "mycapassword"

Make the CA keys and the DH file:

cd /etc/freeradius/3.0/certs/
make ca.pem
make ca.der
make printca
make dh

Edit server.cnf:

nano /etc/freeradius/3.0/certs/server.cnf

… and make some similar changes:
Note: Change the server section to match what your certificate should say about your server. The “myserverkeypassword” in this file should match the “myserverkeypassword” in the eap config we configured previously!

[ CA_default ]
default_days = 1825
[ req ]
default_bits = 4096
input_password = "myserverkeypassword"
output_password = "myserverkeypassword"

Make the server certificate:

make server.pem

Getting around a bug

In order for this FreeRadius configuration to work it needs /tmp/radiusd to be created and be given certain permissions. At the time of writing this it was not automatically being done (we submitted this bug report) so this is how we solved it:

Create the following file …

nano /etc/tmpfiles.d/radius.conf

… with the following content …

d /tmp/radiusd 0700 freerad freerad – –

… save and exit, then execute the following command …

systemd-tmpfiles –create

Is it all working?

Test it by:

service freeradius stop
freeradius -X

The last line should say: “Ready to process requests

If everything is good go ahead and reboot the server and after boot check the FreeRadius service with:

service freeradius status


nano /etc/freeradius/3.0/certs/Makefile

Locate these lines:

client.p12: client.crt
  openssl pkcs12 -export -in client.crt -inkey client.key -out client.p12  -passin pass:$(PASSWORD_CLIENT) -passout pass:$(PASSWORD_CLIENT)
client.pem: client.p12
  openssl pkcs12 -in client.p12 -out client.pem -passin pass:$(PASSWORD_CLIENT) -passout pass:$(PASSWORD_CLIENT)
  cp client.pem $(USER_NAME).pem

Replace them with:

client.p12: client.crt
    openssl pkcs12 -export -in client.crt -inkey client.key -out client.p12  -passin pass:$(PASSWORD_CLIENT) -passout pass:$(PASSWORD_CLIENT)
    cp client.p12 $(USER_NAME).p12
client.pem: client.p12
    openssl pkcs12 -in client.p12 -out client.pem -passin pass:$(PASSWORD_CLIENT) -passout pass:$(PASSWORD_CLIENT)
    cp client.pem $(USER_NAME).pem
client_android.p12: client.crt
    openssl pkcs12 -export -in client.crt -inkey client.key -certfile ca.pem -name "$(USER_NAME)" -out client_android.p12  -passin pass:$(PASSWORD_CLIENT) -passout pass:$(PASSWORD_CLIENT)
    cp client_android.p12 $(USER_NAME)_android.p12

Note: Make sure indented lines are tabs and not spaces or the file will not work. If you just copy-paste this, it will probably paste as spaces, and you’ll need to delete the indents and replace with tabs.

nano /etc/freeradius/3.0/certs/client.cnf

Edit the following information:

[ CA_default ]
default_days = 365
[ req ]
prompt = now
distinguished_name = client
default_bits = 4096
input_password = clientpassword
output_password = clientpassword

Set your defaults just like you did before but this time for any client certificates. Setting the “default_days” to 365 means you will need to regenerate keys for the device in a year. Change the “default_bits” to 4096.
In the “input_password” and “output_password” set both to the same password, and keep in mind that this password will be needed when the certificate is installed on the client hardware.

Note: The “distinguished_name” should remain as “client” and not the name of the client.
The “[client]” section uniquely identifies the user in log files, so be sure the emailAddress and commonName are set properly to the user’s email address. It causes less confusion if the emailAddress and commonName both match.

Create the client certificate:

cd /etc/freeradius/3.0/certs/
make client.pem
make client_android.p12

Simply edit the client.cnf file for the next certificate and run those commands again to generate certificates for each device that will have WIFI access.

Finally, lets set the proper permissions for certificates:

cd /etc/freeradius/3.0/certs/
chmod 600 *
chown root:freerad *
chmod 640 ca.pem
chmod 644 dh
chmod 640 server.key
chmod 640 server.pem

What files are needed where?

  • Windows: ca.der and [user].p12
  • Linux: ca.pem and [user].p12
  • Android: [user]_android.p12

Configure CRL (Certificate Revocation List)

nano /root/crl_gen.sh


cd /etc/freeradius/3.0/certs
openssl ca -gencrl -keyfile ./ca.key -cert ./ca.pem -out /etc/freeradius/3.0/certs/mycrl.pem -config ./ca.cnf -passin pass: *ca.key password*
cat /etc/freeradius/3.0/certs/ca.pem /etc/freeradius/3.0/certs/mycrl.pem > /etc/freeradius/3.0/certs/ca_and_crl.pem
chown root:freerad /etc/freeradius/3.0/certs/ca_and_crl.pem
chmod 640 /etc/freeradius/3.0/certs/ca_and_crl.pem
chmod 750 crl_gen.sh
sh /root/crl_gen.sh
crontab -e

crontab entry:

0 0 */5 * * /root/crl_gen.sh >/dev/null 2>&1

Revoke Certificate

openssl ca -revoke user@email.com.pem -keyfile ca.key -cert ca.pem -config ./ca.cnf

Verify revocation (“Revoked certificates”):

openssl crl -in /etc/freeradius/3.0/certs/ca_and_crl.pem -text

About: techtalk

2 thoughts on “Ubuntu 18.04 + FreeRadius v3 (WiFi Authentication)”

  1. Hi,
    Great tutorial though! It worked a charm for me.

    I am wondering though, you could do it without MySQL, I would presume right? As we’re not going to configure any users using MySQL. But instead, certificates are issues and revoked according to the specified user.

    I would think, can we not remove those steps instead?


  2. Hi,
    Yes, I removed MySQL, MariaDB etc, and configured without, you don’t really need all those additional packages.

Leave a Reply

Your email address will not be published. Required fields are marked *