🚀 Nginx Proxy Manager集成Cloudflare Turnstile全攻略
虽然NPM不原生支持Turnstile验证,但通过 自定义代码注入 + 访问控制规则 的组合方案,可实现无缝集成。以下是详细步骤:
一、基础环境准备
-
启用NPM高级模式
- 登录NPM面板 → 点击右上角「齿轮」图标 → 勾选「Enable Advanced Configuration」
-
安装Lua支持(关键步骤)
在宿主机执行:# 进入NPM容器 docker exec -it nginx-proxy-manager bash # 安装LuaJIT及依赖 apt update && apt install -y libluajit-5.1-2 lua-cjson # 验证模块加载 nginx -V 2>&1 | grep -o with-http_lua_module # 应输出"with-http_lua_module"
二、分场景配置方案
场景1:保护登录页面(/admin)
-
创建代理主机
- 域名:
admin.yourdomain.com
- 目标URL:Halo后台地址(如
http://halo:8090/admin
)
- 域名:
-
添加高级配置
在「Advanced」标签页填入:location / { access_by_lua_block { local http = require "resty.http" local cjson = require "cjson" -- 仅验证POST请求 if ngx.req.get_method() == "POST" then ngx.req.read_body() local args = ngx.req.get_post_args() local token = args.cf_turnstile_token if not token then ngx.exit(ngx.HTTP_FORBIDDEN) end local httpc = http.new() local res, err = httpc:request_uri("https://challenges.cloudflare.com/turnstile/v0/siteverify", { method = "POST", body = "secret=YOUR_SECRET_KEY&response="..token, headers = {["Content-Type"] = "application/x-www-form-urlencoded"} }) if not res or res.status ~= 200 then ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) end local data = cjson.decode(res.body) if not data.success then ngx.exit(ngx.HTTP_FORBIDDEN) end end } proxy_pass http://halo_backend; }
场景2:保护评论提交接口(/api/comments)
-
创建访问控制规则
- 路径:
/api/comments
- 策略:
Custom
- 路径:
-
注入验证脚本
set $turnstile_sitekey "YOUR_SITE_KEY"; location /api/comments { access_by_lua_file /app/lua/turnstile_verify.lua; proxy_pass http://halo_backend; }
创建
/app/lua/turnstile_verify.lua
:ngx.header.Content_Type = "application/json" local token = ngx.req.get_headers()["X-Turnstile-Token"] if not token then ngx.status = ngx.HTTP_FORBIDDEN ngx.say('{"error":"missing_token"}') return ngx.exit(ngx.HTTP_FORBIDDEN) end -- 后续验证逻辑与场景1相同
三、前端适配方案
方法A:修改Halo主题
- 在评论表单中添加:
<div class="cf-turnstile" data-sitekey="YOUR_SITE_KEY" data-callback="onVerify"></div> <script> function onVerify(token) { document.getElementById('comment-form').appendChild( Object.assign(document.createElement('input'), { type: 'hidden', name: 'cf_turnstile_token', value: token }) ); } </script>
方法B:通过NPM插入全局脚本
- 在NPM的「Custom Locations」中添加:
Location: /* Content: <script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
四、性能优化配置
-
启用缓存
在NPM容器的/etc/nginx/nginx.conf
中添加:lua_shared_dict turnstile_cache 10m;
-
调整超时时间
修改高级配置:proxy_read_timeout 300s; lua_socket_connect_timeout 5s; lua_socket_send_timeout 5s; lua_socket_read_timeout 5s;
五、监控与调试
-
实时日志查看
docker logs -f nginx-proxy-manager --tail 100 | grep 'turnstile'
-
生成验证统计报表
使用GoAccess分析:docker run --rm -it -v /path/to/access.log:/logs/log.goaccess goaccess/goaccess \ -f /logs/log.goaccess \ --log-format='%h %^[%d:%t %^] "%r" %s %b "%R" "%u"' \ --date-format=%d/%b/%Y \ --time-format=%T
⚠️ 注意事项
- 修改容器内配置后需重启NPM:
docker restart nginx-proxy-manager
- 每次NPM面板升级可能覆盖自定义配置,建议备份
/data/nginx/custom
目录 - 遇到Lua模块加载失败时,检查容器内
/etc/nginx/nginx.conf
是否包含load_module modules/ndk_http_module.so;
📌 替代方案:若不愿修改容器,可:
- 在Cloudflare设置页面规则,对特定路径启用Turnstile
- 使用Cloudflare Workers作为前置验证层