Heroku, AWS, Google Cloud are great services for hosting Rails application but they are expensive. If you are developing a small app, kicking off a startup or just playing with Rails you can use cheaper solutions - cloud hosting, like DigitalOcean or Upcloud. The problem is the setup - you need to install dependencies on your own. Then deploy your application manually or using for example capistrano, which also requires a lot of setup. What if we had self-hosted heroku?
About dokku
Dokku is a simple PaaS that allows you to easily deploy your application. It’s a great solution if you want to save some money and use cheap cloud providers instead of heroku or AWS. Dokku will handle whole app setup for us. In this article I’ll show how to deploy Rails app with postgres, sidekiq and redis. We’ll secure our app with SSL using Let’s Encrypt certificate. It will be even easier if you are familiar with heroku.
Getting started
First of all we need a server with a debian or ubuntu installed. I’ll use 1 CPU / 1 GB RAM machine on DigitalOcean.
Connect to your machine via SSH as a root and install dokku:
wget https://raw.githubusercontent.com/dokku/dokku/v0.28.1/bootstrap.sh
DOKKU_TAG=v0.28.1 bash bootstrap.sh
Please take a look at dokku documentation for newest version.
Installation can take up to few minutes. After it’s done, add your public ssh key:
Copy if from ~/.ssh/authorized_keys
if it’s already there:
cat ~/.ssh/authorized_keys | dokku ssh-keys:add admin
or add a new one:
echo 'CONTENTS_OF_ID_RSA_PUB_FILE' | dokku ssh-keys:add admin
Setting up the application
Now let’s create an app. In my case it will be mytestapp
. Just replace it with your app’s name:
dokku apps:create mytestapp
To avoid setting up all dependencies manually we’ll use heroku buildpacks (isn’t it great?!):
dokku buildpacks:add mytestapp https://github.com/heroku/heroku-buildpack-nodejs.git
dokku buildpacks:add mytestapp https://github.com/heroku/heroku-buildpack-ruby.git
Setup all necessary envs:
dokku config:set mytestapp RAILS_ENV=production
dokku config:set mytestapp RAILS_MASTER_KEY=your_master_key
Dokku uses Procfile to determine what processes should be running. So if you don’t have one, create a file called Procfile
with following content:
web: bundle exec puma -C config/puma.rb
Database
Now let’s focus on database. The easiest way to install postgres is to use dokku plugin:
dokku plugin:install https://github.com/dokku/dokku-postgres.git
dokku postgres:create mytestapp_db
Now link postgres database to the app:
dokku postgres:link mytestapp_db mytestapp
It will set DATABASE_URL
env variable (same as heroku postgres).
If you want to run migrations automatically after deploy add following line to the Procfile:
release: bundle exec rails db:migrate
SSL
Now it’s the time to add a domain and setup SSL. We’ll need to add both non-www and www version of the domain.
dokku domains:add mytestapp test.kukicola.io
dokku domains:add mytestapp www.test.kukicola.io
Now we can install Let’s Encrypt plugin and generate certificate.
dokku plugin:install https://github.com/dokku/dokku-letsencrypt.git
dokku config:set --no-restart mytestapp [email protected]
dokku letsencrypt:enable mytestapp
Since Let’s Encrypt certificates are valid only for 3 months we can add a cron job to automatically renew them:
dokku letsencrypt:cron-job --add
Deploy
We are ready to deploy our app! It’s the same as on heroku. First we need to add remote repository:
git remote add dokku dokku@IP_ADDRESS:mytestapp
Then we can deploy our app:
git push dokku master
Now our app should be up and running! By default dokku will run 1 instance of web process. We can change with following command:
dokku ps:scale mytestapp web=2
Sidekiq, background processes
If your app is using sidekiq or any other background processes you need to add additional commands to Procfile. For example:
worker: bundle exec sidekiq -C config/sidekiq.yml
In order to use sidekiq you need redis. You can install it in the same way as postgres:
dokku plugin:install https://github.com/dokku/dokku-redis.git redis
dokku redis:create mytestapp_redis
dokku redis:link mytestapp_redis mytestapp
Remember that dokku will not spawn any non-web instances by default so after deploy run:
dokku ps:scale mytestapp worker=1
You don’t need to do it every time. Dokku will remember the number of instances between builds.
Summary
So as you can see deploying Rails application with dokku is very easy. After short setup it can be a great substitute for heroku. Unfortunately it has one big disadvantage - it’s a single server solution, so if you need high scalability it may not be the best option. Let me know in comments if you had any problems with deploying your app. If you would like to read more take a look at Dokku docs.