· 51 min de lectura

Servidor doméstico con contenedores Docker, una bóveda cifrada y las credenciales compartidas con cuatro personas

Terminé de instalar Passbolt, ejecuté su comando de diagnóstico y me devolvió ocho errores. Que la clave del servidor no estaba puesta. Que la huella no coincidía. Que la clave privada no podía descifrar nada.

Estuve a punto de borrarlo todo y empezar de cero. No lo hice, y menos mal, porque la instalación estaba perfecta. Los ocho errores eran mentira.

Esa es más o menos la experiencia de instalar Passbolt: un producto con muy buena reputación, un modelo de cifrado más estricto que el de cualquiera de sus competidores, y una colección de trampas que la mayoría de las guías no menciona, porque las escribe alguien que lo levantó una vez y no volvió a tocarlo.

Yo lo instalé, lo rompí a propósito, borré los volúmenes y lo volví a montar limpio. Cada comando y cada salida de terminal que vas a ver aquí están ejecutados de verdad, no copiados de la documentación. El dominio de los ejemplos es passbolt.itrafa.com, que es el mío.

Antes de que inviertas la tarde: esto es para quien administra sistemas y tiene que compartir credenciales con un equipo técnico. El registrador del dominio, el firewall, el panel de la nube, las cuentas de emergencia. Todo eso que hoy vive en una hoja de cálculo que nadie quiere admitir que existe.

Si lo que buscas es un gestor para tu cuñado, te ahorro la tarde: este no es. Al final están los tres peajes que cobra Passbolt, medidos, y por qué a tu cuñado le salen carísimos.

Lo que necesitas

NecesitasDetalle
Una máquina con DockerRaspberry Pi, mini PC, VPS, máquina virtual o contenedor LXC. Hay imagen para amd64 y arm64
Recursos1 GB de RAM basta: la pila entera consume 219 MiB. 2 núcleos y 20 GB de disco
Docker y Composeguía aquí si nunca lo has instalado
Un dominio propioUna IP no sirve. Un subdominio basta
Un certificado de confianzaGratis con Cloudflare
Un relay de correoObligatorio. Sin él no puedes dar de alta a nadie
Diagrama: navegador, Cloudflare, contenedor LXC con Docker y dentro passbolt y MariaDB
Dos contenedores Docker sobre la máquina que tengas. El certificado lo pone Cloudflare en el borde.

Y lo que sacas, que es la parte que hay que saber explicarle a quien firma los presupuestos: usuarios y grupos ilimitados, sin coste por asiento. La competencia cobra esto entre cuatro y seis dólares por usuario al mes. Mueve los mandos con los números de tu equipo:

¿Cuánto estás pagando por algo que puedes alojar tú?

4,00 $
60 $ al mes
720 $ al año

Eso es lo que dejas de pagar. Passbolt no cobra por asiento: el mismo servidor vale para quince personas que para ciento cincuenta.

Y antes de que pienses en pedir un servidor: probablemente ya lo tienes. En cualquier oficina hay una torre que se dio de baja porque iba lenta para lo que le pedían, un portátil que sustituyeron por otro más nuevo, un mini PC que quedó suelto tras una mudanza. Cualquiera de esos mueve esto de sobra, porque la pila entera consume 219 MiB. El equipo que ya está amortizado y criando polvo en un armario es exactamente el perfil de máquina que necesitas.

Los tres requisitos que no son opcionales

Dominio y certificado de confianza. No sirve una IP, ni HTTP, ni un certificado autofirmado: la interfaz usa criptografía del navegador que solo funciona en contextos seguros.

Doy por hecho que ya tienes un dominio: con reservar un subdominio dentro del que usas te vale, y eso no cuesta nada aparte. Desde ahí hay tres caminos, y eliges uno, no los tres. Ninguno añade un dólar a la factura; lo que cambia entre ellos es cuántos puertos acabas abriendo en tu router:

Si vas por Cloudflare, dos avisos. El primero es sobre el modo de cifrado de SSL/TLS, y conviene entender a qué salto se aplica, porque no es el que uno supone:

El segundo aviso: el certificado gratuito de Cloudflare cubre tudominio.com y un nivel de subdominio, pero no dos.

Comparación de túnel de Cloudflare, proxy de Cloudflare y Traefik según cuántos puertos abre cada uno
Los tres valen y ninguno cuesta dinero. Lo que cambia es cuántos puertos acabas abriendo, y eso sí decide el riesgo.

Un servidor de correo, o un relay SMTP. Y aquí va una contra de Passbolt, dicha sin rodeos: dependes de un servicio de terceros que normalmente se paga. En Passbolt el correo no es una comodidad, es infraestructura: por ahí van las altas, las recuperaciones y los avisos de que alguien compartió algo contigo. Sin correo, no das de alta a nadie. Afortunadamente hay servicios con plan gratuito que sobran de largo para esto.

Yo tiro de SMTP2GO, que da mil correos al mes y doscientos al día sin pedir tarjeta, y está pensado para correo transaccional y no para campañas. Le he dedicado un artículo entero, porque montarlo bien tiene más detalles de los que parece: ahí explico por qué no hay que tocar tu registro SPF, cuál de los tres registros DNS conviene no crear, y por qué el correo saliente es lo único que no te recomiendo autohospedar.

Si prefieres otro, Passbolt trae diez configuraciones ya preparadas: AWS SES, Elastic Email, Google, Mailchimp, Mailgun, Mailjet, Office 365, Sendgrid, Sendinblue y Zoho. Cualquier otro, SMTP2GO incluido, entra por la opción Others.

Y un consejo antes de elegir, y vale para cualquiera de ellos: mira si el que te interese activa por defecto el seguimiento de aperturas y la reescritura de enlaces. Para un boletín es normal; para los correos de tu gestor de contraseñas, no lo quieres. No es capricho: los grandes proveedores puntúan la reputación de quien envía, y un correo lleno de enlaces reescritos que apuntan a dominios de marketing tiene bastantes papeletas de acabar en la carpeta de no deseado. Y de eso tú no te enteras por ningún panel: te enteras por el ticket de soporte y por la llamada de siempre, «es que no me llega el correo». Cuantos menos de esos, mejor.

Tampoco te recomiendo montar un Postfix en el mismo servidor: sin SPF ni DNS inverso acaba en la carpeta de no deseado. Y sobre todo, no te compliques. Te estoy dando alternativas gratuitas que funcionan en diez minutos; guarda el esfuerzo para proyectos más divertidos, que ya iré compartiendo.

La hora sincronizada. Los códigos de un solo uso y la validación de tokens dependen de ello. Compruébalo con timedatectl.

Si lo montas en un contenedor LXC de Proxmox

Yo lo hago así, porque es lo que tengo. Si vas por otro camino, salta a la instalación.

Hay una casilla que decidir, y es la causa de la mitad de los intentos fallidos de correr Docker en Proxmox: hay que activar nesting. Con el contenedor seleccionado, vas a Options → Features → Edit y marcas la casilla.

Dialogo Edit Features de Proxmox con las casillas keyctl, Nesting, NFS, SMB/CIFS y FUSE
Fíjate en que NFS y SMB/CIFS salen en gris: solo valen en contenedores privilegiados.

O por línea de comandos, desde el nodo de Proxmox:

# Sustituye 131 por el ID de tu contenedor
pct stop 131 && pct set 131 -features nesting=1 && pct start 131

Si falta, Proxmox avisa al arrancar, aunque el mensaje no menciona Docker: WARN: Systemd 255 detected. You may need to enable nesting.

El mito de keyctl

Marcar una casilla de más no cuesta nada, y lo cómodo habría sido marcarla, seguir con la instalación y no volver a pensarlo.

Casi todos los tutoriales te dirán que actives una segunda casilla, keyctl. Y no es capricho suyo: lo dice la documentación oficial de Proxmox, con estas palabras, «esto hace falta para usar Docker dentro de un contenedor».

El problema es que yo tenía delante un contenedor con ocho servicios Docker funcionando desde hacía días, sin esa casilla. O la documentación estaba equivocada, o yo no entendía algo. Así que en vez de discutirlo lo probé: las cuatro combinaciones posibles, reiniciando el contenedor en cada una.

Tabla de cuatro pruebas: solo nesting hace falta para Docker, keyctl es irrelevante
Contenedor no privilegiado, Ubuntu 24.04, Docker 29.7.2, overlayfs y cgroups v2.

Lo único que importa es nesting. Con keyctl activado y nesting quitado, Docker no levanta ni un contenedor. El error es siempre el mismo:

rafa@homelab: ~
docker: Error response from daemon: failed to mount ...fstype: overlay, ... err: permission denied  sin nesting, Docker no monta las capas de la imagen
El error con keyctl activado y nesting quitado. Es siempre este.

Ahí está la clave: nesting es lo que permite montar sistemas de ficheros overlay, que es como Docker apila las capas de cada imagen. Y el fallo engaña, porque el daemon arranca igual, docker info responde y los cgroups siguen escribiéndose. Todo parece bien hasta que intentas ejecutar algo.

La recomendación de keyctl viene de cuando Docker usaba el llavero del kernel. Con las versiones actuales ya no, y mejor así, porque activarlo puede romper systemd-networkd, como admite la propia documentación.

Todo esto está medido en un contenedor no privilegiado, el que Proxmox crea por defecto y el que debes usar: en uno privilegiado, el root de dentro es el root del nodo Proxmox. Para algo que guarda las credenciales de tu equipo, esa diferencia no es teórica.

La instalación

Paso 1: poner el sistema al día

Parece de cajón y por eso se salta en casi todas las guías, pero en un contenedor recién creado el primer comando del siguiente paso no funciona. La plantilla de Ubuntu viene mínima: no trae curl, no trae los certificados raíz y no trae ningún editor de texto, ni siquiera vi.

Lo segundo es peor que lo primero, porque falla de una forma que engaña: instalas curl, lanzas la descarga y te salta un error de certificado que parece un problema de red o del servidor de Passbolt. No lo es, es que tu contenedor no sabe todavía en quién confiar.

apt update && apt upgrade -y
apt install -y curl ca-certificates nano

Si ya tienes Docker instalado siguiendo el artículo enlazado más arriba, esto ya lo hiciste y puedes seguir de largo. Lo dejo igualmente porque mucha gente monta el contenedor limpio para esto.

Paso 2: descargar y verificar

Passbolt publica una suma SHA512 del fichero de despliegue. Verifícala. Y ojo, porque es fácil equivocarse: el fichero está en el servidor de descargas, pero la suma está en GitHub.

mkdir -p /opt/passbolt && cd /opt/passbolt

curl -LO https://download.passbolt.com/ce/docker/docker-compose-ce.yaml
curl -LO https://github.com/passbolt/passbolt_docker/releases/latest/download/docker-compose-ce-SHA512SUM.txt

sha512sum -c docker-compose-ce-SHA512SUM.txt
rafa@homelab: ~
docker-compose-ce.yaml: OK  cualquier otra cosa: no sigas, vuelve a descargarlo
Lo único que vale es OK. Si dice FAILED, el fichero no es el que publicó Passbolt.

Paso 3: las cuatro líneas que hay que cambiar

Genera una contraseña antes de nada:

openssl rand -base64 32 | tr -dc 'A-Za-z0-9' | head -c 32

Guárdala a mano. Y sí, soy consciente de la ironía de apuntar la contraseña del gestor de contraseñas que todavía no has instalado: es el huevo y la gallina de todo el que se autohospeda algo.

Ahora toca editar el fichero que descargaste. Ábrelo con el editor que instalamos al principio:

nano docker-compose-ce.yaml

Este es el fichero oficial, con las cuatro líneas marcadas:

services:
  db:
    image: mariadb:10.11
    environment:
      MYSQL_RANDOM_ROOT_PASSWORD: "true"
      MYSQL_DATABASE: "passbolt"
      MYSQL_USER: "passbolt"
      MYSQL_PASSWORD: "P4ssb0lt"          # <-- CAMBIAR (1 de 2)
    volumes:
      - database_volume:/var/lib/mysql

  passbolt:
    image: passbolt/passbolt:latest-ce     # <-- CAMBIAR: fijar una version
    depends_on:
      - db
    environment:
      APP_FULL_BASE_URL: https://passbolt.local   # <-- CAMBIAR: tu dominio
      DATASOURCES_DEFAULT_HOST: "db"
      DATASOURCES_DEFAULT_USERNAME: "passbolt"
      DATASOURCES_DEFAULT_PASSWORD: "P4ssb0lt"    # <-- CAMBIAR (2 de 2)
      DATASOURCES_DEFAULT_DATABASE: "passbolt"
      PASSBOLT_SECURITY_PROXIES_ACTIVE: "true"    # <-- ANADIR si usas proxy inverso
    volumes:
      - gpg_volume:/etc/passbolt/gpg
      - jwt_volume:/etc/passbolt/jwt
    command:
      ["/usr/bin/wait-for.sh", "-t", "0", "db:3306", "--", "/docker-entrypoint.sh"]
    ports:
      - 80:80
      - 443:443

volumes:
  database_volume:
  gpg_volume:
  jwt_volume:

Con las cuatro líneas cambiadas, a guardar: pulsas Ctrl+X, te pregunta si quieres guardar, respondes Y y confirmas el nombre del fichero con Enter. Tres teclas y estás fuera.

Si prefieres la línea de comandos:

DBPASS=$(openssl rand -base64 32 | tr -dc 'A-Za-z0-9' | head -c 32)

sed -i "s|P4ssb0lt|$DBPASS|g" docker-compose-ce.yaml
sed -i "s|https://passbolt.local|https://passbolt.itrafa.com|" docker-compose-ce.yaml

# Tiene que devolver 0
grep -c 'P4ssb0lt\|passbolt.local' docker-compose-ce.yaml

Paso 4: levantar

docker compose -f docker-compose-ce.yaml up -d

# Seguir el arranque
docker compose -f docker-compose-ce.yaml logs -f passbolt
rafa@homelab: ~
NOTICE: fpm is running, pid 126NOTICE: ready to handle connectionsINFO success: nginx entered RUNNING state  27 segundos en mi contenedor. Los avisos de http2 se ignoran
Cuando aparece RUNNING, la pila está en pie.

Ojo con el segundo comando, porque ese comando no termina solo: la opción -f se queda enganchada al registro y va escribiendo según pasan cosas. Cuando veas la línea INFO success: nginx entered RUNNING state, ya está levantado y puedes salir con Ctrl+C.

