feat: add Vaultwarden password manager stack
Added self-hosted password manager to The Falcon infrastructure: **Vault Stack** (vault.pivoine.art): - Vaultwarden (Bitwarden-compatible server) - SQLite database for password storage - WebSocket support for real-time sync - TOTP and WebAuthn/U2F 2FA support - Browser extensions and mobile apps compatible **Configuration:** - Domain: https://vault.pivoine.art - Signups: Disabled (invite-only for security) - Invitations: Enabled - Password hints: Disabled (security best practice) - First user becomes admin **Backup Integration:** - Added vaultwarden-backup plan to Restic - Schedule: 8 AM daily (same as letsencrypt) - Retention: 7 daily, 4 weekly, 12 monthly, 3 yearly - Backup volume: vault_data mounted read-only **Infrastructure Updates:** - Created vault/compose.yaml following stack pattern - Added VAULT_* environment variables to arty.yml - Updated compose.yaml to include vault stack - Added backup_vaultwarden_data volume to restic - Updated restic/config.json with 12th backup plan **Documentation:** - Added Vault to CORE SYSTEMS in README - Added to ship architecture diagram - Documented in CLAUDE.md with configuration details - Updated volume management sections - Backup count increased from 11 to 12 plans Critical data backed up with long retention (3 years yearly). Compatible with official Bitwarden clients on all platforms. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
29
CLAUDE.md
29
CLAUDE.md
@@ -20,6 +20,7 @@ Root `compose.yaml` uses Docker Compose's `include` directive to orchestrate mul
|
||||
- **n8n**: Workflow automation platform (PostgreSQL)
|
||||
- **stash**: Filestash web-based file manager
|
||||
- **links**: Linkwarden bookmark manager (PostgreSQL + Meilisearch)
|
||||
- **vault**: Vaultwarden password manager (SQLite)
|
||||
- **restic**: Backrest backup system with restic backend
|
||||
- **sablier**: Dynamic scaling plugin for Traefik
|
||||
- **vpn**: WireGuard VPN (wg-easy)
|
||||
@@ -197,6 +198,29 @@ Linkwarden bookmark manager with full-text search:
|
||||
- `LINKS_NEXTAUTH_SECRET`: NextAuth.js secret for session encryption
|
||||
- `LINKS_MEILI_MASTER_KEY`: Meilisearch master key for API authentication
|
||||
|
||||
### Vault (vault/compose.yaml)
|
||||
Vaultwarden password manager (Bitwarden-compatible server):
|
||||
- **vaultwarden**: Vaultwarden app exposed at `vault.pivoine.art:80`
|
||||
- Self-hosted password manager compatible with Bitwarden clients
|
||||
- Supports TOTP, WebAuthn/U2F two-factor authentication
|
||||
- Secure password generation and sharing
|
||||
- Browser extensions and mobile apps available
|
||||
- Emergency access and organization support
|
||||
- Data persisted in `vaultwarden_data` volume (SQLite database)
|
||||
|
||||
**Configuration**:
|
||||
- **DOMAIN**: `https://vault.pivoine.art` (required for proper HTTPS operation)
|
||||
- **WEBSOCKET_ENABLED**: `true` (enables real-time sync)
|
||||
- **SIGNUPS_ALLOWED**: `false` (disable open registrations for security)
|
||||
- **INVITATIONS_ALLOWED**: `true` (allow inviting users)
|
||||
- **SHOW_PASSWORD_HINT**: `false` (security best practice)
|
||||
|
||||
**Important**:
|
||||
- First user to register becomes the admin
|
||||
- Use strong master password - it cannot be recovered
|
||||
- Enable 2FA for all accounts
|
||||
- Access admin panel at `/admin` (requires `ADMIN_TOKEN` in `.env`)
|
||||
|
||||
### Restic (restic/compose.yaml)
|
||||
Backrest backup system with restic backend:
|
||||
- **backrest**: Backrest web UI exposed at `restic.pivoine.art:9898`
|
||||
@@ -262,6 +286,10 @@ Backrest backup system with restic backend:
|
||||
- Path: `/volumes/letsencrypt_data`
|
||||
- Retention: 7 daily, 4 weekly, 12 monthly, 3 yearly
|
||||
|
||||
12. **vaultwarden-backup** (8 AM daily)
|
||||
- Path: `/volumes/vaultwarden_data`
|
||||
- Retention: 7 daily, 4 weekly, 12 monthly, 3 yearly
|
||||
|
||||
**Volume Mounting**:
|
||||
All Docker volumes are mounted read-only to `/volumes/` with prefixed names (e.g., `backup_core_postgres_data`) to avoid naming conflicts with other compose stacks.
|
||||
|
||||
@@ -296,6 +324,7 @@ Each service uses named volumes prefixed with project name:
|
||||
- `n8n_n8n_data`: n8n workflow data
|
||||
- `stash_filestash_data`: Filestash configuration and state
|
||||
- `links_data`, `links_meili_data`: Linkwarden bookmarks and Meilisearch index
|
||||
- `vault_data`: Vaultwarden password vault (SQLite database)
|
||||
- `restic_data`, `restic_config`, `restic_cache`, `restic_tmp`: Backrest backup system
|
||||
- `proxy_letsencrypt_data`: SSL certificates
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@ The **Falcon** is a state-of-the-art containerized starship, powered by Docker's
|
||||
| **N8N** | *Automated workflow command center* | [n8n.pivoine.art](https://n8n.pivoine.art) |
|
||||
| **STASH** | *Universal file management portal* | [stash.pivoine.art](https://stash.pivoine.art) |
|
||||
| **LINKS** | *Interstellar bookmark archive* | [links.pivoine.art](https://links.pivoine.art) |
|
||||
| **VAULT** | *Encrypted password vault* | [vault.pivoine.art](https://vault.pivoine.art) |
|
||||
| **RESTIC** | *Automated backup vault system* | [restic.pivoine.art](https://restic.pivoine.art) |
|
||||
| **PROXY** | *Shield control dashboard* | [proxy.pivoine.art](https://proxy.pivoine.art) |
|
||||
| **VPN** | *Cloaking device network* | [vpn.pivoine.art](https://vpn.pivoine.art) |
|
||||
@@ -204,6 +205,7 @@ THE FALCON (falcon_network)
|
||||
│ ├─ n8n Workflows [n8n.pivoine.art]
|
||||
│ ├─ Filestash Files [stash.pivoine.art]
|
||||
│ ├─ Linkwarden Marks [links.pivoine.art]
|
||||
│ ├─ Vaultwarden Vault [vault.pivoine.art]
|
||||
│ ├─ Backrest Backups [restic.pivoine.art]
|
||||
│ └─ WireGuard VPN [vpn.pivoine.art]
|
||||
│
|
||||
@@ -218,6 +220,7 @@ THE FALCON (falcon_network)
|
||||
├─ filestash_data → File manager state
|
||||
├─ linkwarden_data → Bookmark archives
|
||||
├─ meili_data → Search index database
|
||||
├─ vaultwarden_data → Encrypted password vault
|
||||
├─ backrest_data → Backup system state
|
||||
├─ backrest_config → Backup configurations
|
||||
└─ letsencrypt_data → Shield certificates
|
||||
|
||||
9
arty.yml
9
arty.yml
@@ -94,6 +94,15 @@ envs:
|
||||
RESTIC_TRAEFIK_HOST: restic.pivoine.art
|
||||
RESTIC_HOSTNAME: falcon
|
||||
RESTIC_BACKUP_PATH: /mnt/hidrive/users/valknar/Backup
|
||||
# Vault
|
||||
VAULT_TRAEFIK_ENABLED: true
|
||||
VAULT_COMPOSE_PROJECT_NAME: vault
|
||||
VAULT_IMAGE: vaultwarden/server:latest
|
||||
VAULT_TRAEFIK_HOST: vault.pivoine.art
|
||||
VAULT_WEBSOCKET_ENABLED: true
|
||||
VAULT_SIGNUPS_ALLOWED: false
|
||||
VAULT_INVITATIONS_ALLOWED: true
|
||||
VAULT_SHOW_PASSWORD_HINT: false
|
||||
# Proxy
|
||||
PROXY_COMPOSE_PROJECT_NAME: proxy
|
||||
PROXY_DOCKER_IMAGE: traefik:latest
|
||||
|
||||
@@ -8,6 +8,7 @@ include:
|
||||
- n8n/compose.yaml
|
||||
- stash/compose.yaml
|
||||
- links/compose.yaml
|
||||
- vault/compose.yaml
|
||||
- restic/compose.yaml
|
||||
- umami/compose.yaml
|
||||
- sablier/compose.yaml
|
||||
|
||||
@@ -28,6 +28,7 @@ services:
|
||||
- backup_linkwarden_data:/volumes/linkwarden_data:ro
|
||||
- backup_linkwarden_meili_data:/volumes/linkwarden_meili_data:ro
|
||||
- backup_letsencrypt_data:/volumes/letsencrypt_data:ro
|
||||
- backup_vaultwarden_data:/volumes/vaultwarden_data:ro
|
||||
|
||||
environment:
|
||||
TZ: ${TIMEZONE:-Europe/Berlin}
|
||||
@@ -104,6 +105,9 @@ volumes:
|
||||
backup_letsencrypt_data:
|
||||
name: proxy_letsencrypt_data
|
||||
external: true
|
||||
backup_vaultwarden_data:
|
||||
name: vault_data
|
||||
external: true
|
||||
|
||||
networks:
|
||||
compose_network:
|
||||
|
||||
@@ -194,6 +194,22 @@
|
||||
"yearly": 3
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "vaultwarden-backup",
|
||||
"repo": "hidrive-backup",
|
||||
"paths": ["/volumes/vaultwarden_data"],
|
||||
"schedule": {
|
||||
"cron": "0 8 * * *"
|
||||
},
|
||||
"retention": {
|
||||
"policyTimeBucketed": {
|
||||
"daily": 7,
|
||||
"weekly": 4,
|
||||
"monthly": 12,
|
||||
"yearly": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
39
vault/compose.yaml
Normal file
39
vault/compose.yaml
Normal file
@@ -0,0 +1,39 @@
|
||||
services:
|
||||
vaultwarden:
|
||||
image: ${VAULT_IMAGE:-vaultwarden/server:latest}
|
||||
container_name: ${VAULT_COMPOSE_PROJECT_NAME}_app
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- vaultwarden_data:/data
|
||||
environment:
|
||||
TZ: ${TIMEZONE:-Europe/Berlin}
|
||||
DOMAIN: https://${VAULT_TRAEFIK_HOST}
|
||||
WEBSOCKET_ENABLED: ${VAULT_WEBSOCKET_ENABLED:-true}
|
||||
SIGNUPS_ALLOWED: ${VAULT_SIGNUPS_ALLOWED:-false}
|
||||
INVITATIONS_ALLOWED: ${VAULT_INVITATIONS_ALLOWED:-true}
|
||||
SHOW_PASSWORD_HINT: ${VAULT_SHOW_PASSWORD_HINT:-false}
|
||||
networks:
|
||||
- compose_network
|
||||
labels:
|
||||
- 'traefik.enable=${VAULT_TRAEFIK_ENABLED}'
|
||||
- 'traefik.http.middlewares.${VAULT_COMPOSE_PROJECT_NAME}-redirect-web-secure.redirectscheme.scheme=https'
|
||||
- 'traefik.http.routers.${VAULT_COMPOSE_PROJECT_NAME}-web.middlewares=${VAULT_COMPOSE_PROJECT_NAME}-redirect-web-secure'
|
||||
- 'traefik.http.routers.${VAULT_COMPOSE_PROJECT_NAME}-web.rule=Host(`${VAULT_TRAEFIK_HOST}`)'
|
||||
- 'traefik.http.routers.${VAULT_COMPOSE_PROJECT_NAME}-web.entrypoints=web'
|
||||
- 'traefik.http.routers.${VAULT_COMPOSE_PROJECT_NAME}-web-secure.rule=Host(`${VAULT_TRAEFIK_HOST}`)'
|
||||
- 'traefik.http.routers.${VAULT_COMPOSE_PROJECT_NAME}-web-secure.tls.certresolver=resolver'
|
||||
- 'traefik.http.routers.${VAULT_COMPOSE_PROJECT_NAME}-web-secure.entrypoints=web-secure'
|
||||
- 'traefik.http.middlewares.${VAULT_COMPOSE_PROJECT_NAME}-web-secure-compress.compress=true'
|
||||
- 'traefik.http.routers.${VAULT_COMPOSE_PROJECT_NAME}-web-secure.middlewares=${VAULT_COMPOSE_PROJECT_NAME}-web-secure-compress'
|
||||
- 'traefik.http.services.${VAULT_COMPOSE_PROJECT_NAME}-web-secure.loadbalancer.server.port=80'
|
||||
- 'traefik.docker.network=${NETWORK_NAME}'
|
||||
- 'com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}'
|
||||
|
||||
volumes:
|
||||
vaultwarden_data:
|
||||
name: ${VAULT_COMPOSE_PROJECT_NAME}_data
|
||||
|
||||
networks:
|
||||
compose_network:
|
||||
name: ${NETWORK_NAME}
|
||||
external: true
|
||||
Reference in New Issue
Block a user