Dokku: Build Your Own PaaS on Any Linux Server
PROGRAMMING LANGUAGES March 14, 2026, 5:30 p.m.

Dokku: Build Your Own PaaS on Any Linux Server

Imagine having the power of Heroku on your own hardware—no vendor lock‑in, full control over resources, and the flexibility to host any language or framework you love. That’s exactly what Dokku gives you: a lightweight, Docker‑based platform‑as‑a‑service (PaaS) you can spin up on any Linux server in minutes. In this guide we’ll walk through the fundamentals, set up a production‑ready Dokku instance, deploy a sample app, and explore real‑world scenarios where a self‑hosted PaaS shines.

What Is Dokku and Why It Matters

Dokku is often described as a “mini‑Heroku”. Under the hood it uses Docker containers to isolate each app, a set of buildpacks to compile source code, and a simple git push workflow that developers already recognize. Because it’s built on open‑source components, you can extend it with plugins, customize networking, and even integrate it with your existing CI/CD pipelines.

Running Dokku on a VM or a bare‑metal server gives you the same developer experience as a hosted PaaS, but you keep the data, the cost model, and the security policies under your own control. This makes Dokku an attractive choice for startups, agencies, and hobbyists who need a scalable, cost‑effective way to host multiple micro‑services.

Prerequisites Before You Start

  • A fresh Linux server (Ubuntu 22.04 LTS is the most common choice)
  • Root or sudo access
  • At least 1 GB of RAM (2 GB+ is recommended for multiple apps)
  • Domain name(s) pointing to the server’s IP (optional but highly recommended)
  • Basic familiarity with git and Docker concepts

If you’re using a cloud provider, spin up a droplet or VM with the above specs, then SSH into it. All subsequent commands assume you’re operating as a user with sudo privileges.

Installing Dokku: Step‑by‑Step

1. Add the Dokku APT repository

sudo apt-get update
sudo apt-get install -y software-properties-common
sudo add-apt-repository "deb https://packagecloud.io/dokku/dokku/ubuntu/ $(lsb_release -cs) main"
wget -qO- https://packagecloud.io/dokku/dokku/gpgkey | sudo apt-key add -
sudo apt-get update

2. Install the Dokku package

sudo apt-get install -y dokku

During installation you’ll be prompted for a hostname and whether you want to enable HTTP/HTTPS. Enter your domain (e.g., apps.example.com) and say “yes” to both HTTP and HTTPS. Dokku will automatically configure nginx as a reverse proxy and obtain a free Let’s Encrypt certificate.

3. Verify the installation

dokku version

You should see something like Dokku v0.27.0. Open a browser and navigate to http://your-domain.com; you’ll see the default “Welcome to Dokku!” page.

Pro tip: If you’re behind a firewall, ensure ports 80, 443, and 22 (SSH) are open. Dokku also uses port 5000 for internal Docker communication, but this is not exposed externally.

First Deployment: A Simple Node.js App

Let’s deploy a minimal Node.js “Hello World” app to prove everything works. This example demonstrates the classic git push dokku master workflow.

1. Create the app on the server

ssh root@your-server.com
dokku apps:create hello-node

This registers a new application called hello-node and creates a corresponding /home/dokku/hello-node directory for Docker containers.

2. Set up the local repository

mkdir hello-node
cd hello-node
git init
cat > package.json <<EOF
{
  "name": "hello-node",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "start": "node index.js"
  },
  "engines": {
    "node": ">=14"
  }
}
EOF

cat > index.js <<EOF
const http = require('http');
const port = process.env.PORT || 5000;
http.createServer((req, res) => {
  res.end('👋 Hello from Dokku on ' + process.env.HOSTNAME);
}).listen(port, () => console.log(`Listening on ${port}`));
EOF

git add .
git commit -m "Initial commit"

3. Add Dokku remote and push

git remote add dokku dokku@your-server.com:hello-node
git push dokku master

