Dokku: create your own PaaS
If you have been playing for some time with heroku or even now.sh you will be on my boat about how easy is to deploy applications on those services. What if I tell you that you can have your own PaaS using dokku ? π In this post I will explain how to deploy a node.js application within a docker container on your own Dokku service using a cheap Digital Ocean droplet.
π Deploying a DO droplet with Dokku
Due to addition of the Marketplace to Digital Ocean you can easily deploy prebuilt droplets from your DO dashboard. So letβs search for dokku and create a droplet with their 1-click install.
After clicking the install button you have to configure your droplet size and region. Do not enable IPv6 for now as seems that dokku has some problems with it.
Then you have to copy the IP address of your droplet. And open a new browser tab with it. you will see an administration form that will let you configure the Admin SSH key and the base domain name.
One feature that mimics heroku or even netlify is Use virtualhost naming for apps, this option will allow you to run one application per subdomain. If you do not enable this option each application will be exposed on the base domain but on different HTTP ports.
Click Finish setup, and after that you will have your dokku server up and running.
yay -S dokku
Deploying your app
Ok, you have reached the point that you have your own heroku like server. So lets ramp up the server and deploy our custom app on it.
In order to do that we have to connect via SSH to the serer and create the app using the dokku command:
$ ssh [email protected]
Last login: Mon Apr 15 17:58:36 2019 from 83.165.229.217
root@frandieguez-dokku-server:~# dokku apps:create nodejs-app-sample
-----> Creating nodejs-app-sample... done
Connecting services
For this app we do not need any other service, like a database or a queue server, but dokku provides an easy way to do this via plugins. You can review dokku plugins at the next link : Dokku plugins. Think of them as docker-compose services that you have to link to your app. So the steps to add a MySQL server, i.e.:
- Install the plugin
sudo dokku plugin:install https://github.com/dokku/dokku-mysql.git
- Create the mysql service with the name nodejsdatabase
dokku mysql:create nodejsdatabase
- Finally link the service to our app
dokku mysql:link nodejsdatabase nodejs-app-sample
Deploying the app
Then in your development machine download the app code
$ git clone https://github.com/heroku/node-js-sample
Cloning into 'node-js-sample'...
remote: Enumerating objects: 410, done.
remote: Total 410 (delta 0), reused 0 (delta 0), pack-reused 410
Receiving objects: 100% (410/410), 215.25 KiB | 841.00 KiB/s, done.
Resolving deltas: 100% (63/63), done.
Then configure the dokku server to push changes to it
$ git remote add dokku [email protected]:nodejs-app-sample
Finally upload the changes to the dokku server
$ git push dokku master
Enumerating objects: 410, done.
Counting objects: 100% (410/410), done.
Delta compression using up to 16 threads
Compressing objects: 100% (317/317), done.
Writing objects: 100% (410/410), 215.25 KiB | 19.57 MiB/s, done.
Total 410 (delta 63), reused 410 (delta 63)
remote: Resolving deltas: 100% (63/63), done.
-----> Cleaning up...
-----> Building nodejs-app-sample from herokuish...
-----> Setting config vars
CURL_CONNECT_TIMEOUT: 90
-----> Setting config vars
CURL_TIMEOUT: 600
-----> Adding BUILD_ENV to build environment...
-----> Node.js app detected
-----> Creating runtime environment
NPM_CONFIG_LOGLEVEL=error
NODE_VERBOSE=false
NODE_ENV=production
NODE_MODULES_CACHE=true
-----> Installing binaries
engines.node (package.json): 4.0.0
engines.npm (package.json): unspecified (use default)
Resolving node version 4.0.0...
Downloading and installing node 4.0.0...
Using default npm version: 2.14.2
-----> Building dependencies
Installing node modules (package.json)
[email protected] node_modules/express
βββ [email protected]
βββ [email protected]
βββ [email protected]
βββ [email protected]
βββ [email protected]
βββ [email protected]
βββ [email protected]
βββ [email protected]
βββ [email protected]
βββ [email protected]
βββ [email protected]
βββ [email protected]
βββ [email protected]
βββ [email protected]
βββ [email protected]
βββ [email protected]
βββ [email protected]
βββ [email protected]
βββ [email protected]
βββ [email protected]
βββ [email protected]
βββ [email protected] ([email protected])
βββ [email protected] ([email protected])
βββ [email protected]
βββ [email protected] ([email protected], [email protected])
βββ [email protected] ([email protected])
βββ [email protected] ([email protected], [email protected], [email protected], [email protected])
βββ [email protected] ([email protected], [email protected])
βββ [email protected] ([email protected], [email protected])
βββ [email protected] ([email protected], [email protected], [email protected], [email protected])
-----> Caching build
- node_modules
-----> Pruning devDependencies
-----> Build succeeded!
-----> Discovering process types
Procfile declares types -> web
-----> Releasing nodejs-app-sample (dokku/nodejs-app-sample:latest)...
-----> Deploying nodejs-app-sample (dokku/nodejs-app-sample:latest)...
-----> App Procfile file found (/home/dokku/nodejs-app-sample/DOKKU_PROCFILE)
-----> DOKKU_SCALE file not found in app image. Generating one based on Procfile...
-----> New DOKKU_SCALE file generated
=====> web=1
-----> Attempting pre-flight checks
For more efficient zero downtime deployments, create a file CHECKS.
See http://dokku.viewdocs.io/dokku/deployment/zero-downtime-deploys/ for examples
CHECKS file not found in container: Running simple container check...
-----> Waiting for 10 seconds ...
-----> Default container check successful!
-----> Running post-deploy
-----> Creating new /home/dokku/nodejs-app-sample/VHOST...
-----> Setting config vars
DOKKU_PROXY_PORT: 80
-----> Setting config vars
DOKKU_PROXY_PORT_MAP: http:80:5000
-----> Configuring nodejs-app-sample.frandieguez-dokku-server...(using built-in template)
-----> Creating http nginx.conf
-----> Running nginx-pre-reload
Reloading nginx
-----> Setting config vars
DOKKU_APP_RESTORE: 1
=====> Renaming container (938f82f6b6ab) vigorous_shockley to nodejs-app-sample.web.1
=====> Application deployed:
http://nodejs-app-sample.frandieguez-dokku-server
To 159.89.100.242:nodejs-app-sample
* [new branch] master -> master
As you can see from the command output above while pushing changes to the dokku server it will:
- Detect the type of the software, nodejs in this case
- Configure the build environment
- Cache build dependencies
- Build the app
- Launch the app on one HTTP port
- Finally configure the nginx reverse proxy to enable a virtualhost and point it to the new deployed app.
Accessing your deployed app
At this point your app is ready to be accessed
Edit your /etc/hosts adding the next line:
159.89.100.242 nodejs-app-sample.frandieguez-dokku-server
And go to http://nodejs-app-sample.frandieguez-dokku-server. And your app is up and running.
Quite impressive! Your own heroku!