SSD Nodes Learn Hosting plans →
Guías Matt ConnorPor Matt Connor

Cómo alojar Planka con Docker Compose en un VPS

Despliega Planka 2 con Docker Compose, Postgres y Traefik. Configura las variables de administrador y evita el error de inicio de sesión causado por BASE_URL.

Lo que se obtiene al alojar Planka por cuenta propia

Alojar Planka por cuenta propia proporciona al equipo un tablero Kanban con el modelo de tarjetas, listas y etiquetas que ya conocen de Trello, ejecutándose en un VPS bajo su control. No hay límites de usuarios ni facturación por usuario, porque el único coste es el servidor. Esta guía lo implementa con Docker Compose detrás de Traefik, usa Postgres para los datos y un volumen con nombre para cada archivo que carguen los usuarios.

Planka 2 se distribuye bajo la Fair Use License propia del proyecto, que el proyecto describe como disponible para consultar el código fuente, no como software de código abierto. Se permite usarlo en los proyectos internos de su propia organización. Ofrecerlo a terceros como servicio alojado comercial requiere una licencia Pro o Enterprise.

El lector al que va dirigida esta guía forma parte de un equipo de dos a cinco personas que deja el nivel gratuito de Trello. Si todavía está decidiendo qué tablero usar, lea primero la comparación de alternativas autoalojadas a Trello. Esta guía da por tomada esa decisión y sólo cubre la implementación.

Necesita un VPS con Docker Engine y el complemento Compose, además de un registro DNS A que apunte a él. También necesita una instancia de Traefik que ya gestione la terminación TLS (seguridad de la capa de transporte) en ese servidor. Si todavía no tiene Traefik, configure primero un proxy inverso de Traefik delante de varias aplicaciones Compose y lea los conceptos básicos de Docker Compose para un VPS si el archivo siguiente no le resulta familiar.

¿Cuántos recursos de VPS necesita Planka?

El proyecto no publica unos requisitos mínimos de hardware, así que considere cualquier cifra que lea como un punto de partida, no como una medición. La cifra de 2 vCPU y 4 GB que repiten las páginas de hosting es un valor predeterminado cómodo del proveedor, no un requisito medido por el proyecto. Es una configuración generosa para un tablero que usan cinco personas.

El funcionamiento real es sencillo: un proceso de Node.js sirve la API y el frontend compilado, y un servidor de Postgres almacena los datos. Postgres ejecuta un proceso supervisor y un proceso backend por cada conexión abierta. Dentro del contenedor de Planka también se ejecuta un proceso proxy pequeño que filtra sus solicitudes salientes. Un plan con 1 vCPU y 2 GB admite un tablero usado por entre dos y cinco personas. La mayor parte de la memoria libre termina como caché de Postgres. Un tablero consume pocos recursos, así que, si el mismo VPS también debe alojar los documentos de su equipo, dimensione primero para esa aplicación: ejecutar AFFiNE como espacio de trabajo al estilo de Notion necesita un par de gigabytes por sí solo antes de que Planka requiera recursos adicionales.

Dimensione el disco antes que la memoria, porque los archivos adjuntos son lo que más crece. Mida su propia instancia en lugar de confiar en este párrafo:

docker stats --no-stream
docker system df -v

El primer comando muestra en tiempo real la memoria y la CPU de cada contenedor. El segundo indica cuánto espacio ocupa cada volumen. Realice ambas mediciones después de una semana normal de trabajo, no el día de la instalación, porque un tablero inactivo no dice nada sobre su equipo.

Escriba el archivo Compose

Cree el directorio y cambie su propietario para no tener que editar estos archivos mediante sudo.

sudo mkdir -p /opt/planka
sudo chown "$USER":"$USER" /opt/planka
cd /opt/planka

Genere los secretos en un archivo .env junto al archivo Compose. Compose lee ese archivo automáticamente y sustituye los valores.

umask 077
{
  printf 'SECRET_KEY=%s\n' "$(openssl rand -hex 64)"
  printf 'POSTGRES_PASSWORD=%s\n' "$(openssl rand -hex 24)"
  printf 'ADMIN_PASSWORD=%s\n' "$(openssl rand -hex 12)"
} > .env
chmod 600 .env

openssl rand -hex es intencionado. Una cadena hexadecimal sólo contiene dígitos y las letras de la a a la f, por lo que no puede romper la cadena de conexión de DATABASE_URL en la que se inserta. Una contraseña en base64 que contenga una barra o un signo de arroba provoca un error de conexión que parece indicar que el nombre de host es incorrecto. Eso puede hacerle perder una hora. El patrón general se explica en mantener los secretos fuera del archivo Compose.

