Deploying Ruby on Rails on Ubuntu
I always wanted to learn how the deployment and server provisioning is done. While setting up a homelab using Raspbery Pi 4, which uses an ARM based architecture and many deployment tools do not support that yet so I thought this is perfect oppertuity to finally learn.
This is my first ever home lab setup:
- I use 4, Raspbery Pi 4 with 4Gig of RAM.
- The case I am using is from UCTRONICS.
- For operating system I am using Ubuntu server
22.04
.
While configuring the Raspberry Pi to host my Ruby on Rails sites, these are the steps I had to go through.
Secure the remote server with SSH
Install the copy utility
Make sure ssh-copy-id
is installed on Mac, it does not come in mac by default.
1
| brew install ssh-copy-id
|
Copy command
The following command will prompt for password
1
| ssh-copy-id -i ~/.ssh/id_rsa.pub user@remote-host-ip
|
You should now be able to ssh into remote server without needing to provide your password.
Disable password based login
Inside the sshd_config
file set the PasswordAuthentication
to no
1
| sudo vim /etc/ssh/sshd_config
|
Restart the SSH service
1
| sudo systemctl restart ssh
|
Installing Ruby & Rails dependencies
Node.js
Node version manager
1
2
| sudo apt install curl
curl https://raw.githubusercontent.com/creationix/nvm/master/install.sh | bash
|
Run the following command so nvm
command is available
Install node version
Install the LTS version
Install Yarn
Install Redis server
1
2
3
| sudo apt install redis-server
sudo apt install redis-tools
|
### Make sure it is up and running
1
| sudo systemctl status redis-server
|
Dependencies for compiiling Ruby along with Node.js and Yarn
1
| sudo apt 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
|
Install Ruby
rbenv
Run each command separately
1
2
3
4
5
6
7
| 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
|
Ruby
1
2
3
| ubuntu@ubuntu:~$ rbenv install 3.1.2
ubuntu@ubuntu:~$ rbenv global 3.1.2
ubuntu@ubuntu:~$ ruby -v
|
Bundler
Puma
1
| sudo apt -y install puma
|
Nginx
1
| sudo apt -y install nginx
|
Nginx site
Remove defailt site
1
| sudo rm /etc/nginx/sites-enabled/default
|
Enable your site
1
| sudo vim /etc/nginx/sites-enabled/app-name
|
Add site configuration
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
| upstream puma_your_app_name {
server unix:///home/ubuntu/freeapi/shared/tmp/sockets/puma.sock;
}
server {
listen 80 default_server deferred;
server_name freeapi.com www.freeapi.com;
# Don't forget to update these, too
root /home/ubuntu/your_app_directory/current/public;
access_log /home/ubuntu/your_app_directory/current/log/nginx.access.log;
error_log /home/ubuntu/your_app_directory/current/log/nginx.error.log info;
location ^~ /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
try_files $uri/index.html $uri @puma_your_app_name;
location @puma_your_app_name {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://puma_your_app_name;
}
error_page 500 502 503 504 /500.html;
client_max_body_size 10M;
keepalive_timeout 10;
}
|
Restart Nginx service
1
| sudo service nginx restart
|
If the service fails to start check the logs to see what the error is. The status command will also provide helpful information systemctl status nginx.service
. At this stage the error might be related to nginx log files not being available, thats because we did not deploy the app yet. If you want you can comment the access_log
and error_log
line in the above confirutaion, restart the nginx service and then check if it is running successfully.
Install PostgreSQL
1
| sudo apt install postgresql postgresql-contrib libpq-dev
|
If you see a lock error then simply reboot and run the above command again.
Create the PostgreSQL user and database
1
2
3
4
| sudo su - postgres
createuser --pwprompt ubuntu
createdb -O ubuntu your-app-db
exit
|
Deployment
Capistrano
Add the following gems to the Gemfile and run the command bundle install
1
2
3
4
5
| gem 'capistrano', require: false
gem 'capistrano-rails', require: false
gem 'capistrano-puma', require: false
gem 'capistrano-rbenv', require: false
gem 'capistrano-bundler', require: false
|
Generate the deployment files
1
| cap install STAGES=production
|
This will generate the following files
1
2
3
| Capfile
config/deploy.rb
config/deploy/production.rb
|
and the following directory
Add the following in Capfile
1
2
3
4
5
6
7
8
9
10
11
12
| require "capistrano/rails"
require "capistrano/rbenv"
require "capistrano/bundler"
require "capistrano/rails/assets"
require "capistrano/rails/migrations"
require "capistrano/puma"
install_plugin Capistrano::Puma
install_plugin Capistrano::Puma::Systemd
set :rbenv_type, :user
set :rbenv_ruby, '3.1.2'
|
Add the following inside config/deploy.rb
1
2
3
4
5
6
| set :application, "your-app-name"
set :repo_url, "git@github.com:username/myapp.git"
set :deploy_to, "/home/ubuntu/#{fetch :application}"
append :linked_dirs, 'log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle', '.bundle', 'public/system', 'public/uploads'
|
Add the following inside config/deploy/production
1
2
3
4
5
6
7
8
| set :branch, "main"
server "your-ip-server", user: "ubuntu", roles: %w[web app db]
set :ssh_options, {
keys: %w(/Users/your-user/.ssh/id_ed25519.pub),
forward_agent: true,
auth_methods: %w(publickey)
}
|
Make sure the branch you want to deploy is already pushed on GitHub.
Setup env vars
SSH into the remote server
1
2
| mkdir /home/ubuntu/your-app
nano /home/ubuntu/your-app/.rbenv-vars
|
Add the DB and Master key env vars
1
2
3
4
5
6
7
| # For Postgres
DATABASE_URL=postgresql://user:PASSWORD@127.0.0.1/myapp
RAILS_MASTER_KEY=xyz123
RACK_ENV=production
RAILS_ENV=production
|
Upload puma config
1
| cap production puma:config
|
Upload puma service
1
2
| cap production puma:systemd:config puma:systemd:enable
|
Finally deploy the app using the following command
1
2
| cap production deploy --trace
|
Troubleshooting
Removing the repository from Ubuntu
This guide is for Ubuntu 22.04
, if you end up adding the wrong repo which is not compatiable for example sudo add-apt-repository ppa:chris-lea/redis-server
just remove it by using the --remove
flag sudo add-apt-repository --remove ppa:chris-lea/redis-server
Puma
If you see the following error on deployment
1
2
3
4
| NameError: uninitialized constant Capistrano::Puma
install_plugin Capistrano::Puma
^^^^^^
/Users/shairyar/Sites/fakeapi/Capfile:44:in `<top (required)>'
|
Make sure you are using the gem capistrano3-puma
and not capistrano-puma
.
GitHub permission issue
Just make sure the new secure ssh key id_ed25519.pub
is added to remote server and inside config/deploy/production
key forward_agent
is set to true
1
2
3
4
5
| set :ssh_options, {
keys: %w(/Users/shairyar/.ssh/id_ed25519.pub),
forward_agent: true,
auth_methods: %w(publickey)
}
|
Yarn install issue
Running the following command shold fix the problem sudo apt-get remove cmdinstall;sudo apt update;sudo apt-get install yarn
Contribute
Found a mistake? Or if you have any questions, please feel free to open an issue here.
Found something that can be improved? Feel free to create a PR here.