A minimal, self-hosted web UI for managing a single-node Dokku server.
Dokku is powerful but CLI-driven. For solo developers and small teams:
- Non-technical teammates can't use it
- Managing apps via SSH is inconvenient
- No centralized visual overview
- Dokku Pro is expensive for small VPS use cases
Docklight fills the gap β a lightweight, self-hosted UI that wraps the Dokku CLI.
Dokku is powerful, but primarily CLI-driven. Docklight adds a lightweight web interface so you can manage apps, databases, domains, SSL, and operational visibility from one place.
Architecture:
Browser -> React SPA -> Express API -> Shell Exec -> Dokku CLI -> Docker
Docklight is designed to run on the same VPS as Dokku.
- Dashboard with app status, domains, last deploy, and VPS health (CPU, memory, disk) with warning/critical thresholds.
- One-click server cleanup from the dashboard for operators and admins: Clean unused runs
dokku cleanup(removes unused containers and images); Purge build caches runsdokku repo:purge-cacheacross all apps when disk is warning or critical (does not remove volumes or runrepo:gc). - App management: restart, rebuild, scale, config vars, and domains.
- Real-time app status updates via WebSocket push notifications.
- Live app logs over WebSocket.
- Git integration: deploy apps from remote repositories.
- Server settings configuration via UI.
- Database management: list, create, link/unlink, destroy.
- SSL management with Let's Encrypt.
- Audit logs for command history, filtering, and export (JSON/CSV).
- Command transparency: exact CLI command, exit code, stdout/stderr.
- Enhanced health checks with Dokku connectivity and database status.
- Simple auth with username/password and JWT session.
| Layer | Stack |
|---|---|
| Backend | Node.js, Express, TypeScript |
| Frontend | React, Vite, Tailwind CSS, TypeScript |
| Database | SQLite (better-sqlite3) |
| Realtime | WebSocket (ws) |
| Auth | JWT (jsonwebtoken) |
| Deployment | Docker, Dokku |
On a fresh Ubuntu/Debian VPS, run as root:
curl -fsSL https://raw.githubusercontent.com/jellydn/docklight/main/scripts/install.sh | sudo bashWith a custom domain, HTTPS, and your public SSH key pre-registered for git push access:
curl -fsSL https://raw.githubusercontent.com/jellydn/docklight/main/scripts/install.sh \
| sudo DOMAIN=docklight.example.com \
ENABLE_HTTPS=1 LETSENCRYPT_EMAIL=you@example.com \
ADMIN_SSH_KEY_URL=https://sshid.io/your-handle \
bashThe installer will:
- Install Dokku (if not already present)
- Create the
docklightapp and persistent storage - Configure the container β host SSH bridge for the Dokku CLI
- Generate a
JWT_SECRET - Deploy Docklight from this repo
- Create an initial admin user and print the password
- (Optional) Register your public key with Dokku so you can
git push dokku mainandssh dokku@<ip>without a password
Available env vars: APP_NAME, DOMAIN, REPO_URL, BRANCH, DOKKU_VERSION, ENABLE_HTTPS, LETSENCRYPT_EMAIL, ADMIN_USERNAME, ADMIN_PASSWORD, ADMIN_SSH_KEY_URL, ADMIN_SSH_KEY, GLOBAL_DOMAIN.
By default the installer sets Dokku's global vhost to
<ip>.sslip.io, so any future app you create (Docklight or otherwise) gets a usable URL like<app>.<ip>.sslip.ioout of the box β instead of inheriting the provider's system hostname (e.g.*.contaboserver.net). Override withGLOBAL_DOMAIN=apps.yourdomain.com, or passGLOBAL_DOMAIN=(empty) to keep Dokku's auto-detected value.
Already installed without ADMIN_SSH_KEY_URL? Add your key from your laptop:
# Single key from a local file
cat ~/.ssh/id_ed25519.pub \
| ssh root@<server-ip> "sudo -u dokku dokku ssh-keys:add admin"
# Single key from sshid.io / github.com/<user>.keys
curl -fsSL https://sshid.io/your-handle \
| ssh root@<server-ip> "sudo -u dokku dokku ssh-keys:add admin"Multiple keys?
dokku ssh-keys:addaccepts one key per call. Ifhttps://sshid.io/<handle>orhttps://github.com/<user>.keysreturns several lines, pipe them in individually under distinct names (admin-laptop,admin-desktop, β¦), or β easier β re-run the installer withADMIN_SSH_KEY_URL=β¦, which loops over every line and registers them asadmin,admin-2,admin-3, β¦.
Still getting
dokku@<host>'s password:after adding a key? Your local key probably doesn't match what was registered (common whenADMIN_SSH_KEY_URLpublished a key from another machine). See docs/deployment.md β SSH still prompts for a password for the 3-step debug + fix.
# On your Dokku server
dokku apps:create docklight
dokku config:set docklight JWT_SECRET=your-secure-random-secret
# From your local machine
git remote add dokku dokku@<your-server-ip>:docklight
git push dokku mainFull guide: docs/deployment.md
To completely remove Docklight, Dokku, and all associated data from a VPS, run as root:
curl -fsSL https://raw.githubusercontent.com/jellydn/docklight/main/scripts/uninstall.sh | sudo bashThe script stops the Docklight app, removes the auto-update timer (if any), destroys the Dokku app, purges Dokku and herokuish packages, removes /home/dokku, /var/lib/dokku, and /var/log/dokku, and deletes the dokku user.
WARNING: This is destructive β it removes all apps, databases, SSL certs, and configs. Interactive confirmation is required unless CONFIRM=1 is set.
| Variable | Description | Default |
|---|---|---|
APP_NAME |
Dokku app name to destroy | docklight |
REMOVE_DOCKER |
Also purge Docker (1/0) |
0 |
CONFIRM |
Skip interactive confirmation (1/0) |
0 |
# Install dependencies
cd server && bun install
cd ../client && bun install
cd ..
# Required env
export JWT_SECRET=dev-secret-change-in-production
# Terminal 1
cd server && bun run dev
# Terminal 2
cd client && bun run devFirst-time setup: After starting the server, create an admin user:
cd server
npx tsx createUser.ts admin your-password-hereThen open http://localhost:5173 and log in with the credentials you created.
Or use just:
just install
just server-dev
just client-dev# Show available commands
just
# Install dependencies
just install
# Run dev servers
just server-dev
just client-dev
# Quality checks
just lint
just format
just typecheck
just test
# Build
just build| Variable | Required | Description |
|---|---|---|
JWT_SECRET |
Yes (in production) | JWT signing secret |
DOCKLIGHT_DOKKU_SSH_TARGET |
No (recommended in production) | Container-reachable Dokku SSH target (e.g. dokku@172.17.0.1); the public IP may not work from inside Docker |
DOCKLIGHT_DOKKU_SSH_KEY_PATH |
No | Private key path inside container |
DOCKLIGHT_DOKKU_SSH_OPTS |
No | Extra SSH options |
PORT |
No | Server port (default 3001) |
DOCKLIGHT_RATE_LIMIT_WINDOW_MS |
No | Rate limit window in ms (default 900000 = 15 min) |
DOCKLIGHT_AUTH_MAX_REQUESTS |
No | Max auth login requests per window (default 5, dev: 1000) |
DOCKLIGHT_AUTH_CHECK_MAX_REQUESTS |
No | Max auth check requests per window (default 300, dev: 10000) |
DOCKLIGHT_COMMAND_WINDOW_MS |
No | Command rate limit window in ms (default 60000 = 1 min) |
DOCKLIGHT_COMMAND_MAX_REQUESTS |
No | Max command executions per window per user (default 30, dev: 1000) |
DOCKLIGHT_ADMIN_MAX_REQUESTS |
No | Max admin API requests per window (default 30, dev: 1000) |
DOCKLIGHT_APP_URL |
Yes (if reset email enabled) | App URL used to build password reset links (e.g. https://docklight.example.com). Required when RESEND_API_KEY is configured. |
RESEND_API_KEY |
No | API key for Resend email delivery service (required for password reset emails) |
RESEND_FROM_EMAIL |
No | Sender email address for password reset emails (e.g. Docklight <no-reply@yourdomain.com>) |
These are only used by scripts/install.sh (the one-line install):
| Variable | Required | Description |
|---|---|---|
APP_NAME |
No | Dokku app name (default docklight) |
DOMAIN |
No | Custom domain (default <ip>.sslip.io) |
REPO_URL |
No | Git repo to deploy (default this repo) |
BRANCH |
No | Branch to deploy (default main) |
DOKKU_VERSION |
No | Dokku version to install (default v0.35.20) |
ENABLE_HTTPS |
No | Run Let's Encrypt after deploy (1/0, default 0) |
LETSENCRYPT_EMAIL |
If ENABLE_HTTPS=1 |
Email for Let's Encrypt |
ADMIN_USERNAME |
No | Initial admin username (default admin) |
ADMIN_PASSWORD |
No | Initial admin password (default auto-generated) |
ADMIN_SSH_KEY_URL |
No | URL returning operator's SSH public key (e.g. https://sshid.io/<handle>) |
ADMIN_SSH_KEY |
No | Inline SSH public key content (alternative to URL) |
GLOBAL_DOMAIN |
No | Override Dokku global vhost (default <ip>.sslip.io, empty to keep current) |
ENABLE_AUTO_UPDATE |
No | Install a systemd timer for automatic updates (1/0, default 0) |
AUTO_UPDATE_SCHEDULE |
No | systemd OnCalendar value (default daily) |
AUTO_UPDATE_REPO_URL |
No | Git repo for auto-update (default REPO_URL) |
AUTO_UPDATE_BRANCH |
No | Branch for auto-update (default BRANCH) |
AUTO_UPDATE_KEEP_BACKUPS |
No | Number of DB backups to keep (default 5) |
Docklight executes Dokku commands on your server.
- Always set a strong
JWT_SECRET. - Always expose Docklight behind HTTPS.
- Keep SSH fallback access to your server.
- Command execution is restricted to an allowlist.
- Create admin users via CLI or database for access.
docklight/
βββ client/ # React + Vite frontend
βββ server/ # Express + TypeScript backend
βββ docs/ # Documentation (deployment, etc.)
βββ .github/workflows # CI/CD workflows
βββ justfile # Task runner commands
| Category | Commands |
|---|---|
| Apps | apps:list, apps:create, apps:destroy, ps:report, ps:restart, ps:stop, ps:start, ps:rebuild, ps:scale |
| Config | config:show, config:set, config:unset |
| Domains | domains:report, domains:add, domains:remove |
| Git | git:report, git:sync --build |
| Logs | logs <app> -t -n <lines> |
| Databases | plugin:list, <plugin>:list, <plugin>:links, <plugin>:create, <plugin>:link, <plugin>:unlink, <plugin>:destroy |
| Plugins | plugin:list, plugin:install, plugin:enable, plugin:disable, plugin:uninstall |
| SSL | letsencrypt:report, letsencrypt:ls, certs:report, letsencrypt:set <app> email <email>, letsencrypt:enable, letsencrypt:auto-renew |
| Server | cleanup, |
Contributions are welcome. Please read our contributing guidelines before submitting PRs.
This project is licensed under the MIT License - see the LICENSE file for details.
π€ Dung Huynh
- Website: https://productsway.com
- Twitter: @jellydn
- GitHub: @jellydn
Give a βοΈ if this project helped you!