This is an adapted guide of the GoRails guide for Deploy Ruby On Rails: Ubuntu 22.04 Jammy Jellyfish in 2022
2GB Memory, 1 CPU, 50GB SSD, 2TB Transfer Ubuntu 22.04 (LTS) x64. Select your SSH Keys. Enable Backups, Monitoring, IPV6.
Choose a hostname as [project name]-web-prd
Add New SSH Key. In local terminal copy your ssh key and paste into Digital Ocean:
pbcopy < ~/.ssh/id_rsa.pub
After droplet is created, copy droplet IP and ssh in from local
ssh root@IP_ADDRESS
sudo adduser deploy
sudo adduser deploy sudo
su deploy
There are two ways to add SSH keys (1) Using ssh-copy-id (2) Manually adding your public key as an authorized key
On server, add SSH key from deploy user by opening password auth
sudo nano /etc/ssh/sshd_config
Change 'PasswordAuthentication yes'
sudo service ssh stop
sudo service ssh start
On local
$ ssh-copy-id deploy@ip_address
On server, close password auth
sudo nano /etc/ssh/sshd_config
Change 'PasswordAuthentication no'
sudo service ssh stop
sudo service ssh start
On local, test ssh using the deploy user
ssh deploy@ip_address
On local, copy your public key
// for RSA SSH key
cat ~/.ssh/id_rsa.pub
// for ED25519 SSH key
cat ~/.ssh/id_ed25519.pub
On server, ensure you're logged in as a deploy user and create an authorized_keys file
mkdir ~/.ssh && touch ~/.ssh/authorized_keys
Open your authorized_keys file
sudo nano ~/.ssh/authorized_keys
Paste in your public key and save
ssh-ed25519 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX user@computer
On local, test ssh using the deploy user
ssh deploy@ip_address
# Adding Node.js repository
curl -sL https://deb.nodesource.com/setup_16.x | sudo -E bash -
# Adding Yarn repository
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
sudo add-apt-repository ppa:chris-lea/redis-server
# Refresh our packages list with the new repositories
sudo apt-get update
# Install our dependencies for compiiling Ruby along with Node.js and Yarn
sudo apt-get install git-core curl zlib1g-dev build-essential libssl-dev libreadline-dev libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt1-dev libcurl4-openssl-dev software-properties-common libffi-dev dirmngr gnupg apt-transport-https ca-certificates redis-server redis-tools nodejs yarn
node -v
# Node v16.19.0
git clone https://github.com/rbenv/rbenv.git ~/.rbenv
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(rbenv init -)"' >> ~/.bashrc
git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
echo 'export PATH="$HOME/.rbenv/plugins/ruby-build/bin:$PATH"' >> ~/.bashrc
git clone https://github.com/rbenv/rbenv-vars.git ~/.rbenv/plugins/rbenv-vars
exec $SHELL
rbenv install 3.0.3
rbenv global 3.0.3
ruby -v
# ruby 3.0.3
gem install bundler
rbenv users need to run rbenv rehash after installing bundler.
rbenv rehash
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 561F9B9CAC40B2F7
sudo sh -c 'echo deb https://oss-binaries.phusionpassenger.com/apt/passenger focal main > /etc/apt/sources.list.d/passenger.list'
sudo apt-get update
sudo apt-get install -y nginx-extras libnginx-mod-http-passenger
if [ ! -f /etc/nginx/modules-enabled/50-mod-http-passenger.conf ]; then sudo ln -s /usr/share/nginx/modules-available/mod-http-passenger.load /etc/nginx/modules-enabled/50-mod-http-passenger.conf ; fi
sudo ls /etc/nginx/conf.d/mod-http-passenger.conf
Edit passenger.conf
sudo nano /etc/nginx/conf.d/mod-http-passenger.conf
Change the passenger_ruby line to point to your ruby executable:
passenger_ruby /home/deploy/.rbenv/shims/ruby;
Restart Nginx
sudo service nginx start
Visit your server's IP address in the browser and you should see a Nginx message.
Next, update Nginx server settings.
Remove the existing nginx server file
sudo rm /etc/nginx/sites-enabled/default
Create a new one
sudo nano /etc/nginx/sites-enabled/myapp
Paste in the following contents
server {
listen 80;
listen [::]:80;
server_name myapp.com www.myapp.com;
root /home/deploy/myapp/current/public;
passenger_enabled on;
passenger_app_env production;
location /cable {
passenger_app_group_name myapp_websocket;
passenger_force_max_concurrent_requests_per_process 0;
}
# Allow uploads up to 100MB in size
client_max_body_size 100m;
location ~ ^/(assets|packs) {
expires max;
gzip_static on;
}
}
Note that if you don't have a domain name available yet, you can instead put a placeholder in server_name _;
Restart server
sudo service nginx reload
sudo apt-get install postgresql postgresql-contrib libpq-dev
Create Database:
sudo su - postgres
createuser --pwprompt deploy
createdb -O deploy myapp_production
exit
Test Database Login:
psql myapp_production deploy
If Needed, Change Database Password
ALTER USER deploy WITH PASSWORD 'new_password';
In your app Gemfile under the development environment, add capistrano:
group :development do
# Deployment
gem 'capistrano', '~> 3.17'
gem 'capistrano-rails', '~> 1.6', '>= 1.6.2'
gem 'capistrano-passenger', '~> 0.2.1'
gem 'capistrano-rbenv', '~> 2.2'
gem 'ed25519', '~> 1.3'
gem 'bcrypt_pbkdf', '~> 1.1'
end
bundle install
Commit and push your code git commit -m "Add capistrano gem"
cap install STAGES=production
Modify Capfile
by adding the following just above # Load custom tasks from lib/capistrano/tasks if you have any defined
require 'capistrano/rails'
require 'capistrano/passenger'
require 'capistrano/rbenv'
set :rbenv_type, :user
set :rbenv_ruby, '3.0.3'
Modify config/deploy/production.rb
by adding:
server 'your_ip_address', user: 'deploy', roles: %w{app db web}
Modify config/deploy.rb
by adding:
set :application, 'my_app_name'
set :repo_url, 'git@gitlab.com:username/my_app_name.git'
# 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, '/home/deploy/my_app_name'
# Default value for :linked_files is []
append :linked_dirs, 'log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'tmp/webpacker', 'vendor', '.bundle', 'public/system', 'public/uploads', 'storage'
# Only keep the last 5 releases to save disk space
set :keep_releases, 5
Commit and push your code git commit -m "Configure capistrano"
// for RSA SSH key
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_rsa
bundle exec cap production deploy
// for ED25519 SSH key
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
bundle exec cap production deploy
Your deployment may fail due to a different platform being used on your local machine versus the cloud virtual machine. When deploying, I encountered an error:
DEBUG [b4677b9e] Your bundle only supports platforms ["x8664-darwin-21"] but your local platform is x8664-linux. Add the current platform to the lockfile with
bundle lock --add-platform x86_64-linux
and try again.
To resolve this error, I ran bundle lock --add-platform x86_64-linux
to modify my Gemfile.lock.
Commit and push your code git commit -m "Add x86_64-linux to gem lock"
and redeploy.
Your deployment is likely to fail again but this time due to your environment variables not being set.
In your application's config/database.yml
point your production database to use environment variables.
production:
<<: *default
database: <%= ENV["MY_APP_DATABASE_DATABASE"] %>
host: <%= ENV["MY_APP_DATABASE_HOST"] %>
username: <%= ENV["MY_APP_DATABASE_USERNAME"] %>
password: <%= ENV["MY_APP_DATABASE_PASSWORD"] %>
Commit and push your code git commit -m "Update production database.yml"
Next, set your environment variables on the server. SSH into the server and open nano /home/deploy/myapp/.rbenv-vars
. Add in the following:
RAILS_MASTER_KEY=your_rails_master_key
SECRET_KEY_BASE=your_secret_key
MY_APP_DATABASE_DATABASE=myapp_production
MY_APP_DATABASE_HOST=127.0.0.1
MY_APP_DATABASE_USERNAME=deploy
MY_APP_DATABASE_PASSWORD=your_database_password
For your_rails_master_key
, you can reuse your local application's config/master.key
. Note that this file is typically not checked into source control.
You can generate a your_secret_key
by running rails secret
from your terminal. If you encounter any errors when deploying your application asking you for a secret of a certain bit length, you can also generate a secret by opeining your rails console
and running SecureRandom.hex(16)
.
Re-run deployment. This time it should pass. Note the first successful deployment will take longer then usual as all gems will be installed.
bundle exec cap production deploy
Restart Site
touch my_app_name/current/tmp/restart.txt
That's it! Your rails application should now be live. To see your server logs in real time, SSH into the server and run.
tail -f my_app_name/current/log/production.log
*Phusion Passenger doesn't seem to be running *
If during your deploy you encounter an error such as *** ERROR: Phusion Passenger(R) doesn't seem to be running
, you can check what the error might be by viewing nginx logs sudo tail -f /var/log/nginx/error.log
An example of an error I encountered was:
The application encountered the following error: You have already activated strscan 3.0.1, but your Gemfile requires strscan 3.0.4. Since strscan is a default gem, you can either remove your dependency on it or try updating to a newer version of bundler that supports strscan as a default gem. (Gem::LoadError)
To resolve this, I ended up running gem install strscan 3.0.4
. Afterwards, I visited the server's IP address in my browser and was able to be routed to the Rails application.
PassengerAgent: error while loading shared libraries: libcrypto.so.1.1
Another example on Ubuntu 22.04
PassengerAgent: error while loading shared libraries: libcrypto.so.1.1: cannot open shared object file: No such file or directory
2022/00/00 00:00:00 [alert] 37777#37777: Unable to start the Phusion Passenger(R) watchdog: it seems to have crashed during startup for an unknown reason, with exit code 127 (-1: Unknown error)
To resolve this I downloaded and installed the missing package using wget http://nz2.archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.1f-1ubuntu2.16_amd64.deb
and sudo dpkg -i libssl1.1_1.1.1f-1ubuntu2.16_amd64.deb
.
See this StackOverflow page for more details
Error opening Passengerfile.json
2023/01/22 00:07:55 [alert] 40571#40571: *6 Error opening '/home/deploy/myapp/current/Passengerfile.json' for reading: Permission denied (errno=13); This error means that the Nginx worker process (PID 40571, running as UID 33) does not have permission to access this file. Please read this page to learn how to fix this problem: https://www.phusionpassenger.com/library/admin/nginx/troubleshooting/?a=upon-accessing-the-web-app-nginx-reports-a-permission-denied-error; Extra info, client: 0.0.0.0, server: myapp.com, request: "GET / HTTP/1.1", host: "myapp.com"
To resolve this become the root user and grant permissions to the deploy user sudo -i
, cd /home
and chmod g+x,o+x deploy
.
apt-get install libmagickwand-dev # afterwards cap deploy carrierwave commit to production