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

Obtener VPS arrow_forward
eco Principiante Tutorial/Cómo hacer

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

calendar_month Oct 21, 2026 schedule 18 min de lectura visibility 21 vistas
Установка OpenProject на 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 OpenProject en un VPS: Docker, PostgreSQL, SSL, SMTP y copias de seguridad

TL;DR

En esta guía desplegará OpenProject en un VPS mediante Docker Compose: contenedores independientes para la aplicación, PostgreSQL, Redis, el proxy inverso Caddy con SSL automático, SMTP para notificaciones y copias de seguridad automáticas de la base de datos y los archivos.

  • Para un equipo pequeño, basta con un VPS de 2 vCPU, 4 GB de RAM y 50–80 GB de disco NVMe.
  • OpenProject se ejecuta en Docker Compose con PostgreSQL 16 y Redis 7.
  • Caddy emite y renueva automáticamente los certificados de Let's Encrypt.
  • SMTP es necesario para invitaciones de usuarios, notificaciones de tareas y restablecimiento de contraseñas.
  • La copia de seguridad debe incluir PostgreSQL, el directorio de adjuntos de OpenProject y la configuración.
  • Antes de actualizar los contenedores, realice siempre una copia de seguridad verificable.

Qué configuramos y por qué

OpenProject es un sistema self-hosted de gestión de proyectos con tareas, tableros Kanban, diagramas de Gantt, wiki, control de tiempo, roles, paquetes de trabajo e integraciones. Es una opción adecuada si el equipo desea almacenar proyectos, conversaciones y adjuntos en su propia infraestructura, controlar las copias de seguridad y no depender de los planes de plataformas SaaS.

Como resultado, habrá una interfaz web protegida disponible en una dirección como https://projects.example.com. Los usuarios podrán recibir correos sobre asignación de tareas, cambios de estado, comentarios e invitaciones. Todos los componentes estarán aislados en contenedores Docker, por lo que la migración a otro servidor, la actualización y la recuperación serán notablemente más sencillas que con una instalación manual de una aplicación Ruby en el sistema.

Arquitectura del despliegue

Componente Propósito Acceso externo
OpenProject web Interfaz web, API, procesamiento de solicitudes Solo a través de Caddy
OpenProject worker Tareas en segundo plano, correo, notificaciones No
PostgreSQL 16 Base de datos principal de proyectos, usuarios y tareas No
Redis 7 Colas y caché de tareas en segundo plano No
Caddy 2 HTTPS, reverse proxy, certificados automáticos Puertos 80 y 443

Por qué Docker Compose

Docker Compose permite mantener la infraestructura junto con la configuración en un único directorio. Todas las dependencias se describen de forma declarativa: versiones de imágenes, volúmenes, redes, variables de entorno y orden de inicio. Si es necesario reemplazar el VPS, basta con instalar Docker, copiar el directorio del proyecto, restaurar los datos y ejecutar docker compose up -d.

No publique el puerto de PostgreSQL hacia el exterior. En este esquema, la base de datos solo está disponible para los contenedores de la red interna de Docker. Esto reduce la superficie de ataque y elimina la necesidad de mantener reglas de firewall independientes para la base de datos.

Self-hosted y servicio en la nube

Criterio Servicio en la nube OpenProject en un VPS
Mantenimiento El proveedor actualiza la plataforma Usted gestiona las actualizaciones y las copias de seguridad
Control de datos Los datos se encuentran en manos del operador del servicio Los datos y las claves de acceso están bajo su control
Flexibilidad Limitada por el plan y la política del servicio Puede cambiar SMTP, dominio, red, copias de seguridad e integraciones
Coste Normalmente depende de la cantidad de usuarios Depende principalmente de los recursos del servidor y del almacenamiento de copias de seguridad

OpenProject self-hosted está justificado para equipos que necesitan control sobre los datos, un dominio interno, su propia pasarela SMTP e integración con VPN o sistemas locales. Sin embargo, esta opción requiere disciplina: supervisión del espacio libre, pruebas de recuperación y actualizaciones periódicas de seguridad.

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

OpenProject consume considerablemente más recursos que un sitio web simple: se ejecutan la aplicación Ruby, los workers en segundo plano, PostgreSQL, Redis y el reverse proxy. Los principales factores de crecimiento son la cantidad de usuarios activos, el volumen de adjuntos, la intensidad de las notificaciones, el número de integraciones y el historial de proyectos.

