Cal.com is an open source scheduling tool built to be self-hosted, and running it yourself avoids the per-seat pricing of the hosted version once a team grows past a couple of people. This walks through deploying Cal.com’s official Docker image on Ownkube with Postgres, the auth secrets it requires, and a stable HTTPS address.
TL;DR
- Cal.com needs Postgres as its primary datastore. There is no SQLite option, so provision a managed database before deploying the app.
- Deploy the official Cal.com image, set
DATABASE_URL,NEXTAUTH_SECRET, andCALENDSO_ENCRYPTION_KEY, and give it the app’s public address viaNEXT_PUBLIC_WEBAPP_URLbefore creating any bookings. NEXTAUTH_SECRETandCALENDSO_ENCRYPTION_KEYshould be generated once and treated as permanent. Rotating them invalidates sessions and encrypted calendar credentials.- Every Ownkube app gets an
ownkube.appaddress with automatic TLS, which Cal.com’s calendar OAuth flows (Google, Outlook) require to complete correctly. - A Postgres database box starts at $4/month plus storage, and the app runs comfortably on a small reserved box given its steady traffic pattern.
What you need before you start
- The image reference
calcom/cal.com:latest, or a pinned release tag for reproducible deploys. - A subdomain for the app on
ownkube.app, for examplecal-yourteam.ownkube.app. Calendar OAuth (Google, Microsoft) redirects back to this URL and needs HTTPS to complete, so pick it before you connect any calendar. - Two secrets generated ahead of time: a
NEXTAUTH_SECRETand aCALENDSO_ENCRYPTION_KEY, both random strings you generate once and keep.
# Generate both secrets locally before you deployopenssl rand -base64 32 # NEXTAUTH_SECRETopenssl rand -base64 32 # CALENDSO_ENCRYPTION_KEY1. Create a managed Postgres database
Cal.com’s Prisma schema targets Postgres specifically; there is no supported SQLite path. Create a database box on Ownkube (from $4/month plus storage at $0.25/GB/month) and note the connection details.
Cal.com expects a single connection string rather than split host and port variables, so assemble it in the standard Postgres URL format:
postgresql://<user>:<password>@<host>:5432/<database>?schema=public2. Deploy the Cal.com image
Create the app from the official image:
FROM calcom/cal.com:v4.6.6Pinning a version tag rather than latest is worth doing here, since Cal.com ships frequently and a pinned tag keeps a database migration from running unexpectedly on a redeploy. The image listens on port 3000 by default.
3. Set the environment variables
# DatabaseDATABASE_URL=postgresql://<user>:<password>@<host>:5432/<database>?schema=public
# Auth and encryption (generate once, keep permanently)NEXTAUTH_SECRET=<generated-secret>CALENDSO_ENCRYPTION_KEY=<generated-key>
# App URLNEXT_PUBLIC_WEBAPP_URL=https://cal-yourteam.ownkube.appNEXTAUTH_URL=https://cal-yourteam.ownkube.app
# Email (optional but needed for booking confirmations and invites)EMAIL_FROM=notifications@example.comEMAIL_SERVER_HOST=smtp.example.comEMAIL_SERVER_PORT=587EMAIL_SERVER_USER=<smtp-user>EMAIL_SERVER_PASSWORD=<smtp-password>Set NEXT_PUBLIC_WEBAPP_URL and NEXTAUTH_URL to the app’s public address before you connect any calendars. Calendar OAuth providers validate the redirect URL against what the app reports, and a mismatch after the fact means reconnecting every calendar integration rather than a quick edit.
4. Run the database migration
Cal.com’s Prisma schema needs its migrations applied on first boot (and after upgrades that include schema changes). The official image runs this automatically on startup in most versions, but if you deploy from a custom build, run it explicitly as a one-off command against the app:
npx prisma migrate deploy5. Check HTTPS and connect a calendar
The app’s ownkube.app address serves HTTPS from the first deploy, with no DNS to set up. That matters here: Cal.com’s Google and Microsoft calendar OAuth flows both refuse to complete a redirect back to a plain HTTP URL.
curl -I https://cal-yourteam.ownkube.appLog in, create your first event type, and connect a calendar from Settings to confirm the OAuth round trip works end to end.
Sizing the deployment
Cal.com is a Next.js app with a fairly steady request pattern once a team is booking through it regularly (page loads, availability checks, webhook callbacks from calendar providers), which makes a flat Spark box (from $5/month) a reasonable default, since the price stays the same however busy the week gets. A personal scheduling page with light traffic is fine on metered pricing instead, billed per minute.
If self-hosted scheduling eventually needs to move onto infrastructure your company controls directly, the same Cal.com image and environment variables run unchanged in your own AWS account under Ownkube’s own-cloud option, with the same database migration path and the same logs and metrics attached. That is a redeploy target, not a rewrite. For a wider look at how self-hosted platforms compare on cost and control, see our comparison of Railway, Render, and Northflank.
FAQ
Does Cal.com support SQLite for a small deployment?
No. Cal.com’s schema is built for Postgres and there is no supported SQLite backend. A managed Postgres database box is required even for a single-user instance.
What happens if I rotate CALENDSO_ENCRYPTION_KEY?
Rotating it breaks decryption of previously stored calendar credentials and tokens, forcing every connected calendar to be reconnected. Generate it once before first deploy and keep it out of version control but permanently saved somewhere safe.
Do I need to run database migrations manually?
The official image typically applies Prisma migrations automatically on boot. If you build a custom image or skip that step, run npx prisma migrate deploy against the app once before serving traffic.
Why does calendar sync fail after I change the app’s address?
Google and Microsoft OAuth validate the redirect URL against what’s registered for the app. Changing NEXTAUTH_URL or NEXT_PUBLIC_WEBAPP_URL after connecting calendars means reconnecting each one so the provider accepts the new redirect.
What does this cost to run?
A Postgres database box starts at $4/month plus storage. The app itself fits well on a Spark box from $5/month, or metered pricing for lighter, more occasional use.
Where Ownkube fits
Cal.com needs Postgres, two permanent secrets, and a stable HTTPS address to work correctly with calendar providers, and Ownkube Compute gives you all three without provisioning a cloud account first. Deploy the image, attach managed Postgres, and set the auth keys once. See Ownkube pricing for the per-minute wallet model, from $5 a month. Deploy your first app.
Abhishek Jaiswal · Founder and Engineer
Abhishek Jaiswal is the founder and engineer behind Ownkube, a cloud for personal software. He builds the platform and writes here about cloud cost, migrations, and running production infrastructure in your own AWS account without a DevOps team.