BROKABROKA
Sign inDownload CommunityRequest a demo
GuideDeployment

Production deployment checklist

Four containers, one published port, one volume and one key you cannot regenerate. The list is short because the deployment is; the items on it are the ones that cannot be fixed after the first start.

10 min read

BROKA runs as four containers described by one compose file, with every secret in a .env beside it. Most of what goes wrong in production is decided before docker compose up -d — which values were generated, which port is reachable, where the key lives — and cannot be corrected by restarting. This is the list, in the order the decisions have to be made. The files come from the download page, byte for byte with their checksums.

Before the first start

1 — Know what runs, and what is reachable. Four services: the console (ui), the API (orchestrator), the broker service (broker) and PostgreSQL. Only the console publishes a host port — BROKA_HTTP_PORT, default 3000, onto 8080 inside. The orchestrator and the broker service talk to each other by service name, and PostgreSQL is not published at all. There is no message broker in this stack: BROKA is a console for brokers, and you point it at your own after it is running.

The edition is decided by which images you run — not by a setting: the Community broker carries Kafka, and the Commercial one adds Redis, RabbitMQ, Apache Artemis (formerly ActiveMQ Artemis) and Memcached, while only the Commercial orchestrator and console carry the licence screen. Commercial is installed from the customer portal, with its own guide.

2 — Generate the secrets once. The images ship no defaults for them: an unset value stops the start and names the variable — Compose refuses before creating a container, and an image started another way exits naming it — rather than booting on a publicly known key.

Variable What it is Generate with
POSTGRES_PASSWORD The database password, used by all three services openssl rand -base64 24
BROKA_JWT_SECRET Signs access tokens; at least 32 bytes openssl rand -base64 48
BROKA_KEK Encrypts every broker credential you save; exactly 32 bytes, base64 openssl rand -base64 32
BROKA_SERVICE_TOKEN Authorises the internal call from the API to the broker service openssl rand -hex 32

BROKA_KEK_ID is a label for the active key, not a secret. BROKA_KEK, BROKA_KEK_ID and BROKA_SERVICE_TOKEN are read by both the orchestrator and the broker service and must be byte-identical in both; a mismatch is not a startup error — it surfaces later as broker calls that return 401, or a stored credential that cannot be decrypted.

3 — Treat BROKA_KEK as unrecoverable.

Every broker connection secret you save is encrypted with it and stored that way in PostgreSQL. Replace it on an installation that already has connections and those secrets become permanently unrecoverable — no error at startup, no warning in the console, and no database backup helps, because the database is not what was lost. Generate it once. Back up .env as carefully as you back up the database, and keep the two together.

Rotating the key deliberately is supported and does not mean editing this value alone. The current key and its BROKA_KEK_ID move to BROKA_KEK_PREVIOUS and BROKA_KEK_PREVIOUS_ID, the new key goes in with a new label, both services are restarted, and Rotate key-encryption key in Settings ▸ Security, which asks for a reason, re-wraps what is stored before the previous pair is cleared.

4 — Pin the version. BROKA_VERSION=1.0.0. Tracking latest makes an upgrade something that happens to you; pinning makes it an edit you make on purpose, and a rollback a one-line revert.

5 — Check what arrived. The download page lists each file with its SHA-256, and sha256sum -c SHA256SUMS checks them. Those sums prove the files arrived intact, not who published them; the container images the recipe pulls are signed with BROKA's image-signing key, and the download page shows how to check each against its published public half with cosign before you run it.

6 — Decide where TLS terminates. Not in the box: nginx inside the UI image listens on plain HTTP. Put a reverse proxy in front and terminate there, with one upstream — the UI image already proxies /api to the orchestrator, so do not route /api separately. The audit trail and the sign-in rate limit both work from the client's address, and behind a proxy only the proxy knows it. The console believes the proxy's X-Forwarded-For only from the peers in BROKA_TRUSTED_PROXIES. The default covers a proxy on the same host; a proxy on another machine goes in that variable by its address. Get this wrong and every user shares one address: one sign-in limit for everybody, and the proxy's IP in every audit entry. While you are there, put the address people will actually type — scheme, hostname and all — in BROKA_PUBLIC_URL. Nothing inside the stack can work it out, and it is what the Open in Broka link on an alert notification points at; left empty, notifications carry no link rather than a guessed one.

7 — Expect one replica. The orchestrator runs as a single replica by design: it is request-driven and applies its database migrations while it starts. Recovery is restart and continue, not a hot standby, and "highly available" is not a claim this stack makes. Compose starts the services in a fixed order — PostgreSQL, then the orchestrator, then the broker service and the console — each waiting for the one before it to report healthy, so the broker never starts against tables that do not exist yet.

The first start

docker compose up -d
docker compose logs -f orchestrator

When the orchestrator answers its health check, the migrations have run. Open http://localhost:3000 — or the address your proxy serves — and create the first administrator: until that is done every URL redirects to the setup screen, and afterwards it is never shown again. The same screen asks for the installation environment — what this installation of BROKA is, Production until you change it. It is not one of the environments your brokers are grouped into: every audit record the installation writes names it, so records from a production console and a staging one can be told apart. The console does not sign you in automatically; the password is used once before it is relied on.

The first-run screen, 'Create the admin account': full name, email, a password with the policy stated beneath it, 12 characters and all four kinds of character by default, the default timezone set to UTC and the installation environment set to Production, above a 'Create admin & continue' button and the footer 'Initial setup runs once per deployment · Broka v1.0.0'.
One account and two facts about the installation. Once an administrator exists, this screen sends you to sign-in instead.

A Commercial installation is activated next, in Settings ▸ Licence: paste the activation code from the portal, or, on a host with no internet access, generate a request, e-mail it to BROKA support and paste the licence that comes back. Until then Kafka works fully and the commercial platforms are not offered at all.

Then, in this order: create the environments — one, Development, open, already exists — and mark production guarded before it holds a connection. Guarded means every write there has to carry a reason, saving a connection included; a read-only environment refuses new and changed connections outright, so a connection has to be in place before its environment goes read-only. Switch to the environment you mean and add a connection there, because a connection is created in the environment selected in the top bar; and test it before saving — the test says whether the broker could be reached and signed in to, and a pass can carry a caveat naming what the credentials leave out.

The Edit environment sheet for Production: name, colour, the write policy set to 'Guarded — every write asks for a reason', noted as applying to every connection whatever the operator's permissions, the default classification Internal, and the Allow insecure TLS switch left off.
Set before the first connection lands: from then on every write in this environment carries a reason, and it is stored on the write's audit entry.

If it does not come up:

What you see What it means
docker compose up refuses, saying a variable is missing a value, and nothing starts That variable is empty in .env. The images fail closed on purpose.
The orchestrator refuses to start, saying a key is the wrong length BROKA_KEK must decode to exactly 32 bytes and BROKA_JWT_SECRET to at least 32. Regenerate; do not trim.
The console loads but every broker call fails The orchestrator and the broker service disagree about BROKA_SERVICE_TOKEN or BROKA_KEK.
A Redis, RabbitMQ, Apache Artemis or Memcached page fails with 404 NOT_FOUND — No handler for … That platform's module is not in the broker image you are running: you are running Community, which carries Kafka. The edition is decided by which images you pull.

After it is running

Back up two things. PostgreSQL is the only state — the pgdata volume holds users, connections, saved views, the audit trail and the encrypted key ring — and .env holds the key that reads it. Restore by bringing the database back with the same-version images. The real test of a restore is not that the console opens; it is that a stored broker credential still decrypts — run a connection test.

Decide how far back the audit trail has to reach. Retention always runs and keeps at most six months — 180 days, the default; Settings ▸ Security can shorten it, with a reason, but not switch it off. So the database, and every backup of it, holds half a year of trail at most. If your reviews look further back, forward the trail as it is written: to a file or an HTTP endpoint in either edition, through the orchestrator's AuditForwarding__* settings — the Compose recipe does not set them, so they are lines you add to its environment — or, in Commercial, to a Kafka or RabbitMQ connection already registered in BROKA, chosen in Settings ▸ Security. A record that was never forwarded is still deleted at 180 days; BROKA warns seven days before.

Settings › Security: Sign out after inactivity set to 1 hour; the Password policy at its defaults — a minimum length of 12, no expiry, and an uppercase letter, a lowercase letter, a digit and a symbol required; Read auditing on Privileged reads; Audit retention at 6 months; Audit forwarding to the Kafka connection kafka-core-eu and the topic broka.audit, with nothing waiting to be forwarded; and the Secret storage card with Rotate key-encryption key.
Retention, forwarding and the key rotation live on one page, behind the security permission. The Kafka and RabbitMQ destination is Commercial; a file or HTTP destination is set in the deployment instead.

Upgrade by editing, not by restarting. Each release publishes its recipe at https://broka.dev/download/<version>/; if its compose.yml differs from yours — compare the checksums in its SHA256SUMS — take the new file and add any variable its .env.example gained to your .env. Then change BROKA_VERSION, and docker compose pull && docker compose up -d. Migrations run automatically as the orchestrator starts, and they are backward-compatible, so skipping several versions is supported. Rolling the application back is the same edit in reverse — the previous tag, with the database staying where it is. Rolling the schema back is not supported; the way back from a bad migration is a restore.

Point monitoring at the probes the images carry. The console answers on /healthz; the orchestrator on /health for liveness and /health/ready with a database check; the broker service on /actuator/health, which reports the aggregate — so a sustained database outage can mark the broker container unhealthy while the process itself is fine. For a Prometheus you already run, BROKA_METRICS_PROMETHEUS=true serves the orchestrator's own metrics on port 9464 inside the Compose network — off by default, never published, because the endpoint carries no login.

Know the outbound posture. A Community installation makes no outbound calls of its own and needs no activation. A Commercial installation activated online makes one HTTPS call to activate and refreshes about once a day; activated offline, it makes no outbound calls either. In both editions the alert channels and the mail relay you configure send outward, from the broker service, and an HTTP audit-forwarding endpoint receives the trail from the orchestrator — each only once you have set it up.

What this checklist does not cover

  • Sizing. No figure is given here, because none has been measured. Size for concurrent operators, not for broker throughput.
  • Other architectures. The images are built for linux/amd64 only.
  • Clustering. One orchestrator replica is the design, not a limit waiting to be lifted in configuration.

Try it yourself

The installation recipe is the Compose file and environment template this checklist walks through.

Applies to BROKA 1.0 · Community and Commercial.