Escenario vCPU RAM Disco NVMe Número de usuarios adecuado
Entorno de pruebas 2 4 GB 50 GB 1–10
Equipo pequeño 2–4 8 GB 80–160 GB 10–50
Equipo activo 4–6 16 GB 200 GB o más 50–150
Alta carga 8+ 32 GB+ Desde 500 GB 150+ o muchos adjuntos

Para un primer despliegue de production con 10–30 empleados, resulta práctica una configuración de 4 vCPU, 8 GB de RAM, 100 GB NVMe y una conexión de 100 Mbps o superior. Este margen permitirá a PostgreSQL mantener la caché de trabajo en memoria y a OpenProject atender simultáneamente a usuarios y tareas en segundo plano. Puede contratar un VPS con las características indicadas, pero lo principal es elegir un disco SSD/NVMe rápido y la posibilidad de ampliar recursos sin migración.

Cuánto espacio en disco reservar

Planifique espacio no solo para la aplicación. PostgreSQL crece junto con el historial de tareas, comentarios y auditorías, mientras que el directorio de adjuntos suele ocupar más que la propia base de datos. Para calcularlo, use la regla: volumen actual de datos × 3. Una parte es necesaria para el servicio en funcionamiento, la segunda para una copia de seguridad temporal local y la tercera como margen para actualizaciones, registros y crecimiento.

Por ejemplo, si los usuarios han cargado 25 GB de archivos y la base de datos ocupa 5 GB, un disco de 50 GB ya es arriesgado: un archivo local completo casi llenará el servidor. En ese caso, elija al menos 100–160 GB y envíe las copias de seguridad a un almacenamiento externo compatible con S3 o a un servidor independiente.

Cuándo se necesita un servidor dedicado en lugar de un VPS

Un VPS es adecuado para la mayoría de los equipos de hasta varias decenas de empleados activos. Un servidor dedicado tiene sentido cuando se necesita rendimiento garantizado de disco y CPU, la base de datos ha crecido, el número de usuarios simultáneos ha aumentado a cientos o cuando en la misma máquina se ejecutan GitLab, runners de CI, Nextcloud y otros servicios pesados.

También conviene migrar a un servidor dedicado ante requisitos de cumplimiento normativo que exijan aislamiento físico, o cuando PostgreSQL experimenta latencias constantes de entrada/salida. No intente compensar la falta de RAM con swap ilimitado: bajo carga, esto provoca una interfaz lenta y retrasos en las tareas en segundo plano.

Elección de ubicación

La ubicación influye en la latencia para los empleados, los requisitos de almacenamiento de datos personales y la velocidad de transferencia de adjuntos. Si el equipo se encuentra en Europa, elija un centro de datos cercano a los usuarios principales. Si OpenProject se utiliza solo a través de una VPN corporativa, ubique el VPS en la misma zona geográfica que la pasarela VPN.

Para el certificado SSL y el acceso público necesitará un nombre de dominio con un registro A que apunte a la dirección IPv4 del VPS. Antes de iniciar Caddy, cree un registro DNS, por ejemplo projects.example.com, y espere a que se propague.

Preparación del servidor

A continuación se utiliza Ubuntu Server 24.04 LTS, una versión estable con soporte a largo plazo, vigente para despliegues en 2026. Ejecute los comandos como un usuario con privilegios sudo. No ejecute Docker Compose como root sin necesidad: esto dificulta la auditoría y aumenta el riesgo de modificar archivos del sistema por accidente.

Actualización del sistema y utilidades básicas

Primero, conéctese al servidor mediante SSH, actualice los paquetes e instale utilidades para diagnóstico, firewall y bloqueo automático de intentos de contraseñas por fuerza bruta.

sudo apt update && sudo apt upgrade -y
sudo apt install -y curl ca-certificates gnupg ufw fail2ban jq unzip vim htop ncdu
sudo reboot

El primer comando instala las actualizaciones de seguridad, el segundo añade las herramientas necesarias y el reinicio aplica el nuevo kernel y las bibliotecas del sistema si se han actualizado.

Creación de un usuario independiente

Si el proveedor solo ha proporcionado acceso root, cree un usuario independiente llamado deploy. En adelante, será este usuario quien gestione el directorio de OpenProject y Docker Compose.

