๐งญ Overview
This is a walkthrough of my secure, private, self-hosted password manager setup using:
- Vaultwarden (Bitwarden-compatible Rust rewrite)
- Docker
- Traefik as a reverse proxy
- Cloudflare Tunnel for remote HTTPS access
- Tailscale for internal LAN access
๐ ๏ธ My Setup
| Component | Role |
|---|---|
| Vaultwarden | Password manager backend |
| Traefik | Reverse proxy & TLS termination |
| Cloudflare Tunnel | Exposes Vaultwarden securely without port-forwarding |
| Docker Compose | Orchestration layer |
| Tailscale | VPN mesh for local/private access |
๐งฑ Folder Structure
~/docker/vaultwarden/
โโโ docker-compose.yml
โโโ traefik_dynamic.yml
โโโ .env
โโโ data/
โ๏ธ docker-compose.yml
version: "3.8"
services:
vaultwarden:
image: vaultwarden/server:latest
container_name: vaultwarden
environment:
- WEBSOCKET_ENABLED=true
env_file:
- .env
volumes:
- ./data:/data
labels:
- "traefik.enable=true"
- "traefik.http.routers.vaultwarden.rule=Host(`vaultwarden.neilpatterson.dev`)"
- "traefik.http.routers.vaultwarden.entrypoints=websecure"
- "traefik.http.routers.vaultwarden.tls.certresolver=cloudflare"
- "traefik.http.services.vaultwarden.loadbalancer.server.port=80"
networks:
- web
networks:
web:
external: true
๐ .env File
# Vaultwarden admin panel (optional)
ADMIN_TOKEN=supersecureadminkey
# Encryption key (auto-generated on first run or provide your own)
DATABASE_URL=data/db.sqlite3
Restrict file permissions:
chmod 600 .env
๐ DNS & Cloudflare Setup
- Add a DNS record in Cloudflare:
- Type:
CNAME - Name:
vaultwarden - Target:
your-cloudflare-tunnel-id.cfargotunnel.com - Proxy: โ enabled
- Set up Cloudflare Tunnel:
cloudflared tunnel create vaultwarden-tunnel
cloudflared tunnel route dns vaultwarden-tunnel vaultwarden.neilpatterson.dev
- Define config in
/etc/cloudflared/config.yml:
tunnel: vaultwarden-tunnel
credentials-file: /etc/cloudflared/vaultwarden-tunnel.json
ingress:
- hostname: vaultwarden.neilpatterson.dev
service: http://localhost:80
- service: http_status:404
- Start the tunnel:
sudo systemctl start cloudflared
๐ Access Over Tailscale
- You can also access Vaultwarden via local Tailscale IP:
http://100.x.y.z:PORT
- Useful for maintenance or as a backup path if Cloudflare Tunnel goes down.
โ Security Notes
- Vaultwarden encrypts all data client-side.
- Traefik terminates TLS using Let's Encrypt (or Cloudflare DNS challenge).
- Cloudflare Tunnel eliminates port-forwarding and public IP exposure.
- Admin panel protected via
ADMIN_TOKENenv var.
๐งช Restore & Backup
Backups
I backup the /data folder with Restic:
restic backup ~/docker/vaultwarden/data
Restore
- Just copy
db.sqlite3and config JSON to a fresh container
๐ก Final Thoughts
This setup has been stable, private, and cost-effective. I get:
- Browser extensions & mobile app support
- No recurring fees
- Full control of my data
- Local + remote access