bolt Valebyte VPS desde $4/mes — NVMe, despliegue en 60s.

Obtener VPS arrow_forward
eco Principiante Tutorial/Cómo hacer

Instalación de Cal.com en un VPS: Docker, PostgreSQL, SSL, SMTP y copias de seguridad

calendar_month Oct 10, 2026 schedule 20 min de lectura visibility 48 vistas
Установка Cal.com на VPS: Docker, PostgreSQL, SSL, SMTP и резервные копии
info

¿Necesitas un servidor para esta guía? Ofrecemos servidores dedicados y VPS en más de 50 países con configuración instantánea.

¿Necesitas un VPS para esta guía?

Explore otras opciones de servidores dedicados en

Instalación de Cal.com en un VPS: Docker, PostgreSQL, SSL, SMTP y copias de seguridad

TL;DR

En esta guía implementaremos Cal.com en nuestro propio VPS mediante Docker Compose, PostgreSQL y Redis, conectaremos un dominio y HTTPS a través de Caddy, configuraremos el envío de correos mediante SMTP y copias de seguridad automáticas de la base de datos y la configuración.

  • Usaremos Ubuntu Server 24.04 LTS, Docker Engine 28.x y Docker Compose v2.
  • Cal.com funcionará en un contenedor, mientras que PostgreSQL y Redis estarán en contenedores independientes.
  • Organizaremos el acceso externo mediante Caddy con un certificado automático de Let’s Encrypt.
  • Guardaremos los secretos y los parámetros de conexión en el archivo .env, no en el código fuente.
  • Las copias de seguridad de PostgreSQL, la configuración de Docker y los datos de usuario se ejecutarán según un horario mediante cron y Restic.

1. TL;DR

En esta guía implementaremos Cal.com en nuestro propio VPS mediante Docker Compose, PostgreSQL y Redis, conectaremos un dominio y HTTPS a través de Caddy, configuraremos el envío de correos mediante SMTP y copias de seguridad automáticas de la base de datos y la configuración.

  • Usaremos Ubuntu Server 24.04 LTS, Docker Engine 28.x y Docker Compose v2.
  • Cal.com funcionará en un contenedor, mientras que PostgreSQL y Redis estarán en contenedores independientes.
  • Organizaremos el acceso externo mediante Caddy con un certificado automático de Let’s Encrypt.
  • Guardaremos los secretos y los parámetros de conexión en el archivo .env, no en el código fuente.
  • Las copias de seguridad de PostgreSQL, la configuración de Docker y los datos de usuario se ejecutarán según un horario mediante cron y Restic.

2. Contenido

La instalación está pensada para un servidor limpio con una dirección IPv4 pública y un dominio, por ejemplo calendar.example.com. Antes de comenzar, sustituya este dominio por el suyo en todos los comandos y archivos de configuración.

Los comandos están destinados a un usuario con permisos sudo. Si el servidor ya se utiliza para otros sitios, compruebe los puertos ocupados y las redes Docker existentes: Cal.com y Caddy deben tener una configuración aislada.

3. Qué configuramos y por qué

Qué es Cal.com

Cal.com es una plataforma para programar reuniones y reservar horarios. El usuario crea eventos del calendario, publica una página de disponibilidad y permite que otras personas elijan un intervalo libre. El sistema admite horarios laborales, intervalos entre reuniones, distintos tipos de eventos, calendarios de equipo e integraciones con calendarios externos.

Con una instalación independiente de Cal.com, la aplicación, la base de datos, la caché y el proxy inverso están bajo el control del propietario del servidor. Esto resulta práctico para un equipo, un servicio interno o un prototipo SaaS cuando se necesita un dominio propio, almacenamiento independiente de los datos y la posibilidad de cambiar la configuración sin las limitaciones de un plan en la nube.

Qué funcionará después de completar las instrucciones

  • Cal.com estará disponible en una dirección como https://calendar.example.com.
  • PostgreSQL almacenará los usuarios, eventos, configuraciones e integraciones.
  • Redis se utilizará para colas y almacenamiento en caché, si la versión de Cal.com elegida lo requiere.
  • Caddy aceptará las conexiones HTTPS y las redirigirá al contenedor de la aplicación.
  • El servidor SMTP enviará correos de confirmación, invitaciones y notificaciones.
  • Las copias de seguridad se transferirán a un almacenamiento independiente, ubicado en otro disco.

Cal.com Self-hosted o en la nube

