Docker Configuration
Purpose and Scope
Docker configuration for Cal.diy is centered on a simple self-hosting workflow: copy the example environment file, adjust the values that describe your deployment, and then start the desired Docker Compose services. The Docker documentation treats most values as safe to leave unchanged for a first run, but it calls out several variables that affect image construction, authentication, public URL behavior, and optional integrations. This page explains those configuration layers so a self-hoster can decide which values must be set before the first boot, which values only matter when building a custom image, and which values belong to app integrations after the core instance is working.
Sources: apps/docs/content/docker.mdx
The Docker page sits in the getting-started documentation spine, alongside installation, database migrations, upgrading, and app setup. That placement matters because Docker configuration is not an isolated concern: it determines how the web application talks to a database, how the first setup wizard is reached, how authentication callbacks are resolved, and how later integration credentials are consumed. The apps documentation then extends the same environment-file pattern for providers such as Google Calendar, Daily video, and HubSpot, so the recommended path is to stabilize the base container configuration first and add integration secrets afterward.
Sources: apps/docs/content/_meta.ts, apps/docs/content/apps/_meta.ts, apps/docs/content/apps/daily.mdx, apps/docs/content/apps/google.mdx, apps/docs/content/apps/hubspot.mdx
Relevant Source Files
- apps/docs/content/docker.mdx — Primary Docker guide covering image location, Docker Compose startup modes, build-time variables, runtime variables, advanced build guidance, updates, and Docker-specific troubleshooting.
- apps/docs/content/_meta.ts — Places Docker in the getting-started documentation navigation with installation, database migrations, and upgrading.
- apps/docs/content/apps/_meta.ts — Shows the documented app integration categories that commonly add environment variables after the base Docker instance is running.
- apps/docs/content/apps/daily.mdx — Documents Daily environment variables, including the required API key and optional scale-plan flag.
- apps/docs/content/apps/google.mdx — Documents Google Calendar OAuth redirect paths and the environment keys used for Google credentials and login behavior.
- apps/docs/content/apps/hubspot.mdx — Documents HubSpot client credentials, redirect URL, and required CRM contact scopes.
Configuration Model
The documented Docker model starts with a repository checkout and a local environment file. The guide instructs operators to clone the Cal.diy repository, change into it, copy the example environment file, and update the copy before starting services. That flow is important because the environment file is used both as a convenient input for Compose startup and as the place where a self-hoster records deployment-specific secrets. In practice, you should treat this file as the control plane for one instance: it should describe the database, public web address, authentication secret, and any app credentials enabled for that deployment.
Sources: apps/docs/content/docker.mdx
The official startup commands describe three useful service shapes. The complete stack starts a local Postgres database, the Cal.diy web app, and Prisma Studio, which is the most straightforward first-run path because it keeps the database dependency inside the same Compose environment. A second shape runs the web app and Prisma Studio against a remote database, which is useful when a managed database already exists but database inspection is still desired. A third shape runs only the web app, also against a configured remote database, which is closer to a lean production-style deployment where database administration is handled elsewhere.
Sources: apps/docs/content/docker.mdx
git clone https://github.com/calcom/cal.diy.git
cd cal.diy
cp .env.example .env
docker compose pull
docker compose up -dFor the first launch, the documented user experience is to open the configured web address in a browser and complete the setup wizard. The guide names the local address as the default and also points to the value configured as the public web application URL. That means URL configuration is not cosmetic; it affects the first visible route an operator uses, and later it can affect callback behavior for authentication and integrations. Before exposing a containerized instance to other users, verify that the URL in the environment matches the address real browsers and external OAuth providers will use.
Sources: apps/docs/content/docker.mdx
Build-Time Variables
Build-time variables are values that the Docker documentation says must be provided when the image is built. The listed build-time variables are telemetry key, license consent, and public web application URL. The page also says changing these variables is not required for evaluation, but may be required for production, and currently requires building and publishing your own image. That distinction is easy to miss: if you only pull the published Docker image, changing a build-time value in an environment file may not have the same effect as rebuilding the image with that value present during the build phase.
Sources: apps/docs/content/docker.mdx
| Variable | Documented role | Configuration timing |
|---|---|---|
| NEXT_PUBLIC_TELEMETRY_KEY | Public telemetry configuration | Build time |
| NEXT_PUBLIC_LICENSE_CONSENT | Public license-consent configuration | Build time |
| NEXT_PUBLIC_WEBAPP_URL | Public web application URL embedded into the app | Build time |
The practical decision is whether the stock image is sufficient. For evaluation, the docs suggest leaving most configuration as-is. For a deployment where the externally visible URL, telemetry posture, or consent behavior must be baked into the client application, follow the advanced-user path and build a custom image from the repository’s Docker configuration. Because these variables are public client-side values, they are different from private secrets: they shape browser-visible behavior rather than simply granting server-side access. Still, they should be reviewed deliberately because an incorrect public URL can surface later as broken redirects or callback mismatches.
Sources: apps/docs/content/docker.mdx
Runtime Variables and Secrets
Runtime variables are supplied when the container starts, and the Docker page explicitly calls out the authentication secret as an important runtime variable. This secret is part of the security boundary for the running web application, so it should be unique per deployment and treated as sensitive operational configuration. Unlike build-time public values, a runtime secret belongs in the environment of the service that is executing. When rotating or correcting it, plan for a restart of the affected container so the application process reads the new value, and consider the user-session impact of changing authentication-related material.
Sources: apps/docs/content/docker.mdx
| Variable | Documented importance | Operator guidance |
|---|---|---|
| NEXTAUTH_SECRET | Important runtime variable | Set before exposing the instance and keep it private |
| DATABASE_URL | Required when using a remote database startup mode | Point it at an available database before starting the selected services |
| NODE_TLS_REJECT_UNAUTHORIZED | Troubleshooting option for trusted SSL edge termination scenarios | Use only when you understand and trust the load balancer or service path |
The Docker guide also describes remote database operation by requiring the database URL to be configured for an available database before starting selected services. That requirement applies whether you run the web app with Prisma Studio or run only the web app. The difference is operational rather than semantic: Prisma Studio is helpful for inspection and administration, while the web app itself needs the same database connectivity to serve scheduling flows. If the database URL is wrong, the container may start but fail during application initialization, migrations, onboarding, or user-facing requests that depend on persisted state.
Sources: apps/docs/content/docker.mdx
App Integration Environment Variables
After the base Docker instance is reachable, app integrations add their own environment requirements. The Daily guide asks the operator to copy an API key into the environment file and optionally set a scale-plan flag when using features such as video recording. This follows the same pattern as the core Docker setup: credentials are collected from an external provider, stored in the deployment environment, and then consumed by the Cal.diy application. Keep optional flags separate from required credentials during review so a missing enhancement setting is not confused with a broken integration secret.
Sources: apps/docs/content/apps/daily.mdx
Google Calendar configuration is more involved because it combines external API enablement, OAuth consent configuration, redirect URIs, and local environment values. The Google guide documents two redirect paths: one for the calendar integration callback and one for Google authentication callback. It then instructs operators to paste the downloaded OAuth client JSON into both the main environment file and the app-store environment file under the Google credentials key, and to set the login-enabled flag to false when configuring the integration as internal. For Docker operators, the key lesson is that the public Cal.diy URL used in provider consoles must match the deployed web address.
Sources: apps/docs/content/apps/google.mdx
HubSpot follows the same external-provider pattern but with a smaller credential set. The HubSpot guide tells operators to create a developer app, copy the client identifier and secret into the environment file, configure an OAuth redirect path under the Cal.diy URL, and select read and write access for contact objects. This makes HubSpot a useful example for reviewing Docker configuration boundaries: the container needs the secrets at runtime, the provider needs a callback URL that resolves back to the containerized web app, and the selected scopes define what the integration is allowed to do after authorization.
Sources: apps/docs/content/apps/hubspot.mdx
Advanced Build and Configuration Flow
Advanced Docker users are directed to the repository’s Dockerfile and Docker Compose file for detailed build and configuration work. The docs also state that the Docker setup is officially maintained in the main Cal.diy repository and that contributions to it should be made through issues or pull requests there. The safest advanced workflow is therefore incremental: first confirm that the published image and basic Compose startup work with a minimal environment, then introduce remote database configuration, then add a custom image build only when build-time values must change, and finally layer app-provider secrets onto the already healthy deployment.
Sources: apps/docs/content/docker.mdx
# Complete stack for first run
docker compose up -d
# Web app and Prisma Studio with a remote database
docker compose up -d calcom studio
# Web app only with a remote database
docker compose up -d calcomUpdates reuse the same configuration file but refresh the container image. The documented update sequence stops the stack, pulls the latest images, restarts the stack, and then updates environment variables as necessary. Treat that last step as a release-review checkpoint rather than an afterthought. If a new image expects a different public URL setting, secret, database connection behavior, or integration variable, carrying forward an old environment unchanged can produce failures that look like application bugs. Keep a small deployment note with the current image tag, environment changes, and enabled integrations so upgrades remain reproducible.
Sources: apps/docs/content/docker.mdx
Troubleshooting Signals
The Docker page includes two configuration-related troubleshooting signals. One concerns first-user creation through Prisma when metadata is empty; the suggested remedy is to use an empty JSON object for the metadata value, and the id field can usually be left empty because it autoincrements. The other concerns SSL edge termination behind a load balancer. In that case, the docs mention adding an environment variable that disables TLS rejection, but they also warn to do this only when the operator understands and trusts the services directing traffic. That warning should be taken seriously because it changes request validation behavior.
Sources: apps/docs/content/docker.mdx
The page also introduces a client fetch error scenario where the default authentication callback uses the web application URL as a base address and the container may not have access to the same DNS view as the browser. This is a configuration mismatch rather than a generic frontend failure. When investigating it, compare the public URL, the address reachable from inside the container network, the reverse proxy name, and the OAuth callback addresses registered with external providers. If those names differ, decide whether to adjust DNS, Compose networking, reverse proxy configuration, or the environment value that defines the application URL.
Sources: apps/docs/content/docker.mdx
Next Steps
Start with the Docker overview if you have not yet chosen between the complete local stack and a remote-database shape. Then review environment and URL guidance before registering OAuth redirect paths with Google, HubSpot, or other providers. If you need to change build-time public values, move next to the advanced build workflow and maintain your own image. If the instance is already running and you are preparing a version change, read the Docker updates and troubleshooting guidance so image pulls, restarts, and environment changes are handled together rather than as separate operational guesses.