☰
CentOS 下 FreeRADIUS + daloradius + OpenPortal 认证计费系统搭建与限速实战
2026/10/13 23:21:16 网站建设 项目流程

1. 为什么这套组合至今仍值得折腾

认证计费这套东西,做过园区网、酒店无线、校园宿舍宽带的朋友应该都不陌生。FreeRADIUS 负责认证、授权、计费三件事,daloradius 给它套一个能点鼠标的 Web 管理界面,OpenPortal 则负责把用户第一次连上来时的门户页面接住,引导到认证流程里。三个组件拼起来,就是一套完整的"连网先登录、登录要计费、计费能限速"的闭环。

我最早接触这套方案是在一个园区无线改造项目里,当时的需求很朴素:几百个用户,每人一个账号,按流量或者时长计费,超了要限速,管理员要能在网页上看到谁在线、谁欠费。商业 AC 自带的 Portal 也能做,但账号体系跟现有系统对接麻烦,计费规则改起来要提工单,最后干脆自己搭一套。CentOS 作为底座,稳定、资料多、社区包全,FreeRADIUS 是 RADIUS 协议实现里最成熟的开源选择,daloradius 虽然界面老旧但功能齐全,OpenPortal 轻量、改起来方便。这套组合跑下来,维护成本低,扩展性也够。

这篇文章面向的是有一定 Linux 基础、想自己搭一套认证计费系统的运维或者网络工程师。我会把安装、配置、对接、限速这几块拆开讲清楚,重点放在"为什么这么配"和"踩过哪些坑"上,而不是简单贴命令。命令谁都会抄,但出了问题知道往哪查,才是真正省时间的地方。

需要提前说明的是,下面涉及的所有 IP、域名、账号都是示例,实际部署时按自己的环境替换。整套流程我在 CentOS 7 和 CentOS 8 上都验证过,CentOS 7 的包更全一些,新手建议从 7 开始。

2. 整体架构与组件职责拆解

2.1 三个组件各自干什么

先把角色分清楚,不然后面配置容易乱。

FreeRADIUS 是核心,它监听 UDP 1812(认证)和 1813(计费)端口,接收来自 NAS(网络接入设备,比如无线 AC、交换机、网关)的请求。用户连网时,NAS 把用户名密码打包成 RADIUS 请求发给 FreeRADIUS,FreeRADIUS 查数据库或者本地文件验证,返回 Accept 或 Reject。用户上线后,NAS 周期性发计费包,告诉 FreeRADIUS 这个用户用了多少流量、在线多久。

daloradius 是一套 PHP 写的 Web 界面,直接读写 FreeRADIUS 用的 MySQL 数据库。它的价值在于把"改数据库"这件事变成了"点网页",建用户、改密码、看在线、查账单、配 NAS 都在浏览器里完成。它不参与认证过程本身,只是数据库的前端。

OpenPortal 是门户页面,用户连上 WiFi 后,在没认证之前,所有 HTTP 请求会被 NAS 重定向到 OpenPortal 的页面。用户在这个页面输入账号密码,OpenPortal 把凭据提交给 FreeRADIUS 完成认证,认证通过后 NAS 放行流量。它解决的是"用户怎么知道要登录、在哪登录"的问题。

2.2 数据流走向

一次完整的认证流程是这样的:

  1. 用户设备连上无线 SSID,拿到 IP,但此时只能访问 Portal 页面。
  2. 用户打开浏览器,任意 HTTP 请求被 NAS 重定向到 OpenPortal。
  3. 用户在 Portal 输入账号密码,提交。
  4. OpenPortal 把凭据通过 RADIUS 协议发给 FreeRADIUS(或者直接调 FreeRADIUS 的认证接口)。
  5. FreeRADIUS 查 MySQL,验证通过返回 Accept,同时下发限速属性。
  6. NAS 收到 Accept,放行用户流量,并按下发的限速属性做限速。
  7. 用户下线或超时,NAS 发计费停止包,FreeRADIUS 写入数据库。

