Skip to content

fix(self-host): remove public default secrets and refuse to start on placeholders - #3002

Open
07rjain wants to merge 2 commits into
CapSoftware:mainfrom
07rjain:split/self-host-secret-checks
Open

07rjain wants to merge 2 commits into
CapSoftware:mainfrom
07rjain:split/self-host-secret-checks

Conversation

@07rjain

@07rjain 07rjain commented Oct 23, 2026 •

Copy link
Copy Markdown

Split out of #2580 (self-host secret checks).

Problem. docker-compose.yml, docker-compose.template.yml and older docs shipped fixed NEXTAUTH_SECRET, DATABASE_ENCRYPTION_KEY and MEDIA_SERVER_WEBHOOK_SECRET values. They are public in this repo, so anyone could forge sessions, decrypt stored credentials or spoof media-server webhooks on installs that kept them.

What changes

  • Compose files require the three secrets from .env (${VAR:?…}). New .env.self-hosting.example.
  • packages/env/secrets.ts lists the known placeholders. In production, cap-web exits at startup when a secret is missing or still a placeholder. This runs after main's serverEnv() / DATABASE_ENCRYPTION_KEY format validation, and both checks are kept.
  • The media server refuses to start when MEDIA_SERVER_WEBHOOK_SECRET is missing or a placeholder. MEDIA_SERVER_ALLOW_INSECURE_SECRET=true is for packages/local-docker only.
  • Docs: new "Upgrading From an Older Release" section and an updated production checklist.

⚠️ Upgrade warning / release note
Existing self-hosted installs that still use the example secrets from the old compose files will not start after upgrading. docker compose up stops and names the missing variable. Otherwise cap-web logs Refusing to start: insecure secrets and the media server logs [media-server] Refusing to start.
Before pulling the new images: back up MySQL, then set NEXTAUTH_SECRET, DATABASE_ENCRYPTION_KEY and MEDIA_SERVER_WEBHOOK_SECRET in .env (each from openssl rand -hex 32). Use the same MEDIA_SERVER_WEBHOOK_SECRET on cap-web and the media server.

  • New NEXTAUTH_SECRET: everyone signs in again.
  • New DATABASE_ENCRYPTION_KEY: data encrypted with the old key can't be read. That covers custom S3 storage settings, developer app keys and connected integrations, so re-enter storage settings and regenerate developer keys.
  • Installs that already set their own values are unaffected.

Tests. insecure-secrets.test.ts, startup-checks.test.ts, existing database-encryption-key-env.test.ts.

RetriggerView in GreptileConfidence Score: 5/5

The latest changes appear safe to merge; the existing upgrade-documentation finding remains non-blocking.

Findings

  1. P2 Template upgrade steps miss secrets ▶
Fix with agent prompt
### Issue 1
apps/web/content/docs/self-hosting.mdx:211-212
The older `docker-compose.template.yml` sets secrets directly, so adding new values to `.env` does not replace them. `docker compose pull` only updates images; users following these steps still pass the public secrets to the new web image, which refuses to start. Tell template users to update their compose file or replace its hardcoded values before restarting.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

Removes public default secrets and adds startup checks for self-hosted deployments.

  • Self-hosted Compose now waits for three operator-set secrets before starting Cap.
  • Cap-web now checks self-host secrets before scheduling startup work.
  • The media server now checks its webhook secret before it starts listening.

Reviews (2) · Last reviewed commit: "fix(self-host): quote required-secret en..." · Reviewed by Greptile

…h missing or placeholder secrets

The compose files shipped fixed NEXTAUTH_SECRET, DATABASE_ENCRYPTION_KEY and MEDIA_SERVER_WEBHOOK_SECRET values that are public in this repo. They now require values from .env, and cap-web (in production) and the media server refuse to start when a secret is missing or still one of those known placeholders. The self-hosting docs explain the upgrade step and what replacing each secret changes.
@vercel

vercel Bot commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

@07rjain is attempting to deploy a commit to the Cap Software Inc Team on Vercel.

A member of the Team first needs to authorize it.

Comment thread docker-compose.yml Outdated
Comment on lines +17 to +19
DATABASE_ENCRYPTION_KEY: ${DATABASE_ENCRYPTION_KEY:?Set DATABASE_ENCRYPTION_KEY in .env (run: openssl rand -hex 32)}
NEXTAUTH_SECRET: ${NEXTAUTH_SECRET:?Set NEXTAUTH_SECRET in .env (run: openssl rand -hex 32)}
MEDIA_SERVER_WEBHOOK_SECRET: ${MEDIA_SERVER_WEBHOOK_SECRET:?Set MEDIA_SERVER_WEBHOOK_SECRET in .env (run: openssl rand -hex 32)}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Compose files cannot load