Ahora docker-compose.yml. Sustituya kanban.example.com por su propio nombre de host en los dos lugares donde aparece.

services:
  planka:
    image: ghcr.io/plankanban/planka:2.2.1
    restart: unless-stopped
    volumes:
      - planka-data:/app/data
    environment:
      - BASE_URL=https://kanban.example.com
      - DATABASE_URL=postgresql://planka:${POSTGRES_PASSWORD}@postgres/planka
      - SECRET_KEY=${SECRET_KEY}
      - TRUST_PROXY=true
      - DEFAULT_ADMIN_EMAIL=you@example.com
      - DEFAULT_ADMIN_PASSWORD=${ADMIN_PASSWORD}
      - DEFAULT_ADMIN_NAME=Your Name
      - DEFAULT_ADMIN_USERNAME=admin
    networks:
      - proxy
      - internal
    labels:
      - "traefik.enable=true"
      - "traefik.docker.network=proxy"
      - "traefik.http.routers.planka.rule=Host(`kanban.example.com`)"
      - "traefik.http.routers.planka.entrypoints=websecure"
      - "traefik.http.routers.planka.tls.certresolver=default"
      - "traefik.http.services.planka.loadbalancer.server.port=1337"
    depends_on:
      postgres:
        condition: service_healthy

  postgres:
    image: postgres:16-alpine
    restart: unless-stopped
    volumes:
      - db-data:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=planka
      - POSTGRES_USER=planka
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
    networks:
      - internal
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U planka -d planka"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  planka-data:
  db-data:

networks:
  proxy:
    external: true
  internal:

Conviene explicar cuatro decisiones de ese archivo. Son las que más suelen cambiarse y lamentarse después.

  • No hay ningún bloque ports: en el servicio Planka. Traefik llega al contenedor a través de la red proxy, por lo que el puerto 1337 nunca se publica en el host. Publicarlo permitiría a cualquiera eludir el proxy y el certificado.
  • loadbalancer.server.port=1337 especifica el puerto dentro del contenedor. Planka escucha en 1337, y el ejemplo original sólo llega a él en 3000 porque asigna el puerto al host. Aquí no hay ninguna asignación al host, por lo que debe indicar a Traefik el puerto del contenedor.
  • condition: service_healthy se combina con el healthcheck de Postgres. Sin esta opción, Planka se inicia antes de que la base de datos acepte conexiones, falla en su primera consulta y termina. Esto parece un bucle de reinicios. El funcionamiento se explica en healthchecks y orden de inicio en Compose.
  • El servicio de base de datos se llama postgres de forma intencionada. Planka 2 dirige sus propias solicitudes salientes mediante un filtro interno cuya lista de bloqueo predeterminada es localhost,postgres. Si cambia el nombre del servicio, elimina silenciosamente la base de datos de esa lista.

Compruebe que Compose puede ver los secretos antes de iniciar nada:

docker compose config | grep -E 'image:|BASE_URL|POSTGRES_USER'

El comando muestra el archivo con los valores de .env ya sustituidos. Un valor vacío significa que Compose no está leyendo el archivo .env, normalmente porque ejecuta el comando desde otro directorio.

Qué hacen realmente las variables de inicialización del administrador

Desde Planka 1.13 no se crea ningún administrador automáticamente, por lo que una base de datos nueva no tiene usuarios que puedan iniciar sesión. El grupo DEFAULT_ADMIN_* es una de las dos formas de resolverlo.

Al iniciar, Planka busca un usuario que coincida con DEFAULT_ADMIN_EMAIL. Si no existe, crea uno usando la contraseña, el nombre visible y el nombre de usuario definidos junto a esa variable. Esto ocurre durante el primer arranque con una base de datos vacía, por lo que estas variables sirven para inicializar una cuenta, no para administrarla.

DEFAULT_ADMIN_EMAIL cumple una segunda función que suele causar problemas. Mientras la variable esté definida, nadie puede editar ni eliminar desde la interfaz la cuenta que indica, ni siquiera otro administrador. Es una protección contra el bloqueo de acceso. También explica por qué no se puede cambiar el nombre de esa cuenta ni su dirección de correo electrónico desde la interfaz. Elimine la variable y reinicie. La cuenta pasará a ser un administrador normal que podrá editar como cualquier otro.