这里有个关键点:限速属性是 FreeRADIUS 在认证响应里下发给 NAS 的,不是 FreeRADIUS 自己限速。FreeRADIUS 只负责告诉 NAS "这个用户限 2M",真正限速的是 NAS 设备。所以如果你的 NAS 不支持对应的限速属性,限速就不生效。这一点很多人第一次搭会搞混,以为 FreeRADIUS 能直接限速。

2.3 为什么选 MySQL 而不是其他后端

FreeRADIUS 支持多种后端:本地文件、LDAP、MySQL、PostgreSQL 等。选 MySQL 主要因为 daloradius 默认就是对接 MySQL,两者配合开箱即用。如果选 PostgreSQL,daloradius 要改不少代码。另外 MySQL 的运维资料多,备份恢复简单,对中小规模部署足够。

规模再大一些(几万并发),可以考虑把认证缓存到内存,或者用 Redis 做会话存储,但那是后话。先把基础跑通。

3. 环境准备与依赖安装

3.1 系统基础配置

先做几件必做的事,避免后面踩坑。

关闭 SELinux。这东西在 CentOS 上默认开启,会拦 FreeRADIUS 读写数据库、拦 Apache 访问网络,报错信息还特别隐晦。生产环境如果非要开,得逐条配策略,新手直接关掉省事:

setenforce 0 sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config

配置防火墙。FreeRADIUS 用 UDP 1812/1813,daloradius 用 HTTP 80 或 443,OpenPortal 也用 HTTP。如果 NAS 和服务器不在同一网段,还要放行 NAS 过来的流量:

firewall-cmd --permanent --add-port=1812/udp firewall-cmd --permanent --add-port=1813/udp firewall-cmd --permanent --add-service=http firewall-cmd --permanent --add-service=https firewall-cmd --reload

时间同步。计费系统对时间敏感,服务器和 NAS 时间不一致会导致计费时长算错。装个 chrony 同步一下:

yum install -y chrony systemctl enable --now chronyd chronyc sources

3.2 安装 LAMP 环境

daloradius 是 PHP 应用,需要 Apache + PHP + MySQL。CentOS 7 用 yum 装:

yum install -y httpd mariadb-server mariadb php php-mysql php-gd php-curl php-mbstring php-xml systemctl enable --now httpd mariadb

CentOS 8 的话 MariaDB 换成了 mysql-server,命令略有不同。装完先跑mysql_secure_installation把 root 密码设好,删掉匿名用户和测试库。

PHP 版本要注意,daloradius 对 PHP 7.x 兼容性最好,PHP 8 有些函数废弃了会报错。CentOS 7 默认的 PHP 5.4 太老,建议装 remi 源升级到 7.4:

yum install -y epel-release yum install -y https://rpms.remirepo.net/enterprise/remi-release-7.rpm yum-config-manager --enable remi-php74 yum install -y php php-mysql php-gd php-curl php-mbstring php-xml

3.3 安装 FreeRADIUS

yum install -y freeradius freeradius-mysql freeradius-utils systemctl enable radiusd

freeradius-mysql这个包必须装,它提供 MySQL 连接模块,不装的话 FreeRADIUS 连不上数据库。freeradius-utils里有radtest工具,调试时非常有用。

装完先别急着启动,因为默认配置连的是本地文件,我们要改成连 MySQL,配置改完再启动。

4. FreeRADIUS 对接 MySQL 的完整配置

4.1 建库建表

FreeRADIUS 的数据库结构是固定的,官方提供了建表脚本。先建库:

mysql -u root -p CREATE DATABASE radius; GRANT ALL ON radius.* TO 'radius'@'localhost' IDENTIFIED BY 'StrongPass123'; FLUSH PRIVILEGES; exit;

然后导入表结构。脚本在/etc/raddb/mods-config/sql/main/mysql/schema.sql:

mysql -u root -p radius < /etc/raddb/mods-config/sql/main/mysql/schema.sql