Criterio Versión en la nube Self-hosted en un VPS
Implementación No requiere configurar un servidor Es necesario configurar por cuenta propia el sistema operativo, Docker y el dominio
Control de los datos Los datos están en manos del operador de la nube La base de datos y la configuración están en su servidor
Actualizaciones Se realizan automáticamente o por parte del operador Las controla el administrador
Flexibilidad Depende del plan y de las integraciones disponibles Es posible modificar la infraestructura y el esquema de red
Responsabilidad El proveedor asume una parte importante de las tareas Las copias de seguridad, la seguridad y la recuperación son responsabilidad del usuario

Un VPS es adecuado si está dispuesto a supervisar por su cuenta las actualizaciones, el disco, SMTP y la recuperación a partir de una copia de seguridad. Para varios usuarios, este esquema suele ser más sencillo y económico que un clúster de Kubernetes independiente. Para un servicio crítico, prepare con antelación un segundo servidor o un procedimiento de recuperación rápida.

Cómo está estructurado el esquema

El tráfico público llega a Caddy a través de los puertos 80 y 443. Caddy obtiene el certificado y reenvía las solicitudes al contenedor de Cal.com mediante la red interna de Docker. La aplicación se conecta a PostgreSQL y Redis usando los nombres de los contenedores, por lo que no es necesario publicar las bases de datos en Internet.

Internet
    |
    | 80/443
    v
Caddy ---- red interna ---- Cal.com:3000
                                  |       |
                                  v       v
                            PostgreSQL   Redis

4. Qué configuración de VPS se necesita para esta tarea

Configuración mínima

Para un calendario personal pequeño o un equipo de hasta 10–20 personas, son suficientes dos CPU virtuales, 4 GB de RAM y un disco SSD de 40–60 GB. Este servidor es adecuado para la aplicación, PostgreSQL, Redis y Caddy, pero la memoria disponible será limitada durante las actualizaciones y las copias de seguridad.

Escenario CPU RAM SSD Red
Pruebas y uso personal 2 vCPU 4 GB 40 GB 100 Mbit/s
Equipo pequeño 4 vCPU 8 GB 80 GB 100–1000 Mbit/s
Varias organizaciones o SaaS 8 vCPU 16 GB 160 GB NVMe 1 Gbit/s

Una opción inicial práctica es 4 vCPU, 8 GB de RAM, 80–100 GB NVMe, una copia de seguridad del disco o un almacenamiento de objetos independiente, además de una IPv4 pública. Puede contratar un VPS con estas características, siempre que cumpla los requisitos de sistema operativo, red y copias de seguridad.

Disco y copias de seguridad

El tamaño de la base de datos de Cal.com suele ser pequeño en comparación con los archivos de copia de seguridad y los registros. Aun así, no dimensione el disco al límite. Para un servidor con una base de datos de 10 GB, deje al menos 30–50 GB de espacio libre. Docker almacena imágenes, capas y contenedores antiguos, mientras que los registros pueden crecer cuando se producen errores de SMTP o de integraciones externas.

Es preferible almacenar las copias de seguridad en otro disco. Si un atacante elimina el servidor o se daña el sistema de archivos, un archivo local no será útil. Utilice un almacenamiento de objetos compatible con S3, un VPS independiente mediante SSH o un servidor remoto con Restic.

Cuándo se necesita un servidor dedicado

Un servidor dedicado para una sola instancia de Cal.com suele ser excesivo. Está justificado si en la misma máquina funcionan decenas de servicios, se necesita un rendimiento de disco garantizado, hay que alojar un clúster grande de PostgreSQL o la infraestructura debe estar aislada de otras máquinas virtuales.

Para una instalación normal, son más importantes un SSD rápido, una red estable, instantáneas periódicas y un procedimiento de recuperación claro que el tipo físico de servidor. Cuando aumente la carga, primero amplíe el VPS verticalmente y después traslade PostgreSQL y las tareas en segundo plano a nodos independientes.

Elección de la ubicación

La ubicación influye en la latencia de las solicitudes y en los requisitos relativos al tratamiento de datos personales. Elija un centro de datos cercano a los usuarios principales, pero tenga en cuenta dónde están alojados los calendarios externos, SMTP y el almacenamiento de objetos. Para las reuniones, una latencia de varias decenas de milisegundos rara vez es crítica; sin embargo, el acceso rápido a la interfaz se nota al trabajar con muchos eventos.

5. Preparación del servidor

A continuación se utiliza Ubuntu Server 24.04 LTS con una dirección IPv4. En el panel DNS, cree un registro A para calendar.example.com que apunte a la IP del servidor. Para emitir el certificado automáticamente, el dominio debe ser accesible desde Internet y los puertos 80 y 443 no deben estar bloqueados por un firewall externo.

