Skip to content

Docker Compose apps from a git repository

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.

  • 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.
  • 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.
  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 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).

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.
Own Falak service The service leaves the stack and becomes its own Falak site from the same repository and branch.

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.

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.

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 “<stack> <service>”, 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).

The leader server needs that engine. An app server without one can get it later: see 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.

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. 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 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).

The stack’s containers then reach the instance through the Docker bridge; see 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), or Valkey isn’t offered for its OS.

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.

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 (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.

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.

  • 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): <service> 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.

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).

The Variables section lists every ${VAR} the stack uses and every key of its env_files, 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 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.

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.

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 per domain, purge after every deploy and rollback, rate limits per domain, and routing through a Cloudflare Tunnel with no extra setup.
  • 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 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).

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.

  • 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.