导入后进库看看,应该有radacct、radcheck、radreply、radgroupcheck、radgroupreply、radusergroup、nas这几张核心表。简单说:

  • radcheck:存用户认证信息,比如密码。
  • radreply:存用户级别的响应属性,比如限速。
  • radgroupcheck/radgroupreply:组级别的认证和响应属性,用户加入组后继承组的配置。
  • radusergroup:用户和组的对应关系。
  • radacct:计费记录,用户每次上下线都写这里。
  • nas:NAS 设备清单,只有登记过的 NAS 才能发请求。

4.2 配置 SQL 模块

FreeRADIUS 3.x 的配置结构跟 2.x 差别很大,网上很多老教程是 2.x 的,照抄会出错。3.x 的 SQL 模块配置在/etc/raddb/mods-available/sql,启用方式是做个软链接到mods-enabled:

ln -s /etc/raddb/mods-available/sql /etc/raddb/mods-enabled/sql

编辑这个文件,改几个关键项:

driver = "rlm_sql_mysql" dialect = "mysql" server = "localhost" port = 3306 login = "radius" password = "StrongPass123" radius_db = "radius" read_clients = yes

read_clients = yes这个很重要,它让 FreeRADIUS 从nas表读 NAS 清单,而不是从clients.conf读。这样新增 NAS 直接在 daloradius 网页上加就行,不用改配置文件重启服务。

4.3 启用 SQL 认证和计费

FreeRADIUS 3.x 的站点配置在/etc/raddb/sites-available/default,这个文件同时处理认证和计费。打开它,找到authorize、accounting、session、post-auth这几个段,确保里面sql是启用的(前面没有注释)。

具体来说,authorize段里要有sql,accounting段里要有sql,session段里要有sql,post-auth段里也要有sql。这几个地方漏一个,对应功能就不生效。比如accounting里没启用 sql,计费数据就写不进数据库,daloradius 里看不到在线用户。

改完检查一下语法:

radiusd -XC

这个命令会做配置检查,输出Configuration appears to be OK才算过。有报错就按提示改,别硬启动。

4.4 启动并测试

systemctl start radiusd systemctl status radiusd

看日志确认没有报错:

tail -f /var/log/radius/radius.log

然后加一个测试用户。在数据库里插一条:

mysql -u root -p radius INSERT INTO radcheck (username, attribute, op, value) VALUES ('testuser', 'Cleartext-Password', ':=', 'testpass123');

用 radtest 测一下:

radtest testuser testpass123 localhost 0 testing123

testing123是默认的客户端密钥,在clients.conf里。如果返回Access-Accept,说明认证通了。返回Access-Reject就是密码或用户有问题,返回超时就是服务没起来或者端口没通。

注意:radtest 的最后一个参数是 NAS 的共享密钥,必须和clients.conf里 localhost 的 secret 一致,否则会被拒绝。很多人卡在这里,以为是用户密码错了。

5. daloradius 部署与汉化调优

5.1 下载与部署

daloradius 的源码在 SourceForge 上,下载后解压到 Apache 的网站目录:

cd /var/www/html wget https://sourceforge.net/projects/daloradius/files/latest/download -O daloradius.tar.gz tar -zxvf daloradius.tar.gz mv daloradius-* daloradius

设置权限,让 Apache 能读写:

chown -R apache:apache /var/www/html/daloradius chmod -R 755 /var/www/html/daloradius

5.2 导入 daloradius 表结构

daloradius 需要额外的表来存管理员、账单、操作日志等。脚本在contrib/db/mysql-daloradius.sql:

mysql -u root -p radius < /var/www/html/daloradius/contrib/db/mysql-daloradius.sql

导入后数据库里会多出operators、billing、userinfo等表。operators存管理员账号,默认有个administrator,密码是radius,第一次登录后必须改。

5.3 配置数据库连接

编辑/var/www/html/daloradius/library/daloradius.conf.php,改这几项:

$configValues['CONFIG_DB_HOST'] = 'localhost'; $configValues['CONFIG_DB_USER'] = 'radius'; $configValues['CONFIG_DB_PASS'] = 'StrongPass123'; $configValues['CONFIG_DB_NAME'] = 'radius';

这个文件是 daloradius 的核心配置,数据库连不上、界面报错,先查这里。

