502 错误网关 - Rails 应用程序、Puma、Capistrano、Nginx

502 Bad Gateway - Rails App, Puma, Capistrano, Nginx

我在尝试部署我的 rails 应用程序时遇到 'Connection Refused' 错误。这是我从 /var/log/nginx/error.log

那里得到的消息
2020/01/03 20:40:44 [error] 8059#8059: *69 connect() to unix:/var/www/blog/shared/tmp/sockets/puma.sock failed (111: Connection refused) while connecting to upstream, client: 5.189.176.208, server: localhost, request: "GET / HTTP/1.0", upstream: "http://unix:/var/www/blog/shared/tmp/sockets/puma.sock:/500.html"

在 运行 cap production deploy 之后,puma 网络服务器监听一个套接字,但是当我访问我的 Ubuntu EC2 实例的 IP 地址时,我得到一个 nginx 502 Bad Gateway留言。

我已经尝试 cap production deploy:restart 在本地机器上,在服务器上重新启动 nginx,并确保 sock 文件位置正确,但无济于事。错误日志不是很有帮助,所以我想知道如何诊断这个问题?我已经包含了一些配置文件,如果有任何提示,我将不胜感激。

puma.rb

# Puma can serve each request in a thread from an internal thread pool.
# The `threads` method setting takes two numbers: a minimum and maximum.
# Any libraries that use thread pools should be configured to match
# the maximum value specified for Puma. Default is set to 5 threads for minimum
# and maximum; this matches the default thread size of Active Record.
#
max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count }
threads min_threads_count, max_threads_count

# Specifies the `port` that Puma will listen on to receive requests; default is 3000.
#
port        ENV.fetch("PORT") { 3000 }

# Specifies the `environment` that Puma will run in.
#
environment ENV.fetch("RAILS_ENV") { "development" }

# Specifies the `pidfile` that Puma will use.
pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }

# Specifies the number of `workers` to boot in clustered mode.
# Workers are forked web server processes. If using threads and workers together
# the concurrency of the application would be max `threads` * `workers`.
# Workers do not work on JRuby or Windows (both of which do not support
# processes).
#
# workers ENV.fetch("WEB_CONCURRENCY") { 2 }

# Use the `preload_app!` method when specifying a `workers` number.
# This directive tells Puma to first boot the application and load code
# before forking the application. This takes advantage of Copy On Write
# process behavior so workers use less memory.
#
# preload_app!

# Allow puma to be restarted by `rails restart` command.
plugin :tmp_restart

deploy.rb

# config valid for current version and patch releases of Capistrano
lock "~> 3.11.2"

set :default_shell, '/bin/bash -l'
set :puma_conf, "/var/www/blog/shared/config/puma.rb"
set :application, "blog"
set :repo_url, "git@github.com:st4rgut22/blog.git"
set :linked_files, %w{config/master.key}
# Default branch is :master
# ask :branch, `git rev-parse --abbrev-ref HEAD`.chomp

# Default deploy_to directory is /var/www/my_app_name
set :deploy_to, "/var/www/blog"
set :user_sudo, true
set:branch, 'master'
set :linked_dirs, fetch(:linked_dirs, []).push('log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle', 'public/system')

set :rbenv_map_bins, %w{rake gem bundle ruby rails puma pumactl}

# Default value for :format is :airbrussh.
# set :format, :airbrussh

# You can configure the Airbrussh format using :format_options.
# These are the defaults.
# set :format_options, command_output: true, log_file: "log/capistrano.log", color: :auto, truncate: :auto

# Default value for :pty is false
# set :pty, true

# Default value for :linked_files is []
# append :linked_files, "config/database.yml"

# Default value for linked_dirs is []
# append :linked_dirs, "log", "tmp/pids", "tmp/cache", "tmp/sockets", "public/system"

# Default value for default_env is {}
# set :default_env, { path: "/opt/ruby/bin:$PATH" }

# Default value for local_user is ENV['USER']
# set :local_user, -> { `git config user.name`.chomp }

# Default value for keep_releases is 5
# set :keep_releases, 5

