Deploying Ember apps on the cheap with Dokku, Docker and Digital Ocean.
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.
- Login to Digital Ocean.
- Click ‘create droplet’.
- Click the “One-click apps” tab.
- Choose Dokku 0.8.0 on 16.04
- Choose a size at $5/mo (let’s keep this cheap!)
- Pick your preferred region
- Add your ssh keys if you got them, it’ll make ssh’ing in easier.
- Pick 1 droplet, and pick a hostname if you like.
- That’s it! Click “Create”
Under Droplets, check that your droplet is being created.
You should get an IP address for your droplet, in my case it gave me 184.108.40.206. Go ahead and ssh into your newly created droplet.
Let’s make sure dokku is installed alright by running:
Usage: dokku [--quiet|--trace|--rm-container|--rm|--force] COMMAND <app> [command-specific-options]
which should return with how to use dokku and available commands.
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:
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.
Before we continue let’s take care of a few gotchas.
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
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.
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
total used free shared buff/cache available
Mem: 500096 73912 8400 5108 417784 390492
Swap: 1023996 0 1023996
root@dokku-512mb-nyc2-01:/var# echo "/var/swap.img none swap sw 0 0" >> /etc/fstab
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.
- First, let’s install ember-cli-deploy by running ember install ember-cli-deploy .
- 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.
package.json will have been modified and
config/deploy.js added. Let’s commit these files.
12git add .git commit -m "Add ember-cli-deploy and build plugin"
- 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
1echo "https://codon-buildpacks.s3.amazonaws.com/buildpacks/heroku/emberjs.tgz" >> .buildpacks
which should create a .buildpacks file with the buildpack URL inside. If the file already existed the buildpack URL should be added to the bottom.
- Commit your
12git 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
git push . So we will add our dokku digital ocean droplet by adding it to our git remotes by running
1git remote add dokku firstname.lastname@example.org:ember
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:
1git remote add [git-remote-name] dokku@[ip-address]:[dokku-app-name]
- The last step is to deploy, run
1git push dokku master
You should see lots of scrolling text and after a 3-4 minutes you should see one of the last lines say.
12=====> Application deployed:http://your.ip.address:16523
Again, with “your.ip.address” being your droplet’s IP address.
and there it is, we can see in the markup that we have an Ember application with our production build fingerprinted .js files.
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 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. ✌🏽❤️