sudo adduser deploy
sudo usermod -aG sudo deploy
sudo mkdir -p /home/deploy/.ssh
sudo chmod 700 /home/deploy/.ssh

Añada la clave pública al archivo /home/deploy/.ssh/authorized_keys. Los permisos del archivo deben estar estrictamente restringidos; de lo contrario, SSH podría ignorar la clave.

sudo nano /home/deploy/.ssh/authorized_keys
sudo chown -R deploy:deploy /home/deploy/.ssh
sudo chmod 600 /home/deploy/.ssh/authorized_keys

Antes de desactivar el inicio de sesión root, abra una segunda conexión SSH y asegúrese de que el acceso como deploy mediante clave funciona. Solo después de comprobarlo, cambie la configuración de SSH.

sudo nano /etc/ssh/sshd_config.d/99-hardening.conf
sudo systemctl reload ssh

Añada los siguientes parámetros al archivo creado:

PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
KbdInteractiveAuthentication no
X11Forwarding no
AllowUsers deploy

Firewall y fail2ban

Abra únicamente SSH, HTTP y HTTPS. Si SSH no funciona en el puerto estándar, sustituya la regla OpenSSH por el número de puerto específico.

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose

Fail2ban supervisará los intentos fallidos de inicio de sesión mediante SSH y bloqueará temporalmente las direcciones IP. En Ubuntu basta con activar el servicio y comprobar su estado.

sudo systemctl enable --now fail2ban
sudo fail2ban-client status
sudo fail2ban-client status sshd

Comprobación de DNS antes de la instalación

En su ordenador o en el VPS, compruebe que el dominio apunta a la IP correcta. Caddy no podrá obtener un certificado de Let's Encrypt si el DNS aún no se ha actualizado o el puerto 80 está bloqueado por el firewall externo del panel del proveedor.

dig +short projects.example.com A
curl -4 ifconfig.me
sudo ss -lntp

La primera salida debe coincidir con la IPv4 pública del VPS. Antes de iniciar los contenedores, la ausencia de procesos escuchando en los puertos 80 y 443 es normal.

Instalación del software, paso a paso

Para la ejecución se utilizan Docker Engine 27+ y Docker Compose v2. Las imágenes se fijan en la versión principal: OpenProject 16, PostgreSQL 16, Redis 7 y Caddy 2. Antes de una actualización menor, revise el changelog de OpenProject y no use la etiqueta latest en producción: hace que las actualizaciones sean impredecibles.

Instalación de Docker Engine

Agregue el repositorio oficial de Docker para Ubuntu 24.04. Los comandos instalan el motor, la CLI, Buildx y el complemento Docker Compose.

sudo install -m 0755 -d /etc/apt/keyrings
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
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
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Agregue el usuario deploy al grupo Docker. Después deberá salir de la sesión SSH y volver a iniciar sesión para actualizar los grupos.

sudo usermod -aG docker deploy
sudo systemctl enable --now docker
docker --version
docker compose version

Creación del directorio de trabajo

Guarde los archivos compose y los secretos en un directorio accesible únicamente para el usuario deploy. Cree la estructura para Caddy, las copias de seguridad y las variables de entorno.

sudo -iu deploy
mkdir -p ~/openproject/{caddy,data,backups}
cd ~/openproject
umask 077
touch .env
chmod 600 .env

Ejecute los comandos posteriores ya como usuario deploy. El directorio ~/openproject/data se utilizará para los archivos persistentes de Caddy; los datos de OpenProject y PostgreSQL se almacenarán en Docker volumes.

Generación de secretos

Se necesitan valores aleatorios independientes para la base de datos, Rails y Redis. No utilice contraseñas cortas, palabras de diccionario ni un mismo secreto en todos los campos.

openssl rand -hex 32
openssl rand -base64 48
openssl rand -base64 32

Copie los resultados en el archivo .env. En el ejemplo siguiente, sustituya el dominio y las credenciales SMTP por valores reales.

nano ~/openproject/.env
OPENPROJECT_HOST=projects.example.com
POSTGRES_DB=openproject
POSTGRES_USER=openproject
POSTGRES_PASSWORD=REPLACE_WITH_LONG_DATABASE_PASSWORD
OPENPROJECT_SECRET_KEY_BASE=REPLACE_WITH_LONG_RAILS_SECRET
REDIS_PASSWORD=REPLACE_WITH_LONG_REDIS_PASSWORD

