Deployment

Ubuntu + Coolify Hosted Deployment

A split build/runtime model where Forgejo, Coolify, the build server, registry, migration job, and runtime host each have a clear role.

DeploymentCoolifyBuild server

This page shows a practical reference deployment pattern for running Crown on an Ubuntu VPS or a dedicated Ubuntu server with:

  • Coolify on the target host
  • self-hosted Forgejo on the infrastructure as the Git provider
  • a self-hosted OCI registry for private image storage
  • a dedicated Coolify build server for remote image builds
  • a delivery path of Forgejo → Coolify → build server → registry → runtime host

This is intentionally different from the repo-inferred runtime topology. It explains a recommended production hosting shape rather than a graph that can be derived directly from source code alone.

If you want the other curated Coolify reference shapes, also see:

Official references:

What “build server” means here

In this page, build server means Coolify's documented Build Server feature — not just any random CI box with Docker installed.

That means the build server is expected to be:

  • added to Coolify as a server and marked as a build server
  • able to access the application source code
  • running Docker Engine
  • authenticated with the target container registry
  • using the same CPU architecture as the runtime servers

The Coolify docs also call out two important caveats:

  • the built image must be pushed to a registry before deployment
  • a server marked as a build server is effectively build-only until that option is disabled

If you configure multiple build servers, Coolify may select one at random, so keep them equivalent.

Reference topology

Ubuntu / Coolify hosted deployment
Ubuntu / Coolify hosted deployment

Source: ubuntu-coolify-deployment.mmd

Flow order

Ubuntu / Coolify deployment flow
Ubuntu / Coolify deployment flow

Source: ubuntu-coolify-deployment-flow.mmd

This sequence view shows the end-to-end handoff order between Forgejo, Coolify, the dedicated build server, the registry, the migration job, the runtime host, and the live user request path.

Why this pattern works well

The main idea is simple:

  • build somewhere else
  • deploy prebuilt images to Ubuntu
  • let Coolify handle rollout, routing, TLS, and environment management

That gives you a cleaner production box because the deployed host is responsible for:

  • pulling images
  • starting/stopping containers
  • storing runtime secrets and environment values
  • routing HTTPS traffic
  • preserving data volumes

Meanwhile, the dedicated Coolify build server is responsible for:

  • cloning the source from Forgejo
  • running the image build away from the runtime host
  • pushing tagged images to the registry

If you also want broader CI gates like linting, integration tests, or policy checks, run those before the deployment trigger. The Coolify build-server feature is primarily about offloading image builds from the runtime host.

In other words: the production host behaves like a runtime, not like a build farm. Much healthier. Less drama.

Main roles in the deployment

ComponentResponsibility
Self-hosted ForgejoSource of truth for code, PRs, and deployment-triggering webhooks
Coolify build serverDedicated build-only server used by Coolify to build images away from the runtime host
Self-hosted OCI registryStores versioned images for Coolify to deploy
Ubuntu VPS / dedicated serverTarget runtime host
CoolifyManages apps, environment variables, rollouts, domains, and deploy triggers
Reverse proxyTerminates TLS and routes domains to the correct frontend or API
Runtime and delivery storageStores operational data, support files, repositories, and image blobs

Typical deployment flow

  1. A developer pushes to the self-hosted Forgejo instance or creates a release tag there.
  2. A webhook or manual action triggers the resource in Coolify.
  3. The resource is configured with Use a Build Server?, so Coolify dispatches the build to the dedicated build server instead of building on the runtime host.
  4. The Coolify build server clones the source, builds the image, and pushes a versioned image to the self-hosted OCI registry.
  5. Coolify then deploys that image to the Ubuntu runtime host.
  6. The database-migrations job runs before dependent services come up.
  7. Backend and frontend containers are recreated.
  8. Traffic continues through the reverse proxy using the configured public domains.

What runs on the Ubuntu host

A single Ubuntu VPS or dedicated server can host all of this on one machine:

  • Forgejo
  • the self-hosted registry
  • Coolify control plane
  • reverse proxy / ingress
  • frontend containers
  • backend service containers
  • SurrealDB
  • named volumes for persisted data

That is usually the simplest starting point.

For a larger dedicated setup, you often keep the same topology but give it more CPU, memory, and storage headroom. The logical layout does not really change — the box just sweats less.

The main catch is that the host is now serving both the runtime and the delivery plane, so repository growth and registry blob growth become operational concerns rather than somebody-else's problem.

Recommended boundary between build and runtime

The Coolify build server should do the image-build work:

  • source clone
  • dependency install as needed by the image build
  • Docker image creation
  • image tagging
  • registry authentication and image push

The Ubuntu/Coolify host should mainly do runtime work:

  • image pull
  • container restart / rollout
  • env and secret injection
  • TLS and domain routing
  • volume mounting
  • health-check-based recovery
  • optionally hosting Forgejo and the registry if you accept the extra shared blast radius

That separation helps because it:

  • reduces production-host load
  • avoids compiler/toolchain drift on the runtime host
  • makes deploys faster and more repeatable
  • gives you cleaner rollback behaviour through image tags

Network shape

The public internet should normally only reach:

  • 80/443 for HTTP/HTTPS
  • 22 for SSH, ideally restricted

Everything else should stay internal to Docker networking on the Ubuntu host.

A good baseline is:

  • frontends and APIs behind the Coolify-managed proxy
  • Forgejo and the registry also behind explicit domains if they are hosted on the same box
  • SurrealDB not publicly exposed unless there is a very specific operational reason
  • internal service-to-service traffic using container DNS names
  • backups and admin access handled separately from user-facing traffic

Data and persistence

In this pattern, the most important persisted runtime state is still:

  • the SurrealDB volume
  • the support attachments volume
  • the Forgejo repository/config data
  • the registry blob storage

If you are deploying on a VPS or dedicated host with local volumes, make sure you also have:

  • scheduled backups
  • restore testing
  • disk monitoring
  • enough free space for image pulls and log growth
  • cleanup policies for stale images and old repository artifacts

Single-host vs split-host options

Single Ubuntu host

Best when you want the simplest path:

  • Coolify, reverse proxy, services, and DB all on one VPS/dedicated server
  • easiest operational model
  • fewer moving parts
  • good for early production or smaller workloads

If you want that model documented explicitly as a first-class reference pattern, use Single-server Coolify deployment.

Split build + runtime

Best when you already have CI capacity elsewhere:

  • Coolify build server handles image creation away from the runtime host
  • Ubuntu/Coolify host only runs workloads
  • better resource isolation
  • usually the preferred pattern for stable production setups

Split data host

Possible later if needed:

  • app/runtime host remains on Ubuntu + Coolify
  • database moves to a different machine or managed service
  • requires more deliberate networking, backup, and latency planning

If you need full multi-server scale-out rather than only a split build/runtime path, continue with Multi-node Coolify + SurrealDB deployment.

How this fits Crown specifically

For Crown, this pattern maps well because:

  • the repo already produces containerized frontends and services
  • a migration job exists and should run before dependent services
  • frontends are static-container deployments behind a proxy
  • services expect internal DNS-based communication in production-style networking
  • the platform already benefits from separating build concerns from runtime concerns
  • Forgejo can act as the self-hosted Git system while the registry stays private and close to the runtime host

Practical recommendation

If you are deploying Crown to Ubuntu with Coolify, the safest default is:

  • Coolify on the Ubuntu target host
  • Forgejo as the self-hosted Git provider, ideally with explicit storage and domain routing
  • dedicated Coolify build server for remote image builds
  • self-hosted OCI registry using immutable image tags
  • internal-only database networking
  • persistent volumes with backup coverage

That gives you a production flow that is understandable, repeatable, and much easier to reason about during incident response and rollback.