La línea de la contraseña requiere especial cuidado. Cualquier valor incluido en environment: puede leerlo cualquiera que pueda ejecutar docker inspect en el contenedor, por lo que DEFAULT_ADMIN_PASSWORD no debe permanecer allí. Inicie sesión, cambie la contraseña desde la interfaz, elimine esa línea y vuelva a ejecutar docker compose up -d.

La opción más limpia omite por completo las variables. Comente todo el grupo DEFAULT_ADMIN_* y cree la cuenta de forma interactiva:

docker compose run --rm planka npm run db:create-admin-user

El comando solicita el correo electrónico, la contraseña, el nombre visible y un nombre de usuario opcional. Después escribe el usuario directamente en la base de datos. La contraseña nunca pasa por el archivo Compose ni por el entorno del contenedor. Use esta opción si más de una persona tiene acceso de shell al VPS. El comando inicia primero Postgres debido a depends_on, por lo que funciona aunque la pila nunca se haya iniciado.

Con cualquiera de las dos opciones, deberá administrar manualmente las contraseñas de Planka. Hasta la versión 2.1.1, la edición Community podía delegar los inicios de sesión en un proveedor OIDC, como Authentik ejecutándose como su propio servidor de inicio de sesión único, pero la versión 2.2.0, publicada en agosto de 2026, trasladó OIDC y SSO a PLANKA Pro. En la misma versión, la edición Community incorporó la autenticación de dos factores (TOTP) para las cuentas locales. Actívela al menos para la cuenta de administrador.

Por qué BASE_URL interrumpe los inicios de sesión cuando no coincide con el nombre de host

BASE_URL es la dirección exacta que los usuarios escriben en el navegador, con el esquema y sin una barra final. En esta pila es https://kanban.example.com. Planka genera sus propios enlaces y su conexión WebSocket a partir de ese valor, por lo que un BASE_URL incorrecto no produce un error claro. La página se carga, pero nunca termina de cargar.

La situación habitual es esta: copia el ejemplo del proyecto original, deja BASE_URL=http://localhost:3000 sin modificar y accede al sitio mediante HTTPS en el dominio real. El formulario de inicio de sesión se envía y las credenciales se aceptan. El tablero nunca aparece. Abra la consola de desarrollador del navegador y verá que fallan las solicitudes a /socket.io/, porque se indicó al cliente que abriera su conexión en tiempo real con localhost:3000, y esa dirección no existe en su portátil.

TRUST_PROXY=true es la otra parte del mismo problema. Planka se ejecuta detrás de Traefik, por lo que cada solicitud llega desde la dirección del proxy mediante HTTP sin cifrar dentro de la red Docker. Sin TRUST_PROXY, la aplicación ignora las cabeceras X-Forwarded-Proto y X-Forwarded-For que establece Traefik, por lo que considera que la conexión no es segura y trata a todos los clientes como una única dirección IP compartida. Cuando se configura, la aplicación lee esas cabeceras y coincide con el navegador respecto al esquema.

Traefik gestiona los WebSockets sin configuración adicional, que es una de las razones para preferirlo en este caso. En nginx, el proxy debe reenviar las cabeceras de actualización, proxy_set_header Upgrade $http_upgrade y proxy_set_header Connection "upgrade", o aparecerá el mismo indicador de carga atascado por una causa diferente. Pueden estar en el bloque general location /; también funciona un bloque independiente para /socket.io, pero no es necesario.

Mover el tablero a un nuevo nombre de host más adelante implica cambiar dos elementos a la vez: el valor BASE_URL y la regla Host() de Traefik. Si cambia uno y olvida el otro, volverá a aparecer el indicador de carga atascado. Servir Planka desde una subruta como https://example.com/planka funciona a partir de la versión 2.1.0, publicada en March 2026. En las etiquetas anteriores, asígnele un subdominio propio.

Dónde guarda Planka los archivos adjuntos y los avatares

Planka 2 guarda todo lo que sube un usuario en una única ruta dentro del contenedor: /app/data. Los archivos adjuntos, los avatares de usuario y las imágenes de fondo de los tableros se almacenan allí. La versión 1 usaba tres directorios separados, por lo que un archivo de Compose copiado de una guía antigua monta rutas que ya no existen y deja sin montar el directorio de datos real.

