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.farm