Compare commits

..

10 Commits

Author SHA1 Message Date
valknar 9c65cfc9e3 revert(passbolt): remove clock-skew patch — metadata key already created
The patched PublicKeyValidationService.php and its volume mount are
no longer needed now that the metadata key exists in the database.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 22:48:41 +02:00
valknar 15ce2e3f4b chore: remove accidentally committed log file
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 22:47:34 +02:00
valknar 300c685d50 feat: remove Vaultwarden — migrated to Passbolt
Credentials migrated to Passbolt CE at passbolt.pivoine.art.
Removed stack files and README entry. Data wiped on VPS.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 22:47:07 +02:00
valknar 5c398ee77c fix(passbolt): add 300s clock-skew tolerance to key creation date check
The isNotCreatedInTheFutureRule has zero tolerance, causing the
browser extension to fail when generating a metadata key if the
browser clock is even 1 second ahead of the server. Patching
isDateInFuture to allow 300 seconds tolerance and mounting the
file as a read-only volume so the fix survives image updates.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 22:16:56 +02:00
valknar 2e31c1dcc9 fix(passbolt): persist GPG keyring as volume to survive restarts
Passbolt's entrypoint creates /var/lib/passbolt/.gnupg/pubring.kbx
as root while PHP-FPM runs as www-data. Without a volume this file
is recreated with wrong ownership on every container recreate, breaking
all GPG operations. Mounting the dir as a volume keeps the chown
33:33 fix permanent.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 21:44:20 +02:00
valknar 6f12bf9af7 fix(passbolt): disable metadata encryption for new instance setup
Passbolt 5.x's isNotCreatedInTheFutureRule has zero tolerance for
clock skew — even 1 second between browser and server causes the
metadata key creation to fail during first setup. Disabling the
automatic metadata setup for new instances allows the browser
extension to complete account setup successfully.

Encrypted metadata can be enabled from the admin panel post-setup.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 21:24:51 +02:00
valknar 758e69300f fix(passbolt): add TZ env var (Europe/Amsterdam)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 21:06:01 +02:00
valknar ae81935376 fix(passbolt): clean setup with correct GPG fingerprint
Passbolt 5.x does not auto-persist the server key fingerprint across
container restarts (no passbolt.php is written). The fingerprint env var
is required and corresponds to the key auto-generated on first clean start.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 20:39:55 +02:00
valknar d8cfcd23d1 fix(passbolt): fix DB hostname, encoding, and GPG fingerprint
- Use container_name passbolt_db instead of service name db (service names
  are ambiguous on the shared falcon_network — 6 other stacks also have a
  service named db)
