Deploying Ember apps on the cheap with Dokku, Docker and Digital Ocean.

April 18, 2017

The rough idea

With Ember we are spoiled with an excellent `ember-cli-deploy` tool. Need to deploy somewhere, you can go shopping for many of the supported deploy plugins. One company that has made deployment dead simple is Heroku. When I was looking to show off some local Ember apps I wanted something cheap and easy to setup. Heroku would be nice but I think we could go cheaper.

Enter Dokku. It’s project aimed at providing Heroku support by wrapping a docker heroku-friendly project called Herokuish. Dokku gives you a PAAS by wrapping containers with an nginx proxy router. It has
great settings and plugins that help you extend it for a number of use cases. Because Dokku can detect buildpacks and leverage herokuish we can deploy via a git push, using heroku buildpacks, and get a deployed container. With buildpacks you don’t actually need to know Docker or setup the container.

The last piece of the puzzle is Digital Ocean. It provides affordable virtual machine hosting with an easy to understand interface and luckily for us a one-click install of Dokku on a droplet.

With this rough outline let’s get started.

Create your Ember project

Feel free to skip this step if you’ve already got an ember project.

We’ll use a stock ember project.

  1. Go into a fresh folder, and run ember init
  2. Let’s make sure we’re tracking this in a git repo, run git init
  3. Let’s commit the empty ember project:
git add .
git commit -m "Init ember project"

Setup your digital ocean droplet

Now let’s get your Dokku digital ocean droplet going.

  1. Login to Digital Ocean.
  2. Click ‘create droplet’.
  3. Click the “One-click apps” tab.
    ScreenShot2017-04-17at11.47.02AM
  4. Choose Dokku 0.8.0 on 16.04
    ScreenShot2017-04-17at11.46.50AM
  5. Choose a size at $5/mo (let’s keep this cheap!)
  6. Pick your preferred region
  7. Add your ssh keys if you got them, it’ll make ssh’ing in easier.
  8. Pick 1 droplet, and pick a hostname if you like.
  9. That’s it! Click “Create”

Under Droplets, check that your droplet is being created.

ScreenShot2017-04-17at11.47.49AMScreenShot2017-04-17at11.48.26AM

You should get an IP address for your droplet, in my case it gave me 162.243.242.65. Go ahead and ssh into your newly created droplet.

ssh root@your.ip.address

Let’s make sure dokku is installed alright by running:

root@dokku-512mb-nyc2-01:~# dokku
Usage: dokku [--quiet|--trace|--rm-container|--rm|--force] COMMAND  [command-specific-options]

which should return with how to use dokku and available commands.

Setup Dokku

In your browser go to http://your.ip.address with “your.ip.address” being the IP address of your digital ocean droplet above.

You should see a screen similar to:

Screen Shot 2017-04-18 at 7.51.06 AM

Paste your public key which may be the same public key you use for things like github, unless you’ve generated a different one. It might have already filled it in if you had supplied digital ocean with a public key for the droplet. Make sure you have pasted something into the public key. This page is only available once after clicking “Finish Setup”. If you are trying to keep this cheap and plan on only using an IP address make sure you leave “virtualhost naming” unchecked.

If you ever need to change any of this configuration you can do so while ssh’ed into your droplet from the dokku command and pouring over the decently written dokku documentation. Or ask me on twitter, I might be able to help, too.

Click “Finish Setup” when everything is configured.

Gotchas

Before we continue let’s take care of a few gotchas.

Firewall

Your security concerns may differ but in order to not worry about the ports picked by dokku for the running applications I’m going to go ahead disable it.

root@dokku-512mb-nyc2-01:~# sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
22                         ALLOW       Anywhere
80                         ALLOW       Anywhere
443                        ALLOW       Anywhere
2375/tcp                   ALLOW       Anywhere
2376/tcp                   ALLOW       Anywhere
22 (v6)                    ALLOW       Anywhere (v6)
80 (v6)                    ALLOW       Anywhere (v6)
443 (v6)                   ALLOW       Anywhere (v6)
2375/tcp (v6)              ALLOW       Anywhere (v6)
2376/tcp (v6)              ALLOW       Anywhere (v6)

root@dokku-512mb-nyc2-01:~# sudo ufw disable
Firewall stopped and disabled on system startup

It’s not hard to manage the ports on ufw , if you’re interested you can check up on managing Ubuntu’s firewall.

Memory swap

During your build you may run into memory issues which prevent it from finishing. Since we’re going the cheap route I’m going to add some swap, but if you wanted to you could use a droplet with more memory.