Y que no te dé reparo pulsarlo: Ctrl+C solo deja de mostrarte el registro, no para nada. Los contenedores se levantaron con -d, que es lo que los deja corriendo en segundo plano, y ahí siguen. Lo puedes comprobar con docker compose -f docker-compose-ce.yaml ps.

En mi contenedor tardó 27 segundos. Verás también dos avisos de nginx sobre la directiva listen ... http2. Vienen de dentro de la imagen, no de nada que hayas escrito tú, y no puedes hacer nada al respecto. Es el primero de varios mensajes que este tutorial te va a pedir que ignores.

Paso 5: publicarlo en tu dominio

Hasta aquí los contenedores están corriendo, pero solo escuchan dentro de tu máquina. Publican los puertos 80 y 443, y ahí se acaba: desde fuera, tu dominio todavía no lleva a ninguna parte.

Este paso no se puede dejar para después, y es un error fácil de cometer: el paso 7 genera un enlace contra tu dominio, y si el dominio no responde, ese enlace no abre nada. Es el único que tienes para entrar la primera vez.

Aquí se aplica el camino que elegiste al principio. Yo voy por túnel de Cloudflare. El alta del túnel entera, desde crearlo hasta instalar cloudflared, está en conectar tus servicios sin abrir puertos; aquí solo va lo específico de Passbolt, que son dos pantallas.

La primera es el nombre público. Subdominio passbolt y tu dominio, y el DNS lo crea Cloudflare solo:

Panel de Cloudflare Zero Trust con el subdominio passbolt y el dominio elegidos para el túnel
El nombre completo tiene que ser exactamente el que pusiste en APP_FULL_BASE_URL. Si no coinciden, entras pero los enlaces de los correos no llevan a ningún sitio.

La segunda es a dónde manda el tráfico, y es donde está el detalle que hace tropezar a mucha gente. Tipo HTTPS, URL localhost, y luego, dentro de Origin request, activas No TLS Verify:

Configuración del servicio del túnel apuntando a HTTPS localhost con la opción No TLS Verify activada
Tipo HTTPS a localhost, y No TLS Verify activado. Sin ese interruptor, el túnel no levanta.

Por qué hace falta ese interruptor, y por qué no es opcional. Lo miré dentro de la imagen en vez de suponerlo. El contenedor escucha en el 80 y en el 443, y el certificado del 443 se lo genera él solo al arrancar, con este nombre:

CN=www.passbolt.local

Ahí está todo. Es autofirmado, así que no lo respalda ninguna autoridad, y además se llama www.passbolt.local, que no va a coincidir con tu dominio jamás. cloudflared valida el certificado del origen por defecto: se encuentra con eso, no se fía y corta la conexión. No TLS Verify es lo que le dice que en este salto no lo valide.

Y por qué no es un agujero. Ese salto es cloudflared hablando con localhost, dentro de la misma máquina: el tráfico no sale a ninguna red donde alguien pueda ponerse en medio. Es el mismo razonamiento de antes, el de por qué tu zona puede seguir en Full (strict) con un túnel: lo que decide el cifrado de cara a internet es Cloudflare, y eso no lo tocas.

Si prefieres no tocar ese interruptor, la alternativa es tipo HTTP y URL localhost:80: el contenedor también escucha ahí y funciona igual. Yo voy por HTTPS porque así el tramo entero va cifrado, aunque sea con un certificado que no valida nadie. Cualquiera de las dos vale; lo que no vale es HTTPS sin el interruptor, porque entonces el túnel no levanta.

Si vas por proxy de Cloudflare o por Traefik, es el momento de apuntarlos a tu servidor, al 443 o al 80 según prefieras, con el mismo criterio que acabo de explicar.

Y antes de seguir, compruébalo. Passbolt publica un punto de estado que responde sin necesidad de haber entrado:

curl -s https://passbolt.tudominio.com/healthcheck/status.json
rafa@homelab: ~
{"header":{"id":"95e7675b-…","status":"success", "servertime":1786835782,…,"message":"OK"}}  si ves esto, el dominio ya llega a Passbolt
Comprobado contra la instancia real. Esta respuesta solo la puede dar Passbolt.

Uso ese punto y no la portada por un motivo: pedir la raíz devuelve un 302 hacia el formulario de acceso, y un 302 también te lo da un proxy mal apuntado que esté redirigiendo a otra cosa. Ese JSON solo puede salir de Passbolt, así que si lo ves, el camino entero está bien de punta a punta.

Si aquí no responde, para y arréglalo. Seguir sin esto es garantizarte que el enlace de alta no funcione cuando llegues a él.

Paso 6: configurar el correo

Este paso va antes de crear tu cuenta a propósito. En Passbolt el correo no es un extra, es infraestructura: por ahí van las altas, las recuperaciones y los avisos de que alguien compartió algo contigo. Si lo dejas para luego, el enlace de tu propia alta no te llega y hay que ir a rescatarlo a la base de datos.

Necesitas los cuatro datos de tu relay: servidor, puerto, usuario y contraseña. Si todavía no tienes ninguno, en el artículo de relay SMTP gratis con SMTP2GO los consigues en diez minutos y sin tarjeta.

Hay dos formas de metérselos a Passbolt, y las dos valen.

Por variables, en el mismo fichero de despliegue

Es la que yo prefiero, porque queda escrita junto al resto de la configuración y se restaura sola cuando rehaces el contenedor.

Van en el bloque environment: del servicio passbolt, que es el segundo del fichero. Ojo con eso, porque hay dos bloques environment: y el primero es el de la base de datos: si las pones ahí, no las lee nadie.

Así queda ese servicio entero. Las de arriba son las que ya tocaste en el paso 3, y las siete de abajo son las nuevas:

  passbolt:
    image: passbolt/passbolt:5.14.3-ce
    depends_on:
      - db
    environment:
      APP_FULL_BASE_URL: https://passbolt.tudominio.com
      DATASOURCES_DEFAULT_HOST: "db"
      DATASOURCES_DEFAULT_USERNAME: "passbolt"
      DATASOURCES_DEFAULT_PASSWORD: "tu-contrasena"
      DATASOURCES_DEFAULT_DATABASE: "passbolt"
      PASSBOLT_SECURITY_PROXIES_ACTIVE: "true"

      # ---- desde aqui, las lineas nuevas del correo ----
      EMAIL_TRANSPORT_DEFAULT_HOST: mail.smtp2go.com
      EMAIL_TRANSPORT_DEFAULT_PORT: 587
      EMAIL_TRANSPORT_DEFAULT_USERNAME: TU_USUARIO
      EMAIL_TRANSPORT_DEFAULT_PASSWORD: TU_CONTRASENA
      EMAIL_TRANSPORT_DEFAULT_TLS: "true"
      EMAIL_DEFAULT_FROM: [email protected]
      EMAIL_DEFAULT_FROM_NAME: Passbolt
      # ---- hasta aqui ----

    volumes:
      - gpg_volume:/etc/passbolt/gpg
      - jwt_volume:/etc/passbolt/jwt

Los nombres no me los he inventado ni los he sacado de la documentación: están en /etc/passbolt/app.default.php, dentro de la propia imagen. Ahí se ve además que si no pones nada, Passbolt intenta enviar por localhost en el puerto 25, donde no hay nadie escuchando. Por eso, sin configurar esto, los correos no fallan con un error claro: se quedan en la cola.

