Commit graph

26 commits

Author SHA1 Message Date
fde51352d7 feat: migrate monitoring to tools server, fix Outline S3 uploads
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>
2026-03-27 04:10:28 +07:00
36be9fb33d chore: remove SMTP relay, clean up tools role after Outline/n8n migration to main
- Remove smtp-relay (postfix) container — Outline now on main, uses Resend directly
- Remove UFW port 1025 rule (SMTP relay no longer needed)
- Remove postfix-relay from image pull list
- Clean up tools role: remove Outline/n8n/env.j2, simplify tasks/main.yml
- tools docker-compose now empty (pending monitoring migration)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 03:10:56 +07:00
fba7eb68ea fix: add SMTP relay on main server for Outline email auth
Some checks failed
CI/CD / deploy (push) Blocked by required conditions
CI/CD / syntax-check (push) Has been cancelled
tools-server (85.193.83.9) has outbound SMTP ports 465/587 blocked by VPS
provider. Added tecnativa/postfix-relay container on main server that relays
to smtp.resend.com:587. Outline now uses ip_main:1025 as SMTP host.

- UFW rule: allow port 1025 from ip_tools only
- Remove stale authelia_image from docker pull list

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 23:35:30 +07:00
e754d54e81 chore: add outline-mcp to tools stack, clean up stale authelia vars
Some checks are pending
CI/CD / syntax-check (push) Waiting to run
CI/CD / deploy (push) Blocked by required conditions
- Add outline-mcp service to tools docker-compose (was running unmanaged)
- Update OUTLINE_URL from csrx.ru → walava.io via domain_wiki variable
- Bind port 8765 to 127.0.0.1 only (was 0.0.0.0 — security improvement)
- Add vault_outline_mcp_api_key to vault + alias in main.yml
- Remove stale authelia_* aliases from main.yml (authelia removed)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 22:54:14 +07:00
8b140473b4 feat: add Resend SMTP for Outline email auth
Some checks failed
CI/CD / syntax-check (push) Successful in 1m8s
CI/CD / deploy (push) Has been cancelled
Configures smtp.resend.com as SMTP provider for Outline magic links.
Domain csrx.ru needs verification in Resend dashboard.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 17:38:35 +07:00
c1a71b7f50 fix: add remove_orphans to docker compose tasks
All checks were successful
CI/CD / syntax-check (push) Successful in 1m33s
CI/CD / deploy (push) Successful in 14m0s
Ensures removed services (vaultwarden, mailserver, snappymail)
are automatically stopped on next deploy.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 07:00:17 +07:00
75bed6bb04 feat: remove mail stack and Vaultwarden
Some checks failed
CI/CD / syntax-check (push) Successful in 1m15s
CI/CD / deploy (push) Has been cancelled
Removed services:
- docker-mailserver (Postfix + Dovecot)
- SnappyMail webmail
- Vaultwarden password manager

Removed infrastructure:
- certbot + Cloudflare DNS-01 TLS for mx.csrx.ru
- UFW rules for ports 25/587/993/465
- mail-internal and webmail-internal Docker networks
- SMTP config from Outline env
- vault, mail Traefik routes
- All related vault secrets and variables

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 04:06:29 +07:00
e342d39c41 fix(snappymail): configure csrx.ru domain with correct IMAP/SMTP server
All checks were successful
CI/CD / syntax-check (push) Successful in 1m15s
CI/CD / deploy (push) Successful in 15m26s
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>
2026-03-23 04:02:13 +07:00
e09e2fe04a fix(snappymail): set admin password via Python+PHP directly in application.ini
All checks were successful
CI/CD / syntax-check (push) Successful in 1m32s
CI/CD / deploy (push) Successful in 15m57s
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>
2026-03-22 21:51:58 +07:00
1b3f3e62b9 fix(snappymail): correct admin password setup and network config
Some checks failed
CI/CD / syntax-check (push) Successful in 1m35s
CI/CD / deploy (push) Has been cancelled
- 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>
2026-03-22 21:45:17 +07:00
1c16183bf5 fix(snappymail): set admin password explicitly via PHP after container start
Some checks failed
CI/CD / syntax-check (push) Successful in 1m43s
CI/CD / deploy (push) Failing after 16m2s
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>
2026-03-22 20:49:35 +07:00
1e638055c8 feat(mail): rename mail→mx, webmail→mail.csrx.ru + reliability
Some checks failed
CI/CD / syntax-check (push) Successful in 1m23s
CI/CD / deploy (push) Has been cancelled
Rename:
- docker-mailserver: hostname mail → mx, OVERRIDE_HOSTNAME → mx.csrx.ru
- Traefik route: webmail/domain_webmail → mail/domain_mail
- domain_webmail removed, domain_mail + domain_mx added to main.yml
- certbot cert: mail.csrx.ru → mx.csrx.ru

