Por qué autoalojar Cal.com en un VPS
Cal.com es una aplicación Next.js respaldada por PostgreSQL que gestiona la planificación de citas, los tipos de evento, las disponibilidades y la sincronización con los calendarios (Google, CalDAV, Office 365). El autoalojamiento responde a una necesidad concreta: controlar los datos de disponibilidad y de reserva de sus clientes, que normalmente pasan por un servicio externo estadounidense. En un VPS elimina los límites del plan gratuito (un solo tipo de evento, marca impuesta), conecta sus propias claves de API de Google y de videollamada, e integra el widget de reserva directamente en su sitio bajo su dominio. Como Cal.com es una aplicación Node persistente con base de datos y build de producción, exige un VPS: un alojamiento compartido no puede ni ejecutar el proceso ni alojar PostgreSQL.
Beneficios concretos de Cal.com autoalojado
- Tipos de evento ilimitados: entrevistas de 15 min, demos de 30 min, talleres de grupo, sin muro de pago.
- Datos de reserva en su servidor: ninguna fuga de los contactos ni de los horarios de sus clientes hacia un SaaS externo.
- White-label total: el enlace de reserva lleva su dominio, no el de un proveedor.
- Webhooks y API: active automatizaciones (CRM, facturación) con cada cita reservada.
- Integraciones con Google Calendar, CalDAV y videollamada (Jitsi, Google Meet) configuradas con sus propias claves.
- Reservas de equipo y round-robin para repartir las citas entre varios colaboradores.
Requisitos técnicos
Cal.com es más exigente que la media del self-hosting por su base Next.js y por la etapa de build. Prevea 2 vCPU, 4 GB de RAM y 20 GB de disco para una instancia de equipo cómoda; 2 GB de RAM pueden bastar para un uso individual, pero el build inicial queda más ajustado. Necesita Docker y Docker Compose, una base de datos PostgreSQL (incluida en el compose oficial), un dominio rdv.yourdomain.com apuntando al VPS y varias variables de entorno obligatorias: NEXTAUTH_SECRET, CALENDSO_ENCRYPTION_KEY (claves generadas aleatoriamente) y NEXT_PUBLIC_WEBAPP_URL ajustada a su URL HTTPS final. Para la sincronización del calendario y la videollamada, prepare las credenciales OAuth de Google.
Desplegar Cal.com paso a paso
Clonar el repositorio de despliegue Docker
En el VPS:
git clone https://github.com/calcom/docker.git cal-docker && cd cal-docker. Este repositorio proporciona undocker-compose.ymly un archivo.env.exampleque hay que adaptar.Generar los secretos y configurar el entorno
Copie
.env.examplecomo.envy genere después las claves:openssl rand -base64 32paraNEXTAUTH_SECRETy paraCALENDSO_ENCRYPTION_KEY. IndiqueNEXT_PUBLIC_WEBAPP_URL=https://rdv.yourdomain.comy las credenciales de PostgreSQL. Guarde estos tres valores en un gestor de secretos de inmediato — no podrá cambiarlos tras el primer arranque sin perder todas sus integraciones.Añadir NEXTAUTH_URL_INTERNAL para evitar el CLIENT_FETCH_ERROR
Añada
NEXTAUTH_URL_INTERNAL=http://calcom:3000a su.env. Sin esta variable, el contenedor Next.js intenta resolver su propio dominio público (rdv.yourdomain.com) desde dentro de la red Docker, donde el DNS externo no responde — cada petición de autenticación del lado del servidor falla conCLIENT_FETCH_ERROR.NEXTAUTH_URL_INTERNALcortocircuita esa resolución apuntando directamente al nombre del servicio Docker (calcomes el nombre del servicio endocker-compose.yml). Esta variable es independiente deNEXTAUTH_URL: ambas deben estar presentes.Compilar y arrancar la stack
Arranque con
docker compose up -d. El primer arranque construye la imagen Next.js y aplica las migraciones Prisma sobre PostgreSQL: es la etapa más larga, sígala condocker compose logs -f.Conectarse por primera vez
Abra la URL: Cal.com le redirige a su asistente de primera configuración (
/auth/setup), donde crea SU cuenta de administrador. Hágalo nada más terminar la instalación: ese asistente no está protegido por nada mientras no exista la primera cuenta.Crear la cuenta y configurar las disponibilidades
Defina sus franjas horarias y un primer tipo de evento. Pruebe una reserva de principio a fin para validar toda la cadena antes de conectar las integraciones.
Conectar calendario y videollamada
En las integraciones, añada sus credenciales OAuth de Google para la sincronización bidireccional del calendario y active Jitsi o Google Meet para generar automáticamente un enlace de videollamada en cada reserva.
Reverse proxy: nginx y Caddy
Cal.com escucha en el puerto 3000 dentro del contenedor. Un reverse proxy HTTPS es necesario por dos motivos: exponer el puerto 443 y reenviar la cabecera Host correcta — de lo contrario NEXT_PUBLIC_WEBAPP_URL ya no coincide con el origen real y las redirecciones de autenticación fallan.
Con Caddy (recomendado, certificado automático):
rdv.yourdomain.com {
reverse_proxy calcom:3000
}Caddy obtiene y renueva el certificado Let's Encrypt sin configuración adicional.
Con nginx, añada este bloque a su configuración:
server {
listen 443 ssl;
server_name rdv.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/rdv.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/rdv.yourdomain.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}En ambos casos, la URL debe coincidir exactamente con NEXT_PUBLIC_WEBAPP_URL: sin barra oblicua final, en HTTPS, con el subdominio correcto. Una diferencia de un solo carácter produce redirecciones infinitas o pantalla en blanco.
Invariantes críticos del primer arranque
Tres variables de entorno quedan permanentemente bloqueadas en el primer arranque de Cal.com. Modificarlas después corrompe silenciosamente todas las integraciones almacenadas: la aplicación reinicia con normalidad, no muestra ningún error, pero Google Calendar, Zoom y todas las conexiones OAuth dejan de funcionar — sus tokens fueron cifrados con la clave original, ahora incompatible. Este comportamiento está documentado en calcom/docker issue #333 y calcom/cal.diy issue #13290: usuarios han perdido todas sus integraciones tras una actualización que regeneró el archivo .env.
CALENDSO_ENCRYPTION_KEY — cifra los tokens OAuth almacenados en la base de datos. Cualquier cambio invalida silenciosamente todas las integraciones existentes.
NEXTAUTH_URL — ancla las cookies de sesión. Un cambio rompe la autenticación para todos los usuarios activos.
NEXT_PUBLIC_WEBAPP_URL — integrada en el build de Next.js en el momento de la compilación. Cambiar este valor exige un rebuild completo y volver a conectar todas las integraciones.
Buena práctica: copie estos tres valores en un gestor de secretos (Bitwarden, HashiCorp Vault, Ansible Vault) en cuanto los genere. Si gestiona su VPS como infraestructura-como-código, guárdelos en un vault cifrado — nunca deje que el archivo .env sea su único almacén.
Actualizar Cal.com de forma segura
Hacer copia de seguridad de la base PostgreSQL
Antes de cualquier actualización:
docker exec cal-docker-db-1 pg_dump -U calcom calcom | gzip > /opt/backup/calcom-$(date +%Y%m%d).sql.gz. Las migraciones Prisma no son reversibles — esta copia de seguridad es su única red de seguridad.Verificar que CALENDSO_ENCRYPTION_KEY no ha cambiado
Compare el valor de su
.envcon el almacenado en su gestor de secretos. Si difieren, no continúe: restaure el valor original antes de seguir. Una clave diferente destruirá silenciosamente todas sus integraciones OAuth al reiniciar.Descargar la nueva imagen y reiniciar
Actualice con
docker compose pull && docker compose up -d. Siga el arranque condocker compose logs -f calcom— espere el mensaje que indica que el servidor está listo antes de hacer pruebas.Verificar las integraciones tras la actualización
Abra Configuración → Integraciones y confirme que cada conexión existente (Google Calendar, Zoom, etc.) sigue activa. Un estado «no conectado» indica que la clave cambió entre reinicios — restaure la copia de seguridad y el
.envoriginal.
Depuración: CLIENT_FETCH_ERROR y otros errores Docker
CLIENT_FETCH_ERROR al cargar la página — Desde principios de 2026, todas las nuevas instalaciones Docker encuentran este error en la primera carga. Causa: el contenedor Next.js intenta resolver NEXTAUTH_URL (su dominio público) desde dentro de la red Docker, donde el DNS externo no es accesible. Solución: añada NEXTAUTH_URL_INTERNAL=http://calcom:3000 a su .env y reinicie con docker compose up -d. Esta variable fuerza a NextAuth a llamar a su propia API internamente, sin pasar por el dominio público. Documentado en calcom/cal.diy (febrero 2026, issue #27668) (febrero de 2026, 8 comentarios que confirman el error en todas las distribuciones Docker recientes).
Integraciones perdidas tras una actualización — La causa es casi siempre una CALENDSO_ENCRYPTION_KEY diferente entre dos arranques. Compruebe que su .env no haya sido sobreescrito por un .env.example durante el pull. Compare el valor actual con el guardado en su gestor de secretos. Si difieren: restaure la base PostgreSQL, vuelva a poner la clave original en .env y reinicie con docker compose up -d.
Build «JavaScript heap out of memory» — El compilador Next.js se queda sin RAM. Solución: fallocate -l 2G /swapfile && mkswap /swapfile && swapon /swapfile, y vuelva a ejecutar docker compose build. En un VPS de 2 GB, el swap suele ser imprescindible para el primer build y las actualizaciones mayores. Retire el archivo swap una vez terminado el build.
Bucle de redirección o «Unable to find valid origin» — NEXT_PUBLIC_WEBAPP_URL no coincide con la URL real. Compruebe que esta variable sea exactamente https://rdv.yourdomain.com (sin barra oblicua final, dominio correcto, protocolo HTTPS), que el reverse proxy reenvíe correctamente la cabecera Host, y reinicie con docker compose up -d --build para forzar un rebuild con la URL correcta.
Migraciones Prisma bloqueadas al arrancar — Si el contenedor reinicia en bucle con errores de migración, es posible que la base de datos todavía no esté lista. Espere unos segundos y ejecute docker compose restart calcom. Si el problema persiste, revise los logs de PostgreSQL con docker compose logs db.
Automatice la copia de seguridad de su base PostgreSQL con un cron diario. Ejemplo de comando a programar: docker exec cal-docker-db-1 pg_dump -U calcom calcom | gzip > /opt/backup/calcom-$(date +%Y%m%d-%H%M).sql.gz. Conserve al menos 7 días de copias rotativas y envíelas a un almacenamiento de objetos externo (compatible con S3, Backblaze B2): en caso de pérdida del VPS, la base de datos PostgreSQL es la única parte no reproducible de su instancia de Cal.com.
Para ir más lejos
Una vez que Cal.com funciona, varios pasos para reforzar la instalación: activar alertas sobre los certificados SSL para anticipar sus vencimientos, configurar monitorización HTTP (Uptime Kuma, Better Uptime) sobre https://rdv.yourdomain.com/api/health, y restringir el puerto 3000 del contenedor a 127.0.0.1 para que no sea accesible directamente. Para instalaciones de equipo, el reverse proxy puede servir varias instancias de Cal.com detrás de subdominios distintos desde un único VPS — consulte el despliegue con Coolify para una gestión multi-servicio simplificada. La documentación oficial de Cal.com también cubre la configuración SMTP para los correos de confirmación y la integración con Stripe para reservas de pago.