Y ojo con el remitente: EMAIL_DEFAULT_FROM tiene que ser una dirección de tu propio dominio, el mismo que verificaste en el relay. Con otro dominio, el correo sale pero acaba en la carpeta de no deseado.

Después de tocar el fichero hay que recrear el contenedor para que lea las variables nuevas:

docker compose -f docker-compose-ce.yaml up -d

O por la interfaz, una vez dentro

Si prefieres no tocar ficheros, Passbolt trae la configuración de correo en la interfaz de administración, en Administration → Email server, que por dentro es la ruta /app/administration/smtp-settings. Ahí es donde están los diez proveedores ya preparados, y donde SMTP2GO entra por la opción Others.

Pantalla de configuración del servidor SMTP en Passbolt, con SMTP2GO como servidor y el aviso de que la configuración viene de variables de entorno
La misma configuración del paso anterior, vista desde la interfaz. Abajo a la izquierda, el botón para mandarte un correo de prueba.

Fíjate en el recuadro de la derecha, que resuelve la duda evidente de tener dos formas de configurar lo mismo: Configuration source te dice de dónde sale lo que se está usando de verdad. Ahí pone environment variables porque lo puse en el fichero de despliegue. Si lo hubiera escrito en esta pantalla, diría otra cosa. No tienes que adivinar cuál de las dos manda: te lo dice.

La pega de esta vía es la del huevo y la gallina: para entrar en la interfaz necesitas tu cuenta, y para recibir el enlace de tu cuenta necesitas correo. Se resuelve, porque el enlace también sale por la línea de comandos en el paso siguiente, pero es un rodeo. Por eso yo lo dejo puesto antes.

Y compruébalo antes de seguir

Passbolt trae un comando para esto, así que no hay que adivinar:

docker compose -f docker-compose-ce.yaml exec passbolt \
  su -m -c "/usr/share/php/passbolt/bin/cake passbolt send_test_email \
  [email protected]" -s /bin/sh www-data

Si ese correo llega, ya puedes seguir con la cabeza tranquila. Si no llega, para aquí: todo lo que viene después depende de esto.

Paso 7: crear el primer administrador

Este paso no es opcional ni hay forma de saltárselo: en el despliegue con Docker no existe asistente web de primer arranque. La primera cuenta se crea por línea de comandos y punto, hayas configurado el correo o no. La diferencia es que, como ya lo configuraste en el paso anterior, el enlace además te va a llegar al buzón.

docker compose -f docker-compose-ce.yaml exec passbolt \
  su -m -c "/usr/share/php/passbolt/bin/cake passbolt register_user \
  -u [email protected] -f Rafael -l Gomez -r admin" -s /bin/sh www-data
rafa@homelab: ~
User saved successfully.To start registration follow the link provided in your mailbox or here:https://passbolt.itrafa.com/setup/start/6be1d7ab-.../bbf75406-...  cópialo AHORA, fuera de la terminal
Ese enlace es tu única vía de entrada si el correo todavía no funciona.

Ese es el enlace de alta de tu cuenta de administrador. Como el correo ya está configurado desde el paso anterior, ese mismo enlace te acaba de llegar al buzón: si abres el correo, tienes un botón de Get started que hace exactamente lo mismo. Esa es la vía normal, y la que van a usar las personas que invites después.

Aun así, cópialo y pégalo en un bloc de notas. La terminal lo imprime una sola vez: si la cierras o el desplazamiento se te va hacia arriba, no hay forma de volver a pedirlo, y recuperarlo obliga a la consulta a la base de datos que dejo al final. Cuesta dos segundos y te ahorra ese rodeo el día que el correo tarde o acabe en no deseado.

Vayas por el correo o por el enlace copiado, lo que hay que hacer con él es el mismo: pegarlo en la barra de direcciones del navegador donde tengas instalada la extensión de Passbolt, que es lo que hacemos en el siguiente apartado.

El diagnóstico que dice que todo está roto

El error de arranque que no es un error

Antes de que mires ningún diagnóstico, hay uno que te puede salir en los registros y que no significa nada. Si haces logs -f nada más levantar, o después de recrear los contenedores, es muy posible que veas esto:

rafa@homelab: ~
error: EditionManager: DB unavailable during boot,falling back to CE. error: [MissingConnectionException] Connection to Mysqlcould not be established: SQLSTATE[HY000] [1045]Access denied for user 'passbolt'@'172.19.0.3'(using password: YES) error: Could not connect to Database.
Da miedo, y encima habla de contraseñas. Pero si sale solo mientras arranca, no hay nada que tocar.

Lo que ocurre es que Passbolt arranca más rápido de lo que MariaDB tarda en estar lista. El contenedor de la base ya acepta conexiones de red, pero todavía no ha terminado de preparar sus usuarios, así que rechaza a Passbolt. Unos segundos después funciona, y no hay que hacer nada.

El problema es que el mensaje te empuja justo en la dirección equivocada. Dice «Access denied» y menciona la contraseña, así que lo natural es ponerse a revisar contraseñas del compose, que es donde no está el fallo. Yo perdí un rato largo haciendo exactamente eso.

Lo que distingue un caso del otro no es el mensaje, es la hora. Compara la hora del error con la hora a la que arrancó el contenedor de la base:

docker compose -f docker-compose-ce.yaml ps
docker compose -f docker-compose-ce.yaml logs --tail=30 passbolt

Volvemos a los ocho errores del principio, porque te van a pasar a ti también.

Passbolt trae un comando de diagnóstico. Es lo primero que ejecuta cualquiera después de instalar, por ese instinto sano de comprobar que todo está bien antes de meter dentro las contraseñas de tu equipo. Este es el comando, para que lo compruebes tú mismo:

docker compose -f docker-compose-ce.yaml exec passbolt \
  su -m -c "/usr/share/php/passbolt/bin/cake passbolt healthcheck" -s /bin/sh www-data

Y en un despliegue con Docker recién hecho, esto es lo que devuelve:

El comando healthcheck devuelve ocho errores en una instalacion correcta con Docker
Reproducido en una instalación limpia, con los volúmenes borrados y vuelta a crear.

Tu instalación no está rota. La clave existe, está en el llavero, la aplicación responde y el alta de usuarios funciona de principio a fin. Lo que pasa es que el despliegue con Docker se configura por variables de entorno y no escribe el fichero /etc/passbolt/passbolt.php; el comprobador busca ahí la huella, no la encuentra, y da por fallidas todas las pruebas que dependen de ella. Y el aviso de SSL sale porque la TLS la termina el proxy de delante, que es lo que queremos.

Merece la pena saberlo antes de ejecutarlo. Es el tipo de salida que hace que alguien borre una instalación perfectamente sana y vuelva a empezar.

El alta: tres pantallas, y las tres importan

Antes de abrir el enlace, un aviso: la extensión del navegador no es opcional. Sin ella no verás un formulario de acceso, verás una pantalla que te manda a instalarla y no hay forma de saltarla. Ni siquiera puedes crear tu cuenta.

Captura: Passbolt no deja continuar sin instalar la extension del navegador
No es un fallo: la clave privada tiene que vivir en un sitio que el servidor no controle, y ese sitio es la extensión.

