You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Dockify is a self-hosted Docker app deployment platform — single Go binary, SQLite database, SSH-based worker management, embedded Web UI (Go html/template + HTMX), Caddy reverse proxy integration, and Cloudflare DNS automation.
Tech Stack
Layer
Choice
Details
Language
Go 1.23+
Single binary, cross-compile
Database
SQLite via modernc.org/sqlite
Pure Go, no CGo, embedded
Router
github.com/go-chi/chi/v5
Middleware, groups, path params
SSH
golang.org/x/crypto/ssh
Std SSH client, PTY sessions
Web UI
Go html/template + HTMX
Embedded via embed, no JS framework, no build step
CSS
Fully custom (no framework)
CSS variables, dark/light mode, single <style> block
Terminal
xterm.js + WebSocket
Interactive SSH console in browser
Docker
Multi-stage build
Published to ghcr.io/coderbuzz/dockify
Project Structure
cmd/dockify/main.go # Entry point, wires dependencies
internal/
config/config.go # Environment variable config (11 vars)
db/db.go + schema.sql # SQLite setup, 8 tables
ssh/
client.go # SSH client: connect, exec, write file, PTY
mock.go # Mock SSH for dev mode (DOCKIFY_DEV_MOCK=true)
server/
service.go # Server CRUD (list, get, create, update, delete)
handler.go # JSON API handlers
web_handler.go # Web UI handlers (pages + forms)
monitor.go # Background resource polling (every 60s)
app/
service.go # App CRUD + deploy/undeploy/redeploy/rollback/stop/start
handler.go # JSON API handlers (apps, deployments, secrets, files, logs)
web_handler.go # Web UI handlers (pages + forms)
scheduler.go # Auto-select least-loaded server
logs.go # SSH log streaming
backup.go # Compose file write/read on worker
stats.go # Stats collector: container stats, Caddy traffic, history
caddy/client.go # Caddy Admin API client (route CRUD via SSH tunnel)
cloudflare/client.go # Cloudflare DNS API v4 (list, create, upsert records)
webhook/handler.go # GitHub + GitLab webhook receiver, HMAC validation
settings/
handler.go # Settings page, webhook secret CRUD, update check/run
updater.go # GitHub Releases checker, systemd-run self-update
backup/
handler.go # Export/import pages, YAML generation/parsing
encryption.go # AES-GCM encrypt/decrypt with PBKDF2 passphrase
http/
router.go # Chi router, all routes, middleware
auth.go # Session auth, login/logout, middleware
console.go # WebSocket upgrade, PTY relay for SSH console
stats_ws.go # WebSocket real-time resource stats (1s interval)
renderer.go # Template rendering with layout
templates/ # HTML templates (all pages, layout, partials)
layout.html # Base layout: nav, head, all CSS (single <style> block)
dashboard.html # Dashboard with stats cards + server/app summary tables
server_list.html # Server list
server_add.html # Add server form
server_detail.html # Server detail: info, resources card, SSH console, actions
server_edit.html # Edit server form
servers_resources_card.html# HTMX partial: resource usage with human-readable values
app_list.html # App list
app_add.html # Deploy app form (simple/advanced toggle)
app_detail.html # App detail: info, compose, secrets editor, files, logs, deployments
app_edit.html # Edit app form (pre-fills from simple fields or compose)
settings.html # Settings: webhook secret, update check/run, export/import links
about.html # About page: version, description, sponsor link
export.html # Export page: passphrase generator, download YAML
import.html # Import page: file upload, mode selector (merge/replace)
login.html # Login page
scripts/
install.sh # One-liner install (3 modes: Docker Compose / Binary / Binary + Caddy)
setup-worker.sh # Generate SSH key on worker, install Docker, output private key
update.sh # Auto-detect install mode, download & restart latest
release.sh # Version bump + tag helper
Dockerfile # Multi-stage Docker build
docker-compose.yml # Dockify + Caddy reverse proxy (mode 1)
.air.toml # Air live-reload config
.github/workflows/build.yml # CI: vet, test, build binary + Docker, release on v* tag
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 + SSH keys storage
DOCKIFY_SSH_KEY_DIR
$DATA_DIR/keys
No
Per-server SSH private key files
DOMAIN
—
Mode 1
Domain for Caddy reverse proxy (auto HTTPS)
DOCKIFY_ADMIN_USER
admin
No
Web UI login username
DOCKIFY_ADMIN_PASSWORD
—
No
Web UI password. Not set = no authentication
DOCKIFY_DEV_MOCK
false
No
Enable mock SSH client for local development
DOCKIFY_BASE_PATH
—
No
URL prefix when behind reverse proxy (e.g. /proxy/9898)
CLOUDFLARE_API_TOKEN
—
No
Cloudflare API token for DNS automation (Zone:DNS:Edit scope)
CLOUDFLARE_ZONE_ID
—
No
Cloudflare zone ID for the domain
Database Schema (8 Tables)
servers
Column
Type
Description
id
INTEGER PK
Auto-increment
name
TEXT NOT NULL
Display name
host
TEXT NOT NULL
IP or hostname
port
INTEGER DEFAULT 22
SSH port
user
TEXT DEFAULT 'root'
SSH user
ssh_key
TEXT NOT NULL
SSH private key content
status
TEXT DEFAULT 'pending'
pending, online, offline, error, initializing
cpu_cores
INTEGER
Total CPU cores
ram_mb
INTEGER
Total RAM in MB
disk_gb
INTEGER
Total disk in GB
cpu_usage
REAL
CPU usage % (0.0 - 100.0)
ram_usage
REAL
RAM usage % (0.0 - 100.0)
disk_usage
REAL
Disk usage % (0.0 - 100.0)
resources_updated_at
DATETIME
Last resource refresh timestamp
registry_host
TEXT DEFAULT ''
Registry for docker login (empty → ghcr.io)
registry_user
TEXT DEFAULT ''
Registry username (empty = no credential)
registry_token
TEXT DEFAULT ''
Path to registry token file (0600, $DOCKIFY_SSH_KEY_DIR/<id>.registry-token); never serialized to the API
Parse and validate compose (simple mode: generate compose from image + env vars + volumes)
Select target server (manual or auto-scheduler — server_id=0 = auto-select)
Ensure dockify Docker network exists on worker
SSH → write docker-compose.yml to /opt/dockify/apps/app-{id}/
Write app secrets as .env file to /opt/dockify/apps/app-{id}/.env
Write config files to /opt/dockify/apps/app-{id}/{path}
If the server has a registry credential: SSH → docker login <host> -u <user> --password-stdin with the token on stdin; on failure record registry login failed: … (token redacted) and stop
SSH → docker compose pull, then docker compose up -d (auto-detects docker-compose vs docker compose)
Inject Caddy route via Admin API (POST /config/apps/http/servers/srv0/routes)
If HTTP basic auth set: include bcrypt basic_auth handler in route
Create Cloudflare DNS A record (if configured, skips duplicates, upserts on IP change)
Save compose snapshot in deployment record (for rollback)
Record deployment with status, log, commit SHA (if Git-triggered)
Update app status → running
Worker Init Flow
When a server is initialized (POST /api/servers/:id/init):
SSH connect + verify auth
Install Docker via get.docker.com (if not present)
Install Docker Compose plugin (if not present)
Create dockify Docker network
Deploy Caddy container (ports 80/443 + Admin API on localhost:2019)
Collect CPU cores (nproc), RAM total (/proc/meminfo), disk total (df -BG)
Collect CPU usage (/proc/stat), RAM usage (/proc/meminfo), disk usage (df -BG)
Status → online
Init is idempotent — re-running skips components that already exist (Caddy container, Docker, network).
Git Webhook Flow
Receive push event at POST /api/webhook/github or /api/webhook/gitlab
If webhook secret is enabled: validate HMAC-SHA256 (GitHub) or plain token (GitLab); reject 401 if mismatch
GET /api/servers/:id/stats/live — WebSocket endpoint that streams live CPU/RAM/disk metrics every 1 second. Uses the same /proc/stat and /proc/meminfo collection methods as the background collector. Client-side JS reconnects on disconnect.
UI Style Guide
All styles live in internal/http/templates/layout.html as a single <style> block. No external CSS framework — fully custom Vanilla CSS.
Toggle button in nav uses localStorage('dockify-theme'), defaults to OS preference
Icons: ☀ (light mode), ☾ (dark mode)
Component Patterns
Nav:<div class="top-nav"> — .logo (bold), .nav-links (flex). Sticky top bar with glassmorphism backdrop (backdrop-filter: blur(12px)). Includes a responsive mobile drawer navigation for viewports under 680px.
Badges:<span class="badge badge-{status}"> — Status pill badges with optional pulsing indicator dot (<span class="badge-dot"></span>) for live online/running/deploying states.
Logs & Terminal: Terminal and log container styled with dark glass topbar, macOS-style window controls, and crisp monospace log streaming.
CSS Conventions
CSS custom properties for all design tokens (no hardcoded color values)
Fully responsive across desktop, tablet, and mobile viewports
Security Considerations
Worker Caddy Admin API bound to 127.0.0.1:2019 — no external access
Controller ↔ Worker communication only via SSH (encrypted)
SSH private keys stored in DOCKIFY_DATA_DIR/keys/ with 0600 permissions
Registry tokens stored the same way (<id>.registry-token, 0600); DB holds only the path. Sent to docker login --password-stdin over SSH stdin (never in the command line), redacted from deploy logs and errors, never returned by the API
Cloudflare API token requires minimal scope: Zone:DNS:Edit
App containers on internal dockify Docker network only — no public port exposure except via Caddy