Skip to content

Latest commit

 

History

History
796 lines (549 loc) · 23.5 KB

nodejs-digital-ocean-centos-dokku.md

File metadata and controls

796 lines (549 loc) · 23.5 KB

Deploying Any App(s) Using Dokku PaaS

A guide to deploying Any App(s) to your own "Platform-as-a-Service" using Dokku.

dokku-paas-header-image


Like having your own (_self-managed/hosted_) Heroku platform with full VM access/control at a _fraction_ of the cost.

Why?

We need a way of deploying multiple apps to the same Digital Ocean VPS/instance.

Digital Ocean is a great alternative to the "main" cloud providers (Amazon, Google & Microsoft); it has a much more intuitive (UX-focussed) "control panel" which means you can get your "DevOps" learning and work done a lot faster!

Why Not?

Managing your own infrastructure (or "Platform") is a "rabbit hole"; it might be easy to get started, but if (when) things go "wrong", it can take a while to understand the issue (lots of googling!). This is "OK" if you are the type of person who enjoys debugging Docker/Linux, but if you prefer focus on the features of your App, let someone else handle the infra/PaaS until you achieve "critical mass" and can afford to hire a professional DevOps person.

What?

Deploy "unlimited"1 apps to a Virtual Private Server (VPS) instance with great service quality and minimal cost.

In this guide we will be using the following:

  • Digital Ocean Droplet (Virtual Private Server "VPS")
  • CentOS (Operating System) - though any "mainstream linux" will work, and Ubuntu/Debian is the most popular.
  • Dokku "Platform as a Service" ("PaaS") based on Docker.
  • LetsEncrypt Free SSL Certificates.

If you do not already have a Digital Ocean account, please use the following link to register: https://m.do.co/c/29379863a4f8 and get $10 in Credit.

Note: we are launching a Digital Ocean instance in this tutorial. unless you used the "referral link" above, you will incur a small cost. If you use the 1GB instance and go through the tutorial in 1 hour it will cost you 0.007 cents (less than one cent). If you chose to use this method for running your apps it will cost you $5/month which is cheaper than the cheapest paid tier on Heroku, and since we will cover how to run multiple apps, it will cost you less than $1 per month (per app) if you run 5+ apps. Crucially, the service quality/speed will be much better than the "free apps" on Heroku!

1"unlimited" apps is not strictly true; we are limited by the RAM resources of the instance.

Who?

Anyone that needs to deploy one or more App(s) to DigitalOcean and needs a step-by-step guide.

When?

It's only worth investing the time to create your own "Mini Platform-as-a-Service" once you have used (and "out-grown") Heroku.

Heroku offers significant advantages including logging/alerting and "teams", which are not covered here.

If you have never used Heroku, or this is your first time deploying a Node.js app, we highly recommend following the https://github.com/dwyl/learn-heroku guide first.

Bookmark (Star) this repo/tutorial now so you can return to it when you are spending more than $10/month on Heroku; it does not make sense to run your own "PaaS" before then!

How?

These are step-by-step instructions, follow them in order and don't skip steps!

0. Pre-requisites

Before we start, please ensure you have the following:

1. Create the DigitalOcean Instance

Go to: https://cloud.digitalocean.com/droplets/new and Create a Droplet!

Note: We are using a "blank" instance as opposed to a "One-click app", because this will show us how to setup "from scratch" and will thus be applicable to any cloud provider.

The instance we are creating is a CentOS 7.5 Droplet with 1GB RAM.

digital-ocean-dokku-create-droplet

Select your desired region (datacenter); (pick the nearest to your users or dev team) e.g:

digital-ocean-dokku-choose-region

The default hostname for the instance (based on the selected options) is: centos-s-1vcpu-1gb-lon1-01 let's change that to: centos-dokku-paas so that we know what the instance does from reading it's hostname.

digital-ocean-dokku-default-hostname

This also means that if/when we "scale" the instance up we don't need to rename it when the CPU/RAM changes.


hostname updated: dokku-hostname-updated

Click on the "Create" button.

You will see a "loading" progress bar for a few seconds while the instance is being created:

digital-ocean-instance-creation-progress-bar

and then something like this:

digital-ocean-dokku-instance-created

2. Login to the Instance via SSH/Console

There are two ways to access your Digital Ocean instance: the first is via the Web-based console:

do-centos-dokku-console

We only tend to use the web-based console when on a device that does not have a "native" terminal app. (e.g: an iPad)

get the instance's IP (v4) Address, e.g: 138.68.163.126 and run the following command into your terminal to login to the instance via SSH:

ssh root@138.68.163.126

While logged in as root run the update command:

yum update

There are security updates:
image

Update complete:
image

root is the default user for Digital Ocean instances, we prefer to minimise the activity of "root" or sudo users on our instances for security. So our next step we will create a new user called: dokku with reduced privileges.

3. Add dokku User

Create a dokku user on the server (so that we can avoid running as root)""

cat ~/.ssh/id_rsa.pub | ssh root@<ip4> "sudo sshcommand acl-add dokku root"

e.g:

cat ~/.ssh/id_rsa.pub | ssh root@138.68.163.126 "sudo sshcommand acl-add dokku root"

If you are already logged into the server, run the following command:

cat ~/.ssh/id_rsa.pub | sudo sshcommand acl-add dokku root

3.i Need to Remove the Dokku User?

If you ever need to remove the dokku user on the instance, run:

sshcommand acl-remove <USER> <NAME>

e.g:

sshcommand acl-remove dokku root

4. Configure Custom Domain Name (Optional/Recommend)

In this section we'll walk through:

  • Finding and registering a domain name
  • Point the domain's DNS record to DigitalOcean so the "droplet" is configured to receive all traffic for all subdomains.

Note: If you already have a domain name you can use for this, then skip the registration step.
You will still need to "point" the domain's DNS to DigitalOcean for the rest to work
.

4.1 Register the Domain

We registered a custom domain name as we intend to use this server to host multiple "demo" apps,
ademo.app seemed like a logical name for the domain.

We use https://domainr.com to lookup if the domain is available:

image

And then use https://iwantmyname.com to register the domain.

4.2 Update the DNS (NameServer) Records to DigitalOcean

In the settings (where you registered the domain), point DNS servers at the DigitalOcean's name servers:

  • ns1.digitalocean.com
  • ns2.digitalocean.com
  • ns3.digitalocean.com

do-cetos-ademo-app-dns do-cents-ademo-dns-full

This indicates the settings update is in progress ...
dns-settings-updated

4.3 Verify the Domain Servers using whois Command

Verify that the new domain servers are listed by running the whois command:

$ whois <domain.com> | grep "Name Server"

e.g:

whois ademo.app | grep "Name Server"

You should see something like this:
image

Background Reading for DNS on Digital Ocean

https://www.digitalocean.com/community/tutorials/an-introduction-to-digitalocean-dns

Now that we know the domain (DNS) is configured to "point" to DigitalOcean we can move on to creating the SSL Certificate for the domain!

5. LetsEncrypt Wildcard SSL Certificate!

In order to have multiple subdomains on the same server, e.g: hello.ademo.app and awesome-word-game.ademo.app you will need to have a Wildcard SSL Certificate!

Thankfully you can get one for free with about 10 mins work. We wrote a separate (self-contained) tutorial for that:

letsencrypt-wildcard-certificate.md

once you have finished setting it up, return here and continue.

6.Install Dokku

6.1 Install Docker (Dependency)

Given that there is no "package" for CentOS we need to install dokku manually using the "advanced" instructions:
http://dokku.viewdocs.io/dokku/getting-started/advanced-installation

Run the following commands on your DO instance to install Extra Packages for Enterprise Linux ("EPEL")
https://fedoraproject.org/wiki/EPEL to get nginx:

sudo yum install -y epel-release

Install Docker

curl -fsSL https://get.docker.com/ | sudo sh

image

6.2 Install Dokku

Once Docker is installed, proceed to installing Dokku using the following script:

curl -s https://packagecloud.io/install/repositories/dokku/dokku/script.rpm.sh | sudo bash
sudo yum install -y herokuish dokku
sudo dokku plugin:install-dependencies --core

image

That will install quite a few packages, so go for a walk!

image

6.3 Install Dokku LetsEncrypt Plugin

sudo dokku plugin:install https://github.com/dokku/dokku-letsencrypt.git

You should see the following output:

-----> Cloning plugin repo https://github.com/dokku/dokku-letsencrypt.git to /var/lib/dokku/plugins/available/letsencrypt
Cloning into 'letsencrypt'...
remote: Counting objects: 454, done.
remote: Total 454 (delta 0), reused 0 (delta 0), pack-reused 454
Receiving objects: 100% (454/454), 94.57 KiB | 0 bytes/s, done.
Resolving deltas: 100% (276/276), done.
-----> Plugin letsencrypt enabled
Removed symlink /etc/systemd/system/docker.service.wants/dokku-redeploy.service.
Created symlink from /etc/systemd/system/docker.service.wants/dokku-redeploy.service to /etc/systemd/system/dokku-redeploy.service.
-----> Migrating zero downtime env variables to 0.5.x. The following variables have been deprecated
=====> DOKKU_SKIP_ALL_CHECKS DOKKU_SKIP_DEFAULT_CHECKS
=====> Please use dokku checks:[disable|enable] <app> to control zero downtime functionality
=====> Migration complete
=====>
-----> Migrating zero downtime env variables to 0.6.x. The following variables will be migrated
=====> DOKKU_CHECKS_ENABLED -> DOKKU_CHECKS_SKIPPED
=====> Migration complete
=====>
Adding user dokku to group adm
-----> Migrating DOKKU_NGINX env variables. The following variables will be migrated
=====> DOKKU_NGINX_PORT -> DOKKU_PROXY_PORT
=====> DOKKU_NGINX_SSL_PORT -> DOKKU_PROXY_SSL_PORT
=====> Migration complete
-----> Priming bash-completion cache

6.4 Add Domain to Dokku

Add the desired domain to dokku so that it knows we want to deploy our app(s) to that.

dokku domains:add-global <domain.com>

e.g:

dokku domains:add-global ademo.app

via: http://dokku.viewdocs.io/dokku/configuration/domains/#customizing-hostnames

7. Configure Dokku

Run the following commands (on the instance) to add your ssh (public) key to the dokku user:

sudo cp /root/.ssh/authorized_keys /home/dokku/.ssh/dokku.pub
sudo chown dokku:dokku /home/dokku/.ssh/dokku.pub
sudo dokku ssh-keys:add dokku /home/dokku/.ssh/dokku.pub

7.1 Create the /home/dokku/VHOST File

vi /home/dokku/VHOST

paste the following:

A   *.ademo.app  138.68.163.126

7.2 Configure Dokku nginx.conf.sigil

Find the file:

find / -name nginx.conf.sigil

On CentOS the file is located at:

/var/lib/dokku/core-plugins/available/nginx-vhosts/templates/nginx.conf.sigil

For reference, this is the git diff ("before and after") the change: https://github.com/dwyl/learn-devops/compare/82919299ceaa2d0eb308c7501b8aa95b6be2b848...2da1a06365cce145d98e293a263a8ae747fb2f01

For details on nginx configuration in Dokku, see: https://github.com/dokku/dokku/blob/master/docs/configuration/nginx.md

8. Create a Dokku App

Run this command while logged in (via SSH) to the DO instance:

dokku apps:create hello

You should see:

-----> Creating hello... done

8.1 Add the SSL Certificate to the App

dokku certs:add yourapp < /etc/letsencrypt/live/ademo.app/certs.tar

e.g:

dokku certs:add hello < /etc/letsencrypt/live/ademo.app/certs.tar

9. Add Dokku Git Remote

using https://github.com/nelsonic/hello-world-node-http-server as my "hello world" app.

git remote add dokku dokku@138.68.163.126:hello

Now push the app to the Dokku server:

git push dokku master

You should see output similar to the following:

image

9.1 Confirm The App Deployed Successfully

In our case we deployed our hello app to: https://hello.ademo.app

hello-world-example-app

10. Deploy Another App to Prove it Was not a "Fluke"!

10.1 Create New Dokku App on Instance

Create a new Dokku app (on the instance):

dokku apps:create hello-world-node

Output (you should see):

-----> Creating hello-world-node... done

10.2 Add a git remote for the app

git remote add dokku dokku@138.68.163.126:hello-world-node

Now push the app to the Dokku server:

git push dokku master

In my case I am working on a branch so I did:

git push dokku dokku-paas-deployment-issue#24:master

This pushes the branch but tells Dokku to treat it as master So it will be deployed.

The "new" app hello-world-node was successfully deployed to: https://hello-world-node.ademo.app hello-world-node

Done!

You have successfully deployed your first App to A Dokku PaaS!


nginx Server Root and Configuration

Dokku uses nginx as its server for routing requests to specific applications.

If you want to start serving your own pages or application through Nginx, you will want to know the locations of the Nginx configuration files and default server root directory.

Default Server Root

The default server root directory is /usr/share/nginx/html. Files that are placed in there will be served on your web server. This location is specified in the default server block configuration file that ships with Nginx, which is located at /etc/nginx/nginx.conf

