Combined N8n & Cal.com Docker Setup

Intro :

  1. The self-hosted Cal.com does not require a license key, so you can leave that environment variable empty.
  2. You do need to generate a CALCOM_API_KEY from your self-hosted Cal.com admin dashboard.
  3. This API key is then used in your Next.js API route to authenticate requests to the Cal.com API, as shown in the example code.

Cal.com Licensing

The self-hosted version of Cal.com is free to use, with no license key required. The CALCOM_LICENSE_KEY environment variable is only needed if you're using the commercial Cal.com hosting service, which offers additional features and support.

For the self-hosted, open-source version, you can simply leave the CALCOM_LICENSE_KEY environment variable blank or remove it from your Docker Compose file.

Cal.com API Key

The CALCOM_API_KEY is a separate requirement, and it's needed to authenticate with the Cal.com API. This is used in the API integration example you referenced:

// pages/api/calendar/create-booking.ts 

import { CalAPIClient } from '@calcom/api';
 const calApi = new CalAPIClient({   apiKey: process.env.CALCOM_API_KEY,  
 baseURL: process.env.CALCOM_URL });

To get the CALCOM_API_KEY, you'll need to generate an API key within your self-hosted Cal.com instance. The steps are:

  1. Log in to your Cal.com admin dashboard
  2. Go to the "Settings" section
  3. Navigate to the "API" tab
  4. Click "Generate API key"
  5. Copy the generated API key value

Once you have the API key, you can set it in your environment variables as CALCOM_API_KEY for use in your Next.js API route.

# docker-compose.yml
version: "3.8"
services:
  calcom:
    image: calcom/cal.com:latest
    container_name: calcom
    environment:
      - DATABASE_URL=postgresql://postgres:postgres@db:5432/calcom
      - NEXTAUTH_SECRET=your-secret-key
      - CALCOM_LICENSE_KEY=
      - NEXT_PUBLIC_WEBAPP_URL=http://localhost:3000
      - NEXT_PUBLIC_WEBSITE_URL=http://localhost:3000
    ports:
      - "3000:3000"
    depends_on:
      - db
    networks:
      - app-network
    restart: unless-stopped

  n8n:
    image: n8nio/n8n
    container_name: n8n
    environment:
      - DB_TYPE=postgresdb
      - DB_POSTGRESDB_HOST=db
      - DB_POSTGRESDB_DATABASE=n8n
      - DB_POSTGRESDB_USER=postgres
      - DB_POSTGRESDB_PASSWORD=postgres
      - N8N_HOST=localhost
      - N8N_PORT=5678
      - N8N_PROTOCOL=http
      - N8N_USER_MANAGEMENT_DISABLED=true
      - WEBHOOK_URL=http://localhost:5678/
      - GENERIC_TIMEZONE=UTC
    ports:
      - "5678:5678"
    depends_on:
      - db
    networks:
      - app-network
    volumes:
      - n8n-data:/home/node/.n8n
    restart: unless-stopped

  db:
    image: postgres:13
    container_name: shared-db
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
      - POSTGRES_MULTIPLE_DATABASES=calcom,n8n
    volumes:
      - postgres-data:/var/lib/postgresql/data
      - ./init-multiple-dbs.sh:/docker-entrypoint-initdb.d/init-multiple-dbs.sh
    networks:
      - app-network
    restart: unless-stopped

networks:
  app-network:
    driver: bridge

volumes:
  postgres-data:
  n8n-data:

Database Initialization Script

# init-multiple-dbs.sh
#!/bin/bash

set -e
set -u

function create_user_and_database() {
	local database=$1
	echo "  Creating user and database '$database'"
	psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL
	    CREATE DATABASE $database;
	    GRANT ALL PRIVILEGES ON DATABASE $database TO $POSTGRES_USER;
EOSQL
}

if [ -n "$POSTGRES_MULTIPLE_DATABASES" ]; then
	echo "Multiple database creation requested: $POSTGRES_MULTIPLE_DATABASES"
	for db in $(echo $POSTGRES_MULTIPLE_DATABASES | tr ',' ' '); do
		create_user_and_database $db
	done
	echo "Multiple databases created"
fi

Environment Configuration

.env

# .env 
# Shared Database POSTGRES_USER=postgres POSTGRES_PASSWORD=postgres # Cal.com NEXTAUTH_URL=http://localhost:3000 NEXTAUTH_SECRET=your-secret-here CALCOM_DATABASE_URL=postgresql://postgres:postgres@db:5432/calcom # n8n N8N_DATABASE_URL=postgresql://postgres:postgres@db:5432/n8n N8N_WEBHOOK_TEST_URL=http://localhost:5678/ N8N_EDITOR_BASE_URL=http://localhost:5678/
``

```yaml
# Resource limits for each service
services:
  calcom:
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 1G
        reservations:
          cpus: '0.25'
          memory: 512M

  n8n:
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 1G
        reservations:
          cpus: '0.25'
          memory: 512M

  db:
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 1G
        reservations:
          cpus: '0.25'
          memory: 512M

Startup Script

#!/bin/bash
# start-services.sh

# Make the database init script executable
chmod +x init-multiple-dbs.sh

# Start the services
docker-compose up -d

# Wait for database to be ready
echo "Waiting for database to be ready..."
sleep 30

# Initialize Cal.com database
docker-compose exec calcom npx prisma migrate deploy

echo "Services started successfully!"
echo "Cal.com available at: http://localhost:3000"
echo "n8n available at: http://localhost:5678"

Basic Health Check

#!/bin/bash
# health-check.sh

check_service() {
    local service=$1
    local port=$2
    
    if curl -s "http://localhost:$port" > /dev/null; then
        echo "$service is running"
    else
        echo "$service is down"
    fi
}

check_service "Cal.com" 3000
check_service "n8n" 5678

#Backup Script
#!/bin/bash
# backup.sh

# Backup directory
BACKUP_DIR="/backup"
DATE=$(date +%Y%m%d_%H%M%S)

# Create backup directory
mkdir -p $BACKUP_DIR

# Backup databases
docker-compose exec db pg_dump -U postgres calcom > $BACKUP_DIR/calcom_$DATE.sql
docker-compose exec db pg_dump -U postgres n8n > $BACKUP_DIR/n8n_$DATE.sql

# Backup n8n data
docker cp n8n:/home/node/.n8n $BACKUP_DIR/n8n_data_$DATE

# Compress backups
tar -czf $BACKUP_DIR/backup_$DATE.tar.gz $BACKUP_DIR/*_$DATE*

# Clean up temporary files
rm $BACKUP_DIR/*_$DATE.sql
rm -rf $BACKUP_DIR/n8n_data_$DATE

Summary

In the self-hosted, open-source version of Cal.com:

  • You don't need a CALCOM_LICENSE_KEY
  • You do need a CALCOM_API_KEY to integrate with the Cal.com API

The CALCOM_API_KEY is generated from within your self-hosted Cal.com admin dashboard and is used to authenticate API requests, like the one shown in the example API route.