Email reliability improvements:
- certbot renewal cron (03:15 + 15:15 daily)
- deploy-hook: auto-reload Postfix+Dovecot after cert renewal
- POSTFIX_MESSAGE_SIZE_LIMIT=26214400 (25 MB)
- SPF hardened: ~all → -all
- DMARC hardened: p=none → p=quarantine, added ruf + fo=1 + adkim/aspf strict
- autodiscover/autoconfig CNAME records for mail client setup
- dns-zone.zone fully updated with architecture comments

Docs:
- STATUS.md: full mail architecture section, client settings, DNS table
- BACKLOG.md: rDNS task + DNS migration steps
- DECISIONS.md: mx/mail split rationale

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 20:07:59 +07:00
cd562da4d2 fix(snappymail): set data dir owner to uid 82 (www-data/Alpine)
Some checks failed
CI/CD / syntax-check (push) Successful in 1m22s
CI/CD / deploy (push) Has been cancelled
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>
2026-03-22 19:49:33 +07:00
aa6b20c463 fix: make mail account creation idempotent by ignoring 'already exists' error
All checks were successful
CI/CD / syntax-check (push) Successful in 1m39s
CI/CD / deploy (push) Successful in 15m40s
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>
2026-03-22 18:13:13 +07:00
836d554e7b fix: handle None from lookup('file') when postfix-accounts.cf doesn't exist
Some checks failed
CI/CD / syntax-check (push) Successful in 1m12s
CI/CD / deploy (push) Failing after 16m1s
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>
2026-03-22 17:46:30 +07:00
644b5b74c1 feat: add SnappyMail webmail and docker-mailserver with full send/receive
Some checks failed
CI/CD / syntax-check (push) Successful in 1m35s
CI/CD / deploy (push) Failing after 17m28s
- 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>
2026-03-22 17:21:25 +07:00
26c0df851e feat: full mail server — send + receive for @csrx.ru
Some checks failed
CI/CD / syntax-check (push) Successful in 1m25s
CI/CD / deploy (push) Has been cancelled
Upgrade docker-mailserver from SMTP_ONLY to full Postfix + Dovecot:
- Remove SMTP_ONLY, enable Dovecot (IMAP) and Rspamd (spam filter)
- Expose ports 25 (SMTP), 587 (submission), 993 (IMAPS), 465 (SMTPS)
- SSL_TYPE=letsencrypt — certbot obtains cert for mail.csrx.ru via
  Cloudflare DNS-01 challenge (uses existing cloudflare_dns_api_token)
- UFW: open ports 25, 587, 993, 465
- Accounts: admin@csrx.ru, jack@csrx.ru, noreply@csrx.ru

Mail client settings after deploy:
  IMAP: mail.csrx.ru:993 (SSL)
  SMTP: mail.csrx.ru:587 (STARTTLS)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 17:16:09 +07:00
