This is a step by step tutorial that will walk you through setting up a Ruby on Rails application through Docker and Dokku on Digital Ocean.
Digital Ocean account. If you don't already have one you can sign up for a digital ocean account.
Step 1: Create a digital ocean droplet
If you have a real domain available use that as your hostname.
Select the dokku app from the list of applications.
Add your SSH key and create the droplet.
Step 2: Set up a Custom Domain (Optional)
Dokku is your own personal Heroku. If you are familiar with Heroku you know that it runs apps on the domain
herokuapp.com. So if you deploy an app called
hello it will be accessible at
When you set up dokku, you can create your own app domain.
In your DNS settings create the following two
apps.yourdomain.com ---> ip of the droplet *.apps.yourdomain.com ---> ip of the droplet
This means that if you deploy an app called
hello it will be accessible at
hello.apps.yourdomain.com. Of course, you can customize this and skip the
apps subdomain if you wish.
Step 3: Use
/etc/hosts instead of Custom Domain
It can take a while for the DNS records to propagate. Usually it's less than an hour, but Digital Ocean's DNS settings page warns that it can take up to 24 hours. If you don't want to set up your own domain for the dokku or if you don't want to have to wait for the DNS to propagate you can set up a 'fake' DNS entry in your
# /etc/hosts 22.214.171.124 apps.yourdomain.com
Where 126.96.36.199 is the IP of your digital ocean droplet.
Step 4: Dokku VHOST configuration
We need to check that the domain is configured properly on Dokku. The docs explain that if the hostname cannot be resolved at the time you create your dokku image, the domain may not be set.
To check if the domain was set, log in to your droplet as root. ``` ssh firstname.lastname@example.org ```
You should not need to enter a password because the droplet is set up to use public key authentication.
Once you're logged in, let's check if the VHOST file exists in
cd /home/dokku ls
In my case, the VHOST file was not there. This was causing dokku to ask me for the
dokku user's password when I tried to deploy the app.
root@apps:/home/dokku# ls HOSTNAME VERSION
If you do not see the VHOST file, you need to create it.
echo \"apps.yourdomain.com\" > /home/dokku/VHOST chown dokku:root /home/dokku/VHOST
Add your development box's public key to the dokku user. This will allow you to push code without needing a password (sets up public key authentication).
cat ~/.ssh/id_rsa.pub | ssh email@example.com \"sshcommand acl-add dokku dokku\"
Step 5: Install postgres
Let's use the [dokku-pg-plugin](https://github.com/Kloadut/dokku-pg-plugin postgresql).
From your remote server:
cd /var/lib/dokku/plugins git clone https://github.com/Kloadut/dokku-pg-plugin postgresql dokku plugins-install
If you get any nginx-related errors, see the Troubleshooting section below.
Now you should have a few extra pg commands available through dokku:
root@apps:~# dokku help postgresql:console <db> Open a PostgreSQL console postgresql:create <db> Create a PostgreSQL container postgresql:delete <db> Delete specified PostgreSQL container postgresql:dump <db> > dump_file.sql Dump database data postgresql:info <db> Display database informations postgresql:link <app> <db> Link an app to a PostgreSQL database postgresql:list Display list of PostgreSQL containers postgresql:logs <db> Display last logs from PostgreSQL container postgresql:restore <db> < dump_file.sql Restore database data from a previous dump
Install the postgresql client so you can access the database.
From the remote server run:
apt-get install postgresql-client-9.3
Step 6: Create the database
On the remote server run:
dokku postgresql:create -----> Creating /home/dokku/daffy/ENV -----> Setting config vars and restarting daffy DATABASE_URL: postgres://root:firstname.lastname@example.org:49155/db -----> Releasing daffy ... -----> Release complete! -----> Deploying daffy ... -----> Checking status of PostgreSQL Found image postgresql/daffy database Checking status... ok. -----> Deploy complete! -----> daffy linked to postgresql/daffy database -----> PostgreSQL container created: postgresql/daffy Host: 188.8.131.52 Port: 49155 User: 'root' Password: 'supersecret' Database: 'db' Url: 'postgres://root:email@example.com:49155/db'
Now run this command to set the environment variable
DATABASE_URL that will be used in your Rails application's
dokku postgresql:link <app-name> <database-name>
Step 7: App Setup
Set up your app as you would for a Heroku deployment.
Make sure you have a Procfile in your git repo. I am using puma so my Procfile looks like this:
web: bundle exec puma -C config/puma.rb
You can read more about Procfiles here.
Test your production setup on your local machine first. Foreman is a program that reads your Procfile and launches your application.
If you don't have foreman installed, you can install it by running
gem install foreman.
Add git remote
Add your dokku remote to your git repo.
git remote add dokku firstname.lastname@example.org:<app-name>
Set up config/database.yml
On Heroku, they inject a custom
config/database.yml into the app. In many projects database.yml gitignored.
On dokku you will have to make sure
config/database.yml is in your repo (not gitignored) and it contains the following for the production environment:
production: adapter: postgresql url: <%= ENV['DATABASE_URL'] %> encoding: unicode pool: 5
Sidenote: If you want to keep
config/database.yml gitignored there are some things you can do, but I'm not going to go into that here. Hint: If you're using Puma you can play around with
Step 8: Deploy
Exciting! Time to deploy. You deploy dokku apps the same way you would on Heroku.
Push the master branch to dokku.
git push dokku master
This should trigger the deployment.
Counting objects: 2023, done. Delta compression using up to 4 threads. Compressing objects: 100% (1236/1236), done. Writing objects: 100% (2023/2023), 1.53 MiB, done. Total 2023 (delta 1155), reused 1141 (delta 705) -----> Cleaning up ... -----> Building daffy ... remote: Cloning into '/tmp/tmp.P2f4h7p5tB'... remote: warning: You appear to have cloned an empty repository. remote: done. remote: HEAD is now at 606a3a2... Merge branch 'develop' -----> Ruby app detected -----> Compiling Ruby/Rails -----> Using Ruby version: ruby-2.0.0 -----> Installing dependencies using 1.6.3 Running: bundle install --without development:test --path vendor/bundle --binstubs vendor/bundle/bin -j4 --deployment Fetching gem metadata from https://rubygems.org/......... Installing i18n 0.6.9 Installing rake 10.3.2 Installing minitest 5.3.4 Installing thread_safe 0.3.4 Installing builder 3.2.2 Installing erubis 2.7.0 Installing json 1.8.1 Installing rack 1.5.2 Installing mime-types 1.25.1 Installing polyglot 0.3.4 Installing arel 184.108.40.20640414130214 Installing c3-rails 0.3.0 Installing coffee-script-source 1.7.0 Installing execjs 2.0.2 Installing multi_json 1.10.0 Installing thor 0.19.1 Installing request_store 1.1.0 Installing hike 1.2.3 Using bundler 1.6.3 Installing rack-cors 0.2.9 Installing tilt 1.4.1 Installing temple 0.6.7 Installing rack-test 0.6.2 Installing tzinfo 1.2.0 Installing treetop 1.4.15 Installing coffee-script 2.2.0 Installing sprockets 2.11.0 Installing slim 2.0.2 Installing puma 2.8.1 Installing mail 2.5.4 Installing activesupport 4.1.1 Installing activemodel 4.1.1 Installing actionview 4.1.1 Installing activerecord 4.1.1 Installing actionpack 4.1.1 Installing actionmailer 4.1.1 Installing railties 4.1.1 Installing gon 5.2.0 Installing sprockets-rails 2.1.3 Installing coffee-rails 4.0.1 Installing d3_rails 3.4.11 Installing jquery-rails 3.1.0 Installing slim-rails 2.1.4 Installing turbolinks 2.2.2 Installing rails 4.1.1 Installing pg 0.17.1 Your bundle is complete! Gems in the groups development and test were not installed. It was installed into ./vendor/bundle Bundle completed (23.01s) Cleaning up the bundler cache. Detected manifest file, assuming assets were compiled locally ###### WARNING: Include 'rails_12factor' gem to enable all platform features See https://devcenter.heroku.com/articles/rails-integration-gems for more information. ###### WARNING: You have not declared a Ruby version in your Gemfile. To set your Ruby version add this line to your Gemfile: ruby '2.0.0' # See https://devcenter.heroku.com/articles/ruby-versions for more information. -----> Discovering process types Procfile declares types -> web Default process types for Ruby -> rake, console, web, worker -----> Releasing daffy ... -----> Deploying daffy ... =====> Application deployed: http://daffy.apps.yourdomain.com To email@example.com:daffy * [new branch] master -> master
Step 9: Set up the database
From the remote server, let's create and migrate the database.
dokku run <app-name> rake db:create dokku run <app-name> rake db:migrate dokku run <app-name> rake db:seed
Restart the app.
docker restart <docker-container-id>
To find the container id you can run
docker ps -a.
You're done! Go visit your app url.
If anything goes wrong at this point, check out the Troubleshooting section below.
Dokku documentation - http://progrium.viewdocs.io/dokku/index
Error while Compiling Ruby/Rails
-----> Compiling Ruby/Rails ! ! Command: 'set -o pipefail; curl --fail --retry 3 --retry-delay 1 --connect-timeout 30 --max-time 30 https://s3-external-1.amazonaws.com/heroku-buildpack-ruby/cedar-14/ruby-2.1.0.tgz -s -o - | tar zxf - ' failed unexpectedly: ! ! gzip: stdin: unexpected end of file ! tar: Child returned status 1 ! tar: Error is not recoverable: exiting now !
This error means that you are using an unsupported version of ruby in your Gemfile. Dokku seems to be using the Heroku Cedar buildpacks, so you need to use one of the ruby versions supported by Heroku. Other versions might be support which are not listed on this page. For example,
2.1.2 works as of the writing of this article. Anyway, choose a version that makes sense for your app.
502 Bad Gateway
You visit your app url and gasp you get a
502. This means your Rails server did not start or there is some other reason why nginx can't reach your app.
To find out what went wrong, let's look at the logs
docker logs -f a1b2c3d4e5f6
a1b2c3d4e5f6 is your container id. You can find your container id by running
docker ps -a.
In my case, I was missing the config/database.yml file in my Rails app.
If you are not sure if your Rails server is running, you can try accessing it from within the remote server:
curl http://127.0.0.1:`cat /home/dokku/<app-name>/PORT`
dokku plugins-install I got a bunch of errors that culminated in
dpkg: error processing package nginx-full (--configure): dependency problems - leaving unconfigured
After a bit of googling someone suggested reinstalling nginx.
apt-get update apt-get remove nginx
When prompted, choose
N to keep the version of
/etc/nginx/nginx.conf that was configured when dokku was installed.
This fixed things and I was able to run
dokku plugins-install successfully.
It looks like there have been some significant changes to the nginx-vhosts dokku plugin. Hopefully this fixed the issue.