Once the base Matrix stack existed, the next step was obvious: stop leaving important secrets in static files and environment variables.

The target pattern was the same one I had already been building elsewhere:

  • Vault stores the secret values,
  • a Vault Agent fetches them,
  • templates render final runtime files,
  • and the app containers only read local files.

What Belonged In Vault

For the Matrix stack, the important secret material was not just one password.

It included:

  • the database password,
  • Synapse secret values,
  • the TURN shared secret,
  • and later additional auth-related or integration-related credentials.

At the same time, I had to be careful not to treat every file the same way.

Some material is safe to render repeatedly. Some material is part of the long-term identity of the server.

That distinction matters.

Static Files Versus Runtime Files

The cleaner model was:

  • keep static topology and template files in normal config,
  • let Vault render only the dynamic values at runtime.

That meant files like these became runtime outputs rather than source files:

  • the Matrix homeserver config with injected secret values,
  • TURN config with the shared secret,
  • small secret files used by app startup,
  • and other generated fragments needed by the containers.

Why The Agent Pattern Helped

The best part of this model is that the main app containers do not need to speak to Vault directly.

That gives me a narrower trust boundary:

  • the agent knows how to authenticate,
  • the app only knows how to read files,
  • and startup can wait for those files to exist.

This is much easier to operate than pushing sensitive values through ad hoc shell exports or stuffing them into every compose file.

What I Learned

The conceptual mistake would have been to think "Vault integration" means only "move passwords out of YAML."

The real gain is larger:

  • the rendered files become part of a controlled runtime path,
  • per-app access can stay small,
  • and the Unix-user split now matches the secret-access split.

That is when the Matrix stack started fitting into the rest of my platform instead of being a special case.