> ## Documentation Index
> Fetch the complete documentation index at: https://docs.postqueen.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Docker Compose

> The supported way to run PostQueen, and how to configure it

Docker Compose is the supported way to self-host PostQueen. One file describes her and the
three services she depends on, and one command starts all of them.

This page is the reference for that file: what it starts, where settings live, and how to
change them. If you want to be walked through an install instead, use
[Try her locally](/installation/quickstart-local) or
[Deploy to a server](/installation/production).

<Snippet file="installation-pre-reqs.mdx" />

## What the stack contains

`docker compose up -d` starts eight containers. You do not install PostgreSQL, Redis or
Temporal separately, they come with it.

| Service                  | What it does                                 | Reachable at           |
| ------------------------ | -------------------------------------------- | ---------------------- |
| `postqueen`              | The app itself, web interface and API        | `localhost:4007`       |
| `postqueen-postgres`     | PostgreSQL 17, all your data                 | container network only |
| `postqueen-redis`        | Redis, caching and rate limiting             | container network only |
| `temporal`               | The scheduler that fires posts at their time | `127.0.0.1:7233`       |
| `temporal-ui`            | Dashboard for watching scheduled work        | `127.0.0.1:8080`       |
| `temporal-postgresql`    | Temporal's own database, not yours           | container network only |
| `temporal-elasticsearch` | Temporal's search index                      | container network only |
| `temporal-admin-tools`   | One-off maintenance commands for Temporal    | not a service          |

Only `postqueen` is published to your whole machine. Temporal's two ports are bound to
`127.0.0.1`, so they are reachable from the server itself and not from the network.

<Note>
  Clone the repository rather than copying the YAML out of this page. The repository also carries
  a `dynamicconfig` folder that Temporal mounts at startup, and the file changes between releases.
</Note>

```bash theme={"system"}
git clone https://github.com/GkhanKINAY/postqueen-docker-compose
cd postqueen-docker-compose
docker compose up -d
```

## Where configuration lives

Everything is configured with environment variables, and they ship **inline in
`docker-compose.yaml`**. Open the file, find the `environment:` block on the `postqueen`
service, and edit values in place:

```yaml theme={"system"}
services:
  postqueen:
    environment:
      FRONTEND_URL: 'https://postqueen.example.com'
      INSTAGRAM_APP_ID: '12345678901234567890'
```

That is the default and it is all most people need. Note the YAML style: `KEY: 'value'` with a
colon, not `KEY=value`.

<Warning>
  **Dropping a `.env` file next to `docker-compose.yaml` does nothing on its own.** Compose reads
  such a file only to substitute `${VARIABLE}` placeholders inside the YAML, and this file
  contains no placeholders. The variables are never passed to the container. This catches people
  out regularly, because it is genuinely how Compose behaves elsewhere.
</Warning>

### Using a file instead

If you would rather keep secrets out of the YAML, add an `env_file:` key yourself. Compose then
does pass that file's contents to the container:

```yaml theme={"system"}
services:
  postqueen:
    env_file:
      - postqueen.env
```

```env theme={"system"}
JWT_SECRET=your-long-random-string
INSTAGRAM_APP_ID=12345678901234567890
```

Note the syntax difference. Inside `docker-compose.yaml` it is `KEY: 'value'`. Inside an env
file it is `KEY=value` with no quotes needed.

### Using both

You can, and the precedence matters:

<Note>
  **`environment:` wins over `env_file:`.** If the same variable appears in both, the value in
  the YAML is the one the container gets. Since the shipped file already pins many variables to
  literal values, including empty ones, a variable you set only in your env file will be ignored
  if the YAML also mentions it. Either delete the line from the YAML or set your value there.
</Note>

### What does not work

<Warning>
  The Compose file mounts a `postqueen-config` volume at `/config`. **Nothing in the image reads
  it.** A file placed there is never opened. Use `environment:` or an `env_file:` key as above.
</Warning>

## Applying a change

```bash theme={"system"}
docker compose down && docker compose up -d
```

<Warning>
  `docker compose restart` is not enough. It reuses the existing container, which still carries
  the old environment. Changed settings need the container recreated, which is what `down`
  followed by `up` does. Your data lives in volumes and survives this.
</Warning>

## The settings you are most likely to change

The full list of around 135 variables is in
[Configuration Reference](/configuration/reference). These are the ones that matter for almost
every install.

| Variable                  | Shipped value               | Change it to                                                                |
| ------------------------- | --------------------------- | --------------------------------------------------------------------------- |
| `JWT_SECRET`              | a placeholder sentence      | A long random string, from `openssl rand -hex 32`. Set once, then leave it. |
| `MAIN_URL`                | `http://localhost:4007`     | Your public address                                                         |
| `FRONTEND_URL`            | `http://localhost:4007`     | The same public address                                                     |
| `NEXT_PUBLIC_BACKEND_URL` | `http://localhost:4007/api` | Your public address, keeping `/api`                                         |
| `DISABLE_REGISTRATION`    | `false`                     | `true`, once your own account exists                                        |
| `STORAGE_PROVIDER`        | `local`                     | `cloudflare` if you use R2, see [Uploads](/configuration/uploads)           |
| `EMAIL_PROVIDER`          | not set                     | `resend` or `nodemailer`, see [Email](/configuration/emails)                |

Two that people change and should not: `BACKEND_INTERNAL_URL` stays `http://localhost:3000`,
because it describes a hop inside the container rather than a public address. `DATABASE_URL`
and `REDIS_URL` already point at the bundled containers by service name and only need editing
if you bring your own database.

<Warning>
  **`RUN_CRON` and `IS_GENERAL` cannot be turned off by setting them to `false`.** They are
  tested for presence, not value, so the string `false` still counts as on. Leave them as they
  ship.
</Warning>

## Checking your configuration took effect

She inspects her own settings at the end of startup and reports anything questionable, then
carries on running anyway. A container that is up is not proof that the configuration is
sound, so it is worth looking:

```bash theme={"system"}
docker compose logs postqueen | grep -i "configuration issue"
```

Empty output is good news. Anything listed there names the variable it is unhappy about,
commonly a trailing slash or a missing URL.

## Pinning a version

The file ships with `image: ghcr.io/gkhankinay/postqueen-app:latest`. On a real install, change
`latest` to a specific version from the
[releases page](https://github.com/GkhanKINAY/postqueen-app/releases):

```yaml theme={"system"}
image: ghcr.io/gkhankinay/postqueen-app:v3.0.4
```

<Warning>
  This matters more than usual here. She reconciles her database schema on **every** boot, so an
  unattended image change is also an unattended schema change.
  [Backups and Upgrades](/installation/backups-and-upgrades) explains what that means and how to
  switch to migrations instead.
</Warning>

## Next Steps

<Snippet file="next-steps-selfhost.mdx" />
