Docker部署Rails 6应用:Nginx加载静态资源报404错误
生产环境Docker中Rails 6应用Nginx静态资源404问题排查与解决
生产环境下,Docker部署的Rails 6应用中Nginx加载静态资源全部返回404,但文件系统中资源确实存在,其他文件可正常加载。以下是相关配置文件及解决方案:
Dockerfile
FROM ruby:2.6.1 RUN curl https://deb.nodesource.com/setup_12.x | bash RUN curl https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list RUN apt-get update && apt-get install -y nodejs yarn WORKDIR /my_app RUN export RAILS_ENV=production RUN gem install bundler:2.2.31 COPY Gemfile Gemfile.lock ./ COPY package.json ./ COPY vendor/gems/ vendor/gems/ RUN bundle install COPY . ./ RUN yarn install --check-files RUN RAILS_ENV=production bundle exec rake assets:precompile SECRET_KEY_BASE=1 EXPOSE 3000 CMD ["RAILS_ENV=production", "bundle", "exec", "puma", "-C", "config/puma.rb"]
docker-compose.yml
version: '3' services: database: image: mysql:5.7 restart: always container_name: database environment: MYSQL_DATABASE: my_app_production MYSQL_USER: my_app MYSQL_PASSWORD: my_app_password MYSQL_RANDOM_ROOT_PASSWORD: "yes" ports: - "3306:3306" volumes: - dbdata:/var/lib/mysql my_app: image: my_app container_name: my_app volumes: - ./public:/my_app/public - ./public/assets:/my_app/public/assets - tmp:/my_app/tmp - yarn_cache:/var/www/.cache/yarn command: bash -c "sleep 5 && bundle exec rails db:migrate && bundle exec puma -C config/puma.rb" environment: RAILS_ENV: production SECRET_KEY_BASE: xxxxxxx DATABASE_PASSWORD: my_app_password ports: - "3000:3000" depends_on: - database links: - database webserver: image: nginx:latest ports: - 80:80 restart: always volumes: - ./nginx/conf/:/etc/nginx/conf.d/:ro volumes: dbdata: tmp: yarn_cache:
nginx.conf
upstream my_app { server my_app:3000; } server { server_name my.domain.name; root /my_app/public; try_files $uri/index.html $uri @rails; location ~ ^/(assets|packs)/{ try_files $uri @rails; access_log off; gzip_static on; expires max; add_header Cache-Control public; add_header Last-Modified ""; add_header ETag ""; break; } location @rails { proxy_pass http://my_app; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_set_header X-Forwarded-Proto https; proxy_redirect off; proxy_connect_timeout 4m; proxy_read_timeout 4m; proxy_send_timeout 4m; } error_page 500 502 503 504 /500.html; client_max_body_size 4G; keepalive_timeout 10; listen 80; }
问题分析与解决方案
1. Nginx容器无法访问静态资源路径
Nginx配置中root /my_app/public,但Nginx容器内不存在该路径,需将Rails应用的静态资源目录挂载到Nginx容器。修改docker-compose.yml的webserver服务:
webserver: image: nginx:latest ports: - 80:80 restart: always volumes: - ./nginx/conf/:/etc/nginx/conf.d/:ro - ./public:/my_app/public # 挂载本地public目录到Nginx容器内对应路径
2. 本地卷覆盖镜像内预编译资源
Dockerfile已完成assets:precompile,但docker-compose.yml中挂载的./public和./public/assets会覆盖镜像内的预编译资源。若本地目录为空或不一致,就会导致Nginx找不到资源。移除这两个挂载卷:
my_app: image: my_app container_name: my_app volumes: # 移除以下两行 # - ./public:/my_app/public # - ./public/assets:/my_app/public/assets - tmp:/my_app/tmp - yarn_cache:/var/www/.cache/yarn # 其余配置不变
3. Nginx静态资源处理逻辑错误
当前location ~ ^/(assets|packs)/中,找不到文件会转发给Rails,但生产环境Rails默认不处理静态资源,导致404。修改Nginx配置,让Nginx直接处理静态资源:
location ~ ^/(assets|packs)/ { try_files $uri =404; # 找不到直接返回404,不转发 access_log off; gzip_static on; expires max; add_header Cache-Control public; add_header Last-Modified ""; add_header ETag ""; }
4. 确认Rails生产环境配置
确保config/environments/production.rb中config.public_file_server.enabled = false(默认值),让Nginx全权处理静态资源,避免Rails介入。
内容的提问来源于stack exchange,提问作者Simon Mo
相关产品推荐
相关产品推荐

