# Docker Compose apps from a git repository

> Deploy a Docker Compose app from your repository — compose files, overrides and profiles, a choice per service, variables and Falak's adjustments.

Source: https://falak.sh/docs/guides/compose-apps/

You tell Falak that a repository is a **Docker Compose app**, point it at the compose file in the repository, and decide
per service how it runs: inside the stack, public behind Falak's edge, as a Falak-managed database, or as its own Falak
site. Nothing is auto-detected. The repository stays the source of truth: Falak reads the compose files again on every
deploy and never edits them.

This guide covers the repository flow. For the Compose runtime itself (rendering, the deploy flow, the security policy,
inline files) see [Deploy with Docker Compose](/docs/deploy/docker-compose/).

## Prerequisites

- A server of type **app**, **web** or **worker** with **Docker** installed.
- A builder that does Docker builds (a `builder` server), even if no service uses `build:`. Built images go to Falak's
  [built-in registry](/docs/operations/install/#the-built-in-image-registry).
- A git connection. Falak reads files through the provider's API (GitHub, GitLab, Bitbucket). On a plain git server it
  can't read them before a deploy: services are listed after the first deploy, and you add public services in
  **Settings → Compose** then.

## Create the app

1. **+ Create → Git repository**, then pick the connection, repository and branch.
2. Under **App type**, choose **Docker Compose app** (instead of **One app**).
3. **Compose file**: the path in the repository, for example `compose.yaml` or `docker/compose.prod.yml`. Compose files
   found in the repository are offered as suggestions; Falak never picks one for you.
4. Optionally **Add override file**: each one is merged over the files before it, like `docker compose -f a.yaml -f
   b.yaml`. **Profiles** (comma-separated) choose which profiles run; services of other profiles don't run.
5. Falak reads and merges the project like `docker compose config`, then shows the **Services**, the **Variables**, the
   **Falak adjustments**, and any errors or [policy](/docs/deploy/docker-compose/#security-policy) violations.
6. Decide where each service runs (below), fill in the required variables, pick servers and **Create**. The first
   deploy starts.

Every choice stays editable afterwards in the service's **Settings → Compose** (source, files, profiles, the same
services table, variables and adjustments).

## The services table

One row per service, with what Falak found: the image or build context, ports and volumes. For each service, choose:

| Choice | What happens |
|---|---|
| **In the stack** (default) | Runs inside the Compose project, internal only. |
| **In the stack, public** | Runs in the stack and gets a domain through Falak's edge. Pick the **port** (from the service's ports), a **domain** (generated, test, custom or a Cloudflare name) and an optional **health check path**. |
| **Falak PostgreSQL / MySQL / MariaDB database** | Offered for `postgres`, `mysql` and `mariadb` images. The service leaves the stack and becomes a Falak database. |
| **Falak Redis / Valkey** | Offered for the official `redis` and `valkey/valkey` images. The service leaves the stack and becomes a Falak [Redis or Valkey instance](/docs/databases/redis-and-valkey/). |
| **Own Falak service** | The service leaves the stack and becomes its own Falak site from the same repository and branch. |

### Public services

