Saudações.
Esse tutorial é um guia rápido de instalação e uso do Freeradius em Docker.
É sempre nostálgico para mim trabalhar com ele, foi um dos primeiros softwares que documentei no VivaoLinux (2005) e me rendeu as primeiras consultorias da minha carreira.
Pré-requisitos (constam em outros artigos aqui do blog):
- Instalação do Linux (Debian);
- Internet no servidor (sua VPS ou host);
- Docker CE instalado;
1 – Sobre FreeRadius
O FreeRadius é um sistema especializado no protocolo RADIUS (Remote Authentication Dial-In User Service), provendo um framework completo de tratamento de requisições e respostas.
É a plataforma mais utilizada no mundo para AAA (Authentication, Authorization, and Accounting).
1.1 – Conceitos fundamentais
O FreeRadius possui dois serviços internos:
- Autenticação e Autorização: Normalmente escuta na porta UDP 1812, a porta TCP também é suportada mas pouco utilizada;
- Contabilidade: Normalmente escuta na porta UDP 1813.
O AAA funciona com a seguinte divisão de tarefas:
- Autenticação (Authentication): Foco em identificar o usuário que deseja utilizar um recurso de rede, é MUITO importante entender que autenticar não é autorizar, no RADIUS autenticar é garantir que que a identidade de um usuário é verdadeira (Access-Request):
- João é João porque apresentou o nome completo (user-name) e senha (password);
- Autorização (Authorization): Uma vez identificado o usuário como legítimo (devidamente cadastrado), essa etapa visa verificar se ele pode ou não usar o recurso desejado:
- João deseja usar o WIFI (rede “funcionarios”), autorizado (Access-Accept);
- João deseja usar o WIFI (rede “gerencia”), acesso negado (Access-Reject);
- Contabilidade (Accounting): Parte dedicada a registrar o consumo de recursos dos usuários:
- Start: Registra o inicio do uso de um recurso;
- Interim-Update: Atualiza o uso de recursos;
- Stop: Registra o fim do uso dos recursos.
Embora o RADIUS seja empregado majoritariamente para autenticação de conexões PPPoE, VPN e WIFI, ele pode ser usado para qualquer finalidade de controle AAA.
1.2 – Agentes RADIUS
Cada equipamento participa do framework RADIUS como um agente específico:
- NAS (Network Access Service): É o software ou equipamento que atende o usuário final. O NAS ele é o cliente RADIUS, tudo que o usuário final pedir será convertido no pacote RADIUS e enviado ao servidor RADIUS.
- Servidor RADIUS: É onde o FreeRadius opera, ele é um agente passivo esperando pedidos de autenticação para responder, o cliente (NAS) precisa ser autorizado por meio do IP de origem e da “secret“;
- Agente COA: É um software responsável por perceber mudanças na situação do usuário ou da sessão de contabilidade e enviar ordens ao NAS para mudar o tratamento ao usuário:
- Desconectar: Caso ele seja desativado ou exceda o uso de recursos;
- Reclassificação: Caso o usuário precise receber mais ou menos recursos, como velocidade de navegação.
- Servidor COA: É um servidor especial que escuta pedidos no NAS, ele autentica se pedidos COA são legítimos por meio de autenticação “secret“.
Visão geral:

Em alguns casos especiais, existe o emprego do servidor RADIUS como Proxy RADIUS. Essa modalidade é usada para pre-processamento de requisições antes do servidor final:
- Switch: Faz separação por REALM (domínio), exemplo:
- joao vai para o servidor A;
- maria@intranet.br vai para o servidor B;
- jose%tech vai para o servidor C;
- Fail-over: Quando o servidor X para de responder, encaminha para o servidor Y.
2 – Preparativos
Você deve ter o Docker instalado no servidor Linux (Tutorial de Docker).
Atualizar seu sistema Debian:
# Atualizar sistema local
apt -y update;
apt -y upgrade;
apt -y dist-upgrade;
apt -y autoremove;
Ferramentas que vamos precisar para testes:
# Instalar ferramentas para testar o servidor RADIUS:
apt-get -y install freeradius-utils;
Rede Docker onde vamos rodar os containers de FreeRadius:
# Rede de containers FreeRadius
docker network create radius \
-d bridge \
-o com.docker.network.bridge.name=br-radius \
-o com.docker.network.driver.mtu=1500 \
-o com.docker.network.bridge.gateway_mode_ipv4=nat-unprotected \
--subnet 10.177.177.0/24 \
--gateway 10.177.177.254;
3 – FreeRadius coringa
O primeiro contato com um servidor FreeRadius é a montagem de um servidor aberto que autoriza todo mundo, normalmente apelidado de “RADIUS Coringa“. Eu prefiro chamar de “FreeRadius aberto” e criei um container “freeradius-open“.
Esse servidor é MUITO desejado quando o verdadeiro servidor sai do ar e a rede fica 100% parada.
Criando container no Docker (modo rápido, secret padrão tulipa):
#!/bin/sh
# Volume (para logs)
mkdir -p /storage/freeradius-open;
# Rodar container
docker rm -f freeradius-open 2>/dev/null;
docker run -d \
--name=freeradius-open --hostname freeradius-open.intranet.br \
--restart=always \
--read-only \
\
-p 1812:1812/tcp -p 1813:1813/tcp \
-p 1812:1812/udp -p 1813:1813/udp \
\
--tmpfs /run:rw,size=2m \
-v /storage/freeradius-open:/data \
\
tmsoftbrasil/freeradius-open:latest;
Exemplo mais completo do mesmo container acima usando a rede “radius” e personalizando a secret na variável FREERADIUS_SECRET (usar tulipa):
#!/bin/sh
# Volume (para logs)
mkdir -p /storage/freeradius-open;
# Rodar container
docker rm -f freeradius-open 2>/dev/null;
docker run -d \
--name=freeradius-open --hostname freeradius-open.intranet.br \
--cpus=1.0 --memory=128m --memory-swap=128m \
--restart=always \
--network radius \
--ip=10.177.177.20 \
--mac-address "00:10:00:00:00:02" \
\
-p 1812:1812/tcp -p 1813:1813/tcp \
-p 1812:1812/udp -p 1813:1813/udp \
\
-e FREERADIUS_SECRET=tulipa \
\
--read-only \
--tmpfs /run:rw,size=2m \
-v /storage/freeradius-open:/data \
\
tmsoftbrasil/freeradius-open:latest;
Acompanhando os logs:
# Analisar logs em tempo real:
tail -f /storage/freeradius-open/logs/radius.log;
# Mon Mar .. : Auth: (13) Login OK: [ping/pass] (from client LOCALHOSTv4 port 0)
# Mon Mar .. : Auth: (14) Login OK: [ping/pass] (from client LOCALHOSTv4 port 0)
# Mon Mar .. : Auth: (15) Login OK: [ping/pass] (from client LOCALHOSTv4 port 0)
# Mon Mar .. : Auth: (16) Login OK: [ping/pass] (from client LOCALHOSTv4 port 0)
Testando: Envie para o IP do container ou para o IP do servidor (HOST):
# IP do servidor
IP="45.255.128.2";
# Porta
AUTH_PORT="1812";
# Secret (padrao)
SECRET="tulipa";
radtest teste 123456 $IP:$AUTH_PORT 0 $SECRET;
# Sent Access-Request Id 219 from 0.0.0.0:27534 to 45.255.128.2:1812 length 75
# User-Name = "teste"
# User-Password = "123456"
# NAS-IP-Address = 45.255.128.90
# NAS-Port = 0
# Message-Authenticator = 0x00
# Cleartext-Password = "123456"
# Received Access-Accept Id 219
# from 45.255.128.2:1812 to 45.255.128.90:27534 length 38
# Message-Authenticator = 0xecf699cb8e7837bfb48c2090560e8c94
4 – Código-fonte
O código-fonte do projeto original é necessário para obter os arquivos de configuração padrão para os próximos capítulos.
# Obter codigo do projeto vai Github
#PROJECT_VERSION="master";
PROJECT_VERSION="v3.2.x";
# Diretorio local
mkdir -p /usr/src/freeradius;
cd /usr/src/freeradius;
# Clonar fontes (download):
git clone \
--branch $PROJECT_VERSION \
--single-branch https://github.com/FreeRADIUS/freeradius-server.git . ;
5 – FreeRadius com MariaDB
Evoluindo na dificuldade, montar um servidor RADIUS com dados de usuários e contabilidade no MariaDB (antigo MySQL). Esse é o tipo mais mediocre de servidor que existe e quase sempre resulta em crises de I/O do banco de dados por conta da estrutura mal feita e entregue por padrão na configuração do FreeRadius.
5.1 – Preparando banco de dados
Instalar MariaDB Client para conectar partindo do HOST:
# Instalar cliente mysql/mariadb, comando final: mariadb
apt-get -y install mariadb-client;
Criando o container do MariaDB com nome “freeradius-mariadb“:
# Diretório para o volume do MariaDB:
mkdir -p /storage/freeradius-mariadb;
# Parar atual (para update de imagem)
docker stop freeradius-mariadb 2>/dev/null;
docker rm freeradius-mariadb 2>/dev/null;
# Baixar imagem atualizada
docker pull mariadb:latest;
# Rodar/ranovar mariadb:
docker run \
-d \
--name freeradius-mariadb \
--hostname freeradius-mariadb.intranet.br \
--cpus=4.0 --memory=2g --memory-swap=2g --shm-size=1g \
--restart=always \
\
--network radius \
--ip=10.177.177.251 \
--mac-address "00:10:00:00:f2:51" \
\
-e MYSQL_ROOT_PASSWORD=tulipasql \
-e MYSQL_DATABASE=freeradius \
-e MYSQL_USER=freeradius \
-e MYSQL_PASSWORD=tulipasql \
\
--tmpfs /run:rw,noexec,nosuid,size=8m \
--tmpfs /run/mysqld:rw,noexec,nosuid,size=64m \
--tmpfs /tmp:rw,noexec,nosuid,size=64m \
\
-v /storage/freeradius-mariadb:/var/lib/mysql \
\
mariadb:latest;
Acessando e administrando o banco:
# Acesso como root (administrador): root / tulipasql
mariadb -h 10.177.177.251 -u root -ptulipasql;
# Acesso como freeradius (cliente comum do banco)
mariadb -h 10.177.177.251 -u freeradius -ptulipasql freeradius;
# Comandos comuns:
# SHOW DATABASES;
# USE freeradius;
# SHOW TABLES;
# DESCRIBE nome_da_tabela;
#
# Comando para sair do shell sql:
# exit5.2 – Criando tabelas no MariaDB
Instalando esquema padrão de tables para MySQL:
# Caminho do esquema padrao no codigo-fonte do projeto:
SRC="/usr/src/freeradius";
SCH_MAIN="$SRC/raddb/mods-config/sql/main/mysql/schema.sql";
SCH_CUI="$SRC/raddb/mods-config/sql/cui/mysql/schema.sql";
SCH_POOL="$SRC/raddb/mods-config/sql/ippool/mysql/schema.sql";
SCH_DHCP="$SRC/raddb/mods-config/sql/ippool-dhcp/mysql/schema.sql";
# Aplicar no banco de dados 'freeradius':
cat $SCH_MAIN | mariadb -h 10.177.177.251 -u root -ptulipasql freeradius;
cat $SCH_CUI | mariadb -h 10.177.177.251 -u root -ptulipasql freeradius;
cat $SCH_POOL | mariadb -h 10.177.177.251 -u root -ptulipasql freeradius;
cat $SCH_DHCP | mariadb -h 10.177.177.251 -u root -ptulipasql freeradius;
Conferindo tabelas:
# Listar tabelas do banco 'freeradius':
mariadb -h 10.177.177.251 -u freeradius -ptulipasql freeradius -e "SHOW TABLES";
# Retorno desejado:
# +----------------------+
# | Tables_in_freeradius |
# +----------------------+
# | cui |
# | dhcpippool |
# | nas |
# | nasreload |
# | radacct |
# | radcheck |
# | radgroupcheck |
# | radgroupreply |
# | radippool |
# | radpostauth |
# | radreply |
# | radusergroup |
# +----------------------+
5.3 – Cadastrando concentradores (NAS)
O servidor RADIUS responderá somente a pedidos vindo de equipamentos conhecidos, os NAS (concentradores PPPoE, roteadores hotspot, WIFI, etc).
# Comando base para executar SQL:
_sql(){
echo;
echo "# SQL QUERY: $1";
mariadb -h 10.177.177.251 -u freeradius -ptulipasql freeradius -e "$1";
echo;
};
# Variaveis para acelerar comandos SQL
IN="INSERT INTO nas(nasname, shortname, secret) VALUES";
# Cadastrar concentrador GLOBALv4 para permitir todos os endereços IPv4
_sql "DELETE FROM nas WHERE shotname = 'GLOBALv4';";
_sql "$IN ('0.0.0.0/0', 'GLOBALv4', 'tulipa');";
# Cadastrar concentrador GLOBALv6 para permitir todos os endereços IPv6
_sql "DELETE FROM nas WHERE shotname = 'GLOBALv6';";
_sql "$IN ('::/0', 'GLOBALv6', 'tulipa');";
# Conferindo:
_sql "SELECT * FROM nas;";
5.4 – Criando usuários
Preencher tabelas com objetos de teste.
Usuário básico para teste simples “teste” (usado pelo ping healthcheck):
# Comando base para executar SQL:
_sql(){
echo;
echo "# SQL QUERY: $1";
mariadb -h 10.177.177.251 -u freeradius -ptulipasql freeradius -e "$1";
echo;
};
# Variaveis para acelerar comandos SQL
IC="INSERT INTO radcheck(username, attribute, op, value) VALUES";
IR="INSERT INTO radreply(username, attribute, op, value) VALUES";
#------------------------------------------------ login: teste
# Remover usuario de teste 'teste':
_sql "DELETE FROM radcheck WHERE username = 'teste';"
_sql "DELETE FROM radreply WHERE username = 'teste';"
# - auth:
_sql "$IC ('teste', 'Cleartext-Password', ':=', '123456')";
# - reply:
_sql "$IR ('teste', 'Acct-Interim-Interval', '=', '60')";
# Conferindo:
_sql "SELECT * FROM radcheck WHERE username = 'teste';";
_sql "SELECT * FROM radreply WHERE username = 'teste';";
Usuário “mk01“:
# Comando base para executar SQL:
_sql(){
echo;
echo "# SQL QUERY: $1";
mariadb -h 10.177.177.251 -u freeradius -ptulipasql freeradius -e "$1";
echo;
};
# Variaveis para acelerar comandos SQL
IC="INSERT INTO radcheck(username, attribute, op, value) VALUES";
IR="INSERT INTO radreply(username, attribute, op, value) VALUES";
#------------------------------------------------ login: mk01
# Remover usuario de teste 'mk01':
_sql "DELETE FROM radcheck WHERE username = 'mk01';"
_sql "DELETE FROM radreply WHERE username = 'mk01';"
# - auth:
_sql "$IC ('mk01', 'Cleartext-Password', ':=', '123456')";
_sql "$IC ('mk01', 'Simultaneous-Use', ':=', '1')";
# - reply:
_sql "$IR ('mk01', 'RP-Downstream-Speed-Limit', '=', '5128')";
_sql "$IR ('mk01', 'RP-Upstream-Speed-Limit', '=', '2048')";
_sql "$IR ('mk01', 'Mikrotik-Rate-Limit', '=', '2048k/5128k')";
_sql "$IR ('mk01', 'Mikrotik-Delegated-IPv6-Pool','=', '2001:db8:baba:baba::/64')";
_sql "$IR ('mk01', 'Acct-Interim-Interval', '=', '300')";
_sql "$IR ('mk01', 'Framed-IP-Address', '=', '10.80.80.2')";
_sql "$IR ('mk01', 'Framed-IPv6-Address', '=', '2001:db8:beba:cafe::9999')";
_sql "$IR ('mk01', 'Framed-IPv6-Prefix', '=', '2001:db8:beba:fada::/64')";
_sql "$IR ('mk01', 'Delegated-IPv6-Prefix', '=', '2001:db8:beba:c0ca::/64')";
_sql "$IR ('mk01', 'Framed-IPv6-Route', '=', '2001:db8:beba:fafa::/64')";
# Conferindo:
_sql "SELECT * FROM radcheck WHERE username = 'mk01';";
_sql "SELECT * FROM radreply WHERE username = 'mk01';";
5.5 – Criando container FreeRadius com MariaDB
Agora é hora de colocar o FreeRadius trabalhar baseado nos dados que constam no banco MariaDB:
# Volume
mkdir -p /storage/freeradius-server;
# Rodar container
echo "# Iniciando container...";
docker rm -f freeradius-server 2>/dev/null;
docker run \
-d \
-h freeradius-server \
--name=freeradius-server \
--restart=always \
--network radius \
--ip=10.177.177.40 \
--mac-address "00:10:00:00:0a:04" \
\
--memory=1g --memory-swap=1g \
--sysctl net.core.somaxconn=8192 \
\
-p 1812:1812/tcp -p 1813:1813/tcp \
-p 1812:1812/udp -p 1813:1813/udp \
\
--read-only \
--tmpfs /run:rw,size=8m \
-v /storage/freeradius-server:/data \
\
-e MARIADB_HOST=freeradius-mariadb \
-e MARIADB_USER=freeradius \
-e MARIADB_PASS=tulipasql \
-e MARIADB_NAME=freeradius \
\
-e FREERADIUS_TEST_USER=teste \
-e FREERADIUS_TEST_PASSWORD=123456 \
-e FREERADIUS_TEST_SECRET=tulipa \
\
tmsoftbrasil/freeradius-server-mariadb:latest;
5.6 – Testando o FreeRadius com MariaDB
Os usuários e senhas precisam estar cadastrados no MariaDB (capítulo 5.4).
# IP do servidor
IP="10.177.177.40";
# Porta
AUTH_PORT="1812";
# Secret (padrao)
SECRET="tulipa";
radtest teste 123456 $IP:$AUTH_PORT 0 $SECRET;
# Sent Access-Request Id 20 from 0.0.0.0:23987 to 10.177.177.40:1812 length 75
# User-Name = "teste"
# User-Password = "123456"
# NAS-IP-Address = 191.37.79.225
# NAS-Port = 0
# Message-Authenticator = 0x00
# Cleartext-Password = "123456"
# Received Access-Accept Id 20
# from 10.177.177.40:1812 to 10.177.177.254:23987 length 44
# Message-Authenticator = 0xb9815e1ab87ed55b5228bb0e08233252
# Acct-Interim-Interval = 60
6 – FreeRadius com PostgreSQL
O PG é um banco melhor para o FreeRADIUS, se bem operado.
6.1 – Preparando banco de dados
Instalar PSQL (Postgre Client) para conectar partindo do HOST:
apt-get -y install postgresql-client;
Criando o container do Postgres com nome “freeradius-postgres“:
# Diretório para o volume do Postgres:
mkdir -p /storage/freeradius-postgres;
chown -R 999:999 /storage/freeradius-postgres;
# Parar atual (para update de imagem)
docker stop freeradius-postgres 2>/dev/null;
docker rm freeradius-postgres 2>/dev/null;
# Baixar imagem atualizada
docker pull pgvector/pgvector:pg18-trixie;
# Rodar/renovar postgres:
docker run \
-d \
--name freeradius-postgres \
--hostname freeradius-postgres.intranet.br \
--cpus=4.0 --memory=2g --memory-swap=2g --shm-size=1g \
--restart=always \
\
--network radius \
--ip=10.177.177.252 \
--mac-address "00:10:00:00:f2:52" \
\
-e POSTGRES_USER=postgres \
-e POSTGRES_PASSWORD=tulipasql \
-e POSTGRES_DB=freeradius \
-e PGDATA=/var/lib/postgresql/data/pgdata \
\
--tmpfs /run:rw,noexec,nosuid,size=64m \
--tmpfs /tmp:rw,noexec,nosuid,size=64m \
\
-v /storage/freeradius-mariadb:/var/lib/mysql \
\
--health-cmd="pg_isready -U postgres" \
--health-interval=15s \
--health-timeout=5s \
--health-retries=4 \
\
\
--entrypoint "docker-entrypoint.sh" \
\
pgvector/pgvector:pg18-trixie \
postgres \
--max_connections=8192 \
--wal_level=minimal \
--max_wal_senders=0 \
--port=5432;
Acessando e administrando o banco:
# Acesso como root (no PG o root e' o usuario postgres)
PGPASSWORD='tulipasql' psql -h 10.177.177.252 -U postgres;
# Comandos comuns:
# Listar bancos de dados.: \l
# Conectar a um banco....: \c freeradius
# Exibir tabelas do banco: \dt
# Sair do terminal psql...: \q
6.3 – Criando usuário no PG para o FreeRadius
Precisamos criar o usuário freeradius senha tulipasql para o banco freeradius dentro do Postgres. Primeiro, entre como administrador.
# Acesso como administrador
PGPASSWORD='tulipasql' psql -h 10.177.177.252 -U postgres;
Sem seguida, garantir existência do banco e do acesso de usuário freeradius:
x
x
x
x
x
# Acesso como root (no PG o root e' o usuario postgres)
PGPASSWORD='tulipasql' psql -h 10.177.177.252 -U postgres;
# Acesso como freeradius
PGPASSWORD='tulipasql' psql -h 10.177.177.252 -U freeradius -d freeradius;
# Comandos comuns:
# Listar bancos de dados.: \l
# Conectar a um banco....: \c freeradius
# Exibir tabelas do banco: \dt
# Sair do terminal psql...: \q
6.2 – Criando tabelas no PG
Instalando esquema padrão de tables para PostgreSQL:
# Caminho do esquema padrao no codigo-fonte do projeto:
SRC="/usr/src/freeradius";
SCH_MAIN="$SRC/raddb/mods-config/sql/main/postgresql/schema.sql";
SCH_CUI="$SRC/raddb/mods-config/sql/cui/postgresql/schema.sql";
SCH_POOL="$SRC/raddb/mods-config/sql/ippool/postgresql/schema.sql";
SCH_DHCP="$SRC/raddb/mods-config/sql/ippool-dhcp/postgresql/schema.sql";
# Aplicar no banco de dados 'freeradius':
PGPASSWORD='tulipasql' psql -h 10.177.177.252 -U postgres -d freeradius -f $SCH_MAIN;
PGPASSWORD='tulipasql' psql -h 10.177.177.252 -U postgres -d freeradius -f $SCH_CUI;
PGPASSWORD='tulipasql' psql -h 10.177.177.252 -U postgres -d freeradius -f $SCH_POOL;
PGPASSWORD='tulipasql' psql -h 10.177.177.252 -U postgres -d freeradius -f $SCH_DHCP;
6.3 – Cadastrando concentradores (NAS)
Cadastrando equipamentos conhecidos (concentradores PPPoE, roteadores hotspot, WIFI, etc):
# Comando base para executar SQL:
_sql(){
echo;
echo "# SQL QUERY: $1";
PGPASSWORD='tulipasql' \
psql -h 10.177.177.252 -U postgres -d freeradius -c "$1";
echo;
};
# Variaveis para acelerar comandos SQL
IN="INSERT INTO nas(nasname, shortname, secret) VALUES";
# Cadastrar concentrador GLOBALv4 para permitir todos os enderecos IPv4
_sql "DELETE FROM nas WHERE shortname = 'GLOBALv4';";
_sql "$IN ('0.0.0.0/0', 'GLOBALv4', 'tulipa');";
# Cadastrar concentrador GLOBALv6 para permitir todos os enderecos IPv6
_sql "DELETE FROM nas WHERE shortname = 'GLOBALv6';";
_sql "$IN ('::/0', 'GLOBALv6', 'tulipa');";
# Conferindo:
_sql "SELECT * FROM nas;";
x
x
x
x
(parei aqui, estou escrevendo em tempo real)
.
.
.
“O foco não deve ser o problema, mas, sim,
sua atitude em relação ao problema.”
Capitão Jack Sparrow
Terminamos por hoje!
Patrick Brandão, patrickbrandao@gmail.com