SMTP_ADDRESS=smtp.example.com
SMTP_PORT=587
SMTP_DOMAIN=example.com
[email protected]
SMTP_PASSWORD=REPLACE_WITH_SMTP_PASSWORD
SMTP_FROM=OpenProject <[email protected]>

Creación del archivo Docker Compose

El siguiente archivo crea una red interna para la aplicación, la base de datos y Redis. Solo se publican externamente los puertos de Caddy. Los contenedores de OpenProject utilizan la misma imagen, pero desempeñan funciones diferentes: servidor web y procesador de colas.

nano ~/openproject/compose.yml
services:
  db:
    image: postgres:16-alpine
    container_name: openproject-db
    restart: unless-stopped
    environment:
      POSTGRES_DB: ${POSTGRES_DB}
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
      interval: 10s
      timeout: 5s
      retries: 10
    networks:
      - backend

  redis:
    image: redis:7-alpine
    container_name: openproject-redis
    restart: unless-stopped
    command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD}
    volumes:
      - redisdata:/data
    healthcheck:
      test: ["CMD-SHELL", "redis-cli -a \"$${REDIS_PASSWORD}\" ping | grep PONG"]
      interval: 10s
      timeout: 5s
      retries: 10
    environment:
      REDIS_PASSWORD: ${REDIS_PASSWORD}
    networks:
      - backend

  web:
    image: openproject/openproject:16
    container_name: openproject-web
    restart: unless-stopped
    command: "./docker/prod/web"
    env_file: .env
    environment:
      DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}
      OPENPROJECT_HOST__NAME: ${OPENPROJECT_HOST}
      OPENPROJECT_HTTPS: "true"
      OPENPROJECT_HSTS: "true"
      OPENPROJECT_SECRET_KEY_BASE: ${OPENPROJECT_SECRET_KEY_BASE}
      OPENPROJECT_CACHE__MEMCACHE__SERVER: redis:6379
      OPENPROJECT_EMAIL__DELIVERY__METHOD: smtp
      OPENPROJECT_SMTP__ADDRESS: ${SMTP_ADDRESS}
      OPENPROJECT_SMTP__PORT: ${SMTP_PORT}
      OPENPROJECT_SMTP__DOMAIN: ${SMTP_DOMAIN}
      OPENPROJECT_SMTP__AUTHENTICATION: login
      OPENPROJECT_SMTP__USER_NAME: ${SMTP_USERNAME}
      OPENPROJECT_SMTP__PASSWORD: ${SMTP_PASSWORD}
      OPENPROJECT_SMTP__ENABLE_STARTTLS_AUTO: "true"
      OPENPROJECT_EMAIL__FROM: ${SMTP_FROM}
    volumes:
      - opdata:/var/openproject/assets
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy
    networks:
      - backend
      - proxy

  worker:
    image: openproject/openproject:16
    container_name: openproject-worker
    restart: unless-stopped
    command: "./docker/prod/worker"
    env_file: .env
    environment:
      DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}
      OPENPROJECT_HOST__NAME: ${OPENPROJECT_HOST}
      OPENPROJECT_HTTPS: "true"
      OPENPROJECT_SECRET_KEY_BASE: ${OPENPROJECT_SECRET_KEY_BASE}
      OPENPROJECT_CACHE__MEMCACHE__SERVER: redis:6379
      OPENPROJECT_EMAIL__DELIVERY__METHOD: smtp
      OPENPROJECT_SMTP__ADDRESS: ${SMTP_ADDRESS}
      OPENPROJECT_SMTP__PORT: ${SMTP_PORT}
      OPENPROJECT_SMTP__DOMAIN: ${SMTP_DOMAIN}
      OPENPROJECT_SMTP__AUTHENTICATION: login
      OPENPROJECT_SMTP__USER_NAME: ${SMTP_USERNAME}
      OPENPROJECT_SMTP__PASSWORD: ${SMTP_PASSWORD}
      OPENPROJECT_SMTP__ENABLE_STARTTLS_AUTO: "true"
      OPENPROJECT_EMAIL__FROM: ${SMTP_FROM}
    volumes:
      - opdata:/var/openproject/assets
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy
    networks:
      - backend

  caddy:
    image: caddy:2-alpine
    container_name: openproject-caddy
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    environment:
      OPENPROJECT_HOST: ${OPENPROJECT_HOST}
    volumes:
      - ./caddy/Caddyfile:/etc/caddy/Caddyfile:ro
      - caddydata:/data
      - caddyconfig:/config
    depends_on:
      - web
    networks:
      - proxy

volumes:
  pgdata:
  redisdata:
  opdata:
  caddydata:
  caddyconfig:

networks:
  backend:
    internal: true
  proxy:

El parámetro internal: true impide que los contenedores de la red backend tengan conexión externa directa. Caddy se encuentra simultáneamente en la red proxy y puede enviar solicitudes al contenedor web.

Verificación de sintaxis e inicio

Docker Compose sustituirá los valores del archivo .env, pero no muestre la configuración resultante en registros públicos: contendrá contraseñas. Primero descargue las imágenes y después inicie la pila en segundo plano.

cd ~/openproject
docker compose config --quiet
docker compose pull
docker compose up -d
docker compose ps

El primer inicio puede tardar varios minutos: OpenProject prepara la base de datos y ejecuta las migraciones. Supervise los registros hasta que la aplicación web indique que está lista para aceptar solicitudes.

docker compose logs -f web
docker compose logs -f worker
docker compose ps

Configuración de OpenProject, SSL y SMTP

Configuración de Caddy y HTTPS

Caddy solicita automáticamente un certificado Let's Encrypt, redirige HTTP a HTTPS y renueva el certificado. Para ello, el registro DNS del dominio debe apuntar al servidor, y los puertos 80 y 443 deben estar abiertos tanto en UFW como en el firewall de red del panel VPS.

nano ~/openproject/caddy/Caddyfile
{$OPENPROJECT_HOST} {
    encode zstd gzip

    reverse_proxy web:8080 {
        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 stdout
        format console
    }
}

Después de guardar, reinicie solo Caddy. Durante los primeros minutos obtendrá el certificado y lo guardará en el Docker volume persistente caddydata.

cd ~/openproject
docker compose up -d caddy
docker compose logs -f caddy

Si el certificado no se emite, no desactive HTTPS en OpenProject. Primero compruebe el DNS, los puertos abiertos y que no haya otro proceso que ya esté ocupando el 80 o el 443.

Verificación de la interfaz web

Después de un inicio correcto, abra en el navegador la dirección https://projects.example.com. En la primera pantalla, OpenProject propondrá crear un administrador. Utilice una contraseña larga y única, y guárdela en un gestor de contraseñas.

Desde el servidor, compruebe la respuesta HTTP, TLS y el estado de los contenedores. El código 200, 302 o la página de inicio de sesión indican que el proxy funciona. Los errores 502 suelen indicar un problema con el contenedor web.

curl -I http://projects.example.com
curl -Ik https://projects.example.com
docker compose ps
docker stats --no-stream

Verificación de PostgreSQL y Redis

No es necesario abrir PostgreSQL al exterior para comprobarlo. Utilice comandos dentro de la red Docker. Mostrarán que la base de datos acepta conexiones y que Redis responde a las solicitudes.

docker compose exec db pg_isready -U openproject -d openproject
docker compose exec db psql -U openproject -d openproject -c "SELECT version();"
docker compose exec redis redis-cli -a "$REDIS_PASSWORD" ping

El último comando se ejecuta desde un shell donde está disponible la variable de .env. Si abrió una sesión nueva, primero vaya al directorio del proyecto y cargue las variables con el comando set -a; . ./.env; set +a.

SMTP para notificaciones

OpenProject utiliza SMTP para invitaciones, recordatorios, notificaciones de tareas y recuperación de acceso. Sin un correo saliente correctamente configurado, los usuarios podrán trabajar en la interfaz, pero no recibirán eventos importantes por email.

En el archivo .env, utilice un usuario SMTP autorizado para enviar desde la dirección indicada en SMTP_FROM. Para la mayoría de proveedores externos son adecuados el puerto 587 y STARTTLS. El puerto 465 normalmente requiere SSL desde el inicio de la conexión y puede necesitar una configuración independiente, por lo que para el primer inicio elija 587 si es posible.

Después de modificar las variables SMTP, aplique la configuración reiniciando web y worker. A continuación, abra la configuración administrativa de correo en la interfaz web y envíe un mensaje de prueba a una dirección personal.

cd ~/openproject
docker compose up -d --force-recreate web worker
docker compose logs --tail=100 worker
docker compose logs --tail=100 web

Si el correo no se envía, busque en los registros errores de autenticación, TLS o DNS. No introduzca la contraseña SMTP en la línea de comandos: permanecerá en el historial del shell. Guárdela únicamente en .env con permisos 600.

Configuración básica después del primer inicio de sesión

  1. Cree una cuenta de administrador independiente para el trabajo diario y mantenga la cuenta de administrador de emergencia por separado.
  2. Compruebe que la URL de instalación sea correcta en la configuración administrativa, para que los enlaces de los correos dirijan al dominio HTTPS.
  3. Cree los roles: administrador, jefe de proyecto, participante, observador y cliente externo.
  4. Configure los campos obligatorios de las tareas, los tipos de paquetes de trabajo y los estados según el proceso del equipo.
  5. Restrinja el registro autónomo si el sistema está destinado únicamente al equipo interno.

No guarde secretos en compose.yml ni agregue el archivo .env al repositorio Git. La pérdida de OPENPROJECT_SECRET_KEY_BASE puede complicar la recuperación de sesiones y datos cifrados, por lo que debe incluirse en una copia de seguridad protegida de la configuración.

Copias de seguridad y mantenimiento

Un OpenProject en funcionamiento sin copia de seguridad es una instalación temporal. Para una restauración completa no bastan los datos de PostgreSQL. Es necesario conservar los adjuntos de los usuarios, los secretos de .env, el archivo compose, el Caddyfile y los datos de Caddy que contienen certificados e información de servicio.

Qué respaldar exactamente

Datos Dónde se encuentran Criticidad
Base de datos de OpenProject Docker volume pgdata Crítico
Adjuntos y assets Docker volume opdata Crítico
Secretos y configuración ~/openproject/.env, compose.yml, Caddyfile Crítico
Certificados de Caddy Docker volume caddydata Recomendado
Redis Docker volume redisdata No obligatorio, pero útil

Para PostgreSQL, use un volcado lógico pg_dump, no una simple copia de los archivos de una base de datos en ejecución. Un volcado lógico se puede restaurar en una nueva versión del host y verificar por separado. Para los Docker volumes con adjuntos, use un archivo mediante un contenedor Alpine temporal.

Script de copia de seguridad local

Cree un script que genere un volcado de la base de datos y archive el volumen de adjuntos y la configuración. El script conserva las copias locales durante siete días; esto no es suficiente como única protección, por lo que a continuación se añade el envío a almacenamiento externo.

mkdir -p ~/openproject/scripts
nano ~/openproject/scripts/backup.sh
chmod 700 ~/openproject/scripts/backup.sh
#!/usr/bin/env bash
set -euo pipefail

BASE_DIR="$HOME/openproject"
BACKUP_DIR="$BASE_DIR/backups"
DATE="$(date +%F_%H-%M-%S)"
ARCHIVE="$BACKUP_DIR/$DATE"

mkdir -p "$ARCHIVE"
cd "$BASE_DIR"

set -a
. ./.env
set +a

docker compose exec -T db pg_dump \
  -U "$POSTGRES_USER" \
  -d "$POSTGRES_DB" \
  --format=custom \
  --file=/tmp/openproject.dump

docker cp openproject-db:/tmp/openproject.dump "$ARCHIVE/openproject.dump"
docker compose exec -T db rm -f /tmp/openproject.dump

docker run --rm \
  -v openproject_opdata:/source:ro \
  -v "$ARCHIVE":/backup \
  alpine:3.20 \
  tar czf /backup/opdata.tar.gz -C /source .

tar czf "$ARCHIVE/config.tar.gz" \
  .env compose.yml caddy/Caddyfile scripts/backup.sh

sha256sum "$ARCHIVE"/ > "$ARCHIVE/SHA256SUMS"
find "$BACKUP_DIR" -mindepth 1 -maxdepth 1 -type d -mtime +7 -exec rm -rf {} \;

echo "Copia de seguridad completada: $ARCHIVE"

Antes de automatizarlo, ejecute el script manualmente. Compruebe el tamaño de los archivos: el volcado de la base de datos no debe estar vacío y el archivo opdata.tar.gz debe contener adjuntos, si ya existen.