La instalas desde la tienda de tu navegador, y conviene mirar que es la oficial: la publica Passbolt SA, está marcada como destacada y la usan cuatrocientas mil personas. Hay copias con nombres parecidos, y para una extensión que va a custodiar tu clave privada esa comprobación de diez segundos no sobra.

Ficha de la extensión oficial de Passbolt en la Chrome Web Store, marcada como destacada y con 400.000 usuarios
La ficha oficial en la Chrome Web Store. También está para Firefox y para Edge.

Con la extensión puesta, el asistente pide primero la frase secreta. Es la única que vas a necesitar recordar, y si la olvidas no hay recuperación en la edición gratuita.

Y aquí hay un detalle que no esperaba y que merece la pena: Passbolt comprueba si la frase que estás escribiendo aparece en alguna filtración conocida. Si aparece, no te avisa y sigue: te bloquea, el botón se queda desactivado.

Passbolt avisando de que la frase secreta forma parte de una filtración conocida, con el botón siguiente desactivado
No es un aviso que puedas ignorar: mientras la frase esté en una filtración, el botón no se activa.

La pregunta evidente es a dónde manda tu frase para saberlo, y la respuesta es que no la manda: consulta el servicio de contraseñas filtradas enviando solo un trozo del resumen criptográfico, nunca la frase. Es el mismo modelo que usa Have I Been Pwned.

Dicho lo cual, aquí va una historia que dice mucho de cómo trabaja este proyecto. En abril de 2024, los investigadores de Quarkslab encontraron que esa comprobación se hacía según ibas tecleando, letra a letra, y que esas consultas intermedias permitían acotar la frase por fuerza bruta mucho más rápido de lo normal. Es CVE-2024-33669, de gravedad media.

Lo corrigieron en la versión 4.6.2 de la extensión, y la corrección es la que uno querría: ahora la consulta se hace una sola vez, al enviar el formulario, y solo si la frase ya supera los 60 bits de entropía. Es decir, tu frase buena nunca se consulta a medio escribir. Si vas a instalar esto hoy no te afecta, pero cuenta algo importante: publican sus incidentes con nombre, fecha y quién los encontró.

La segunda pantalla es donde Passbolt se separa de todo lo demás, y donde más gente se equivoca: el kit de recuperación.

Pantalla del kit de recuperación con el fichero passbolt-recovery-kit.txt apareciendo en las descargas del navegador
El fichero aparece en las descargas y ya no vuelve a aparecer. Ese .txt de mil bytes contiene tu clave privada: es la única red de seguridad que vas a tener.

Guárdalo donde guardarías la copia de una clave SSH privada.

Comparacion: Vaultwarden pide la contrasena, Psono anade la huella, Passbolt exige el fichero de clave privada
La diferencia práctica frente a los otros dos gestores autohospedados más usados.

La tercera pantalla suele pasarse rápido y merece atención: el token de seguridad, un color y tres caracteres que eliges tú.

Lo interesante es dónde reaparece. Cada vez que la extensión te pide la frase secreta, muestra tu token dentro del campo:

Diálogo de Passbolt pidiendo la frase secreta con el token de seguridad del usuario visible dentro del campo
Ese JMS sobre verde es el mío. El tuyo será otro: el token va por cuenta, no por servidor.

Ahí está la defensa. Un sitio falso que copie este diálogo píxel a píxel no puede acertar ni el color ni las tres letras, porque no los ha visto nunca: viven en tu extensión, no en el servidor. Si algún día te piden la frase secreta y el recuadro no es el tuyo, no la escribas.

Es una protección que ni Vaultwarden ni Psono tienen, y cuesta cero: son tres letras que eliges una vez.

Captura del espacio de trabajo de Passbolt vacio tras completar el alta
Y ya estás dentro.

Si pierdes el navegador, o la frase

Arriba dije que si olvidas la frase secreta no hay recuperación en la edición gratuita. Es cierto, pero se queda corto y puede asustar de más, porque hay dos pérdidas distintas y solo una es definitiva.

Qué has perdidoQué pasa
El navegador, la computadora o la extensiónSe arregla. Necesitas el kit de recuperación y la frase
El kit de recuperación, pero conservas la fraseSe arregla si tienes copia de la clave privada en otro sitio
La frase secretaNo se arregla. Ni tú ni un administrador

La razón de que la última no tenga vuelta es la misma que hace seguro a Passbolt: el servidor guarda tu clave pública, nunca la privada. Sin la frase, esa clave privada no se abre, y sin ella tus secretos son bytes cifrados que nadie puede descifrar. No es una limitación de la edición gratuita, es el diseño.

El caso normal: navegador nuevo

Este es el que te va a pasar de verdad. Cambias de computadora, reinstalas el navegador o pruebas desde otro, y Passbolt no te reconoce, porque tu clave privada vivía en la extensión. Para volver a entrar hacen falta tres cosas:

  1. El kit de recuperación, ese fichero que descargaste al darte de alta y que contiene tu clave privada.
  2. La frase secreta, que abre esa clave.
  3. Un enlace de recuperación, que es lo único que puede darte el servidor.

Lo normal es pedir ese enlace desde la pantalla de acceso y que llegue por correo. Pero si el correo todavía no funciona, o si eres el único administrador y te has quedado fuera, se genera a mano desde el servidor.

Generar el enlace desde el servidor

El comando es recover_user, y tiene una trampa que hace fallar el primer intento: Passbolt se niega a ejecutar sus comandos como root. Hay que lanzarlo como el usuario del servidor web, que en la imagen de Docker es www-data.

rafa@homelab: ~
# 1. Lanzado como root, que es lo que sale natural$ docker compose -f docker-compose-ce.yaml exec passbolt \> /usr/share/php/passbolt/bin/cake passbolt \> recover_user -u [email protected]  [ aquí Passbolt imprime su logotipo ] Open source password manager for teams------------------------------------------------------- Passbolt commands cannot be executed as root. The command should be executed with the same user asyour web server. By instance:su -s /bin/bash -c "/usr/share/php/passbolt/bin/cakepassbolt recover_user" HTTP_USERwhere HTTP_USER match your web server user:www-data, nginx, apache, http aborting # 2. Otra vez, como el usuario del servidor web$ docker compose -f docker-compose-ce.yaml exec passbolt \> su -m -c "/usr/share/php/passbolt/bin/cake passbolt \> recover_user -u [email protected]" -s /bin/sh www-data  [ aquí Passbolt imprime su logotipo ] Open source password manager for teams-------------------------------------------------------The user [email protected] can recover its account here:https://passbolt.itrafa.com/setup/recover/start/ 4f1c8a20-…-9b7d/c3e90f14-…-2a6b recortado
Las dos ejecuciones son reales, con el logotipo recortado y los identificadores del enlace cambiados. Fíjate en que Passbolt te sugiere su -s /bin/bash -c "…" HTTP_USER, que no es exactamente la forma que uso yo: las dos funcionan. Ese enlace es de un solo uso, así que no lo pegues donde no debas.

Fíjate en que no hizo falta ninguna opción extra: ya había un token activo porque media hora antes había pedido la recuperación desde la pantalla de acceso, y el comando reutilizó ese. Si no hay ninguno, el comando te lo dice y te sugiere añadir --create (o -c) para generarlo. Con el enlace delante, ábrelo en el navegador donde quieras volver a entrar, importa el kit, escribe la frase y ya estás dentro.