cb798b67e9 fix: add mailserver to front network for outbound internet access
Some checks failed
CI/CD / syntax-check (push) Successful in 1m11s
CI/CD / deploy (push) Has been cancelled
mail-internal is internal:true (no internet). mailserver needs the
front network to resolve DNS and deliver emails to external MX servers.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 17:08:33 +07:00
b745041d55 fix: correct DKIM path (opendkim, not rspamd) in tools tasks
Some checks failed
CI/CD / syntax-check (push) Successful in 1m8s
CI/CD / deploy (push) Has been cancelled
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>
2026-03-22 16:57:32 +07:00
a28fffa7ae fix: mailserver account check via host file, not docker exec
Some checks failed
CI/CD / syntax-check (push) Successful in 1m30s
CI/CD / deploy (push) Has been cancelled
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>
2026-03-22 16:55:52 +07:00
b616c18c58 feat: add docker-mailserver for self-hosted outbound SMTP
Some checks failed
CI/CD / syntax-check (push) Successful in 1m6s
CI/CD / deploy (push) Failing after 18m22s
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>
2026-03-22 16:28:29 +07:00
bf59b75c8f fix: redesign backup archive structure + enable Outline email auth
Some checks failed
CI/CD / syntax-check (push) Successful in 1m13s
CI/CD / deploy (push) Has been cancelled
Backup (backup.sh.j2):
- Creates a single data_YYYY-MM-DD_HH-MM.tar.gz archive
- Unified data/ layout: databases/ (pg_dump .sql.gz) + volumes/ (docker volumes)
- Includes RESTORE.md with step-by-step instructions inside the archive
- S3 uploads to main/ prefix instead of flat root

Outline (tools role):
- Add SMTP_HOST/PORT/FROM vars to env.j2 template (required for email magic-link auth to activate)
- Add outline_smtp_* defaults to roles/tools/defaults/main.yml
- Without SMTP_HOST, the email auth plugin is disabled and clicking login does nothing

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 16:20:11 +07:00
a7b14759af fix: add front network to tools stack for Docker port binding
Some checks failed
CI/CD / syntax-check (push) Successful in 1m11s
CI/CD / deploy (push) Failing after 1m45s
Docker 29.x does not create DNAT rules for containers only on internal
networks. Add a non-internal 'front' network that outline and n8n join
alongside their internal networks, enabling host port binding to work.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 15:10:52 +07:00
9ca1177461 fix: crowdsec proxy network, uptime-kuma curl healthcheck, outline en_US, n8n 127.0.0.1
Some checks failed
CI/CD / syntax-check (push) Successful in 1m4s
CI/CD / deploy (push) Failing after 10m46s
- crowdsec: add proxy network for internet access (hub downloads)
- crowdsec-bouncer: remove (image crowdsecurity/cs-firewall-bouncer doesn't exist on Docker Hub)
- uptime-kuma: switch healthcheck from wget to curl (wget not in image)
- outline: fix DEFAULT_LANGUAGE ru_RU → en_US (unsupported locale)
- n8n: fix healthcheck localhost → 127.0.0.1 (IPv6 issue in Alpine)
- alertmanager: config permissions 0644 (was 0640, container couldn't read)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 08:14:07 +07:00
92d2c845d8 feat: add n8n, outline routes, remove syncthing, fix backup awscli
Some checks failed
CI/CD / syntax-check (push) Successful in 1m14s
CI/CD / deploy (push) Failing after 10m51s
- Add n8n to tools server (n8n.csrx.ru)
- Add cross-server Traefik routes: wiki.csrx.ru + n8n.csrx.ru → tools
- Remove Syncthing (replaced by Outline wiki)
- Fix awscli install: download static binary (apt/pip broken on Ubuntu 24.04)
- Add n8n secrets to vault (encryption key + JWT secret)
- Improve CI/CD workflow: syntax-check both playbooks, deploy both servers
- Update site.yml: unified single-command deploy for all servers

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 06:19:39 +07:00
05bcbab858 feat: add tools role (Outline wiki) + 3-server architecture
Some checks failed
CI/CD / syntax-check (push) Successful in 59s
CI/CD / deploy (push) Failing after 11m20s
Services:
- Outline wiki at wiki.csrx.ru → visual-tools:3000
- Outline uses Timeweb S3 (visual-outline bucket) for files

Structure:
- roles/tools/ — docker-compose + env templates for tools server
- playbooks/tools.yml — deploys base+docker+tools to visual-tools

Config changes:
- domain_dashboard: dashboard → dash.csrx.ru
- domain_wiki: wiki.csrx.ru (new)
- domain_mon: mon.csrx.ru (new, for Grafana)
- ip_main/tools/mon vars for cross-server Traefik routing
- outline_* secrets added to vault + main.yml aliases

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 05:36:04 +07:00