Self-hosted Docker app deployment platform. Deploy Docker Compose stacks to your own VMs with auto HTTPS, Cloudflare DNS, and Git-based CI/CD — all from a single binary.
Inspired by Coolify. Built for simplicity.
- Single binary — Go + SQLite, no external dependencies
- Caddy reverse proxy — auto Let's Encrypt, no config needed
- Cloudflare DNS — auto-create DNS records on deploy
- Git webhook — push to main, auto deploy
- VM pool — add VMs, deploy to least-loaded VM
- SSH console — interactive terminal via browser (WebSocket + xterm.js)
- Dashboard — live resource monitoring and deployment status at a glance
- Encrypted backups — export/import config with AES-GCM passphrase encryption
- Web UI — manage everything from the browser, dark/light mode
Controller VM (Dockify binary)
├── Web UI + REST API (:8080)
├── SQLite (state)
├── SSH manager → workers
├── Caddy Admin API → inject routes
├── Cloudflare API → DNS
└── Git webhook → auto deploy
Worker VM
├── Caddy (Docker, :80/:443 + Admin API :2019)
├── App containers (Docker Compose)
└── Caddy routes to containers via Docker network
Setting up a new controller or worker VM for production? Follow the step-by-step VM setup and security SOP (firewall, loopback bind, key-only SSH, controller-generated worker keys, host-key verification, rollback).
Recommended OS: Debian 12 (minimal, no GUI). All specs are total VM size (OS + Dockify).
| Mode | Min vCPU | Min RAM | Min Disk | RAM used | HTTPS | Docker? |
|---|---|---|---|---|---|---|
| 1: Docker Compose | 1 | 1 GB | 10 GB | ~100 MB | Auto (Caddy container) | ✅ |
| 2: Binary only | 1 | 512 MB | 10 GB | ~30 MB | Manual | ❌ |
| 3: Binary + Caddy | 1 | 512 MB | 10 GB | ~40 MB | Auto (native Caddy) | ❌ |
Option A: Binary + native Caddy (lightweight + auto HTTPS) — recommended
curl -fsSL https://raw.githubusercontent.com/coderbuzz/dockify/main/scripts/install.sh | bash
# Select mode 3 (Binary + Caddy)
sudo systemctl start dockify-caddyDockify + Caddy run as native binaries (no Docker). Caddy auto-obtains Let's Encrypt certificates and proxies to Dockify on 127.0.0.1:8080.
Option B: Binary only (lightest)
curl -fsSL https://raw.githubusercontent.com/coderbuzz/dockify/main/scripts/install.sh | bash
# Select mode 2 (Binary only)
sudo systemctl start dockifyNo Caddy, no Docker. Access at http://<ip>:8080. Add a reverse proxy manually if needed.
Option C: Docker Compose (bundled Caddy)
curl -fsSL https://raw.githubusercontent.com/coderbuzz/dockify/main/scripts/install.sh | bash
# Select mode 1 (Docker Compose) - default
cd /opt/dockify && docker compose up -dThe image binds DOCKIFY_HOST=0.0.0.0, so the container needs DOCKIFY_ADMIN_PASSWORD in /opt/dockify/.env (the installer asks for it) or it exits at start; DOCKIFY_ALLOW_NO_AUTH=true overrides this.
Worker SSH keys live in the dockify_data volume (/var/lib/dockify/keys); the host's ~/.ssh is not mounted. Dockify generates each worker's key when you add the server and shows the public key on the server page (Step 2). Older compose files mounted ${HOME}/.ssh read-only, which made adding a server fail with read-only file system: re-download docker-compose.yml and run docker compose up -d.
Option D: Build from source (development)
git clone https://github.com/coderbuzz/dockify.git
cd dockify
go build -o dockify ./cmd/dockify
DOCKIFY_HOST=127.0.0.1 ./dockify serve # or set DOCKIFY_ADMIN_PASSWORDAll installation methods share the same architecture for worker VMs:
- Dockify connects to workers via SSH
- Installs Docker + creates the
dockifyDocker network on each worker - Deploys Caddy on each worker (port 80/443 + Admin API on localhost:2019)
- Apps communicate with Caddy through the
dockifynetwork
The choice between binary and Docker only affects how you host the Dockify controller itself. Worker VMs are identical either way.
Open https://<your-domain> or http://<controller-ip>:8080.
Create a .env file in the project root or set these environment variables:
| Variable | Default | Required | Description |
|---|---|---|---|
DOCKIFY_HOST |
0.0.0.0 |
No | Network interface to bind |
DOCKIFY_PORT |
8080 |
No | HTTP port |
DOCKIFY_DATA_DIR |
/var/lib/dockify |
No | SQLite DB + data storage directory |
DOCKIFY_SSH_KEY_DIR |
/var/lib/dockify/keys |
No | Per-server SSH private key storage |
DOMAIN |
— | Mode 1 | Domain for Caddy reverse proxy (auto HTTPS) |
DOCKIFY_ADMIN_USER |
admin |
No | Web UI login username |
DOCKIFY_ADMIN_PASSWORD |
— | Yes, unless bound to loopback | Web UI password. Without it Dockify refuses to start on a non-loopback DOCKIFY_HOST |
DOCKIFY_ALLOW_NO_AUTH |
false |
No | true lets Dockify start without a password on a non-loopback bind (web UI open to anyone who can reach it) |
DOCKIFY_API_TOKEN |
— | No | Bearer token for scripts/agents calling /api/* (needs DOCKIFY_ADMIN_PASSWORD set) |
DOCKIFY_DEV_MOCK |
false |
No | Enable mock SSH for local development (no real VMs needed) |
CLOUDFLARE_API_TOKEN |
— | No | Cloudflare API token for automatic DNS A records |
CLOUDFLARE_ZONE_ID |
— | No | Cloudflare zone ID |
DOCKIFY_BASE_PATH |
— | No | URL prefix when behind a reverse proxy (e.g. /proxy/9898); links and redirects stay under it. A proxy can send X-Forwarded-Prefix per request instead |
DOCKIFY_TRUST_PROXY |
false |
No | true takes the client IP from X-Forwarded-For/X-Real-IP (login throttle, logs). Set it only when every request comes through a proxy that sets these headers |
To enable web UI authentication, set DOCKIFY_ADMIN_PASSWORD:
# In .env
DOCKIFY_ADMIN_USER=admin
DOCKIFY_ADMIN_PASSWORD=secret123
# Or as env vars
DOCKIFY_ADMIN_PASSWORD=secret123 docker compose up -d- Default username:
admin(configurable viaDOCKIFY_ADMIN_USER) - No password set: Dockify refuses to start unless it binds to loopback (
DOCKIFY_HOST=127.0.0.1,::1orlocalhost) orDOCKIFY_ALLOW_NO_AUTH=trueis set; in both cases the web UI has no authentication - Password set: All routes (except
/healthand/api/webhook/*) require login - Failed logins: each one waits 1 s; more than 10 from one client IP within 15 minutes get
429until the 15 minutes are over. The client IP is the TCP peer unlessDOCKIFY_TRUST_PROXY=true. Behind a reverse proxy (e.g. Caddy in front of127.0.0.1:8080) setDOCKIFY_TRUST_PROXY=trueand keep the port unreachable from outside; otherwise every client counts as the proxy and failed logins from anyone lock everyone out for 15 minutes - Session: Cookie-based (
HttpOnly,SameSite=Lax,Securebehind HTTPS), expires after 24 hours - Cross-site requests: a form or script on another site cannot change anything (
403). Behind a reverse proxy, forward the originalHostheader (Caddy does this by default) - Logout: Visit
/logout
API token (scripts, CI, AI agents): set DOCKIFY_API_TOKEN (e.g. openssl rand -hex 32) and
send it as a bearer header. It works on every protected route, needs no login and survives
controller restarts and self-updates. A wrong token gets 401; requests without the header
still get the login redirect.
curl -H "Authorization: Bearer $DOCKIFY_API_TOKEN" https://dockify.example.com/api/apps
curl -X POST -H "Authorization: Bearer $DOCKIFY_API_TOKEN" https://dockify.example.com/api/settings/update/runThe login page is at /login. Webhook endpoints (/api/webhook/github, /api/webhook/gitlab) and health check (/health) do not require authentication.
Fresh Ubuntu/Debian VM. Zero dependencies needed — Dockify installs everything.
-
In Dockify go to Servers → Add Server and fill in:
- Name:
worker-01 - Host:
<worker-ip> - User: the SSH user Dockify connects as (
root, or a user in thedockergroup)
- Name:
-
Leave the SSH key empty and click Add Server. Dockify generates an ed25519 key pair on the controller; the private key never leaves it. The server page shows the public key and the command to run on the worker.
-
On the worker VM, as that user, run the command from the server page:
curl -fsSL https://raw.githubusercontent.com/coderbuzz/dockify/main/scripts/setup-worker.sh | bash -s -- 'ssh-ed25519 AAAA... dockify'
The script adds the key to
~/.ssh/authorized_keys, installs Docker + the Docker Compose plugin (if not present), prepares/opt/dockifyand prints the worker IP and user. Run without an argument it only prints its usage. -
Back in Dockify, click Init Worker on the server page.
The public_key is also returned by POST /api/servers (send no ssh_key) and GET /api/servers/{id}.
Advanced: existing key. Under Advanced on the Add Server form you can paste an existing private key instead (the key material, not a file path); then Dockify tests the connection and initializes the worker right away.
Host keys. The first connection to a worker pins its SSH host key; the fingerprint is on the server page. If the worker presents a different key later, every connection fails with "host key mismatch". After reinstalling a worker, tick Forget pinned host key on its edit page (or PATCH /api/servers/{id} with {"host_key_clear": true}); changing host or port also forgets it.
Workers set up with an older
setup-worker.shstill hold the private key~/.ssh/dockify(and~/.ssh/dockify.pub). Dockify keeps its own copy, so both files can be deleted on the worker; keep the matching line in~/.ssh/authorized_keys, Dockify still logs in with that key.
What "Initialize Worker" does automatically:
- SSH connect + verify
- Install Docker via
get.docker.com(if not present) - Install Docker Compose plugin (if not present)
- Create
dockifyDocker network - Deploy Caddy container
caddy:2(port 80/443 + Admin API on localhost:2019). Acaddycontainer Dockify did not create (no/opt/dockify/caddymount, nodockify.managed=truelabel) is left alone and init fails until it is removed or renamed - Collect CPU, RAM, Disk info
- Status → online. Ready to deploy apps.
Initialization is idempotent — re-running it on an already-initialized server skips existing components.
- Go to Apps → Deploy App
- Choose Simple Mode (just an image name + env vars + volumes) or Advanced Mode (full
docker-compose.yml) - Set domain, port, and select a server (or Auto-select for least-loaded)
- Optional: fill Basic Auth username/password to protect the app behind HTTP basic auth
- Click Deploy App
What happens on deploy:
- SSH → write compose file to
/opt/dockify/apps/<name>/ - SSH →
docker compose up -d - Inject Caddy route via Admin API (domain → container:port)
- If basic auth is set, Caddy requires username/password before proxying
- Create Cloudflare DNS A record (if configured, skips duplicates)
- Record deployment + save compose snapshot for rollback
- Status → running
The home page (/) provides a live overview of your infrastructure:
- Stats cards — total servers, online servers, total apps, running apps
- Server summary — all servers with live CPU/RAM usage and status badges
- App summary — all apps with status badges and domain links
- Empty state call-to-action buttons when no servers or apps exist yet
The Servers page lists all worker VMs with connection status and live resource usage. Click any server for its detail page.
Servers can be added via the web form (name, host, port, user; Dockify generates the SSH key pair, or you paste an existing private key) and edited after creation — update host, port, user, or SSH key without deleting and re-adding.
Each server can optionally store one registry credential (Registry Host, default ghcr.io; Registry User; Registry Token) so private images can be pulled without making the package public or running docker login by hand on the worker.
- On every deploy, if the server has a credential, Dockify runs
docker login <host> -u <user> --password-stdinon the worker beforedocker compose pull. The token is sent over the SSH session's stdin — it never appears in the remote command line (ps, shell history). - If login fails, the deploy stops and the deployment log shows
registry login failed: …with the token redacted ([REDACTED]). - The token is stored like the SSH private key: a
0600file inDOCKIFY_SSH_KEY_DIR(<id>.registry-token); the database only holds its path. It is never returned by the API or shown in the UI. - When editing a server, leave the token empty to keep the current one; tick Remove registry credential to delete it (host, user, and token file).
- Servers without a credential deploy exactly as before (no login).
- Docker saves the login in
~/.docker/config.jsonof the SSH user on the worker (standarddocker loginbehavior). - API:
POST /api/serversandPATCH /api/servers/:idacceptregistry_host,registry_user,registry_token;PATCHalso accepts"registry_clear": true.
Creating a GHCR token (PAT):
- GitHub → Settings → Developer settings → Personal access tokens → Tokens (classic) → Generate new token (classic).
- Select only the
read:packagesscope (pulling needs nothing more). Set an expiration that suits you. - Copy the token (
ghp_…) into the server's Registry Token field, with your GitHub username as Registry User andghcr.ioas Registry Host.
For an organization package, the token's owner must have read access to the package (or the org must allow the user via package settings). If the org enforces SSO, authorize the token for that org.
Dockify collects CPU, RAM, and disk usage from all online servers every 10 seconds in the background. Resource cards update via HTMX partial refresh (no page reload). A manual refresh button is available on each server detail page.
- CPU — core count via
nproc, usage % via two-sample/proc/stat(1s interval) - RAM — total and usage via
/proc/meminfo(MemTotal/MemAvailable), with human-readable "used / free" info - Disk — total and usage via
df -BG
Real-time WebSocket stats (GET /api/servers/:id/stats/live) stream live metrics every 1 second for the server detail page resource card.
The scheduler uses these metrics to auto-select the least-loaded server (score = CPU% × 0.5 + RAM% × 0.5).
Each server detail page includes an interactive SSH terminal powered by xterm.js and WebSocket. Open a full terminal session directly in the browser — no SSH client needed.
- WebSocket connection:
GET /api/servers/:id/console - Full xterm.js with FitAddon for responsive terminal sizing
- Window resize events propagate to the remote PTY
- Raw keystroke passthrough for a native terminal feel
The Initialize Worker action installs Docker, creates the dockify network, and deploys Caddy. It is idempotent — safe to run multiple times.
The Apps page lists all deployed apps. Click any app for its detail page with full management controls.
- Simple Mode — provide an image name, port, volumes, environment variables, resource limits, and an optional command override. Dockify auto-generates the docker-compose file.
- Advanced Mode — paste a full
docker-compose.ymlwith complete control over the stack.
The compose mode (simple / advanced) is tracked per app and used to render the correct edit form.
Optionally enforce container resource constraints via dropdown selects:
- Memory Limit —
128m,256m,512m,1g,2g,4g - CPU Limit —
0.25,0.5,1.0,2.0,4.0 - Log Max Size — max size per log file (
10m,50m,100m,500m,1g) - Log Max File — number of log files to keep (
1,3,5,10)
Defaults to "unset" (no limit applied). In Advanced mode, set resource limits directly in the compose YAML.
Override the container's default command/entrypoint. Useful for passing flags or running a specific script instead of the image's built-in CMD. Leave empty to use the image default.
Re-configure an existing app via the edit page. Dockify pre-fills the form with current settings (parsed from simple fields or the raw compose), saves changes, and automatically redeploys the app.
When creating or editing an app, set the server field to Auto-select (or server_id=0 via API). Dockify picks the least-loaded online worker VM based on CPU and RAM usage.
Pause and resume an app without undeploying or losing configuration. Stopping runs docker compose stop and removes the Caddy route. Starting re-creates the route and DNS record.
Roll back to the last successful deployment. Dockify restores the compose snapshot saved at deploy time and redeploys the app.
Each app keeps a history of deployments with status (running/failed), log output, commit SHA (for Git-triggered deploys), and timestamps. Viewable on the app detail page.
Stream container logs via SSH (docker compose logs). Lazy-load buttons on the app detail page let you tail the last 50, 200, or 500 lines with HTMX partial updates.
While an app is deploying or a server is initializing, the detail page auto-refreshes every 2 seconds until the operation completes.
Each app's environment variables are managed through a unified editor with per-variable type control:
- Plain — value is visible in the UI and editable inline
- Secret — value is masked (
••••••) in the UI and encrypted in exports
Multi-line support — values can span multiple lines (useful for private keys, certificates, etc.) using resizable textareas.
On deploy, all variables (plain + secret) are written to a .env file at /opt/dockify/apps/<name>/.env on the worker VM (mode 0600, rewritten on every deploy so removed variables disappear). Each value is trimmed and written double-quoted (KEY="value"), so quotes, spaces, # and $ reach the app unchanged and multi-line values arrive as written. Keys must match [A-Za-z_][A-Za-z0-9_]*. In Simple mode, the compose file auto-generates ${KEY} environment variable references, so containers can access all variables without manual compose editing.
Editing secrets: On the edit page, secret values are shown as empty (like GitHub Actions). Leave empty to keep the existing value. Type a new value to override.
Import from .env: Click the import button to open a modal dialog, paste KEY=VALUE lines, and bulk-add variables. Imported variables default to the Secret type.
Each app can have arbitrary config files. Files are written to /opt/dockify/apps/<name>/<path> on the worker VM. Paths are relative to the app folder, without .., and use only A-Z a-z 0-9 . _ / -. Removing a file in Dockify does not delete it from the worker. Upload files directly from the browser (FileReader API) or paste content. Manage them inline on the app detail page.
Set auth_user and auth_pass on an app to require HTTP basic auth before accessing it. Caddy enforces this at the proxy level with bcrypt — the app itself does not need to handle authentication.
In simple mode, Dockify renames the first service in the generated compose to a sanitized version of the app name (replacing ., _, spaces with -). This prevents service name conflicts when multiple apps use the same image.
Dockify can auto-deploy on every push via GitHub or GitLab webhooks. When an app is created with a Git Repo URL and Branch, Dockify matches incoming webhooks by repo + branch and triggers a redeploy. A single webhook can trigger redeploys for multiple matching apps.
A global webhook secret is auto-generated on first startup. See the Webhook Security section below.
- In your app repo, go to Settings → Webhooks → Add webhook
- Fill in:
Payload URL: https://dockify.example.com/api/webhook/github Content type: application/json Secret: <copy from Dockify Settings page — Webhook Secret field> Events: Just the push event - In the Dockify UI, when creating the app, fill in:
- Git Repo URL:
https://github.com/user/repo.git - Branch:
main
- Git Repo URL:
Dockify verifies incoming webhooks using HMAC-SHA256 (GitHub) or secret token (GitLab). Non-push events are ignored gracefully (returns 200 with "ignored").
Dockify auto-generates a global webhook secret (64-character hex) on first startup, stored in the database. You can view, copy, or regenerate (roll) it on the Settings page (/settings). It cannot be turned off: every webhook must be signed.
Dockify validates every incoming webhook:
- GitHub — HMAC-SHA256 via
X-Hub-Signature-256header - GitLab — token via
X-Gitlab-Tokenheader
If the signature or token does not match, the webhook is rejected with 401 Unauthorized.
To configure:
- Go to Settings in the Dockify web UI
- Click Show → Copy the webhook secret
- Paste it as the Secret in your GitHub/GitLab webhook settings
- For GitHub Actions, pass the secret via
${{ secrets.DOCKIFY_WEBHOOK_SECRET }}(see the example below)
Note: When you Roll the secret, the old one stops working immediately. Update all CI secrets to match.
Add repository secrets (Settings → Secrets and variables → Actions):
DOCKIFY_URL— your Dockify URL (e.g.https://dockify.example.com)DOCKIFY_WEBHOOK_SECRET— the webhook secret from Dockify Settings
The workflow signs the payload with the secret (HMAC-SHA256):
name: Deploy via Dockify
on:
push:
branches: [main]
jobs:
test-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run tests
run: |
echo "Running tests..."
# npm test, go test, etc.
- name: Trigger Dockify deploy
env:
DOCKIFY_URL: ${{ secrets.DOCKIFY_URL }}
DOCKIFY_WEBHOOK_SECRET: ${{ secrets.DOCKIFY_WEBHOOK_SECRET }}
run: |
REPO="https://github.com/${{ github.repository }}.git"
BRANCH="${GITHUB_REF#refs/heads/}"
COMMIT="${{ github.sha }}"
PAYLOAD=$(cat <<EOF
{"ref":"refs/heads/${BRANCH}","after":"${COMMIT}","repository":{"clone_url":"${REPO}"}}
EOF
)
SIGNATURE=$(echo -n "$PAYLOAD" | openssl dgst -sha256 -hmac "$DOCKIFY_WEBHOOK_SECRET" | sed 's/^.* //')
curl -s -o /dev/null -w "%{http_code}" \
-X POST $DOCKIFY_URL/api/webhook/github \
-H "Content-Type: application/json" \
-H "X-GitHub-Event: push" \
-H "X-Hub-Signature-256: sha256=${SIGNATURE}" \
-d "$PAYLOAD"- GitHub sends a push event to
POST /api/webhook/github - Dockify parses
ref→ branch,after→ commit SHA,clone_url→ repo URL - Finds all matching apps by
git_repo+git_branch - Triggers
deployWithCommit(app.ID, commitSHA)for each match — same deploy flow as UI - Records the deployment with commit SHA in history
When CLOUDFLARE_API_TOKEN and CLOUDFLARE_ZONE_ID are configured, Dockify automatically manages DNS records on deploy:
- Creates an A record pointing to the worker VM's IP on app deploy (120s TTL)
- Skips creation if a matching record already exists (deduplication)
- Upserts records if the worker IP changes on re-deploy
- DNS records are tracked in the database for cleanup
- Certificate-safe updates: When updating an existing A record with a different IP, Dockify temporarily disables Cloudflare's proxy (orange cloud → gray) to allow Caddy to complete HTTP-based certificate validation. Once the certificate is issued, the proxy is re-enabled to its original state.
No DNS automation occurs if the env vars are not set.
Export your configuration (servers + apps with their resource limits, command, ports and every domain + secrets + config files) as YAML and import it into another instance.
Backups can be protected with a passphrase using AES-GCM encryption (PBKDF2 key derivation, 600,000 iterations):
- Secret environment variables, SSH keys, registry tokens, and auth passwords are encrypted before export
- Plain environment variables are exported as readable YAML (they are not sensitive by definition)
- The
is_secretflag is preserved on import, so plain/secret distinctions survive migration - Encrypted values use the prefix
enc:with base64 salt + nonce + ciphertext - The export page includes a client-side passphrase generator (32-character hex, via
crypto.getRandomValues) - Without a passphrase, data is exported without encryption (still useful for offline/internal backups)
When importing on a new instance, all servers and their SSH keys are restored automatically — no need to re-enter keys one by one, as long as the target VMs are reachable or use the same key pair.
Upload a previously exported YAML file via the Import page (/import):
- merge (default): skip entries that already exist by name
- replace: delete all existing servers and apps before import; refused unless every app is stopped, a draft or never deployed (stop or undeploy running apps first)
- Encrypted values are validated by attempting decryption before the actual import
Both Export and Import are accessible from dedicated pages (/export, /import) and also linked from the Settings page for convenience.
The Settings page (/settings) provides centralized management:
| Feature | Description |
|---|---|
| Webhook Secret | View, copy, or roll (regenerate) the global webhook secret |
| Update Check | Checks GitHub Releases for a newer version |
| Run Update | Triggers a self-update via systemd-run — runs update.sh from the latest release tag found by the update check (refused when none is known); output in journalctl -u dockify-upgrade |
The About page (/about) shows the current version, project description, and a Sponsor link. An update progress bar with live polling keeps you informed during self-updates.
Dockify's web UI is built with Go html/template + HTMX and fully custom CSS (no framework):
- Dark/Light mode — toggle via nav button, persisted in
localStorage(dockify-theme) - HTMX partial updates — resource cards, log viewer, and status badges update without full page reloads
- No CDN scripts — htmx and xterm.js are embedded in the binary and served from
/static/; a Content-Security-Policy limits scripts to Dockify itself (only Google Fonts is loaded from outside) - Responsive — adapts to mobile screen sizes (single breakpoint at 600px)
- Status badges — color-coded for all server and app states
- Confirm dialogs — destructive actions (undeploy, delete, rollback) require confirmation
- Relative timestamps — deployment and resource times rendered in browser timezone
For local development without real worker VMs, set DOCKIFY_DEV_MOCK=true:
- Enables a mock SSH client with realistic CPU/RAM/Disk responses
- Mock SSH console — simulated interactive terminal that echoes commands
- A yellow "Dev Mock Mode" banner appears above the nav bar
- Works with Air for live-reload:
air # starts at http://localhost:8080, auto-rebuilds on saveData is stored in ./data/ (SQLite DB, gitignored). See AGENTS.md for full development workflow details.
A universal update script detects your install mode and updates accordingly:
curl -fsSL https://raw.githubusercontent.com/coderbuzz/dockify/main/scripts/update.sh | bashBinary installs are checked against the release's dockify-linux-amd64.sha256 before the binary is replaced; the update aborts if the file is missing (releases published before checksums have none) or does not match. DOCKIFY_VERSION=vX.Y.Z pins the release.
Or manually per mode:
Mode 1 (Docker Compose):
cd /opt/dockify && docker compose pull && docker compose up -dMode 2 & 3 (Binary):
sudo systemctl stop dockify
sudo curl -fsSL -o /usr/local/bin/dockify \
"https://github.com/coderbuzz/dockify/releases/latest/download/dockify-linux-amd64"
sudo chmod +x /usr/local/bin/dockify
sudo systemctl start dockifyscripts/gen-ssh-key.sh generates a dedicated SSH key on any VM for external,
general-purpose access — e.g. handing an agentic AI SSH access for remote
debugging, running shell commands, or cleaning up a compromised VM. It is fully
independent of Dockify's automation key, so you can revoke or rotate it without
affecting Dockify.
curl -fsSL https://raw.githubusercontent.com/coderbuzz/dockify/main/scripts/gen-ssh-key.sh | bashThe script will:
- Generate an SSH key pair at
$HOME/.ssh/remote-access(ed25519, no passphrase) - Add the public key to
$HOME/.ssh/authorized_keys - Configure
KexAlgorithmsin/etc/ssh/sshd_config(requiressudo) - Output the private key content — copy this into your agentic-AI / SSH client config
The key is generic and separate from the key Dockify itself connects with.
To revoke access later: rm ~/.ssh/remote-access* and remove its line from
~/.ssh/authorized_keys.
dockify/
├── cmd/dockify/main.go
├── internal/
│ ├── ssh/ # SSH client, remote exec, worker init, mock client
│ ├── server/ # Server CRUD, resource monitoring
│ ├── app/ # App CRUD, deployment, rollback, stats collector
│ ├── caddy/ # Caddy Admin API client
│ ├── cloudflare/ # Cloudflare DNS API
│ ├── webhook/ # Git webhook handler (GitHub + GitLab)
│ ├── scheduler/ # Idle server auto-selection
│ ├── settings/ # Global settings, update checker
│ ├── backup/ # Export/import YAML with encrypted secrets
│ ├── db/ # SQLite layer
│ └── http/ # HTTP server, handlers, templates (HTMX + custom CSS)
│ ├── console.go # WebSocket SSH console
│ ├── stats_ws.go # WebSocket real-time resource stats
│ └── templates/ # HTML templates
├── scripts/ # Install, worker setup, update, release scripts
└── Dockerfile # Multi-stage Docker build
MIT © 2025 CoderBuzz