Monitoring stack (Prometheus, AlertManager, Grafana, Loki, Uptime Kuma)
moved from main to tools server. Prometheus now scrapes main exporters
over network (ip_main:9100/8080). Promtail pushes logs to ip_tools:3100.
Traefik routes for dash/status.walava.io updated to ip_tools. discord-bot
PROMETHEUS_URL updated to http://ip_tools:9090.
Outline S3 fix: remove AWS_S3_ACL=private (Timeweb doesn't support
per-object ACLs — caused upload failures). Add CORS configuration task
for browser-side presigned uploads.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Ensures removed services (vaultwarden, mailserver, snappymail)
are automatically stopped on next deploy.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
SnappyMail defaulted to localhost:143 for IMAP. Create csrx.ru.json
domain config pointing to the mailserver container (shared front network):
- IMAP: mailserver:993 SSL
- SMTP: mailserver:587 STARTTLS with auth
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
djmaze/snappymail does not reliably apply SNAPPYMAIL_ADMIN_PASSWORD.
Instead: read current hash from application.ini, verify it against vault
password using password_verify() in container PHP, update only if wrong.
Idempotent — no restart if password is already correct.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace broken PHP require path with docker restart to let entrypoint
apply SNAPPYMAIL_ADMIN_PASSWORD env var (path /var/www/snappymail/index.php
does not exist in djmaze/snappymail image)
- Move snappymail from webmail-internal to mail-internal so it can reach
mailserver for IMAP/SMTP connections
- Remove unused webmail-internal network
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The SNAPPYMAIL_ADMIN_PASSWORD env var may not apply if the container
started when data dir had wrong permissions. Now sets password directly
via RainLoop PHP API after every deploy — idempotent and reliable.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
SnappyMail container runs as www-data (uid 82 in Alpine).
Directory was created as deploy:deploy (uid 1000) → [202] is_readable() error.
Fix: chown 82:82 on the data directory.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace fragile file-content lookup with proper failed_when that accepts
'already exists' exit code 1 as a non-failure. Simpler and works on every run.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
lookup(..., errors='ignore') returns None (not empty string) for missing files.
Use | default('', true) to also convert falsy None to empty string.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add docker-mailserver (Postfix+Dovecot) with SSL via certbot+Cloudflare DNS-01
- Add SnappyMail webmail client at webmail.csrx.ru (port 8888)
- Open UFW ports 25/465/587/993 on tools server
- Create mail accounts: noreply@, admin@, jack@csrx.ru
- Generate DKIM key and print DNS instructions on first run
- Add Traefik route on main server proxying webmail → tools:8888
- Add all secrets to vault (mailserver passwords, snappymail admin)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
docker-mailserver uses opendkim by default; generated keys go to
config/opendkim/keys/<domain>/mail.{private,txt}, not rspamd/dkim/.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
setup email list fails with rc=1 when postfix-accounts.cf doesn't
exist yet (fresh install). Check the mounted config file on the host
instead, which correctly handles the empty/missing case.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds docker-mailserver (SMTP_ONLY mode) to the tools stack so Outline
can send magic-link emails without depending on an external SMTP provider.
Changes:
- docker-compose.yml.j2: add mailserver service + mail-internal network
outline gets mail-internal network to reach mailserver
- env.j2: point Outline SMTP at local mailserver:587 with noreply account
- defaults/main.yml: add mailserver_image (v14)
- tasks/main.yml: create mailserver dirs, wait for postfix ready,
idempotent account creation, DKIM key generation + DNS instructions
- inventory/group_vars/all/main.yml: add mailserver_noreply_password alias
- vault.yml: add vault_mailserver_noreply_password
After deploy, Ansible will print DKIM/SPF/DMARC DNS records to add
to Cloudflare.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>