Creación del administrador

Conéctese al servidor con el usuario inicial, normalmente root, y cree una cuenta administrativa independiente. No ejecute contenedores de producción como root salvo que sea necesario.

# Создаём пользователя для администрирования
adduser deploy

# Добавляем его в группу sudo
usermod -aG sudo deploy

# Проверяем наличие пользователя
id deploy

En el ordenador local, genere una clave SSH si aún no dispone de ella e instale la parte pública en el servidor.

# Выполняется на локальном компьютере
ssh-keygen -t ed25519 -C "deploy@calendar-server"

# Копируем ключ на сервер
ssh-copy-id deploy@SERVER_IP

# Проверяем вход по ключу
ssh deploy@SERVER_IP

Actualización de Ubuntu y paquetes básicos

# Обновляем индексы пакетов и устанавливаем исправления
sudo apt update && sudo apt full-upgrade -y

# Устанавливаем инструменты для администрирования и репозиториев
sudo apt install -y ca-certificates curl gnupg git jq unzip \
  htop vim ufw fail2ban unattended-upgrades

# Проверяем версию операционной системы
. /etc/os-release && echo "$PRETTY_NAME"

Después de la actualización, compruebe si es necesario reiniciar debido a un nuevo kernel.

# Показываем необходимость перезагрузки
if [ -f /var/run/reboot-required ]; then echo "Reboot required"; fi

# Перезагружаем сервер при необходимости
sudo reboot

Configuración de SSH

Antes de desactivar el acceso mediante contraseña, asegúrese de que la nueva clave SSH funciona en otra ventana de terminal. Después, cree un fragmento independiente de configuración.

# Запрещаем вход root и вход по паролю
sudo tee /etc/ssh/sshd_config.d/ hardening.conf >/dev/null <<'EOF'
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
EOF

# Проверяем синтаксис конфигурации SSH
sudo sshd -t

# Применяем настройки без разрыва существующей сессии
sudo systemctl reload ssh

En la primera línea del comando anterior no debe haber un espacio dentro de la ruta. La variante correcta, si el shell no acepta la escritura con espacio, es la siguiente:

sudo tee /etc/ssh/sshd_config.d/hardening.conf >/dev/null <<'EOF'
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
EOF

Firewall y fail2ban

Abra SSH, HTTP y HTTPS. Si SSH funciona en un puerto no estándar, sustituya 22/tcp por el valor correspondiente. Docker puede omitir algunas reglas de UFW para los puertos publicados, por lo que no publicaremos PostgreSQL ni Redis hacia el exterior.

# Разрешаем необходимые входящие соединения
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

# Включаем межсетевой экран
sudo ufw --force enable

# Проверяем правила
sudo ufw status verbose

# Включаем защиту SSH от перебора паролей
sudo systemctl enable --now fail2ban
sudo fail2ban-client status

Después de desactivar el acceso mediante contraseña, el filtro estándar de fail2ban para SSH sigue siendo útil, aunque la principal protección pasa a ser la autenticación mediante clave. Compruebe periódicamente los registros:

# Смотрим последние события SSH-защиты
sudo fail2ban-client status sshd

# Проверяем ошибки авторизации
sudo journalctl -u ssh --since "24 hours ago" --no-pager

6. Instalación del software — paso a paso

Paso 1. Instalación de Docker Engine

En 2026, utilice la rama estable actual de Docker Engine 28.x o una versión compatible más reciente. Los paquetes se instalan desde el repositorio oficial de Docker, no desde un script aleatorio ni desde un paquete antiguo del sistema.

# Создаём каталог для ключей репозиториев
sudo install -m 0755 -d /etc/apt/keyrings

# Загружаем ключ официального репозитория Docker
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
  sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

# Разрешаем чтение ключа пакетным менеджером
sudo chmod a+r /etc/apt/keyrings/docker.gpg

# Добавляем репозиторий для Ubuntu 24.04
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
  https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list >/dev/null

# Устанавливаем Docker Engine и Compose v2
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io \
  docker-buildx-plugin docker-compose-plugin

# Добавляем deploy в группу Docker
sudo usermod -aG docker "$USER"

# Проверяем версии
docker --version
docker compose version

Después de añadirlo al grupo Docker, cierre la sesión SSH y vuelva a conectarse. La pertenencia al grupo proporciona efectivamente privilegios de root a través de la API de Docker, por lo que solo debe añadir administradores de confianza.

Paso 2. Creación de los directorios del proyecto

# Создаём каталог приложения и каталог резервных копий
sudo mkdir -p /opt/calcom/{caddy,data,backups,db-init}

