Host Your Own AI Agent with OpenClaw - Free 1-Click Setup!

How to Self-Host cal.com with Docker and PostgreSQL

Calendly charges per seat, per month, forever. cal.com is the open-source alternative that runs on your own server with no per-user pricing — booking pages, team scheduling, round-robin assignment, calendar sync, and webhook automation, all yours for the cost of a VPS.

This guide covers self-hosting cal.com with Docker and PostgreSQL. The .env variable names are verified against the current cal.com GitHub repository as of May 2026, but cal.com adds new variables regularly — always cross-reference the current .env.example in the repo before your first run. Cal.diy, the community fork, follows the same installation process.

What cal.com Does and Who Should Self-Host It

cal.com is an open-source scheduling platform — the infrastructure behind booking pages, availability rules, round-robin routing, team collective scheduling, and calendar sync with Google, Outlook, and iCal. The feature set is comparable to Calendly. The pricing difference is stark: Calendly’s Teams plan runs $16–20 per user per month. Self-hosted cal.com costs whatever your server costs.

Three situations where self-hosting makes obvious sense: GDPR or data residency requirements mean you cannot send booking data through a third-party SaaS. You have hit Calendly’s per-seat ceiling at team scale. You want API-level control for custom integrations.

If you just want a booking link up in five minutes with zero server to manage, cal.com’s hosted free tier is the simpler path. This guide is for teams that have already decided self-hosting is the right call.

Server and Software Requirements

cal.com is a Next.js application backed by PostgreSQL. The footprint is reasonable.

Minimum: 2 vCPU, 4 GB RAM, 20 GB disk. This covers individual use and small teams with a single cal.com instance and its Postgres database.

Recommended for co-located services: 4 vCPU, 8 GB RAM. If you plan to run cal.com alongside n8n or other tools on the same server, 8 GB gives each service enough headroom.

Software: Docker and Docker Compose (the plugin version — ‘docker compose’ without the hyphen), a domain with DNS access, and SMTP credentials for booking email notifications. Ubuntu 22.04 or 24.04 is the recommended OS.

Step 1 — Clone the Repo and Configure Your Environment

The Docker configuration is maintained in the main cal.com monorepo — clone it and copy the environment template:

git clone https://github.com/calcom/cal.com.git cd cal.com cp .env.example .env

Open .env and set the following variables. These are the variables verified as required in May 2026 — always check the current .env.example for any additions:

DATABASE_URL — your PostgreSQL connection string. Format: postgresql://USER:PASSWORD@HOST:5432/DBNAME. The bundled Postgres container default is postgresql://unicorn_user:magical_password@database:5432/calendso — change those credentials before running.

NEXTAUTH_SECRET — session encryption key. Generate with:

openssl rand -base64 32

CALENDSO_ENCRYPTION_KEY — credential encryption key. Generate with:

openssl rand -base64 24 

This key uses 24 bytes (not 32). It must never be changed after your first run — changing it permanently corrupts all stored integration credentials (Google OAuth tokens, calendar connections, etc.). Back it up externally immediately.

NEXT_PUBLIC_WEBAPP_URL and NEXTAUTH_URL — both set to the full public URL where cal.com will be accessible: https://cal.yourdomain.com

EMAIL_FROM, EMAIL_SERVER_HOST, EMAIL_SERVER_PORT, EMAIL_SERVER_USER, EMAIL_SERVER_PASSWORD — SMTP provider credentials for booking confirmation emails. Resend and Postmark are reliable options.

Step 2 — Start the Stack

With .env configured, start the full stack — cal.com, PostgreSQL, and Prisma Studio:

docker compose up -d

The first run pulls images and runs database migrations automatically. It takes a few minutes. Access cal.com at http://YOUR_SERVER_IP:3000 (or your defined NEXT_PUBLIC_WEBAPP_URL). A setup wizard runs on first load — create your admin account and set your organisation name.

Prisma Studio (database browser) runs on port 5555 if you need to inspect the database directly.

Test before touching DNS: create a test event type, make a booking, and confirm the booking appears in your admin view. If email notifications aren’t arriving, check your SMTP variables — that’s the most common first-run issue.

Step 3 — Domain and HTTPS

Create an A record in DNS pointing your domain to your server’s IP. Then configure a reverse proxy in front of cal.com’s port 3000 with SSL. Nginx with Certbot and Caddy are both common choices:

  • Proxy all traffic on port 443 (HTTPS) to localhost:3000
  • Provision a Let’s Encrypt certificate for your domain
  • Redirect HTTP (port 80) to HTTPS

After the proxy is in place, update NEXT_PUBLIC_WEBAPP_URL and NEXTAUTH_URL in .env to the https:// version of your domain, then restart:

docker compose restart calcom

