decisionshared last reviewed 2026-05-21

Coolify multi-server topology โ€” staging+control vs prod

Context

Aspire's customer-facing apps deploy via Coolify. As the app count grew, running everything on one box created risk: a staging deploy could starve a production app of resources, and the control plane (Coolify itself) shared a host with customer workloads. The decision splits deployment across two servers with clear roles.

Detail

Topology

ServerIPRoleSSH
Staging + control plane112.121.151.46Coolify control plane + staging deploysssh coolify-staging (key ~/.ssh/coolify_vps)
Production103.243.116.249Customer-facing prod appsssh coolify-prod (key ~/.ssh/id_ed25519, UUID x9dcph0q2mtwql9illb6umkp)

Why split

Risk on single boxMitigated by split
Staging build starves prod appSeparate hosts, separate resources
Control plane outage takes down appsControl plane on staging box; prod apps keep serving
Resource contention during concurrent deploysBuilds happen on staging-side; prod just runs

Companion: OpenClaw VPS

Note this is SEPARATE from the OpenClaw VPS (112.121.151.239) which hosts the AI agent fleet + Knowledge OS โ€” see openclaw-vps-architecture. Three distinct servers total:

Coolify deploy gotchas (hard-won, per MEMORY.md reference_coolify_gotchas)

28 documented quirks. The ones that bite most often:

#QuirkWorkaround
1ports_exposes API param silently rejected (defaults to 80)Encode port in FQDN as https://host:4000
2update_application doesn't regenerate Traefik labelsDelete + recreate to change port routing
3limits_memory bytes bugWatch the unit
โ€”dockercompose default path .yaml not .ymlName files .yaml
21-23helper-prep race / container-recycle race / helper-killed-mid-build"Wait until in_progress queue EMPTY, then retry on idle VPS"
24GitLab PAT in ~/.claude.json rotates mid-sessionRe-read on 401
25Coolify auto-cancels queued >2hRetry
26force=true amplifies contentionAvoid during busy periods
28SvelteKit-proxies-Go-API needs explicit /api/* proxy routesAdd them

Build-time env injection gotcha (per MEMORY.md feedback_coolify_env_add_race)

Build log access (per MEMORY.md reference_coolify_build_logs)

Image-size killer (per MEMORY.md feedback_docker_image_size)

Constraints we accepted

Revisit trigger

Actions

Related

๐Ÿ”— Relationships

graph LR coolify_multi_server_topology["coolify-multi-server-topology"]:::self coolify_multi_server_topology --> openclaw_vps_architecture["openclaw-vps-architecture"] coolify_multi_server_topology --> coolify_deployment_default["coolify-deployment-default"] coolify_multi_server_topology --> gitlab_self_hosted_not_github["gitlab-self-hosted-not-github"] classDef self fill:#715EE3,color:#fff,stroke:#291F50;