# Передаём каталог проекта административному пользователю
sudo chown -R "$USER":"$USER" /opt/calcom

# Переходим в рабочий каталог
cd /opt/calcom

Paso 3. Obtención de la plantilla oficial de Docker

La estructura de los archivos Docker de Cal.com cambia entre versiones. Para production, utilice el archivo Compose del repositorio oficial del proyecto y fije una etiqueta estable concreta, en lugar de una imagen nightly impredecible. A continuación se muestra una variante mínima independiente, adecuada para una instalación básica.

# Создаём файл переменных окружения
touch /opt/calcom/.env

# Ограничиваем права доступа к секретам
chmod 600 /opt/calcom/.env

# Переходим в каталог проекта
cd /opt/calcom

Paso 4. Generación de secretos

Cal.com utiliza secretos para las sesiones y el cifrado de los tokens de las integraciones. El valor de CALENDSO_ENCRYPTION_KEY no se puede cambiar después de crear las integraciones activas sin comprender las consecuencias: los tokens cifrados pueden dejar de estar disponibles.

# Генерируем секрет сессий длиной 64 hex-символа
openssl rand -hex 32

# Генерируем ключ шифрования Cal.com
openssl rand -hex 32

# Генерируем пароль PostgreSQL
openssl rand -base64 32

Copie los tres resultados en un archivo temporal protegido o directamente en .env. No envíe este archivo a Git, mensajeros ni sistemas de monitorización.

Paso 5. Preparación de Docker Compose

El ejemplo utiliza la imagen de Cal.com del registro oficial del proyecto, PostgreSQL 16 y Redis 7. En 2026, antes de actualizar, compruebe la etiqueta recomendada de Cal.com y la compatibilidad de las variables de entorno en la documentación de la versión correspondiente.

# Создаём Compose-файл
cat > /opt/calcom/compose.yml <<'EOF'
services:
  db:
    image: postgres:16-alpine
    restart: unless-stopped
    environment:
      POSTGRES_DB: ${POSTGRES_DB}
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    networks:
      - internal
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
      interval: 10s
      timeout: 5s
      retries: 10

  redis:
    image: redis:7-alpine
    restart: unless-stopped
    command: redis-server --appendonly yes
    volumes:
      - redis_data:/data
    networks:
      - internal
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 10

  calcom:
    image: ${CALCOM_IMAGE}
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy
    env_file:
      - .env
    environment:
      DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}
      REDIS_URL: redis://redis:6379
      NODE_ENV: production
      PORT: 3000
      HOSTNAME: 0.0.0.0
    expose:
      - "3000"
    networks:
      - internal
      - proxy

networks:
  internal:
    internal: true
  proxy:

volumes:
  postgres_data:
  redis_data:
EOF

# Проверяем синтаксис и подстановку переменных
docker compose config

Paso 6. Primer inicio de la base de datos y la aplicación

# Загружаем образы PostgreSQL, Redis и Cal.com
docker compose pull

# Запускаем контейнеры в фоне
docker compose up -d

# Проверяем состояние всех сервисов
docker compose ps

# Смотрим последние логи приложения
docker compose logs --tail=100 calcom

Durante el primer inicio, Cal.com puede ejecutar migraciones de la base de datos. No reinicie el contenedor varias veces seguidas hasta revisar los registros. Si la imagen requiere un comando de migración independiente, ejecútelo según la documentación de la versión concreta, por ejemplo mediante docker compose exec calcom.

Paso 7. Instalación de Caddy

Caddy se instalará en el host, no en un contenedor. Esto simplifica la obtención de certificados y permite hacer proxy de varios proyectos Docker mediante un único reverse proxy.

# Устанавливаем Caddy из официального репозитория
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl

curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | \
  sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg

curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | \
  sudo tee /etc/apt/sources.list.d/caddy-stable.list

sudo apt update
sudo apt install -y caddy

# Проверяем установленную версию
caddy version

Paso 8. Creación del administrador de Cal.com

Abra el dominio en el navegador después de configurar Caddy en la sección siguiente. Normalmente, el primer usuario registrado se convierte en el propietario de la instalación. Utilice una dirección de correo electrónico de trabajo, ya que sin SMTP algunas funciones de recuperación e invitación no funcionarán.

7. Configuración

Archivo de variables de entorno

Abra el archivo /opt/calcom/.env y complételo. Sustituya el valor de CALCOM_IMAGE por una etiqueta estable concreta publicada para su versión de Cal.com. No utilice latest en un entorno production crítico: una etiqueta flotante puede cambiar inesperadamente el esquema de la base de datos o el conjunto de variables.