Server Block Configuration

Any additional server blocks, known as Virtual Hosts in Apache, can be added by creating new configuration files in /etc/nginx/conf.d Files that end with .conf in that directory will be loaded when Nginx is started.

Nginx Global Configuration

The main Nginx configuration file is located at /etc/nginx/nginx.conf. This is where you can change settings like the user that runs the Nginx daemon processes, and the number of worker processes that get spawned when Nginx is running, among other things.

Default Log Files for Apps

By default, access and error logs are written for each app to /var/log/nginx/${APP}-access.log and /var/log/nginx/${APP}-error.log respectively

Default Dokku Nginx Conf

/home/dokku/*/nginx.conf e.g:

/home/dokku/hello/nginx.conf

nginx -t -c /etc/nginx/conf.d/dokku.conf


Useful Dokku / Nginx Commands

nginx Check (Test) Config

nginx -t

via: http://dokku.viewdocs.io/dokku/getting-started/troubleshooting/

nginx start, stop & restart

nginx -s reload

via: https://www.digitalocean.com/community/tutorials/how-to-install-nginx-on-centos-7

Nginx Running?

To check if nginx is running on the CentOS instance run:

ps waux | grep nginx

e.g:

root     14575  0.0  0.0 112704   968 pts/0    S+   20:39   0:00 grep --color=auto nginx
root     19119  0.0  0.2 141272  2100 ?        Ss   18:31   0:00 nginx: master process nginx
nginx    19120  0.0  0.3 141660  3572 ?        S    18:31   0:00 nginx: worker process

Kill all Nginx Processes

kill $(ps aux | grep '[n]ginx' | awk '{print $2}')

or the cleaner version:

pkill nginx

Check Running Apps

dokku apps:list

Sample response:

=====> My Apps
hello

via: https://github.com/dokku/dokku/blob/master/docs/deployment/process-management.md

Proxy Settings

dokku proxy:report hello

Sample output:

[root@centos-dokku-paas hello]# dokku proxy:report hello
=====> hello proxy information
       Proxy enabled:                 true                     
       Proxy type:                    nginx                    
       Proxy port map:                http:80:5000  

via: http://dokku.viewdocs.io/dokku/networking/proxy-management/

Re-Start an App

dokku ps:restart <app>

e.g:

dokku ps:restart hello

via: https://stackoverflow.com/questions/21247195/what-is-the-proper-command-to-restart-a-dokku-app-from-ssh

Destroy (Delete) an App

To delete or "destro" an app run:

dokku apps:destroy <app>

e.g:

dokku apps:destroy hello

via: dokku/dokku#36

Docker Info

docker -D info

Background / Further Reading

Credits

This tutorial stands on the shoulders of several giants. The particular "guide" we found the most useful was written by Gleb Bahmutov @bahmutov https://glebbahmutov.com/blog/running-multiple-applications-in-dokku PDF snapshot: running-multiple-applications-in-dokku.pdf
His post is 2 years old, uses a much older version Dokku, and is focussed on Ubuntu, so we had to fill-in quite a few "gaps". But on the whole, it's a superb post!

Troubleshooting

"failed to push some refs"

To 138.68.163.126:hello-dokku
 ! [remote rejected] dokku-paas-deployment-issue#24 -> master (pre-receive hook declined)
error: failed to push some refs to 'dokku@138.68.163.126:hello-dokku'

I ended up having to "kill" the nginx server before pushing the app to the server.

see: /bin/deploy.sh#L32-L38

DOKKU_PROXY_PORT_MAP

By default Dokku sets the App's TCP Port to 5000. Unless you have a very good reason to change it, leave it as the default. If you see the following error message:

-----> Configuring ademo.app...(using built-in template)
-----> Configuring hello-dokku....(using built-in template)
-----> Configuring hello-dokku.ademo.app...(using built-in template)
-----> Creating https nginx.conf
-----> Running nginx-pre-reload
       Reloading nginx
Job for nginx.service invalid.
-----> Configuring ademo.app...(using built-in template)
-----> Configuring hello-dokku....(using built-in template)
-----> Configuring hello-dokku.ademo.app...(using built-in template)
-----> Creating https nginx.conf
-----> Running nginx-pre-reload
       Reloading nginx
Job for nginx.service invalid.

It's because you are attempting to override the PORT environment variable. (we learned this he hard way ... don't make the same mistake!)