Ese único montaje determina si un tablero sobrevive a una actualización o si provoca problemas. Si /app/data no está en un volumen, las cargas se guardan en la capa escribible del contenedor. Esa capa se elimina cuando se vuelve a crear el contenedor, y el contenedor se vuelve a crear cada vez que se cambia la etiqueta de la imagen. El tablero vuelve a aparecer correctamente, todas las tarjetas siguen allí y todos los enlaces a los archivos adjuntos están rotos, porque las filas de la base de datos siguen apuntando a archivos que ya no existen.

El volumen con nombre del archivo de Compose anterior evita este problema. También puede usar un bind mount, que facilita las copias de seguridad de los archivos con herramientas habituales, pero requiere un paso adicional. El proceso de Node dentro del contenedor se ejecuta con el UID 1000, por lo que un directorio del host propiedad de root produce un error de permisos en la primera carga:

sudo chown -R 1000:1000 /opt/planka/data

La diferencia entre ambas opciones se explica en bind mounts frente a volúmenes con nombre.

Si los archivos adjuntos superan el espacio de disco incluido en su plan, Planka puede escribirlos en un almacenamiento compatible con S3 mediante S3_ENDPOINT, S3_BUCKET y las variables de clave correspondientes. Puede apuntar a un bucket alojado o a un almacén de objetos MinIO autogestionado en otro equipo. Decida esto antes de que el equipo llene el tablero, porque la configuración sólo se aplica a las cargas nuevas.

Inicie la pila y compruebe que funciona

docker compose pull
docker compose up -d
docker compose ps

docker compose ps debería mostrar postgres como healthy y planka como running. Si Planka se reinicia en un bucle, lo primero que debe comprobar es la conexión con la base de datos, no la aplicación.

docker compose logs -f planka

Un primer arranque correcto ejecuta las migraciones de la base de datos y después indica que el servidor escucha en el puerto 1337. Confirme que el esquema se haya creado realmente consultando Postgres directamente, en lugar de confiar en el registro:

docker compose exec postgres psql -U planka -d planka -c '\dt'

Una lista de tablas que incluya board y card significa que las migraciones se ejecutaron. "Did not find any relations" significa que Planka nunca se conectó. Compare DATABASE_URL con los valores POSTGRES_USER y POSTGRES_PASSWORD de su .env.

Después, compruebe la ruta desde su propio equipo, no desde el VPS:

curl -I https://kanban.example.com

HTTP/2 200 significa que Traefik tiene un certificado y puede llegar al contenedor. Un 404 servido por Traefik significa que ningún router coincidió con la solicitud: la regla Host() no coincide con el nombre de host solicitado, o Traefik nunca detectó las etiquetas. Un 502 significa que el router coincidió, pero Traefik no pudo llegar al contenedor, por ejemplo, porque no está conectado a la red proxy. Ahora abra el sitio e inicie sesión con la cuenta de administrador.

Haz un pg_dump antes de cada actualización de versión

Tu tablero se almacena en dos ubicaciones independientes, por lo que la copia de seguridad debe cubrir ambas: la base de datos de Postgres y el volumen planka-data. Haz el volcado de la base de datos mientras la pila está en ejecución.

docker compose exec -T postgres pg_dump -U planka -d planka > "planka-db-$(date +%F).sql"

-T no es opcional. Sin esta opción, Compose asigna un pseudo-terminal y la capa del terminal reescribe los finales de línea en el flujo. Como resultado, obtienes un archivo de volcado que falla a mitad de una restauración. El fallo aparece semanas después, que es el peor momento posible.

A continuación, haz una copia de las cargas. Primero busca el nombre real del volumen, porque Compose le añade como prefijo el nombre del directorio del proyecto.

docker volume ls | grep planka
docker run --rm -v planka_planka-data:/data -v "$PWD":/backup alpine \
  tar czf /backup/planka-files-$(date +%F).tgz -C /data .

El proyecto también incluye docker-backup.sh y docker-restore.sh en su repositorio, y la documentación oficial indica que deben ejecutarse mediante un cron nocturno. Cualquiera de los dos métodos es válido. Lo que no es válido es tener una copia de seguridad que nunca hayas restaurado. Restaura una en una VPS de prueba y confirma que puedes iniciar sesión y abrir un archivo adjunto. Este mismo par de almacenes aparece en todas las aplicaciones de Compose que aceptan cargas. Por eso, si más adelante instalas Chatwoot en el mismo servidor que tu mesa de ayuda, el procedimiento que construyas aquí se puede reutilizar con pocos cambios, principalmente en los nombres de los volúmenes.