sudo -u "$USER" tee /opt/calcom/.env >/dev/null <<'EOF'
# Версия образа Cal.com. Зафиксируйте стабильный тег текущего релиза.
CALCOM_IMAGE=calcom/cal.com:v5

# Основные параметры PostgreSQL
POSTGRES_DB=calcom
POSTGRES_USER=calcom
POSTGRES_PASSWORD=REPLACE_WITH_LONG_RANDOM_PASSWORD

# URL приложения
NEXTAUTH_URL=https://calendar.example.com
NEXT_PUBLIC_WEBAPP_URL=https://calendar.example.com

# Секрет сессий и ключ шифрования интеграций
NEXTAUTH_SECRET=REPLACE_WITH_64_HEX_CHARACTERS
CALENDSO_ENCRYPTION_KEY=REPLACE_WITH_64_HEX_CHARACTERS

# Настройки электронной почты
[email protected]
EMAIL_SERVER_HOST=smtp.example.net
EMAIL_SERVER_PORT=587
EMAIL_SERVER_USER=smtp-user
EMAIL_SERVER_PASSWORD=REPLACE_WITH_SMTP_PASSWORD
EMAIL_SERVER_SECURE=false

# Параметры окружения
NODE_ENV=production
NEXT_PUBLIC_LICENSE_CONSENT=agree
EOF

# Закрываем файл от чтения другими пользователями
chmod 600 /opt/calcom/.env

# Проверяем, что Docker видит обязательные переменные
docker compose config --environment

En algunas versiones, los nombres de las variables SMTP o de las configuraciones obligatorias pueden diferir. Compárelos con el ejemplo .env.example de la misma etiqueta de Cal.com. Esto es especialmente importante después de pasar de una versión principal a otra.

Configuración de Caddy y HTTPS

Cree el Caddyfile. Caddy solicitará automáticamente un certificado de Let’s Encrypt si el DNS ya apunta al servidor, los puertos 80 y 443 están abiertos y el dominio no está protegido por una autorización adicional.

# Создаём конфигурацию reverse proxy
sudo tee /etc/caddy/Caddyfile >/dev/null <<'EOF'
calendar.example.com {
    encode gzip zstd

    reverse_proxy 127.0.0.1:3000 {
        header_up Host {host}
        header_up X-Real-IP {remote_host}
        header_up X-Forwarded-For {remote_host}
        header_up X-Forwarded-Proto {scheme}
    }

    log {
        output file /var/log/caddy/calcom-access.log
        format json
    }
}
EOF

# Создаём каталог для журнала Caddy
sudo mkdir -p /var/log/caddy
sudo chown caddy:caddy /var/log/caddy

# Проверяем синтаксис Caddyfile
sudo caddy validate --config /etc/caddy/Caddyfile

# Запускаем и добавляем Caddy в автозагрузку
sudo systemctl enable --now caddy

# Перечитываем конфигурацию без остановки сервиса
sudo systemctl reload caddy

En el archivo Compose actual, el contenedor de Cal.com no publica el puerto 3000 en el host. Para que Caddy en el host pueda conectarse a la aplicación, añada la publicación del puerto únicamente en la interfaz loopback.

# Показываем фрагмент текущего Compose-файла
grep -A5 -B3 "expose" /opt/calcom/compose.yml

Sustituya el bloque expose dentro del servicio calcom por el siguiente:

ports:
  - "127.0.0.1:3000:3000"

Después del cambio, reinicie el contenedor:

# Пересоздаём только контейнер приложения с новым портом
cd /opt/calcom
docker compose up -d calcom

# Проверяем локальный ответ приложения
curl -I http://127.0.0.1:3000

# Проверяем статус Caddy
sudo systemctl status caddy --no-pager

# Проверяем HTTPS с сервера
curl -I https://calendar.example.com

Comprobación de la base de datos y Redis

# Проверяем готовность PostgreSQL
docker compose exec db pg_isready -U calcom -d calcom

# Проверяем Redis
docker compose exec redis redis-cli ping

# Проверяем состояние контейнеров
docker compose ps

# Просматриваем ошибки приложения за последние минуты
docker compose logs --since=10m calcom | grep -iE "error|warn|migration"

SMTP

Para el puerto SMTP estándar 587 normalmente se utiliza STARTTLS: EMAIL_SERVER_SECURE=false. Para SMTPS en el puerto 465 suele ser necesario EMAIL_SERVER_SECURE=true. No confunda el cifrado SMTP con HTTPS: el certificado del sitio no se encarga de la entrega de correo.

