Deploy a Rails app with Dokku and Digital Ocean

Created: December 13, 2018 14:37 | Updated: August 18, 2019 17:30
Tags: Digital Ocean, DNS, Dokku, Rails 5, Servers

Credit to Dave Kiss

Buy a domain name

I use Namecheap and have been happy with them, I don't know if they are the best but they are certainly not the worst and I have had no issues with them. Just stay away from GoDaddy.

Point your Domain name at Digital Ocean's DNS

We are doing this now because it can take a while for the settings to distribute across the web. In Namecheap I selected "Custom DNS" under Nameservers and put in Digital Ocean's 3 name servers:

  • ns1.digitalocean.com
  • ns2.digitalocean.com
  • ns3.digitalocean.com

I really like how creative they were with the names.

Sign up for Digital Ocean

Sign up for Digital Ocean using this link to get $100 in free credits over 60 days. Full disclosure: Once you spend $25 on their service I will get a $25 credit on my service. And I like free credits. I'd also be really happy that someone read this post. So please use the link!

Create a Droplet

You can create a droplet (read: virtual private server) with Dokku pre-installed! When creating a droplet choose Dokku under the One-Click-Apps tab, add your SSH keys and boot that puppy up.

Finish Dokku Setup

Do this right away, if someone else beats you to it then they will have access to your server instead of you.

Navigate to your server's IP address (listed in Digital Ocean) and finish the setup on the admin page that appears. You will have to paste in your public ssh key again and I recommend using virtual host naming for your apps. It means that if you create an app called myapp, it will be accessible at myapp.mydomain.com

Create an app on your server

SSH onto your server

ssh root@your.droplet.ip.address

Create an app

dokku apps:create awesomeapp

Install Postgres, create and link database

dokku plugin:install https://github.com/dokku/dokku-postgres.git
dokku postgres:create awesomeappdb
dokku postgres:link awesomeappdb awesomeapp

Create a swap file to help out on the ram front. You will only see output after the 3rd line.

fallocate -l 2G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile

Open fstab with Nano

nano /etc/fstab

Add this line at the bottom

/swapfile none swap sw 0 0

And then use CTRL+x, y, and then enter to save and exit.

Configure Digital Ocean's DNS

Add the domain that you purchased on namecheap and you should see 3 entries pointing at each of Digital Ocean's cleverly named servers.

Now you need to create 'A' records for your domains. I created the following:

Type Hostname Value
A mydomain.com (select your server)
A www.mydomain.com (select your server)
A awesomeapp.mydomain.com (select your server)

etc.

Install dokku-cli

dokku-cli is very similar to the Heroku command line tool and is a joy to use. No configuration is needed! Just run in your project directory and use 'dokku' in the place of 'heroku'.

Install Dokku CLI

gem install dokku-cli

Make a Rails App

rails new awesomeapp --database=postgresql

Add a page and a route

cd awesomeapp
rails generate controller Static index

Add something to that index page in app/views

And add to config/routes.rb

root 'static#index'

Automatic Migrations

This one just runs rails db:migrate automatically.

Create app.json in the root directory of your app

{
  "name": "awesomeapp",
  "description": "My awesome Rails app, running on Dokku!",
  "keywords": [
    "dokku",
    "rails"
  ],
  "scripts": {
    "dokku": {
      "postdeploy": "bundle exec rails db:migrate"
    }
  }
}

Add checks

This feature is rather nice, it makes Dokku check to make sure that your freshly uploaded code actually starts up before switching over to it!

Create a file called CHECKS in the root of your project directory

# CHECKS

WAIT=10  
ATTEMPTS=6  
/check.txt it_works

Add the following route to config/routes.rb

get '/check.txt', to: proc {[200, {}, ['it_works']]}

And it will make a call to that route when it starts up your new code, thereby ensuring that the new server actually started.

Add your secrets file

# config/secrets.yml
production:
  secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>

Add remote repository

Navigate to your awesomeapp project directory and add the repository

git remote add dokku dokku@your.droplet.ip.address:awesomeapp

Set your config variables

Run bundle exec rake secret and copy the result for your server's secret_key_base. This is stored on your server as an environment variable.

dokku config:set RAILS_ENV=production SECRET_KEY_BASE=yoursecretkeybasethatyoucopied

You can now push your code with

git add .
git commit -m 'rails new'
git push dokku master

Free SSL with Let's Encrypt

Let's Encrypt provides free SSL certificates. You can find more complete instructions and explanations here.

SSH onto your server

ssh root@your.droplet.ip.address

Install Let's Encrypt

dokku plugin:install https://github.com/dokku/dokku-letsencrypt.git

Update if it was already installed

dokku plugin:update letsencrypt

Set your email address (note that you need to change MYAPP and ME@MYEMAIL.COM)

dokku config:set --no-restart awesomeapp DOKKU_LETSENCRYPT_EMAIL=ME@MYEMAIL.COM

Turn it on

dokku letsencrypt awesomeapp

Set up auto-renewal with a cronjob

dokku letsencrypt:cron-job --add

Backup your databases

I wrote a shell script for this very issue. It downloads all your Postgres databases from Heroku and Dokku and uploads them (conveiently dated) to Google Drive. Check it out and let me know what you think!

Written by Alan Vardy. Let me know how I can make this better!