Dokku detects the Node.js buildpack, builds a Docker image, and starts a container listening on the port assigned by the PORT environment variable. Once the push completes, open https://hello-node.your-domain.com to see the greeting.

Pro tip: For faster builds, enable the dokku-buildpacks plugin and cache Docker layers. Run dokku plugin:install https://github.com/dokku/dokku-buildpacks.git buildpacks and then dokku buildpacks:set hello-node https://github.com/heroku/heroku-buildpack-nodejs.git.

Managing Environment Variables and Secrets

Production apps need database URLs, API keys, and other secrets. Dokku stores these as environment variables that are injected into the container at runtime. The dokku config command mirrors Heroku’s config:set syntax.

# Example: Setting a PostgreSQL URL
dokku config:set hello-node DATABASE_URL="postgres://user:pass@db.example.com:5432/appdb"

# Verify
dokku config:show hello-node

For added security, you can use the dokku plugin:install command to add the dokku-letsencrypt plugin, which automatically renews TLS certificates without exposing the private key.

Deploying a Python Flask Application with a Custom Domain

Now let’s switch gears to a Python stack. This example shows how to attach a custom subdomain, configure a PostgreSQL service via the official Dokku plugin, and use a Dockerfile for fine‑grained control.

1. Install the PostgreSQL plugin

dokku plugin:install https://github.com/dokku/dokku-postgres.git postgres
dokku postgres:create mydb
dokku postgres:link mydb flask-app

The last command creates a DATABASE_URL environment variable inside the flask-app container, pointing to the newly provisioned database.

2. Create the Flask app locally

mkdir flask-app
cd flask-app
python3 -m venv venv
source venv/bin/activate
pip install flask gunicorn psycopg2-binary
cat > app.py <<EOF
import os
from flask import Flask
app = Flask(__name__)

@app.route('/')
def home():
    db_url = os.getenv('DATABASE_URL', 'not set')
    return f"👋 Flask on Dokku! DB: {db_url}"

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=int(os.getenv('PORT', 5000)))
EOF

cat > requirements.txt <<EOF
Flask
gunicorn
psycopg2-binary
EOF

cat > Dockerfile <<EOF
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["gunicorn", "-b", "0.0.0.0:$PORT", "app:app"]
EOF

git init
git add .
git commit -m "Initial Flask app"

3. Create the app on Dokku and bind the domain

dokku apps:create flask-app
dokku domains:add flask-app api.example.com
git remote add dokku dokku@your-server.com:flask-app
git push dokku master

After the push finishes, navigate to https://api.example.com. You should see the greeting with the database URL printed, confirming that the PostgreSQL plugin is correctly linked.

Pro tip: Use dokku config:set flask-app DEBUG=False to disable Flask’s debug mode in production. Pair this with dokku nginx:build-config flask-app to regenerate the Nginx configuration after any domain changes.

Scaling and Managing Multiple Containers

One of Dokku’s strengths is the ability to scale horizontally by increasing the number of container instances for a given app. This is useful for handling traffic spikes or achieving high availability.

# Scale the Node app to 3 containers
dokku ps:scale hello-node web=3

# Verify
dokku ps:report hello-node

Dokku uses Docker’s built‑in load balancing via Nginx; incoming requests are distributed across all running containers. You can also set resource limits per container using the dokku config:set syntax with Docker flags.

dokku config:set hello-node DOKKU_WEB_MEMORY_LIMIT=256M
dokku config:set hello-node DOKKU_WEB_CPU_LIMIT=0.5

These settings prevent a single container from monopolizing the host’s RAM or CPU, a crucial safeguard when you host many apps on the same machine.

Real‑World Use Cases for Dokku

  • Start‑up MVP hosting: Spin up a cheap VPS, deploy a prototype, and iterate quickly without paying per‑dyno fees.
  • Agency multi‑client platform: Give each client their own subdomain and isolated container, while sharing the same underlying hardware.
  • Internal CI/CD sandbox: Developers push feature branches to dokku to spin up preview environments that disappear after testing.
  • Educational labs: Teach students about Docker, CI/CD, and PaaS concepts by letting them manage real deployments.

