docker compose images -q reports the image IDs of currently running
containers, which don't change after a pull — so before == after always
and containers were never recreated.
Fix: resolve each service's image tag to its local SHA256 ID via
docker image inspect, which reads the local image store and correctly
reflects the newly pulled image. Falls back from 'config --images'
(compose v2.19+) to parsing 'config' yaml for older versions.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Inline update logic (pull → compare digests → up -d → prune → notify)
- Inline backup logic with dynamic Postgres detection: any running
<stack>_db container is dumped using the <stack>/<stack> convention
- Systemd unit files are now generated on `install` from embedded
heredocs pointing at stacks.sh itself — no external scripts needed
- Root .env (WEBHOOK_URL, RESTIC_REPOSITORY, RESTIC_PASSWORD) replaces
the per-service .env files in _backup/ and _update/
- Remove _backup/ and _update/ directories entirely
- Update README accordingly
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace manual docker compose / systemctl snippets with stacks.sh
equivalents and add a dedicated section covering all commands.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Bakes the current stack list into the generated completion script instead
of using runtime directory discovery. Useful for remote hosts where the
stacks dir path differs from the local repo.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Bash script for managing Docker Compose stacks with glob filtering,
parallel execution, service management, scaffolding, and shell completion.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Use image ID diff instead of grepping "Pulled" (which appears even
when images are already up to date). Add timestamp, stack count, and
updated/total ratio to all notification messages.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add +x permission to update.sh (was causing systemd 203/EXEC failure)
- Remove $ anchor from grep so trailing space in docker output is matched
- Add .data/ to .gitignore
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Mount templates/custom/ directly to Gitea's default GITEA_CUSTOM templates
path. No entrypoint override or envsubst needed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Injects the Umami tracking script into every Gitea page using a custom
header.tmpl generated at startup via envsubst. Script URL and website ID
are externalized to UMAMI_SCRIPT_URL / UMAMI_WEBSITE_ID env vars.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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>
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>
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>
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>
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>
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>
- 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>
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>
Removes the watchtower container in favour of a host-side script that
runs daily at 2:00 AM via systemd timer. Mirrors the _backup pattern:
auto-discovers stacks, pulls images, recreates changed containers,
prunes dangling images, and notifies via n8n → Telegram.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
No longer needed after Coolify update — verified on VPS, container
stays healthy without them.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Mount from stack directory instead of .data, consistent with how
gitea handles runner-config.yaml.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>