5.4 访问与初始设置

浏览器打开http://服务器IP/daloradius,用administrator/radius登录。进去第一件事改密码,在"Operators"菜单里改。

然后配置 NAS。在"Management" -> "NAS" 里添加你的 NAS 设备,填 IP、短名、类型、共享密钥。这个密钥要和 NAS 上配的一致,否则认证请求会被 FreeRADIUS 拒绝。添加后 FreeRADIUS 会自动从数据库读到,不用重启。

接着建用户组和用户。建议先建组,把限速策略配在组上,用户加入组就继承。比如建一个"2M带宽"组,在组的 Reply 属性里加限速属性,后面讲限速时细说。

5.5 汉化与界面优化

daloradius 默认是英文,中文用户看着累。汉化文件在lang/目录下,把en.php复制成zh.php,然后逐条翻译。工作量不小,但常用的菜单和提示翻一下就够了。

界面优化方面,daloradius 的 UI 比较老,表格在小屏幕上会溢出。可以在css/里调一下表格宽度和字体。另外建议开启 HTTPS,因为登录密码是明文传输的,用 HTTP 不安全。配个自签证书或者用 Let's Encrypt 都行。

实操心得:daloradius 的某些页面在 PHP 7.4 下会有 deprecated 警告,把php.ini里的error_reporting调成E_ALL & ~E_DEPRECATED & ~E_NOTICE,界面就干净了。生产环境别开display_errors,会暴露路径信息。

6. OpenPortal 门户对接与认证流程

6.1 OpenPortal 的定位

OpenPortal 不是 FreeRADIUS 官方组件,而是一类轻量门户程序的统称。它的作用是给未认证用户展示一个登录页,收集账号密码,然后触发认证。实现方式有两种:一种是 OpenPortal 自己作为 RADIUS 客户端,把凭据发给 FreeRADIUS;另一种是 OpenPortal 只做页面,认证由 NAS 直接跟 FreeRADIUS 交互,Portal 通过 NAS 的 API 触发。

第一种方式更通用,不依赖 NAS 的 API。下面按第一种讲。

6.2 部署与配置

OpenPortal 通常是 PHP 或 Python 写的,部署到 Apache 或 Nginx 下。核心配置是 FreeRADIUS 的地址、共享密钥、认证端口:

$radius_host = '127.0.0.1'; $radius_secret = 'testing123'; $radius_auth_port = 1812; $radius_acct_port = 1813;

用户提交表单后,OpenPortal 用 PHP 的 radius 扩展或者 socket 直接发 RADIUS 请求。用 PHP radius 扩展的话,装一下:

yum install -y php-pear pecl install radius echo "extension=radius.so" >> /etc/php.ini systemctl restart httpd

然后认证代码大概是这样:

$radius = radius_auth_open(); radius_add_server($radius, $radius_host, $radius_auth_port, $radius_secret, 5, 3); radius_create_request($radius, RADIUS_ACCESS_REQUEST); radius_put_attr($radius, RADIUS_USER_NAME, $username); radius_put_attr($radius, RADIUS_USER_PASSWORD, $password); radius_put_attr($radius, RADIUS_NAS_IP_ADDRESS, $nas_ip); $result = radius_send_request($radius); if ($result == RADIUS_ACCESS_ACCEPT) { // 认证通过 }

6.3 与 NAS 的配合

Portal 认证有个绕不开的问题:用户认证通过后,NAS 怎么知道放行?这取决于 NAS 的工作模式。

如果是"Portal 认证"模式,NAS 会把用户的 MAC 和 IP 告诉 Portal,Portal 认证通过后调 NAS 的 API 把用户加入白名单。这种模式需要 NAS 提供 API,配置起来因设备而异。

如果是"RADIUS 认证"模式,NAS 自己就是 RADIUS 客户端,Portal 只是把用户引导到 NAS 的认证接口。这种模式下 Portal 不直接跟 FreeRADIUS 交互,而是把凭据 POST 给 NAS。

实际项目里,我建议先确认 NAS 支持哪种模式,再决定 Portal 怎么写。很多坑都是模式没对齐导致的。

6.4 认证流程的完整串联

把三个组件串起来,一次认证的时序是这样的:

  1. 用户连 WiFi,NAS 拦截 HTTP,重定向到 OpenPortal。
  2. OpenPortal 展示登录页,用户输入账号密码。
  3. OpenPortal 发 RADIUS 请求给 FreeRADIUS。
  4. FreeRADIUS 查 MySQL 的radcheck,验证密码。
  5. 验证通过,FreeRADIUS 从radreply或radgroupreply读限速属性,放在 Access-Accept 里返回。
  6. OpenPortal 收到 Accept,调 NAS API 放行用户,或者告诉用户"认证成功,请重新连接"。
  7. NAS 开始计费,周期性发计费包给 FreeRADIUS。
  8. FreeRADIUS 把计费数据写入radacct。

这里第 5 步的限速属性是关键,下一节详细讲。

7. 流量控制的实现方法与参数详解

7.1 限速属性的标准与厂商差异

RADIUS 协议本身没有定义限速属性,限速是靠厂商私有属性实现的。常见的几类:

  • 标准属性:Filter-Id,值是字符串,NAS 根据这个字符串查本地策略。通用但不精确。
  • 厂商私有属性:比如某厂商的Mikrotik-Rate-Limit,值是2M/2M这种格式,直接指定上下行速率。
  • RFC 标准扩展:WISPr-Bandwidth-Max-Down和WISPr-Bandwidth-Max-Up,值是 bps,这是无线漫游联盟定义的标准,很多无线 AC 支持。

选哪个取决于你的 NAS。先查 NAS 文档,看它认哪个属性。如果不确定,用 WISPr 属性试,兼容性最好。

7.2 在 daloradius 里配置限速

限速属性配在组上最方便。在 daloradius 里进"Management" -> "Groups",新建一个组,比如叫group_2M。然后在组的 Reply 属性里加:

属性操作符值说明
WISPr-Bandwidth-Max-Down:=2097152下行 2Mbps,单位 bps
WISPr-Bandwidth-Max-Up:=1048576上行 1Mbps
Simultaneous-Use:=1同时在线数限制

注意单位是 bps,不是 KB/s。2Mbps = 2 * 1024 * 1024 = 2097152 bps。很多人填 2048 以为是 2M,结果限成了 2Kbps,用户投诉网速慢得打不开网页。

配好组后,把用户加入组。在"Users"里编辑用户,选 Group 为group_2M。用户认证时,FreeRADIUS 会把组的 Reply 属性合并到响应里下发。

7.3 按流量动态限速的思路

固定限速好做,动态限速(比如用超 1G 后降到 1M)就要动点脑筋。思路是:FreeRADIUS 在认证时查radacct里该用户本月的累计流量,超过阈值就下发低速率属性。

这需要写自定义的认证逻辑。FreeRADIUS 支持在authorize段里调用 Perl 或 Python 模块,或者用rlm_sqlcounter模块。sqlcounter是官方提供的,专门做"按流量/时长计数"的场景。

配置sqlcounter分三步:定义计数器、在authorize段引用、在radreply里配阈值。具体配置在/etc/raddb/mods-available/sqlcounter,定义一个按月流量的计数器:

sqlcounter monthly_traffic { counter-name = Monthly-Traffic check-name = Max-Monthly-Traffic sqlmod-inst = sql query = "SELECT SUM(acctinputoctets + acctoutputoctets) FROM radacct WHERE username = '%{User-Name}' AND acctstarttime > DATE_FORMAT(NOW(), '%Y-%m-01')" reset = monthly }

然后在用户的 check 属性里加Max-Monthly-Traffic = 1073741824(1G),超过后sqlcounter会返回一个属性,配合radreply里的策略做降速。

注意:sqlcounter的查询在每次认证时执行,用户量大时对数据库压力不小。建议给radacct表的username和acctstarttime建索引,能显著提升查询速度。

7.4 限速不生效的排查

限速配了但没效果,按这个顺序查:

  1. NAS 是否支持该属性。抓包看 Access-Accept 里有没有下发属性,有的话就是 NAS 不认。
  2. 属性值格式对不对。WISPr 是 bps,Mikrotik 是2M/2M,格式错了 NAS 会忽略。
  3. 用户是否真的加入了组。查radusergroup表,确认用户和组的对应关系存在。
  4. 组属性是否被用户属性覆盖。如果用户在radreply里也有同名属性,用户级的优先。
  5. NAS 的限速功能是否开启。有些设备默认不限速,要在配置里显式打开。

抓包是最直接的排查手段,在 FreeRADIUS 服务器上:

tcpdump -i any -n udp port 1812 -w radius.pcap

然后用 Wireshark 打开,看 Access-Accept 包里带了哪些属性。

8. 常见问题与排查技巧实录

8.1 认证类问题速查

现象可能原因排查方法
Access-Reject密码错、用户不存在、NAS 密钥不匹配查 radcheck 表,核对 clients 配置
无响应超时服务没起、端口没通、防火墙拦截systemctl status radiusd,telnet 测端口
认证通过但无法上网NAS 未放行、限速属性导致查 NAS 日志,抓包看响应
部分用户认证失败密码加密方式不匹配确认 radcheck 里是 Cleartext-Password 还是 MD5

8.2 计费数据不写入

用户能上网,但 daloradius 里看不到在线记录,多半是accounting段没启用 sql。检查/etc/raddb/sites-available/default的accounting段,确认sql没被注释。另外 NAS 要配置计费服务器地址和端口,有些设备默认不发计费包。

还有一种情况是radacct表写满了或者磁盘满了,MySQL 写入失败。查一下磁盘空间和表大小。

8.3 daloradius 界面报错

常见的有数据库连接失败、权限不足、PHP 扩展缺失。按提示查daloradius.conf.php的配置,确认数据库账号密码对,确认 PHP 装了 mysql、gd、mbstring 扩展。如果页面空白,看 Apache 错误日志:

tail -f /var/log/httpd/error_log

8.4 性能与稳定性经验

用户量上来后,几个优化点:

  • 给radacct表建索引,尤其是username、acctstarttime、acctstoptime。
  • 定期归档旧计费数据,radacct表太大查询会慢。
  • FreeRADIUS 开多线程,在radiusd.conf里调max_requests。
  • MySQL 调innodb_buffer_pool_size,给足内存。
  • 认证和计费分离到不同实例,减轻单点压力。

踩过的坑:有次用户反映认证时快时慢,查了半天发现是 MySQL 的radacct表没建索引,每次认证都要全表扫描。建完索引后认证时间从 800ms 降到 20ms。这个坑很隐蔽,因为功能是正常的,只是慢。

9. 我在这套系统上的一些实际体会

搭这套东西,最花时间的不是安装,而是跟 NAS 的对接。不同厂商的设备对 RADIUS 属性的支持差异很大,同一套配置换个 NAS 可能就不生效。我的习惯是先在测试环境用 radtest 把 FreeRADIUS 本身跑通,确认认证、计费、限速属性都正确,再接 NAS。这样出问题时能快速定位是 FreeRADIUS 的问题还是 NAS 的问题。

另一个体会是数据库的备份一定要做。radacct表里是用户的计费记录,丢了就是真金白银的损失。我一般配个每日定时备份,保留 30 天。备份命令很简单:

mysqldump -u root -p radius > /backup/radius_$(date +%F).sql

最后分享一个小技巧:调试阶段把 FreeRADIUS 的日志级别调到 debug,在radiusd.conf里把log { auth = yes }打开,然后radiusd -X前台运行,所有认证细节都会打印出来,比看日志文件直观得多。生产环境记得调回去,debug 日志量很大,会拖慢性能。

这套组合虽然组件多,但每个组件的职责清晰,拆开看都不复杂。真正难的是把它们串起来,以及处理各种 NAS 的兼容性问题。把上面这些配置和排查思路过一遍,基本能覆盖 80% 的场景。剩下的 20%,就得靠抓包和看日志慢慢磨了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询