Web dashboard for managing a Dokku server. Built with Hono + HTMX, connects via SSH.
- App management — start, stop, restart, destroy, create
- Log streaming (live SSE)
- Environment variables editor
- Domain management with Let's Encrypt
- Process scaling
- Postgres databases with optional SQL explorer
- Google OAuth (restrict to your org) or password auth
The dashboard groups apps by DOKKU_APP_TYPE. You can use any value:
dokku config:set --no-restart my-app DOKKU_APP_TYPE=api
dokku config:set --no-restart my-worker DOKKU_APP_TYPE=worker
dokku config:set --no-restart my-indexer DOKKU_APP_TYPE=indexerApps without this var are shown in the untyped group. If you deploy via GitHub Actions, set it in your workflow:
- name: Create app and configure
run: |
dokku apps:create my-app || true
dokku config:set --no-restart my-app DOKKU_APP_TYPE=bot# 1. Clone
git clone git@github.com:mutativ/dokku-dashboard.git
cd dokku-dashboard
# 2. Interactive setup (generates .env)
./bin/setup.sh
# 3. Deploy to your VPS
./bin/deploy.sh root@your-vps-ip --ssh-key ~/.ssh/your_keyThat's it. The deploy script builds a Docker image, pushes it to your VPS, and deploys it as a Dokku app.
Push to main → auto-deploy. Works out of the box for forks.
Monorepo deployment — stake-dao/backend-monorepo tracks a fork of this repo (stake-dao/dokku-dashboard). The fork auto-syncs from this repo every 6 hours and triggers a redeploy. See
.github/workflows/sync-fork.yml.
-
Add 2 GitHub Secrets to your repo:
Secret Value DOKKU_HOSTVPS IP or hostname DOKKU_SSH_PRIVATE_KEYSSH private key authorized on Dokku -
Optionally set
DOKKU_APP_NAMEas a GitHub Variable (defaults todokku-dashboard). -
Push to
main— the workflow checks out the repo andgit pushes to Dokku, which builds the Dockerfile on the VPS and deploys with zero downtime.
For first-time setup or when changing env config:
# Full deploy — builds image, sets config, deploys
./bin/deploy.sh root@your-vps-ip --ssh-key ~/.ssh/your_key
# Code-only — skip config:set, just rebuild
./bin/deploy.sh --code-only- Fork the repo
- On your VPS:
dokku apps:create dokku-dashboard - Run
./bin/setup.shto generate.env, then./bin/deploy.shonce to create the app and set config - Add the 2 GitHub Secrets above
- Push to
main— auto-deploys from now on
- A server running Dokku
- SSH access (root or a user with
dockergroup) - Docker installed on the VPS (Dokku installs this)
No other dependencies needed on the server — the dashboard runs as a Dokku app itself.
Restrict access to your Google Workspace organization:
- Go to Google Cloud Console and create a project
- Navigate to APIs & Services > OAuth consent screen, select Internal (org only)
- Create OAuth 2.0 credentials (Web application type)
- Add your dashboard URL as an authorized redirect URI:
https://your-domain.com/auth/google/callback - Configure the dashboard:
dokku config:set dokku-dashboard \
AUTH_MODE=google \
GOOGLE_CLIENT_ID="your-client-id" \
GOOGLE_CLIENT_SECRET="your-client-secret" \
GOOGLE_ALLOWED_DOMAIN="yourorg.com" \
PUBLIC_URL="https://your-domain.com"Only users with a @yourorg.com Google account can sign in.
Simple shared password — good for single-user setups:
# Generate a password hash
pnpm run hash-password
# or: npx tsx src/hash-password.ts
# Set it on the server
dokku config:set dokku-dashboard \
AUTH_MODE=password \
DASHBOARD_PASSWORD_HASH="scrypt:..."Set AUTH_MODE=both to show both Google and password login options.
The dashboard connects to Dokku via SSH. Create a key specifically for it:
# On your VPS
ssh-keygen -t ed25519 -f /root/.ssh/dokku_dashboard_key -N ""
# Register it with Dokku
cat /root/.ssh/dokku_dashboard_key.pub | dokku ssh-keys:add dashboardImportant: Don't include
adminin the key name —dokku-aclgrants admin keys unrestricted access.
./bin/setup.shIt prompts for SSH host, port, user, key path, auth mode, and generates a .env file with a random SESSION_SECRET. Use .env.example as a reference for all available options.
# Uses root@<DOKKU_SSH_HOST> from .env by default
./bin/deploy.sh
# Or specify explicitly
./bin/deploy.sh root@1.2.3.4 --ssh-key ~/.ssh/my_key
# Custom app name
./bin/deploy.sh root@1.2.3.4 --app my-dashboardThe deploy script:
- Builds a
linux/amd64Docker image locally - Pushes it via
docker save | ssh docker load - Creates the Dokku app if needed
- Sets all env vars from
.env - Deploys with
git:from-image
dokku domains:add dokku-dashboard your-domain.com
dokku letsencrypt:enable dokku-dashboardInstall dokku-acl to limit what the dashboard's SSH key can do:
dokku plugin:install https://github.com/dokku-community/dokku-acl.git acl
dokku config:set --global DOKKU_ACL_USER_COMMANDS="apps:list,apps:create,apps:destroy,ps:report,ps:start,ps:stop,ps:restart,ps:rebuild,ps:scale,logs,config:get,config:show,config:set,config:unset,domains:report,domains:add,domains:remove,letsencrypt:enable,letsencrypt:disable,postgres:list,postgres:create,postgres:destroy,postgres:info,postgres:link,postgres:unlink,postgres:links,postgres:connect,resource:report,resource:limit"This blocks dangerous commands (docker-options:add, storage:mount, ssh-keys:add, plugin:install, network:*) at the Dokku layer — even if the dashboard is compromised.
Restrict who can reach the dashboard:
- Tailscale — Run on a mesh VPN. Only devices on your tailnet can access it.
- IP allowlist — Restrict via nginx:
mkdir -p /home/dokku/dokku-dashboard/nginx.conf.d echo 'allow 1.2.3.4; deny all;' > /home/dokku/dokku-dashboard/nginx.conf.d/ip-restrict.conf dokku nginx:build-config dokku-dashboard
- Cloudflare Access — Identity-aware proxy at the edge.
If behind a reverse proxy, set TRUSTED_PROXIES so rate limiting uses the real client IP:
dokku config:set dokku-dashboard TRUSTED_PROXIES="10.0.0.1,172.16.0.0/12"pnpm install # or: bun install
pnpm dev # starts with hot reload on :4200| Variable | Required | Default | Description |
|---|---|---|---|
AUTH_MODE |
No | password |
password, google, or both |
DASHBOARD_PASSWORD_HASH |
When password auth | scrypt hash (pnpm run hash-password) |
|
SESSION_SECRET |
Yes | 32+ char hex string for cookie signing | |
GOOGLE_CLIENT_ID |
When google auth | OAuth 2.0 client ID | |
GOOGLE_CLIENT_SECRET |
When google auth | OAuth 2.0 client secret | |
GOOGLE_ALLOWED_DOMAIN |
When google auth | Workspace domain (e.g. yourorg.com) |
|
PUBLIC_URL |
When google auth | Dashboard URL (e.g. https://dash.yourorg.com) |
|
DOKKU_SSH_HOST |
Yes | Dokku server IP/hostname | |
DOKKU_SSH_PORT |
No | 22 |
SSH port |
DOKKU_SSH_USER |
No | dokku |
SSH username |
DOKKU_SSH_KEY |
Yes | Base64-encoded SSH private key | |
PORT |
No | 4200 |
Dashboard port |
ENABLE_SQL_EXPLORER |
No | false |
Enable the SQL query runner |
ENABLE_DESTRUCTIVE_ACTIONS |
No | true |
Enable create/update/delete actions (false = view-only mode) |
TRUSTED_PROXIES |
No | Comma-separated IPs for X-Forwarded-For |
- Hono — HTTP framework
- HTMX — Server-rendered interactivity
- ssh2 — Native SSH client (no system openssh)
- Tailwind CSS — Utility-first styling
- TypeScript — Compiled to JS, runs on Node.js 22
MIT