Después de cambiar las variables SMTP, vuelva a crear el contenedor para que reciba los nuevos valores:

# Пересоздаём приложение с обновлёнными SMTP-настройками
cd /opt/calcom
docker compose up -d --force-recreate calcom

# Проверяем журнал отправки и ошибок SMTP
docker compose logs --since=15m calcom | grep -iE "smtp|email|mail|error"

Para production, utilice un proveedor SMTP con credenciales independientes para la aplicación y límites de frecuencia de envío. No ejecute su propio servidor de correo en el mismo VPS sin necesidad: requerirá SPF, DKIM, DMARC, un registro DNS inverso, monitorización de la cola y control de la reputación de la IP.

Comprobación del inicio automático

# Проверяем, что контейнеры автоматически перезапускаются
docker inspect -f '{{.Name}}: {{.HostConfig.RestartPolicy.Name}}' \
  $(docker compose ps -q)

# Имитируем перезапуск Docker
sudo systemctl restart docker

# Убеждаемся, что сервисы вернулись
sleep 15
cd /opt/calcom
docker compose ps

8. Copias de seguridad y mantenimiento

Qué se debe guardar

  • Volcado de PostgreSQL: usuarios, eventos, configuraciones, comandos e integraciones.
  • Archivo .env: sin él no se pueden restaurar algunas conexiones y secretos.
  • compose.yml y la configuración de Caddy.
  • Docker volumes, si la versión seleccionada de Cal.com almacena archivos cargados o datos adicionales.
  • Claves de cifrado e información sobre el procedimiento de restauración.

La base de datos es la fuente principal del estado de Cal.com. No basta con copiar el contenedor: los contenedores se pueden recrear desde la imagen, mientras que los datos de PostgreSQL deben exportarse de forma coherente mediante pg_dump.

Instalación de Restic

Restic cifra los archivos antes de enviarlos al almacenamiento remoto. El ejemplo utiliza almacenamiento compatible con S3. Obtenga un bucket y una clave independientes con permisos mínimos: la aplicación de copias de seguridad no necesita permisos para toda la cuenta.

# Устанавливаем Restic из пакетов Ubuntu
sudo apt update
sudo apt install -y restic

# Проверяем версию
restic version

# Создаём каталог для временных дампов
sudo mkdir -p /opt/calcom/backup-work
sudo chown -R "$USER":"$USER" /opt/calcom/backup-work

Script de copia de seguridad

Cree el archivo /usr/local/sbin/calcom-backup. Es mejor guardar la contraseña del repositorio Restic y los parámetros de S3 en un archivo separado con permisos 600, en lugar de escribirlos directamente en el script.

# Создаём файл секретов Restic
sudo tee /root/.config/calcom-restic.env >/dev/null <<'EOF'
export RESTIC_REPOSITORY=s3:https://s3.example.net/calcom-backups
export AWS_ACCESS_KEY_ID=REPLACE_WITH_ACCESS_KEY
export AWS_SECRET_ACCESS_KEY=REPLACE_WITH_SECRET_KEY
export RESTIC_PASSWORD=REPLACE_WITH_LONG_REPOSITORY_PASSWORD
EOF

# Ограничиваем доступ к секретам
sudo chmod 600 /root/.config/calcom-restic.env

# Создаём скрипт резервного копирования
sudo tee /usr/local/sbin/calcom-backup >/dev/null <<'EOF'
#!/usr/bin/env bash
set -Eeuo pipefail

PROJECT=/opt/calcom
WORK="$PROJECT/backup-work"
STAMP="$(date -u +%Y%m%dT%H%M%SZ)"
DUMP="$WORK/calcom-$STAMP.sql.gz"

source /root/.config/calcom-restic.env
mkdir -p "$WORK"

# Создаём согласованный сжатый дамп PostgreSQL
cd "$PROJECT"
docker compose exec -T db \
  pg_dump -U "$POSTGRES_USER" -d "$POSTGRES_DB" --no-owner --no-acl \
  | gzip -9 > "$DUMP"

# Инициализируем репозиторий при первом запуске
restic snapshots >/dev/null 2>&1 || restic init

# Сохраняем дамп, конфигурацию и Compose-файл
restic backup "$DUMP" "$PROJECT/.env" "$PROJECT/compose.yml" \
  /etc/caddy/Caddyfile

# Удаляем локальные дампы старше двух дней
find "$WORK" -type f -name '.sql.gz' -mtime +2 -delete

# Удаляем старые удалённые снимки по политике хранения
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune
EOF

# Делаем скрипт исполняемым
sudo chmod 750 /usr/local/sbin/calcom-backup