# Uncomment the following to require manually verifying the host key before first deploy.
# set :ssh_options, verify_host_key: :secure

/etc/nginx/sites-available/default(在部署目标上)

upstream app {
    # Path to Puma SOCK file, as defined previously
    server unix:/var/www/blog/shared/tmp/sockets/puma.sock fail_timeout=0;
}

server {
    listen 80;
    server_name localhost;

    root /var/www/blog/public;

    try_files $uri/index.html $uri @app;

    location @app {
        proxy_pass http://app;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
    }

    error_page 500 502 503 504 /500.html;
    client_max_body_size 4G;
    keepalive_timeout 10;
}

/var/www/blog/shared/config/puma.rb(在部署目标上)

# Change to match your CPU core count
workers 2

# Min and Max threads per worker
threads 1, 6

app_dir = File.expand_path("../..", __FILE__)
shared_dir = "#{app_dir}/shared"

# Default to production
rails_env = ENV['RAILS_ENV'] || "production"
environment rails_env

# Set up socket location
#bind "unix://#{shared_dir}/sockets/puma.sock"
bind "unix:/var/www/blog/shared/tmp/sockets/puma.sock"

# Logging
stdout_redirect "#{shared_dir}/log/puma.stdout.log", "#{shared_dir}/log/puma.stderr.log", true

# Set master PID and state locations
pidfile "#{shared_dir}/pids/puma.pid"
state_path "#{shared_dir}/pids/puma.state"
activate_control_app

on_worker_boot do
  require "active_record"
  ActiveRecord::Base.connection.disconnect! rescue ActiveRecord::ConnectionNotEstablished
  ActiveRecord::Base.establish_connection(YAML.load_file("#{app_dir}/config/database.yml")[rails_env])
end

/etc/nginx/nginx.conf(在部署目标上)

user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
    worker_connections 768;
    # multi_accept on;
}

http {

    ##
    # Basic Settings
    ##

    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;
    # server_tokens off;

    # server_names_hash_bucket_size 64;
    # server_name_in_redirect off;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    ##
    # SSL Settings
    ##

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
    ssl_prefer_server_ciphers on;

    ##
    # Logging Settings
    ##

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    ##
    # Gzip Settings
    ##

    gzip on;

    # gzip_vary on;
    # gzip_proxied any;
    # gzip_comp_level 6;
    # gzip_buffers 16 8k;
    # gzip_http_version 1.1;
    # gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

    ##
    # Virtual Host Configs
    ##

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}


#mail {
#   # See sample authentication script at:
#   # http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript
# 
#   # auth_http localhost/auth.php;
#   # pop3_capabilities "TOP" "USER";
#   # imap_capabilities "IMAP4rev1" "UIDPLUS";
# 
#   server {
#       listen     localhost:110;
#       protocol   pop3;
#       proxy      on;
#   }
# 
#   server {
#       listen     localhost:143;
#       protocol   imap;
#       proxy      on;
#

有两个 puma 配置文件,在第一个文件中您指定了端口而不是套接字。对生产环境有影响吗?

port        ENV.fetch("PORT") { 3000 }

请仔细检查套接字文件以及 puma 进程在部署后是否存在。

ps ax|grep puma
ls -la /var/www/blog/shared/tmp/sockets/puma.sock

如果是,请查看 puma 和应用程序的日志文件

在下方评论讨论后更新:

部署后发现没有puma进程。 puma 的日志文件也是空的。这就是为什么我们决定通过转到应用程序根路径 /var/www/blog/current 并执行

在服务器上手动尝试 运行
bundle exec puma -b /var/www/blog/shared/tmp/sockets/puma.sock

结果是 STDOUT 上显示的权限错误。因此,在我们将 /var/www/blog/shared/config/puma.rb 中的日志和 pid 文件位置固定后问题就消失了,如下所示:

stdout_redirect "/var/www/shared/logs/puma.stdout.log", "/var/www/shared/logs/puma.stderr.log", true

pidfile "/var/www/blog/shared/tmp/pids/puma.pid" 
state_path "/var/www/blog/shared/tmp/pids/puma.state"