> ## Content Index
> Fetch the complete content index at: https://blog.mebooks.co.nz/llms.txt
> Use this file to discover other available public pages before exploring further.

# Setting Up Your Own PAAS Using Dokku
- URL: https://blog.mebooks.co.nz/setting-up-your-own-paas-using-dokku/
- Published: 2016-02-25T03:29:00.000Z
- Updated: 2017-10-01T03:31:04.000Z
- Author: Jason Darwin
- Tags: #Import 2026-09-23 10:11

These are notes about how we setup Dokku on EC2 with [Vagrant](https://www.vagrantup.com/?ref=blog.mebooks.co.nz), [Docker](http://docker.com/?ref=blog.mebooks.co.nz) and [Dokku](http://dokku.viewdocs.io/dokku/?ref=blog.mebooks.co.nz).

> Note: an earlier version of this post mentioned that the maintainers of Dokku worked at Deis, however that's incorrect — previously Deis sponsored the project, but this has now finished, and none of the maintainers work at or have worked at Deis.

> Also, it appears that a custom Buildpack is no longer needed for releasing a static site (though use of the plugin mentioned below won't break the deploy)

## What is Dokku?

[Dokku](http://dokku.viewdocs.io/dokku/?ref=blog.mebooks.co.nz) allows us to spin up our own Platform-as-a-Service (PaaS) and create a [Heroku-style](https://heroku.com/?ref=blog.mebooks.co.nz) environment that's cheap, and that we can easily deploy to simply by performing a `git push`.

Under the covers, Dokku uses Nginx to serve sites, creating a reverse proxy Nginx config for each app that we deploy. Dokku also installs a command-line tool that allows us to configure and stop / start our applications.

We can deploy apps written using a range of technologies, including Node.js, PHP, Ruby-on-rails, and even static sites, and Dokku supports a variety of mechanisms to determine how to deploy an app, including:

- the presence of a `package.json` file, letting Dokku know that it's dealing with a node.js app
- Procfiles
- Docker files
- Heroku-style Buildpacks

## Dokku versus Dokku-alt

Our approach described below is based on [the tutorial by Alex MaCaw at ClearBit](http://blog.clearbit.com/ec2-heroku/?ref=blog.mebooks.co.nz), but we'll amend this to use [Dokku](http://dokku.viewdocs.io/dokku/?ref=blog.mebooks.co.nz) rather than [Dokku-alt](https://dokku-alt.github.io/?ref=blog.mebooks.co.nz).

Dokku-alt arose because people wanted Dokku installed complete with a range of verified plugins, and because the Dokku project wasn't being maintained after the founder, Jeff Lindsay, stepped aside.

However, the situation has now reversed, with Dokku receiving active support from it's new maintainers, and Dokku-alt now a number of versions behind Dokku.

Jeff Lindsay described his experience with [stepping aside from Dokku](http://progrium.com/blog/2015/12/04/leadership-guilt-and-pull-requests/?ref=blog.mebooks.co.nz) and he left the new maintainers a [roadmap for future development](https://github.com/dokku/dokku/wiki/Refactoring?ref=blog.mebooks.co.nz) which the maintainers have been following.

Recent Dokku features include:

- [zero-downtime deployment](http://dokku.viewdocs.io/dokku/checks-examples/?ref=blog.mebooks.co.nz#zero-downtime-deploys), with Dokku waiting a configurable amount of time before routing traffic to from your old container to your newly-deployed container
- an increasing [range of plugins](http://dokku.viewdocs.io/dokku/plugins/?ref=blog.mebooks.co.nz#official-plugins-beta)
- the ablity to specify [deploy-time checks](http://dokku.viewdocs.io/dokku/checks-examples/?ref=blog.mebooks.co.nz#checks-examples) (such as text appearing at a given URL) to ensure that  
the deploy worked correctly
- the ability to rename a deployed app

## Amazon EC2 instance setup

We presume that you've already setup an AWS account, and have retrieved your `AWS_ACCESS_KEY_ID` and your `AWS_SECRET_ACCESS_KEY`.

We need to create our [EC2 keypair](https://console.aws.amazon.com/ec2/v2/home?ref=blog.mebooks.co.nz#KeyPairs:) as `aws`, and save the `aws.pem` to `~/.ssh/aws.pem`.

Then, we create our [EC2 Security Group](https://console.aws.amazon.com/ec2/v2/home?ref=blog.mebooks.co.nz#SecurityGroups:) as `production`, adding the rules to allow incoming traffic from port 22 (SSH) and port 80 (HTTP).

Next, set environment variables for our `AWS_ACCESS_KEY_ID` and our `AWS_SECRET_ACCESS_KEY`:

```
export AWS_ACCESS_KEY_ID=WHATEVER
export AWS_SECRET_ACCESS_KEY=WHICHEVER

```

These can be set in a `.bash_profile` or similar.

Create a new `t2.micro` instance — in our case we'll use the region `ap-southeast-2`.  
Then, in the AWS dashboard, access the instance, and check the public IP address, which we'll need later to set our DNS:

```
52.62.179.58

```

Note that, depending on the apps you'll be deploying, you may need to upgrade to a larger EC2 instance.

Now, we need to determine the AMI instance to use. Use the [Amazon EC2 AMI Locator](http://cloud-images.ubuntu.com/locator/ec2/?ref=blog.mebooks.co.nz)  
to determine the correct ami-id — scroll down to the bottom of the locator and use the dropdowns to filter the available instances.

We'll need one that has:

- region: ap-southeast-2
- version: 14.04 LTS
- instance type: hvm:ebs

Originally, when I ran the `Vagrantfile` below, I received the following message:

```
InvalidParameterValue => Value () for parameter groupId is invalid

```

The problem turned out to be that I was specifying an `aws.ami` id that was not valid for the specified `aws.region` — using the [Amazon EC2 AMI Locator](http://cloud-images.ubuntu.com/locator/ec2/?ref=blog.mebooks.co.nz) allowed me to find a suitable AMI id.

Add an entry accordingly to our `/etc/hosts` file — here we presume we'll be using the domain `dokku.me`, as we'll be using our hosts file to specify our DNS, but you can use a real (i.e. registered) domain if you'd like to make your dokku box accessiable via the public web.

```
52.62.179.58	dokku.me

```

## Vagrant setup

Install the [vagrant plugin for aws](https://github.com/mitchellh/vagrant-aws?ref=blog.mebooks.co.nz):

```
vagrant plugin install vagrant-aws

```

We'll retrieve the following `Vagrantfile`:

```
curl https://gist.githubusercontent.com/jcdarwin/e1991320f1c4f3d1db2f/raw/d5e2796a3c632ec63e8a503501ead7af5744d6c2/Vagrantfile > Vagrantfile

```

Our `Vagrantfile` is as follows:

```
Vagrant::configure('2') do |config|
	config.vm.define :dokku, autostart: false do |box|
		box.vm.box      = 'trusty'
		box.vm.box_url  = 'https://github.com/mitchellh/vagrant-aws/raw/master/dummy.box'
		box.vm.hostname = 'dokku.me'

		box.vm.provider :aws do |aws, override|
			aws.access_key_id     = ENV['AWS_ACCESS_KEY_ID']
			aws.secret_access_key = ENV['AWS_SECRET_ACCESS_KEY']
			aws.keypair_name      = 'aws'

			# As per the Amazon EC2 AMI Locator
			aws.ami               = 'ami-4f32142c'
			aws.region            = 'ap-southeast-2'
			aws.instance_type     = 't2.micro'

			# Customize this to the id of the security group you're using
			aws.security_groups   = 'production'

			# To mount EBS volumes
			aws.block_device_mapping = [
				{
					:DeviceName => "/dev/sdb",
					:VirtualName => "ephemeral0"
				},
				{
					:DeviceName => "/dev/sdc",
					:VirtualName => "ephemeral1"
				}
			]

			override.ssh.username = 'ubuntu'

			# Customize this to your AWS keypair path
			override.ssh.private_key_path = '~/.ssh/aws.pem'
		end

		# To make sure we use EBS for our tmp files
		box.vm.provision "shell" do |s|
			s.privileged = true
			s.inline = %{
				mkdir -m 1777 /mnt/tmp
				echo 'export TMPDIR=/mnt/tmp' > /etc/profile.d/tmpdir.sh
			}
		end

		# To make sure packages are up to date
		box.vm.provision "shell" do |s|
			s.privileged = true
			s.inline = %{
				export DEBIAN_FRONTEND=noninteractive
				apt-get update
				apt-get --yes --force-yes upgrade
			}
		end

		# Install dokku as per http://dokku.viewdocs.io/dokku/getting-started/install/debian/
		box.vm.provision "shell" do |s|
			s.privileged = true
			s.inline = %{
				export DEBIAN_FRONTEND=noninteractive

				echo "install prerequisites"
				sudo apt-get update -qq > /dev/null
				sudo apt-get install -qq -y apt-transport-https

				echo "setup unattended installation"
				echo "dokku dokku/vhost_enable boolean true" | sudo debconf-set-selections
				echo "dokku dokku/hostname string dokku.me" | sudo debconf-set-selections

				echo "install docker"
				sudo apt-get install lxc wget bsdtar curl
				sudo apt-get install linux-image-extra-$(uname -r)
				sudo modprobe aufs
				sudo usermod -aG docker ubuntu
				wget -nv -O - https://get.docker.com/ | sh

				echo "install dokku"
				wget -nv -O - https://packagecloud.io/gpg.key | apt-key add -
				echo "deb https://packagecloud.io/dokku/dokku/ubuntu/ trusty main" | sudo tee /etc/apt/sources.list.d/dokku.list
				sudo apt-get update -qq -y > /dev/null
				sudo apt-get install -qq -y dokku
				sudo dokku plugin:install-dependencies --core
                sudo dokku plugin:install https://github.com/dokku/dokku-letsencrypt.git
			}
		end
	end
end

```

Note that our `box_url` is a blank Vagrant box to coax Vagrant into working with AWS — we can add our box manually:

```
vagrant box add dummy https://github.com/mitchellh/vagrant-aws/raw/master/dummy.box

```

Inspect the metadata:

```
cat ~/.vagrant.d/boxes/dummy/0/aws/metadata.json

```

We should see something like:

```
{
    "provider": "aws"
}

```

## Create our EC2 instance using Vagrant

Start up our VM:

```
vagrant up dokku --provider=aws

```

Our `Vagrantfile` will create the EC2 instance, and run the provisioning script.

Once Vagrant finishes provisioning the box, you should be able to ssh into it using Vagrant:

```
vagrant ssh dokku

```

Note that if you experience any problems with the provisioning, you may need to check that Dokku and the core plugins installed correctly:

```
sudo apt-get install dokku
sudo dokku plugin:install-dependencies --core

```

While in our box, change `/home/dokku/HOSTNAME` and `/home/dokku/VHOST` from the Amazon-generated name (e.g. `ip-172-31-3-31.ap-southeast-2.compute.internal`) to our domain:

```
dokku.me

```

We can now `exit` from our ssh session.

## Complete Dokku setup

We should now be able to finish the Dokku setup using Dokku's web interface at [http://dokku.me](http://dokku.me/?ref=blog.mebooks.co.nz)

- change our hostname from the IP address to our domain: `dokku.me`
- choose `Use virtualhost naming for apps`

## Setup direct ssh access

We want to be able to ssh into our box without relying on Vagrant.

First, register our normal public key with our box:

```
cat ~/.ssh/id_rsa.pub | vagrant ssh dokku -- sudo sshcommand acl-add dokku ${USER}

```

Check the ssh config for our box:

```
vagrant ssh-config dokku

Host dokku
  HostName ec2-52-62-179-58.ap-southeast-2.compute.amazonaws.com
  User ubuntu
  Port 22
  UserKnownHostsFile /dev/null
  StrictHostKeyChecking no
  PasswordAuthentication no
  IdentityFile /Users/jasondarwin/.ssh/aws.pem
  IdentitiesOnly yes
  LogLevel FATAL

```

We can use the reported `HostName` for direct ssh access to our box:

```
# This will print out the Dokku help menu
ssh dokku@ec2-52-62-179-58.ap-southeast-2.compute.amazonaws.com

# We can run commands over ssh
ssh dokku@ec2-52-62-179-58.ap-southeast-2.compute.amazonaws.com version

```

## Deploy our app

We'll use the [heroku node-js-sample app](https://github.com/heroku/node-js-sample?ref=blog.mebooks.co.nz) to prove that we can deploy an app to our dokku box:

```
# Clone the repo
git clone https://github.com/heroku/node-js-sample
cd node-js-sample

# Add our Dokku box as a remote:
git remote add dokku dokku@ec2-52-62-179-58.ap-southeast-2.compute.amazonaws.com:<our app name>

# Push our repo to our box and set off the deploy
git push dokku master

```

Add an entry to our hosts file for our app:

```
52.62.179.58	node-js-sample.dokku.me

```

We should now be able to access our app at [http://node-js-sample.dokku.me](http://node-js-sample.dokku.me/?ref=blog.mebooks.co.nz)

```
dokku config:set --no-restart node-js-sample DOKKU_LETSENCRYPT_EMAIL=<email>
dokku letsencrypt node-js-sample

```

More notes about application deployments can be found in [the Dokku documentation](http://dokku.viewdocs.io/dokku/application-deployment/?ref=blog.mebooks.co.nz).

## Further

- Dokku has support for [plugins](https://github.com/progrium/dokku/wiki/Plugins?ref=blog.mebooks.co.nz) which allow  
functionality such as database setup and access.
- Note also that web applications, like the sample nodejs app, are expected to be exposed through port 5000 unless an environment variable is specified.
- We can use [Florian Heinemann's custom buildpack](https://www.florianheinemann.com/github/dokku/2014/11/17/Hosting-static-pages-on-Dokku.html?ref=blog.mebooks.co.nz) to deploy a static site.
- Note that we can run docker directly on our box, e.g.  
vagrant ssh dokku  
docker run hello-world
- Check the [Dokku docs](http://dokku.viewdocs.io/dokku/installation/?ref=blog.mebooks.co.nz) for further information