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 请求发给 FreeRADIUSFreeRADIUS 查数据库或者本地文件验证返回 Accept 或 Reject。用户上线后NAS 周期性发计费包告诉 FreeRADIUS 这个用户用了多少流量、在线多久。daloradius 是一套 PHP 写的 Web 界面直接读写 FreeRADIUS 用的 MySQL 数据库。它的价值在于把改数据库这件事变成了点网页建用户、改密码、看在线、查账单、配 NAS 都在浏览器里完成。它不参与认证过程本身只是数据库的前端。OpenPortal 是门户页面用户连上 WiFi 后在没认证之前所有 HTTP 请求会被 NAS 重定向到 OpenPortal 的页面。用户在这个页面输入账号密码OpenPortal 把凭据提交给 FreeRADIUS 完成认证认证通过后 NAS 放行流量。它解决的是用户怎么知道要登录、在哪登录的问题。2.2 数据流走向一次完整的认证流程是这样的用户设备连上无线 SSID拿到 IP但此时只能访问 Portal 页面。用户打开浏览器任意 HTTP 请求被 NAS 重定向到 OpenPortal。用户在 Portal 输入账号密码提交。OpenPortal 把凭据通过 RADIUS 协议发给 FreeRADIUS或者直接调 FreeRADIUS 的认证接口。FreeRADIUS 查 MySQL验证通过返回 Accept同时下发限速属性。NAS 收到 Accept放行用户流量并按下发的限速属性做限速。用户下线或超时NAS 发计费停止包FreeRADIUS 写入数据库。这里有个关键点限速属性是 FreeRADIUS 在认证响应里下发给 NAS 的不是 FreeRADIUS 自己限速。FreeRADIUS 只负责告诉 NAS 这个用户限 2M真正限速的是 NAS 设备。所以如果你的 NAS 不支持对应的限速属性限速就不生效。这一点很多人第一次搭会搞混以为 FreeRADIUS 能直接限速。2.3 为什么选 MySQL 而不是其他后端FreeRADIUS 支持多种后端本地文件、LDAP、MySQL、PostgreSQL 等。选 MySQL 主要因为 daloradius 默认就是对接 MySQL两者配合开箱即用。如果选 PostgreSQLdaloradius 要改不少代码。另外 MySQL 的运维资料多备份恢复简单对中小规模部署足够。规模再大一些几万并发可以考虑把认证缓存到内存或者用 Redis 做会话存储但那是后话。先把基础跑通。3. 环境准备与依赖安装3.1 系统基础配置先做几件必做的事避免后面踩坑。关闭 SELinux。这东西在 CentOS 上默认开启会拦 FreeRADIUS 读写数据库、拦 Apache 访问网络报错信息还特别隐晦。生产环境如果非要开得逐条配策略新手直接关掉省事setenforce 0 sed -i s/SELINUXenforcing/SELINUXdisabled/g /etc/selinux/config配置防火墙。FreeRADIUS 用 UDP 1812/1813daloradius 用 HTTP 80 或 443OpenPortal 也用 HTTP。如果 NAS 和服务器不在同一网段还要放行 NAS 过来的流量firewall-cmd --permanent --add-port1812/udp firewall-cmd --permanent --add-port1813/udp firewall-cmd --permanent --add-servicehttp firewall-cmd --permanent --add-servicehttps firewall-cmd --reload时间同步。计费系统对时间敏感服务器和 NAS 时间不一致会导致计费时长算错。装个 chrony 同步一下yum install -y chrony systemctl enable --now chronyd chronyc sources3.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 mariadbCentOS 8 的话 MariaDB 换成了 mysql-server命令略有不同。装完先跑mysql_secure_installation把 root 密码设好删掉匿名用户和测试库。PHP 版本要注意daloradius 对 PHP 7.x 兼容性最好PHP 8 有些函数废弃了会报错。CentOS 7 默认的 PHP 5.4 太老建议装 remi 源升级到 7.4yum 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-xml3.3 安装 FreeRADIUSyum install -y freeradius freeradius-mysql freeradius-utils systemctl enable radiusdfreeradius-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 radiuslocalhost IDENTIFIED BY StrongPass123; FLUSH PRIVILEGES; exit;然后导入表结构。脚本在/etc/raddb/mods-config/sql/main/mysql/schema.sqlmysql -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计费记录用户每次上下线都写这里。nasNAS 设备清单只有登记过的 NAS 才能发请求。4.2 配置 SQL 模块FreeRADIUS 3.x 的配置结构跟 2.x 差别很大网上很多老教程是 2.x 的照抄会出错。3.x 的 SQL 模块配置在/etc/raddb/mods-available/sql启用方式是做个软链接到mods-enabledln -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 yesread_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段里要有sqlaccounting段里要有sqlsession段里要有sqlpost-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 testing123testing123是默认的客户端密钥在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/daloradius5.2 导入 daloradius 表结构daloradius 需要额外的表来存管理员、账单、操作日志等。脚本在contrib/db/mysql-daloradius.sqlmysql -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 不安全。配个自签证书或者用 Lets 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 extensionradius.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 告诉 PortalPortal 认证通过后调 NAS 的 API 把用户加入白名单。这种模式需要 NAS 提供 API配置起来因设备而异。如果是RADIUS 认证模式NAS 自己就是 RADIUS 客户端Portal 只是把用户引导到 NAS 的认证接口。这种模式下 Portal 不直接跟 FreeRADIUS 交互而是把凭据 POST 给 NAS。实际项目里我建议先确认 NAS 支持哪种模式再决定 Portal 怎么写。很多坑都是模式没对齐导致的。6.4 认证流程的完整串联把三个组件串起来一次认证的时序是这样的用户连 WiFiNAS 拦截 HTTP重定向到 OpenPortal。OpenPortal 展示登录页用户输入账号密码。OpenPortal 发 RADIUS 请求给 FreeRADIUS。FreeRADIUS 查 MySQL 的radcheck验证密码。验证通过FreeRADIUS 从radreply或radgroupreply读限速属性放在 Access-Accept 里返回。OpenPortal 收到 Accept调 NAS API 放行用户或者告诉用户认证成功请重新连接。NAS 开始计费周期性发计费包给 FreeRADIUS。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单位 bpsWISPr-Bandwidth-Max-Up:1048576上行 1MbpsSimultaneous-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 10737418241G超过后sqlcounter会返回一个属性配合radreply里的策略做降速。注意sqlcounter的查询在每次认证时执行用户量大时对数据库压力不小。建议给radacct表的username和acctstarttime建索引能显著提升查询速度。7.4 限速不生效的排查限速配了但没效果按这个顺序查NAS 是否支持该属性。抓包看 Access-Accept 里有没有下发属性有的话就是 NAS 不认。属性值格式对不对。WISPr 是 bpsMikrotik 是2M/2M格式错了 NAS 会忽略。用户是否真的加入了组。查radusergroup表确认用户和组的对应关系存在。组属性是否被用户属性覆盖。如果用户在radreply里也有同名属性用户级的优先。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 radiusdtelnet 测端口认证通过但无法上网NAS 未放行、限速属性导致查 NAS 日志抓包看响应部分用户认证失败密码加密方式不匹配确认 radcheck 里是 Cleartext-Password 还是 MD58.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_log8.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%就得靠抓包和看日志慢慢磨了。