It’s a Plan
Self-hosting

Deploy on Coolify

Coolify builds the stack from source and generates the secrets itself, so the setup is a resource, a branch and two domains. The same six containers as the Compose stack, managed from the Coolify interface.

AGPL-3.0 · Builds from source · Secrets generated

Before you start

  • A Coolify instanceWith a server attached to deploy on. coolify.io
  • A domain you controlTwo hostnames, one for the api and one for the web app. Keep them under one registrable domain, because the session cookie is issued on the parent they share.

Coolify builds the stack from source and generates the secrets itself, so the setup is a resource, a branch and two domains. Postgres, RustFS, api, worker, bot and web all come from one compose file.

Set it up

  1. 1Create the application

    New Resource → Public Repository, then pick the server to deploy on. Enter the repository URL and press Check repository:

    https://github.com/croffasia/itsaplan.git

    Fill in the rest and press Continue:

    • Build PackDocker Compose
    • Base Directory/
    • Compose Location/docker-compose.coolify.yml
  2. 2Choose the branch

    The application starts on main. Change it in Configuration → Git Source: set Branch, leave Commit SHA as HEAD, and press Save.

    • releaseReleased versions only. The release workflow moves this branch to each published release. It appears with the first published release; until then there is nothing to deploy from.
    • mainThe latest features, the moment they merge. Expect breaking changes between releases.
  3. 3Set the domains

    The stack serves two origins. Both are set in Configuration → General, one field per service, and each needs the container port after the host:

    • Domains for apihttps://api.example.com:3000
    • Domains for webhttps://app.example.com:3001

    Coolify turns those into SERVICE_URL_API and SERVICE_URL_WEB, which the compose file reads as the api’s API_URL and APP_URL, and as the api origin web hands to the browser.

  4. 4Deploy

    Press Deploy. Postgres, RustFS, api, worker, bot and web come up together. The one-shot migrate service applies the migrations first, and api, worker and bot start once it exits. The first account registered becomes the instance admin.

Environment variables

There is nothing to fill in by hand. The database password, auth secret, encryption key and RustFS credentials are generated on the first deploy and stay stable across later ones. The two domains you set in step 3 become the two public origins.

Optional variables from .env.example go in Configuration → Environment Variables: legal document URLs, passkey and cookie settings, telemetry opt-out, worker tuning. Mail, AI provider keys, single sign-on and the Telegram bot token are not variables. You configure them in the interface after you sign in.

Changing a domain or a variable later takes a redeploy, which is how Coolify applies an environment change.

Running the published images

A Public Repository resource always builds from source. To run the images published to GHCR on each release, create the stack as a service instead:

  1. 1New Resource → Docker Compose Empty

    Then pick the server.

  2. 2Paste the compose file

    Paste the whole of docker-compose.coolify-images.yml into Docker Compose file and press Save. It carries no build: sections, so nothing is built.

  3. 3Pick a version

    In Environment Variables, set VERSION to a release. Leave it out for the newest.

  4. 4Deploy

    Coolify generates a domain for api and one for web on the first deploy. Rename them under the service if you want your own.

To keep an existing Public Repository resource and pull instead of build, set Custom build command in Configuration → General to docker compose pull and redeploy.

Updates

A redeploy is the whole upgrade. On release it builds the newest published release; on the images service it pulls the tag in VERSION, or the newest when that is unset. The migrate service applies the new migrations before api, worker and bot start.

Before it applies them, it dumps the database and stops if the dump fails, so a release whose migrations rewrite data is never applied without something to go back to.

Troubleshooting

The release branch is not there.

It appears with the first published release. Until then, deploy from main.

A domain answers nothing, or answers with the wrong service.

The container port is missing from the domain field. Coolify needs https://api.example.com:3000 and https://app.example.com:3001, port included.

Sign-in returns to the login page.

The two domains are not under one registrable domain, so the browser drops the session cookie. Put both under the same domain and redeploy.

A changed variable had no effect.

Coolify applies environment changes on the next deploy. Redeploy the resource.

For anything else, read the container logs in Coolify, starting with migrate and the api.

Support

Other ways to run it: Railway, Docker Compose, Kubernetes.