Full workflow to deploy a Docker container with secrets, Caddy, and DNS
Complete workflow to deploy a new Docker container service with secrets, Caddy reverse proxy, and DNS.
If parameters are missing from $ARGUMENTS, use mcp_question to gather them:
mcp_question({
questions: [
{
question: "What should the service be named?",
header: "Service",
options: [
{ label: "Enter name...", description: "e.g., myapp (used for container, DNS, database)" }
]
},
{
question: "Which host should run this container?",
header: "Host",
options: [
{ label: "pilaster (Recommended)", description: "Main web services host" },
{ label: "monolith", description: "Infrastructure services" },
{ label: "zenith", description: "AI/GPU (AMD ROCm)" },
{ label: "obelisk", description: "GPU compute (NVIDIA)" }
]
},
{
question: "What is the container image?",
header: "Image",
options: [
{ label: "Enter image...", description: "e.g., ghcr.io/org/image:v1.0.0" }
]
},
{
question: "Does this service need a database?",
header: "Database",
options: [
{ label: "No", description: "No database needed" },
{ label: "Yes", description: "Create PostgreSQL database" }
]
}
]
})
Expected $ARGUMENTS format: <service_name> <hostname> <container_image>
myapp pilaster ghcr.io/org/myapp:1.0.0/initialize-pgdb)agenix-helper unlock
mkdir -p hosts/<hostname>/files/docker/env
/initialize-pgdb <hostname> <service>
cat > /tmp/<service>.env << 'EOF'
DATABASE_URL=postgres://<service>:<password>@postgres:5432/<service>
API_KEY=
SECRET_KEY=
EOF
# Encrypt
agenix edit -i /tmp/<service>.env hosts/<hostname>/files/docker/env/<service>.env.age
rm /tmp/<service>.env
virtualisation.oci-containers.containers.<service> = {
image = "registry/image:tag";
environmentFiles = [config.age.secrets.<hostname>_docker_env_<service>.path];
networks = ["servicenet"];
volumes = ["/data/docker/<service>/data:/app/data"];
dependsOn = ["postgres"]; # if using database
};
age.secrets.<hostname>_docker_env_<service> = {
rekeyFile = ./files/docker/env/<service>.env.age;
mode = "600";
};
Use /add-caddy-route skill or manually:
agenix view hosts/<hostname>/files/caddy/Caddyfile.age > /tmp/Caddyfile
echo '<service>.meskill.farm {
reverse_proxy <service>:8080
}' >> /tmp/Caddyfile
rm hosts/<hostname>/files/caddy/Caddyfile.age
agenix edit -i /tmp/Caddyfile hosts/<hostname>/files/caddy/Caddyfile.age
rm /tmp/Caddyfile
agenix rekey -a
cfcli --domain meskill.farm --type CNAME add <service> <hostname>.meskill.farm
agenix-helper lock
git add .
git commit -S -m "feat: add <service> container to <hostname>"
just remote-rebuild <hostname>
| Network | Purpose | Use For |
|---------|---------|---------|
| servicenet | Inter-container + Caddy | Web apps |
| datanet | Internal only (--internal) | Databases, caches |
| proxynet | Host port binding | Caddy, UDP services |
networks = ["servicenet" "datanet"];
dependsOn = ["postgres"];
devices = ["nvidia.com/gpu=all"];
extraOptions = [
"--device=/dev/kfd"
"--device=/dev/dri"
"--security-opt=seccomp=unconfined"
];
environment = {
HSA_OVERRIDE_GFX_VERSION = "11.0.0";
};
/deploy-container myapp pilaster ghcr.io/org/myapp:1.0.0
docker ps | grep <service>docker logs <service>curl https://<service>.meskill.farmSearch for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer