Logs, privacy and security¶
Who this is for: hosters (sysadmins).
This page is for the admin: where the logs are, what they contain, and how to keep transcripts, audio and tokens private. It also states the trust assumptions the stack is built on, so you can decide when you have outgrown them. Terms such as origin and service access token are defined in the Glossary. Both supported ways to run the stack are covered: Docker Compose and Co-op Cloud.
Where the logs are¶
Under Docker Compose the services run as containers, so their output goes to the container log for the whole stack:
docker compose --env-file .env.production \
-f docker-compose.yml -f docker-compose.prod.yml logs -f
Add --tail=100 to start from the last 100 lines instead of following live.
On Co-op Cloud, read the same logs through abra app <domain> logs; the
caption-ninja recipe documents the exact form.
/health is the quickest live view: it reports the model, the actual device,
readiness, worker count, running and queued requests, and failures.
What is logged¶
By default the speech service logs only startup and diagnostic lines. Request
metadata is off until you ask for it. Turn it on with CAPTION_LOG_REQUESTS=1,
after which it emits one JSON line per request.
That request metadata is deliberately narrow. It contains:
- the fixed route template, the HTTP method, the status, and the duration.
It excludes query strings, tokens, stream and request IDs, IP addresses, filenames, audio, and transcript text. Logging helps diagnose delay; it is not a recording of transcripts and not a complete authentication audit trail.
Audio buffers and the bounded retry cache live in process memory. Logs hold operational messages and errors, not transcripts or audio. Let the container runtime handle rotation and retention rather than letting logs grow without bound; on Co-op Cloud the recipe's logging settings apply.
Tip
Leave request logging off unless you are diagnosing a problem. You keep less on disk, and you keep fewer request fingerprints around.
Keeping transcripts and audio private¶
- Transcripts are saved only when someone downloads them. Nothing is persisted automatically.
- Audio and pending retry results stay in memory. If the process or the browser crashes, pending work is lost — that is a resilience limit, not a privacy one.
- Closing the capture tab discards unsaved text and pending audio.
- Sharing sends the caption text through the relay you configure. There is no built-in relay and no end-to-end encryption, so anything in transit is visible to the relay you run.
- The capture page keeps the service access token in tab memory only. It is cleared on reload and never forwarded to the caption relay.
Token handling and rotation¶
There are two kinds of secret in this stack, and they are separate:
- The service access token (
CAPTION_API_KEY) gates the speech service's API. It is a shared bearer token for trusted producers, not an OpenAI, Google or Gemini key. - Room tokens gate relay rooms. Each room has separate read and write tokens.
Handle them like passwords:
- Keep the service access token in
secrets/caption-local.env; use a random value of at least 24 ASCII characters with no whitespace. - Keep tokens out of Git, out of committed Compose or recipe files, and out of any image. Restrict file permissions on whatever holds them.
- The capture page asks for the service access token and holds it in tab memory;
API clients send
Authorization: Bearer <token>. - To rotate the service access token, recreate the service with a new value. Save pending captions first: a restart drops in-memory retry caches.
- Give the audience overlay only a read room token. Hand out write tokens privately, and rotate the records if a link was shared widely.
- Public relay room names act as access secrets; the private relay uses distinct viewing and publishing tokens. Neither replaces encrypted transport.
Do not expose the speech service¶
The speech service binds to loopback, and Docker publishes only a loopback port.
That is the intended access model. Never publish the raw caption-local port or
bind it to 0.0.0.0.
Public traffic should reach the stack only through the TLS router described in Deploy with Docker Compose; on Co-op Cloud the recipe places the app behind the platform's TLS reverse proxy. Keep Host and Origin checks in place and do not bypass them to reach the service directly from a browser.
Host and Origin checks and bounded audio requests reduce accidental exposure, but they are not user authentication or tenant authorization. Stream IDs are not credentials.
The trust model, in plain terms¶
The speech service is designed for a local computer or for trusted producers on a private network. The optional service access token extends that to a small group of trusted producers; it does not add per-user authorization, tenant isolation or encryption.
If you need individual accounts, per-user quotas, tenant separation or public internet hosting, this is a different deployment: a separate authenticated gateway and identity/transport design is required. Do not disable the Host or Origin checks, and do not publish the raw port, as a shortcut around that.
For an actual event, test with short recordings and never reuse real event rooms or tokens in tests.
Reporting a problem¶
Security fixes target the latest published release. If you believe you have
found a vulnerability, use the project's private reporting channel rather than a
public issue, and never post credentials, private recordings or an unpatched
exploit. When reporting an operational bug, include your OS, release, install
method, model and settings, and sanitised /health output and logs — never
credentials, private room names or confidential transcripts.