[Coolify](https://coolify.io) is a self-hosted PaaS (an open-source Heroku/Netlify alternative) you run on your own VPS. It runs ClassroomIO from the published `classroomio/*` images — your Coolify host **pulls** them and never builds anything.
## Watch the walkthrough
Prefer to follow along? This video walks through the whole Coolify deployment end to end. The written steps below mirror it, and the [Environment variable reference](#environment-variable-reference) has every value to copy.
{/* TODO: replace REPLACE_WITH_VIDEO_ID with the Coolify walkthrough video id once recorded */}
- A running **Coolify instance** with a connected server.
- A **domain** with a DNS **A record pointing at your Coolify server's IP**. Coolify's built-in proxy terminates HTTPS and issues the certificate for you.
- An **SMTP provider** (or Zoho/ZeptoMail) for signup verification, password reset, and invite emails. See [Nodemailer SMTP docs](https://nodemailer.com/smtp/).
- *Optional:* an **OpenAI API key** (transcription + AI course generation) and Google OAuth / Unsplash keys.
This uses a **Docker Compose resource**: you paste the compose file and set every environment value yourself. The flow is: **create a project → add the compose file → set environment variables → point the dashboard domain → deploy → sign up**.
Log in to Coolify and **create a project**. When you add a resource, Coolify asks what type it is — GitHub, a Docker image, a service, or a **Docker Compose** file. Choose **Docker Compose**, then **paste the contents of [`docker-compose.images.yaml`](https://github.com/classroomio/classroomio/blob/main/docker-compose.images.yaml)** into the editor.
After saving, Coolify parses the compose file and lists the services: `postgres`, `redis`, `api`, `dashboard`, `jobs` (and `minio` once you enable its profile in the next step). Confirm they all appear before moving on.
Open the resource's **Environment Variables** page. This is where most Coolify deployments go wrong, so treat the [Environment variable reference](#environment-variable-reference) below as the source of truth: **set every variable it lists as required, and leave the optional ones blank.** The block here covers the essentials to get you started; the full copy-paste reference is a few sections down.
```zsh title="Essentials — set all of these"
COMPOSE_PROFILES=minio # runs the bundled MinIO object storage
DASHBOARD_ORIGIN=https://dash.yourdomain.com
BETTER_AUTH_SECRET=<openssl rand -hex 32>
PRIVATE_SERVER_KEY=<openssl rand -hex 32> # must be identical in the api and dashboard services
# Object storage + domains: see the full reference below
```
👉 The essentials above get you started, but the complete list of what to set — object storage, domains, and every optional variable — is in the [**Environment variable reference**](#environment-variable-reference) below. Copy that full block before you deploy.
`CIO_VERSION` chooses the tag pulled for `classroomio/{api,dashboard,jobs}`. **Confirm the tag you use actually exists** at [hub.docker.com/r/classroomio](https://hub.docker.com/r/classroomio/) before deploying.
Open the **dashboard** service → **Settings** and set its domain, including the internal port, e.g. `https://dash.yourdomain.com:3082`. Coolify maps that FQDN to the container's port `3082` and issues the certificate through its proxy.
The dashboard proxies API calls server-side, so you normally only expose the dashboard publicly — the `api` service stays internal.
Click **Deploy**. Coolify pulls `classroomio/{api,dashboard,jobs}:${CIO_VERSION}`, starts Postgres + Redis, the API container runs database setup on first boot, then the dashboard and the **jobs worker** come up. Watch the **logs** — they tell you when every service is up.
Once the logs show the stack is healthy, open your dashboard URL (`https://dash.yourdomain.com`) in a new browser tab and **sign up**. The **first** account becomes the organization **admin**. Every signup or sign-in after that joins as a student — unless you invite them with a specific role.
You set these on the resource's Environment Variables page (Step 3). This is the complete picture — copy the block below, then replace the placeholder values with your own.
Bump `CIO_VERSION` to a newer release and redeploy; roll back by setting it to the previous version and redeploying. Because you pin a version, a new release never restarts you onto broken images unattended. See [Configuration → Versions & upgrades](/self-hosted/configuration/versions) for the full upgrade and backup steps.