~/openproject/scripts/backup.sh
ls -lh ~/openproject/backups/$(date +%F)
cat ~/openproject/backups/$(date +%F)/SHA256SUMS

Envío de copias de seguridad a S3 mediante restic

Una copia local no protegerá ante la eliminación del VPS, un fallo de disco o la vulneración del servidor. Guarde una segunda copia en un almacenamiento compatible con S3 independiente, en otro centro de datos o en un servidor separado. Restic cifra los datos del lado del cliente antes de cargarlos.

sudo apt install -y restic
mkdir -p ~/.config/restic
chmod 700 ~/.config/restic
nano ~/.config/restic/openproject.env
chmod 600 ~/.config/restic/openproject.env
RESTIC_REPOSITORY=s3:https://s3.example.com/openproject-backups
RESTIC_PASSWORD=REPLACE_WITH_LONG_RESTIC_REPOSITORY_PASSWORD
AWS_ACCESS_KEY_ID=REPLACE_WITH_ACCESS_KEY
AWS_SECRET_ACCESS_KEY=REPLACE_WITH_SECRET_KEY

Inicialice el repositorio una vez y luego añada el envío al final del script, después de crear las sumas de comprobación.

set -a
. ~/.config/restic/openproject.env
set +a
restic init

Añada los siguientes comandos a backup.sh antes de la línea echo:

set -a
. "$HOME/.config/restic/openproject.env"
set +a
restic backup "$ARCHIVE"
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune

Ejecución automática mediante cron

Ejecute la copia de seguridad por la noche, por ejemplo a las 03:30. Cron redirige la salida a un registro para poder detectar rápidamente un error de carga o falta de espacio.

crontab -e
30 3    /home/deploy/openproject/scripts/backup.sh >> /home/deploy/openproject/backups/backup.log 2>&1

Una vez al mes, compruebe el repositorio y realice una restauración de prueba en otra máquina o en un directorio separado. Una copia de seguridad se considera válida solo después de una restauración correcta.

set -a
. ~/.config/restic/openproject.env
set +a
restic snapshots
restic check
restic restore latest --target /tmp/openproject-restore-test

Actualizaciones de OpenProject y la infraestructura

Para un equipo pequeño, es mejor realizar las actualizaciones durante una maintenance window. OpenProject puede aplicar migraciones de base de datos, por lo que no actualice los contenedores en plena jornada laboral. Primero lea las notas de la versión, haga una copia de seguridad y luego descargue la imagen y reinicie los servicios.

cd ~/openproject
./scripts/backup.sh
docker compose pull
docker compose up -d
docker compose logs --tail=100 web
docker compose ps

Una actualización rolling con varios contenedores web solo tiene sentido con un balanceador independiente, PostgreSQL externo y un esquema de migraciones probado. Para un único VPS, es más adecuado un breve periodo de mantenimiento: activar una notificación para el equipo, actualizar el stack, comprobar el inicio de sesión, la creación de una tarea, los adjuntos y el envío de un correo de prueba.

Compruebe semanalmente el estado del disco, el consumo de memoria y el tamaño de los objetos Docker. No ejecute sin pensar docker system prune -a: el comando puede eliminar imágenes necesarias para una reversión rápida. Elimine únicamente las imágenes no utilizadas después de revisar la lista.

df -h
free -h
docker system df
docker compose logs --since=24h --tail=200 web
sudo journalctl -u docker --since "24 hours ago"

Solución de problemas + FAQ

¿Por qué Caddy muestra un error al obtener el certificado SSL?

Primero compruebe que el registro A del dominio apunta a la IPv4 pública del VPS: dig +short projects.example.com. Después asegúrese de que los puertos 80 y 443 estén permitidos en UFW y en el panel de protección de red. El error también ocurre si otro proceso ya escucha el puerto 80: compruébelo con el comando sudo ss -lntp '( sport = :80 or sport = :443 )'. Después de corregirlo, reinicie Caddy mediante docker compose restart caddy.

¿Por qué el sitio responde 502 Bad Gateway?

El código 502 significa que Caddy está disponible, pero no puede conectarse al contenedor de OpenProject. Ejecute docker compose ps y asegúrese de que el contenedor openproject-web tenga el estado Up. Luego consulte los últimos registros: docker compose logs --tail=150 web. Las causas frecuentes son una migración de base de datos fallida, un error en la variable DATABASE_URL, falta de memoria o un PostgreSQL no saludable. Corrija el error inicial y ejecute docker compose up -d.

