作为运维/开发同学,你是否遇到过需要精准统计域名访问数据的需求?比如统计 www.mnxz.fun、blog.mnxz.fun 这类域名的今日访问量、总访问量,原生Nginx又搞不定Lua相关的高级玩法?今天就手把手教你基于CentOS系统,用OpenResty(Nginx+Lua生态)实现这一需求,避开手动编译的各种坑,全程可复制!
一、需求背景
我们需要实现:
✅ 统计指定域名(www.mnxz.fun/blog.mnxz.fun)的访问记录;
✅ 区分「今日访问量」和「总访问量」,数据持久化不丢失;
✅ 基于Nginx+Lua实现,轻量化、高并发不卡顿。
避坑提醒 :原生Nginx不带Lua模块,手动编译易遇到版本兼容、resty.core 缺失等问题,优先选择OpenResty(官方集成Lua生态,开箱即用)。
二、核心方案:用OpenResty替换原生Nginx
OpenResty是Nginx的增强版,内置了完整的Lua模块和resty核心库,完美解决手动编译的版本兼容坑,这也是我们踩过多次坑后总结的最优方案!
步骤1:环境准备(CentOS系统)
bash
# 1. 检查系统环境(确认CentOS版本,适配依赖)
cat /etc/redhat-release
# 2. 安装基础依赖
yum install -y wget gcc gcc-c++ make zlib-devel pcre-devel openssl-devel
步骤2:安装OpenResty(替换原生Nginx)
如果你的服务器已装过原生Nginx(路径/usr/local/nginx),先备份再替换:
bash
# 1. 停止原生Nginx,避免端口冲突
/usr/local/nginx/sbin/nginx -s stop
ps -ef | grep nginx | grep -v grep | awk '{print $2}' | xargs kill -9 2>/dev/null
# 2. 备份原生Nginx配置(防止丢失)
mv /usr/local/nginx /usr/local/nginx_legacy
# 3. 添加OpenResty官方源
wget https://openresty.org/package/centos/openresty.repo -O /etc/yum.repos.d/openresty.repo
yum clean all && yum makecache
# 4. 安装OpenResty(自带Lua模块,无需手动编译)
yum install -y openresty
# 5. 创建软链接,复用原有路径习惯
ln -s /usr/local/openresty/nginx /usr/local/nginx
步骤3:安装Redis(数据持久化必备)
统计数据需要持久化,避免Nginx重启丢失,Redis是最优选择:
bash
# 1. 安装Redis
yum install -y redis
# 2. 启动Redis并设置开机自启
systemctl start redis
systemctl enable redis
# 3. 验证Redis(返回PONG即正常)
redis-cli ping
步骤4:核心配置(Lua统计访问日志)
编辑Nginx主配置文件 /usr/local/nginx/conf/nginx.conf,替换http块内的server节点:
nginx
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
# Lua共享字典(减轻Redis压力)
lua_shared_dict traffic_stats 10m;
# 定义获取今日日期的Lua函数
init_by_lua_block {
function get_today_date()
return os.date("%Y%m%d")
end
}
server {
listen 80;
server_name www.mnxz.fun blog.mnxz.fun;
# 核心:访问统计逻辑(所有请求触发)
access_by_lua_block {
-- 1. 获取当前访问域名,仅统计目标域名
local domain = ngx.var.server_name
local target_domains = {["www.mnxz.fun"]=true, ["blog.mnxz.fun"]=true}
if not target_domains[domain] then return end
-- 2. 定义Redis键名(区分今日/总访问量)
local today = get_today_date()
local total_key = "traffic:total:" .. domain
local today_key = "traffic:today:" .. domain .. ":" .. today
-- 3. 连接Redis(超时1秒,失败不影响业务)
local redis = require "resty.redis"
local red = redis:new()
red:set_timeout(1000)
local ok, err = red:connect("127.0.0.1", 6379)
if not ok then
ngx.log(ngx.WARN, "Redis连接失败: ", err)
return
end
-- 4. 原子自增统计(高并发不丢数)
red:incr(total_key) -- 总访问量+1
red:incr(today_key) -- 今日访问量+1
red:expire(today_key, 86400*2) -- 今日数据保留2天
-- 5. 复用Redis连接(提升性能)
red:set_keepalive(10000, 100)
-- 日志记录(方便排查)
ngx.log(ngx.INFO, "【访问统计】域名:", domain, " 今日Key:", today_key)
}
# 静态文件根目录(替换为你的实际路径)
root /usr/local/nginx/html;
index index.html index.htm;
# 【实用】本地查看统计数据的接口(仅允许服务器本地访问)
location = /get_traffic_stats {
allow 127.0.0.1;
deny all;
default_type application/json;
content_by_lua_block {
local redis = require "resty.redis"
local red = redis:new()
red:set_timeout(1000)
local ok, err = red:connect("127.0.0.1", 6379)
if not ok then
ngx.say('{"code":500,"msg":"Redis连接失败:'..err..'"}')
return
end
local today = get_today_date()
local result = {}
local domains = {"www.mnxz.fun", "blog.mnxz.fun"}
for _, domain in ipairs(domains) do
local total = red:get("traffic:total:" .. domain) or 0
local today_count = red:get("traffic:today:" .. domain .. ":" .. today) or 0
result[domain] = {
total = tonumber(total),
today = tonumber(today_count)
}
end
-- 输出JSON格式统计结果
ngx.say(require("cjson").encode({
code = 200,
data = result,
date = today
}))
red:set_keepalive(10000, 100)
}
}
# 错误页面配置
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
步骤5:启动并验证效果
bash
# 1. 检查配置语法(无报错即正常)
/usr/local/nginx/sbin/nginx -t
# 2. 启动OpenResty
/usr/local/nginx/sbin/nginx
# 3. 模拟访问,触发统计
curl http://www.mnxz.fun
curl http://blog.mnxz.fun
# 4. 本地查看统计结果(仅服务器内执行)
curl http://127.0.0.1/get_traffic_stats
预期输出(JSON格式,数据实时更新):
json
{
"code":200,
"data":{
"www.mnxz.fun":{"total":1,"today":1},
"blog.mnxz.fun":{"total":1,"today":1}
},
"date":"20260209"
}
步骤6:查看访问日志
bash
# 查看Lua统计日志(关键信息)
tail -f /usr/local/nginx/logs/error.log
# 查看常规访问日志
tail -f /usr/local/nginx/logs/access.log
三、避坑指南(踩过的坑全告诉你)
- 报错:unknown directive "access_by_lua_block"
→ 原因:用了原生Nginx而非OpenResty;解决方案:按步骤替换为OpenResty即可。 - 报错:failed to load the 'resty.core' module
→ 原因:手动编译的Lua模块版本过低;解决方案:放弃手动编译,直接用OpenResty(自带兼容版本)。 - 报错:open() "/usr/local/nginx/logs/nginx.pid" failed
→ 原因:logs目录缺失/权限不足;解决方案:mkdir -p /usr/local/nginx/logs && chmod 755 /usr/local/nginx/logs。
四、拓展与总结
1. 功能拓展
- 按小时统计:修改Redis键名为
traffic:hour:www.mnxz.fun:2026020919(拼接小时); - 按页面统计:新增
local uri = ngx.var.uri,将uri加入Redis键名; - 数据可视化:结合Grafana+Redis,制作访问量仪表盘。
2. 核心总结
✅ 优先选OpenResty:避免手动编译Lua模块的版本兼容坑,开箱即用;
✅ 数据持久化:用Redis的incr原子操作,高并发下统计不丢数;
✅ 轻量化:基于Nginx+Lua实现,无需额外部署应用,性能拉满。