Test end-to-end: open the HTTPS URL, log in, create a booking, and confirm the confirmation email arrives with the correct domain in the link. If email links still show localhost or http://, the env vars haven’t taken effect — check for typos and restart.

Step 4 — Keeping cal.com Updated

Before any update, back up your database. The exact pg_dump command depends on the container name in your Compose file — check with docker compose ps to confirm your Postgres container name, then:

docker exec -t <postgres-container-name> pg_dump -U unicorn_user calendso > backup_$(date +%Y%m%d).sql

Then pull new images and restart:

docker compose pull docker compose up -d

cal.com runs database migrations automatically on startup when schema changes are present. Check container logs after an update to confirm migrations completed before sending traffic.

Never regenerate CALENDSO_ENCRYPTION_KEY during an update. It is not a password you rotate — it is a master encryption key. Changing it corrupts all stored credentials.

Connecting Google Calendar and Email

For Google Calendar sync, create an OAuth 2.0 application in the Google Cloud Console with the Google Calendar API enabled. Add the client credentials to .env under the Google-related variables — check the current .env.example for the exact variable names, as they have been renamed between cal.com releases.

Set the authorised redirect URI to https://cal.yourdomain.com/api/auth/callback/google.

In the cal.com admin panel, app integrations are enabled under Settings → Apps. Users can then connect their individual Google accounts from their own settings pages.

SMTP for booking emails should already be working if you set the EMAIL_SERVER_* variables in Step 1. If confirmation emails aren’t arriving: verify port 587 is not blocked by your VPS provider, check you’re using a transactional (not marketing) email API key, and check docker logs calcom for the SMTP error.

A note on hosting

cal.com is a Next.js app with a PostgreSQL database — lean by self-hosted standards. A solo user or small team runs comfortably on 8 GB RAM. The upgrade case is when you start co-locating cal.com with other tools: n8n for booking automation, analytics, or additional services on the same box. For that, 12–24 GB gives each service room without resource contention. Contabo Cloud VPS 10 (8 GB RAM, €4,28/mo) is a practical starting point; Cloud VPS 30 (13 GB RAM, €6,33/mo) makes sense if cal.com is part of a wider self-hosted stack on the same server.

FAQ: Self-Hosting cal.com

Do I need to run database migrations when updating cal.com?

In most cases, yes — cal.com runs Prisma migrations automatically on container startup when schema changes are present. After pulling new images and running docker compose up -d, check the application container logs to confirm migrations completed successfully before sending traffic:
docker compose logs calcom --tail=50
Look for a line indicating migrations applied or ‘No pending migrations.’ If the container fails to start after an update, a failed migration is usually the cause — check the logs, verify DATABASE_URL is correct, and confirm the Postgres container is healthy before retrying.
Always take a database backup before any update. A broken migration against a live database without a backup is a bad day.

What are the server requirements for self-hosting cal.com?

Minimum: 2 vCPU, 4 GB RAM, 20 GB disk, Ubuntu 22.04 or 24.04 with Docker. 4 vCPU and 8 GB RAM is more comfortable for a team deployment, especially if other services share the same server.

How do I connect cal.com to PostgreSQL?

Set DATABASE_URL in .env to a PostgreSQL connection string: postgresql://USER:PASSWORD@HOST:5432/DBNAME. The bundled docker compose file includes a Postgres container — use that connection string for a single-server setup. cal.com runs migrations automatically on first startup.

Can I use cal.com with my own domain?

Yes. Set NEXT_PUBLIC_WEBAPP_URL and NEXTAUTH_URL in .env to your full domain (https://cal.yourdomain.com), configure a reverse proxy pointing to port 3000 with SSL, and booking pages will serve from your own domain.

What happens if I change CALENDSO_ENCRYPTION_KEY after setup?

Every stored credential in your cal.com instance — Google OAuth tokens, calendar connections, integration secrets — is encrypted using this key. Changing it after your first run does not re-encrypt the stored data; it just makes it permanently unreadable.
The result: all calendar integrations break silently. Users lose their Google Calendar connections. The app may start, but integrations stop working with no clear error message.
Treat CALENDSO_ENCRYPTION_KEY like a database master key — generate it once with openssl rand -base64 24, store it somewhere safe outside the server, and never change it. If you lose it and need to rotate it, cal.com’s documentation covers the migration procedure for that specific scenario.

How do I set up email for self-hosted cal.com?

Set EMAIL_FROM, EMAIL_SERVER_HOST, EMAIL_SERVER_PORT, EMAIL_SERVER_USER, and EMAIL_SERVER_PASSWORD in .env with your SMTP provider credentials. Resend and Postmark are reliable options for transactional email. Restart after .env changes: docker compose restart calcom.

Scroll to Top