OpenProject se reinicia constantemente después de iniciarse. ¿Qué hacer?

Primero consulte la causa mediante docker compose logs --tail=200 web y docker compose logs --tail=200 worker. Si los registros contienen OOMKilled, el VPS no tiene memoria suficiente: para producción use al menos 4 GB de RAM, y preferiblemente 8 GB. Si el error está relacionado con la base de datos, compruebe docker compose logs db y el estado de pg_isready. Asegúrese también de que OPENPROJECT_SECRET_KEY_BASE no esté vacío ni cambie entre reinicios.

¿Por qué no se envían correos mediante SMTP?

Compruebe los registros de web y worker: los errores de autenticación suelen contener 535, y los errores TLS mencionan un certificado o handshake. Para la mayoría de los proveedores SMTP, use el puerto 587, OPENPROJECT_SMTP__ENABLE_STARTTLS_AUTO=true y una contraseña de aplicación en lugar de la contraseña principal de la cuenta. Asegúrese de que la dirección SMTP_FROM esté permitida por el proveedor. Después de modificar .env, vuelva a crear los contenedores web y worker con el indicador --force-recreate.

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

Para pruebas o un equipo de hasta diez personas, el mínimo es un VPS con 2 vCPU, 4 GB de RAM y 50 GB de SSD/NVMe. Es adecuado con pocos adjuntos y actividad moderada. Para un equipo de trabajo real, es mejor elegir desde el principio 4 vCPU, 8 GB de RAM y 80–100 GB de NVMe: PostgreSQL obtiene más caché, las tareas en segundo plano no interfieren con la interfaz web y queda espacio en disco para copias de seguridad temporales. No ahorre en la velocidad del disco.

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

Para la mayoría de las instalaciones de OpenProject, un VPS es suficiente: es más económico, se escala más rápido y resulta adecuado para equipos de hasta varias decenas de usuarios. Se necesita dedicated con cientos de usuarios activos, grandes volúmenes de archivos, alta carga en PostgreSQL, requisitos estrictos de aislamiento físico o si se ejecutan servicios pesados en la misma máquina. Una vía práctica es comenzar con un VPS con margen de RAM y disco, medir la carga y migrar solo cuando sea realmente necesario.

¿Cómo restaurar OpenProject desde una copia de seguridad?

En el nuevo servidor, implemente Docker y el mismo directorio de configuración compose, pero no inicie OpenProject antes de restaurar los datos. Cree los volúmenes con el comando docker compose up -d db redis, importe el volcado mediante pg_restore en el contenedor PostgreSQL y extraiga opdata.tar.gz en el Docker volume openproject_opdata. Restaure el archivo original .env, especialmente el secreto de Rails, luego inicie todo el stack y compruebe el inicio de sesión, los proyectos y los adjuntos.

El disco se llena rápidamente. ¿Qué datos se pueden eliminar?

Primero determine el origen del crecimiento: df -h, docker system df, du -sh ~/openproject/backups y docker volume ls. Normalmente, el espacio lo ocupan las copias de seguridad locales, los adjuntos de usuarios o los registros de contenedores. Reduzca el período de conservación de los archivos locales solo después de enviarlos correctamente al almacenamiento externo. No elimine manualmente los Docker volumes de PostgreSQL u OpenProject: esto destruirá los datos en producción. Para los registros, configure la rotación de Docker y controle los tamaños.

Conclusiones y próximos pasos

Ahora OpenProject funciona en un VPS con Docker Compose, utiliza PostgreSQL y Redis, está disponible mediante HTTPS a través de Caddy, envía notificaciones por SMTP y cuenta con copias de seguridad automatizadas. Este esquema es adecuado para un equipo pequeño o mediano y permite controlar los datos, las actualizaciones y la restauración.

  1. Pruebe la restauración de la última copia de seguridad en un servidor independiente o en un entorno Docker aislado.
  2. Configure la monitorización de CPU, RAM, espacio libre, disponibilidad de HTTPS y estado de las copias de seguridad.
  3. A medida que crezca el equipo, traslade PostgreSQL a un servidor independiente, añada S3 externo para los adjuntos y prepare un plan de actualizaciones sin tiempos de inactividad prolongados.

¿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 OpenProject 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.