Rails 5.2+Docker+Nginx环境下Passenger转Puma后静态资源加载失败
问题描述
我在Rails 5.2项目中尝试从Passenger迁移至Puma,项目采用Docker部署,通过Nginx实现HTTP转HTTPS并将请求转发至Rails容器。此前用Passenger时架构运行正常,换成Puma后,Nginx与Puma能正常通信,动态内容加载正常,但所有静态资源都无法访问,始终返回301永久重定向。我不想开启Rails静态资源服务(出于性能考虑),且相同配置在Passenger环境下能正常运行。
wget测试静态资源结果
wget http://myserver.de/assets/application-606786f053f1b452d1089f9f5e4741add1d55c6d89223168b844dd9f21740aee.css URL transformed to HTTPS due to an HSTS policy --2024-07-08 16:21:27-- https://myserver.de/assets/application-606786f053f1b452d1089f9f5e4741add1d55c6d89223168b844dd9f21740aee.css Auflösen des Hostnamens myserver.de (myserver.de)… xxx.xxx.xxx.xxx Verbindungsaufbau zu myserver.de (myserver.de)|xxx.xxx.xxx.xxx|:443 … verbunden. HTTP-Anforderung gesendet, auf Antwort wird gewartet … 301 Moved Permanently Platz: https://myserver.de/404.html [folgend] --2024-07-08 16:21:27-- https://myserver.de/404.html Wiederverwendung der bestehenden Verbindung zu myserver.de:443. HTTP-Anforderung gesendet, auf Antwort wird gewartet … 301 Moved Permanently Platz: https://myserver.de/404.html [folgend] --2024-07-08 16:21:27-- https://myserver.de/404.html Wiederverwendung der bestehenden Verbindung zu myserver.de:443. HTTP-Anforderung gesendet, auf Antwort wird gewartet … 301 Moved Permanently ...
德语内容翻译
- Auflösen des Hostnamens = 解析主机名
- Verbindungsaufbau zu = 连接至
- HTTP-Anforderung gesendet, auf Antwort wird gewartet = 已发送HTTP请求,等待响应
- Wiederverwendung der bestehenden Verbindung zu = 复用与...的现有连接
补充配置文件
Nginx 配置
# NGINX config: server { listen 80; listen [::]:80; server_name mydomain.de; access_log /var/log/nginx/my.access.log main; error_log /var/log/nginx/my.error_log warn; proxy_connect_timeout 900; proxy_send_timeout 900; proxy_read_timeout 900; send_timeout 900; # for issuing certificates # #location ~ /.well-known/acme-challenge/ { # root /var/www/certbot; #} location / { return 301 https://$host$request_uri; # proxy_pass http://app:3000/; } # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } } server { listen 443 ssl; http2 on; ssl_certificate /etc/letsencrypt/live/mydomain.de/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/mydomain.de/privkey.pem; server_name mydomain.de; root /var/www/html; index index.html; client_max_body_size 20M; access_log /var/log/nginx/my.access.log main; error_log /var/log/nginx/my.error_log warn; proxy_connect_timeout 900; proxy_send_timeout 900; proxy_read_timeout 900; send_timeout 900; # for re-issuing certificates # location ~ /.well-known/acme-challenge/ { root /var/www/certbot; } location / { proxy_pass https://app_net:3001/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Host $server_name; } # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } }
Docker Compose 配置
# DOCKER-COMPOSE.yml services: proxy: image: nginx container_name: nginx_proxy restart: unless-stopped networks: mynetwork: ipv4_address: 192.168.80.10 ports: - "80:80" - "443:443" volumes: - /root/volumes/nginx/conf:/etc/nginx/conf.d:ro - /root/volumes/nginx/certbot/conf:/etc/letsencrypt - /root/volumes/nginx/certbot/www:/var/www/certbot app: image: myrepo/myapp depends_on: - db container_name: app restart: always volumes: source: /root/volumes/nginx/certbot/conf target: /myhomedir/config/certs environment: ...
Docker 入口脚本
# DOCKER_ENTRYPOINT.sh #! /usr/bin/env bash cron crontab /etc/cron.d/my_crontab touch ./log/cron.log sleep 5 && bundle exec rake db:migrate bundle exec rake tmp:clear bundle exec puma -b 'ssl://0.0.0.0:3001?key=/myhomedir/config/certs/live/mydomain.de/privkey.pem&cert=/myhomedir/config/certs/live/mydomain.de/fullchain.pem'
问题分析与解决方案
核心问题
- Nginx未配置静态资源直接处理:当前Nginx把所有请求(包括
/assets/路径)都转发给了Puma,但Puma默认不会处理静态资源(除非开启Rails静态服务),导致请求找不到资源后触发301重定向到404页面,进而陷入循环重定向。 - Passenger与Puma的差异:Passenger默认会自动处理Rails的静态资源请求,而Puma不会,这就是之前Passenger正常、Puma出问题的关键原因。
解决方案
修改Nginx的HTTPS server配置,添加专门处理/assets/路径的规则,直接从Rails编译后的静态资源目录读取文件:
步骤1:确认Rails静态资源目录
在Docker的Rails容器中,静态资源编译后默认存放在/myhomedir/public/assets/(假设你的Rails项目根目录是/myhomedir)。
步骤2:修改Nginx配置
在HTTPS的server块中,添加以下location /assets/规则,放在location /之前:
location /assets/ { # 方法1:直接挂载Rails的public目录到Nginx(推荐) root /path/to/rails/public; # 需在Docker Compose中给Nginx添加对应volume # 方法2:如果静态资源已预编译并复制到Nginx容器的/var/www/html/assets,可直接用: # root /var/www/html; expires 1y; add_header Cache-Control public; add_header ETag ""; break; }
步骤3:调整Docker Compose配置
给Nginx服务添加volume,挂载Rails容器的public目录(或者预编译后的静态资源目录):
proxy: # ... 其他配置不变 volumes: # ... 现有volume - /root/volumes/rails/public:/path/to/rails/public:ro # 替换为实际路径
步骤4:验证配置
重启Nginx和Rails容器,再次用wget测试静态资源URL,确认返回200状态码。
额外排查点
- 检查Rails是否已执行
rails assets:precompile,确保public/assets目录下有编译后的静态文件。 - 确认Nginx容器中挂载的静态资源目录权限正确,Nginx进程能读取文件。
- 检查Puma启动命令是否正确,确保没有额外的重定向配置。
内容的提问来源于stack exchange,提问作者MDickten
相关产品推荐
相关产品推荐