Ese enlace es de un solo uso y caduca. Si alguien lo intercepta antes que tú, no le sirve de nada sin tu kit y tu frase, pero aun así no lo mandes por un canal que no controles.

Y si lo que perdiste es la frase

Aquí no hay comando que valga. Lo único que puede hacer un administrador es borrar tu usuario y volver a invitarte, y conviene saber exactamente qué significa eso: entras con una clave nueva, y esa clave no descifra nada de lo anterior. Los secretos que compartieron contigo hay que volver a compartirlos uno a uno desde una cuenta que sí los pueda leer.

Por eso el kit de recuperación y la frase no se guardan en el mismo sitio, y por eso la frase es lo único que de verdad tienes que recordar.

Si aun así el correo no llega

Diagrama: sin servidor de correo el alta se queda en la cola y nadie puede entrar
Las tres causas están en orden de frecuencia, y la primera se lleva la mayoría: hay dos bloques environment: en el fichero y solo uno vale.

Puede pasar: configuraste el relay en el paso 6, el correo de prueba no llegó y ahora estás sin poder entrar. Passbolt no pierde esos mensajes, los deja en una cola dentro de la base de datos, así que se pueden mirar. Si la columna sent vale 0, ese correo no ha salido. Y para desatascarte mientras lo arreglas, el enlace de alta se puede reconstruir a mano:

docker compose -f docker-compose-ce.yaml exec db \
  mariadb -u passbolt -p passbolt -N -B -e "
SELECT CONCAT('https://passbolt.itrafa.com/setup/start/', t.user_id, '/', t.token)
FROM authentication_tokens t
JOIN users u ON u.id = t.user_id
WHERE u.username = '[email protected]'
  AND t.active = 1
ORDER BY t.created DESC LIMIT 1;"

Devuelve la URL completa, lista para pegar. Sirve igual para altas y para recuperaciones. Pero que quede claro: es un parche para salir del paso, no la solución. Si has llegado aquí, tienes el correo mal configurado, y eso hay que arreglarlo antes de meter a nadie más: sin correo, tu equipo no puede ni darse de alta ni recuperar su cuenta.

Qué pasa cuando compartes una contraseña

Aquí es donde el modelo de Passbolt deja de ser una frase de folleto y se nota. En casi todos los gestores, compartir significa dar acceso a algo que ya está cifrado: la copia es una y se le abre la puerta a alguien más. Passbolt no puede hacer eso, porque el servidor no tiene ninguna clave con la que descifrar nada.

Diagrama: en el modelo habitual se comparte el acceso a una bóveda cifrada; en Passbolt el navegador descifra el secreto y lo vuelve a cifrar una vez por cada destinatario con su clave pública
La diferencia no es de interfaz, es de dónde vive la capacidad de descifrar.

Lo compruebas compartiendo una vez. Creé una segunda cuenta y compartí con ella un recurso de prueba. Son tres pantallas y la interesante es la segunda.

1. Eliges con quién

Nada raro todavía. Añades a la persona y le das un permiso.

Diálogo Share resource de Passbolt: Rafael Gomez como propietario y Ana Prueba recién añadida con permiso de lectura
Ana entra con permiso de lectura. Hasta aquí, igual que en cualquier otro gestor.

2. Te pide tu frase secreta

Y aquí está lo que lo delata todo.

Passbolt pidiendo la frase secreta al guardar el compartido, con la casilla de recordarla durante cinco minutos
Para compartir con otra persona, Passbolt necesita tu clave privada. Y para abrirla, tu frase.

Piensa en lo que significa que te la pida. Tu navegador tiene que descifrar el secreto para poder volver a cifrarlo con la clave pública de Ana. Y para descifrarlo necesita tu clave privada, que está protegida por esa frase.

Un gestor que solo tuviera que darle acceso a Ana no necesitaría nada tuyo. Le bastaría con cambiar un permiso en su base de datos. Que te pida la frase es la prueba de que el trabajo criptográfico ocurre en tu máquina y no en el servidor.

3. Y lo hace

Ventana de progreso de Passbolt al terminar de compartir, con la barra al cien por cien
Un cifrado por destinatario. Con uno solo, ni te da tiempo a leer la barra.

Un aviso sobre la velocidad, porque he leído lo contrario en varios sitios y no me cuadró al probarlo: con un secreto y una persona es inmediato. La barra de progreso aparece y desaparece. No hay ninguna espera que comentar.

Donde sí se nota es cuando el número crece, porque el trabajo es una operación por cada secreto y por cada destinatario. Compartir una carpeta de cincuenta contraseñas con cinco personas son doscientas cincuenta operaciones de cifrado, y esas se hacen en tu navegador. Ahí es donde toca esperar, no al compartir una suelta.

Y de aquí sale la consecuencia incómoda del modelo: quitarle el acceso a alguien borra su copia cifrada, pero no borra lo que ya leyó. Si esa persona vio la contraseña, hay que cambiarla. Eso vale para cualquier gestor, pero conviene tenerlo claro cuando el sistema parece tan hermético.

La prueba, en la base de datos

Todo lo anterior es lo que enseña la interfaz. Esto es lo que hay guardado, y se puede repetir en cualquier instancia.

docker compose -f docker-compose-ce.yaml exec db \
  mariadb -u passbolt -p passbolt -e \
  "SELECT u.username, LEFT(s.data,45) AS cifrado
     FROM secrets s JOIN users u ON u.id = s.user_id
    ORDER BY u.username\G"
rafa@homelab: ~
*************************** 1. row ***********username: [email protected] cifrado: -----BEGIN PGP MESSAGE----- wV4Dc6GPjCVnvYkS *************************** 2. row ***********username: [email protected] cifrado: -----BEGIN PGP MESSAGE----- wV4Dxt13y1qaftsS
Dos copias del mismo secreto. En verde el principio, idéntico. En rojo, donde se separan.

Dos filas para un solo secreto. No es el mismo texto guardado dos veces: son dos cifrados distintos. Y fíjate en que los dos empiezan por wV4D y divergen justo después. Eso tampoco es casualidad.

Descodifica wV4D desde base64 y salen tres bytes: c1 5e 03. El 0xC1 es un paquete OpenPGP de tipo 1, «clave de sesión cifrada con clave pública», y el 03 su versión. Los ocho bytes siguientes son el identificador de la clave a la que va dirigida esa copia, y por eso los dos textos se separan exactamente ahí.

O sea que cada copia lleva escrito en la cabecera quién puede abrirla.

Y aquí hay una trampa que casi me come

Lo lógico es comprobar que esos identificadores son los de las claves de cada persona. Passbolt las guarda en gpgkeys:

docker compose -f docker-compose-ce.yaml exec db \
  mariadb -u passbolt -p passbolt -e \
  "SELECT u.username, g.key_id
     FROM gpgkeys g JOIN users u ON u.id = g.user_id
    ORDER BY u.username\G"
rafa@homelab: ~
username: [email protected] key_id: ECF21AEE22D5B79E username: [email protected] key_id: CC432BAF6B626766
Y no coinciden con los del texto cifrado. Aquí es donde uno cree que se equivocó.

