hotify Plugin
Traefik/Cloudflare app management CLI — deploy web apps behind Traefik with Cloudflare DNS and Let's Encrypt SSL certificates. Also supports Docker container management.
Current Version: v2.8.1
v2.8.1 Features (External Reverse Proxy Support)
- External reverse proxy support: Apps can now run on external machines while hotify handles DNS, TLS, and Traefik routing
- --backend-url parameter: Configure custom backend URLs for apps (e.g., http://100.114.4.57:8080)
- Web UI support: Backend URL field added to add/edit app forms
- Traefik integration: Automatic routing to custom backend URLs when configured
- Use cases: Apps running on different servers via Tailscale/VPN, containerized apps on separate hosts, microservices architectures
v2.7.4 Features (Permission Enforcement)
- Implemented permission enforcement at server level - all endpoints now require specific permissions
- Added permission checking to auth middleware with 403 Forbidden responses
- Wildcard support -
all or * grants full access for easier key management
- Comprehensive endpoint-to-permission mapping for all API routes
- Permission denials logged in audit system for security monitoring
- Admin permission automatically grants all permissions
- Fine-grained access control for multi-team deployments
v2.7.3 Features (Remote Execution for App Configuration)
- Remote execution for basic-auth, setup-traefik, setup-dns — all app configuration commands now support remote execution via HTTP API
- Added
--target and --local flags to basic-auth, setup-traefik, and setup-dns commands
- New remote API endpoints:
/api/remote/apps/{id}/basic-auth, /api/remote/apps/{id}/setup-traefik, /api/remote/apps/{id}/setup-dns
- No-humans mindset: Always prefer hotify HTTP API over SSH/scp when possible — developers can manage apps remotely without SSH access
- Use case: DevOps installs hotify-cli on remote server, developers use hotify-cli locally with configured targets
v2.7.1 Features (Docker Compose Status Detection)
- Improved status detection for Docker Compose apps — now checks actual compose stack status instead of cached config
- Added
checkComposeStatus() function to verify Docker Compose stack is running
- Local status checks now detect Docker Compose app status via
--local flag
- Config automatically updated when actual status differs from cached status
- Fixed
--daemon flag parsing in handleCLIAppStart() — daemon mode now works correctly
- Added
--port flag to start command for custom daemon port configuration
v2.7.0 Features (Full SSH Independence)
- Refactored
traefik-system to use HTTP API — all commands now use HTTP API (no SSH required)
- Added server-side API endpoints for Traefik installation/management (
/api/traefik-system/status, /api/traefik-system/install, /api/traefik-system/remove)
- Removed SSH execution from
traefik_system.go — commands now run on remote server via hotify daemon
- hotify-cli is now fully SSH-independent — all remote operations use HTTP API
v2.6.0 Features (Docker Compose Deployment Automation)
deploy-compose — Copy full project tree to remote compose_path via HTTP API (replaces manual scp)
compose-sync — Sync compose file (+ .env) only — faster than full deploy
compose-copy-dir — Copy a specific local directory into remote compose_path
volume-init — Populate a Docker named volume with local directory content
setup-compose — Register app config + deploy project files in one command
- All v2.6.0 commands use HTTP API (no SSH required)
v2.5.0 Features (Docker Compose Support)
compose command — passthrough to docker compose (all subcommands forwarded verbatim)
--id flag resolves compose_path and compose_file from app config automatically
--compose-file and --compose-path flags in setup/add/edit
compose_file and compose_path fields in app config and list output
- Hotify is responsible only for knowing which compose file to use — Docker config stays in the app repo
v2.4.0 Features (Docker Support)
- Docker container management (list/start/stop/restart/status/logs)
- Traefik Docker provider enable/disable
- Docker CLI integration via sudo docker commands
v2.3.0 Features (Traefik Configuration Improvements)
- Explicit domain specification in dynamic.yml (fixes ACME "domain not defined" errors)
- --challenge-type flag (http/dns selection for ACME)
- Smart restart (never uses reload, works even when reload unsupported)
- DNS record existence check (skip/update/create based on current state)
- Pre-flight config validation before touching Traefik files
- New CLI commands: setup-dns, setup-traefik
v2.1.0 Features (Process Management)
- Pause/resume for both local and remote apps
- Daemon PID tracking with two-strategy resolver (proc tree + port lookup)
- Local mode with --local flag for direct execution
Commands
App Management
hotify setup --id <id> --name <n> --domain <d> --port <p> --cmd <c> [--compose-file <f>] [--compose-path <p>] [--backend-url <url>] — Create or update app (upsert)
hotify add --id <id> --name <n> --domain <d> --port <p> --cmd <c> [--compose-file <f>] [--compose-path <p>] [--backend-url <url>] — Strict create (fails if exists)
hotify remove --id <id> — Delete app
hotify list — List all apps
Process Management
hotify start --id <id> [--local] — Start app (local or remote)
hotify stop --id <id> [--local] — Stop app (local or remote)
hotify restart --id <id> [--local] — Restart app (local or remote)
hotify status --id <id> [--local] — App status (local or remote)
hotify pause --id <id> [--local] — Pause app (SIGSTOP)
hotify resume --id <id> [--local] — Resume paused app (SIGCONT)
Daemon
hotify start --daemon — Start hotify daemon (web UI + API)
hotify stop — Stop daemon
hotify status — Daemon status
DNS & Traefik Configuration (v2.3.0+)
hotify setup-dns --id <id> [--ip <ip>] [--target <t>] [--local] — Create/update Cloudflare DNS A record
hotify setup-traefik --id <id> [--challenge-type http|dns] [--target <t>] [--local] — Configure Traefik routing
Basic Auth Management (v2.7.3+)
hotify basic-auth --id <id> --action <add|remove|list> [--user <u>] [--password <p>] [--hash <h>] [--target <t>] [--local] — Manage Traefik HTTP basic auth
Docker Compose (v2.5.0+)
hotify compose [--id <app>] <subcommand> [args...] — passthrough to docker compose
- When
--id is set, resolves compose_path and compose_file from app config
- All subcommands and flags are forwarded verbatim to
docker compose
Docker Compose Deployment Automation (v2.6.0+)
hotify deploy-compose --id <id> --source <dir> [--compose-file <f>] [--remote-path <p>] [--start] — Copy full project tree to remote
hotify compose-sync --id <id> [--source <dir>] [--restart] [--env=false] — Sync compose file (+ .env) only
hotify compose-copy-dir --id <id> --dir <subdir> --source <local-dir> — Copy a directory into remote compose_path
hotify volume-init --id <id> --volume <vol-name> --source <dir> — Populate Docker named volume with local directory
hotify setup-compose --id <id> --name <n> --domain <d> --port <p> --cmd <c> --source <dir> [--compose-file <f>] [--remote-path <p>] [--setup-dns] [--start] — Register app + deploy in one command
Examples:
# App-aware (resolves path and compose file automatically)
hotify-cli compose --id cmdcenter up -d
hotify-cli compose --id cmdcenter down
hotify-cli compose --id cmdcenter ps
hotify-cli compose --id cmdcenter logs -f
hotify-cli compose --id cmdcenter restart
hotify-cli compose --id cmdcenter pull
# Raw passthrough (runs docker compose in current directory)
hotify-cli compose -f compose.binary.yml up -d
hotify-cli compose ps
Docker Management (v2.4.0+)
hotify docker list — List all containers
hotify docker start <id> — Start container
hotify docker stop <id> — Stop container
hotify docker restart <id> — Restart container
hotify docker status <id> — Container status
hotify docker logs <id> — Container logs
hotify docker enable-traefik — Enable Traefik Docker provider
hotify docker disable-traefik — Disable Traefik Docker provider
Deployment
hotify deploy --id <id> --source <path> [--target <t>] [--setup-dns] — Deploy binary/folder
hotify prune --id <id> — Remove DNS/Traefik for app
hotify prune --all — Rebuild Traefik for all apps
Authentication
hotify auth --url <u> --token <t> --name <n> — Authenticate with remote daemon
hotify targets --action list — List targets
hotify targets --action use --name <n> — Set active target
API Key Management (Local Only)
hotify api-keys --action add --name <n> [--permissions <p>] — Create API key with permissions
hotify api-keys --action list — List all API keys
hotify api-keys --action remove --name <n> — Remove API key
hotify api-keys --action permissions --name <n> --add <p> --remove <p> — Update permissions
hotify api-keys --action usage --name <n> — Show API key usage statistics
Available Permissions: deploy, start, stop, restart, logs, config, admin, all, *
Note: Permissions are fully enforced at server level as of v2.7.4. Use all or * for full access.
Infrastructure
hotify traefik-system — Manage Traefik installation on targets
Setup
# Interactive setup (Cloudflare token, domain, email)
hotify-cli init
# Or non-interactive
hotify-cli init --token <cf-token> --domain example.com --email admin@example.com
This creates ~/.hotify/config.json with Cloudflare API credentials.
Typical Workflow
# 1. Register an app
hotify-cli setup --id myapp --name "My App" --domain myapp --port 3000 --cmd "/usr/local/bin/myapp start"
# 2. Setup DNS (checks for existing record)
hotify-cli setup-dns --id myapp --ip 92.113.145.178
# 3. Setup Traefik (HTTP challenge by default)
hotify-cli setup-traefik --id myapp --challenge-type http
# 4. Deploy binary to remote
hotify-cli deploy --id myapp --source ./myapp-binary --target dk1
# 5. Start app on remote
hotify-cli start --id myapp --target dk1
# 6. Check status
hotify-cli status --id myapp --target dk1
External Reverse Proxy Workflow (v2.8.1+)
The v2.8.1 release adds support for external reverse proxy targets, allowing apps to run on different machines while hotify handles DNS, TLS, and Traefik routing.
Use Cases
- Apps running on different servers via Tailscale/VPN
- Containerized apps on separate hosts
- Microservices architectures across multiple machines
Usage Example
# Setup app with external backend URL (e.g., Tailscale network)
hotify-cli setup \
--id gitea-rbm2 \
--name "Gitea on rbm2" \
--domain gitea \
--port 3000 \
--cmd "/usr/local/bin/gitea start" \
--backend-url "http://100.114.4.57:3000"
# Setup DNS and Traefik (still handled by hotify)
hotify-cli setup-dns --id gitea-rbm2
hotify-cli setup-traefik --id gitea-rbm2
When --backend-url is set:
- Traefik routes to the specified URL instead of
http://127.0.0.1:<port>
- DNS and TLS certificate management still handled by hotify
- Basic auth and other Traefik middleware still apply
- The app can run on any reachable machine (local network, Tailscale, VPN)
Docker Compose Workflow (v2.5.0+)
# 1. Register app with compose config (Docker config stays in the app repo)
hotify-cli setup \
--id cmdcenter \
--name "Command Center" \
--domain cmdcenter \
--port 3031 \
--cmd "docker compose up -d" \
--compose-file compose.binary.yml \
--compose-path /home/dk1/cmdcenter
# 2. Start compose stack (resolves path + file automatically)
hotify-cli compose --id cmdcenter up -d
# 3. Check status
hotify-cli compose --id cmdcenter ps
# 4. View logs
hotify-cli compose --id cmdcenter logs -f
# 5. Restart
hotify-cli compose --id cmdcenter restart
# 6. Stop
hotify-cli compose --id cmdcenter down
Docker Compose Deployment Workflow (v2.6.0+)
The v2.6.0 commands automate the manual scp workflow for Docker Compose deployments. All use the HTTP API (no SSH required).
# Full deploy: copy entire project tree (compose file, .env, webui/, templates/, etc.)
hotify-cli deploy-compose \
--id cir-doc-gen \
--source /local/path/to/project
# Deploy and start immediately
hotify-cli deploy-compose --id cir-doc-gen --source ./project --start
# Sync only compose file (+ .env) after editing docker-compose.yml
hotify-cli compose-sync --id cir-doc-gen --restart
# Copy a specific directory (e.g., webui/)
hotify-cli compose-copy-dir \
--id cir-doc-gen \
--dir webui \
--source /local/path/webui
# Populate a Docker named volume with local content
hotify-cli volume-init \
--id cir-doc-gen \
--volume cir-webui \
--source /local/webui
# One-shot: register app + deploy + DNS + start
hotify-cli setup-compose \
--id cir-doc-gen \
--name "CIR Doc Gen" \
--domain cir-doc-gen \
--port 8080 \
--cmd "docker compose up -d" \
--source /local/project \
--compose-file docker-compose.yml \
--remote-path /home/dk1/cir-doc-gen \
--setup-dns \
--start
What this replaces:
deploy-compose replaces: scp docker-compose.yml, scp .env, scp -r webui/, scp -r templates/
compose-sync replaces: scp docker-compose.yml host:/path/
compose-copy-dir replaces: scp -r webui/ host:/path/webui/
volume-init replaces: sudo cp -r webui/* /var/lib/docker/volumes/.../ (requires write access on remote)
Docker Workflow (v2.4.0+)
# List all containers
hotify-cli docker list
# Check container status
hotify-cli docker status --id mycontainer
# Start/stop container
hotify-cli docker start --id mycontainer
hotify-cli docker stop --id mycontainer
# Enable Traefik Docker provider (requires Traefik v3.6+)
hotify-cli docker enable-traefik
Architecture
- Local CLI: All CRUD, authentication, deployment, and Docker commands
- Daemon Mode (
hotify-cli start -daemon): HTTP server on port 8080 with embedded web UI + REST API
- Remote Targets: Manage multiple servers via API with encrypted tokens
- Docker Integration: Container management via Docker CLI, Traefik Docker provider support
- Transport: All commands use HTTP API (no SSH required) — hotify-cli is fully SSH-independent as of v2.7.0
No-Humans Mindset: Prefer Hotify Over SSH/SCP
Core Principle: If an operation can be done via hotify's HTTP API, always prefer it over SSH/scp. This enables true remote management without requiring SSH access to servers.
When to Use Hotify HTTP API (Preferred)
- App configuration:
setup, add, edit, remove, list
- Process management:
start, stop, restart, status, pause, resume
- DNS & Traefik:
setup-dns, setup-traefik, basic-auth (v2.7.3+)
- Deployment:
deploy, deploy-compose, compose-sync, compose-copy-dir
- Docker operations:
compose, docker commands
- Infrastructure:
traefik-system (v2.7.0+)
When SSH Might Still Be Needed
- Initial hotify-cli installation on remote server
- System-level troubleshooting outside hotify's scope
- Manual file operations not supported by hotify API
Remote Execution Pattern (v2.7.3+)
# Remote mode (default - uses configured target)
hotify-cli basic-auth --id myapp --action list
hotify-cli setup-traefik --id myapp
hotify-cli setup-dns --id myapp
# Explicit target specification
hotify-cli basic-auth --id myapp --action list --target dk1
hotify-cli setup-traefik --id myapp --target dk1
# Local mode (execute directly on local server)
hotify-cli basic-auth --id myapp --action list --local
hotify-cli setup-traefik --id myapp --local
Benefits of HTTP API Over SSH
- No SSH keys required: Developers don't need SSH access to infrastructure
- Audit logging: All operations logged via hotify's audit system
- Consistent interface: Same commands work locally and remotely
- No tunneling required: Works through firewalls/NAT without SSH tunnels
- Team collaboration: Multiple developers can work via shared API tokens
Important Note: Permission Enforcement (v2.7.4+)
✅ Permission Enforcement Implemented: As of v2.7.4, hotify-cli enforces permissions at the server level. The auth middleware validates tokens AND checks specific permissions for each endpoint.
Current State:
- Permissions are enforced for all authenticated endpoints
- Permission types:
deploy, start, stop, restart, logs, config, admin
- Wildcard support:
all or * grants full access
- Admin permission automatically grants all permissions
- 403 Forbidden responses for insufficient permissions
Permission Mapping:
/api/status → requires logs
/api/config → requires config
/api/apps/*/start → requires start
/api/apps/*/stop → requires stop
/api/deploy → requires deploy
/api/api-keys/* → requires admin
- And more... (see permissions.go for full mapping)
Wildcard Usage:
# Create full access key using wildcard
hotify-cli api-keys --action add --name fullaccess --permissions all
# Alternative wildcard syntax
hotify-cli api-keys --action add --name fullaccess --permissions "*"
Recommendation for Agents:
- Use appropriate permission scoping for security
- Create keys with minimum required permissions
- Use wildcards (
all/*) only for trusted administrative access
- Monitor audit logs for permission denials
Implementation Pattern
When working with hotify, follow this decision tree:
- Is there a hotify command for this operation? → Use hotify CLI
- Does it support remote execution? → Use
--target flag (default)
- Only use SSH if: hotify cannot perform the operation at all
Key Learnings & Caveats
Traefik Configuration
ACME "Domain Not Defined" Error (v2.3.0 fix)
ACME Challenge Type Conflicts
- Issue: Having both DNS and HTTP challenges in traefik.yml causes conflicts
- Fix: Use only one challenge type (HTTP is simpler, DNS for wildcards)
- Default: HTTP challenge (v2.3.0+)
Service Reload Not Supported
- Issue:
systemctl reload traefik fails on some systems
- Fix: Always use
systemctl restart traefik (v2.3.0+)
- Implementation: Detect running state, use start vs restart accordingly
DNS Record Existence Check
- Issue: Attempting to create duplicate DNS records fails
- Fix: Check existing record before creation — skip if IP matches, update if differs (v2.3.0+)
- Benefit: Idempotent DNS setup
Docker Compatibility
Docker API Version Mismatch
- Issue: Traefik v3.1.4 uses Docker API v1.24, but Docker 29.x requires v1.44+
- Symptom: "client version 1.24 is too old. Minimum supported API version is 1.44"
- Fix: Upgrade Traefik to v3.6+ (v3.7.0 recommended)
- Requirement: Traefik v3.6+ for Docker 29.x compatibility
Traefik Docker Provider
PID Tracking (v2.1.0+)
Daemon PID Tracking Issue
- Issue: When starting app via
sh -c <command>, tracked shell PID exits immediately for daemon apps
- Fix: Two-strategy resolver:
/proc tree walk — finds leaf child of shell (single-fork processes)
- Port-based lookup via
ss — finds PID by app's configured port (double-fork/setsid daemons)
- Implementation:
resolveActualPID(shellPID int, port int) in local_ops.go
Local vs Remote Operations
- Local mode:
--local flag executes commands directly on server (no API)
- Remote mode: Uses hotify daemon API on target server
- PID tracking: Both local and remote use same two-strategy resolver
File Size Limits
- 500 LOC Limit
- hotify-cli enforces 500 lines of code per source file
- Files exceeding limit must be split (e.g., process.go → local_ops.go + remote_ops.go)
- Rationale: Maintainability and readability
Smoke Testing
- Smoke Test Approach
- Comprehensive test document for each version
- Test server: dk1@92.113.145.178
- Categories: CLI structure, feature-specific, regression, E2E
- Document issues found and fixed during testing
- All tests must pass before release
Security & Permissions
Traefik Service File Permissions
- Issue:
/etc/systemd/system/traefik.service owned by root, regular user can't write
- Fix: Skip service file write if already exists (v2.3.0+)
- Rationale: Config files in
/etc/traefik/ owned by deploy user, only service file needs root
Cloudflare Token Format
- Issue: Legacy API format (X-Auth-Key + X-Auth-Email) vs Bearer token
- Fix: hotify-cli uses legacy format for broader compatibility
- Note: Bearer tokens may work but not explicitly tested
Common Pitfalls
Base Domain Extraction Bug
- Issue:
getZoneID was extracting only TLD (fr instead of intrane.fr)
- Fix: Split on all dots, take last 2 parts for registrable domain
- Impact: DNS setup would fail with "zone not found" error
Configuration Validation
- Best practice: Always validate config before touching Traefik files
- Check: admin_email, domain, app ID, app domain, app port
- Benefit: Prevents partial/broken state
Watch vs Restart
- Issue: Traefik's
watch: true on file provider doesn't always pick up changes
- Fix: Always restart Traefik after configuration changes
- Rationale: Reliable configuration application
Troubleshooting
Traefik Errors
"domain not defined" in ACME logs
- Cause: Missing explicit
domains: block in router TLS configuration
- Fix: Use v2.3.0+ setup-traefik (adds domain spec automatically)
"reload is not supported for this unit"
- Cause: systemd service doesn't support reload
- Fix: v2.3.0+ uses restart automatically
Docker provider errors
- Check Traefik version (needs v3.6+ for Docker 29.x)
- Check Docker API version (
docker version | grep "API version")
- Verify Docker socket accessible:
ls -la /var/run/docker.sock
DNS Errors
"zone not found"
- Check Cloudflare token permissions
- Verify domain is managed in Cloudflare
- Check base domain extraction (should be 2-part, not just TLD)
"record already exists"
- v2.3.0+ handles this automatically (skip/update/create)
- If using older version, manually delete via Cloudflare dashboard
Process Errors
PID becomes invalid after start
- Daemon app double-forked, shell PID exited
- v2.1.0+ uses two-strategy resolver to find actual daemon PID
- Check:
hotify-cli status --id <app> --local
Version-Specific Notes
v2.7.4
- Implemented server-side permission enforcement for all API endpoints
- Added wildcard support (
all/*) for full access keys
- Created comprehensive endpoint-to-permission mapping in permissions.go
- Updated auth middleware to check permissions before allowing access
- Added 403 Forbidden responses with audit logging for permission denials
- Simplified permission management by removing redundant PermissionManager struct
- Updated API key creation to expand wildcards to individual permissions
v2.7.3
- Added remote execution support for
basic-auth, setup-traefik, and setup-dns commands
- Added
--target and --local flags to app configuration commands
- New remote API endpoints:
/api/remote/apps/{id}/basic-auth, /api/remote/apps/{id}/setup-traefik, /api/remote/apps/{id}/setup-dns
- Fixed route conflicts by using
/api/remote/apps/ path pattern instead of /api/apps/
- Added
PostWithData method to HTTPClient for POST requests that return response data
- Updated AGENTS.md with remote execution documentation and "no-humans mindset"
v2.7.0
- Refactored
traefik-system to use HTTP API instead of SSH
- Added server-side API endpoints for Traefik installation/management
- hotify-cli is now fully SSH-independent (all commands use HTTP API)
- Removed SSH execution code from traefik_system.go
v2.6.0
- Added Docker Compose Deployment Automation (5 new commands)
- All new commands use HTTP API (no SSH required)
- Only
traefik-system still uses SSH (legacy, to be refactored)
- Added server-side API endpoint
/api/compose/volume-init for volume initialization
- Added
HTTPClient.PostLarge() with 5-minute timeout for large uploads
v2.4.0
- Added Docker container management
- Added Traefik Docker provider enable/disable
- Requires Traefik v3.6+ for Docker 29.x compatibility
- Docker commands use
sudo docker internally
v2.3.0
- Fixed ACME domain specification
- Added --challenge-type flag
- Fixed service reload vs restart
- Added DNS existence check
- Added config validation
- New CLI: setup-dns, setup-traefik
v2.1.0
- Added pause/resume for apps
- Fixed daemon PID tracking (both local and remote)
- Added --local flag for direct execution
- Split process.go into local_ops.go + remote_ops.go
Dependencies
- Go: Pure stdlib, no external dependencies
- Docker: Required for Docker commands (v2.4.0+)
- Traefik: Required for reverse proxy (v2.3.0+ requires v3.6+ for Docker 29.x)
- Cloudflare: DNS provider (requires API token)
- systemd: Service management (Linux)
1---2name: hotify3description: Use this skill when the user wants to manage web apps behind Traefik with Cloudflare DNS and SSL automation, deploy apps to remote servers, manage Docker containers, or troubleshoot Traefik/DNS issues.4---56# hotify Plugin78Traefik/Cloudflare app management CLI — deploy web apps behind Traefik with Cloudflare DNS and Let's Encrypt SSL certificates. Also supports Docker container management.910## Current Version: v2.8.11112### v2.8.1 Features (External Reverse Proxy Support)13- **External reverse proxy support**: Apps can now run on external machines while hotify handles DNS, TLS, and Traefik routing14- **--backend-url parameter**: Configure custom backend URLs for apps (e.g., http://100.114.4.57:8080)15- **Web UI support**: Backend URL field added to add/edit app forms16- **Traefik integration**: Automatic routing to custom backend URLs when configured17- Use cases: Apps running on different servers via Tailscale/VPN, containerized apps on separate hosts, microservices architectures1819### v2.7.4 Features (Permission Enforcement)20- **Implemented permission enforcement** at server level - all endpoints now require specific permissions21- Added permission checking to auth middleware with 403 Forbidden responses22- **Wildcard support** - `all` or `*` grants full access for easier key management23- Comprehensive endpoint-to-permission mapping for all API routes24- Permission denials logged in audit system for security monitoring25- Admin permission automatically grants all permissions26- Fine-grained access control for multi-team deployments2728### v2.7.3 Features (Remote Execution for App Configuration)29- **Remote execution for basic-auth, setup-traefik, setup-dns** — all app configuration commands now support remote execution via HTTP API30- Added `--target` and `--local` flags to `basic-auth`, `setup-traefik`, and `setup-dns` commands31- New remote API endpoints: `/api/remote/apps/{id}/basic-auth`, `/api/remote/apps/{id}/setup-traefik`, `/api/remote/apps/{id}/setup-dns`32- **No-humans mindset**: Always prefer hotify HTTP API over SSH/scp when possible — developers can manage apps remotely without SSH access33- Use case: DevOps installs hotify-cli on remote server, developers use hotify-cli locally with configured targets3435### v2.7.1 Features (Docker Compose Status Detection)36- **Improved status detection for Docker Compose apps** — now checks actual compose stack status instead of cached config37- Added `checkComposeStatus()` function to verify Docker Compose stack is running38- Local status checks now detect Docker Compose app status via `--local` flag39- Config automatically updated when actual status differs from cached status40- Fixed `--daemon` flag parsing in `handleCLIAppStart()` — daemon mode now works correctly41- Added `--port` flag to `start` command for custom daemon port configuration4243### v2.7.0 Features (Full SSH Independence)44- **Refactored `traefik-system` to use HTTP API** — all commands now use HTTP API (no SSH required)45- Added server-side API endpoints for Traefik installation/management (`/api/traefik-system/status`, `/api/traefik-system/install`, `/api/traefik-system/remove`)46- Removed SSH execution from `traefik_system.go` — commands now run on remote server via hotify daemon47- **hotify-cli is now fully SSH-independent** — all remote operations use HTTP API4849### v2.6.0 Features (Docker Compose Deployment Automation)50- `deploy-compose` — Copy full project tree to remote compose_path via HTTP API (replaces manual `scp`)51- `compose-sync` — Sync compose file (+ .env) only — faster than full deploy52- `compose-copy-dir` — Copy a specific local directory into remote compose_path53- `volume-init` — Populate a Docker named volume with local directory content54- `setup-compose` — Register app config + deploy project files in one command55- All v2.6.0 commands use HTTP API (no SSH required)5657### v2.5.0 Features (Docker Compose Support)58- `compose` command — passthrough to `docker compose` (all subcommands forwarded verbatim)59- `--id` flag resolves `compose_path` and `compose_file` from app config automatically60- `--compose-file` and `--compose-path` flags in `setup`/`add`/`edit`61- `compose_file` and `compose_path` fields in app config and `list` output62- Hotify is responsible only for knowing which compose file to use — Docker config stays in the app repo6364### v2.4.0 Features (Docker Support)65- Docker container management (list/start/stop/restart/status/logs)66- Traefik Docker provider enable/disable67- Docker CLI integration via sudo docker commands6869### v2.3.0 Features (Traefik Configuration Improvements)70- Explicit domain specification in dynamic.yml (fixes ACME "domain not defined" errors)71- --challenge-type flag (http/dns selection for ACME)72- Smart restart (never uses reload, works even when reload unsupported)73- DNS record existence check (skip/update/create based on current state)74- Pre-flight config validation before touching Traefik files75- New CLI commands: setup-dns, setup-traefik7677### v2.1.0 Features (Process Management)78- Pause/resume for both local and remote apps79- Daemon PID tracking with two-strategy resolver (proc tree + port lookup)80- Local mode with --local flag for direct execution8182## Commands8384### App Management85- `hotify setup --id <id> --name <n> --domain <d> --port <p> --cmd <c> [--compose-file <f>] [--compose-path <p>] [--backend-url <url>]` — Create or update app (upsert)86- `hotify add --id <id> --name <n> --domain <d> --port <p> --cmd <c> [--compose-file <f>] [--compose-path <p>] [--backend-url <url>]` — Strict create (fails if exists)87- `hotify remove --id <id>` — Delete app88- `hotify list` — List all apps8990### Process Management91- `hotify start --id <id> [--local]` — Start app (local or remote)92- `hotify stop --id <id> [--local]` — Stop app (local or remote)93- `hotify restart --id <id> [--local]` — Restart app (local or remote)94- `hotify status --id <id> [--local]` — App status (local or remote)95- `hotify pause --id <id> [--local]` — Pause app (SIGSTOP)96- `hotify resume --id <id> [--local]` — Resume paused app (SIGCONT)9798### Daemon99- `hotify start --daemon` — Start hotify daemon (web UI + API)100- `hotify stop` — Stop daemon101- `hotify status` — Daemon status102103### DNS & Traefik Configuration (v2.3.0+)104- `hotify setup-dns --id <id> [--ip <ip>] [--target <t>] [--local]` — Create/update Cloudflare DNS A record105- `hotify setup-traefik --id <id> [--challenge-type http|dns] [--target <t>] [--local]` — Configure Traefik routing106107### Basic Auth Management (v2.7.3+)108- `hotify basic-auth --id <id> --action <add|remove|list> [--user <u>] [--password <p>] [--hash <h>] [--target <t>] [--local]` — Manage Traefik HTTP basic auth109110### Docker Compose (v2.5.0+)111- `hotify compose [--id <app>] <subcommand> [args...]` — passthrough to `docker compose`112- When `--id` is set, resolves `compose_path` and `compose_file` from app config113- All subcommands and flags are forwarded verbatim to `docker compose`114115### Docker Compose Deployment Automation (v2.6.0+)116- `hotify deploy-compose --id <id> --source <dir> [--compose-file <f>] [--remote-path <p>] [--start]` — Copy full project tree to remote117- `hotify compose-sync --id <id> [--source <dir>] [--restart] [--env=false]` — Sync compose file (+ .env) only118- `hotify compose-copy-dir --id <id> --dir <subdir> --source <local-dir>` — Copy a directory into remote compose_path119- `hotify volume-init --id <id> --volume <vol-name> --source <dir>` — Populate Docker named volume with local directory120- `hotify setup-compose --id <id> --name <n> --domain <d> --port <p> --cmd <c> --source <dir> [--compose-file <f>] [--remote-path <p>] [--setup-dns] [--start]` — Register app + deploy in one command121122Examples:123```bash124# App-aware (resolves path and compose file automatically)125hotify-cli compose --id cmdcenter up -d126hotify-cli compose --id cmdcenter down127hotify-cli compose --id cmdcenter ps128hotify-cli compose --id cmdcenter logs -f129hotify-cli compose --id cmdcenter restart130hotify-cli compose --id cmdcenter pull131132# Raw passthrough (runs docker compose in current directory)133hotify-cli compose -f compose.binary.yml up -d134hotify-cli compose ps135```136137### Docker Management (v2.4.0+)138- `hotify docker list` — List all containers139- `hotify docker start <id>` — Start container140- `hotify docker stop <id>` — Stop container141- `hotify docker restart <id>` — Restart container142- `hotify docker status <id>` — Container status143- `hotify docker logs <id>` — Container logs144- `hotify docker enable-traefik` — Enable Traefik Docker provider145- `hotify docker disable-traefik` — Disable Traefik Docker provider146147### Deployment148- `hotify deploy --id <id> --source <path> [--target <t>] [--setup-dns]` — Deploy binary/folder149- `hotify prune --id <id>` — Remove DNS/Traefik for app150- `hotify prune --all` — Rebuild Traefik for all apps151152### Authentication153- `hotify auth --url <u> --token <t> --name <n>` — Authenticate with remote daemon154- `hotify targets --action list` — List targets155- `hotify targets --action use --name <n>` — Set active target156157### API Key Management (Local Only)158- `hotify api-keys --action add --name <n> [--permissions <p>]` — Create API key with permissions159- `hotify api-keys --action list` — List all API keys160- `hotify api-keys --action remove --name <n>` — Remove API key161- `hotify api-keys --action permissions --name <n> --add <p> --remove <p>` — Update permissions162- `hotify api-keys --action usage --name <n>` — Show API key usage statistics163164**Available Permissions**: `deploy`, `start`, `stop`, `restart`, `logs`, `config`, `admin`, `all`, `*`165**Note**: Permissions are fully enforced at server level as of v2.7.4. Use `all` or `*` for full access.166167### Infrastructure168- `hotify traefik-system` — Manage Traefik installation on targets169170## Setup171172```bash173# Interactive setup (Cloudflare token, domain, email)174hotify-cli init175176# Or non-interactive177hotify-cli init --token <cf-token> --domain example.com --email admin@example.com178```179180This creates `~/.hotify/config.json` with Cloudflare API credentials.181182## Typical Workflow183184```bash185# 1. Register an app186hotify-cli setup --id myapp --name "My App" --domain myapp --port 3000 --cmd "/usr/local/bin/myapp start"187188# 2. Setup DNS (checks for existing record)189hotify-cli setup-dns --id myapp --ip 92.113.145.178190191# 3. Setup Traefik (HTTP challenge by default)192hotify-cli setup-traefik --id myapp --challenge-type http193194# 4. Deploy binary to remote195hotify-cli deploy --id myapp --source ./myapp-binary --target dk1196197# 5. Start app on remote198hotify-cli start --id myapp --target dk1199200# 6. Check status201hotify-cli status --id myapp --target dk1202```203204## External Reverse Proxy Workflow (v2.8.1+)205206The v2.8.1 release adds support for external reverse proxy targets, allowing apps to run on different machines while hotify handles DNS, TLS, and Traefik routing.207208### Use Cases209- Apps running on different servers via Tailscale/VPN210- Containerized apps on separate hosts211- Microservices architectures across multiple machines212213### Usage Example214```bash215# Setup app with external backend URL (e.g., Tailscale network)216hotify-cli setup \217 --id gitea-rbm2 \218 --name "Gitea on rbm2" \219 --domain gitea \220 --port 3000 \221 --cmd "/usr/local/bin/gitea start" \222 --backend-url "http://100.114.4.57:3000"223224# Setup DNS and Traefik (still handled by hotify)225hotify-cli setup-dns --id gitea-rbm2226hotify-cli setup-traefik --id gitea-rbm2227```228229When `--backend-url` is set:230- Traefik routes to the specified URL instead of `http://127.0.0.1:<port>`231- DNS and TLS certificate management still handled by hotify232- Basic auth and other Traefik middleware still apply233- The app can run on any reachable machine (local network, Tailscale, VPN)234235## Docker Compose Workflow (v2.5.0+)236237```bash238# 1. Register app with compose config (Docker config stays in the app repo)239hotify-cli setup \240 --id cmdcenter \241 --name "Command Center" \242 --domain cmdcenter \243 --port 3031 \244 --cmd "docker compose up -d" \245 --compose-file compose.binary.yml \246 --compose-path /home/dk1/cmdcenter247248# 2. Start compose stack (resolves path + file automatically)249hotify-cli compose --id cmdcenter up -d250251# 3. Check status252hotify-cli compose --id cmdcenter ps253254# 4. View logs255hotify-cli compose --id cmdcenter logs -f256257# 5. Restart258hotify-cli compose --id cmdcenter restart259260# 6. Stop261hotify-cli compose --id cmdcenter down262```263264## Docker Compose Deployment Workflow (v2.6.0+)265266The v2.6.0 commands automate the manual `scp` workflow for Docker Compose deployments. All use the HTTP API (no SSH required).267268```bash269# Full deploy: copy entire project tree (compose file, .env, webui/, templates/, etc.)270hotify-cli deploy-compose \271 --id cir-doc-gen \272 --source /local/path/to/project273274# Deploy and start immediately275hotify-cli deploy-compose --id cir-doc-gen --source ./project --start276277# Sync only compose file (+ .env) after editing docker-compose.yml278hotify-cli compose-sync --id cir-doc-gen --restart279280# Copy a specific directory (e.g., webui/)281hotify-cli compose-copy-dir \282 --id cir-doc-gen \283 --dir webui \284 --source /local/path/webui285286# Populate a Docker named volume with local content287hotify-cli volume-init \288 --id cir-doc-gen \289 --volume cir-webui \290 --source /local/webui291292# One-shot: register app + deploy + DNS + start293hotify-cli setup-compose \294 --id cir-doc-gen \295 --name "CIR Doc Gen" \296 --domain cir-doc-gen \297 --port 8080 \298 --cmd "docker compose up -d" \299 --source /local/project \300 --compose-file docker-compose.yml \301 --remote-path /home/dk1/cir-doc-gen \302 --setup-dns \303 --start304```305306**What this replaces:**307- `deploy-compose` replaces: `scp docker-compose.yml`, `scp .env`, `scp -r webui/`, `scp -r templates/`308- `compose-sync` replaces: `scp docker-compose.yml host:/path/`309- `compose-copy-dir` replaces: `scp -r webui/ host:/path/webui/`310- `volume-init` replaces: `sudo cp -r webui/* /var/lib/docker/volumes/.../` (requires write access on remote)311312## Docker Workflow (v2.4.0+)313314```bash315# List all containers316hotify-cli docker list317318# Check container status319hotify-cli docker status --id mycontainer320321# Start/stop container322hotify-cli docker start --id mycontainer323hotify-cli docker stop --id mycontainer324325# Enable Traefik Docker provider (requires Traefik v3.6+)326hotify-cli docker enable-traefik327```328329## Architecture330331- **Local CLI**: All CRUD, authentication, deployment, and Docker commands332- **Daemon Mode** (`hotify-cli start -daemon`): HTTP server on port 8080 with embedded web UI + REST API333- **Remote Targets**: Manage multiple servers via API with encrypted tokens334- **Docker Integration**: Container management via Docker CLI, Traefik Docker provider support335- **Transport**: All commands use HTTP API (no SSH required) — hotify-cli is fully SSH-independent as of v2.7.0336337## No-Humans Mindset: Prefer Hotify Over SSH/SCP338339**Core Principle**: If an operation can be done via hotify's HTTP API, always prefer it over SSH/scp. This enables true remote management without requiring SSH access to servers.340341### When to Use Hotify HTTP API (Preferred)342- **App configuration**: `setup`, `add`, `edit`, `remove`, `list`343- **Process management**: `start`, `stop`, `restart`, `status`, `pause`, `resume`344- **DNS & Traefik**: `setup-dns`, `setup-traefik`, `basic-auth` (v2.7.3+)345- **Deployment**: `deploy`, `deploy-compose`, `compose-sync`, `compose-copy-dir`346- **Docker operations**: `compose`, `docker` commands347- **Infrastructure**: `traefik-system` (v2.7.0+)348349### When SSH Might Still Be Needed350- Initial hotify-cli installation on remote server351- System-level troubleshooting outside hotify's scope352- Manual file operations not supported by hotify API353354### Remote Execution Pattern (v2.7.3+)355```bash356# Remote mode (default - uses configured target)357hotify-cli basic-auth --id myapp --action list358hotify-cli setup-traefik --id myapp359hotify-cli setup-dns --id myapp360361# Explicit target specification362hotify-cli basic-auth --id myapp --action list --target dk1363hotify-cli setup-traefik --id myapp --target dk1364365# Local mode (execute directly on local server)366hotify-cli basic-auth --id myapp --action list --local367hotify-cli setup-traefik --id myapp --local368```369370### Benefits of HTTP API Over SSH371- **No SSH keys required**: Developers don't need SSH access to infrastructure372- **Audit logging**: All operations logged via hotify's audit system373- **Consistent interface**: Same commands work locally and remotely374- **No tunneling required**: Works through firewalls/NAT without SSH tunnels375- **Team collaboration**: Multiple developers can work via shared API tokens376377### Important Note: Permission Enforcement (v2.7.4+)378**✅ Permission Enforcement Implemented**: As of v2.7.4, hotify-cli enforces permissions at the server level. The auth middleware validates tokens AND checks specific permissions for each endpoint.379380**Current State**:381- Permissions are enforced for all authenticated endpoints382- Permission types: `deploy`, `start`, `stop`, `restart`, `logs`, `config`, `admin`383- Wildcard support: `all` or `*` grants full access384- Admin permission automatically grants all permissions385- 403 Forbidden responses for insufficient permissions386387**Permission Mapping**:388- `/api/status` → requires `logs`389- `/api/config` → requires `config`390- `/api/apps/*/start` → requires `start`391- `/api/apps/*/stop` → requires `stop`392- `/api/deploy` → requires `deploy`393- `/api/api-keys/*` → requires `admin`394- And more... (see permissions.go for full mapping)395396**Wildcard Usage**:397```bash398# Create full access key using wildcard399hotify-cli api-keys --action add --name fullaccess --permissions all400401# Alternative wildcard syntax402hotify-cli api-keys --action add --name fullaccess --permissions "*"403```404405**Recommendation for Agents**:406- Use appropriate permission scoping for security407- Create keys with minimum required permissions408- Use wildcards (`all`/`*`) only for trusted administrative access409- Monitor audit logs for permission denials410411### Implementation Pattern412When working with hotify, follow this decision tree:4131. **Is there a hotify command for this operation?** → Use hotify CLI4142. **Does it support remote execution?** → Use `--target` flag (default)4153. **Only use SSH if**: hotify cannot perform the operation at all416417## Key Learnings & Caveats418419### Traefik Configuration4204211. **ACME "Domain Not Defined" Error (v2.3.0 fix)**422 - **Issue**: Traefik rejects domain configuration without explicit `domains:` block423 - **Fix**: Always include `domains: - main: <domain>` in router TLS configuration424 - **Example**:425 ```yaml426 tls:427 certResolver: letsencrypt428 domains:429 - main: app.example.com430 ```4314322. **ACME Challenge Type Conflicts**433 - **Issue**: Having both DNS and HTTP challenges in traefik.yml causes conflicts434 - **Fix**: Use only one challenge type (HTTP is simpler, DNS for wildcards)435 - **Default**: HTTP challenge (v2.3.0+)4364373. **Service Reload Not Supported**438 - **Issue**: `systemctl reload traefik` fails on some systems439 - **Fix**: Always use `systemctl restart traefik` (v2.3.0+)440 - **Implementation**: Detect running state, use start vs restart accordingly4414424. **DNS Record Existence Check**443 - **Issue**: Attempting to create duplicate DNS records fails444 - **Fix**: Check existing record before creation — skip if IP matches, update if differs (v2.3.0+)445 - **Benefit**: Idempotent DNS setup446447### Docker Compatibility4484495. **Docker API Version Mismatch**450 - **Issue**: Traefik v3.1.4 uses Docker API v1.24, but Docker 29.x requires v1.44+451 - **Symptom**: "client version 1.24 is too old. Minimum supported API version is 1.44"452 - **Fix**: Upgrade Traefik to v3.6+ (v3.7.0 recommended)453 - **Requirement**: Traefik v3.6+ for Docker 29.x compatibility4544556. **Traefik Docker Provider**456 - **Configuration**: Use `exposedByDefault: false` for security457 - **Endpoint**: `unix:///var/run/docker.sock`458 - **Labels**: Required for routing (traefik.enable=true, Host rule, certResolver)459 - **Example labels**:460 ```yaml461 labels:462 - "traefik.enable=true"463 - "traefik.http.routers.myapp.rule=Host(\`myapp.example.com\`)"464 - "traefik.http.routers.myapp.entrypoints=websecure"465 - "traefik.http.routers.myapp.tls.certresolver=letsencrypt"466 - "traefik.http.services.myapp.loadbalancer.server.port=8080"467 ```468469### PID Tracking (v2.1.0+)4704717. **Daemon PID Tracking Issue**472 - **Issue**: When starting app via `sh -c <command>`, tracked shell PID exits immediately for daemon apps473 - **Fix**: Two-strategy resolver:474 1. `/proc` tree walk — finds leaf child of shell (single-fork processes)475 2. Port-based lookup via `ss` — finds PID by app's configured port (double-fork/setsid daemons)476 - **Implementation**: `resolveActualPID(shellPID int, port int)` in local_ops.go4774788. **Local vs Remote Operations**479 - **Local mode**: `--local` flag executes commands directly on server (no API)480 - **Remote mode**: Uses hotify daemon API on target server481 - **PID tracking**: Both local and remote use same two-strategy resolver482483### File Size Limits4844859. **500 LOC Limit**486 - hotify-cli enforces 500 lines of code per source file487 - Files exceeding limit must be split (e.g., process.go → local_ops.go + remote_ops.go)488 - **Rationale**: Maintainability and readability489490### Smoke Testing49149210. **Smoke Test Approach**493 - Comprehensive test document for each version494 - Test server: dk1@92.113.145.178495 - Categories: CLI structure, feature-specific, regression, E2E496 - Document issues found and fixed during testing497 - All tests must pass before release498499### Security & Permissions50050111. **Traefik Service File Permissions**502 - **Issue**: `/etc/systemd/system/traefik.service` owned by root, regular user can't write503 - **Fix**: Skip service file write if already exists (v2.3.0+)504 - **Rationale**: Config files in `/etc/traefik/` owned by deploy user, only service file needs root50550612. **Cloudflare Token Format**507 - **Issue**: Legacy API format (X-Auth-Key + X-Auth-Email) vs Bearer token508 - **Fix**: hotify-cli uses legacy format for broader compatibility509 - **Note**: Bearer tokens may work but not explicitly tested510511### Common Pitfalls51251313. **Base Domain Extraction Bug**514 - **Issue**: `getZoneID` was extracting only TLD (`fr` instead of `intrane.fr`)515 - **Fix**: Split on all dots, take last 2 parts for registrable domain516 - **Impact**: DNS setup would fail with "zone not found" error51751814. **Configuration Validation**519 - **Best practice**: Always validate config before touching Traefik files520 - **Check**: admin_email, domain, app ID, app domain, app port521 - **Benefit**: Prevents partial/broken state52252315. **Watch vs Restart**524 - **Issue**: Traefik's `watch: true` on file provider doesn't always pick up changes525 - **Fix**: Always restart Traefik after configuration changes526 - **Rationale**: Reliable configuration application527528## Troubleshooting529530### Traefik Errors531532**"domain not defined" in ACME logs**533- Cause: Missing explicit `domains:` block in router TLS configuration534- Fix: Use v2.3.0+ setup-traefik (adds domain spec automatically)535536**"reload is not supported for this unit"**537- Cause: systemd service doesn't support reload538- Fix: v2.3.0+ uses restart automatically539540**Docker provider errors**541- Check Traefik version (needs v3.6+ for Docker 29.x)542- Check Docker API version (`docker version | grep "API version"`)543- Verify Docker socket accessible: `ls -la /var/run/docker.sock`544545### DNS Errors546547**"zone not found"**548- Check Cloudflare token permissions549- Verify domain is managed in Cloudflare550- Check base domain extraction (should be 2-part, not just TLD)551552**"record already exists"**553- v2.3.0+ handles this automatically (skip/update/create)554- If using older version, manually delete via Cloudflare dashboard555556### Process Errors557558**PID becomes invalid after start**559- Daemon app double-forked, shell PID exited560- v2.1.0+ uses two-strategy resolver to find actual daemon PID561- Check: `hotify-cli status --id <app> --local`562563## Version-Specific Notes564565### v2.7.4566- Implemented server-side permission enforcement for all API endpoints567- Added wildcard support (`all`/`*`) for full access keys568- Created comprehensive endpoint-to-permission mapping in permissions.go569- Updated auth middleware to check permissions before allowing access570- Added 403 Forbidden responses with audit logging for permission denials571- Simplified permission management by removing redundant PermissionManager struct572- Updated API key creation to expand wildcards to individual permissions573574### v2.7.3575- Added remote execution support for `basic-auth`, `setup-traefik`, and `setup-dns` commands576- Added `--target` and `--local` flags to app configuration commands577- New remote API endpoints: `/api/remote/apps/{id}/basic-auth`, `/api/remote/apps/{id}/setup-traefik`, `/api/remote/apps/{id}/setup-dns`578- Fixed route conflicts by using `/api/remote/apps/` path pattern instead of `/api/apps/`579- Added `PostWithData` method to HTTPClient for POST requests that return response data580- Updated AGENTS.md with remote execution documentation and "no-humans mindset"581582### v2.7.0583- Refactored `traefik-system` to use HTTP API instead of SSH584- Added server-side API endpoints for Traefik installation/management585- hotify-cli is now fully SSH-independent (all commands use HTTP API)586- Removed SSH execution code from traefik_system.go587588### v2.6.0589- Added Docker Compose Deployment Automation (5 new commands)590- All new commands use HTTP API (no SSH required)591- Only `traefik-system` still uses SSH (legacy, to be refactored)592- Added server-side API endpoint `/api/compose/volume-init` for volume initialization593- Added `HTTPClient.PostLarge()` with 5-minute timeout for large uploads594595### v2.4.0596- Added Docker container management597- Added Traefik Docker provider enable/disable598- Requires Traefik v3.6+ for Docker 29.x compatibility599- Docker commands use `sudo docker` internally600601### v2.3.0602- Fixed ACME domain specification603- Added --challenge-type flag604- Fixed service reload vs restart605- Added DNS existence check606- Added config validation607- New CLI: setup-dns, setup-traefik608609### v2.1.0610- Added pause/resume for apps611- Fixed daemon PID tracking (both local and remote)612- Added --local flag for direct execution613- Split process.go into local_ops.go + remote_ops.go614615## Dependencies616617- **Go**: Pure stdlib, no external dependencies618- **Docker**: Required for Docker commands (v2.4.0+)619- **Traefik**: Required for reverse proxy (v2.3.0+ requires v3.6+ for Docker 29.x)620- **Cloudflare**: DNS provider (requires API token)621- **systemd**: Service management (Linux)