The unquoted secret values contain : in (run: openssl rand -hex 32), which breaks YAML syntax. Docker Compose cannot read either compose file, even when all three secrets are set. Quote the entire ${...} value at every changed secret entry in both docker-compose.yml and docker-compose.template.yml.

Prompt To Fix With AI
This is a comment left during a code review.
Path: docker-compose.yml
Line: 17-19

Comment:
**Compose files cannot load**

The unquoted secret values contain `: ` in `(run: openssl rand -hex 32)`, which breaks YAML syntax. Docker Compose cannot read either compose file, even when all three secrets are set. Quote the entire `${...}` value at every changed secret entry in both `docker-compose.yml` and `docker-compose.template.yml`.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Comment on lines +211 to +212
2. Generate a new value for each secret with `openssl rand -hex 32` and put them in the `.env` next to your compose file (or in your platform's variables). Use the same `MEDIA_SERVER_WEBHOOK_SECRET` on cap-web and the media server.
3. Pull and restart: `docker compose pull && docker compose up -d`.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Template upgrade steps miss secrets

The older docker-compose.template.yml sets secrets directly, so adding new values to .env does not replace them. docker compose pull only updates images; users following these steps still pass the public secrets to the new web image, which refuses to start. Tell template users to update their compose file or replace its hardcoded values before restarting.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/web/content/docs/self-hosting.mdx
Line: 211-212

Comment:
**Template upgrade steps miss secrets**

The older `docker-compose.template.yml` sets secrets directly, so adding new values to `.env` does not replace them. `docker compose pull` only updates images; users following these steps still pass the public secrets to the new web image, which refuses to start. Tell template users to update their compose file or replace its hardcoded values before restarting.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

The `${VAR:?... (run: openssl rand -hex 32)}` values contain ': ', which YAML reads as a nested mapping, so docker compose rejected docker-compose.yml and docker-compose.template.yml before interpolation. Quoting keeps the friendly missing-secret message.
@richiemcilroy

Copy link
Copy Markdown
Member

Thanks @07rjain for splitting this out and for the detailed upgrade section, that's exactly what we were hoping for. Quoting the values in eae90b6 fixes Greptile's P1: both compose files parse now, and docker compose config shows the "Set ... in .env" message when a secret is missing. A few things are still open:

  1. Upgrade steps don't update the compose files or the media server (Greptile P2, apps/web/content/docs/self-hosting.mdx:208-212). Valid, and it goes a bit further. Anyone using an older docker-compose.template.yml copy has the secrets hardcoded, so adding them to .env changes nothing. On top of that, docker-compose.yml and the template build the media server from source (build:), so docker compose pull doesn't update it either. Please make step 3 something like git pull, then docker compose pull && docker compose up -d --build, and add a line telling template users to replace the three hardcoded values in their copy (or switch to the new template) before restarting.
  2. No way to keep data encrypted with the old key (apps/web/instrumentation.node.ts:31-42). The media server has MEDIA_SERVER_ALLOW_INSECURE_SECRET, but cap-web has no override. An install that has been running on the old default DATABASE_ENCRYPTION_KEY has to rotate it as part of the upgrade and loses its S3 storage settings, developer app keys and integrations, as the docs say. Could you give cap-web an explicit opt-in override too (for example CAP_ALLOW_INSECURE_SECRETS=true, with a loud warning logged on every start) so people can upgrade first and rotate when they are ready, and document it in the upgrade section as a temporary measure? A small re-encryption script that takes the old and new keys would be even better, but the override is enough for this PR.
  3. Quick starts still say one command (README.md:83, self-hosting.mdx:14-22 and step 2 at line 55). With the defaults gone, docker compose up -d on a fresh clone now fails until .env exists, but both quick starts still show it as the only step followed by "That's it!". Please move the cp .env.self-hosting.example .env and secret generation steps into the Quick Start code block itself and into the README.
  4. Coolify isn't affected (self-hosting.mdx:199). docker-compose.coolify.yml uses ${SERVICE_HEX_32_*}, which Coolify generates per deployment, so Coolify installs never had fixed example secrets. Please drop Coolify from that sentence, or say Coolify users don't need to do anything.
  5. The branch is about 155 commits behind main. Please merge main so CI runs against current code.

We need Greptile at 5/5 on the latest commit and green CI before we can merge. After pushing, you can mention @greptileai in a comment to get a re-review. Thanks!

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants