Chapter 11 of Be Your Own Cloud deploys Vaultwarden on the proxy network from Chapter 8, with no port published on the host at all, and explains why. This page walks the same deploy click by click and adds what comes after: a safer admin token, two-factor on your own account, and a backup you can open even if the server is gone.
You need Chapter 8’s reverse proxy and certificate working (Reverse Proxy and HTTPS), and Chapter 10’s Pi-hole answering for vault.home.yourdomain.com.
Deploy it
mkdir -p /opt/stacks/vaultwarden
cd /opt/stacks/vaultwarden
The compose file:
services:
vaultwarden:
image: vaultwarden/server:1.37.3
container_name: vaultwarden
restart: unless-stopped
volumes:
- ./data:/data
environment:
# set in .env: true now, false once your account exists
- SIGNUPS_ALLOWED=${SIGNUPS_ALLOWED}
- ADMIN_TOKEN=${ADMIN_TOKEN}
networks:
# Chapter 8's shared network -- no host port published at all
- proxy
networks:
proxy:
external: true Then the admin token and the .env that holds it:
openssl rand -base64 48 # your ADMIN_TOKEN value, per Chapter 9 # .env
ADMIN_TOKEN=the_value_from_the_line_above
SIGNUPS_ALLOWED=true Lock the file down (Chapter 9) and start it:
chmod 600 .env
docker compose up -d
docker compose logs -f
Nothing is published on the host, so there’s no port to visit yet. That’s the point: the only way in is through the proxy.
The proxy host
In Nginx Proxy Manager, Hosts → Proxy Hosts → Add Proxy Host:
| Tab | Setting | Value |
|---|---|---|
| Details | Domain Names | vault.home.yourdomain.com |
| Details | Scheme | http |
| Details | Forward Hostname / IP | vaultwarden |
| Details | Forward Port | 80 |
| Details | Websockets Support | on — live sync between devices uses it |
| Details | Block Common Exploits | on |
| SSL | SSL Certificate | your DNS-challenge certificate from Chapter 8 |
| SSL | Force SSL, HTTP/2 Support | on |
vaultwarden works as a hostname because both containers are on the proxy network — Docker resolves container names there.
Check it from any machine at home:
curl https://vault.home.yourdomain.com/alive
A timestamp back means the whole chain works: Pi-hole’s record, the proxy, the certificate and the container.
Create your account, then close the door
Open https://vault.home.yourdomain.com, create your account, then switch sign-ups off:
Change this one line, then docker compose up -d.
# In .env, then docker compose up -d again:
SIGNUPS_ALLOWED=false docker compose up -d
docker exec vaultwarden printenv SIGNUPS_ALLOWED # should print false
Hash the admin token
The book stores ADMIN_TOKEN as a long random string. Vaultwarden accepts that, but logs a notice on every start that a plain-text token is insecure — anyone who reads .env or the container’s environment has the admin password. Vaultwarden can store a hash of it instead:
docker exec -it vaultwarden /vaultwarden hash --preset owasp
It asks for a password twice — type the token you want to log in with — and prints a line starting ADMIN_TOKEN='$argon2id$. Replace the ADMIN_TOKEN= line in .env with that whole line, single quotes included, then docker compose up -d.
The quotes matter. The hash is full of $ signs, and without single quotes Compose treats each $… as a variable to fill in, silently mangling the hash so the admin page never accepts your password.
Two-factor on your own account
In the web vault: Settings → Security → Two-step login. An authenticator app (TOTP) is the simplest. Once it’s on, the same page has View recovery code — write the code on paper and keep it somewhere that isn’t your vault. If you lose your phone, that code is the only way back into your account. (Two-Factor Codes You Won’t Lose goes further.)
Connecting the apps
In the Bitwarden browser extension, desktop app or phone app, change the server before logging in. On the login screen, the region selector (it usually says bitwarden.com) has a self-hosted option; enter https://vault.home.yourdomain.com.
The backup that doesn’t need your server
Chapter 18 backs up Vaultwarden’s database safely with SQLite’s own .backup command, and the rest of /opt/stacks/vaultwarden/data — attachments, keys — goes with /opt/stacks. That protects the server.
It’s also worth having a copy you can read without the server. In the web vault, Tools → Export, choose the file format .json (Encrypted), then the export type Password protected, and set a file password. Keep the file somewhere offline, and the password in your head or on paper.
The export type matters. Account restricted — the other choice — can only be imported back into the same account it came from, which is exactly what you won’t have if the server is gone. A password-protected export can be imported into any Bitwarden account, so if the server and its backups were both lost, your passwords wouldn’t be.
Optional: telling Vaultwarden its own address
Vaultwarden works without knowing its public address, but a few features need it — security keys and passkeys as a second factor, for one. If you want those, add to .env:
DOMAIN=https://vault.home.yourdomain.com
and one line under environment: in the compose file, next to the others:
- DOMAIN=${DOMAIN}
Updating
Bump the tag in the compose file (vaultwarden/server:1.37.3 today), after reading the release notes and with last night’s backup behind you — Chapter 27’s routine. Your Bitwarden apps don’t need to change; they speak to whatever version the server runs.
Official documentation
- Vaultwarden wiki — including Enabling the admin page and Proxy examples
- Bitwarden help: self-hosted server URL
Stuck on a step? Get in touch.