Rails app on Ubuntu production server under RVM + puma service + NginX + letsencrypt cert
Rails
NginX
Puma
ruby
Ubuntu
Idea is to run Rails 7 (Rails 8) app under Ruby installed via RVM (so it's easy to upgrade Ruby versions), where Puma is systemctl service (so it can start on system reboot) and NginX is infront of Puma while SSL certificates are for free auto updated with Let's encrypt
Prerequisites :
- Install RVM - Ubuntu steps
- install NginX
- Install certbot (Let's encrypt ubuntu daemon that auto updates certs)
- ssh to server and git clone repo
Clone project to server
ssh to your server and git clone it. My example will be cloned in
/root/myapp
Install Ruby via RVM + alias
rvm install 3.3.5 rvm alias create myapp123 ruby-3.3.5 rvm alias list # you should see myapp123 => ruby-3.3.5
RVM alias will be important when we create puma service. We will tel it to use RVM alias instead of hardcode version number therefore we don't need to update service file every time we update ruby
Make sure your project has ./.ruby-version file and in it desired version number (e.g: ruby-3.3.5 ) this is so that you can start rails console in proper env when debugging stuff
Puma as a systemctl service
Create file /etc/systemd/system/myapp_puma.service
[Unit] Description=Puma HTTP Server for MyApp After=network.target # Uncomment for socket activation (see below) # Requires=puma.socket [Service] Type=notify WatchdogSec=10 # Preferably configure a non-privileged user # User= WorkingDirectory=/root/myapp # Explicitly define your ENV variables as they may be ignored Environment=WEB_CONCURRENCY=1 Environment=RAILS_ENV=production Environment=PORT=3009 # Helpful for debugging socket activation, etc. # Environment=PUMA_DEBUG=1 ExecStart=/usr/share/rvm/wrappers/myapp123/bundle exec ./bin/rails server Restart=always [Install] WantedBy=multi-user.target
Now if you run
sudo service myapp_puma start
...you should be able to curl localhost:3000 (or whatever port you define in config/puma.rb)
Important debugging note: if something fails and you change the service file content you need to run
sudo systemctl daemon-reload
before you can try sudo service myapp_puma start again so that it reloads
In order for this to work after system reboot you need to register the service:
sudo systemctl enable myapp_puma
to restart:
sudo service myapp_puma restart sudo service myapp_puma stop sudo service myapp_puma start sudo service myapp_puma status
NginX + ssl certificate
Given Nginx you've installed have configs in /etc/nginx/sites-enabled
And you want to run your website on domain myapp.com and www.myapp.com
Then create a file in /etc/nginx/sites-available/myapp with content:
upstream myapp678 { server 127.0.0.1:3009; # ...or whatever port you use } server { server_name myapp.com www.myapp.com; client_max_body_size 32M; # Optional - change this to whatever you feel like the biggest file upload be to your server root /var/www/html; location / { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-NginX-Proxy true; proxy_pass http://myapp678; } }
that's it. Now if you run $ sudo nginx -t you should not see any errors. However we still need to add ssl certs. This will be added by running $ sudo certbot and following the steps in the CLI. It will insert lines directly to this file and end result will look something like:
# DON'T COPY PASTE THIS - THIS IS EXAMPLE OF WHAT CERTBOT GENERATES! upstream myapp678 { server 127.0.0.1:3009; # ...or whatever port you use } server { server_name myapp123.com www.myapp123.com; client_max_body_size 32M; # Optional - change this to whatever you feel like the biggest file upload be to your server root /var/www/html; location / { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-NginX-Proxy true; proxy_pass http://myapp678; # DON'T COPY PASTE THIS - THIS IS EXAMPLE OF WHAT CERTBOT GENERATES! proxy_set_header X-Forwarded-Proto https; proxy_set_header X-Forwarded-Server $host; proxy_set_header Host $http_host; proxy_redirect off; } # DON'T COPY PASTE THIS - THIS IS EXAMPLE OF WHAT CERTBOT GENERATES! # START These lines are added by certbot #listen [::]:443 ssl http2 ipv6only=on; # managed by Certbot listen 443 http2 ssl; # managed by Certbot ssl_certificate /etc/letsencrypt/live/myapp123.com/fullchain.pem; # managed by Certbot ssl_certificate_key /etc/letsencrypt/live/myapp123.com/privkey.pem; # managed by Certbot include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot # END certbot }
now you can manage NginX with
sudo service nginx stop sudo service nginx start sudo service nginx status sudo service nginx restart sudo nginx -t
------------------------------------------------------
Archive
Old Puma service (before Rails 8):
[Unit] Description=Puma HTTP Server for MyApp123 After=network.target # Uncomment for socket activation (see below) # Requires=puma.socket [Service] Type=notify WatchdogSec=10 # Preferably configure a non-privileged user # User= WorkingDirectory=/home/ubuntu/myapp123 # Explicitly define your ENV variables as they may be ignored Environment=WEB_CONCURRENCY=3 Environment=RAILS_ENV=production # Helpful for debugging socket activation, etc. # Environment=PUMA_DEBUG=1 # use absolute path ov RVM alias for ruby version we use ExecStart=/usr/share/rvm/wrappers/myapp123/bundle exec puma -C ./config/puma.rb Restart=always [Install] WantedBy=multi-user.target