El nombre de la base de datos y del usuario se toman de las variables del contenedor. Si el script ejecuta pg_dump con variables vacías, páselas explícitamente o cargue los valores desde un archivo protegido. Para este Compose puede sustituir la parte correspondiente por:

docker compose exec -T db \
  pg_dump -U calcom -d calcom --no-owner --no-acl \
  | gzip -9 > "$DUMP"

Primera ejecución y verificación del archivo

# Запускаем резервное копирование вручную
sudo /usr/local/sbin/calcom-backup

# Проверяем список снимков
sudo bash -c 'source /root/.config/calcom-restic.env && restic snapshots'

# Проверяем целостность последних данных
sudo bash -c 'source /root/.config/calcom-restic.env && restic check'

Programador cron

Ejecute la copia de seguridad por la noche, cuando la probabilidad de cambios activos en los datos sea menor. El volcado de PostgreSQL sigue siendo coherente incluso con la aplicación en funcionamiento, por lo que no es necesario detener Cal.com todos los días.

# Создаём ежедневное задание в cron
sudo tee /etc/cron.d/calcom-backup >/dev/null <<'EOF'
17 03    root /usr/local/sbin/calcom-backup >> /var/log/calcom-backup.log 2>&1
EOF

# Проверяем права и содержимое задания
sudo chmod 644 /etc/cron.d/calcom-backup
cat /etc/cron.d/calcom-backup

Realice periódicamente una restauración de prueba en un entorno temporal independiente. Una copia de seguridad que nunca se ha restaurado es solo una suposición de que los datos existen.

Actualización de Cal.com

No actualice production automáticamente a una etiqueta flotante. Primero lea las release notes, compruebe los requisitos de Node.js, PostgreSQL y las variables de entorno, y después realice una copia de seguridad completa.

# Сохраняем текущий список образов
cd /opt/calcom
docker compose images

# Делаем резервную копию перед обновлением
sudo /usr/local/sbin/calcom-backup

# Меняем CALCOM_IMAGE на новый проверенный тег
sudo vim /opt/calcom/.env

# Загружаем новый образ и пересоздаём приложение
docker compose pull calcom
docker compose up -d calcom

# Наблюдаем за миграциями и ошибками
docker compose logs -f --tail=200 calcom

Para un equipo pequeño, utilice una breve maintenance window e informe con antelación a los usuarios sobre una posible indisponibilidad. Una actualización rolling con dos instancias de la aplicación es posible, pero requiere un balanceador independiente, comprobación de compatibilidad de las migraciones y control de las tareas en segundo plano. Para un único VPS, es más segura una actualización secuencial con una reversión preparada.

Monitorización de recursos

# Показываем загрузку контейнеров
docker stats --no-stream

# Проверяем заполнение диска
df -h

# Проверяем размер Docker-данных
sudo du -sh /var/lib/docker

# Смотрим использование памяти
free -h

# Проверяем ошибки ядра и диска
sudo journalctl -p warning..alert --since "24 hours ago" --no-pager

Configure una alerta cuando el uso del disco supere el 80–85 por ciento. Un disco lleno en PostgreSQL puede provocar no solo la detención de las escrituras, sino también daños en los procesos de trabajo si el sistema no puede crear archivos temporales.

9. Resolución de problemas y FAQ

Cal.com responde con el error 502 Bad Gateway. ¿Qué comprobar?

Primero compruebe docker compose ps y los registros con el comando docker compose logs --tail=200 calcom. Después asegúrese de que el puerto 3000 esté publicado en 127.0.0.1 y de que la aplicación realmente lo esté escuchando: curl -I http://127.0.0.1:3000. Si el contenedor se reinicia constantemente, compruebe las variables obligatorias en .env, el estado de PostgreSQL y el resultado de las migraciones. En Caddy, el registro está disponible mediante journalctl -u caddy.

El certificado HTTPS no se emite. ¿Por qué?

Compruebe que el registro A del dominio apunte al IPv4 correcto y que el registro AAAA no apunte a una dirección IPv6 inaccesible. Los puertos 80 y 443 deben estar abiertos en UFW, el panel del proveedor y el firewall externo. Asegúrese de que otro servidor web no esté ocupando estos puertos: sudo ss -ltnp | grep -E ':80|:443'. Después de corregir el DNS, consulte el registro sudo journalctl -u caddy -n 100 y repita la recarga de Caddy.

Los correos no se envían, aunque el sitio se abre. ¿Qué hacer?