root@dokku-512mb-nyc2-01:~# cd /var
root@dokku-512mb-nyc2-01:/var# touch swap.img
root@dokku-512mb-nyc2-01:/var# chmod 600 swap.img
root@dokku-512mb-nyc2-01:/var# dd if=/dev/zero of=/var/swap.img bs=1024k count=1000
1000+0 records in
1000+0 records out
1048576000 bytes (1.0 GB, 1000 MiB) copied, 2.98223 s, 352 MB/s
root@dokku-512mb-nyc2-01:/var# mkswap /var/swap.img
Setting up swapspace version 1, size = 1000 MiB (1048571904 bytes)
no label, UUID=469c4937-54d0-413c-a237-3bd7098c545b
root@dokku-512mb-nyc2-01:/var# swapon /var/swap.img

root@dokku-512mb-nyc2-01:/var# free
              total        used        free      shared  buff/cache   available
Mem:         500096       73912        8400        5108      417784      390492
Swap:       1023996           0     1023996
root@dokku-512mb-nyc2-01:/var#
root@dokku-512mb-nyc2-01:/var# echo "/var/swap.img    none    swap    sw    0    0" >> /etc/fstab

instructions via dokku advanced installation and digital ocean guides

Creating your app on dokku

While we are still ssh’ed into our digital ocean box let’s go ahead and setup the application on dokku.

root@dokku-512mb-nyc2-01:/var# dokku apps:create ember
Creating ember... done

Configure your Ember project for dokku

This is kind of the cool part. Because dokku can be treated like Heroku we can use the wonderful work the people at Heroku have done.

  1. First, let’s install ember-cli-deploy by running ember install ember-cli-deploy .
  2. Now install ember-cli-deploy-build by running ember install ember-cli-deploy-build . This is the basic build plugin that takes care of the build process upon deployment.
  3. package.json  will have been modified and config/deploy.js  added. Let’s commit these files.
    git add .
    git commit -m “Add ember-cli-deploy and build plugin”
  4. Dokku tries to do its best to automatically determine the heroku buildpack for a given application but given ours is Ember it needs a bit more setup than a regular node app. There are many different ways to specify the buildpack for an app with Dokku but I prefer setting the .buildpacks  file, because then it’s checked into git. In your project root run
    echo ”https://codon-buildpacks.s3.amazonaws.com/buildpacks/heroku/emberjs.tgz” >> .buildpacks
which should create a <span class="lang:default decode:true crayon-inline ">.buildpacks</span> file with the buildpack URL inside. If the file already existed the buildpack URL should be added to the bottom.</li> 

  * Commit your <span class="lang:default decode:true crayon-inline ">.buildpacks</span>  file <pre class="lang:default decode:true">git add .

git commit -m “Add .buildpacks with ember buildpack”

  * The last step is to tell our project where to deploy. Dokku follows the Heroku-easy model of just <span class="lang:default decode:true crayon-inline">git push</span> . So we will add our dokku digital ocean droplet by adding it to our git remotes by running <pre class="lang:default decode:true">git remote add dokku dokku@your.ip.address:ember</pre>
    
    With "your.ip.address" being your digital ocean droplet's IP address. Note: The user for the push is dokku, not root. After the IP address is a ":project-name", in our case it is "ember". So if you're curious the breakdown is:
    
    <pre class="lang:default decode:true">git remote add [git-remote-name] dokku@[ip-address]:[dokku-app-name]</pre>

  * The last step is to deploy, run <pre class="lang:default decode:true">git push dokku master</pre>
    
    You should see lots of scrolling text and after a 3-4 minutes you should see one of the last lines say.
    
    <pre class="lang:default decode:true">=====> Application deployed:
   http://your.ip.address:16523</pre>
    
    Again, with "your.ip.address" being your droplet's IP address.  
Screen Shot 2017-04-18 at 8.09.08 AM and there it is, we can see in the markup that we have an Ember application with our production build fingerprinted .js files. ## Bonus steps Who wants to remember a random port number? Not me. So let's go ahead and swap that for something we can choose. Login to your droplet via ssh. If we wanted to access it on port 80 we would do:
dokku config:set ember DOKKU_NGINX_PORT=80
dokku config:set ember DOKKU_PROXY_PORT_MAP=http:80:5000
Each command will reconfigure the nginx, and after the second command you should be able to access the application at the given port. ## That's all folks And that's it. Hopefully you were able to get your Ember application deployed. There are probably some easier solutions, like just using Heroku itself, but it's nice to know that there are options if you're on a budget. Also, this can scale with you for other projects across other platforms and help introduce you to the world of Docker. You can access any of the running containers that Dokku sets up for you which is pretty neat and great if you absolutely need to tail some logs or access the environment directly for debugging. ## Thanks Thanks to the developers at dokku, herokuish, heroku, and ember-cli-deploy. This was made pretty easy thanks to the work done by people from these projects. ✌🏽❤️