Falak publishes each public service on `127.0.0.1:<allocated port>` and routes its domains to it with HTTPS; other host
ports are not published. The first public service is the site itself (it gets the site's domains). Every public service
has its own domains and edge settings; see [Edge for every public service](#edge-for-every-public-service).

After each deploy Falak requests every public service through its own domains: the **health check path** you set, or
else the site's health path for the first service and "any answer below 500" for the others. Public services without a
Docker `healthcheck` get a warning.

### A Falak database

Choose **Falak PostgreSQL / MySQL / MariaDB database** for a database service, and Falak:

- creates a database on the stack's leader server, named after `POSTGRES_DB`, `MYSQL_DATABASE` or `MARIADB_DATABASE`
  (else `<slug>_<service>`), or links an existing database of the same engine in the same environment;
- places it on the canvas next to the stack as "&lt;stack&gt; &lt;service&gt;", with backups and metrics like any Falak
  database;
- removes the service from the stack, drops `depends_on` on it, and points the variables that used it at the
  database (see [How references are rewritten](#how-references-are-rewritten)).

The leader server needs that engine. An app server without one can get it later: see
[Install an engine on an existing server](/docs/databases/create-databases/#install-an-engine-on-an-existing-server).
The stack's containers then reach the database through the Docker bridge (agent 0.4.5 or newer); see
[Containers and databases on the same server](/docs/databases/create-databases/#containers-and-databases-on-the-same-server).

### A Falak Redis or Valkey

Since v0.7.1, a service running the official `redis` image (also `docker.io/library/redis`) or `valkey/valkey` — any tag
or digest — can become a Falak-managed [Redis or Valkey instance](/docs/databases/redis-and-valkey/). Other images
(`redis/redis-stack`, `bitnami/redis`, other registries, services built with `build:`) stay containers. Choose
**Falak Redis / Valkey** for the service, and Falak:

- creates an instance named `<stack-slug>-<service>` (then `-2`, `-3` if taken) on the stack's leader server, with its
  own port (6380–6479) and password;
- reads its settings from the service's `command:` line: `--maxmemory` becomes the memory limit (whole MB, at least
  16), `--maxmemory-policy` the eviction policy, and `--appendonly yes` turns on `aof` persistence. The command may be
  a string or a list starting with `redis-server` / `valkey-server` or with a flag; a shell command or a config file
  gives the [defaults](/docs/databases/redis-and-valkey/#create-an-instance) instead;
- removes the service from the stack, drops `depends_on` on it, and points the variables that used it at the instance
  (see [How references are rewritten](#how-references-are-rewritten)).

The stack's containers then reach the instance through the Docker bridge; see
[Connecting from containers](/docs/databases/redis-and-valkey/#connecting-from-containers).

The leader server must already run the image's engine. Otherwise the service stays in the stack with a warning: the
server runs the other cache engine (one cache engine per server), it has none yet (install Redis or Valkey on it first,
see [Install an engine on an existing server](/docs/databases/redis-and-valkey/#install-an-engine-on-an-existing-server)),
or Valkey isn't offered for its OS.

The new instance starts empty. Whatever the `redis` / `valkey` container holds in its volume stays there and is not
migrated; the services table says so before you confirm. Copy the data over yourself if you need it.

Two cases are left for you to finish, and Falak warns about each:

- **TLS URLs.** `rediss://` and `valkeys://` values that point at the service are not rewritten (Falak instances don't
  offer TLS), nor are the port and password keys next to them. They keep pointing at the old service name.
- **Healthchecks.** A healthcheck of another service that names the extracted service as a host, such as
  `redis-cli -h cache ping`, is not rewritten — host, port and password flags differ per tool. Update it to use the
  instance's `REDIS_*` values. The same warning applies when a SQL database service is extracted.

### Its own Falak site

Choose **Own Falak service**, give it a name, and pick what it **runs as**: **Docker** (its Dockerfile), **Laravel** or
**Node.js**. Falak creates a site from the same repository and branch with:

- the service's build context as its [root directory](/docs/deploy/monorepos/#root-directory) (relative to the compose
  file; contexts outside the repository and remote contexts are refused);
- the service's `dockerfile` and container port;
- the service's `environment:` as variables (`${VAR}` and `${VAR:-default}` filled in from the stack's variables);
- the stack's servers.

You then pick its domain like any site. References to it from the stack become `https://<its primary domain>` plus the
path.

**Docker** is the runtime that keeps it connected to the stack: the site joins the stack's networks
(`<stack-slug>_default`, or the networks the service was on) on every server the stack runs on, under its service name
plus the aliases it declared. It still reaches `postgres`, `redis` and the other services by name, and the stack still
reaches it as before. A container joins at most 8 networks with Docker-safe names; others are left out with a warning.

A **Laravel** or **Node.js** site runs on the host, outside Docker's networks, so it only reaches the stack's **public**
services. When the service uses others (`depends_on`, or their names as hosts in its environment), the table warns:
pick Docker, or make those services public.

Splitting a service out needs permission for what it creates: `databases.manage` for a database, `sites.create` for a
site. Without it the service stays in the stack, with a warning.

### Deploy order for split-out services

- A split-out **Docker** site needs the stack's networks, which exist once the stack has been deployed. Its deploy waits
  up to 60 seconds for them, then fails with *deploy the compose stack it belongs to first, then redeploy this site*.
  A missing network never removes the running container.
- The stack's deploy stops while one of its split-out sites has never been deployed (an nginx proxying to it would fail
  to start): *&lt;service&gt; now runs as its own Falak site, which hasn't been deployed yet. Deploy that site first,
  then this stack.*

So split services out of a stack that is already running: deploy the new site, then redeploy the stack.

### How references are rewritten

When a service moves to a Falak database or its own site, Falak finds the variables that pointed at it, in the services
that stay and in the stack's own variables, and rewrites them:

| Before | After |
|---|---|
| `DATABASE_URL=postgres://u:p@db:5432/app` | `${{ <database>.DATABASE_URL }}`-style references (resolved at deploy) |
| `DB_HOST=db`, `PGHOST=db`, `db:5432` | The database's host, and companion keys (`…PORT`, `…USER`, `…PASSWORD`, `…DB` / `…NAME`) |
| `REDIS_URL=redis://cache:6379/1` | `${{ <instance>.REDIS_URL }}`-style reference; the path (`/1`) is kept, credentials are replaced |
| `REDIS_HOST=cache`, `cache:6379` | The instance's `REDIS_HOST` (and `REDIS_HOST:REDIS_PORT`), plus the `…PORT` and `…PASSWORD` keys of the same prefix (`REDIS_QUEUE_PORT` follows `REDIS_QUEUE_HOST`) |
| `API_URL=http://api:8000/v1` | `https://<the site's primary domain>/v1` |

Rewrites are kept per service, so `DB_PASSWORD` in two services can point at two databases. They follow renames and
domain changes. A driver name such as `DB_CONNECTION=mysql` is not treated as a host, nor is an image name such as
`IMAGE=redis:7`.

For Redis and Valkey, a `REDIS_HOST` that had no `REDIS_PORT` or `REDIS_PASSWORD` next to it gains them: clients
default to port 6379 and no password, while a Falak instance listens on its own port and requires its password.
`redis://` and `valkey://` URLs are rewritten wherever they appear in a value; `rediss://` and `valkeys://` are not (see
[A Falak Redis or Valkey](#a-falak-redis-or-valkey)).

## Variables

The **Variables** section lists every `${VAR}` the stack uses and every key of its `env_file`s, with the default from
the files. Only `${VAR:?message}` and `${VAR?message}` are **required**: the create flow asks for a value before the
first deploy. The values are saved as the service's variables (encrypted), and may use
[references](/docs/guides/variable-references/) such as `${{ shop-db.DATABASE_URL }}`.

Members with view access see the services and the variable names, but not the YAML or the env-file values.

## Falak adjustments

At render time Falak applies a few changes so the project runs well under Falak. Your repository is never changed;
**Settings → Compose → Falak adjustments** lists them with **Show the diff** ("your project → what Falak runs").

- **Host ports** are removed; public services are published on loopback ports.
- **`container_name`** is removed (names would clash between environments and during a rollback).
- **`restart: unless-stopped`** is added where a service sets no restart policy, so the stack comes back after a
  server reboot. Since v0.7.1 this applies at every deploy to inline stacks too (including ones created through the
  API); before, inline stacks got no policy and stayed `Exited` after a reboot.
- **Missing bind sources:** a bind mount like `./data:/var/lib/data` whose source isn't in the repository becomes a
  named volume `<service>-<path>`, kept across deploys. Tick the mount in the services table to keep an empty folder
  per release instead.
- **Repository files ship with each release.** Files the project mounts or reads (bind sources, `env_file`,
  `configs` and `secrets` with `file:`) are copied from the repository into the release, so `./nginx.conf:/etc/nginx/nginx.conf`
  works. This needs agent feature `compose.v2`.
- **Falak's `.env` only where needed.** An `env_file` the repository lacks is dropped, and only those services get
  Falak's `.env` (every site variable) instead. Other services read site variables through `${VAR}` interpolation, so
  third-party images don't receive unrelated secrets. Mounts and env files naming Falak's own `./.env` and
  `./compose.yaml` keep pointing at them.
- **Services run elsewhere** (Falak databases, own sites) are removed with their `depends_on`, and their references
  rewritten.

The security policy stays blocking unless an admin allows privileged compose.

## Edge for every public service

Every public service gets the same edge features as a site. In **Settings → Networking**, pick the service in the
service picker:

- **Domains:** several per service — generated, test, custom or names under a managed Cloudflare zone — each with
  automatic TLS and `www` redirects. The domain chosen at creation becomes the service's first domain.
- **Cloudflare:** DNS records, proxy on or off, a [cache mode](/docs/guides/cloudflare/#cache-purge-and-protection) per
  domain, purge after every deploy and rollback, [rate limits](/docs/guides/cloudflare/#rate-limits) per domain, and
  routing through a [Cloudflare Tunnel](/docs/guides/cloudflare/#cloudflare-tunnel-no-open-ports) with no extra setup.
- **[Routing rules](/docs/guides/routing-rules/):** redirects, basic auth and headers apply to the whole site or to one
  service. IP lists per service: a service's allow list **replaces** the site's, its deny list **adds** to it.
- **Path mounts:** a [function's path](/docs/guides/functions/#paths-on-other-sites) can be mounted on one service,
  for example `app.example.com/api/*`.

When a public service is split into its own site, it takes its domains and rules along (and the site-wide basic auth,
headers and IP lists are copied to it).

## On the canvas

A repository stack is drawn as a **group**: one card per service with its state, image, public URL and volumes, and
`depends_on` arrows. A database split out of it is placed next to it. The **Services** tab lists each service's
health, image digest, ports, restarts, CPU and memory.

## Limits

- Repository files shipped with a release: at most **200 files / 2 MB** per release. A compose file read from the
  repository is at most 1 MB.
- Paths may use any name except `.`, `..` or empty segments, backslashes and control characters. The release's
  repository files are written from scratch on every deploy, without following links.
- `include` and `extends` work with files from the repository only (no remote includes).
- Previews check each referenced path with the provider (at most 100 lookups in 20 seconds).
- On a plain git server (no API), Falak can't preview the project; services show up after the first deploy.
- Services built with `build:` need a Docker builder; managed servers never build.

## Next steps
