Self-Hosting Cal.com with Docker Compose

What Makes Cal.com Worth Self-Hosting?

Calendly charges $12–16/user/month for features Cal.com gives you for free. Cal.com is an open-source scheduling platform — booking pages, round-robin assignments, team scheduling, Google/Outlook calendar integration, payment collection, and webhook automations. Self-hosting means your scheduling data stays on your infrastructure with no per-seat licensing.

Cal.com is built on Next.js with Prisma ORM and PostgreSQL. The Docker image includes everything needed to run the full application.

Prerequisites

  • A Linux server (Ubuntu 22.04+ recommended)
  • Docker and Docker Compose installed (guide)
  • 2 GB RAM minimum
  • 20 GB free disk space
  • A domain name (required for OAuth calendar integrations)
ResourceMinimumRecommended
RAM2 GB (total stack)4 GB
CPU1 core2 cores
Disk10 GB20 GB
App idle RAM~300 MB~400 MB

Cal.com is lightweight compared to other scheduling tools. PostgreSQL is the biggest memory consumer.

Docker Compose Configuration

Create a project directory and docker-compose.yml:

services:
  calcom:
    image: calcom/cal.com:v6.2.0
    container_name: calcom
    depends_on:
      calcom-db:
        condition: service_healthy
      calcom-redis:
        condition: service_started
    environment:
      - DATABASE_URL=postgresql://calcom:${DB_PASSWORD}@calcom-db:5432/calendso
      - REDIS_URL=redis://calcom-redis:6379
      - NEXTAUTH_SECRET=${NEXTAUTH_SECRET}
      - CALENDSO_ENCRYPTION_KEY=${ENCRYPTION_KEY}
      - NEXTAUTH_URL=${BASE_URL}/api/auth
      - NEXT_PUBLIC_WEBAPP_URL=${BASE_URL}
    ports:
      - "3000:3000"
    restart: unless-stopped

  calcom-db:
    image: postgres:15
    container_name: calcom-db
    environment:
      - POSTGRES_DB=calendso
      - POSTGRES_USER=calcom
      - POSTGRES_PASSWORD=${DB_PASSWORD}
    volumes:
      - calcom_db:/var/lib/postgresql/data
    restart: unless-stopped
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U calcom -d calendso"]
      interval: 10s
      timeout: 5s
      retries: 5

  calcom-redis:
    image: redis:7-alpine
    container_name: calcom-redis
    volumes:
      - calcom_redis:/data
    restart: unless-stopped

volumes:
  calcom_db:
  calcom_redis:

Create a .env file:

# Your public URL — used for OAuth callbacks and booking links
BASE_URL=https://cal.example.com

# Database password — change this
DB_PASSWORD=change_me_to_a_strong_password

# Authentication secret — generate with: openssl rand -base64 32
NEXTAUTH_SECRET=generate_a_random_string_here

# Encryption key for sensitive data — generate with: openssl rand -base64 32
ENCRYPTION_KEY=generate_another_random_string_here

Generate the secrets:

echo "NEXTAUTH_SECRET=$(openssl rand -base64 32)" >> .env
echo "ENCRYPTION_KEY=$(openssl rand -base64 32)" >> .env

Start the stack:

docker compose up -d

Initial Setup

  1. Open http://your-server:3000 (or your domain if reverse proxied)
  2. Click Create Account and register the first user — this becomes the admin
  3. Complete the onboarding wizard: timezone, availability, booking page URL slug
  4. Your booking page is immediately live at https://cal.example.com/your-username

Connecting Google Calendar

Cal.com syncs with Google Calendar to check availability and create events:

  1. Create a project in Google Cloud Console
  2. Enable the Google Calendar API
  3. Create OAuth 2.0 credentials with redirect URI: https://cal.example.com/api/auth/callback/google
  4. Add GOOGLE_API_CREDENTIALS to your Cal.com environment with the client ID and secret

Connecting Outlook/Office 365

Similar process through Azure AD app registration. Redirect URI: https://cal.example.com/api/auth/callback/office365

Key Features

FeatureFree (Self-Hosted)Calendly FreeCalendly Pro ($12/mo)
Booking pagesUnlimited1 event typeUnlimited
Team schedulingYesNoYes
Round-robinYesNoYes
Calendar integrationsGoogle, Outlook, CalDAVGoogle, OutlookGoogle, Outlook
Custom brandingFull controlCalendly brandingRemove branding
WebhooksYesNoYes
Payment collectionStripe, PayPalNoStripe
API accessFull APINoYes
Recurring eventsYesNoYes

Reverse Proxy

Cal.com runs on port 3000. Put it behind a reverse proxy for SSL.

Caddy:

cal.example.com {
    reverse_proxy calcom:3000
}

The NEXTAUTH_URL and NEXT_PUBLIC_WEBAPP_URL environment variables must match your public URL exactly, including the protocol (https://). Mismatches cause authentication loops.

See Reverse Proxy Setup for Nginx Proxy Manager and Traefik configurations.

Backup

Cal.com stores everything in PostgreSQL. Back up the database:

docker exec calcom-db pg_dump -U calcom calendso > calcom-backup.sql

Redis data is ephemeral cache — losing it doesn’t lose bookings.

For automated backup strategies, see Backup Strategy.

Troubleshooting

CLIENT_FETCH_ERROR on login

Symptom: Login page shows “CLIENT_FETCH_ERROR” or infinite redirect loop.

Fix: NEXTAUTH_URL must be reachable from inside the container. If you’re behind a reverse proxy, use the internal URL for NEXTAUTH_URL:

NEXTAUTH_URL=http://localhost:3000/api/auth

And set the public URL separately:

NEXT_PUBLIC_WEBAPP_URL=https://cal.example.com

Booking page shows 404

Symptom: https://cal.example.com/username returns 404.

Fix: The username must match exactly what was set during onboarding. Check in Settings → Profile. Also verify NEXT_PUBLIC_WEBAPP_URL matches your domain.

Calendar sync not working

Symptom: Google Calendar events don’t show as busy times.

Fix: OAuth credentials must have the correct redirect URI. Check Google Cloud Console — the redirect must be https://your-domain/api/auth/callback/google (HTTPS, exact domain match). Re-authorize the calendar connection after fixing.

ARM64 compatibility

Symptom: Container crashes on Raspberry Pi or ARM-based server.

Fix: Use the ARM-specific image tag:

image: calcom/cal.com:v6.2.0-arm

Verdict

Cal.com is the clear winner for self-hosted scheduling. It replaces Calendly with zero compromises on features — booking pages, team scheduling, calendar sync, payments, and webhooks are all included. The Docker setup is straightforward, resource usage is modest, and the community is active.

Use Cal.com if: You want a Calendly replacement without per-seat costs, need team scheduling or round-robin routing, or want full API access to your scheduling data.

Look elsewhere if: You only need simple appointment booking without calendar sync — Easy Appointments is lighter. Or if you need event ticketing rather than 1:1 scheduling, see Hi.Events or Alf.io.

Comments