├── .gitignore
├── tests
├── apps
│ ├── .go.disabled
│ │ ├── .godir
│ │ ├── Procfile
│ │ ├── check_deploy
│ │ └── web.go
│ ├── nodejs-express
│ │ ├── Procfile
│ │ ├── check_deploy
│ │ ├── package.json
│ │ └── web.js
│ ├── python-flask
│ │ ├── Procfile
│ │ ├── requirements.txt
│ │ ├── check_deploy
│ │ └── hello.py
│ └── php
│ │ ├── index.php
│ │ └── check_deploy
├── setup_travis
├── test_deploy
├── run_vagrant
└── run_ec2
├── .gitmodules
├── nginx-reloader.conf
├── HISTORY.md
├── nginx-app-conf
├── ROADMAP.md
├── receiver
├── dokku
├── AUTHORS
├── .travis.yml
├── Vagrantfile
├── deploystep
├── LICENSE
├── Makefile
├── .s3cfg
├── bootstrap.sh
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | .vagrant
2 |
--------------------------------------------------------------------------------
/tests/apps/.go.disabled/.godir:
--------------------------------------------------------------------------------
1 | go
2 |
--------------------------------------------------------------------------------
/tests/apps/.go.disabled/Procfile:
--------------------------------------------------------------------------------
1 | web: go
2 |
--------------------------------------------------------------------------------
/tests/apps/nodejs-express/Procfile:
--------------------------------------------------------------------------------
1 | web: bin/node web.js
2 |
--------------------------------------------------------------------------------
/tests/apps/python-flask/Procfile:
--------------------------------------------------------------------------------
1 | web: gunicorn hello:app
2 |
--------------------------------------------------------------------------------
/tests/apps/php/index.php:
--------------------------------------------------------------------------------
1 | php'; ?>
2 |
--------------------------------------------------------------------------------
/tests/apps/.go.disabled/check_deploy:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e; test "$(curl -s $1)" == "go"
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "buildstep"]
2 | path = buildstep
3 | url = https://github.com/progrium/buildstep.git
4 |
--------------------------------------------------------------------------------
/tests/apps/python-flask/requirements.txt:
--------------------------------------------------------------------------------
1 | Flask==0.9
2 | Jinja2==2.6
3 | Werkzeug==0.8.3
4 | gunicorn==0.17.2
5 |
6 |
--------------------------------------------------------------------------------
/tests/apps/python-flask/check_deploy:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e; output="$(curl -s $1)"; echo $output; test "$output" == "python/flask"
--------------------------------------------------------------------------------
/nginx-reloader.conf:
--------------------------------------------------------------------------------
1 | script
2 | echo | sudo -u git nc -l -U /home/git/reload-nginx && /etc/init.d/nginx reload
3 | end script
4 | respawn
--------------------------------------------------------------------------------
/tests/apps/nodejs-express/check_deploy:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e; output="$(curl -s $1)"; echo $output; test "$output" == "nodejs/express"
--------------------------------------------------------------------------------
/tests/apps/php/check_deploy:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e; output="$(curl -s $1)"; echo $output; test "$output" == "
php
"
--------------------------------------------------------------------------------
/tests/apps/python-flask/hello.py:
--------------------------------------------------------------------------------
1 | import os
2 | from flask import Flask
3 |
4 | app = Flask(__name__)
5 |
6 | @app.route('/')
7 | def hello():
8 | return 'python/flask'
9 |
--------------------------------------------------------------------------------
/HISTORY.md:
--------------------------------------------------------------------------------
1 | # History
2 |
3 | ## 0.1.0 (2013-06-15)
4 |
5 | * First release
6 | * Bootstrap script for Ubuntu system
7 | * Basic push / deploy with git
8 | * Hostname support with Nginx
9 | * Support for Java, Ruby, Node.js buildpacks
--------------------------------------------------------------------------------
/tests/apps/nodejs-express/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "node-example",
3 | "version": "0.0.1",
4 | "dependencies": {
5 | "express": "2.5.x"
6 | },
7 | "engines": {
8 | "node": "0.8.x",
9 | "npm": "1.1.x"
10 | }
11 | }
--------------------------------------------------------------------------------
/nginx-app-conf:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | APP="$1"; PORT="$2"; HOSTNAME="$3"
3 | cat< Building $APP ..."
7 | cat | $HOME/buildstep $CONTAINER
8 | echo "-----> Build complete!"
9 |
10 | echo "-----> Deploying $APP ..."
11 | $HOME/deploystep $APP $CONTAINER
12 | echo "-----> Application deployed:"
13 | echo " http://$(< "$HOME/$APP/HOSTNAME")"
14 | echo
--------------------------------------------------------------------------------
/dokku:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | case "$1" in
3 | logs)
4 | CONTAINER=$( ~/.ssh/id_rsa.pub
--------------------------------------------------------------------------------
/AUTHORS:
--------------------------------------------------------------------------------
1 | # This file lists all individuals having contributed content to the repository.
2 | # If you're submitting a patch, please add your name here in alphabetical order as part of the patch.
3 | #
4 | Felipe Coury
5 | Jeff Lindsay
6 | rhy-jot
7 | Richard North
8 | Leo Unbekandt
9 | Martin Weiss
10 | Silas Baronda
11 |
--------------------------------------------------------------------------------
/tests/test_deploy:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 | SELF=`which $0`; APP="$1"; TARGET="$2"
4 | TMP=$(mktemp -d -t "$TARGET.XXXXX")
5 | trap "rm -rf $TMP" EXIT
6 | rmdir $TMP && cp -r $(dirname $SELF)/$APP $TMP
7 | cd $TMP
8 | git init
9 | git config user.email "robot@example.com"
10 | git config user.name "Test Robot"
11 | git add .
12 | git commit -m 'initial commit'
13 | REPO="test-$(basename $APP)-$RANDOM"
14 | git remote add target git@$TARGET:$REPO
15 | git push target master
16 | ./check_deploy "$(ssh dokku@$TARGET url $REPO)" && echo "-----> Deploy success!"
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | ---
2 | script: cd tests && ./run_ec2 test
3 | before_install:
4 | - "sudo apt-get install -y ec2-api-tools"
5 | - "sudo apt-get install -y s3cmd"
6 | - "tests/setup_travis"
7 | env:
8 | global:
9 | - EC2_CERT=/tmp/cert
10 | - EC2_PRIVATE_KEY=/tmp/pk
11 | - secure: "flDyaNZ6Xn2W1JyI3N1DCzI+K7ACgAZJ38vVfSde6rmI/V2iaAR4YH+7PC/x\nb/uCW9JCl+IVq5DJ0vu59HkAXlV4i4S9gVDExygt/fAo+sfGiMWubRUZMZeC\nHKK+92kexmqGRJLU8s5wDakddMAZ4+y7QPfVdxAHp/Tuijq+9iE="
12 | - secure: "gSYrtzzmbwumE60J9sUhIaA5vakfXnP4NtCbxha0pyepPFrlds3YO0lxoH7J\nYdG8Yl5ObdqyDNQ2Yb/FL7wmctuPZSZ3OHQNjDpOqsqOqr7M2+b8aVM8URKE\n/Lki+GP8M8kajBr6zKgIV1W+e8SZQsAazhHwKRaJJQVWT58Aghk="
13 |
--------------------------------------------------------------------------------
/tests/run_vagrant:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | SELF=`which $0`
3 | VAGRANT_SSH_PORT=${$VAGRANT_SSH_PORT:-"2222"}
4 | PUBLIC_KEY=${PUBLIC_KEY:-"~/.ssh/id_rsa.pub"}
5 | indent() { sed "s/^/ /"; }
6 | if [[ ! $(cat ~/.ssh/config 2>/dev/null | grep dokku.me) ]]; then
7 | echo "-----> Configuring SSH to use $VAGRANT_SSH_PORT for dokku.me..."
8 | touch ~/.ssh/config
9 | echo "Host dokku.me" >> ~/.ssh/config
10 | echo " Port $VAGRANT_SSH_PORT" >> ~/.ssh/config
11 | fi
12 | echo "-----> Ensuring Vagrant is running..."
13 | cd "$(dirname $SELF)/.." && vagrant up | indent
14 | cat $PUBLIC_KEY | ssh -o "StrictHostKeyChecking=no" -i ~/.vagrant.d/insecure_private_key vagrant@dokku.me "sudo gitreceive upload-key test"
15 |
--------------------------------------------------------------------------------
/Vagrantfile:
--------------------------------------------------------------------------------
1 | # -*- mode: ruby -*-
2 | # vi: set ft=ruby :
3 |
4 | BOX_NAME = ENV["BOX_NAME"] || "raring"
5 | BOX_URI = ENV["BOX_URI"] || "https://cloud-images.ubuntu.com/vagrant/raring/current/raring-server-cloudimg-amd64-vagrant-disk1.box"
6 | DOKKU_DOMAIN = ENV["DOKKU_DOMAIN"] || "dokku.me"
7 | DOKKU_IP = ENV["DOKKU_IP"] || "10.0.0.2"
8 |
9 | Vagrant::configure("2") do |config|
10 | config.vm.box = BOX_NAME
11 | config.vm.box_url = BOX_URI
12 | config.vm.provision :shell, :path => "bootstrap.sh"
13 | config.vm.network :forwarded_port, guest: 80, host: 8080
14 | config.vm.hostname = "#{DOKKU_DOMAIN}"
15 | config.vm.network :private_network, ip: DOKKU_IP
16 |
17 | config.vm.provider :virtualbox do |vb|
18 | vb.customize ["modifyvm", :id, "--natdnshostresolver1", "on"]
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/deploystep:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | APP="$1"; CONTAINER="$2"
3 |
4 | if [[ ! -f "$HOME/$APP/PORT" ]]; then
5 | # First deploy
6 | ID=$(docker run -d -p 5000 -e PORT=5000 $CONTAINER /bin/bash -c "/start web")
7 | echo $ID > "$HOME/$APP/CONTAINER"
8 | PORT=$(docker port $ID 5000)
9 | echo $PORT > "$HOME/$APP/PORT"
10 | if [[ -f "$HOME/DOMAIN" ]]; then
11 | HOSTNAME="${APP/\//-}.$(< "$HOME/DOMAIN")"
12 | $HOME/nginx-app-conf ${APP/\//-} $PORT $HOSTNAME > $HOME/$APP/nginx.conf
13 | nc -U $HOME/reload-nginx
14 | else
15 | HOSTNAME="$(< "$HOME/HOSTNAME"):$PORT"
16 | fi
17 | echo $HOSTNAME > "$HOME/$APP/HOSTNAME"
18 | else
19 | # Regular deploy
20 | OLDID=$(< "$HOME/$APP/CONTAINER")
21 | docker kill $OLDID > /dev/null
22 | PORT=$(< "$HOME/$APP/PORT")
23 | ID=$(docker run -d -p ":$PORT" -e "PORT=$PORT" $CONTAINER /bin/bash -c "/start web")
24 | echo $ID > "$HOME/$APP/CONTAINER"
25 | fi
26 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (C) 2013 Jeff Lindsay
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | GITRECEIVE_URL = https://raw.github.com/progrium/gitreceive/master/gitreceive
2 | SSHCOMMAND_URL = https://raw.github.com/progrium/sshcommand/master/sshcommand
3 |
4 | all: install
5 |
6 | install: submodule gitreceive sshcommand
7 | cp dokku /usr/local/bin/dokku
8 | cp receiver /home/git/receiver
9 | cp deploystep /home/git/deploystep
10 | cp buildstep/buildstep /home/git/buildstep
11 | cp nginx-app-conf /home/git/nginx-app-conf
12 | cp nginx-reloader.conf /etc/init/nginx-reloader.conf
13 | echo "include /home/git/*/nginx.conf;" > /etc/nginx/conf.d/dokku.conf
14 |
15 | submodule:
16 | git submodule init
17 | git submodule update
18 |
19 | gitreceive:
20 | wget -qO /usr/local/bin/gitreceive ${GITRECEIVE_URL}
21 | chmod +x /usr/local/bin/gitreceive
22 | gitreceive init
23 |
24 | sshcommand:
25 | wget -qO /usr/local/bin/sshcommand ${SSHCOMMAND_URL}
26 | chmod +x /usr/local/bin/sshcommand
27 | sshcommand create dokku /usr/local/bin/dokku
28 |
29 | count:
30 | cat receiver deploystep bootstrap.sh nginx-app-conf nginx-reloader.conf | wc -l
--------------------------------------------------------------------------------
/.s3cfg:
--------------------------------------------------------------------------------
1 | [default]
2 | access_key
3 | secret_key
4 | bucket_location = US
5 | cloudfront_host = cloudfront.amazonaws.com
6 | cloudfront_resource = /2010-07-15/distribution
7 | default_mime_type = binary/octet-stream
8 | delete_removed = False
9 | dry_run = False
10 | encoding = UTF-8
11 | encrypt = False
12 | follow_symlinks = False
13 | force = False
14 | get_continue = False
15 | gpg_command = None
16 | gpg_decrypt = %(gpg_command)s -d --verbose --no-use-agent --batch --yes --passphrase-fd %(passphrase_fd)s -o %(output_file)s %(input_file)s
17 | gpg_encrypt = %(gpg_command)s -c --verbose --no-use-agent --batch --yes --passphrase-fd %(passphrase_fd)s -o %(output_file)s %(input_file)s
18 | gpg_passphrase =
19 | guess_mime_type = True
20 | host_base = s3.amazonaws.com
21 | host_bucket = %(bucket)s.s3.amazonaws.com
22 | human_readable_sizes = False
23 | list_md5 = False
24 | log_target_prefix =
25 | preserve_attrs = True
26 | progress_meter = True
27 | proxy_host =
28 | proxy_port = 0
29 | recursive = False
30 | recv_chunk = 4096
31 | reduced_redundancy = False
32 | send_chunk = 4096
33 | simpledb_host = sdb.amazonaws.com
34 | skip_existing = False
35 | socket_timeout = 300
36 | urlencoding_mode = normal
37 | use_https = False
38 | verbosity = WARNING
39 |
--------------------------------------------------------------------------------
/bootstrap.sh:
--------------------------------------------------------------------------------
1 | DOKKU_REPO=${DOKKU_REPO:-"https://github.com/progrium/dokku.git"}
2 | DOKKU_STACK=${DOKKU_STACK:-"https://s3.amazonaws.com/progrium-dokku/progrium_buildstep.tgz"}
3 | DOCKER_PKG=${DOCKER_PKG:-"https://launchpad.net/~dotcloud/+archive/lxc-docker/+files/lxc-docker_0.4.2-1_amd64.deb"}
4 | set -e
5 |
6 | apt-get update
7 | DEBIAN_FRONTEND=noninteractive apt-get install -y linux-image-extra-`uname -r`
8 | apt-get install -y git nginx make curl dnsutils
9 |
10 | wget -qO- "$DOCKER_PKG" > /tmp/lxc-docker_0.4.2-1_amd64.deb
11 | dpkg --force-depends -i /tmp/lxc-docker_0.4.2-1_amd64.deb && apt-get install -f -y
12 | rm /tmp/lxc-docker_0.4.2-1_amd64.deb
13 |
14 | sed -i.bak 's/docker -d/docker -d -r=true/' /etc/init/docker.conf # Docker should restart containers
15 |
16 | cd ~ && git clone ${DOKKU_REPO}
17 | cd dokku && make install
18 | if [[ $DOKKU_STACK ]]; then
19 | curl "$DOKKU_STACK" | gunzip -cd | docker import - progrium/buildstep
20 | else
21 | cd buildstep && make build
22 | fi
23 |
24 | [[ -f /etc/nginx/nginx.conf ]] && sed -i 's/# server_names_hash_bucket_size/server_names_hash_bucket_size/' /etc/nginx/nginx.conf
25 |
26 | /etc/init.d/nginx start
27 | start nginx-reloader
28 |
29 | [[ $(dig +short $HOSTNAME) ]] && HOSTFILE=DOMAIN || HOSTFILE=HOSTNAME
30 | echo $HOSTNAME > /home/git/$HOSTFILE
31 |
32 | echo
33 | echo "Be sure to upload a public key for your user:"
34 | echo " cat ~/.ssh/id_rsa.pub | ssh root@$HOSTNAME \"gitreceive upload-key progrium\""
35 |
--------------------------------------------------------------------------------
/tests/run_ec2:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | KEYNAME="$1"
3 | indent() { sed "s/^/ /"; }
4 | echo "-----> Booting EC2 instance..."
5 | start=$(ec2-run-instances -k $1 ami-f3d1bb9a 2>&1 )
6 | if [[ $? > 0 ]]; then
7 | echo "$start" | indent
8 | exit 3
9 | fi
10 | INSTANCE=$(echo "$start" | awk '/^INSTANCE/ {print $2}')
11 | terminate() {
12 | echo "-----> Terminating $INSTANCE..."
13 | ec2-terminate-instances $INSTANCE &>/dev/null && echo " Shutting down"
14 | }
15 | [[ $NOCLEANUP ]] || trap "terminate" EXIT
16 | sleep 30
17 | status=""
18 | while [[ "$status" != "running" ]]; do
19 | info=$(ec2-describe-instances 2>/dev/null | grep $INSTANCE)
20 | status=$(echo "$info" | cut -f 6 | grep run)
21 | echo " Waiting..."
22 | sleep 5
23 | if [[ $status == "running" ]]; then
24 | echo "-----> $INSTANCE has succesfully booted!"
25 | break
26 | fi
27 | done
28 | PUBLIC_IP=$(echo "$info" | awk '{print $14}')
29 | echo "-----> Waiting for SSH at $PUBLIC_IP..."
30 | while [[ ! $(echo | nc $PUBLIC_IP 22) ]]; do
31 | sleep 5
32 | echo " Waiting..."
33 | done
34 | set -e
35 | echo "-----> Connecting and running boostrap script..."
36 | cat ../bootstrap.sh | ssh -o "StrictHostKeyChecking=no" ubuntu@$PUBLIC_IP "HOSTNAME=$PUBLIC_IP sudo bash" 2>&1 | indent
37 | echo "-----> Installing SSH public keys..."
38 | cat ~/.ssh/id_rsa.pub | ssh -o "StrictHostKeyChecking=no" ubuntu@$PUBLIC_IP "sudo gitreceive upload-key test" > /dev/null
39 | cat ~/.ssh/id_rsa.pub | ssh -o "StrictHostKeyChecking=no" ubuntu@$PUBLIC_IP "sudo sshcommand acl-add dokku test" > /dev/null
40 | for app_path in apps/*; do
41 | app=$(basename $app_path)
42 | echo "-----> Running test deploy of $app..."
43 | ./test_deploy $app_path $PUBLIC_IP
44 | done
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Dokku
2 |
3 | Docker powered mini-Heroku. The smallest PaaS implementation you've ever seen.
4 |
5 | ## Requirements
6 |
7 | Assumes Ubuntu 13 right now. Ideally have a domain ready to point to your host. It's designed for and is probably
8 | best to use a fresh VM. The bootstrapper will install everything it needs.
9 |
10 | ## Installing
11 |
12 | $ wget -qO- https://raw.github.com/progrium/dokku/master/bootstrap.sh | sudo bash
13 |
14 | This may take around 5 minutes. Certainly better than the several hours it takes to bootstrap Cloud Foundry.
15 |
16 | ## Configuring
17 |
18 | Set up a domain and a wildcard domain pointing to that host. Make sure `/home/git/DOMAIN` is set to this domain.
19 | By default it's set to whatever the hostname the host has.
20 |
21 | You'll have to add a public key associated with a username as it says at the end of the bootstrapper. You'll do something
22 | like this from your local machine:
23 |
24 | $ cat ~/.ssh/id_rsa.pub | ssh progriumapp.com "sudo gitreceive upload-key progrium"
25 |
26 | That's it!
27 |
28 | ## Deploy an App
29 |
30 | Right now Buildstep supports buildpacks for Node.js, Ruby, Python, [and more](https://github.com/progrium/buildstep#supported-buildpacks). It's not hard to add more, [go add more](https://github.com/progrium/buildstep#adding-buildpacks)! Let's deploy
31 | the Heroku Node.js sample app. All you have to do is add a remote to name the app. It's created on-the-fly.
32 |
33 | $ cd node-js-sample
34 | $ git remote add progrium git@progriumapp.com:node-js-app
35 | $ git push progrium master
36 | Counting objects: 296, done.
37 | Delta compression using up to 4 threads.
38 | Compressing objects: 100% (254/254), done.
39 | Writing objects: 100% (296/296), 193.59 KiB, done.
40 | Total 296 (delta 25), reused 276 (delta 13)
41 | remote: -----> Building node-js-app ...
42 | remote: Node.js app detected
43 | remote: -----> Resolving engine versions
44 |
45 | ... blah blah blah ...
46 |
47 | remote: -----> Application deployed:
48 | remote: http://node-js-app.progriumapp.com
49 |
50 | You're done!
51 |
52 | ## Advanced installation (for development)
53 |
54 | The bootstrap script allows source URLs to be overridden to include customizations from your own
55 | repositories. The GITRECEIVE_URL and DOKKU_REPO environment variables
56 | may be set to override the defaults (see the bootstrap.sh script for how these apply). Example:
57 |
58 | $ wget j.mp/dokku-bootstrap
59 | $ chmod +x bootstrap.sh
60 | $ sudo DOKKU_REPO=https://github.com/yourusername/dokku.git ./bootstrap.sh
61 |
62 | ## Upgrading
63 |
64 | Dokku is in active development. You can update the deployment step and the build step separately.
65 | To update the deploy step (this is updated less frequently):
66 |
67 | $ cd ~/dokku
68 | $ git pull origin master
69 | $ sudo make install
70 |
71 | More frequently, the build step is updated. This is where the app "stack" lives and where buildpacks
72 | are supported. You can update this by running:
73 |
74 | $ cd ~/dokku/buildstep
75 | $ git pull origin master
76 | $ sudo make build
77 |
78 | Nothing needs to be restarted. Changes will take effect on the next push / deployment.
79 |
80 | ## Support
81 |
82 | You can use [Github Issues](https://github.com/progrium/dokku/issues), check [Troubleshooting](https://github.com/progrium/dokku/wiki/Troubleshooting) on the wiki, or join us on Freenode in #dokku
83 |
84 | ## Components
85 |
86 | * [Docker](https://github.com/dotcloud/docker) - Container runtime and manager
87 | * [Buildstep](https://github.com/progrium/buildstep) - Buildpack builder
88 | * [gitreceive](https://github.com/progrium/gitreceive) - Git push interface
89 | * [sshcommand](https://github.com/progrium/sshcommand) - Fixed commands over SSH
90 |
91 | ## Ideas for Improvements
92 |
93 | * Custom domain support for apps
94 | * HTTPS support on default domain
95 | * Support more buildpacks (see Buildstep)
96 | * Use dokku as the system user instead of git
97 | * Heroku-ish commands to be run via SSH (like [Dokuen](https://github.com/peterkeen/dokuen#available-app-sub-commands))
98 |
99 | Looking to keep codebase as simple and hackable as possible, so try to keep your line count down.
100 |
101 | ## Things this project won't do
102 |
103 | * **Multi-host.** Not a huge leap, but this isn't the project for it. Maybe as Super Dokku.
104 | * **Multitenancy.** It's ready for it, but again, probably for Super Dokku.
105 | * **Client app.** Given the constraints, running commands remotely via SSH is fine.
106 |
107 | ## License
108 |
109 | MIT
110 |
--------------------------------------------------------------------------------