How to Deploy Rails using Passenger - Part 2
Recap
This post is a continuation from here. Previously we have installed Ruby, Rails, Nginx, Passenger and PostgreSQL. On this post we will install git, configure nginx config file to deploy rails app and git push the rails app from your development machine to the VPS. The step number will continue from the previous one, which is eleven.
Step Eleven - Install git and creating a repository
Install git on the VPS using this command :
sudo apt-get install git
After installing Git, we will now create a bare git repository named awesomeapp.git and a folder to store the source code awesomeapp, let’s put the repository on your user folder for this tutorial ( you can of course change to other location ).
cd ~
mkdir awesomeapp
mkdir repo && cd repo
mkdir awesomeapp.git && cd awesomeapp.git
git init --bare
–bare indicates that the repository will have no working files / source code, just the version control.
Type pwd
to get your present working directory, you will need this later. My output looks like this :
Next, we will dive into the git hooks to add a work tree directory (where your source code will be stored), more info about git hooks here. We will use the post-receive hook as it is executed after a git push has finished receiving.
Inside awesomeapp.git directory, if you type ls
, you can see the list of files and folders like this :
Go to the hooks folder
cd hooks
Create a file named ‘post-receive’ :
cat > post-receive
When you execute the command above, you will see a blank line indicating that everything you type will be saved to this file. Let’s proceed to type :
#!/bin/sh git --work-tree=/home/soulchild/awesomeapp --git-dir=/home/soulchild/repo/awesomeapp.git checkout -f
Replace the work-tree directory with your desired location, this is the place where the source code will be saved.
Replace the git-dir directory with the bare git repository you created just now.
After finish typing, press Ctrl + D to save. We need to allow permissions for the file to be executable :
chmod +x post-receive
Now the source code will be saved in the work-tree every time a git push is received by the awesomeapp.git repository.
Step Twelve - Push the Rails app from your local machine to VPS
Now on your local machine ( your laptop/pc ), locate to your existing Rails application or create one if you don’t have one :
rails new awesomeapp -d postgresql
If you are creating a new Rails application, make sure to point the root route to a controller action first.
Open /config/database.yml of the rails app, scroll to the bottom and edit the production database username to look like this :
We will also generate a secret key for the production secret key base.
cd awesomeapp
rake secret
Copy down the string generated, we will need it later for setting environment variables.
Remember the present working directory from the previous step? We will add it to the git remote of the Rails app. If your local rails application has not initialize a git repository yet,
#inside awesomeapp rails root folder
#cd awesomeapp
git init
Then add the remote :
git remote add live ssh://user@YOUR_SERVER_IP_OR_DOMAIN_NAME/repo_location
live is the name of the remote, you can change this to whatever name you like.
user is the username you used to login to the ssh, change this to your ssh username.
YOUR_SERVER_IP_OR_DOMAIN_NAME is pretty much self-explanatory.
repo_location is the location of the repository in the VPS, replace this with the bare git repository mentioned in the previous step (eg: ‘home/soulchild/repo/awesomeapp.git’).
And now you are ready to push to the remote VPS, replace live with the remote name you have chosen just now.
git add -A
git commit -m "Awesome app first commit"
git push live master
Sweet! Next, let’s edit the Nginx configuration to serve the Rails app and include environment variables as well.
Step Thirteen - Edit Nginx Configuration file and deploy
Connect to your VPS using ssh
ssh demo@SERVER_IP_ADDRESS
Edit the Nginx configuration file using nano
sudo nano /opt/nginx/conf/nginx.conf
In the server block inside http block, edit it to look like this :
server { listen 80; server_name localhost; root /path/to/rails_app_root/public; # <-- be sure to point to 'public' passenger_app_root /path/to/rails_app_root; passenger_enabled on; rack_env production; passenger_env_var SECRET_KEY_BASE d6532f57f0e1f5150f38ef413fd85c2c9081195431177950d6e44248822ab3d05bb2619871c29a8367d95ff04abaaba84bfc4433f37d089c9437c3e2e1efadc6; passenger_env_var AWESOMEAPP_DATABASE_USERNAME demo; passenger_env_var AWESOMEAPP_DATABASE_PASSWORD correcthorsebatterystaple; }
- Replace the /path/to/rails_app_root/ with the work tree you defined in previous step.
- rack_env is the environment of the rails app, we set it to production.
- passenger_env_var is used to define environment variables, you can define multiple environment variables in the config file. Replace the value of environment variables above with yours.
Press Ctrl + X to finish editing, type ‘Y’ and press Enter when prompted to save.
Your nginx.conf will look similar to this :
Now we will move to the Rails application root directory (the work tree),
cd ~/awesomeapp
Run bundle install
bundle install
Precompile assets, remember to set the RAILS_ENV to production
rake assets:precompile RAILS_ENV=production
Restart the Nginx server first so that the environment variables will be loaded :
sudo service nginx restart
Run rake:db create to create database
rake db:create RAILS_ENV=production
Run rake:db migrate to migrate database
rake db:migrate RAILS_ENV=production
And finally restart the Passenger app to update the changes
passenger-config restart-app /path/to/rails_app_root
Step Fourteen - Cheers!
Now navigate to your VPS IP /domain name in the browser, you should see your Rails app running. 🍻
Next time whenever you git push a new update to remote, remember to login to the VPS and run these commands :
- bundle install
- rake assets:precompile RAILS_ENV=production
- rake db:migrate RAILS_ENV=production
- passenger-config restart-app /path/to/rails_app_root
Passenger app server must be restarted to reflect the changes after every git push.
Wait…. why do we need to repetitively execute these commands after git push, there must be a better way to automate this right? Yes there is! we can add these command to run in the post-receive hook, remember?
Step Fifteen - Adding deployment task to post-receive hooks
Lets go to the repository of the rails app again and edit the post-receive hook :
cd ~/repo/awesomeapp.git
cd hooks
nano post-receive
We will edit it to look like this :
Replace the work tree and git dir accordingly, press Ctrl + X to end editing.
Edited 19 July 2016 : I found that restarting the Passenger app is sufficient without restarting Nginx, no sudo permission is required for restarting passenger app.
Let's edit the user file in sudoers.d directory, replace demo with your username :
sudo visudo -f /etc/sudoers.d/90-demo
Add this line to the end of the file , replace demo with your username :
demo ALL=(ALL) NOPASSWD:/etc/init.d/nginx
Press Ctrl + X to finish editing, type 'Y' and press Enter to save.
Now you should be good to go. In your local machine development repository, make a commit and push it the remote, you will see an output like this :
And after receiving push, the server will run those deployment commands automatically and the web pages has changed :
Now every time you push master branch to remote, the remote will deploy automatically. Sounds like Heroku? 😜
Congratulation for making this far! 🎉 You have learnt how to deploy Rails app on a bare VPS using git flow.