Comprehensive Guide to Setting Up a Containerized RADIUS Server with FreeRADIUS and a Mikrotik Router For WiFi Access with Captive Portal

Comprehensive Guide to Setting Up a Containerized RADIUS Server with FreeRADIUS and a Mikrotik Router For WiFi Access with Captive Portal

In today’s digital age, the demand for secure and efficient network access control has never been higher. Organizations of all sizes are increasingly relying on wireless networks to provide connectivity to their employees, customers, and guests. However, with this convenience comes the challenge of ensuring that only authorized users can access the network, and that their usage can be monitored and managed effectively.

This comprehensive guide is designed to address these challenges by providing a detailed, step-by-step approach to setting up a RADIUS (Remote Authentication Dial-In User Service) server using FreeRADIUS, integrated with a Mikrotik router, Access Points, and a captive portal. The goal is to create a robust and scalable solution for WiFi client authentication and usage tracking.

FreeRADIUS is one of the most popular and widely deployed RADIUS servers in the world. It is open-source, highly configurable, and supports a wide range of authentication methods. By running FreeRADIUS in a Docker container, you can achieve a high level of flexibility and portability, making it easier to manage and scale your network infrastructure.

Mikrotik routers are known for their powerful features and affordability. They can act as Network Access Servers (NAS), handling authentication and accounting requests, and integrating seamlessly with FreeRADIUS.

This guide will walk you through the entire process of setting up and configuring your network, including:

  1. System Communication Flow: Understanding the interaction between different components such as WiFi clients, access points, the Mikrotik router, FreeRADIUS server, captive portal, and MySQL database.
  2. FreeRADIUS Server Configuration: Detailed instructions on installing and setting up FreeRADIUS in a Docker container, configuring clients, user authentication, accounting, and integrating with a captive portal.
  3. Mikrotik Router Configuration: Steps to configure the Mikrotik router to use FreeRADIUS for authentication and accounting, and setting up the Hotspot feature for the captive portal.
  4. Troubleshooting Tips: Common issues and solutions to help you diagnose and resolve problems during the setup process.

This guide is intended for network administrators, IT professionals, and anyone with a basic understanding of networking concepts who wants to implement a secure and manageable WiFi network. Whether you are setting up a network for a small office, a large enterprise, or a public hotspot, this guide will provide you with the knowledge and tools you need to succeed.

By following this guide, you will be able to create a network that not only provides secure access to authorized users but also tracks and manages their usage effectively. This is crucial for maintaining network performance, ensuring compliance with organizational policies, and providing a positive user experience.

The system comprises of the following components and their interactions:

  1. WiFi Client: A device (e.g., smartphone, tablet, laptop etc) attempting to connect to the WiFi network.
  2. Access Points (APs): Handle wireless connections and forward traffic to the Mikrotik router.
  3. Mikrotik Router (NAS): Acts as the Network Access Server (NAS) and RADIUS client, managing authentication and accounting requests.
  4. FreeRADIUS Server: Runs in a Docker container, handling authentication, authorization, and accounting (AAA).
  5. Captive Portal: A web interface (likely Mikrotik’s built-in Hotspot portal) where users enter tokens for authentication.
  6. MySQL Database: Stores user credentials and accounting data for tracking usage.
  • Step 1: Client Connection: The WiFi client connects to the network via an AP (Access Point), which forwards the request to the Mikrotik router.
  • Step 2: Captive Portal Redirection: If unauthenticated, the Mikrotik router redirects the client to the captive portal.
  • Step 3: Token Submission: The user enters a token (username and password) in the portal, which the router sends to FreeRADIUS as an authentication request (Access-Request) over UDP port 1812.
  • Step 4: Authentication: FreeRADIUS verifies the token against the MySQL database. If valid, it sends an Access-Accept message; otherwise, it sends an Access-Reject.
  • Step 5: Network Access: Upon receiving Access-Accept, the Mikrotik router grants the client network access.
  • Step 6: Accounting: The router sends Accounting-Start, interim updates, and Accounting-Stop packets to FreeRADIUS (port 1813) to track session data (e.g., data volume, time).
  • Step 7: Quota Enforcement: FreeRADIUS uses the sqlcounter module to monitor usage against data or time limits, sending attributes like Mikrotik-Total-Limit to enforce quotas.