El texto cifrado de Ana decía 73A18F8C2567BD89 y su tabla dice ECF21AEE22D5B79E. No cuadra. Yo di por hecho que coincidirían, escribí que coincidirían, y me equivoqué.

La razón es que una clave OpenPGP moderna no es una clave, son varias. Hay una principal, que firma y certifica, y colgando de ella una subclave de cifrado. Passbolt guarda el identificador de la principal, y el cifrado se hace contra la subclave. Se comprueba pidiéndole a gpg que enseñe las subclaves:

# Es una clave pública: no hay nada que proteger aquí
docker compose -f docker-compose-ce.yaml exec -T db \
  mariadb -u passbolt -p passbolt -N -B -e \
  "SELECT armored_key FROM gpgkeys g JOIN users u ON u.id=g.user_id
    WHERE u.username='[email protected]'" \
  | sed 's/\\n/\n/g' > ana.asc

docker compose -f docker-compose-ce.yaml exec -T passbolt \
  gpg --show-keys --with-subkey-fingerprints < ana.asc
rafa@homelab: ~
pub ed25519 2026-08-29 [SC] D8B097AEE03F91641989EF68ECF21AEE22D5B79Euid Ana Prueba <[email protected]>sub cv25519 2026-08-29 [E] 2F68E1CF694078CEBB473E9E73A18F8C2567BD89
Ahí está. La subclave marcada [E], la de cifrado, termina exactamente en el destinatario que llevaba la copia de Ana.

Si te sale un aviso de unsafe ownership on homedir, ignóralo: es gpg quejándose de los permisos del directorio dentro del contenedor, y no afecta a lo que estás mirando.

Con esto la cadena queda entera, y cada eslabón se puede repetir: un secreto, una copia por persona, cada copia dirigida a la subclave de cifrado de esa persona, y la clave privada que la abre no está en el servidor. No hay que creerle nada a nadie.

De paso, un detalle que dice bastante: esas claves son ed25519 para firmar y cv25519 para cifrar. Curva 25519, no RSA de hace quince años.

Antes de invitar a tu equipo

  1. Configura el SMTP y pruébalo. No inviertas ni un minuto en lo demás hasta que ese correo llegue.
  2. Activa el segundo factor en los ajustes de organización. TOTP es la opción sin dependencias externas.
  3. Cierra el autorregistro. Tienes las dos vías: la variable PASSBOLT_PLUGINS_SELF_REGISTRATION_ENABLED: "false", o el interruptor de Self Registration en los ajustes de organización, que en la captura de arriba se ve que no lleva estrella y por tanto lo tienes. Y activa también PASSBOLT_SECURITY_PREVENT_EMAIL_ENUMERATION.
  4. Explica el kit de recuperación antes del alta, no después. La gente pulsa «siguiente» sin leer.
  5. Documenta la baja. Revocar el acceso no descifra lo que esa persona ya vio: las contraseñas que conocía hay que rotarlas.

Los respaldos: la parte que no puedes saltarte

Diagrama: 14 KB de claves frente a 17 MB de base de datos; sin las claves la base no sirve
Tamaños medidos en una instancia recién instalada con una cuenta creada.

Una instancia de Passbolt son dos piezas, y las dos son imprescindibles: unos 14 KB de claves y unos 17 MB de base de datos.

Un respaldo de la base sin esos 14 KB no sirve absolutamente para nada. Los secretos están cifrados con OpenPGP: sin la clave privada del servidor, restaurar la base te deja datos que nadie puede descifrar.

# La base de datos. Se vuelca primero y solo se comprime si salió bien:
# con `| gzip > fichero` te queda un .gz válido y vacío aunque falle.
FECHA=$(date +%F)
docker compose -f docker-compose-ce.yaml exec -T db \
  mariadb-dump -u passbolt -p passbolt > passbolt-db-$FECHA.sql \
  && gzip passbolt-db-$FECHA.sql \
  || { echo "EL VOLCADO FALLÓ, no te fíes del fichero"; rm -f passbolt-db-$FECHA.sql; }

# Las claves del servidor y las de JWT
docker run --rm \
  -v passbolt_gpg_volume:/gpg -v passbolt_jwt_volume:/jwt \
  -v "$PWD":/salida alpine \
  tar czf /salida/passbolt-claves-$(date +%F).tgz /gpg /jwt

# Y compruébalo, que es el paso que todo el mundo se salta
ls -lh passbolt-db-*.sql.gz passbolt-claves-*.tgz
zcat passbolt-db-*.sql.gz | head -3

Ese && no es adorno. Si escribes mariadb-dump … | gzip > fichero.gz, la redirección crea el fichero aunque el volcado falle, y comprimir cero bytes da un .gz perfectamente válido de unos 20 bytes. Acabas con un respaldo que parece correcto y está vacío. Así se vuelca primero y solo se comprime si el volcado terminó bien.

Cifra el fichero de claves y guárdalo separado del volcado de la base: quien consiga las dos piezas a la vez tiene tu instancia entera. Y prueba la restauración, porque un respaldo que nunca se ha restaurado no es un respaldo.

Qué no tiene la edición gratuita

No hay que fiarse de ninguna tabla de precios para saber qué te falta: se ve en la propia interfaz, porque en los ajustes de organización las opciones de pago llevan una estrella al lado.

Ajustes de autenticacion de Passbolt: cuatro opciones marcadas con una estrella y Multi Factor Authentication sin ella
Los ajustes de autenticación en una instancia gratuita. Cuatro opciones con estrella, y Multi Factor Authentication sin ella.

Y ahí se ve de un vistazo el matiz que más importa: Multi Factor Authentication no lleva estrella, pero MFA Policy. Ofrecer el segundo factor es gratis. Obligar a que lo usen es de pago. Que es una diferencia enorme y no la cuenta ninguna comparativa.

Tabla: que trae la Community Edition y que queda reservado a la edicion Pro
Verificado en la interfaz y en su tabla de precios.

Dos ausencias pesan más que las demás. Puedes ofrecer MFA pero no puedes exigirlo: activas TOTP, YubiKey o Duo, y cada usuario decide. Y no hay recuperación de cuenta, que conviene no confundir con lo de más arriba. Volver a entrar desde un navegador nuevo sí se puede, y lo vimos: hace falta tu kit y tu frase, y el enlace lo emite recover_user. Lo que no existe aquí es que la organización pueda devolverte el acceso cuando has perdido el kit o la frase, porque eso necesita una copia en depósito que la edición gratuita no guarda. Si alguien de tu equipo olvida su frase, sus secretos se acabaron y ningún administrador puede hacer nada. En un equipo eso va a pasar, es cuestión de tiempo.

La edición Pro cuesta 4,90 $ por usuario y mes, facturada anual, con un mínimo de diez usuarios.

Las críticas de hace tres años, comprobadas hoy

En 2023, DB Tech publicó un vídeo explicando por qué no podía recomendar Passbolt para quien se autohospeda cosas en casa. Se cita mucho todavía. Como tenía una instancia recién montada, comprobé sus quejas una por una.

Su queja, en 2023Estado en 2026
Cientos de correos al importar la bóveda, uno por contraseñaCorregido. La notificación de contraseña creada viene desactivada de fábrica
Todos los usuarios se ven entre síSigue igual
La extensión del navegador es obligatoriaSigue igual
Hace falta el fichero de recuperación para volver a entrarSigue igual
La frase secreta es por dispositivo, hay que cambiarla en cada navegadorSigue igual

