# Multi-node Coolify + SurrealDB deployment

This page describes a **scaled-out reference deployment** for Crown using:

- a self-hosted **Forgejo** delivery plane for source control and webhooks
- a self-hosted **OCI registry** for private image storage
- Coolify's documented **multi-server** operating model, specifically the **multiple domains across multiple servers** approach from the scalability docs
- distinct domain groups routed directly to **workload server A** and **workload server B**, each with its own Coolify-managed proxy
- separate workload hosts for frontends, APIs, and jobs
- SurrealDB's documented **multi-node scalable cluster** mode backed by **TiKV**

Official references:

- [Coolify scalability](https://coolify.io/docs/knowledge-base/internal/scalability)
- [Coolify introduction](https://coolify.io/docs/get-started/introduction)
- [Coolify concepts](https://coolify.io/docs/get-started/concepts)
- [Coolify build server](https://coolify.io/docs/knowledge-base/server/build-server)
- [Coolify multiple servers](https://coolify.io/docs/knowledge-base/server/multiple-servers)
- [Coolify proxies](https://coolify.io/docs/knowledge-base/server/proxies)
- [Coolify Docker registry](https://coolify.io/docs/knowledge-base/docker/registry)
- [Forgejo installation overview](https://forgejo.org/docs/latest/admin/installation/)
- [Forgejo installation with Docker](https://forgejo.org/docs/latest/admin/installation/docker/)
- [Forgejo container registry](https://forgejo.org/docs/latest/user/packages/container/)
- [SurrealDB multi-node TiKV deployment](https://surrealdb.com/docs/surrealdb/installation/running/tikv)
- [SurrealDB Docker deployment notes](https://surrealdb.com/docs/surrealdb/installation/running/docker)

## Reference topology

![Multi-node Coolify + SurrealDB deployment](../diagrams/generated/multi-node-coolify-surrealdb-deployment.svg)

Source: [`multi-node-coolify-surrealdb-deployment.mmd`](../diagrams/generated/multi-node-coolify-surrealdb-deployment.mmd)

## Flow order

![Multi-node Coolify + SurrealDB deployment flow](../diagrams/generated/multi-node-coolify-surrealdb-flow.svg)

Source: [`multi-node-coolify-surrealdb-flow.mmd`](../diagrams/generated/multi-node-coolify-surrealdb-flow.mmd)

This sequence view shows both halves of the model: the one-build-to-many-servers deployment flow and the runtime request flow where DNS sends a hostname to the specific workload server that owns that domain set.

## Why this pattern exists

The official Coolify scalability docs show two traditional horizontal-scaling shapes:

- **one domain across multiple servers**
- **multiple domains across multiple servers**

Coolify generally recommends the **one-domain** option as the simpler default. For Crown, this reference intentionally models the **multiple-domains** option instead, because that maps better to a platform with several frontends and APIs that can be placed deliberately on different machines.

Separately, the SurrealDB docs describe the **TiKV-backed cluster mode** as the option for **highly-available and highly-scalable setups**.

Putting those together gives a sensible Server A / Server B scaling path for Crown:

- treat self-hosted Forgejo and the registry as delivery infrastructure, not app features
- keep one control plane for deployment management
- spread workloads over multiple runtime hosts with **per-server proxies** and **per-server domain ownership**
- move the data tier to the SurrealDB clustering mode that was actually designed for scale

## How to read the diagram

This reference splits the platform into five concerns:

### 1. Delivery services

The self-hosted delivery plane holds:

- Forgejo as the Git provider and webhook source
- a dedicated **Coolify build server** that performs image builds away from runtime hosts
- a private OCI registry that stores deployable artifacts

If you use Forgejo's built-in container registry, the registry endpoint can live on the Forgejo instance domain. If you use a separate registry product, the deployment flow is still the same: builder pushes, Coolify pulls.

Coolify's multiple-server docs add one more important detail: when a deployment needs a build, Coolify builds the image once on the main server or the dedicated build server, pushes that image to the registry, and only then tells the workload servers to pull and deploy it.

### 2. Control plane

The Coolify server holds:

- project and environment configuration
- deployment targets
- deploy coordination

It does **not** need to sit in the public request path for every Crown hostname.

### 3. Workload server A

Server A is one domain-serving pool:

- it runs its own Coolify-managed proxy
- DNS sends a specific set of Crown hostnames directly to that server
- that local proxy then routes those domains to the frontend and API containers placed on Server A

This is the key difference from the single shared-load-balancer model: the server owns the domains it serves.

### 4. Workload server B

Server B works the same way:

- it has its own Coolify-managed proxy
- DNS points a different domain set at it
- it can host additional frontends, APIs, and jobs behind that local proxy

Because each server can host multiple apps, this model can be cost-efficient — but it also means bigger servers may be needed as you consolidate more domains and workloads onto a single machine.

### 5. Clustered data tier

The official SurrealDB multi-node guide uses **TiKV** as the backing store. In practice, that means thinking about the data layer as two parts:

- **SurrealDB query nodes** that Crown talks to
- **TiKV cluster nodes** that provide the distributed storage layer

The diagram intentionally abstracts the exact TiKV quorum sizing, but it shows the architectural truth: once you want the official scalable-cluster mode, SurrealDB is no longer just one local file on one host.

## Important SurrealDB nuance

The SurrealDB TiKV page uses a **single-node development TiKV cluster** in its example and explicitly frames that as being for **development and testing purposes only**.

That matters for Crown.

For real production multi-node deployments, you should treat the TiKV layer as a real distributed data platform with its own:

- sizing decisions
- redundancy model
- backup and restore procedures
- observability
- upgrade plan

In other words: the multi-node app topology is only half the story. The data tier must also be production-grade.

## Traffic pattern

In this reference shape:

- developers push to the self-hosted Forgejo instance
- Coolify dispatches the build once to the dedicated build server
- the build tier publishes versioned images to the self-hosted registry
- Coolify pulls those images onto workload hosts
- DNS points one hostname set directly at **Server A's proxy** and another hostname set directly at **Server B's proxy**
- each workload server terminates HTTPS locally through its own Coolify-managed proxy
- each local proxy routes only to the containers placed on that server
- Crown services talk to an **internal database endpoint** rather than a single pinned machine name
- that internal endpoint fans into multiple SurrealDB query nodes
- those nodes share the TiKV-backed cluster state

There is no single shared public ingress in front of all Crown domains in this reference. The domain split is the traffic-distribution mechanism.

## Coolify-specific operational caveats

The Coolify docs call out a few details that matter here:

- the **multiple servers** feature is still marked **experimental**
- each deployment server — and the optional build server — should use the **same architecture**
- every server that needs to pull images must be authenticated to the registry via Docker credentials
- the extra per-server proxy adds a small amount of overhead, though the docs note this is usually not noticeable
- health checks in this pattern are effectively **server-level**, not a single shared application-level load-balancer health model

## When to choose this pattern

Choose the multi-node pattern when:

- one server is no longer enough for the combined workload
- you want **domain-based placement**, where specific Crown hostnames live on Server A or Server B
- you want workload isolation between frontends, APIs, and background jobs
- maintenance or failure on one machine should not take out the whole platform
- the database workload justifies the operational complexity of a distributed data tier

## When not to choose it

Do **not** choose this pattern just because it looks impressively enterprise on a diagram.

Avoid it when:

- the current workload fits comfortably on a single host
- the team does not have operational ownership for clustered databases yet
- the main pain point is build speed rather than runtime scale
- you want one shared public entrypoint with central app-level load-balancer health checks

If the real issue is build pressure, the [Ubuntu / Coolify hosted deployment](./ubuntu-coolify-deployment.md) pattern with a dedicated Coolify build server is usually the better next move.

## Crown recommendation

For Crown, this Server A / Server B pattern is the right **second-stage scaling model** when you specifically want the Coolify **multiple-domains-across-multiple-servers** approach:

- keep Forgejo and the registry in the delivery plane rather than on app nodes
- use Coolify to manage multiple workload hosts
- give each workload host its own proxy and its own domain set
- keep runtime images immutable and registry-driven
- expose only the per-server proxy layers publicly
- front SurrealDB query nodes with an internal endpoint
- treat TiKV as a separately operated production subsystem

That gives Crown a credible path from “single box, simple ops” to “multiple hosts, deliberate domain placement” without inventing a custom platform story from scratch.
