[TERMINAL · SKILLS]
> mounting /skills...
> indexing skill manifests...
> linking agents: claude · codex · gemini · cursor
> ready.
[░░░░░░░░░░░░░░░░░░░░░░░░░░░░] 0%
Use Cases/Self-Host a Team Password Manager with Vaultwarden

Self-Host a Team Password Manager with Vaultwarden

Run a Bitwarden-compatible password manager on your own server with HTTPS, a hashed admin token, closed signups and tested encrypted backups, for a small team that wants to own its credentials.

DevOps#vaultwarden#bitwarden#password-manager#self-hosted#docker
Works with:claude-codeopenai-codexgemini-clicursor
agent@terminalskills — playground
full playground →

Try this use case on your own files

simulated preview
$
$

real run in an isolated sandbox · files auto-deleted after 7 days · nothing touches your machine

Skills stack · 3 skills

Avg quality 93/100·All SAFE
>

vaultwarden

v1.0.0

Deploys and hardens Vaultwarden, a lightweight self-hosted server that is compatible with the official Bitwarden apps and browser extensions, so a person, family or small team can run their own password manager. Use when a user asks to "self-host Bitwarden", "set up Vaultwarden with Docker", "hash the ADMIN_TOKEN", "disable signups", "put Vaultwarden behind Caddy or nginx", or "back up the vault". Covers the container, environment variables, HTTPS reverse proxy, SMTP, backups and updates.

93/100 quality
2.50× impact
SAFE
View skill
>

caddy

v1.1.0

Caddy is a web server and reverse proxy that obtains and renews HTTPS certificates automatically. Covers reverse proxying, load balancing, file serving, redirects, headers, rate limiting, and configuration through the admin API. Use when tasks involve serving websites, proxying to backend services, automatic TLS certificate management, or replacing Nginx with a simpler configuration.

100/100 quality
10.00× impact
SAFE· stale score
View skill
>

restic

v1.1.0

Back up and restore data with Restic. Use when a user asks to set up backups, create encrypted backups, back up to S3 or cloud storage, implement a backup strategy, restore files from backup, deduplicate backup storage, schedule automated backups, back up databases or servers, or set up offsite backups. Covers repository initialization, backup/restore operations, snapshot management, pruning, encryption, and multiple storage backends (local, S3, SFTP, B2, Azure, GCS).

87/100 quality
6.70× impact
SAFE· stale score
View skill
$

The Problem

Marek Novak runs a six-person web agency. Client logins, hosting panels and API keys live in a shared spreadsheet, two browsers' built-in password stores and a few Slack messages. When a developer left last month, nobody could say which credentials he had seen. The agency does not want to pay per seat for a hosted vault, and the clients' contracts say credentials must stay on infrastructure the agency controls. Marek has a small VPS and a domain, and wants a real password manager the whole team can use from their browsers and phones within an afternoon.

The Solution

Use vaultwarden, a lightweight server that speaks the Bitwarden protocol, so everyone can use the official Bitwarden apps and extensions against the agency's own server. caddy terminates HTTPS with automatic certificates, and restic ships encrypted, versioned backups off the box. The agent does the deployment and hardening; each person creates their own account and master password, which the agent never sees.

Step-by-Step Walkthrough

Step 1: Hash the admin token and write the Compose file

Prompt to the agent: "Deploy Vaultwarden on this server for vault.northwind-dev.net. Bind it to localhost, protect the admin page with a hashed token, and keep signups open only until we have registered."

The agent asks Marek to type an admin password into a hashing prompt, so the password never appears in the chat:

bash
mkdir -p /srv/vaultwarden && cd /srv/vaultwarden
docker run --rm -it vaultwarden/server:1.37.4 /vaultwarden hash

It copies the printed $argon2id$... string into compose.yaml, doubling every $ as $$ so Compose does not treat it as a variable:

yaml
services:
  vaultwarden:
    image: vaultwarden/server:1.37.4
    container_name: vaultwarden
    restart: unless-stopped
    environment:
      DOMAIN: "https://vault.northwind-dev.net"
      SIGNUPS_ALLOWED: "true"
      ADMIN_TOKEN: "$$argon2id$$v=19$$m=65540,t=3,p=4$$vlAH8es2mqEXQtF78PoOqBRUjWgXYEJcieXQeAOd0Fo$$KGdicJaJXypr1123nLpA+SiJawzD2niNKIAvZ6gNVqY"
    volumes:
      - ./vw-data/:/data/
    ports:
      - 127.0.0.1:8000:80

(The hash shown is a throwaway example; the agent uses the one generated for Marek.)

bash
docker compose up -d
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8000/alive

The check prints 200.

Step 2: Put Caddy in front with HTTPS

Prompt: "Expose it at vault.northwind-dev.net with a real certificate."

caddyfile
vault.northwind-dev.net {
  encode zstd gzip
  reverse_proxy 127.0.0.1:8000 {
    header_up X-Real-IP {remote_host}
  }
}
bash
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy
curl -s -o /dev/null -w "%{http_code}\n" https://vault.northwind-dev.net/alive

The last command prints 200 over HTTPS. The web vault needs this secure context to run its cryptography, so plain HTTP would not work even on a private network.

Step 3: Register the team, then close signups

Prompt: "Tell me when I can register, then close registration."

Marek and five colleagues open https://vault.northwind-dev.net, create their accounts and set their own master passwords, then install the Bitwarden browser extension and point it at the agency's server URL under the self-hosted option. Once all six exist the agent changes SIGNUPS_ALLOWED to "false", runs docker compose up -d, and confirms that the "Create account" link has disappeared. Future hires are invited from the admin page at /admin, which the agent restricts to the office VPN address range in the Caddyfile.

Step 4: Set up email

Prompt: "Hook up our SMTP relay so invitations work."

The agent adds SMTP_HOST, SMTP_FROM, SMTP_PORT, SMTP_SECURITY=starttls, SMTP_USERNAME and SMTP_PASSWORD to the service, reading the password from an environment file kept out of Git, and sends a test invitation from the admin page.

Step 5: Back up nightly and test the restore

Prompt: "Back it up every night to the storage box and prove the restore works."

bash
docker exec vaultwarden /vaultwarden backup
export RESTIC_PASSWORD_FILE=/root/.restic-vw-password
restic -r sftp:backup@storage.northwind-dev.net:/vw-backups init
restic -r sftp:backup@storage.northwind-dev.net:/vw-backups backup /srv/vaultwarden/vw-data --exclude /srv/vaultwarden/vw-data/icon_cache
restic -r sftp:backup@storage.northwind-dev.net:/vw-backups forget --keep-daily 14 --keep-weekly 8 --prune

These go into a systemd timer. To prove the restore, the agent restores the latest snapshot into /tmp/vw-restore-check, confirms that db.sqlite3, rsa_key.pem and attachments/ are present and that the database opens, then deletes the check directory.

Real-World Example

By evening the agency has a working vault. Marek imports the passwords from the shared spreadsheet through the web vault's import tool and deletes the spreadsheet. The six users have the browser extension and the phone app. /admin is reachable only from the VPN, the admin token is stored hashed, signups are closed, and the first nightly snapshot of 41 MB is on the storage box with a restore verified. The next time a developer leaves, Marek removes the account in the admin panel and rotates only the shared credentials that person could open, which the collections list shows him in a minute.

Related Skills

  • vaultwarden — the password server: container, admin token, signup policy, backups
  • caddy — HTTPS reverse proxy with automatic certificates
  • restic — encrypted, versioned off-site backups of the data directory

Related use cases