Because Dokku is just a thin layer over Docker, you can integrate it with existing orchestration tools like Kubernetes (as a “gateway” for simple apps) or with monitoring stacks such as Prometheus + Grafana for deep observability.

Backup Strategies and Disaster Recovery

Running a PaaS means you’ll eventually need to protect data. Dokku itself is stateless, but attached services (databases, file storage) are not. The recommended approach is to schedule regular dumps of each service and store them off‑site.

# Example: Daily PostgreSQL backup for app "flask-app"
dokku postgres:export mydb > /var/backups/mydb_$(date +%F).sql
# Upload to S3 (requires AWS CLI configured)
aws s3 cp /var/backups/mydb_$(date +%F).sql s3://my-backups/dokku/

Automate the above with a cron job and rotate old backups to keep storage costs low. For container‑level snapshots, Docker’s commit command can capture the exact filesystem state, but it’s generally better to rely on source control and reproducible Dockerfiles.

Pro tip: Use the dokku plugin:install https://github.com/dokku/dokku-snapshot.git snapshot plugin to create point‑in‑time snapshots of the entire Dokku environment with a single command.

Monitoring, Logging, and Performance Tweaks

Out of the box Dokku forwards container logs to docker logs, which you can view with dokku logs. For production, pipe these logs to a centralized system like Papertrail, Loki, or ELK.

# Forward logs to syslog (example for Papertrail)
dokku config:set hello-node LOGSPOUT=papertrail
dokku config:set hello-node PAPERTRAIL_HOST=logs.papertrailapp.com
dokku config:set hello-node PAPERTRAIL_PORT=12345

Metrics such as CPU, memory, and network I/O can be gathered with cAdvisor or the dokku-monitor plugin. Install it with:

dokku plugin:install https://github.com/dokku/dokku-monitor.git monitor
dokku monitor:enable

Once enabled, you’ll have a simple dashboard at /monitor on your server that visualizes per‑app resource consumption.

Extending Dokku with Plugins

Dokku’s plugin architecture is one of its most powerful features. Over 150 community plugins exist, covering everything from SSL automation to custom buildpacks. Here are three favorites for production workloads:

  1. dokku-letsencrypt – automatically fetches and renews free TLS certificates.
  2. dokku-redis – spins up a Redis instance and links it to your app with a single command.
  3. dokku-autodeploy – watches a GitHub repository and triggers a deployment on every push.

Installing a plugin is as simple as:

dokku plugin:install https://github.com/dokku/dokku-redis.git redis
dokku redis:create mycache
dokku redis:link mycache hello-node

After linking, the REDIS_URL environment variable becomes available inside your app, ready for use with any Redis client library.

Security Best Practices

  • SSH keys only: Disable password authentication on the server and enforce key‑based logins for the dokku user.
  • Least‑privilege containers: Use the dokku security:enable command to drop unnecessary Linux capabilities.
  • Automatic updates: Set up unattended upgrades for the host OS and schedule dokku plugin:update weekly.
  • Network isolation: If you host multiple apps, consider creating a Docker network per app and using firewall rules to limit inter‑app traffic.

Combine these with regular vulnerability scans (e.g., trivy on Docker images) to keep your PaaS hardened against emerging threats.

Cost Comparison: Dokku vs. Managed PaaS

Let’s do a quick back‑of‑the‑envelope calculation. A small DigitalOcean droplet (2 vCPU, 4 GB RAM, 80 GB SSD) costs $12/month. With Dokku you can run 5–10 small apps on that single droplet, each consuming ~200 MB RAM. In contrast, the same number of apps on a managed service like Heroku would cost roughly $25–$40/month per dyno, plus add‑ons for databases and SSL.

The trade‑off is operational overhead: you must maintain the host, handle backups, and monitor health. However, for teams comfortable with Linux administration, the cost savings can be substantial, especially at scale.

Troubleshooting Common Issues

Problem

Share this article