Deploying Rails 6.0.1 app on Digitalocean VPS using Dokku 0.19.10. Following Alan Vardy's blog post and video presentation on Youtube. Dokku also uses dokku-postgres to handle the database.
app versions are indicated at the time of this writing (Dec. 9, 2019)
For testing I used Freenom which is you guessed, free domain hosting. Alan uses Namecheap and is proud about it.
One of the best and cheapest VPS hosting you can find out there.
First time creating ssh keys? learn how
You can create a droplet (virtual private server) with Dokku pre-installed! When creating a droplet, select the Marketplace and look for Dokku, add your SSH keys and for testing you can select the lowest and cheapest plan.
Note: If working on Cloud IDE like Cloud9 do your ssh-keygen on your Cloud9 project terminal then copy your id_rsa.pub file contents, this will serve as your IDE's ssh key to access the droplet. It is usually located on root/.ssh/id_rsa.pub, you can try using:
cat /.ssh/id_rsa.pub
Navigate to your droplet's IP address which will be listed in digitalocean. You will need to paste in your public ssh key, then make sure to check "Virtual host naming" for your apps. It means that if you create an app called myapp, it will be accessible at myapp.mydomain.com
This will be important as dokku will generate url based on what you put on Hostname field such as myapp.mydomain.com where mydomain.com is the hostname. It is possible to change hostnames after installation but I would just recommend to rebuild the app completely if you are changing hostnames. TIP: you can also use IP address instead of domain. If you decide to use a domain name, Dokku will generate url base on the domain but if you choose to put IP on Hostname field it will only generate using the IP. This is good if you are expecting to change domain name sooner or later.
ssh root@your.droplet.ip.address
6. Update everything (Digital Ocean's droplets will not be completely up to date, and Dokku can easily be a few versions behind)
apt update && apt upgrade
dokku apps:create yourappname
dokku plugin:install https://github.com/dokku/dokku-postgres.git postgres
dokku postgres:create yourdbname
dokku postgres:link yourdbname yourappname
fallocate -l 2G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
vi /etc/fstab
/swapfile none swap sw 0 0
- Press "i" to enter edit mode.
- Press "esc" after finish adding the line to exit edit mode
- Press "shift+:" then type "wq" to write file and quit editor
Click Add domain on digitalocean then add the domain you have got freely on freenom or bought on namecheap. Create 'A' record for your domain:
Type | Hostname | Value |
---|---|---|
A | yourdomain.com | (select your droplet) |
rails new yourrailsapp --database=postgresql
cd awesomeapp
rails generate controller Static index
- Here we got a controller name Static with index method
- Add something to that index page in app/views
- then add the route to config/routes.rb
root 'static#index'
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"
}
}
}
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.
# config/secrets.yml
production:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
- on Rails 6 we now also have encryption for the secret key base file in the form of the master.key file which decrypts the file called credentials.yml.enc that holds your secret_key_base
- the 2 file will be generated upon executing
rails new
command at the start of creating your rails app.
# config/database.yml
production:
adapter: postgresql
secret_key_base: <%= Rails.application.credentials.dig(:secret_key_base) %>
rails_master_key: <%= ENV['RAILS_MASTER_KEY'] %>
encoding: unicode
pool: 5
- It is recommended not to include your master.key when pushing to repo. By default it is included on .gitignorefile
- Without the master.key, the application won't run
- Locate ythe master key on same directory as credentials.yml.enc
config/master.key
then copy the hash string - Since it will not be included when pushing to our dokku vps, we will save it on ENV variable instead and access it from the variable. ssh to your droplet then run the following dokku command:
dokku config:set yourappname RAILS_MASTER_KEY=thehashstringfromyourmasterkeyfile
Note: In case you are using different PCs, better save the master.key file somewhere you can access for later use. You can include it on your .gitignore but that is a bad practice and will have more risk of being leaked.
If you are using Rails 6, take a look at this post to save yourself some headache in getting Puma up and running.
TL;DR You may have noticed the following lines to your /config/puma.rb file:
# Specifies the `pidfile` that Puma will use.
pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }
Puma's "pidfile", or process ID file, is where Puma stores the unique ID it uses while it's running. A server admin or another process on the system may use this number to check Puma's status or issue the process a kill command if necessary. Unfortunately, if the directory Puma wants to store this file doesn't exist, Puma won't start at all:
Errno::ENOENT: No such file or directory @ rb_sysopen - tmp/pids/server.pid
change the previous puma.rb code to this:
# Specifies the `pidfile` that Puma will use.
pidfile ENV.fetch("PIDFILE") { "server.pid" }
Creating this folder in your project repository isn't quite enough—and in fact, in your local repository, it's probably already there. The /tmp/ folder is added to /.gitignore by default, and for good reason: /tmp/ can be a dumping ground for temporary files and caches, and you usually don't want to commit these files. In order to ignore the files that should be ignored and still commit the above pidfile directory to your remote repository, you’ll need to add the following lines to your .gitignore file:
# Ignore all logfiles and tempfiles.
/log/*
/tmp/*
/tmp/pids/* # this line
!/log/.keep
!/tmp/.keep
!/tmp/pids # this line
!/tmp/pids/.keep # and this line
Navigate to your yourrailsapp project directory and add the remote repository, use either of the two below. Using the IP will bind your remote link to the IP address only, helpful in case of changing domains. Using the domain as remote link will bind the repo to the domain only.
git remote add dokku dokku@your.droplet.ip.address:yourappname
or
git remote add dokku dokku@your.domain.address:yourappname
TIP: list all remote links on your git repo
git remote
you can use the following git command to remove the remote link in case you are changing the IP or domain address:
git remote remove dokku
git add .
git commit -m 'Initialize repo'
git push dokku master
Let's Encrypt provides free SSL certificates. You can find more complete instructions and explanations here.
ssh root@your.droplet.ip.address
dokku plugin:install https://github.com/dokku/dokku-letsencrypt.git
- Update if it was already installed
dokku plugin:update letsencrypt
3. 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
dokku letsencrypt yourappname
dokku letsencrypt:cron-job --add