--- # Cal.com - Open-source scheduling infrastructure # https://cal.com/ # # Features: # - Stripe payment integration (native) # - Configurable time slots # - Cancellation policies with fees # - Google Calendar sync # - Email notifications # - Multiple event types # - Booking notes # - White-label capable # - OIDC/SAML SSO support (Authentik integration!) # # Prerequisites: # 1. Create databases in shared PostgreSQL: # kubectl exec -it postgresql-1 -n database-system -- psql -U postgres # # -- Main database # CREATE DATABASE calcom; # CREATE USER calcom WITH PASSWORD 'your-secure-password'; # GRANT ALL PRIVILEGES ON DATABASE calcom TO calcom; # \c calcom # GRANT ALL ON SCHEMA public TO calcom; # # -- SSO/SAML database (required for OIDC!) # CREATE DATABASE calcom_saml; # GRANT ALL PRIVILEGES ON DATABASE calcom_saml TO calcom; # \c calcom_saml # GRANT ALL ON SCHEMA public TO calcom; # # 2. Set up Stripe account at https://stripe.com (Hungary supported) # Get API keys from Dashboard -> Developers -> API keys # # 3. Set up Authentik OIDC provider: # - Create OAuth2/OpenID Provider in Authentik # - Client type: Confidential # - Redirect URIs: https://booking.dooplex.hu/api/auth/callback/oidc # - Note the Client ID, Client Secret # - Well-known URL: https://authentik.dooplex.hu/application/o//.well-known/openid-configuration # # 4. (Optional) Set up Google OAuth for calendar sync: # https://console.cloud.google.com/apis/credentials # # After deployment: # 1. Access https://booking.dooplex.hu # 2. Create first user with email matching SAML_ADMINS # 3. Go to Settings → Security → SSO # 4. Click "Configure SSO with OIDC" # 5. Enter Client ID, Client Secret, Well-known URL from Authentik # 6. Configure event types, availability, and Stripe integration --- apiVersion: v1 kind: Namespace metadata: name: booking-system labels: app.kubernetes.io/name: calcom --- # Redis for Cal.com (required for sessions, rate limiting, etc.) apiVersion: v1 kind: PersistentVolumeClaim metadata: name: calcom-redis namespace: booking-system labels: app.kubernetes.io/instance: calcom app.kubernetes.io/name: redis spec: accessModes: - ReadWriteOnce storageClassName: longhorn resources: requests: storage: 1Gi --- apiVersion: apps/v1 kind: Deployment metadata: name: calcom-redis namespace: booking-system labels: app.kubernetes.io/instance: calcom app.kubernetes.io/name: redis spec: replicas: 1 strategy: type: Recreate selector: matchLabels: app.kubernetes.io/instance: calcom app.kubernetes.io/name: redis template: metadata: labels: app.kubernetes.io/instance: calcom app.kubernetes.io/name: redis spec: containers: - name: redis image: redis:7-alpine imagePullPolicy: IfNotPresent args: - redis-server - --appendonly - "yes" - --maxmemory - "256mb" - --maxmemory-policy - "allkeys-lru" ports: - containerPort: 6379 name: redis protocol: TCP resources: requests: cpu: 50m memory: 64Mi limits: cpu: 200m memory: 256Mi volumeMounts: - name: data mountPath: /data livenessProbe: exec: command: - redis-cli - ping initialDelaySeconds: 10 periodSeconds: 10 readinessProbe: exec: command: - redis-cli - ping initialDelaySeconds: 5 periodSeconds: 5 volumes: - name: data persistentVolumeClaim: claimName: calcom-redis --- apiVersion: v1 kind: Service metadata: name: calcom-redis namespace: booking-system labels: app.kubernetes.io/instance: calcom app.kubernetes.io/name: redis spec: type: ClusterIP ports: - port: 6379 targetPort: redis protocol: TCP name: redis selector: app.kubernetes.io/instance: calcom app.kubernetes.io/name: redis --- # Cal.com Web Application apiVersion: apps/v1 kind: Deployment metadata: name: calcom namespace: booking-system labels: app.kubernetes.io/instance: calcom app.kubernetes.io/name: calcom app.kubernetes.io/version: "v6.0.8" spec: replicas: 1 strategy: type: Recreate selector: matchLabels: app.kubernetes.io/instance: calcom app.kubernetes.io/name: calcom template: metadata: labels: app.kubernetes.io/instance: calcom app.kubernetes.io/name: calcom app.kubernetes.io/version: "v6.0.8" spec: initContainers: # Wait for PostgreSQL - name: wait-for-db image: busybox:1.36 command: - sh - -c - | echo "Waiting for PostgreSQL..." until nc -z postgresql-rw.database-system.svc.cluster.local 5432; do echo "PostgreSQL not ready, waiting..." sleep 2 done echo "PostgreSQL is ready!" # Wait for Redis - name: wait-for-redis image: busybox:1.36 command: - sh - -c - | echo "Waiting for Redis..." until nc -z calcom-redis 6379; do echo "Redis not ready, waiting..." sleep 2 done echo "Redis is ready!" containers: - name: calcom image: calcom/cal.com:v6.0.8 imagePullPolicy: IfNotPresent env: # License (empty for AGPL, set key for enterprise features) - name: CALCOM_LICENSE_KEY value: "" # Telemetry - name: NEXT_PUBLIC_IS_E2E value: "false" - name: CALCOM_TELEMETRY_DISABLED value: "1" # URLs - name: NEXT_PUBLIC_WEBAPP_URL value: "https://booking.dooplex.hu" - name: NEXTAUTH_URL value: "https://booking.dooplex.hu/api/auth" - name: NEXT_PUBLIC_API_V2_URL value: "https://booking.dooplex.hu/api/v2" # Database - using shared PostgreSQL - name: DATABASE_URL value: "postgresql://$(DB_USER):$(DB_PASS)@postgresql-rw.database-system.svc.cluster.local:5432/calcom" - name: DATABASE_DIRECT_URL value: "postgresql://$(DB_USER):$(DB_PASS)@postgresql-rw.database-system.svc.cluster.local:5432/calcom" - name: DB_USER valueFrom: secretKeyRef: name: calcom-db key: username - name: DB_PASS valueFrom: secretKeyRef: name: calcom-db key: password # Redis - name: REDIS_URL value: "redis://calcom-redis:6379" # SSO/OIDC Configuration (for Authentik integration) # Requires separate database - see prerequisites - name: SAML_DATABASE_URL value: "postgresql://$(DB_USER):$(DB_PASS)@postgresql-rw.database-system.svc.cluster.local:5432/calcom_saml" # Admin email(s) who can configure SSO in the UI # Must match the email used when creating the first user - name: SAML_ADMINS valueFrom: secretKeyRef: name: calcom-app key: saml-admin-email # Auth secrets - name: NEXTAUTH_SECRET valueFrom: secretKeyRef: name: calcom-app key: nextauth-secret - name: CALENDSO_ENCRYPTION_KEY valueFrom: secretKeyRef: name: calcom-app key: calendso-encryption-key # Email/SMTP - name: EMAIL_FROM valueFrom: secretKeyRef: name: smtp-credentials key: from-address - name: EMAIL_SERVER_HOST valueFrom: secretKeyRef: name: smtp-credentials key: host - name: EMAIL_SERVER_PORT valueFrom: secretKeyRef: name: smtp-credentials key: port - name: EMAIL_SERVER_USER valueFrom: secretKeyRef: name: smtp-credentials key: username - name: EMAIL_SERVER_PASSWORD valueFrom: secretKeyRef: name: smtp-credentials key: password # Stripe (optional - for payments) - name: STRIPE_API_KEY valueFrom: secretKeyRef: name: calcom-app key: stripe-api-key - name: STRIPE_WEBHOOK_SECRET valueFrom: secretKeyRef: name: calcom-app key: stripe-webhook-secret - name: NEXT_PUBLIC_STRIPE_PUBLIC_KEY valueFrom: secretKeyRef: name: calcom-app key: next-public-stripe-key - name: PAYMENT_FEE_PERCENTAGE value: "0" - name: PAYMENT_FEE_FIXED value: "0" # Google Calendar (optional) - name: GOOGLE_API_CREDENTIALS valueFrom: secretKeyRef: name: calcom-app key: google-client-id optional: true # Timezone - name: TZ value: "Europe/Budapest" # Misc - name: NODE_ENV value: "production" - name: NODE_TLS_REJECT_UNAUTHORIZED value: "0" # Allow signup (set to "false" after creating your account if you want to restrict) - name: NEXT_PUBLIC_DISABLE_SIGNUP value: "false" # CSP - needed for embedded iframes if you want to embed booking widget - name: CSP_POLICY value: "" ports: - containerPort: 3000 name: http protocol: TCP resources: requests: cpu: 200m memory: 512Mi limits: cpu: "2" memory: 2Gi livenessProbe: httpGet: path: /api/health port: http initialDelaySeconds: 120 periodSeconds: 30 timeoutSeconds: 10 failureThreshold: 5 readinessProbe: httpGet: path: /api/health port: http initialDelaySeconds: 60 periodSeconds: 15 timeoutSeconds: 10 failureThreshold: 3 startupProbe: httpGet: path: /api/health port: http initialDelaySeconds: 30 periodSeconds: 10 timeoutSeconds: 10 failureThreshold: 30 --- apiVersion: v1 kind: Service metadata: name: calcom namespace: booking-system labels: app.kubernetes.io/instance: calcom app.kubernetes.io/name: calcom spec: type: ClusterIP ports: - port: 3000 targetPort: http protocol: TCP name: http selector: app.kubernetes.io/instance: calcom app.kubernetes.io/name: calcom --- # Ingress apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: calcom namespace: booking-system labels: app.kubernetes.io/instance: calcom app.kubernetes.io/name: calcom annotations: cert-manager.io/cluster-issuer: letsencrypt-prod external-dns.alpha.kubernetes.io/hostname: booking.dooplex.hu,booking.home nginx.ingress.kubernetes.io/ssl-redirect: "true" nginx.ingress.kubernetes.io/proxy-body-size: "64m" nginx.ingress.kubernetes.io/proxy-read-timeout: "300" nginx.ingress.kubernetes.io/proxy-send-timeout: "300" # Required for WebSocket connections (if using Cal.com video) nginx.ingress.kubernetes.io/proxy-http-version: "1.1" nginx.ingress.kubernetes.io/proxy-set-headers: "booking-system/calcom-proxy-headers" spec: ingressClassName: nginx-internal rules: - host: booking.dooplex.hu http: paths: - path: / pathType: Prefix backend: service: name: calcom port: number: 3000 - host: booking.home http: paths: - path: / pathType: Prefix backend: service: name: calcom port: number: 3000 tls: - hosts: - booking.dooplex.hu secretName: calcom-tls --- # ConfigMap for nginx proxy headers (WebSocket support) apiVersion: v1 kind: ConfigMap metadata: name: calcom-proxy-headers namespace: booking-system data: Upgrade: "$http_upgrade" Connection: "upgrade" --- # Optional: Prisma Studio for database management/first user creation # Uncomment if you need direct database access # Access via port-forward: kubectl port-forward svc/calcom-prisma-studio 5555:5555 -n booking-system # --- # apiVersion: apps/v1 # kind: Deployment # metadata: # name: calcom-prisma-studio # namespace: booking-system # labels: # app.kubernetes.io/instance: calcom # app.kubernetes.io/name: prisma-studio # spec: # replicas: 1 # selector: # matchLabels: # app.kubernetes.io/instance: calcom # app.kubernetes.io/name: prisma-studio # template: # metadata: # labels: # app.kubernetes.io/instance: calcom # app.kubernetes.io/name: prisma-studio # spec: # containers: # - name: prisma-studio # image: calcom/cal.com:v5.9.15 # command: ["npx", "prisma", "studio"] # env: # - name: DATABASE_URL # value: "postgresql://calcom:YOUR_PASSWORD@postgresql-rw.database-system.svc.cluster.local:5432/calcom" # ports: # - containerPort: 5555 # name: http # --- # apiVersion: v1 # kind: Service # metadata: # name: calcom-prisma-studio # namespace: booking-system # spec: # type: ClusterIP # ports: # - port: 5555 # targetPort: 5555 # selector: # app.kubernetes.io/instance: calcom # app.kubernetes.io/name: prisma-studio