How to Self-Host Plausible Analytics With Docker Compose
Plausible Community Edition (CE) is the self-hosted version of Plausible, a web analytics service. Docker Compose uses a configuration file to run…
Each Docker Compose service on a host you control needs settings such as ports and image tags. Some services also need credentials, such as database passwords or API tokens. A credential is a secret because someone who obtains it may gain access to another service or its data.
For most single-host setups, keep ordinary settings in a .env file and give credentials to services as Compose secret files. A .env file is plain text, while Compose secrets limit which services receive a mounted secret. A dedicated secrets manager centralizes access controls and adds features such as audit logs and credential rotation. You must also secure and maintain the manager.
Choose based on which credentials you need to protect and whether you can maintain another service. None of these options protects a secret from an administrator or attacker who already controls the host, or from a service that is authorized to read it.
.env files for configuration, not as a vaultDocker Compose reads a project .env file to substitute values into the Compose configuration. Compose calls this substitution interpolation. A value in .env does not automatically appear inside a container; the Compose file must pass it in, for example through environment or a service-level env_file entry. The Compose interpolation documentation explains how the file and shell environment supply those values.
Use .env for settings such as an image tag or a development-mode flag. If you temporarily store credentials there, treat the file as a plaintext credential store. Keep it out of version control. Restrict access to the file, and protect copies in host backups. Avoid printing resolved Compose configuration to shared terminals or logs. The docker compose config --environment command displays values Compose uses for interpolation, including sensitive ones.
A secret passed through environment becomes an environment variable inside the container. Docker warns that environment variables can be exposed through processes or diagnostic output, so prefer a file-based method when the application supports one. Keep credentials out of Dockerfile ARG and ENV instructions; those instructions can leave values in image data or metadata. If a credential is committed, deleting the file from the latest version does not remove it from Git history; GitHub’s guidance on secret leakage says to revoke and replace the exposed credential.
Compose interpolation is a Docker Compose CLI feature. Do not assume the same .env behavior applies to Swarm’s docker stack deploy.
A Compose secret is a value that Compose makes available to an authorized service as a file, typically under /run/secrets/. You declare the secret and grant it to each service that needs it. For example, a file-backed secret can be configured like this:
services:
app:
image: example/app
secrets:
- db_password
secrets:
db_password:
file: ./secrets/db_password
The application must read /run/secrets/db_password. Some container images also support a convention such as a _FILE environment variable that points to the secret file. Whether _FILE works depends on the image; Compose does not make every application understand it automatically. Docker’s Compose secrets instructions describe the service-level grants and file delivery.
This approach narrows which containers receive each secret and avoids passing the value itself through a container environment variable. It does not remove the host-side source file: with the file: source shown above, Compose reads a file on the host and mounts it into the container. Protect that file and its backups. The Compose documentation does not promise that a local file-backed secret is encrypted at rest or automatically rotated.
Review Compose files before running unfamiliar projects. Compose can read host files, and its trust model documentation advises treating a Compose project as code that can affect the host. Docker also documents platform limits: Compose secrets support Linux containers, with a limitation for Windows containers.
If a Docker image build needs credentials, use BuildKit secret mounts to make them available during the build step. Docker warns against putting build secrets in ARG or ENV, which can persist in image data or metadata. A build secret does not replace a runtime secret mounted for a running service.
A secrets manager stores credentials behind access rules and gives services or operators a controlled way to retrieve them. Depending on the product and setup, it can support audit logs, rotation, and dynamic secrets: credentials generated for a consumer or session rather than shared as long-lived passwords. OWASP recommends limiting access and tracking secret creation, use, rotation, revocation, and expiration in its Secrets Management Cheat Sheet.
A manager does not connect itself to a Compose service. The service must retrieve and use the credential, either by requesting it directly or by reading a file written by an agent. Choose an integration that fits the application and its identity mechanism; a normal Compose file: secret declaration still reads a host file.
To rotate a credential without interrupting access, the service that issues it must accept the new value, the consuming service must receive it, and the old credential must be invalidated. A dynamic credential has a lease, meaning a defined period before it expires; the consumer must handle renewal or replacement. These features only work when the backing service and the application support the required lifecycle.
When you self-host a manager, you must secure and maintain it. For example, HashiCorp Vault’s production guidance calls for TLS, restricted network access, and protection of its storage. Vault also starts sealed, so operators must configure how it becomes available after startup. Vault’s audit devices are disabled by default; when enabled, Vault refuses a request if it cannot write that request to any enabled audit device. That behavior makes audit storage and availability part of the manager’s operation. See Vault’s guidance on production hardening, sealing and unsealing, and audit devices.
Before adopting a self-hosted manager, decide how services will authenticate to it, how you will back it up and recover it, how you will start it securely, and what services will do when it is unavailable. If you cannot maintain those parts, centralization may add a dependency without giving you the lifecycle controls you intended to use.
For a single host, use .env for non-sensitive settings and Compose secret files for credentials when the application can read them. Keep each secret’s access limited to the services that need it, and protect the host files that supply those secrets.
Consider a secrets manager if several services or hosts need shared credential control. Consider one if you need audit records or if your infrastructure supports short-lived credentials and coordinated rotation. A manager gives you access controls and features for managing credentials over time. You must manage its security and availability. You must also manage its storage and recovery.
Give Vroni a GitHub issue, bug report, spec, or rough idea. It reads the repo, plans the change, writes code, runs checks, and works toward a review-ready pull request.
Take a look at vroni.com