Skip to main content

Containerization

Containerization is the architecture that runs all self-hosted services here — OS-level virtualisation, isolating processes on a shared kernel, as opposed to a hypervisor running a separate guest OS per workload the way a full VM does. The core idea is isolation: each service runs in its own container with its own filesystem, network, and process space. Services can't interfere with each other, dependencies don't conflict, and deploying or removing a service doesn't touch anything else on the host.

Docker is the implementation used here — the de facto standard, with the largest ecosystem of pre-built images and the tooling this stack's deployment platform is itself built on. It's not the only one: Podman and containerd are the other common runtimes, closer to the container spec without Docker's daemon architecture. The concepts below (images, containers, volumes) are common to all of them; the specifics (Compose, the daemon) are Docker's own. Understanding the basics makes it much easier to debug issues, manage resources, and understand what Coolify is actually doing under the hood.

Basics

Images and containers

An image is a packaged, read-only snapshot of an application — the code, runtime, dependencies, and configuration all bundled together. Images are built from a Dockerfile and stored in a registry (Docker Hub, GitHub Container Registry, etc.). When you deploy a service in Coolify, it pulls the image for that service.

A container is a running instance of an image. You can run multiple containers from the same image, and each one is isolated — its own filesystem, network, and process space. Stopping or deleting a container doesn't affect the image it came from.

Think of it like this: an image is a recipe, a container is the dish.

Isolation and storage

Each container gets its own:

  • Filesystem — based on the image, with a writable layer on top for runtime changes
  • Network — containers communicate through Docker networks; services on the same network can reach each other by container name
  • Process space — processes inside a container cannot see or affect processes in other containers

Data that needs to survive container restarts is stored in volumes — directories on the host mapped into the container. Volumes are managed separately from containers and persist when a container is removed or restarted.

Resource management

Docker containers share the host's kernel, CPU, memory, and disk — but each container is isolated from the others. By default, a container can use as much CPU and memory as the host allows. If a container misbehaves and consumes too many resources, it affects everything else running on the same host. This is a real concern, but it's also controllable: resource limits (CPU and memory caps) can be set per container, ensuring no single service can starve the rest.

Orchestration

Three levels — Compose, a deployment platform, and Kubernetes — all answering the same underlying question: coordinating more than one container, just scoped differently: one app, one stack, or a fleet of machines. Each exists because the level below it runs out of reach at that scope.

Docker Compose

Docker Compose is a tool for defining and running multi-container applications. A docker-compose.yml file describes all the services that make up an application — which image each uses, what environment variables it needs, which ports to expose, which volumes to mount, and how the containers connect to each other. Most self-hosted apps consist of several containers this way: the app itself, a database, maybe a cache or a background worker. Compose starts and manages all of them as a unit — but only that one unit. Coolify generates and manages Compose files behind the scenes — you rarely need to edit them directly, but knowing what they do helps when something breaks.

Deployment platform

Compose stops at one app's containers — it has no UI, no accounts, no routing or SSL across many apps at once, and no shared way to handle secrets or environment variables across a whole stack. Multiply that by however many services this stack actually runs, and hand-editing a docker-compose.yml per service, SSHing in to run docker compose up for each one, stops being an operational model at all.

That's the gap a deployment platform fills. Coolify sits on top of Docker — generating and managing Compose files itself — and adds the layer Compose was never meant to provide: one dashboard for every service, routing and certificates handled automatically, environment variables and access managed centrally instead of per-server. It deliberately stays at the scale Compose already covers — a single server, or a handful — rather than reaching for the next level down.

Kubernetes

Kubernetes solves a different problem again: orchestration across many nodes, not one. Its core value is stuff this stack doesn't need yet — self-healing rescheduling when a node dies, horizontal autoscaling, a declarative API built around a cluster rather than a single host. Getting that means running Kubernetes' own considerable machinery too: a control plane, etcd, a networking overlay, all of it another layer of infrastructure to operate correctly before a single service of your own is deployed.

That's not a knock on Kubernetes itself — it's a genuinely powerful answer to a different shape of problem: one huge, heavy application that needs to scale elastically, not many small ones that are barely used. This stack's actual shape is the second — a long list of self-hosted apps, each under modest and fairly steady load — not a single workload that needs a cluster's worth of capacity behind it.