This flow ensures secure authentication and usage tracking, with the captive portal providing a user-friendly interface.


FreeRADIUS will run in a Docker container alongside a MySQL container for storing user data and accounting records. The setup includes configuring clients, user authentication, accounting, and captive portal integration.

Use Docker to deploy FreeRADIUS and MySQL, managed via a docker-compose.yml file for simplicity.

i) Create a Project Directory:

mkdir radius-project && cd radius-project

ii) Copy Default Configuration:

Run a temporary container to extract the default FreeRADIUS configuration:

docker run --name temp-radius -d freeradius/freeradius-server
docker cp temp-radius:/etc/raddb ./raddb
docker stop temp-radius && docker rm temp-radius

This creates a ./raddb directory with configuration files.

iii) Create a MySQL Data Directory:

mkdir mysql-data

iv) Create docker-compose.yml:

version: '3'

services:
  radius:
    image: freeradius/freeradius-server
    ports:
      - "1812:1812/udp"
      - "1813:1813/udp"
    volumes:
      - ./raddb:/etc/raddb
    depends_on:
      - db

  db:
    image: mysql:5.7
    environment:
      - MYSQL_ROOT_PASSWORD=rootpass
      - MYSQL_DATABASE=radius
      - MYSQL_USER=radius
      - MYSQL_PASSWORD=radiuspass
    volumes:
      - ./mysql-data:/var/lib/mysql
      - ./raddb/mods-config/sql/main/mysql/schema.sql:/docker-entrypoint-initdb.d/schema.sql

Purpose: Defines two services: radius (FreeRADIUS) and db (MySQL). Maps ports 1812 (authentication) and 1813 (accounting), mounts the raddb directory, and initializes MySQL with the FreeRADIUS schema.

v) Start the Containers:

docker-compose up -d

This step defines the Mikrotik router as a RADIUS client in FreeRADIUS.

i) Edit ./raddb/clients.conf:

client mikrotik {
    ipaddr = <Mikrotik_IP>
    secret = <shared_secret>
}
  • Parameters:
    • ipaddr: The IP address of the Mikrotik router (e.g., 192.168.1.1).
    • secret: A shared secret for secure communication (e.g., mysecret123).
  • Purpose: Allows the Mikrotik router to send RADIUS requests to FreeRADIUS.

Store user tokens (username and password) in the MySQL database for captive portal authentication.

i) Access MySQL:

docker exec -it radius-project_db_1 mysql -uradius -pradiuspass radius

ii) Add Users:

INSERT INTO radcheck (username, attribute, op, value) VALUES ('testuser', 'Cleartext-Password', ':=', 'testpassword');
  • Parameters:
    • username: The user’s identifier (e.g., testuser).
    • attribute: Cleartext-Password for simple password storage.
    • op: := for exact match.
    • value: The password or token (e.g., testpassword).
  • Purpose: Defines users who can authenticate via the captive portal.

Use the sqlcounter module to track and enforce data volume and time limits.

i) Create Data Volume Counter:

Create ./raddb/mods-available/dailycounter:

sqlcounter dailycounter {
    counter_name = Daily-Transfer
    check_name = Max-Daily-Transfer
    reply_name = Mikrotik-Total-Limit
    sql_module_instance = sql
    key = User-Name
    reset = daily
    query = "SELECT SUM(acctinputoctets + acctoutputoctets) FROM radacct WHERE UserName='%{${key}}' AND UNIX_TIMESTAMP(acctstarttime) > UNIX_TIMESTAMP(CURDATE())"
}
  • Parameters:
    • counter_name: Internal name for the counter.
    • check_name: Attribute to check against (set in radcheck).
    • reply_name: Attribute sent to Mikrotik to enforce limits.
    • reset: Resets the counter daily.
    • query: SQL query to sum data usage for the current day.
  • Purpose: Tracks daily data usage and sends limits to Mikrotik.

ii) Create Time-Based Counter:

Create ./raddb/mods-available/dailysession:

