|
| 1 | +# Compose reference example |
| 2 | + |
| 3 | +> **Reference example only, not the supported deployment (NFR7).** The supported path is |
| 4 | +> single-node RKE2 with Fleet: [`docs/deploy/`](../../docs/deploy/README.md). Nothing here is |
| 5 | +> tested beyond `docker compose config`, and no upgrade, backup or restore path exists for it. |
| 6 | +
|
| 7 | +[`compose.yaml`](compose.yaml) runs the released images the way the Helm charts in |
| 8 | +[`deploy/charts`](../charts/README.md) do, on one Docker host: PostgreSQL 18.6 with the databases |
| 9 | +`coldframe`, `temporal`, `temporal_visibility` and `keycloak` ([`postgres-init.sh`](postgres-init.sh)), |
| 10 | +NATS 2.15.0 with JetStream, the Temporal schema and namespace one-shots and Temporal Server 1.31.2, |
| 11 | +Phase Two Keycloak, the migration one-shot, the Server and the web app. It is useful to read how the |
| 12 | +pieces fit together, or to try the web app on a LAN before you set up the real thing. |
| 13 | + |
| 14 | +What it does not have: |
| 15 | + |
| 16 | +- **No TLS.** Everything is plain HTTP on the LAN: the Server trusts an `http://` issuer |
| 17 | + (`Identity__RequireHttpsMetadata=false`), the web app talks to Keycloak over HTTP |
| 18 | + (`KEYCLOAK_ALLOW_INSECURE_HTTP=true`) and its session cookie is not `Secure`. Never expose these |
| 19 | + ports to the internet. |
| 20 | +- **No backups.** The data lives in the Docker volumes `postgres` and `nats`; `docker compose down -v` |
| 21 | + deletes it. |
| 22 | +- **The web app only.** Release builds of the mobile apps need HTTPS with a public certificate, and |
| 23 | + no push credentials are wired in ([`docs/build/apps.md`](../../docs/build/apps.md)). |
| 24 | + |
| 25 | +## Ports |
| 26 | + |
| 27 | +| Port on the Docker host | Service | |
| 28 | +| --- | --- | |
| 29 | +| 3000 | the web app: `http://<COLDFRAME_HOST>:3000` | |
| 30 | +| 8080 | the Server | |
| 31 | +| 8180 | Keycloak: `http://<COLDFRAME_HOST>:8180`, issuer `http://<COLDFRAME_HOST>:8180/realms/coldframe` | |
| 32 | + |
| 33 | +`COLDFRAME_HOST` is one LAN name or IP address of the Docker host. The browser and the containers |
| 34 | +both use it, so the issuer in a token is the same string the Server and the web app expect; the |
| 35 | +containers must be able to reach the host's published ports under that name. |
| 36 | + |
| 37 | +## Start it |
| 38 | + |
| 39 | +From the repository root, at the release tag you run (`git checkout vX.Y.Z`), with Docker Compose |
| 40 | +v2.23 or later and `jq`: |
| 41 | + |
| 42 | +1. Write the realm for your origin. The origin must be exactly `http://<COLDFRAME_HOST>:3000`, |
| 43 | + with the same `COLDFRAME_HOST` as in `.env` (step 2); a mismatch only shows as a `redirect_uri` |
| 44 | + error at the first sign-in, after the one-time import. `--allow-http` exists for this example |
| 45 | + only: |
| 46 | + |
| 47 | + ```sh |
| 48 | + deploy/realm/prepare-realm.sh --allow-http --web-origin http://<COLDFRAME_HOST>:3000 \ |
| 49 | + --out deploy/compose/coldframe-realm.json |
| 50 | + ``` |
| 51 | + |
| 52 | +2. Copy the settings and replace every value (git ignores `.env`; never commit it): |
| 53 | + |
| 54 | + ```sh |
| 55 | + cp deploy/compose/.env.example deploy/compose/.env |
| 56 | + $EDITOR deploy/compose/.env |
| 57 | + ``` |
| 58 | + |
| 59 | + `COLDFRAME_VERSION` is the release without the `v` (there is no default and no `latest`). |
| 60 | + Generate the secrets with `openssl rand -hex 32` and the Device key-encryption key with |
| 61 | + `openssl rand -base64 32`; record that key apart from this machine, since no enrolled Device works |
| 62 | + without it. The enrolment key goes on one line with `\n` between its lines: |
| 63 | + |
| 64 | + ```sh |
| 65 | + printf 'ENROLMENT_PRIVATE_KEY_PEM="%s"\n' "$(openssl genpkey -algorithm X25519 | awk '{printf "%s\\n", $0}')" |
| 66 | + ``` |
| 67 | + |
| 68 | +3. Start it: |
| 69 | + |
| 70 | + ```sh |
| 71 | + docker compose -f deploy/compose/compose.yaml --env-file deploy/compose/.env up -d |
| 72 | + docker compose -f deploy/compose/compose.yaml --env-file deploy/compose/.env ps -a |
| 73 | + ``` |
| 74 | + |
| 75 | + `temporal-schema`, `temporal-namespace` and `migrations` run once and exit 0; the rest keep |
| 76 | + running. On a host with SELinux (Fedora, RHEL) the containers cannot read the bind-mounted |
| 77 | + `postgres-init.sh` and `coldframe-realm.json` until you relabel them |
| 78 | + (`chcon -t container_file_t deploy/compose/postgres-init.sh deploy/compose/coldframe-realm.json`). |
| 79 | + |
| 80 | +4. Open `http://<COLDFRAME_HOST>:3000`, Register, verify the email (the SMTP values of `.env`) and |
| 81 | + create a Site, as in [section 6 of the deploy guide](../../docs/deploy/README.md#6-first-sign-in). |
| 82 | + |
| 83 | +The realm is imported on the first start only; to change it later use the Keycloak admin console |
| 84 | +(`http://<COLDFRAME_HOST>:8180/admin`, the bootstrap admin of `.env`), or start over with |
| 85 | +`docker compose ... down -v`, which deletes every volume. |
0 commit comments