如何配置Nginx处理带Secret的Github Webhook POST请求
Nginx 接收并验证GitHub Webhook 实现方案
现有前提与需求
- GitHub Webhook 已完成基础配置:Payload URL 为
https://myUrl/payload,预设校验密钥为thisisthesecret - 已有全局
nginx.conf基础配置如下:
user nginx; worker_processes 1; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; #tcp_nopush on; keepalive_timeout 65; #gzip on; include /etc/nginx/conf.d/*.conf; }
- 核心需求:
- 仅响应指向
/payload的POST类型GitHub Webhook请求 - 校验请求签名与预设密钥
thisisthesecret匹配 - 校验通过后返回固定响应
OK - 自动存储请求payload到本地持久化路径
- 仅响应指向
此前网络上仅找到零散参考示例,无完整可落地的实现方案。
前置依赖说明
纯Nginx原生配置无法完成HMAC-SHA256签名校验逻辑,需要使用带ngx_http_lua_module的Nginx发行版,推荐直接使用OpenResty,无需额外编译模块,开箱即用。
可落地配置实现
所有自定义站点配置放在全局nginx.conf指向的/etc/nginx/conf.d/目录下,新建webhook.conf文件,内容如下:
# 提前创建payload存储目录并给nginx运行用户权限:mkdir -p /var/www/webhook_payload && chown -R nginx:nginx /var/www/webhook_payload server { listen 80; server_name myUrl; # 替换为你的实际域名 # 允许最大1M的payload,适配GitHub Webhook常规请求大小 client_max_body_size 1m; client_body_buffer_size 1m; # 仅匹配/payload的POST请求 location = /payload { # 禁用请求体缓冲,直接读取完整内容用于校验和存储 lua_need_request_body on; default_type text/plain; # Lua逻辑实现签名校验、payload存储 access_by_lua_block { local secret = "thisisthesecret" local signature_header = ngx.var.http_x_hub_signature_256 -- 缺失签名头直接拒绝 if not signature_header then ngx.exit(ngx.HTTP_FORBIDDEN) end -- 分离签名头的算法和实际值 local algo, recv_sig = signature_header:match("(%w+)=(.+)") if not algo or algo ~= "sha256" then ngx.exit(ngx.HTTP_FORBIDDEN) end -- 计算请求体的HMAC-SHA256值 local resty_hmac = require "resty.hmac" local hmac = resty_hmac:new(secret, resty_hmac.ALGOS.SHA256) local calc_sig = hmac:final(ngx.req.get_body_data(), true) -- 签名不匹配直接拒绝 if calc_sig ~= recv_sig then ngx.exit(ngx.HTTP_FORBIDDEN) end -- 校验通过:存储payload到指定目录,文件名用时间戳+客户端IP避免重名 local file_name = ngx.var.time_iso8601:gsub("[:/]", "-") .. "_" .. ngx.var.remote_addr .. ".json" local file_path = "/var/www/webhook_payload/" .. file_name local f, err = io.open(file_path, "w") if not f then ngx.log(ngx.ERR, "存储payload失败: ", err) ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) end f:write(ngx.req.get_body_data()) f:close() -- 返回固定响应OK ngx.say("OK") } } }
生效步骤
- 先执行
nginx -t校验配置语法是否正确 - 执行
nginx -s reload重载配置生效 - 可通过GitHub Webhook的测试发送功能验证校验逻辑、payload存储是否正常
内容的提问来源于stack exchange,提问作者jrz
相关产品推荐
相关产品推荐

