Autoalojar Vaultwarden en un VPS con Docker Compose

13 min de lectura·Matthieu·self-hostingfail2bansecuritypassword-managerdocker-composedockervaultwarden|

Despliega un gestor de contraseñas Vaultwarden fortificado en tu VPS. Docker Compose con contenedores de solo lectura, fail2ban, SMTP para 2FA, copias de seguridad y restauración, y acceso de emergencia.

Vaultwarden almacena todas las contraseñas que posees. Un despliegue descuidado es peor que no tener ninguno. Este tutorial configura Vaultwarden en un VPS con contenedores Docker fortificados, fail2ban, SMTP para autenticación de dos factores y un procedimiento de copia de seguridad y restauración.

Asumimos que Docker Engine y un reverse proxy (Nginx o Caddy) ya están funcionando en tu servidor. Si no es así, empieza con Docker en producción en un VPS: qué falla y cómo solucionarlo y Cómo configurar Nginx como reverse proxy.

¿Qué es Vaultwarden y en qué se diferencia de Bitwarden?

Vaultwarden es una reimplementación en Rust de la API del servidor Bitwarden. Se ejecuta como un único contenedor Docker, usa SQLite por defecto, consume alrededor de 50 MB de RAM en reposo y es totalmente compatible con todos los clientes oficiales de Bitwarden (extensiones de navegador, apps móviles, escritorio, CLI). El despliegue autoalojado oficial de Bitwarden requiere más de 11 contenedores y al menos 4 GB de RAM.

Vaultwarden Bitwarden autoalojado
Lenguaje Rust C# (.NET)
Contenedores 1 11+
RAM (reposo) ~50 MB ~2-4 GB
Base de datos SQLite (defecto), MySQL, PostgreSQL MSSQL (obligatorio)
Clientes Bitwarden Compatibilidad total Compatibilidad total
SSO (OpenID Connect) Desde la versión 1.35.0 Solo plan Enterprise
Soporte oficial Comunidad Bitwarden Inc.
Licencia AGPL-3.0 Propietaria (SSPL para el servidor)

Vaultwarden se llamaba anteriormente bitwarden_rs. Si encuentras ese nombre en guías antiguas, se refiere al mismo proyecto.

¿Cómo despliego Vaultwarden con Docker Compose en un VPS?

Crea una estructura de directorios para los datos y la configuración de Vaultwarden. Todos los datos persistentes residen en un único directorio que respaldarás más adelante.

mkdir -p /opt/vaultwarden/data
cd /opt/vaultwarden

Genera un token de administración hasheado con argon2. Nunca almacenes el token de admin en texto plano.

docker run --rm -it vaultwarden/server:1.35.4 /vaultwarden hash

El comando pide una contraseña dos veces y luego muestra una cadena PHC argon2id:

Generate an Argon2id PHC string using the 'bitwarden' preset:

Password:
Confirm Password:
ADMIN_TOKEN='$argon2id$v=19$m=65540,t=3,p=4$S2mMOA8VnTtIOb3J8Gj9Jw$9cZ0YIKmGxfWEqSMKFMbORkBiW7hMGCls3SXAFXSIVE'

Guarda esa cadena. La necesitarás en el archivo de entorno.

Crea el archivo de secretos con permisos restringidos:

touch /opt/vaultwarden/.env
chmod 600 /opt/vaultwarden/.env

Edita /opt/vaultwarden/.env con tus valores:

DOMAIN=https://vault.example.com
ADMIN_TOKEN='$argon2id$v=19$m=65540,t=3,p=4$your-hash-here'

SIGNUPS_ALLOWED=true
INVITATIONS_ALLOWED=true
EMERGENCY_ACCESS_ALLOWED=true
ORG_CREATION_USERS=all

SHOW_PASSWORD_HINT=false
IP_HEADER=X-Real-IP
LOG_FILE=/data/vaultwarden.log
LOG_LEVEL=warn

