In this article, I will go through the steps to successfully launch a rails app using a Digital Ocean droplet and Dokku. We all love Heroku and the way it works, but as convenient as Heroku is, it doesn't always make sense for freelancers and those of us who want to put a few sites online with no real means to monetize them - even at Heroku's cheapest price point. That is where it is great to have options like a Digital Ocean, DreamHost, UpCloud, Linode, Vultr, or Kamatera.
Check them all out. They are all very similar but some might have a few nuances that you like better. This tutorial would be similar for all of them save for a few differences. I, in fact, have spun up servers on most all of them just to see what they were about and which ones I found easiest. Digital Ocean is at the top of the list for ease, so that's the one I am using.
I also went through several other tutorials about running Dokku and while all good, all seem to leave out a piece or two. So this aims to bring all of it together for a more complete guide. So let's get started.
This goes without saying. Sign up for Digital Ocean and put your credit card details in. They will only charge you for what you use. But you will need a credit card to get started.
The next step is to start a new project which can hold a droplet or many droplets for that matter. I named my project, aptly, "Railscoder." You can fill in the other details about your project as you wish.
You need to create a droplet in your project. While Digital Ocean has predefined droplet for Dokku, do not use this one. Create a new droplet with just the Ubuntu 18.104.22.168 distribution. That way we can get the latest version of Dokku and install it ourselves.
I chose the cheapest setup ($5 a month) and picked Toronto as my datacenter region (simply because I am huge Maple Leafs fan, so why not). You may want to pick a region that is close to you in proximity, although I have not noticed any latency between Toronto and Denver where I am.
You'll also want to set up SSH Keys to administer the server. Once you have an SSH key on file with Digital Ocean, you'll be able to just select that key with any new droplet.
You will get an ipv4 address once your server is started. You will need to create an A record in your DNS entry wherever you have your domain hosted. I, personally use Google Domains and it's as simple as choosing a custom resource record, setting the resource to A and then adding your new IP address. It will look similar to below.
NOTE: Be sure to add "www", as well, to a CNAME record pointing to your domain - that way your domain will resolve correctly using either "http://example.com" or "http://www.example.com". It also will have implications later when we get to adding the encryption certificate.
Open your terminal and SSH into the server:
$ ssh [email protected]<server ip from droplet>
Now, let's get the latest version of Dokku on the server:
# SSH terminal to droplet server # for debian systems, installs Dokku via apt-get wget https://raw.githubusercontent.com/dokku/dokku/v0.20.4/bootstrap.sh; sudo DOKKU_TAG=v0.20.4 bash bootstrap.sh
This was the latest version at the time of this writing. Check here to see if there is an update.
After it finishes, you need to go to your browser to finish the setup. And do this right away or it could expose security vulnerabilities.
In your browser, go to the droplet IP.
You should see you SSH Key listed that you already configured when setting up your account.
The only thing you should need to change is the "Hostname Configuration." In my case, I added my hostname "railscoder.com". I also checked that I wanted to use virtualhost naming for apps. That would mean apps on the domain would look like this: "example.railscoder.com".
Now, since we're using the smallest droplet which does not have a ton of RAM or other resources, let's enable swap to better handle deployments so we don't error out from not having enough resources.
Enable swap with following commands:
# SSH terminal to droplet server sudo fallocate -l 4G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile sudo sh -c 'echo "/swapfile none swap sw 0 0" >> /etc/fstab'
Let's get the application set up on the server. Just replace "myapp" with your app name.
# SSH terminal to droplet server dokku apps:create myapp
Add Heroku buildpacks. This will avoid setting up any dependencies manually.
# SSH terminal to droplet server dokku buildpacks:add myapp https://github.com/heroku/heroku-buildpack-nodejs.git dokku buildpacks:add myapp https://github.com/heroku/heroku-buildpack-ruby.git # Add this if you plan on using Active Storage dokku buildpacks:add myapp https://github.com/heroku/heroku-buildpack-activestorage-preview
Set up ENV variables on the server:
# SSH terminal to droplet server dokku config:set myapp RAILS_ENV=production dokku config:set myapp RAILS_MASTER_KEY=<master_key_from_app>
Your master key will be located in a file called "master.key" in your app's config folder.
Get Postgres up and running:
# SSH terminal to droplet server dokku plugin:install https://github.com/dokku/dokku-postgres.git dokku postgres:create myapp_db
Link Postgres DB to app:
# SSH terminal to droplet server dokku postgres:link myapp_db myapp
You need to add a file called ".procfile" to the root of your app. The declarations in the file tell the app which processes should be running once your app is deployed.
In the procfile, add these lines:
# add to .procfile # this tells the app upon deployment to run Puma to serve the app web: bundle exec puma -C config/puma.rb # add this line to automatically run migrations upon each deployment release: bundle exec rails db:migrate
Add Domain To The App: Examples for both top level domain or subdomain below.
# SSH to droplet server dokku domains:add myapp example.com dokku domains:add myapp www.example.com # If it were subdomain dokku domains:add myapp myapp.example.com dokku domains:add myapp www.mayapp.example.com
Acquire SSL Encryption and Certificate:
# SSH to droplet server dokku plugin:install https://github.com/dokku/dokku-letsencrypt.git dokku config:set --no-restart myapp DOKKU_LETSENCRYPT_EMAIL=[email protected] dokku letsencrypt myapp # Add cron job so certificate automatically renews dokku letsencrypt:cron-job --add myapp
Definitely add the cron job. Let's Encrypt's certificates are only valid for 3 months, so you will want to have the cron job handle getting the new one automatically to keep your domain from experiencing any disruptions.
Almost ready to roll. Now, we just need to add a remote repository.
Add Remote Repository
# Terminal within your app folder git remote add dokku [email protected]_ADDRESS:myapp
With this setup, it is using the IP Address. If you domain is resolving already and correctly, you could use "myapp.com:myapp" for example. But for now, I will just stick with the IP address.
Deploy app just like you would on Heroku but with Dokku:
# Terminal within your app folder git push dokku master
Dokku runs one instance of web process by default. You can up that by using this command.
# SSH to droplet server dokku ps:scale myapp web=2
You should be good to go and if you enabled swap, your experience should be as smooth as using Heroku, just as mine has been.
Going forward, after you commit changes in git inside your app, all you should need to do is to run the "git push dokku master" command and your site will deploy the latest version.