Compruebe el host SMTP, el puerto, el usuario, la contraseña y el modo TLS. Para el puerto 587 normalmente se necesita STARTTLS y el valor EMAIL_SERVER_SECURE=false; para el 465, la configuración SMTPS recomendada por su proveedor. Consulte los registros de Cal.com después de recrear el contenedor. También compruebe si el proveedor bloquea las conexiones SMTP salientes y si la dirección del remitente está autorizada. SPF, DKIM y DMARC afectan a la entregabilidad, pero no corrigen una autenticación SMTP incorrecta.

¿Qué error indica que Cal.com no se conecta a PostgreSQL?

Mensajes como ECONNREFUSED, password authentication failed o database does not exist indican un problema con la conexión o las variables. Dentro de Compose, el host debe ser el servicio db, no localhost. Compruebe docker compose exec db pg_isready -U calcom -d calcom, luego compare el nombre de la base de datos, el usuario y la contraseña en Compose y .env. Después de cambiar la contraseña, el volume existente de PostgreSQL no se reinicializa automáticamente.

¿Qué configuración de VPS es mínimamente adecuada?

Para una instalación de prueba o personal, bastan 2 vCPU, 4 GB de RAM y 40–60 GB de SSD. Para un equipo pequeño es mejor contar con 4 vCPU, 8 GB de RAM y al menos 80 GB de NVMe, especialmente si el servidor tendrá monitorización, copias de seguridad o servicios adicionales. Se necesitan Ubuntu 24.04 LTS, un IPv4 público, los puertos 80 y 443 abiertos y la capacidad de realizar conexiones HTTPS y SMTP salientes. Guarde las copias de seguridad aparte del VPS.

¿Qué elegir: VPS o dedicated para esta tarea?

Para un solo Cal.com o un equipo pequeño, elija VPS: los recursos son suficientes y el escalado se realiza cambiando de plan. Dedicated se justifica si el servidor atiende simultáneamente muchos proyectos, se requiere rendimiento de disco garantizado o existen requisitos de aislamiento físico. Por sí solo, dedicated no resuelve las cuestiones de seguridad ni de copias de seguridad. En ambos casos se necesitan actualizaciones, monitorización, almacenamiento independiente para copias de seguridad y un plan de restauración.

Después de la actualización desaparecieron las integraciones de calendario. ¿Cómo restaurar el funcionamiento?

Compruebe si CALENDSO_ENCRYPTION_KEY ha cambiado. Si la clave difiere de la que se utilizó al crear las integraciones, Cal.com podría no poder descifrar los tokens guardados. Restaure el valor anterior desde el almacenamiento protegido y reinicie el contenedor. Si la clave se ha perdido, restaure la base de datos junto con la clave original desde una copia de seguridad compatible. No elimine el volume de PostgreSQL hasta finalizar el diagnóstico y asegúrese de conservar los registros actuales.

El disco se llena rápidamente. ¿Qué acciones son seguras?

Compruebe df -h, docker system df, el tamaño de los directorios de Docker y los registros de Caddy. Elimine únicamente imágenes no utilizadas después de verificar que la versión necesaria ya está en ejecución: docker image prune no elimina imágenes en funcionamiento, pero ejecútelo de todos modos de forma consciente. Configure la rotación de registros para Docker y limite el período de conservación de los volcados locales. No elimine manualmente el volume de PostgreSQL ni el directorio /var/lib/docker/volumes.

10. Conclusiones y próximos pasos

Como resultado, Cal.com se ejecuta en Docker en un VPS, los datos se almacenan en PostgreSQL, las solicitudes están protegidas mediante HTTPS a través de Caddy y las notificaciones se envían mediante un servicio SMTP externo. Una copia de seguridad independiente con Restic guarda la base de datos, la configuración y los secretos en un repositorio remoto cifrado.

Como siguiente paso, configure la monitorización de disponibilidad, disco, memoria y vigencia del certificado. A medida que aumente la carga, traslade PostgreSQL a un nodo independiente, añada una segunda instancia de la aplicación y pruebe el procedimiento de restauración en un entorno limpio. Antes de cada actualización importante, registre la etiqueta actual de la imagen, realice una copia de seguridad y compruebe las migraciones en un servidor de staging.

¿Te fue útil esta guía?

Tus comentarios nos ayudan a mejorar nuestras guías.

Compartir esta publicación:

Envía esta guía a alguien a quien pueda resultarle útil.

Telegram VKVK WhatsApp Facebook LinkedIn XX

instalación de cal.com en VPS: Docker, PostgreSQL, SSL, SMTP y copias de seguridad
support_agent
Valebyte Support
Usually replies within minutes
Hi there!
Send us a message and we'll reply as soon as possible.