Dokku with Multiple Domains and Letsencrypt

Dokku is still my favourite deployment platform for my side projects. It's an easy fix for tons of different stacks, jammed onto one server (that doesn't have to deal with having the correct node or PHP version for anything).

If you aren't familiar with Dokku yet, have a look at the related articles at the bottom of this post.

Adding Domains

To add a domain to your site there's a built in domain module which makes it trivial.

When adding domains, make sure to deploy your app before you add a domain to it. This little note is in the docs:

Adding a domain before deploying an application will result in port mappings being set. This may cause issues for applications that use non-standard ports, as those will not be automatically detected. Please refer to the proxy documentation for information as to how to reconfigure the mappings.

dokku domains:add someapp example.com
dokku domains:set someapp example.com

This will add a domain to your domain pool and assing it to an app. You can see all assigned domains and their app affiliation by running dokku domains:report.

Enabling HTTPS with Letsencrypt

If you don't have a some sort of setup already, you can use a community plugin called dokku-letsencrypt which will handle the creation of certs, take care of making the challenges available and provide a command for you to easily renew all your certs.

Let's have a look at the following, assuming my apps name is "someapp"

dokku config:set --no-restart someapp DOKKU_LETSENCRYPT_EMAIL=jonathan@example.com
dokku letsencrypt someapp

The first line makes sure that Letsencrypt knows where to send emails of expiry and has a contact to reach, if you plan to sell home-cooked perscription meds over your HTTPS site ;)

In order to renew your certificates automatically, you can add a cronjob on your dokku host using crontab -e:

#!/bin/bash
5 5 * * * dokku letsencrypt:auto-renew >/dev/null 2>&1

This will run the auto-renew portion of the plugin and throw out the output of the tool. If you're curious you can write them to a file, but if something would be about to expire, I'd get an email anyways.

Troubleshooting: Undeployed Site Error

If you're running multiple domains, pointing to different apps, on your dokku host, you might run into the following error, for example when the deployment failed:

2018-03-06 16:10:59,415:ERROR:acme.challenges:324: Unable to reach http://example.com/.well-known/acme-challenge/uqjibber-y4totallynottherealthing-FCKSk_YsqgLQuyywE: HTTPSConnectionPool(host='example.com', port=443): Max retries exceeded with url: /.well-known/acme-challenge/uqDc2dLCm-y4what-FCKSk_isthis (Caused by SSLError(CertificateError("hostname 'example.com' doesn't match 'example.org'",),))

This happens when your nginx server serves up the first page it can find, instead of serving up the right domain and app.

This can be rather confusing, just be sure to check your domains point to the right thing and test the site is available in the non HTTPS version already.

Troubleshooting: Which Ports does my App use?

If you want to check out which ports your apps run on, you can use dokku proxy:report.

dokku proxy:report
=====> captain proxy information
       Proxy enabled:       true                     
       Proxy type:          nginx                    
       Proxy port map:      http:xxx:5000          
=====> xxx proxy information
       Proxy enabled:       true                     
       Proxy type:          nginx                    
       Proxy port map:      http:80:5000 https:443:5000
=====> trustedprovider proxy information
       Proxy enabled:       true                     
       Proxy type:          nginx                    
       Proxy port map:      http:80:5000 https:443:5000

Summary

Working with Dokku usually is a lot of fun. Sometimes it can be frustrating, but mostly it's your own fault. Writing apps that go into containers force you to be very specific about build steps. You need to know what needs to happen before the deployment can succeed. You need to add all dependencies.

For me, using one server for wildly different stacks without getting a migraine for working with different Node.js versions is reason enough for a deployment tool.

Tagged with: #Dokku #letsencrypt

Thank you for reading! If you have any comments, additions or questions, please tweet or toot them at me!