La primera ya no aplica: saqué los valores por defecto del contenedor y PASSBOLT_EMAIL_SEND_PASSWORD_CREATE viene en false. Su problema era importar la bóveda y recibir un correo por cada entrada creada; hoy esa notificación está apagada de serie.

La segunda la comprobé creando una cuenta con rol de usuario normal, sin privilegios. Esto es lo que ve:

Lista de usuarios vista por una cuenta sin privilegios: nombre, correo, rol y fecha de modificacion
Ana Empleada, rol «user», ve a los cuatro usuarios del servidor: nombre, correo, rol y cuándo se modificó cada cuenta.

Nombre completo, dirección de correo y rol, así que también sabe quiénes son los administradores. Passbolt lo justifica diciendo que hace falta para compartir, porque necesitas ver la clave pública de la persona con la que compartes. Es una explicación coherente con su modelo, pero conviene saberlo antes de meter a gente que no se conoce entre sí.

Un matiz sobre la crítica original: la columna dice Modified, no último acceso. Lo que se ve es cuándo se modificó la cuenta, no cuándo entró esa persona. Y el panel de administración sí está bien cerrado: ese mismo usuario recibe un 403 al intentar entrar.

Y una cosa que sí ha pasado desde entonces

En abril de 2026, un cambio en la caché de páginas de Chromium 147 dejó la extensión de Passbolt sin inicializarse tras cerrar sesión. Lo reconocieron como incidente y lo corrigieron el mismo día en la versión 5.11.1.

La respuesta fue rápida y transparente, que es lo que quieres de un proveedor de seguridad. Pero el episodio deja algo claro: en Passbolt el navegador es un punto único de fallo. Si una actualización rompe la extensión, no hay plan B, porque no existe una bóveda web que funcione sin ella. Eso no es un defecto de implementación, es la consecuencia de su modelo, y hay que contarlo entre los peajes.

Y algo que sí ha mejorado, y mucho

Hasta la versión 4, Passbolt cifraba los secretos de punta a punta pero los nombres y las direcciones de cada entrada los guardaba en claro. El servidor no podía leer tus contraseñas, pero sí sabía que tenías una cuenta en tu banco, otra en el panel de tu proveedor de nube y otra en el registrador del dominio. Para un modelo que presume de que el servidor no puede saber nada, era una grieta grande.

La versión 5 lo cerró con los llamados metadatos cifrados. En los análisis de 2025 se explica que hay que activarlo a mano tras actualizar, y es cierto, pero en una instalación nueva de hoy viene puesto de fábrica. Lo comprobé mirando la configuración de la instancia recién montada:

Los valores que trae una instalación limpia de 5.14.3:

rafa@homelab: ~
default_resource_types -> v5allow_creation_of_v5_resources -> trueallow_creation_of_v4_resources -> false  metadatos cifrados, de fábrica, en una instalación nueva
Lo que trae de serie una instalación limpia de 5.14.3. No hay que activar nada.

Y se puede verificar sin fiarse de nadie. Creas una contraseña, entras en la base de datos y miras qué guardó:

Antes de correrlo, dos avisos que ahorran un rato. Guarda una contraseña primero, porque si no la tabla está vacía y la consulta no devuelve nada, que parece un fallo y no lo es. Y no te olvides del \G del final: sin él la salida sale en forma de tabla y los bloques PGP la deforman hasta que no se lee.

# Ojo con el \G del final: sin él la salida sale en tabla y los bloques
# PGP la deforman hasta que no se lee nada.
docker compose -f docker-compose-ce.yaml exec db \
  mariadb -u passbolt -p passbolt -e \
  "SELECT name, uri, username, LEFT(metadata,60) AS metadata FROM resources\G"

docker compose -f docker-compose-ce.yaml exec db \
  mariadb -u passbolt -p passbolt -e \
  "SELECT LEFT(data,150) AS secreto FROM secrets\G"

Y esto es lo que hay guardado:

rafa@homelab: ~
*************************** 1. row **************** name: NULL uri: NULLusername: NULLmetadata: -----BEGIN PGP MESSAGE----- wV4Dxt13y1qaftsSAQdAptiBqxOF9mG *************************** 1. row **************** secreto: -----BEGIN PGP MESSAGE----- wV4Dxt13y1qaftsSAQdAdDDSfzDUQ4MbkKt9rA9L/zgHSJKoI/F8eVDqsU2z6AkwL4plfeRJTWOHe0UvFeBOrbH1ul0lxFl5dNUMbeoN
Salida real de una instancia 5.14.3 CE recién montada, sobre un recurso de prueba. El texto cifrado va recortado.

No hay nada legible. Ni el nombre de la entrada, ni la dirección del sitio, ni el usuario. Los tres salen NULL porque su contenido se fue a metadata, cifrado, y la contraseña vive aparte en secrets, cifrada también. Entré en la base con credenciales de administrador, desde el propio servidor, y no pude leer absolutamente nada.

Que quede claro por qué esto importa más que la captura de la configuración de antes: los ajustes dicen lo que debería pasar, y esto dice lo que pasa. Es la diferencia entre creerse una promesa y comprobarla.

rafa@homelab: ~
name uri metadataNULL NULL -----BEGIN PGP MESSAGE-----  el servidor guarda la credencial sin saber cómo se llama
La prueba, leída de la base de datos: nombre y dirección vacíos, y en su lugar un bloque OpenPGP.

El nombre y la dirección están vacíos, y en su lugar hay un bloque cifrado con OpenPGP. El servidor guarda tus credenciales sin saber siquiera cómo se llaman. Es raro encontrar eso en un gestor de contraseñas, porque complica la búsqueda, la recuperación y la auditoría, y esa es justo la razón por la que casi ninguno lo hace.

Veredicto

Dos contenedores, 219 MiB de memoria en reposo y 27 segundos de arranque. El modelo criptográfico más sólido de su categoría: tu clave privada vive en tu navegador y el servidor no puede descifrar nada, lo cual es comprobable leyendo el código y no un acto de fe.

A cambio pide tres peajes: la extensión del navegador es obligatoria, y con ella el navegador se convierte en un punto único de fallo; el correo es infraestructura y no un extra; y en la edición gratuita no existe la recuperación de cuentas, que no es lo mismo que no poder volver a entrar desde otro navegador.

Si administras sistemas y tu equipo es técnico, son peajes asumibles. A cambio te llevas un sitio para las credenciales de la infraestructura que no es una hoja de cálculo ni un chat privado, sin pagar por asiento, y con un modelo que puedes defender delante de un auditor sin bajar la mirada. Resuelve con presupuesto cero un problema que llevaba años sin resolver justamente por presupuesto.

Si tu equipo no lo es, te lo digo claro: la fricción de la extensión y la ausencia de recuperación van a acabar siendo tu problema, no el suyo. Tú serás quien reciba la llamada un domingo porque alguien perdió su kit y no puede entrar. Y no vas a poder hacer nada.

En las próximas entregas instalaremos Vaultwarden y Psono con el mismo nivel de detalle, y al final compararemos los tres con datos de haberlos usado.

Seguir leyendo en IT Rafa

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *