资讯动态

Puma 与 Nginx 反向代理配置实战:从 Unix Socket upstream 到静态文件缓存

发布时间:2026/9/27 23:35:26 来源:尧图企业网站定制
后端网络【免费下载链接】pumaA Ruby/Rack web server built for parallelism项目地址https://gitcode.com/gh_mirrors/pu/puma点击查看免费下载Puma 作为 Ruby/Rack 服务器通常部署在 Nginx 之后由 Nginx 承担 80/443 端口监听、静态文件服务与反向代理职责。本文基于仓库中的 docs/nginx.md 官方配置示例逐段拆解一套经典且可直接复用的 Nginx 配置从unix://socket upstream、keepalive 超时调优到 Rack 页面缓存重写、维护页切换与错误页兜底并结合 lib/puma/dsl.rb 等源码说明 Puma 侧如何与之对齐帮助读者完整掌握“Nginx Puma”生产级部署方案。一、整体架构Nginx 在前Puma upstream 在后典型的生产部署形态是Nginx 监听公网 80 端口并持有静态文件目录/myapp/public所有未命中静态资源的动态请求被proxy_pass转发到 Puma upstream。Puma 默认监听 TCP 端口如tcp://0.0.0.0:9292但官方示例推荐使用Unix socketunix:///myapp/tmp/puma.sock作为 upstream因为仅限本机进程间通信无需经过网卡与 TCP 协议栈延迟更低不存在暴露 TCP 端口带来的防火墙/暴露面问题Nginx 与 Puma 同机部署时是最常规、性能最优的组合方式。仓库源码对 Unix socket 提供了完整支持lib/puma/dsl.rb 中的bind方法明确声明只接受tcp://、unix://、ssl://三种协议并支持通过 URL query 参数配置 socket 的backlog默认 1024与umasksocket 权限。测试用例 test/test_unix_socket.rb 也验证了通过UNIXSocket直接向 Unix socket 发起 HTTP 请求的完整链路。二、Puma 侧准备绑定 Unix socket要让上文架构成立首先需要让 Puma 监听在 Unix socket 上。在 Puma 配置文件中例如config/puma.rb写入# config/puma.rb # 绑定 Unix socket路径必须与 nginx 的 upstream server 一致 bind unix:///myapp/tmp/puma.sock # 可选通过 query 参数调整 socket 行为 # bind unix:///myapp/tmp/puma.sock?backlog512 # 设置 socket 队列深度默认 1024 # bind unix:///myapp/tmp/puma.sock?umask0111 # 限制 socket 文件权限 # 生产环境常用补充配置 environment production threads 5, 5 # 每进程线程数官方建议 5见 deployment 文档 workers 4 # 进程数建议与 CPU 核数匹配 pidfile /myapp/tmp/puma.pid state_path /myapp/tmp/puma.state对应源码细节lib/puma/dsl.rbdef bind(url) options[:binds] || [] options[:binds] url endbind可被多次调用且不会互相覆盖因此 Puma 可以同时绑定 Unix socket 与 TCP 端口。workers传入:auto时需concurrent-rubygem会依据Concurrent.available_processor_count自动匹配机器 CPU 核数lib/puma/dsl.rbthreads min, max会校验 min ≤ max 且 max ≥ 1lib/puma/dsl.rb。需要特别注意Puma 必须先于 Nginx 启动并成功创建 socket 文件否则 Nginx 的upstream会因找不到 socket 而报connect() to unix://... failed。建议由 systemd 等进程管理器保证 Puma 常驻参见 docs/systemd.md 与 docs/deployment.md 中关于进程监控的论述。三、Nginx 完整配置示例官方原文以下是 docs/nginx.md 提供的完整示例是一个常见的 upstream 部署模板源自社区 Capistrano 部署经验upstream myapp { server unix:///myapp/tmp/puma.sock; } server { listen 80; server_name myapp.com; # ~2 seconds is often enough for most folks to parse HTML/CSS and # retrieve needed images/icons/frames, connections are cheap in # nginx so increasing this is generally safe... keepalive_timeout 5; # path for static files root /myapp/public; access_log /myapp/log/nginx.access.log; error_log /myapp/log/nginx.error.log info; # this rewrites all the requests to the maintenance.html # page if it exists in the doc root. This is for capistranos # disable web task if (-f $document_root/maintenance.html) { rewrite ^(.*)$ /maintenance.html last; break; } location / { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $host; # If the file exists as a static file serve it directly without # running all the other rewrite tests on it if (-f $request_filename) { break; } # check for index.html for directory index # if its there on the filesystem then rewrite # the url to add /index.html to the end of it # and then break to send it to the next config rules. if (-f $request_filename/index.html) { rewrite (.*) $1/index.html break; } # this is the meat of the rack page caching config # it adds .html to the end of the url and then checks # the filesystem for that file. If it exists, then we # rewrite the url to have explicit .html on the end # and then send it on its way to the next config rule. # if there is no file on the fs then it sets all the # necessary headers and proxies to our upstream pumas if (-f $request_filename.html) { rewrite (.*) $1.html break; } if (!-f $request_filename) { proxy_pass http://myapp; break; } } # Now this supposedly should work as it gets the filenames with querystrings that Rails provides. # BUT theres a chance it could break the ajax calls. location ~* \.(ico|css|gif|jpe?g|png|js)(\?[0-9])?$ { expires max; break; } # Error pages # error_page 500 502 503 504 /500.html; location /500.html { root /myapp/current/public; } }下文逐段解释每部分的作用与调优要点。四、upstream 与 keepalive_timeoutupstream myapp { server unix:///myapp/tmp/puma.sock; } server { ... keepalive_timeout 5; ... }upstream myapp定义了一个名为myapp的上游服务器组成员是本机 Puma 的 Unix socket。若想扩展为多实例负载均衡可在其中追加多个server条目。keepalive_timeout 5控制 Nginx 与客户端之间空闲连接的超时时间。官方注释指出约 2 秒通常足够客户端解析 HTML/CSS 并获取所需的图片/图标/框架资源由于 Nginx 连接开销很低适当调大这个值一般是安全的。这里需要把“Nginx ↔ 客户端”与“Nginx ↔ Puma”两条 keepalive 链路区分开keepalive_timeout只作用于前者而 Nginx 到 Puma upstream 的连接池化还需要在upstream块内使用keepalive指令例如upstream myapp { server unix:///myapp/tmp/puma.sock; keepalive 32; # 复用 Nginx 到 Puma 的空闲连接 }Puma 侧对 keepaliveHTTP 持久连接的支持是内置的默认persistent_timeout为 65 秒见 lib/puma/dsl.rb 附近源码注释即客户端空闲连接在 65 秒内可被复用。仓库 docs/7.0-Upgrade.md 也特别提到 Puma 7 对 keepalive 重流量场景的尾延迟tail latency做了专门优化因此长连接部署在 Puma 上是受到官方重视与支持的场景。五、静态文件服务与 Rack 页面缓存# path for static files root /myapp/public; ... location / { ... # 静态文件存在则直接返回不再执行后续 rewrite if (-f $request_filename) { break; } # 目录索引存在 index.html 则重写 URL 追加 /index.html if (-f $request_filename/index.html) { rewrite (.*) $1/index.html break; } # Rack 页面缓存把 URL 加上 .html 后缀再检查文件系统 if (-f $request_filename.html) { rewrite (.*) $1.html break; } # 文件系统上不存在对应文件则带齐转发头交给上游 Puma if (!-f $request_filename) { proxy_pass http://myapp; break; } }这是整套配置中最核心的逻辑它实现了一个完整的**“静态优先、动态兜底”**请求处理流程root /myapp/public声明静态文件根目录动态应用产出的 assets 均发布于此请求路径对应的文件真实存在时-f $request_filenameNginx 直接以静态文件响应不会进入 Ruby 应用从而显著减轻 Puma 负载请求路径对应目录下的index.html存在时重写为目录索引文件Rack 页面缓存page caching如果磁盘上存在$request_filename.html例如请求/articles/1时存在/myapp/public/articles/1.html则重写 URL 直接返回缓存的 HTML。这是不少 Rails/Rack 应用常用的全页缓存策略由 Nginx 在应用层之前完成命中判断Puma 完全不必参与以上条件全部不满足时才通过proxy_pass http://myapp把请求转发给 Puma。需要注意的是location /内的if指令在 Nginx 中属于“rewrite 阶段”指令其执行时机先于内容处理阶段因此这套写法在官方示例中成立同时官方注释也提醒若追加带 querystring 的静态文件规则见下文有可能影响 Ajax 请求改造时需要充分测试。六、带版本号的静态资源与长缓存location ~* \.(ico|css|gif|jpe?g|png|js)(\?[0-9])?$ { expires max; break; }该正则 location 匹配常见的图片、CSS、JS 静态资源并允许 URL 后跟形如?1234567890的数字版本号Rails 的 asset pipeline 即采用这种指纹/版本号策略。expires max让浏览器对这些资源做最大时长缓存——由于版本号变化时 URL 也随之变化缓存失效由文件名版本号自动驱动无需手动清缓存。官方注释再次提醒这条规则与 Ajax 调用存在潜在冲突风险引入前应验证前端请求模式。七、维护页maintenance.html切换# this rewrites all the requests to the maintenance.html # page if it exists in the doc root. This is for capistranos # disable web task if (-f $document_root/maintenance.html) { rewrite ^(.*)$ /maintenance.html last; break; }这是配合 Capistranodisable web任务实现的维护模式方案只要在文档根目录放置maintenance.html文件所有请求都会被重写并返回该静态维护页应用进入只读的维护状态删除该文件即自动恢复服务。这种“以文件存在与否作为开关”的做法无需改动 Nginx 配置、无需 reload非常适合部署脚本触发。八、错误页兜底# Error pages # error_page 500 502 503 504 /500.html; location /500.html { root /myapp/current/public; }当 Puma 返回 5xx 错误时如 502 Bad Gateway、503 不可用error_page指令可让 Nginx 返回统一的自定义错误页/500.html。示例中该页面放在/myapp/current/publicCapistrano 部署中的 current 目录。location /500.html的精确匹配保证该 location 只处理这一个路径且其root覆盖外层root指向的目录。需注意示例将该指令注释掉读者可自行按需开启并确保错误页文件真实存在于对应目录。九、传递客户端信息X-Forwarded-For 与 Puma 侧的配合proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $host;X-Forwarded-For记录了原始客户端 IP$proxy_add_x_forwarded_for会自动追加当前连接的对端地址使后端应用能够识别真实访客 IP 而不是 Nginx 本机地址Host $host保持原始 Host 头供 Rails/Rack 应用做基于 host 的路由或 URL 生成。Puma 源码对这些转发头有完整的消费逻辑lib/puma/commonlogger.rb 的访问日志输出优先使用env[HTTP_X_FORWARDED_FOR]其次才是env[REMOTE_ADDR]与 lib/puma/error_logger.rb 的错误日志行为一致——也就是说只要 Nginx 正确设置了X-Forwarded-ForPuma 日志中的客户端地址就是真实访客 IPlib/puma/client_env.rb 在处理请求环境变量时对REMOTE_ADDR的赋值逻辑明确考虑了存在反代proxy的场景源码注释中直接点明应区分“由代理设置、而非客户端伪造”的头部如X-Forwarded-For。此外如果应用只通过 HTTPS 对外提供服务应把proxy_set_header X-Forwarded-Proto $scheme;一并加入并在 Puma 配置中开启相应选项确保env[rack.url_scheme]正确为https可参见 lib/puma/dsl.rb 附近关于X-Forwarded-Proto的注释说明。十、利用 X-Request-Start 头测量请求排队时间deployment.md 提供了一个与本文配置直接配套的生产观测技巧通过让 Nginx 记录它收到请求的精确时间戳从而量化请求在 Nginx → Puma 之间的排队等待时长。在 Nginx 侧添加proxy_set_header X-Request-Start ${msec};然后在 Rack 中间件中计算当前时间与X-Request-Start的差值即可得到请求自进入 Nginx 到被 Puma 线程处理之间的排队时间。该文档还提示可以进一步扣除慢客户端等待时间env[puma.request_body_wait]记录了 Puma 等待客户端发送请求体的毫秒数减去它可以得到更精确的“Puma 线程占用”时间。十一、与容量规划、部署规范的衔接最后这套 Nginx 配置落地的效果取决于 Puma 进程/线程规模的合理性docs/deployment.md 给出如下与 upstream 架构配套的要点single mode 与 cluster modeworkers 0为单进程模式适合 JRuby、TruffleRuby 或单核 MRI 环境workers 0进入 cluster mode多核机器应使用 cluster mode 以充分利用 CPUworker 与 CPU 核数建议 CPU 核与 worker 比例约 1:1workers :auto会自动按可用核数设置需concurrent-rubygemthreads 默认 5除非应用属于重 I/O 场景50% 时间等待 IO否则使用默认线程数即可盲目调高线程会增加延迟与内存占用常见起步规格约 80% 的 Puma 应用最终会选择“4 workers × 5 threads、4 vCPU、8GB 内存”的 pod 规模内存上限一般不建议低于单进程 2GB重启与进程管理Puma 5.0 起移除了 daemonize 能力官方明确建议用 systemd、runit 等进程监控器守护 Puma详见 docs/systemd.md无停机重启的机制见 docs/restart.md。十二、完整落地清单综合全文从零搭建“Nginx Puma”生产环境时可按下述顺序检查Puma 侧在配置文件中bind unix:///myapp/tmp/puma.sock并按机器规模设置workers与threads确保 socket 路径与 Nginx 一致目录存在且对运行用户可写启动顺序先启动 Puma可由 systemd 托管确认 socket 文件已生成再启动/重载 NginxNginx 侧将 docs/nginx.md 示例中myapp、server_name、root、日志与 socket 路径替换为实际值按需开启error_page、静态资源正则 location 与 upstreamkeepalive验证转发头在 Rack 应用中确认X-Forwarded-For、Host及 HTTPS 场景的X-Forwarded-Proto正确透传Puma 访问日志显示真实客户端 IP压测与观测参考 docs/deployment.md 的X-Request-Start方案测量排队时间结合 CPU/内存占用调整 worker 与线程数避免进程长期满负荷或长期空闲。完成以上步骤即得到一个“Nginx 静态资源缓存 Puma Unix socket 动态处理”的标准生产部署可直接套用到 Capistrano 或 systemd 部署体系中。赞分享后端网络【免费下载链接】pumaA Ruby/Rack web server built for parallelism项目地址https://gitcode.com/gh_mirrors/pu/puma点击查看免费下载相关推荐JeeSite Nginx配置反向代理与缓存JeeSite Nginx配置反向代理与缓存 前言为什么需要Nginx配置 在企业级应用部署中前端静态资源的性能优化至关重要。JeeSite Vue3前前端企业应用CMSflutter_tts完全指南跨平台文本转语音插件的终极入门教程flutter_tts完全指南跨平台文本转语音插件的终极入门教程 flutter_tts是一个功能强大的Flutter文本转语音插件能够帮助开发者快速实现跨语音音频移动开发Nginx 配置实战速查手册从虚拟主机、反向代理到缓存与安全加固Nginx 配置实战速查手册从虚拟主机、反向代理到缓存与安全加固 本指南以开源仓库 reference https://link.gitcode.com/i/文档教程知识库上一篇Dopamine 从像素输入训练 SAC基于 dm_control 图像观测的 Soft Actor-Critic 实战指南下一篇GLM-4.5 API接口调用完全指南从curl测试到应用集成创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