This is a guide/tutorial on how to setup and deploy your Rails application to AWS Ec2 instance (Ubuntu Server). In this tutorial, I worked from an Ubuntu 16.10 and just recently I decided to try it on Linux Mint (which is also Debian based like Ubuntu) and it worked! In this tutorial I made use of the following tools:
- RVM (on local machine as well as Ec2 instance)
- PostgreSQL
- Capistrano
- GitHub
I also did a previous tutorial on how to deploy your rails app from a Windows machine to an AWS instance(Ubuntu Server) with just GitHub, so if you are interested, check it out.
Let’s get started with deploying your rails application to an Ec2 instance with Capistrano using nginx and puma server:
1. CREATE RAILS APP
rails new commodre -d postgresql
Commodre is a simple blog site, and we’ll use scaffold for that. . .
cd commodre
rails g scaffold Blog title:string content:text
Update config/database.yml by adding your username, password, host: localhost.
To your /config/routes.rb add:
root ‘blogs#index’ |
Back to your terminal. . .
rake db:create
rake db:migrate
rails s
Go to localhost:3000 and you should see the blog home page. . .
WORKS FINE! Let’s stop the server: Ctrl C
2. CAPISTRANO AND PUMA SETUP (ON LOCAL MACHINE)
To your Gemfile add:
gem ‘figaro’gem ‘puma’ #Should already be in your Gemfilegroup :development do gem ‘capistrano’ gem ‘capistrano3-puma’ gem ‘capistrano-rails’ #Should already be in your Gemfile gem ‘capistrano-bundler’ gem ‘capistrano-rvm’end |
Back to your terminal. . .
bundle install
To generate Capistrano configuration run (on the terminal)
cap install STAGES=production
If that doesn’t work, then run bundle exec cap install STAGES=production
This should generate some files like you see in the image above.
To your Capfile, add:
require ‘capistrano/rvm’require ‘capistrano/bundler’require ‘capistrano/rails/migrations’require ‘capistrano/rails/assets’ require ‘capistrano/puma’ |
To your deploy.rb add:
set :application, ‘commodre’set :repo_url, ‘git@github.com:ohiodn8/commodre.git’ # should match git reposet :branch, :masterset :deploy_to, ‘/home/deploy/commodre’set :pty, trueset :linked_files, %w{config/database.yml config/secrets.yml}set :linked_dirs, %w{bin log tmp/pids tmp/cache tmp/sockets vendor/bundle public/system public/uploads}set :keep_releases, 5set :rvm_type, :userset :rvm_ruby_version, ‘ruby-2.4.0’ # Should match ruby version set :puma_rackup, -> { File.join(current_path, ‘config.ru’) }set :puma_state, “#{shared_path}/tmp/pids/puma.state”set :puma_pid, “#{shared_path}/tmp/pids/puma.pid”set :puma_bind, “unix://#{shared_path}/tmp/sockets/puma.sock” #accept array for multi-bindset :puma_conf, “#{shared_path}/puma.rb”set :puma_access_log, “#{shared_path}/log/puma_error.log”set :puma_error_log, “#{shared_path}/log/puma_access.log”set :puma_role, :appset :puma_env, fetch(:rack_env, fetch(:rails_env, ‘production’))set :puma_threads, [0, 8]set :puma_workers, 0set :puma_worker_timeout, nilset :puma_init_active_record, trueset :puma_preload_app, false |
To your .gitignore, add:
/config/database.yml/config/secrets.yml |
3. SETUP EC2
I’m guessing you know how to setup up an Instance already. I’ll be using an Ubuntu Instance (free tier).
Over to your aws.amazon.com account, find and click the link to Ec2. On the Ec2 dashboard click the launch Instance button
Select Ubuntu Server
Choose the instance you prefer… I’m using t2.micro (free tier eligible)
Next through the steps. . .
I’ll create a new security group for this project
Add the security group rule like you see in the image above and then click the review and launch button. . . then launch button… then select a keypair. I’ll create one for the project and remember to download the key pair (very important) and then launch the instance.
Scroll down and click view Instances button
Move the downloaded key pair silence.pem to a folder. I’ll create a new folder (Cred) on my Desktop for keys.
4. TIME TO START A NEW TERMINAL FOR YOUR EC2 INSTANCE/SERVER
Still on my local machine, you may want to start a new terminal for this step.
cd into the folder you have your key pair and change the access right. . .
cd /home/odion/Desktop/Cred
(this is for my local machine, you should use your username and directory)
chmod 400 silence.pem
Now time to login into to the ec2 instance/server (copy your IPV4 public DNS from your running Ec2 Instance)
ssh -i silence.pem ubuntu@ec2-34-210-21-124.us-west-2.compute.amazonaws.com
Congratulations! You’re now in your Ec2 instance. We will patch the instance by running. . .
sudo apt-get update && sudo apt-get -y upgrade
Let’s create a user
sudo su
The command above will place you in the root directory
adduser deploy
and it’ll prompt you to add a password, I’ll use deploy. . . leave the rest of the fields blank by clicking enter.
To check if the user was created. . .
id deploy
Give the new user sudo rights
sudo nano /etc/sudoers
Add:
deploy ALL=(ALL:ALL) ALL |
and save the file by clicking Ctrl X. It’ll ask for yes and no…type y and click Enter.Switch to the deploy user and generate an ssh key for the user:
su - deploy
ssh-keygen
Do not set a passphrase and just click enter.
List the directory:
ls -al
And now you have .ssh directory.
cd .ssh
ls
You have id_rsa and id_rsa.pub
cat id_rsa.pub
Copy the the key and paste in an empty notepad. head over to your GitHub account.
5. SETUP GIT REPOSITORY
Off to your GitHub account and create new repository
On the new page remember to copy ssh git link to deploy.rb Back to your local machine terminal, type. . .
git init
git add .
git commit -am '1st_commit'
git remote add origin git@github.com:ohiodn8/commodre.git
git push -u origin master
Refresh your github page, and your app directory should show.
Note: If you get an ssh error and you’re unable to push your app to your GitHub repository, follow this link. It may resolve the issue.
click the user icon at the top right of your GitHub page and click Settings
Click SSH and GPG Keys
Click the New SSH key Button
Name it what ever you like. I’ll name mine commodre key. Paste in the id_rsa.pub key you copied from your Ec2 Server and then click save SSH key button.
Head back to the Ec2 Instance/Server Terminal and install git (you probably have it already)
sudo apt-get install git
To test the ssh connection, run. . .
ssh -T git@github.com
It may ask for a yes/no… type yes and you should get a response like the image below.
6.
Now head over to your Local Machine terminal. . . this step is important. If you ever tried the Capistrano setup before, and while deploying got some SSH NET error, this might just fix it.On your local machine terminal:
cd /home
ls
You should see your user directory, mine is odion.
cd odion/.ssh
ls
I generated id_rsa and id_rsa.pub in here after getting the SSH NET error and that fixed, so you’ll probably want to try it. . . (if you followed the link in step 5, you already generated this key and you don’t have to follow the step below).
ssh-keygen
ls
You should see id_rsa and id_rsa.pub (if you have this in the directory, no need to generate the keys).
cat id_rsa.pub
Copy the keys and just like you did with the Linux Instance keys, paste this into your GitHub/SSH keys settings, and after that return to your local machine and type. . .(if you followed the link in step 5 just jump to the next step).
ssh -T git@github.com
Back to your Ec2 Instance/Server, you should still be in the .ssh directory. So, in the .ssh directory :
nano authorized_keys
Paste the same keys you copied from your local machine (and put in GitHub) in the authorized_keys, and then save.
7. TIME TO INSTALL NGINX:
Still in your Ec2 Instance/Server:
cd ..
pwd
You should get something like /home/deploy
sudo apt-get install nginx
Once nginx is installed, logout by typing
exit
This should take you back to the root user. Log back in. . .
su - deploy
It’ll prompt you for your password, remember we used deploy.
We have to edit a file. Instead of nano we’ll be using vim
sudo vi /etc/nginx/sites-available/default
and comment out every field. To comment out, click i on your keyboard and you should see insert at the bottom of the terminal. Now comment the white fields out by adding # in front( reason why we’re using vim), they should be blue. At the bottom of the page paste. . .
upstream app { # Path to Puma SOCK file, as defined previously server unix:/home/deploy/commodre/shared/tmp/sockets/puma.sock fail_timeout=0;} server { listen 80; server_name localhost; root /home/deploy/commodre/current/public; try_files $uri/index.html $uri @app; location / { proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Real-IP $remote_addr; proxy_set_header Host $host; proxy_redirect off; proxy_http_version 1.1; proxy_set_header Connection ”; proxy_pass http://app; } location ~ ^/(assets|fonts|system)/|favicon.ico|robots.txt { gzip_static on; expires max; add_header Cache-Control public; } error_page 500 502 503 504 /500.html; client_max_body_size 4G; keepalive_timeout 10;} |
I’m guessing you know how to save with vim. If you’re more of a nano user (like me), just click ESC button, Shift : button, typewq! and hit Enter.
8. TIME TO INSTALL RVM, RUBY, NODEJS AND POSTGRESQL
Still on the Ec2 Instance/server
gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
curl -sSL https://get.rvm.io | bash -s stable
source /home/deploy/.rvm/scripts/rvm
rvm install ruby
This may prompt you for your deploy password (which is deploy). When the installation is complete, you can type ruby -v to check the version of ruby. If you have another version of ruby on your local machine, install that using rvm install ruby-2.*.*To list the versions, type
rvm list
Install bundler. . .
gem install bundler --no-ri --no-rdoc
Install node JS. . .
sudo apt-get install -y nodejs
If you don’t install nodejs, your cap deployment will stop mid way and return an error.
Install and Setup Postgresql. . .
sudo apt-get install postgresql postgresql-contrib libpq-dev
sudo -u postgres createuser -s commodre
sudo -u postgres psql
\password commodre
Type a password. I’ll use commodre.Quit by typing \qCreate a database:
sudo -u postgres createdb -O commodre commodre_production
Time To Create Directories for the capistrano deployment:
Still in the Ec2 Instance/Server:
mkdir commodre
mkdir -p commodre/shared/config
nano commodre/shared/config/database.yml
Paste the following codes and save. . .
production: adapter: postgresql encoding: unicode database: commodre_production username: commodre password: commodre host: localhost port: 5432 |
nano commodre/shared/config/secrets.yml
Paste the following code (and save):
production: secret_key_base: <%= ENV[“SECRET_KEY_BASE”] %> |
9. ALMOST DONE. . .
Go to your application folder on your Local Machine /config/deploy/production.rbScroll to the bottom and add
server ‘34.210.21.124’, user: ‘deploy’, roles: %w{web app db} |
Put your Ec2 public IPV4 where it says server and save.
On our local machine terminal, try to find your way to your application
pwd
cd /home/odion/sites/commodre
(That’s for me. . . try to find your way to your app. . .)
Now run. . .
cap production deploy
. . .and that should do it.
Okay! To your Ec2 Instance/Server. . . your rails app should be deployed in here now.Lets add a secret key to our secrets.yml (well, to our server environment)
cd /home/deploy/commodre/current
ls
that should list your rails app root directory.
rake secret
if that doesn’t work bundle exec rake secret
You’ll get a long string. . . copy and paste in an empty notepad, then run. . .
sudo nano /etc/environment
paste to the bottom:
export SECRET_KEY_BASE=rake secret ruby -e ‘p ENV[“SECRET_KEY_BASE”] |
where rake secret is the long string you copied, like so. . .
Then run. . .
echo $SECRET_KEY_BASE
If that doesn’t return your rake secret, logout by typing. . .
exit
and log back in with
su - deploy
try to run it again
echo $SECRET_KEY_BASE
It should return your rake secret, and we’re good.
Restart nginx server. . .
sudo service nginx restart
and you may see this error
(if you don’t, great!)
It happens. . . guess we made an error, let’s find out whats wrong
sudo vi /etc/nginx/sites-available/default
And that’s the error. . .
It is still white comment out the bracket.
Now lets try to restart the server
sudo service nginx restart
No error this time. Off to a browser and put your IPV4 address or Public IPV4 DNS. I’ll use the IP address.
Great! Now we’re served a 502 error page. . . just where we want to be. Let’s fix this: To fix the nginx 502 error, First thing is to know what happened, so we’re going to check the nginx log. Run. . .
sudo cat /var/log/nginx/error.log
And there’s the error right there. . .
It tried to connect to unix:/home/deploy/commodre/shared/tmp/sockets/puma.sock, and it says “No such File”. Remember we fixed that as our upstream path. Now this is because we haven’t started puma server itself, so lets go do that.Make sure you’re in your app directory (still in Ec2 Instance/Server terminal). . .
pwd
should return
/home/deploy/commodre/currentIf you’re not in the current directory, please get there and run
bundle exec puma -e production -b unix:/home/deploy/commodre/shared/tmp/sockets/puma.sock
and puma server should start up. Go back to your web browser and refresh the 502 error page. Refresh page. . . and everything should be working fine. We don’t want puma running like that, so we’re going to stop the server and daemonize it. Add a -d to the code:
bundle exec puma -e production -d -b unix:/home/deploy/commodre/shared/tmp/sockets/puma.sock
You can check to see if the process is running. . .
ps aux | grep puma
Restart the daemon puma server :
kill -s SIGUSR2 24673
Stop the server:kill -s SIGTERM 24673
THE ENDI’ll continue this tutorial by adding a monitoring tool known as Monit in a part 2 tutorial. Hope this long tutorial helped you.