SMTP_HOST=smtp.example.com
SMTP_FROM=vault@example.com
SMTP_PORT=587
SMTP_SECURITY=starttls
SMTP_USERNAME=vault@example.com
SMTP_PASSWORD=your-smtp-password

SHOW_PASSWORD_HINT=false evita la filtración de pistas a cualquiera que conozca un nombre de usuario. IP_HEADER=X-Real-IP indica a Vaultwarden que lea la IP del cliente desde la cabecera de tu reverse proxy, necesario para que fail2ban bloquee la dirección correcta.

Ahora crea el archivo Compose.

¿Cómo fortifico el contenedor Docker de Vaultwarden?

El archivo Compose a continuación fija la versión de la imagen, elimina todas las capabilities de Linux, habilita un sistema de archivos raíz de solo lectura, bloquea la escalada de privilegios y establece límites de memoria. Estos son los valores por defecto de esta guía, no complementos opcionales.

Crea /opt/vaultwarden/compose.yaml:

services:
  vaultwarden:
    image: vaultwarden/server:1.35.4
    container_name: vaultwarden
    restart: unless-stopped
    env_file: .env
    user: "1000:1000"
    security_opt:
      - no-new-privileges:true
    cap_drop:
      - ALL
    read_only: true
    tmpfs:
      - /tmp
    volumes:
      - ./data:/data
    ports:
      - "127.0.0.1:8080:80"
    deploy:
      resources:
        limits:
          memory: 512M
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:80/alive"]
      interval: 30s
      timeout: 5s
      retries: 3
  • user: "1000:1000" ejecuta el proceso como usuario no-root dentro del contenedor. Debes ajustar la propiedad del directorio de datos: chown -R 1000:1000 /opt/vaultwarden/data.
  • cap_drop: ALL elimina todas las capabilities de Linux. Vaultwarden no necesita ninguna porque escucha en el puerto 80 dentro del contenedor (un puerto no privilegiado en este contexto ya que Docker gestiona el mapeo).
  • read_only: true impide que el contenedor escriba en cualquier lugar excepto en los volúmenes montados explícitamente y tmpfs. Si algo explota Vaultwarden, no puede escribir en el sistema de archivos del contenedor.
  • ports: "127.0.0.1:8080:80" vincula solo a localhost. El reverse proxy gestiona el tráfico externo. Nunca expongas Vaultwarden directamente a Internet.
  • deploy.resources.limits.memory: 512M evita que un proceso descontrolado consuma toda la RAM del servidor. Vaultwarden usa ~50 MB en reposo y ~100-150 MB bajo carga. 512 MB dan margen de sobra.

Corrige la propiedad del directorio de datos e inicia el contenedor:

chown -R 1000:1000 /opt/vaultwarden/data
docker compose up -d
[+] Running 1/1Container vaultwarden  Started

Comprueba el estado del contenedor:

docker compose ps
NAME          IMAGE                       COMMAND       SERVICE       CREATED          STATUS                    PORTS
vaultwarden   vaultwarden/server:1.35.4   "/start.sh"   vaultwarden   Up 30 seconds (healthy)   127.0.0.1:8080->80/tcp

El estado (healthy) significa que el healthcheck pasó. Revisa los logs en busca de errores de inicio:

docker compose logs --tail 20

Los logs muestran Vaultwarden arrancando en el puerto 80 dentro del contenedor, sin errores.

Configuración del reverse proxy

Tu reverse proxy reenvía el tráfico HTTPS a 127.0.0.1:8080. Aquí tienes un bloque de servidor Nginx mínimo:

server {
    listen 443 ssl;
    http2 on;
    server_name vault.example.com;

    ssl_certificate /etc/letsencrypt/live/vault.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/vault.example.com/privkey.pem;

    client_max_body_size 525M;
    server_tokens off;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

client_max_body_size 525M permite la subida de archivos adjuntos hasta el límite de Bitwarden. server_tokens off oculta la versión de Nginx en las respuestas, ya que la divulgación de versión ayuda a los atacantes a apuntar a vulnerabilidades conocidas.

Desde Vaultwarden 1.29.0, el tráfico WebSocket se sirve en el mismo puerto que HTTP. No se necesita una ruta proxy separada para /notifications/hub. Si ves WEBSOCKET_ENABLED en tutoriales antiguos, ignóralo. Esa variable se depreció en 1.29.0 y se eliminó en 1.31.0.

Para detalles de configuración de Nginx, consulta Cómo configurar Nginx como reverse proxy y Configurar SSL/TLS de Let's Encrypt para Nginx en Debian 12 y Ubuntu 24.04.

¿Cómo configuro el correo SMTP para Vaultwarden?

Vaultwarden necesita SMTP para enviar códigos de verificación por correo, emails de configuración 2FA, invitaciones de organización y notificaciones de acceso de emergencia. Sin SMTP, funciones como el registro por invitación, 2FA por email y acceso de emergencia no funcionan.

Las variables de entorno principales son SMTP_HOST, SMTP_PORT, SMTP_SECURITY, SMTP_USERNAME, SMTP_PASSWORD y SMTP_FROM. Usa SMTP_PORT=587 con SMTP_SECURITY=starttls para la mayoría de proveedores, o SMTP_PORT=465 con SMTP_SECURITY=force_tls para TLS implícito.

Estas variables ya están incluidas en el archivo .env anterior. Después de iniciar el contenedor, prueba el envío de correo: inicia sesión en la bóveda web en https://vault.example.com, crea tu cuenta, ve a Settings > Security > Two-step Login y activa la 2FA por email. Si recibes el código de verificación, SMTP funciona.

Revisa los logs si el envío falla:

docker compose logs | grep -i smtp

Problemas frecuentes:

  • Fallo de autenticación: comprueba SMTP_USERNAME y SMTP_PASSWORD. Los caracteres especiales en la contraseña pueden necesitar comillas simples en el archivo .env.
  • Conexión rechazada en el puerto 587: algunos proveedores de VPS bloquean los puertos salientes 25 y 587 por defecto. Consulta con tu proveedor o prueba el puerto 465 con force_tls.
  • Error de certificado: el certificado TLS del servidor SMTP debe ser válido. Los certificados autofirmados requieren SMTP_ACCEPT_INVALID_CERTS=true (no recomendado en producción).
Variable Propósito Ejemplo
SMTP_HOST Nombre del servidor de correo smtp.example.com
SMTP_PORT Puerto de conexión 587
SMTP_SECURITY Método TLS starttls o force_tls
SMTP_FROM Dirección del remitente vault@example.com
SMTP_USERNAME Usuario de autenticación vault@example.com
SMTP_PASSWORD Contraseña de autenticación (almacenada en .env, chmod 600)
SMTP_AUTH_MECHANISM Tipo de autenticación (opcional) Login

¿Cómo protejo el panel de administración de Vaultwarden?

El panel de administración en /admin permite gestionar usuarios, ver la configuración y cambiar ajustes. Está protegido por el ADMIN_TOKEN que generaste antes. El hash argon2 significa que el token sin procesar nunca se almacena en tu archivo .env. Aunque alguien lea el archivo, obtiene un hash, no la contraseña.

Después de la configuración inicial (creación de cuenta, configuración SMTP, desactivación de registros), tienes dos opciones:

Opción 1: Desactivar el panel de administración por completo. Elimina o comenta ADMIN_TOKEN en .env y reinicia:

docker compose down && docker compose up -d

Sin ADMIN_TOKEN definido, el endpoint /admin devuelve un 404. Es la opción más segura para despliegues de un solo usuario.

Opción 2: Restringir el acceso mediante el reverse proxy. Mantén el panel activo pero bloquea el acceso externo:

location /admin {
    allow 127.0.0.1;
    deny all;

    proxy_pass http://127.0.0.1:8080;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}

Accede al panel de administración a través de un túnel SSH cuando lo necesites:

ssh -L 8888:127.0.0.1:443 user@your-vps

Luego abre https://127.0.0.1:8888/admin en tu navegador.

Desactivar el registro público

Una vez que tu cuenta existe, desactiva los registros abiertos. Edita /opt/vaultwarden/.env:

SIGNUPS_ALLOWED=false

Reinicia el contenedor:

cd /opt/vaultwarden && docker compose down && docker compose up -d

Los nuevos usuarios aún pueden unirse mediante invitaciones de organización si INVITATIONS_ALLOWED=true. Esto te permite añadir miembros al equipo sin abrir el registro a todo el mundo.

¿Cómo configuro fail2ban para Vaultwarden en Docker?

Fail2ban monitoriza el archivo de logs de Vaultwarden en busca de intentos de inicio de sesión fallidos y bloquea las IPs infractoras. Como Vaultwarden se ejecuta en Docker, la regla de bloqueo debe apuntar a la cadena iptables DOCKER-USER. Las reglas de la cadena INPUT estándar no afectan al tráfico enrutado por Docker.

El contenedor Vaultwarden escribe los logs en /opt/vaultwarden/data/vaultwarden.log (mapeado desde /data/vaultwarden.log dentro del contenedor) porque definimos LOG_FILE=/data/vaultwarden.log en el entorno.

Para una guía detallada de instalación de fail2ban, consulta Instalar y configurar Fail2Ban en un VPS Linux.

Filtro de inicio de sesión

Crea /etc/fail2ban/filter.d/vaultwarden.local:

[INCLUDES]
before = common.conf

[Definition]
failregex = ^.*?Username or password is incorrect\. Try again\. IP: <ADDR>\. Username:.*$
ignoreregex =

Filtro del panel de administración

Crea /etc/fail2ban/filter.d/vaultwarden-admin.local:

[INCLUDES]
before = common.conf

[Definition]
failregex = ^.*?Invalid admin token\. IP: <ADDR>.*$
ignoreregex =

Configuración del jail

Crea /etc/fail2ban/jail.d/vaultwarden.local:

[vaultwarden]
enabled = true
port = http,https
filter = vaultwarden
action = iptables-allports[name=vaultwarden, chain=DOCKER-USER]
logpath = /opt/vaultwarden/data/vaultwarden.log
maxretry = 3
bantime = 14400
findtime = 14400
backend = pyinotify

[vaultwarden-admin]
enabled = true
port = http,https
filter = vaultwarden-admin
action = iptables-allports[name=vaultwarden-admin, chain=DOCKER-USER]
logpath = /opt/vaultwarden/data/vaultwarden.log
maxretry = 3
bantime = 14400
findtime = 14400
backend = pyinotify
Parámetro Valor Por qué
chain DOCKER-USER Docker sortea la cadena INPUT. Las reglas deben ir en DOCKER-USER para afectar al tráfico de contenedores.
maxretry 3 Tres intentos fallidos activan el bloqueo. Un usuario legítimo rara vez falla más de dos veces.
bantime 14400 Bloqueo de cuatro horas. Suficiente para disuadir la fuerza bruta, no tanto como para bloquear permanentemente a un usuario legítimo que tecleó mal.
findtime 14400 Cuenta los fallos dentro de una ventana de cuatro horas.
backend pyinotify Monitorización de logs basada en archivos. El backend systemd por defecto no puede leer archivos de log de contenedores Docker.

Reinicia fail2ban y comprueba el jail:

systemctl restart fail2ban
fail2ban-client status vaultwarden
Status for the jail: vaultwarden
|- Filter
|  |- Currently failed: 0
|  |- Total failed:     0
|  `- File list:        /opt/vaultwarden/data/vaultwarden.log
`- Actions
   |- Currently banned: 0
   |- Total banned:     0
   `- Banned IP list:

Prueba la regex contra el formato de log real:

fail2ban-regex /opt/vaultwarden/data/vaultwarden.log /etc/fail2ban/filter.d/vaultwarden.local

Si aún no existen intentos fallidos, la salida muestra 0 matched. Es lo esperado. Provoca un inicio de sesión fallido a través de la bóveda web y vuelve a ejecutar para confirmar que la regex coincide.

¿Cómo conecto las extensiones del navegador y las apps móviles a Vaultwarden?

Todos los clientes oficiales de Bitwarden funcionan con Vaultwarden. El único cambio es apuntarlos a la URL de tu servidor en lugar de bitwarden.com.

Extensión del navegador (Chrome, Firefox, Safari):

  1. Instala la extensión Bitwarden desde la tienda de complementos de tu navegador
  2. En la pantalla de inicio de sesión, haz clic en el icono del engranaje (o «Self-hosted» en versiones recientes)
  3. Establece Server URL en https://vault.example.com
  4. Guarda e inicia sesión con tus credenciales

App móvil (iOS, Android):

  1. Instala la app Bitwarden desde App Store o Google Play
  2. Antes de iniciar sesión, pulsa el icono del engranaje en la pantalla de inicio de sesión
  3. Establece Server URL en https://vault.example.com
  4. Guarda e inicia sesión

App de escritorio:

  1. Antes de iniciar sesión, haz clic en el icono del engranaje
  2. Establece Server URL en https://vault.example.com

CLI:

bw config server https://vault.example.com
bw login

Todos los clientes se sincronizan a través de tu instancia Vaultwarden. Los datos de la bóveda nunca pasan por los servidores de Bitwarden.

¿Cómo configuro el acceso de emergencia en Vaultwarden?

El acceso de emergencia permite que un contacto de confianza acceda a tu bóveda o la tome bajo su control si no estás disponible. Requiere que SMTP esté configurado porque Vaultwarden envía correos de notificación durante el proceso.

Confirma que la función está habilitada en tu .env:

EMERGENCY_ACCESS_ALLOWED=true

Configurar un contacto de confianza:

  1. Inicia sesión en la bóveda web en https://vault.example.com
  2. Ve a Settings > Emergency Access
  3. Haz clic en Add emergency contact
  4. Introduce el correo de la persona de confianza (debe tener cuenta en tu instancia Vaultwarden)
  5. Elige el nivel de acceso:
    • View: el contacto puede ver los elementos de tu bóveda (solo lectura)
    • Takeover: el contacto puede restablecer tu contraseña maestra y tomar el control total
  6. Establece el tiempo de espera (1 a 90 días). Es el plazo entre la solicitud de acceso del contacto y la obtención efectiva. Recibes una notificación por correo y puedes rechazar la solicitud durante ese período.
  7. Haz clic en Save

El contacto de confianza recibe un correo de invitación. Tras aceptar, aparece como contacto de emergencia pendiente. El tiempo de espera funciona como un mecanismo de seguridad: si no respondes dentro de los días configurados, el acceso se concede automáticamente.

Para una bóveda personal, 7 días de espera con acceso View es razonable. Para infraestructura de equipo compartida, considera tiempos más cortos.

¿Cómo hago copias de seguridad y restauro una instancia Vaultwarden?

Vaultwarden almacena todo en el directorio /data: la base de datos SQLite (db.sqlite3), archivos adjuntos, caché de iconos y configuración. Una copia de seguridad correcta captura todo esto de forma consistente.

La base de datos SQLite debe respaldarse con sqlite3 .backup, no copiando el archivo directamente. Copiar un archivo SQLite en uso puede producir una copia corrupta si ocurre una escritura durante la copia. El comando .backup crea una instantánea consistente.

Qué respaldar Ubicación Método Frecuencia
Base de datos SQLite /opt/vaultwarden/data/db.sqlite3 sqlite3 .backup Diaria
Adjuntos /opt/vaultwarden/data/attachments/ rsync o cp -a Diaria
Caché de iconos /opt/vaultwarden/data/icon_cache/ Omitir (se regenera automáticamente) -
Archivo de entorno /opt/vaultwarden/.env cp Al modificar
Archivo Compose /opt/vaultwarden/compose.yaml cp Al modificar

Script de copia de seguridad

Para copias automatizadas, el script usa age con un archivo de clave de destinatario. Esto evita solicitudes interactivas de frase de paso para que el script pueda ejecutarse desde cron.

Genera un par de claves (una sola vez):

apt install age
age-keygen -o /opt/vaultwarden/backup-key.txt
chmod 600 /opt/vaultwarden/backup-key.txt

El comando muestra la clave pública en stdout. Guárdala en un archivo de destinatario:

age-keygen -y /opt/vaultwarden/backup-key.txt > /opt/vaultwarden/backup-key.pub

Guarda una copia de backup-key.txt (la clave privada) fuera del servidor. La necesitas para descifrar las copias de seguridad. Si pierdes esta clave, tus copias cifradas serán irrecuperables.

Crea /opt/vaultwarden/backup.sh:

#!/bin/bash
set -euo pipefail

BACKUP_DIR="/opt/vaultwarden/backups"
DATA_DIR="/opt/vaultwarden/data"
DATE=$(date +%Y-%m-%d_%H%M)
BACKUP_FILE="${BACKUP_DIR}/vaultwarden-${DATE}.tar"
RECIPIENT="/opt/vaultwarden/backup-key.pub"

mkdir -p "${BACKUP_DIR}"

# Back up SQLite database consistently
sqlite3 "${DATA_DIR}/db.sqlite3" ".backup '${BACKUP_DIR}/db-${DATE}.sqlite3'"

# Package database + attachments + config
tar cf "${BACKUP_FILE}" \
  -C "${BACKUP_DIR}" "db-${DATE}.sqlite3" \
  -C "${DATA_DIR}" attachments/ \
  -C /opt/vaultwarden .env compose.yaml 2>/dev/null || true

# Encrypt with age recipient key (non-interactive)
age -R "${RECIPIENT}" -o "${BACKUP_FILE}.age" "${BACKUP_FILE}"

# Clean up unencrypted files
rm -f "${BACKUP_FILE}" "${BACKUP_DIR}/db-${DATE}.sqlite3"

# Remove backups older than 30 days
find "${BACKUP_DIR}" -name "*.age" -mtime +30 -delete

echo "Backup complete: ${BACKUP_FILE}.age"
chmod 700 /opt/vaultwarden/backup.sh

Para copias de seguridad diarias automatizadas, añade una tarea cron:

echo "0 3 * * * root /opt/vaultwarden/backup.sh >> /var/log/vaultwarden-backup.log 2>&1" > /etc/cron.d/vaultwarden-backup
chmod 644 /etc/cron.d/vaultwarden-backup

Para copias fuera del servidor, envía la copia cifrada a un servidor remoto o almacenamiento de objetos:

rsync -az /opt/vaultwarden/backups/*.age backup-user@remote-server:/backups/vaultwarden/

Procedimiento de restauración

Una copia de seguridad que nunca has restaurado es una copia en la que no puedes confiar. El procedimiento completo:

# Stop the container
cd /opt/vaultwarden && docker compose down

# Decrypt the backup
age -d -i /opt/vaultwarden/backup-key.txt -o /tmp/vaultwarden-restore.tar /opt/vaultwarden/backups/vaultwarden-2026-03-20_0300.tar.age

# Extract
mkdir -p /tmp/vaultwarden-restore
tar xf /tmp/vaultwarden-restore.tar -C /tmp/vaultwarden-restore

# Replace the database (delete WAL files first)
rm -f /opt/vaultwarden/data/db.sqlite3-wal /opt/vaultwarden/data/db.sqlite3-shm
cp /tmp/vaultwarden-restore/db-2026-03-20_0300.sqlite3 /opt/vaultwarden/data/db.sqlite3
chown 1000:1000 /opt/vaultwarden/data/db.sqlite3

# Restore attachments
rsync -a /tmp/vaultwarden-restore/attachments/ /opt/vaultwarden/data/attachments/
chown -R 1000:1000 /opt/vaultwarden/data/attachments/

# Start the container
docker compose up -d

# Clean up
rm -rf /tmp/vaultwarden-restore /tmp/vaultwarden-restore.tar

Debes eliminar los archivos WAL (Write-Ahead Log) y SHM antes de restaurar. Estos archivos pertenecen al estado anterior de la base de datos. Iniciar Vaultwarden con una base de datos restaurada pero archivos WAL obsoletos corrompe los datos.

Tras la restauración, inicia sesión en la bóveda web y confirma que tus entradas están presentes.

¿Cómo actualizo Vaultwarden de forma segura?

Fija tu imagen a un tag de versión específico (usamos 1.35.4). Nunca uses :latest en producción porque no puedes rastrear qué cambió ni revertir de forma fiable.

Para actualizar:

cd /opt/vaultwarden

# Back up first
./backup.sh

# Pull the new version
docker compose pull

# Recreate the container
docker compose up -d

Antes de hacer pull, edita compose.yaml para cambiar el tag de la imagen a la nueva versión. Consulta las notas de la versión en busca de cambios que rompan compatibilidad.

docker compose logs --tail 30

Si la actualización causa problemas, restaura desde tu copia de seguridad:

# Revert compose.yaml to the old version tag
docker compose down
# Follow the restore procedure above
docker compose up -d

¿Algo salió mal?

El contenedor se detiene inmediatamente:

docker compose logs

Busca errores de permisos. La directiva user: 1000:1000 requiere propiedad correspondiente en /opt/vaultwarden/data. Ejecuta chown -R 1000:1000 /opt/vaultwarden/data e inténtalo de nuevo.

No se puede acceder a la bóveda web:

Comprueba que el reverse proxy está reenviando a 127.0.0.1:8080:

curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8080/alive

Una respuesta 200 significa que Vaultwarden está funcionando. El problema está en la configuración de tu reverse proxy.

Fail2ban no bloquea:

fail2ban-regex /opt/vaultwarden/data/vaultwarden.log /etc/fail2ban/filter.d/vaultwarden.local

Si la regex no coincide con ninguna línea, comprueba que LOG_FILE=/data/vaultwarden.log esté definido en .env y que el archivo de log exista en /opt/vaultwarden/data/vaultwarden.log.

Los correos no se envían:

docker compose logs | grep -i "smtp\|mail\|email"

Verifica que tu VPS permite conexiones salientes en el puerto SMTP:

nc -zv smtp.example.com 587

Errores de base de datos bloqueada:

Esto puede ocurrir si copias el archivo de base de datos mientras Vaultwarden está en ejecución. Usa siempre sqlite3 .backup para las copias de seguridad y detén siempre el contenedor antes de restaurar.

Ubicación de los logs:

# Application logs
docker compose logs -f

# Log file (if LOG_FILE is set)
tail -f /opt/vaultwarden/data/vaultwarden.log

# Fail2ban logs
journalctl -u fail2ban -f

Para seguridad de contenedores Docker más allá de lo que cubre este tutorial, consulta Hardening de seguridad en Docker: modo rootless, seccomp y AppArmor en un VPS. Para estrategias de copia de seguridad de todos tus servicios Docker, consulta Copia de seguridad y restauración de volúmenes Docker en un VPS.


Copyright 2026 Virtua.Cloud. Todos los derechos reservados. Este contenido es una obra original del equipo de Virtua.Cloud. La reproducción, republicación o redistribución sin permiso escrito está prohibida.

¿Listo para probarlo?

Despliega tu propio servidor en segundos. Linux, Windows o FreeBSD.

Ver planes VPS