1. Introducción
Vaultwarden es una reimplementación en Rust, ligera, de la API de servidor de Bitwarden. Permite usar los clientes oficiales de Bitwarden (navegador, extensión, móvil, escritorio) contra un servidor propio, autoalojado, sin depender de la nube de Bitwarden. Esta guía lo levanta en un único contenedor Docker, con HTTPS servido por el propio Vaultwarden.
localhost. Una IP normal de la red servida por http no lo cumple, y sin ello el navegador deshabilita el cifrado que el propio vault necesita para funcionar. La solución más simple aquí no es un proxy aparte: Vaultwarden puede servir HTTPS él mismo con un certificado autofirmado, montado como volumen y activado con una única variable (ROCKET_TLS). Un solo contenedor, sin piezas adicionales.2. Variables de esta guía
Todos los bloques usan el siguiente marcador en MAYÚSCULAS. Sustitúyelo por el valor real de tu servidor.
| Marcador | Qué es | Dónde se obtiene |
|---|---|---|
IP_HOST_DOCKER | IP del servidor donde corre Docker | La interfaz de red de ese servidor (ip a) |
IP_HOST_DOCKER es también el texto que se escribe como CN y subjectAltName al generar el certificado (sección 6). Si esa IP cambia más adelante, hay que regenerar el certificado.8444, cámbialo por otro libre (por ejemplo 8445) en las secciones 7, 8, 10, 11, 12 y 13 antes de arrancar. Dos contenedores no pueden publicar el mismo puerto del host a la vez, aunque cada uno tenga su propio certificado.3. Arquitectura y flujo
Un único contenedor recibe todo el tráfico HTTPS directamente, sin proxy delante: el propio Vaultwarden termina el TLS con el certificado autofirmado montado como volumen.
[Navegador, en cualquier equipo de la red]
|
| https://IP_HOST_DOCKER:8444 (certificado autofirmado)
v
[vaultwarden] :8444 (HTTPS servido por el propio contenedor)
|
v
./vw-data (volumen persistente: bóveda, config, adjuntos)
./certs (volumen: cert.pem + key.pem)
4. Requisitos
- Un servidor con Ubuntu Server, físico o virtual, con red en la misma LAN desde la que vas a acceder.
- Docker Engine y el plugin Docker Compose (
docker compose, sin guion) instalados en ese servidor. - No hace falta salida a internet: todo el flujo vive dentro de la red local.
- Un navegador cualquiera en otro equipo de la misma red (o en el propio servidor).
- Confirmar que el puerto
8444está libre en ese servidor (ss -tlnp | grep 8444); si ya lo usa otro contenedor, elige otro puerto antes de empezar.
5. Crear la carpeta del stack
sudo mkdir -p /docker/vaultwarden && cd /docker/vaultwarden sudo mkdir -p vw-data certs
6. Generar el certificado autofirmado
Certificado con clave EC (curva elíptica), válido para la IP del servidor:
cd /docker/vaultwarden sudo openssl ecparam -name prime256v1 -genkey -noout -out certs/key.pem sudo openssl req -new -x509 -key certs/key.pem -out certs/cert.pem -days 825 \ -subj "/CN=IP_HOST_DOCKER" \ -addext "subjectAltName=IP:IP_HOST_DOCKER"
7. Crear el .env
sudo nano .env
Pega esto, sustituyendo IP_HOST_DOCKER y dejando ADMIN_TOKEN pendiente hasta la sección 9:
# URL de acceso: IP del servidor + puerto HTTPS
DOMAIN=https://IP_HOST_DOCKER:8444
# Se rellena en la sección 9, con el hash generado por "vaultwarden hash"
ADMIN_TOKEN=PENDIENTE_SECCION_9
# Registro abierto mientras se hace la prueba; se cierra en la sección 11
SIGNUPS_ALLOWED=true
# HTTPS servido por el propio Vaultwarden
ROCKET_TLS={certs="/ssl/cert.pem",key="/ssl/key.pem"}
ROCKET_PORT=8444
/ssl/cert.pem y /ssl/key.pem son rutas dentro del contenedor, no del host: el volumen ./certs:/ssl:ro del docker-compose.yml (sección 8) es el que hace que coincidan con los ficheros generados en la sección 6.ADMIN_TOKEN se carga aquí con env_file: en vez de con environment: ${ADMIN_TOKEN} en el docker-compose.yml, y es a propósito: el hash de la sección 9 lleva varios símbolos $ dentro ($argon2id$v=19$...), y con env_file: Docker Compose los pasa tal cual al contenedor, sin intentar interpretarlos como sus propias variables. Si alguna vez migras esto a environment:, tendrías que duplicar cada $ como $$.8. Crear el docker-compose.yml
sudo nano docker-compose.yml
services:
vaultwarden:
image: vaultwarden/server:latest
container_name: vaultwarden
restart: unless-stopped
env_file:
- .env
volumes:
- ./vw-data:/data
- ./certs:/ssl:ro
ports:
- "8444:8444"
ROCKET_TLS (sección 7).9. Generar el ADMIN_TOKEN
El panel /admin exige un token hasheado con Argon2, no una contraseña en texto plano:
docker run --rm -it vaultwarden/server:latest /vaultwarden hash
Introduce la contraseña que quieras usar para /admin. Copia el hash completo (empieza por $argon2id$...) y sustitúyelo en .env:
sudo nano .env # Sustituye la línea: # ADMIN_TOKEN=PENDIENTE_SECCION_9 # por: # ADMIN_TOKEN=$argon2id$v=19$m=...(hash completo)...
.env, sin comillas adicionales. La contraseña en claro no se guarda en ningún sitio: solo tú la recuerdas para entrar en /admin.10. Arrancar el stack y verificar
cd /docker/vaultwarden docker compose up -d docker compose ps
docker logs -f vaultwarden
Busca una línea de arranque sin errores de certificado ni de permisos. Ctrl+C para salir del log (el contenedor sigue corriendo).
curl -kv https://IP_HOST_DOCKER:8444/alive
11. Crear la cuenta y cerrar el registro
Desde el navegador, en https://IP_HOST_DOCKER:8444, pulsa Crear cuenta y registra tu email y contraseña maestra. Inicia sesión y confirma que la bóveda carga.
Entra en el panel de administración:
https://IP_HOST_DOCKER:8444/admin
Usa la contraseña en claro de la sección 9 (no el hash). Una vez creada tu cuenta, cierra el registro público:
sudo nano .env # Cambia: # SIGNUPS_ALLOWED=true # por: # SIGNUPS_ALLOWED=false docker compose up -d
13. Tabla de puertos y componentes
| Puerto | Componente | Sentido de la conexión | Para qué sirve |
|---|---|---|---|
| 8444/tcp | vaultwarden (Docker) | Navegador → contenedor | HTTPS servido por el propio Vaultwarden (certificado autofirmado, sin proxy) |
| — | ./vw-data (volumen) | Contenedor ↔ host | Persistencia de la bóveda, adjuntos y configuración |
| — | ./certs (volumen) | Host → contenedor (solo lectura) | Certificado y clave usados por ROCKET_TLS |
14. Errores comunes
| Problema | Causa probable | Solución |
|---|---|---|
El contenedor no arranca, error de port is already allocated |
Otro contenedor en el mismo servidor ya está publicando el puerto 8444 (o el que hayas elegido) | docker ps para localizar qué lo está usando; cambiar el puerto en las secciones 7, 8, 10, 11 y 12, o parar el otro servicio |
El contenedor no arranca, error relacionado con ROCKET_TLS |
Ruta incorrecta en el valor de ROCKET_TLS, o los ficheros cert.pem/key.pem no están en ./certs |
Revisar que ./certs contiene ambos ficheros (sección 6) y que la ruta en .env es exactamente /ssl/cert.pem y /ssl/key.pem (sección 7) |
El navegador o curl -k dan un error de protocolo TLS raro (no el aviso normal de certificado no confiable, sino algo tipo alert internal error o conexión que se corta a medias) |
Puede ser un problema del propio sistema o del contenedor, no del certificado en sí | Aislarlo probando el mismo cert.pem/key.pem directamente con openssl s_server -key certs/key.pem -cert certs/cert.pem -accept 9999 -www fuera de Docker; si eso también falla, el problema es del sistema, no de Vaultwarden |
/admin da "no autorizado" |
Se está usando el hash guardado en .env en vez de la contraseña en claro |
Usar la contraseña que escribiste al ejecutar vaultwarden hash (sección 9), no el hash resultante |
Cambios en .env no se aplican |
Falta relanzar el contenedor tras editar el archivo | docker compose up -d de nuevo (Vaultwarden no recarga en caliente) |
15. Notas de ampliación
Este despliegue cubre lo esencial: un contenedor, HTTPS propio y una cuenta de usuario. Para un uso más allá de un entorno de pruebas, conviene ampliar con:
- Importar el certificado en el almacén de confianza de cada equipo cliente, para que el aviso de "certificado no confiable" desaparezca de forma permanente.
- Dominio propio + Let's Encrypt en vez de certificado autofirmado, si el servicio va a estar accesible desde fuera de la red local.
- SSO corporativo (Entra ID, Google Workspace u otro proveedor SAML/OIDC), para centralizar el inicio de sesión con las cuentas ya existentes en la organización.
- Apps cliente (extensión de navegador, móvil, escritorio de Bitwarden) apuntando al mismo
DOMAIN, una vez el certificado esté importado o sea válido. - Copias de seguridad de
./vw-data(incluye la bóveda cifrada y la configuración del servidor).