Ejecuta el volcado inmediatamente antes de cada cambio de versión. Una copia de seguridad de anoche no equivale a una copia de seguridad realizada antes de la migración que estás a punto de ejecutar.

Fije las etiquetas y lea las notas de la versión

Las dos etiquetas de imagen de ese archivo están fijadas de forma intencionada.

ghcr.io/plankanban/planka:2.2.1 corresponde a una versión específica, vigente en octubre de 2026. latest cambia cada vez que el proyecto original publica una versión, por lo que un docker compose pull rutinario puede incorporar una migración de esquema en un momento que usted no ha elegido. Lea las notas de la versión antes de cambiar ese número, porque ahí se describen los cambios incompatibles y las correcciones de seguridad. La versión 2.0.3 se publicó como una versión de seguridad. Es exactamente el tipo de cambio que debe leer, no incorporar por accidente. Lo mismo ocurrió con la versión 2.2.1, publicada en agosto de 2026: corrige un fallo de recorrido de rutas que permitía a un usuario autenticado leer archivos arbitrarios en instancias que usaban almacenamiento de archivos local. Esa es la configuración de esta guía. El aviso de seguridad indica que 2.1.1 y las versiones anteriores estaban afectadas. Si procede de 2.1.x, lea primero las notas de 2.2.0, porque esa versión desactiva a los usuarios que sólo habían iniciado sesión mediante SSO hasta que un administrador les asigna una contraseña. Aquí es fácil fijar la versión porque el proyecto original publica imágenes. Cuando un proyecto no publica ninguna, debe aplicar la misma disciplina con un paso adicional, como en openGym compilado en el equipo a partir de una etiqueta de git verificada.

postgres:16-alpine está fijado a una versión principal por un motivo más importante. Postgres escribe su directorio de datos en un formato vinculado a la versión principal, y el servidor se niega a abrir un directorio escrito por otra versión. Escriba postgres:latest, deje que la etiqueta avance más allá de 16 y el contenedor no se iniciará. Por ejemplo, la imagen 17 se detiene con:

FATAL:  database files are incompatible with server
DETAIL:  The data directory was initialized by PostgreSQL version 16, which is not compatible with this version 17.

No se pierde nada y reiniciar tampoco soluciona el problema. Cambiar a una nueva versión principal de Postgres requiere hacer un volcado con la versión antigua y restaurarlo en un directorio de datos nuevo de la versión nueva, o ejecutar pg_upgrade, que convierte los datos sin hacer un volcado, pero necesita disponer al mismo tiempo de los binarios del servidor antiguo y del nuevo. En ambos casos se trata de una tarea planificada, con la pila detenida, no de un efecto secundario de descargar una imagen.

Si va a migrar una instalación existente de Planka 1.x en lugar de empezar desde cero, esa actualización tiene su propio procedimiento documentado en la documentación del proyecto, y no hay forma de volver a la versión 1 sin una copia de seguridad creada previamente.

Modos de fallo y mensajes que verá

Planka se reinicia en bucle y el registro menciona la base de datos. Las credenciales de DATABASE_URL no coinciden con el entorno de Postgres. Tenga en cuenta que POSTGRES_PASSWORD sólo se aplica cuando el directorio de datos se inicializa por primera vez, por lo que corregir la variable después de un primer arranque incorrecto no cambia nada. Debe eliminar el volumen db-data y volver a iniciar.

El inicio de sesión funciona, pero el tablero nunca se carga. BASE_URL no coincide con la dirección de la barra del navegador, o falta TRUST_PROXY. La consola del navegador muestra solicitudes fallidas a /socket.io/.

Las cargas de archivos fallan, pero todo lo demás funciona. El montaje bind pertenece a root. Ejecute sudo chown -R 1000:1000 en el directorio del host y reinicie el contenedor.

Los archivos adjuntos desaparecieron después de una actualización. /app/data no estaba en un volumen, por lo que los archivos estaban en la capa del contenedor que reemplazó la actualización. Restaure los archivos desde una copia de seguridad y añada el volumen antes de volver a cambiar la etiqueta de la imagen.

Traefik devuelve 404. Ningún router coincidió con la solicitud: la regla Host() no coincide con su registro DNS, o las etiquetas nunca llegaron a Traefik. docker compose config muestra las etiquetas después de la sustitución; ahí se hacen visibles los errores tipográficos. Un 502 indica que la ruta coincidió, pero no se pudo acceder al contenedor. Compruebe que esté conectado a la red proxy.

Las notificaciones o los webhooks nunca llegan. Planka 2 envía sus solicitudes HTTP salientes mediante un filtro interno, y la lista de bloqueo predeterminada incluye localhost y postgres. Un webhook dirigido a localhost se bloquea intencionadamente. Además, cuando establece OUTGOING_ALLOWED_HOSTS, también se bloquea cualquier host que no esté en esa lista. Dirija el webhook al nombre de servicio del otro contenedor y añada ese nombre a OUTGOING_ALLOWED_HOSTS si usa una lista de permitidos, en lugar de eliminar el filtro.

Una vez que funciona, la carga operativa es reducida. Revise las notas de la versión y vuelque la base de datos antes de cada actualización. Un reinicio vuelve a iniciar la pila automáticamente gracias a restart: unless-stopped, siempre que el servicio de Docker esté habilitado durante el arranque. Pilas de Compose que vuelven a iniciarse después de un reinicio cubre los casos en los que no sea así.

FAQ

¿Por qué Planka se queda cargando indefinidamente después de iniciar sesión?

Las credenciales se aceptaron, pero la conexión en tiempo real no se estableció. Planka construye su URL de WebSocket a partir de BASE_URL. Si esa variable aún contiene http://localhost:3000 y accede al sitio mediante https://kanban.example.com, el navegador intenta abrir un socket hacia una dirección que no existe en su máquina. La consola del desarrollador muestra solicitudes fallidas a /socket.io/. Establezca BASE_URL con la dirección pública exacta, sin barra final, añada TRUST_PROXY=true para que la aplicación respete la cabecera X-Forwarded-Proto del reverse proxy y, después, ejecute docker compose up -d.

¿Cómo creo el primer usuario administrador de Planka?

Desde la versión 1.13 no se crea ningún administrador automáticamente. Puede establecer DEFAULT_ADMIN_EMAIL junto con las variables correspondientes de contraseña, nombre y nombre de usuario, y después iniciar el stack; también puede ejecutar docker compose run --rm planka npm run db:create-admin-user y responder a las indicaciones. El comando interactivo es más seguro en un servidor compartido, porque la contraseña nunca entra en el entorno del contenedor, donde docker inspect puede leerla. Mantener DEFAULT_ADMIN_EMAIL establecido después bloquea esa cuenta e impide modificarla o eliminarla desde la interfaz.

¿Dónde almacena Planka los archivos adjuntos y los avatares?

En Planka 2, todos los archivos cargados se almacenan en /app/data dentro del contenedor, incluidos los archivos adjuntos, los avatares de usuario y los fondos de los tableros. Monte esa ruta en un volumen con nombre. Si no está montado, los archivos quedan en la capa escribible del contenedor y se destruyen la próxima vez que se vuelva a crear el contenedor, algo que ocurre en cada actualización de la imagen. También puede usar un bind mount, pero el proceso de Node se ejecuta con UID 1000. Por tanto, ejecute sudo chown -R 1000:1000 en el directorio del host o las cargas fallarán con un error de permisos.

¿Cuánta RAM necesita una instancia de Planka alojada por uno mismo?

El proyecto no publica un requisito mínimo de hardware. La cifra de 2 vCPU y 4 GB que se repite en las páginas de hosting es el valor predeterminado de un proveedor, no una medición, y resulta holgada para un tablero pequeño. La carga completa consta de un proceso de Node y un servidor de Postgres, que inicia un proceso backend pequeño por cada conexión abierta. Por eso, un plan con 1 vCPU y 2 GB es suficiente para un equipo de dos a cinco personas. Ejecute docker stats --no-stream después de una semana normal y dimensione el sistema a partir de sus propios datos. Supervise el disco con más atención que la memoria, porque lo que crece son los archivos adjuntos.

¿Cómo actualizo Planka sin perder datos?

Vuelque la base de datos y archive el volumen de cargas justo antes de la actualización, no según la tarea programada de la noche anterior. Use docker compose exec -T postgres pg_dump -U planka -d planka > planka-db.sql y conserve -T para que el pseudoterminal no corrompa la salida redirigida. Lea las notas de la versión de todas las versiones que omita, cambie la etiqueta de la imagen por una versión específica en lugar de latest y, después, ejecute docker compose pull y docker compose up -d y supervise el registro para comprobar la migración. Mantenga fijada la etiqueta de Postgres en su versión mayor, porque el servidor rechaza abrir un directorio de datos escrito por una versión mayor diferente.