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 requirers a lot of setup. What if we had self-hosted heroku?
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 6 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.
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.19.13/bootstrap.sh DOKKU_TAG=v0.19.13 bash bootstrap.sh
Please take a look at dokku documentation for newest version.
Installation can take up to few minutes. After it's done navigate to your machine's IP address in the browser. Add your public ssh key and finish setup. You can skip hostname settings, we'll get to that later.
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
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
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 DOKKU_LETSENCRYPT_[email protected] dokku letsencrypt 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 mytestapp
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 [email protected]_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.
So as you can see deploying Rails 6 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.