Production deployment can quickly turn into a headache if you are not careful. In the ideal world, you’d simply click a button, and your code can go straight into production, delivering your latest releases to your users without skipping a beat.
This is critical to get right because without a deployment step, your app that you’ve worked so hard to develop will not reach your users. Thing is, deployments need to be simplified so they don’t take up precious time. Mina came up on my radar recently when I was considering options for deploying my Rails apps. Turns out, you can use it for more or less any stack, like Django or Node.js, if that’s your thing.
In this guide I will show you how close you can get to the ideal using the cute tool Mina, your ordinary Rails workflow, and the Nginx server.
I like to deploy on Ubuntu because I run Linux Mint as my go-to OS, so dev and prod look very similar, however, this process should work for Unix-like systems. In the future, I intend to explore OpenBSD, it has a very attractive open philosophy and a well-earned reputation for security. Running Linux Mint alongside OpenBSD would be a geek’s dream come true.
Getting Your Application Ready
First you need to get the application code for the app you want to deploy.
Make sure you have a Ruby on Rails development environment on your machine already.
In case you do not have a Ruby on Rails environment ready, consult this guide on setting up a Rails development environment. With your environment read, the next thing is to install your application’s dependencies and ensure the application at least runs on your local development environment.
Test your app locally
Now you can run the application. You might also want to set up and connect a database. Rails comes with SQLite set up out of the box, but if you are deploying into production, PostgreSQL or MongoDB might be better choices.
Running the app is the easy part, just type:
Make sure your specific app is working as expected and you can access it in your browser or over your API before going on to a server. For example, if I run my test app, I should be able to see the development version when I visit http://localhost:3000 in your browser.
Spinning up a server
Now that we have the code and verified the app is working locally, you’ll want to get your production environment setup.
You’ll want to spin up an EC2 instance running Ubuntu 14 LTS as its operating system, or your server of choice on the other platforms, then install all dependencies your server will need to run Ruby and Ruby on Rails.
Server setup can be a bit of a rabbithole, so I recommend following a solid guide to installing Rails and your other server dependencies.
Mapping Your Domain to point to your server
In addition, if you have a domain name at which you want your application to be accessible once you deploy it, then you’ll want to map your domain to the public IP address of your EC2 instance or other server.
The process varies from one domain registrar to another. As a rule of thumb, it involves going into your domain registrar domain account, then creating a new A record, and pointing it to the actual IP address of your new server. You may also need to make a CNAME record pointing to the server. In some cases, you may need to obtain an elastic IP address.
Installing Mina and Nginx, and verifying they are all set up to go
Now that your server is all set up, and you can now access your server via your domain name or at the very least a public IP address, we should setup Nginx and Mina as the next steps.
Nginx is a highly-scalable web server and reverse proxy. It has a lot of flexibility regarding what it can do and how you configure it.
For this reason I’m a big fan of Nginx. A lot of websites have scaled to millions of hits on the back of Nginx. It has quite a colorful history, which you can read here.
Mina, our deploy hero, is a really fast deployer and server automation tool. Alternatives like Capistrano exist, but Mina has the particular advantage of being faster and somewhat more elegant. You could also reach for other tools like Chef and Puppet, however, Mina is likely to be a strong option for most deployments.
You’ll want to SSH into your server. Here’s a guide on how to do this.
Once you are SSH’d into your server or EC2 instance, installing Nginx is simple enough:
In case you run into any problems installing Nginx, you’ll want to consult the official Nginx installation and setup guides.
To install Mina you just run
Remember if you’re using Rbenv and you run into executable errors, that you probably need to rehash your shims, using:
Great, now you have Mina and Nginx installed.
Configuring the deploy
Let’s configure Mina.
This creates a mina deploy file at config/deploy.rb
Take a look at this file, we’ll be editing it to customize our deployment.
What makes Mina such a great tool, behind it’s speed, is how simple everything is in how it works. Mina allows us to “queue” tasks that are to be run as part of the deployment process.
Think of the queue from the standpoint of a normal deployment. What would need to happen in order for us to deploy on a server.
Typically, the steps would go something like this, in chronology:
- Log in to the server
- Create the directory where our app is going to be deployed, and from which our web server will serve the files
- Retrieve the latest source code from a code repository hosted on our version control server or cloud repos like GitLab, Bitbucket or Github
- Set up any database changes that need to be in place
- Start or restart our web application server
This process is what Mina does for us. How it does so is using this notion of “queues”.
At its heart, a queue is just a sequence of commands that Mina will run for us on the server. So, as you can imagine, our queue will include all the above steps as separate commands.
Here are some important parameters you will want to configure in your config/deploy.rb file:
For the domain option, you’ll want to set your appropriate server or EC2 instance IP address.
The deploy_to option refers to the actual directory on your server where your app files are going to live. This depends on your preference. I’ve seen some people use /var/www/foobar.com, the Nginx default is /usr/share/nginx/html/foobar.com
You’ll want to replace foobar.com with your app’s domain name or just your app name if you do not have a domain name setup. Note that if you are going to be in production, getting a domain name will be essential.
I’ll also direct your attention to the very last option I copied above, the user. On an Ubuntu box with Amazon EC2, this will typically be “ubuntu”, however, you may want to create a specific user that is responsible for handling this deployment process.
Also note that if you are using RVM or Rbenv, you will likely need to enable the options for RVM or Rbenv, respectively, in your config/deploy.rb file.
Now your app is more or less ready to deploy. You want to have Mina setup your deploy directory on the server. This also tests our configuration, helping us catch any errors before we deploy. So run:
The verbose option will enable us to see what’s going on on the server, and allow us to spot problems with the deployment, if any.
Now to deploy, we can run:
When the last command is run, our app deployment is pretty much done. And this whole set of commands, once configured initially, leads us to be able to deploy our application at any particular moment with one simple command.
You can check the docs if you run into deployment errors. Rails 5 now comes with Puma as the default server, but there are others out there, like Unicorn or Passenger so explore a bit to find the one that suits you best. Passenger is a great, simple option for beginners so, if you are just starting out, I’d recommend that. Whichever server you go with, if you are running at a live domain like example.com, you need to look up how to proxy nginx to resolve to your rails server’s socket.