6.5 KiB
name, description
| name | description |
|---|---|
| deploy-app | Automated deployment of Dockerized applications to remote servers with Gitea registry, Docker Compose orchestration, and Nginx Proxy Manager integration. |
Deploy Application
Lean-mode deployment contract for token-efficient execution. Use this file for runtime behavior. For deep examples and full walkthroughs, reference README.md.
Prerequisites
DEPLOY_CONFIG_{TARGET}env var exists and is valid JSON- SSH host alias works from
~/.ssh/config Dockerfileexists in workspace root- Docker available locally and on target server
Deployment Steps
1. Parse target
Extract {TARGET} from user request (for example: deploy production → PRODUCTION).
2. Detect app metadata (minimal set)
Detect and store:
{app_name}: frompackage.json/Cargo.toml/pyproject.toml/go.mod/ directory fallback{port}: fromEXPOSE,.env PORT, or framework patterns; fallback3000(container internal port){app_type}:webapp,service, orworker{requires_llm}: true ifopenai|ollama|llamadetected{detected_volumes}: bind all host paths under./data/(including secrets paths)
If .env* exists (excluding .env.local), process variables into:
- generated secrets (
*SECRET*,*KEY,*TOKEN) - inferred service URLs (
DATABASE_URL,REDIS_URL, etc.) - copied simple values (
NODE_ENV,PORT,LOG_LEVEL, ...) - user-required values (placeholders/external API keys)
3. Load and validate deploy config
Read DEPLOY_CONFIG_{TARGET} and validate required fields:
gitea_registry_url,gitea_username,gitea_token,gitea_namespacessh_host,stacks_dir
If missing/invalid: STOP with explicit error.
4. Confirm detected configuration
Use ask_questions with detected summary (app, port, type, env, volumes, URL if webapp, deploy mode).
If user declines, STOP and request adjustments.
If user-input env values are required, collect them before continuing.
5. Validate and build locally
Verify Dockerfile exists, then run:
docker build -t {app_name}:test-build .
If build fails: STOP and report error output.
6. Push image to registry
- Login with
--password-stdin - Tag as
latestand{timestamp}(YYYYMMDD-HHMMSS) - Push both tags
If auth/network/permission fails: STOP with targeted troubleshooting.
7. Detect deploy mode (new vs update)
On remote host and in NPM API (when configured), detect:
- stack path exists:
{stacks_dir}/{app_name} - compose file exists:
{stacks_dir}/{app_name}/compose.yaml - proxy host exists for
{app_name}.{domain}(webapp only)
Classification:
new: none of the above existupdate: stack path or proxy host already exists
If only one side exists (for example proxy exists but stack does not, or inverse), continue in cautious update mode and include this mismatch in confirmation.
8. Prepare remote stack
- Verify SSH connectivity
- Create
{stacks_dir}/{app_name}/dataand required subdirectories - Process
.envwith update-safe merge strategy:- if update and remote
.envexists, preserve existing keys/values - append newly required keys not present remotely
- never delete existing keys automatically
- block on unresolved required user-input secrets/placeholders
- if update and remote
- Apply secure permissions to remote
.env(chmod 600) - Handle volume drift safely:
- create newly required host directories
- enforce all volume and secrets host paths as children of
./data/ - keep existing volume paths intact
- never remove existing volume mounts automatically
9. Generate and upload compose.yaml
Compose requirements:
- image:
{gitea_registry_url}/{gitea_namespace}/{app_name}:latest - restart:
unless-stopped - all volumes and secrets host paths under
./data - do NOT publish ports on host (no
ports:mapping by default) - use external proxy network for
webapp - add ollama network and
OLLAMA_BASE_URLwhen{requires_llm}=true
Update behavior for compose generation:
- keep service naming stable for idempotent updates
- preserve existing mounts/networks unless user explicitly confirms removal
- if update and env + volume definitions are unchanged, do NOT rewrite
compose.yaml - if update requires compose rewrite, fetch remote
compose.yamland use it as template baseline before applying required deltas
Upload compose file to {stacks_dir}/{app_name}/compose.yaml.
10. Deploy on server
On remote host:
docker loginto registrydocker compose downdocker compose pulldocker compose up -d- Inspect logs (
--tail=50) after short wait
If container exits or logs show startup failure: STOP and report logs.
11. Configure reverse proxy (webapp only)
If {app_type}=webapp and NPM config exists:
- Authenticate to NPM API
- Check if proxy host for
{app_name}.{domain}already exists - Set upstream target to Docker service name + internal container port (
{app_name}:{port}) on shared proxy network - If existing: update upstream target and SSL settings (idempotent update)
- If not existing: create proxy host, request certificate, then enable SSL
If SSL creation fails: WARN and continue HTTP-only.
12. Verify deployment
- Webapp:
curl -I https://{app_name}.{domain}and expect2xx/3xx - Non-webapp: verify running container and health/log readiness
Return structured success summary (image, host, location, URL/container).
Error Recovery
On failure:
- Show concrete error
- Provide immediate remediation steps
- STOP (no implicit continuation)
- Offer rollback option using ONLY non-destructive actions:
- run
docker compose downin the app stack directory - rollback changes in Nginx Proxy Manager (remove/disable created proxy host entries for this deploy)
- run
Forbidden Operations
Safety policy for this skill is strict:
- NEVER execute deletion commands on local or remote systems.
- NEVER run any
rm-family or delete operations, including recursive deletes. - NEVER use destructive cleanup commands that remove files, directories, volumes, or containers.
Allowed remediation is limited to:
docker compose down- rollback changes in Nginx Proxy Manager
If a remediation path would require deletion, STOP and report manual follow-up steps without executing destructive commands.
Security
- Never print secrets in logs
- Use
--password-stdinfor all docker logins - Quote shell variables
- Validate all required inputs before executing remote operations
Notes
- Keep runtime behavior minimal and deterministic.
- For advanced examples, edge-case recipes, and setup wizard usage, see README.md.