sqlcounter dailysession {
    counter_name = Daily-Session
    check_name = Max-Daily-Session
    reply_name = Session-Timeout
    sql_module_instance = sql
    key = User-Name
    reset = daily
    query = "SELECT SUM(acctsessiontime) FROM radacct WHERE UserName='%{${key}}' AND UNIX_TIMESTAMP(acctstarttime) > UNIX_TIMESTAMP(CURDATE())"
}
  • Parameters: Similar to dailycounter, but tracks session time in seconds.
  • Purpose: Limits daily session time.

iii) Enable Counters:

ln -s ../mods-available/dailycounter ./raddb/mods-enabled/dailycounter
ln -s ../mods-available/dailysession ./raddb/mods-enabled/dailysession

iv) Update sites-enabled/default:

In ./raddb/sites-enabled/default, add to the authorize section:

dailycounter
dailysession

v) Set User Quotas:

INSERT INTO radcheck (username, attribute, op, value) VALUES ('testuser', 'Max-Daily-Transfer', ':=', '100000000');  # 100 MB
INSERT INTO radcheck (username, attribute, op, value) VALUES ('testuser', 'Max-Daily-Session', ':=', '3600');  # 1 hour

The captive portal (assumed to be Mikrotik’s Hotspot) sends authentication requests using PAP, which FreeRADIUS supports by default. Ensure the sql module is enabled in the authorize section to authenticate users from the database. No additional FreeRADIUS configuration is needed unless a custom portal is used.


docker-compose down && docker-compose up -d

In this stage, we are going to configure the Mikrotik router to use FreeRADIUS for authentication and accounting, and set up the Hotspot feature for the captive portal.

i) Access Mikrotik (via WinBox or CLI).

ii) Add RADIUS Server:

/radius
add address=<RADIUS_IP> secret=<shared_secret> service=hotspot
  • Parameters:
    • address: FreeRADIUS server IP (e.g., 192.168.1.100).
    • secret: Must match the secret in clients.conf.
    • service: Enables Hotspot authentication.
  • Purpose: Allows the router to send RADIUS requests to FreeRADIUS.

i) Set Up Hotspot:

/ip hotspot
setup
  • Follow prompts to select the wireless interface (e.g., wlan1).
  • Choose defaults or customize as needed.

ii) Enable RADIUS in Hotspot Profile:

/ip hotspot profile
set [find name="hsprof1"] use-radius=yes radius-accounting=yes radius-interim-update=10m
  • Parameters:
    • use-radius: Enables RADIUS authentication.
    • radius-accounting: Enables accounting packets.
    • radius-interim-update: Sends updates every 10 minutes.
  • Purpose: Configures the Hotspot to use FreeRADIUS and track usage.

  • Mikrotik’s Hotspot provides a built-in captive portal, accessible when users connect.
  • Ensure the Hotspot server is active:
/ip hotspot server
set [find] enabled=yes

Purpose: Redirects unauthenticated users to the login page, which sends credentials to FreeRADIUS.


  • Check that accounting packets are sent to FreeRADIUS by monitoring logs or the radacct table in MySQL.
  • Use radtest to verify authentication:
docker exec -it radius-project_radius_1 radtest testuser testpassword <RADIUS_IP> 0 <shared_secret>

  • FreeRADIUS Logs: Run FreeRADIUS in debug mode (docker-compose.yml with command: -X) to diagnose issues.
  • Mikrotik Logs: Check /log print for RADIUS or Hotspot errors.
  • Network Issues: Ensure firewall rules allow UDP ports 1812 and 1813.
  • Database: Verify MySQL schema and user data with SELECT * FROM radcheck;.

About the Author

Joshua Makuru Nomwesigwa is a seasoned Telecommunications Engineer with vast experience in IP Technologies; he eats, drinks, and dreams IP packets. He is a passionate evangelist of the forth industrial revolution (4IR) a.k.a Industry 4.0 and all the technologies that it brings; 5G, Cloud Computing, BigData, Artificial Intelligence (AI), Machine Learning (ML), Internet of Things (IoT), Quantum Computing, etc. Basically, anything techie because a normal life is boring.

Spread the word:

Leave a Reply