Easy Application Deployment and Management with Dokku
Tags: dokku, docker, deploy, selfhosted
Published: 2021-12-18 00:46:00

---
title: Easy Application Deployment and Management with Dokku
published: true
date: 2021-12-05 21:35:00 UTC
tags: dokku, docker, deploy, selfhosted
canonical_url: https://kevinlangleyjr.dev/blog/easy-app-deployments-and-management-with-dokku
---

Application management and deployment are some of the most important aspects of the web development process. Thankfully, we are long past the days of using FTP or similar toolings to manage application deployments. Especially for proof of concepts, I like to get things up and running with as little configuration as possible. In this case, I've opted to use [Dokku](https://dokku.com) and will give a brief overview here. Let's dive in!

## What is Dokku?

[Dokku](https://dokku.com) is a popular, open-source, and self-hosted platform as a service (PaaS) that allows users to easily deploy and manage their applications, very similar to your own self-hosted [Heroku](https://heroku.com). Under the hood, Dokku is powered by [Docker](https://docker.com/), uses [Heroku buildpacks](https://devcenter.heroku.com/articles/buildpacks) by default, and has a number of official and community [plugins](https://dokku.com/docs/community/plugins/).

There is a [one-click](https://marketplace.digitalocean.com/apps/dokku) install image you can use from Digital Ocean, but I personally like to start with a fresh box and enjoy installing and configuring it all myself.

The only system requirements are 1GB of memory and either Ubuntu 18.04/20.04 x64, Debian 9+ x64, or CentOS 7 x64.

### Installation

```bash
wget https://raw.githubusercontent.com/dokku/dokku/v0.26.6/bootstrap.sh

sudo DOKKU\_TAG=v0.26.6 bash bootstrap.sh
```

This process can take between 5-10 minutes before it finishes. You can also see the other installation options which do not use `curl`, [here](https://dokku.com/#install-apt).

### Configuration

Next, you'll want to configure the SSH access and the servers domain using the following commands:

```bash
# Usually, you can find your key in the current user's `~/.ssh/authorized_keys` file.

cat ~/.ssh/authorized\_keys | dokku ssh-keys:add admin

# Be sure to replace this domain when running the command yourself!

dokku domains:set-global example.com
```


You'll want to also install and configure a simple firewall, something like UFW would work great. The only ports you need open to work with Dokku is the SSH port (can be customized), HTTP (80), and HTTPS (443) ports.

```bash
# Install UFW.
sudo apt-get install ufw

# Allow SSH access.
sudo ufw allow ssh

# Allow http, port 80, and https, port 443.
sudo ufw allow http
sudo ufw allow https

# Enable UFW
sudo ufw enable
```

You can find a more in depth guide to setup and configure UFW, [here](https://www.digitalocean.com/community/tutorials/how-to-setup-a-firewall-with-ufw-on-an-ubuntu-and-debian-cloud-server).

### Let's deploy an app!

Let's create a simple Next.js app and deploy it to our new Dokku instance.

```bash
# Using yarn
yarn create next-app

# Or using NPM
npx create-next-app
```

Next, let's open our `index.js` file in the `pages` directory and modify a few things.

```js
// ... more code not shown for brevity

export default function Home() {

  return (

    <div className={styles.container}>

      <Head>
        <title>Create Next App and Deploy to Dokku!</title>
        <meta name="description" content="Generated by create next app" />
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <main className={styles.main}>
        <h1 className={styles.title}>
          Welcome to <a href="https://nextjs.org">Next.js</a> and <a href="https://dokku.com">Dokku!</a>
        </h1>
        { // .... more code down here }
      </main>

    </div>
  );

}

// ... yep, you guessed it, more code not shown here.
```

Next, we need to add the git remote for our project.

```bash
# Be sure to replace `example.com` with the domain for your dokku instance and `new-app-name` with the name for your application.

git remote add dokku dokku@example.com:new-app-name
```

And now, we can simply deploy with a `git push` to that new dokku remote.

```bash
git push dokku main

Enumerating objects: 7, done.
Counting objects: 100% (7/7), done.
Delta compression using up to 8 threads
Compressing objects: 100% (4/4), done.
Writing objects: 100% (4/4), 358 bytes | 358.00 KiB/s, done.
Total 4 (delta 3), reused 0 (delta 0)

-----> Set main to DOKKU\_DEPLOY\_BRANCH.
-----> Cleaning up...
-----> Building test-app from herokuish
-----> Adding BUILD\_ENV to build environment...
 BUILD\_ENV added successfully
-----> Node.js app detected
-----> Creating runtime environment
NPM\_CONFIG\_LOGLEVEL=error
USE\_YARN\_CACHE=true
NODE\_VERBOSE=false
NODE\_ENV=production
NODE\_MODULES\_CACHE=true
-----> Installing binaries
 engines.node (package.json): unspecified
 engines.npm (package.json): unspecified (use default)
 engines.yarn (package.json): unspecified (use default)
 Resolving node version 14.x...
 Downloading and installing node 14.17.6...
 Using default npm version: 6.14.15
 Resolving yarn version 1.22.x...
 Downloading and installing yarn (1.22.11)
 Installed yarn 1.22.11
-----> Restoring cache
 - yarn cache
-----> Installing dependencies
 Installing node modules (yarn.lock)
yarn install v1.22.11
[1/4] Resolving packages...
[2/4] Fetching packages...
 info @next/swc-darwin-arm64@11.1.2: The platform "linux" is incompatible with this module.
 info "@next/swc-darwin-arm64@11.1.2" is an optional dependency and failed compatibility check. Excluding it from installation.
 info @next/swc-darwin-arm64@11.1.2: The CPU architecture "x64" is incompatible with this module.
 info @next/swc-darwin-x64@11.1.2: The platform "linux" is incompatible with this module.
 info "@next/swc-darwin-x64@11.1.2" is an optional dependency and failed compatibility check. Excluding it from installation.
 info @next/swc-win32-x64-msvc@11.1.2: The platform "linux" is incompatible with this module.
 info "@next/swc-win32-x64-msvc@11.1.2" is an optional dependency and failed compatibility check. Excluding it from installation.
 info fsevents@2.3.2: The platform "linux" is incompatible with this module.
 info "fsevents@2.3.2" is an optional dependency and failed compatibility check. Excluding it from installation.
[3/4] Linking dependencies...
 warning "next > styled-jsx > @babel/plugin-syntax-jsx@7.14.5" has unmet peer dependency "@babel/core@^7.0.0-0".
 warning "eslint-config-next > @typescript-eslint/parser > @typescript-eslint/typescript-estree > tsutils@3.21.0" has unmet peer dependency "typescript@>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta".
[4/4] Building fresh packages...
 Done in 3.95s.
-----> Build
 Running build (yarn)
yarn run v1.22.11
 $ next build
 info - Loaded env from /tmp/build/.env
 info - Using webpack 5. Reason: Enabled by default https://nextjs.org/docs/messages/webpack5
 warn - No build cache found. Please configure build caching for faster rebuilds. Read more: https://nextjs.org/docs/messages/no-cache
 Attention: Next.js now collects completely anonymous telemetry regarding usage.
 This information is used to shape Next.js' roadmap and prioritize features.
 You can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:

 https://nextjs.org/telemetry
 info - Checking validity of types...
 info - Creating an optimized production build...
 info - Compiled successfully
 info - Collecting page data...
 info - Generating static pages (0/3)
 info - Generating static pages (3/3)
 info - Finalizing page optimization...

 Page Size First Load JS
 ┌ ○ / 4.65 kB 71.6 kB
 ├ └ css/5dd3a863eec8dc33b66f.css 727 B
 ├ /\_app 0 B 66.9 kB
 ├ ○ /404 194 B 67.1 kB
 └ λ /api/hello 0 B 66.9 kB
 + First Load JS shared by all 66.9 kB
 ├ chunks/framework.b97a0e.js 42 kB
 ├ chunks/main.c4f254.js 23.6 kB
 ├ chunks/pages/\_app.68998c.js 555 B
 ├ chunks/webpack.fb7614.js 770 B
 └ css/120f2e2270820d49a21f.css 209 B

 λ (Server) server-side renders at runtime (uses getInitialProps or getServerSideProps)
 ○ (Static) automatically rendered as static HTML (uses no initial props)
 ● (SSG) automatically generated as static HTML + JSON (uses getStaticProps)
(ISR) incremental static regeneration (uses revalidate in getStaticProps)

 Done in 15.95s.

-----> Pruning devDependencies

yarn install v1.22.11

[1/4] Resolving packages...
[2/4] Fetching packages...
 info @next/swc-darwin-arm64@11.1.2: The platform "linux" is incompatible with this module.
 info "@next/swc-darwin-arm64@11.1.2" is an optional dependency and failed compatibility check. Excluding it from installation.
 info @next/swc-darwin-arm64@11.1.2: The CPU architecture "x64" is incompatible with this module.
 info @next/swc-darwin-x64@11.1.2: The platform "linux" is incompatible with this module.
 info "@next/swc-darwin-x64@11.1.2" is an optional dependency and failed compatibility check. Excluding it from installation.
 info @next/swc-win32-x64-msvc@11.1.2: The platform "linux" is incompatible with this module.
 info "@next/swc-win32-x64-msvc@11.1.2" is an optional dependency and failed compatibility check. Excluding it from installation.
 info fsevents@2.3.2: The platform "linux" is incompatible with this module.
 info "fsevents@2.3.2" is an optional dependency and failed compatibility check. Excluding it from installation.
[3/4] Linking dependencies...
 warning "next > styled-jsx > @babel/plugin-syntax-jsx@7.14.5" has unmet peer dependency "@babel/core@^7.0.0-0".
 warning "eslint-config-next > @typescript-eslint/parser > @typescript-eslint/typescript-estree > tsutils@3.21.0" has unmet peer dependency "typescript@>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta".
[4/4] Building fresh packages...
 warning Ignored scripts due to flag.
 Done in 1.69s.
-----> Caching build
 - yarn cache
-----> Build succeeded!
! Unmet dependencies don\'t fail yarn install but may cause runtime issues
 https://github.com/npm/npm/issues/7494
-----> Discovering process types
 Default types for -> web
-----> Releasing test-app...
-----> Checking for predeploy task
 No predeploy task found, skipping
-----> Checking for release task
 No release task found, skipping
-----> App Procfile file found
=====> Processing deployment checks

 No CHECKS file found. Simple container checks will be performed.

 For more efficient zero downtime deployments, create a CHECKS file. See https://dokku.com/docs/deployment/zero-downtime-deploys/ for examples

-----> Deploying test-app...
-----> Attempting pre-flight checks (web.1)
 Waiting for 10 seconds ...
 Default container check successful!
 Scheduling old container shutdown for web.1 in 60 seconds

-----> Running post-deploy

-----> Configuring test-app.example.com...(using built-in template)

-----> Creating https nginx.conf

 Enabling HSTS

 Reloading nginx

-----> Renaming containers

 Found previous container(s) (ed302d9e2e9b) named test-app.web.1

 Renaming container (ed302d9e2e9b) test-app.web.1 to test-app.web.1.1632683188

 Renaming container test-app.web.1.upcoming-2851 (2c1f0d45c456) to test-app.web.1

-----> Checking for postdeploy task

 No postdeploy task found, skipping

-----> Shutting down old containers in 60 seconds

=====> Application deployed:

 http://test-app.example.com

 https://test-app.example.com

To example.com:test-app

 778f90c..8521e6c main -> main
```

<img alt="Newly deployed site" src="https://res.cloudinary.com/kevinlangleyjr-dev/image/upload/v1632019689/blog/easy-app-deployments-and-management-with-dokku/sample-dokku-app_tdvvsx.png">

### Dokku Plugins

There are a number of official and community based [plugins](https://dokku.com/docs/community/plugins/) available for use. These plugins range from databases like [MariaDB](https://github.com/dokku/dokku-mariadb-plugin), [Postgres](https://github.com/dokku/dokku-postgres-plugin), [Redis](https://github.com/dokku/dokku-redis-plugin), [Mongo](https://github.com/dokku/dokku-mongo-plugin) and more, all the way to [Memcached](https://github.com/dokku/dokku-memcached-plugin), [Let's Encrypt](https://github.com/dokku/dokku-letsencrypt) for SSL certificates, and [Elasticsearch](https://github.com/dokku/dokku-elasticsearch-plugin) for search integration.

## Ledokku

Ledokku dubs itself as a _"beautiful web UI for all things Dokku"_ and I think they hit the nail right on the head. With Ledokku, you can view the logs, edit/add/remove environment variables, change domain configuration settings, link databases or other services, and more!

### Installation

```bash
wget https://raw.githubusercontent.com/ledokku/ledokku/v0.7.0/ledokku-bootstrap.sh

sudo bash ledokku-bootstrap.sh
```

# Be sure to change `example.com` to your domain!
```bash
dokku domains:set ledokku dashboard.example.com

# Let's throw it behind SSL!

dokku config:set --no-restart ledokku DOKKU\_LETSENCRYPT\_EMAIL=your@email.com

dokku letsencrypt:enable ledokku
```

There are also manual installation instructions you can find [here](https://www.ledokku.com/docs/advanced/manual-installation/).

Now, you should be able to open ledokku.example.com, with `example.com` being changed to the domain supplied previously.

<img alt="Ledokku Dashboard" src="https://res.cloudinary.com/kevinlangleyjr-dev/image/upload/v1632019689/blog/easy-app-deployments-and-management-with-dokku/ledokku-dashboard_sw2fcr.png">