The Custom app option (deploy from a GitHub repository) runs a single container, and can have a MySQL, MariaDB, PostgreSQL, MongoDB or Redis database created with it (see Add a Database to Your App). Some projects are not a single process. They declare their own Postgres, Redis or several services together, usually with a docker-compose.yml already in the repo. For those, use Bring Your Own Compose.
When you need this instead of Custom app
If the project's README or setup instructions mention running docker compose up, or it needs a database connection just to start, a single container has nowhere to get that from. It will build successfully and then fail or crash-loop every time.
How it works
Open Templates in your dashboard and paste a full docker-compose.yml. Every service it declares (your app, Postgres, Redis, a worker, whatever the project needs) deploys together as one stack, with real values filled in for any placeholder passwords or secrets the file expects. If the project ships its own compose file for self-hosting, start from that instead of writing one from scratch. Check which branch it is on, since it is not always the repo's default branch.
What is not allowed
Each service runs as an unprivileged container on shared infrastructure, so host networking, privileged mode and host-path bind mounts are not supported.
Delete every ports: line as well. A published host port such as "8080:8080" tries to claim that port on the shared server directly. It can collide with another app, and the deploy fails with port is already allocated. Services still reach each other by name without it, and whichever one needs to be public gets its URL from FlyNode's domain routing instead.
Common mistake
A project's own self-hosting compose file almost always publishes a port for every service, because it was written assuming it owns the whole machine. Before pasting one in, open it and delete every ports: block first.
Example
services:
app:
build: https://github.com/you/your-repo.git#main
environment:
DATABASE_URL: postgres://app:${DB_PASSWORD}@db:5432/app
REDIS_URL: redis://cache:6379
depends_on:
- db
- cache
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_DB: app
volumes:
- db-data:/var/lib/postgresql/data
cache:
image: redis:7-alpine
volumes:
db-data:
Services reach each other by name (db, cache), the same way they would with plain Docker Compose anywhere else.
Build your own code from Git
A service can build your own project instead of using a ready-made image. Give it a Git address, as in the example above. build: . does not work, because your compose file is stored apart from your code and there is nothing in that folder to build. The repository must be public and have a Dockerfile at its root. For a private repository, use a Custom app with a private repository, or publish an image.
Settings your file asks for
Write a password or secret as a reference such as ${DB_PASSWORD}, never as plain text. When your file contains references like that, a box appears under the file asking for each value. Type one in, or press Generate to make a random one. The values are in place before anything starts. This matters for databases: one that starts without its password sets itself up without one, and a password added later does not change that.
After it deploys
- Settings, then Deploys lists every build and start with its log. If a deploy fails, the reason is there.
- Settings, then Variables holds the values you set. Change one and press Save and redeploy. A database that has already set itself up keeps its first password.
- Database shows the host, port, user, password and database name of every Postgres, MySQL, MariaDB or MongoDB service in your file. The database is only reachable from your own services (use the host name shown), never from the internet.
Open a database in your browser
On the Database tab, press the one-click button for your database: pgAdmin for Postgres, phpMyAdmin for MySQL and MariaDB, mongo-express for MongoDB. It starts next to your app, connects on its own and opens in a new tab. mongo-express has its own sign-in; the username and password are shown once, so save them. These tools count toward your workspace's apps and memory, so delete them when you are done.
Deploying a single-process repo instead? See Deploy a GitHub Repository.
Still stuck?
Open a support ticket from your dashboard and include the container name.