- Add DATASOURCES_DEFAULT_ENCODING=utf8 to override MySQL's utf8mb4 default
- Add DATASOURCES_QUOTE_IDENTIFIER=true for PostgreSQL identifier quoting
- Set PASSBOLT_GPG_SERVER_KEY_FINGERPRINT for the auto-generated server key
- Add PASSBOLT_GPG_SERVER_KEY_EMAIL for correct server key identity

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 20:14:57 +02:00
valknar a1f0f7091b feat(passbolt): add Passbolt CE stack
Password manager with GPG encryption. Uses PostgreSQL for consistency
with other stacks. Backed up alongside existing databases. Vaultwarden
kept running during migration.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 20:00:05 +02:00
6 changed files with 70 additions and 41 deletions
+1 -1
View File
@@ -16,7 +16,7 @@ Each stack is independently deployable with its own `compose.yml` and `.env`. Al
| `n8n` | Workflow automation & notification relay | n8n, db |
| `gitea` | Git hosting + CI runner | gitea, runner, db |
| `coolify` | Deployment platform | coolify, realtime, redis, db |
| `vaultwarden` | Password manager | vaultwarden |
| `passbolt` | Password manager (GPG-encrypted, team sharing) | passbolt, db |
## Tools
+1
View File
@@ -38,6 +38,7 @@ declare -A DATABASES=(
[n8n_db]="n8n:n8n"
[immich_db]="immich:immich"
[coolify_db]="coolify:coolify"
[passbolt_db]="passbolt:passbolt"
)
dump_errors=()
+2
View File
@@ -0,0 +1,2 @@
TRAEFIK_HOST=passbolt.example.com
NETWORK_NAME=falcon_network
+66
View File
@@ -0,0 +1,66 @@
services:
passbolt:
image: passbolt/passbolt:latest-ce
container_name: passbolt
environment:
APP_FULL_BASE_URL: https://${TRAEFIK_HOST}
PASSBOLT_SSL_FORCE: "false"
TZ: ${TIMEZONE:-Europe/Amsterdam}
PASSBOLT_REGISTRATION_PUBLIC: "false"
DATASOURCES_DEFAULT_HOST: passbolt_db
DATASOURCES_DEFAULT_PORT: "5432"
DATASOURCES_DEFAULT_DATABASE: passbolt
DATASOURCES_DEFAULT_USERNAME: passbolt
DATASOURCES_DEFAULT_PASSWORD: passbolt
DATASOURCES_DEFAULT_DRIVER: Cake\Database\Driver\Postgres
DATASOURCES_DEFAULT_ENCODING: utf8
DATASOURCES_QUOTE_IDENTIFIER: "true"
EMAIL_TRANSPORT_DEFAULT_HOST: mailpit
EMAIL_TRANSPORT_DEFAULT_PORT: "1025"
EMAIL_TRANSPORT_DEFAULT_TLS: "false"
EMAIL_DEFAULT_FROM: passbolt@pivoine.art
EMAIL_DEFAULT_FROM_NAME: Passbolt
volumes:
- ../.data/passbolt/gpg:/etc/passbolt/gpg
- ../.data/passbolt/jwt:/etc/passbolt/jwt
- ../.data/passbolt/gnupg:/var/lib/passbolt/.gnupg
depends_on:
db:
condition: service_healthy
restart: unless-stopped
labels:
- "traefik.enable=true"
- "traefik.http.middlewares.passbolt-redirect-web-secure.redirectscheme.scheme=https"
- "traefik.http.routers.passbolt-web.middlewares=passbolt-redirect-web-secure"
- "traefik.http.routers.passbolt-web.rule=Host(`${TRAEFIK_HOST}`)"
- "traefik.http.routers.passbolt-web.entrypoints=web"
- "traefik.http.routers.passbolt-web-secure.rule=Host(`${TRAEFIK_HOST}`)"
- "traefik.http.routers.passbolt-web-secure.tls.certresolver=resolver"
- "traefik.http.routers.passbolt-web-secure.entrypoints=web-secure"
- "traefik.http.routers.passbolt-web-secure.middlewares=security-headers@file,no-index@file"
- "traefik.http.services.passbolt-web-secure.loadbalancer.server.port=80"
- "traefik.docker.network=${NETWORK_NAME}"
networks:
- compose_network
db:
image: postgres:16-alpine
container_name: passbolt_db
environment:
POSTGRES_DB: passbolt
POSTGRES_USER: passbolt
POSTGRES_PASSWORD: passbolt
POSTGRES_INITDB_ARGS: --data-checksums
volumes:
- ../.data/passbolt/db:/var/lib/postgresql/data
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
interval: 5s
timeout: 5s
retries: 5
networks:
- compose_network
networks:
compose_network:
name: ${NETWORK_NAME}
external: true
-3
View File
@@ -1,3 +0,0 @@
TRAEFIK_HOST=vault.example.com
NETWORK_NAME=falcon_network
SMTP_FROM=vaultwarden@example.com
-37
View File
@@ -1,37 +0,0 @@
services:
vaultwarden:
image: vaultwarden/server:latest
container_name: vaultwarden
environment:
TZ: ${TIMEZONE:-Europe/Amsterdam}
DOMAIN: https://${TRAEFIK_HOST}
WEBSOCKET_ENABLED: "true"
SIGNUPS_ALLOWED: "true"
INVITATIONS_ALLOWED: "true"
SHOW_PASSWORD_HINT: "false"
SMTP_HOST: mailpit
SMTP_FROM: ${SMTP_FROM}
SMTP_FROM_NAME: Vaultwarden
SMTP_SECURITY: off
SMTP_PORT: 1025
volumes:
- ../.data/vaultwarden:/data
restart: always
labels:
- "traefik.enable=true"
- "traefik.http.middlewares.vaultwarden-redirect-web-secure.redirectscheme.scheme=https"
- "traefik.http.routers.vaultwarden-web.middlewares=vaultwarden-redirect-web-secure"
- "traefik.http.routers.vaultwarden-web.rule=Host(`${TRAEFIK_HOST}`)"
- "traefik.http.routers.vaultwarden-web.entrypoints=web"
- "traefik.http.routers.vaultwarden-web-secure.rule=Host(`${TRAEFIK_HOST}`)"
- "traefik.http.routers.vaultwarden-web-secure.tls.certresolver=resolver"
- "traefik.http.routers.vaultwarden-web-secure.entrypoints=web-secure"
- "traefik.http.routers.vaultwarden-web-secure.middlewares=security-headers@file,no-index@file"
- "traefik.http.services.vaultwarden-web-secure.loadbalancer.server.port=80"
- "traefik.docker.network=${NETWORK_NAME}"
networks:
- compose_network
networks:
compose_network:
name: ${NETWORK_NAME}
external: true