Безопасность, SMTP, очередь отправки, DKIM, деплой на Jambotron (Jambotron v0.2.3 75.1–75.3)
- SMTP-сервер переписан: разбор по строкам, AUTH PLAIN/LOGIN, нет открытого релея, MAIL FROM только свой после входа, 250 только после сохранения (иначе 451), лимит размера - отправка наружу: очередь outbound_queue (V2) с повторами ~22 ч и уведомлением о недоставке; Jakarta Mail, режимы off / mx / smarthost, байты письма не меняются (DKIM) - DKIM: подпись utils-mail-dkim, проверка Apache jDKIM; ключ PKCS#8, старый PKCS#1 читается - права: письма, папки, вложения — только владельцу (было: любой по номеру); имена вложений без ../ - секреты без значений по умолчанию (DB_PASSWORD, JWT_SECRET), регистрация закрыта, admin123 и /api/simulate/receive — только профиль dev - веб-клиент внутри jar (относительный /api), Dockerfile в 3 этапа, не root, health; docker-compose.jambotron.yml: секреты создаются при первом запуске, наружу только 8080 - gradle-wrapper.jar был в .gitignore — сборка не запускалась - тесты: 26 (SMTP реальным клиентом и сокетом, GreenMail, DKIM подпись+проверка, очередь) α Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
# Test deploy on Jambotron (v0.2.3 75.3): pick this file in the deploy wizard.
|
||||
# Outside, only the web client + API (service "mail", port 8080) through Jambotron's Caddy — give it a domain.
|
||||
# SMTP (3025) stays inside the VM's docker network; nothing is sent outside (OUTBOUND_MODE=off).
|
||||
# Secrets are generated on the first start into the "secrets" volume — nothing to type in, nothing in git.
|
||||
# The first mailbox (admin@<MAIL_DOMAINS>) and its password: in the "mail" logs on the first start.
|
||||
name: reactive-mail
|
||||
|
||||
services:
|
||||
secrets-init:
|
||||
image: alpine:3.20
|
||||
restart: "no"
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- |
|
||||
umask 077
|
||||
for name in DB_PASSWORD JWT_SECRET; do
|
||||
[ -s /secrets/$$name ] || head -c 48 /dev/urandom | base64 | tr -dc 'A-Za-z0-9' > /secrets/$$name
|
||||
done
|
||||
# postgres reads it as uid 70, the app as "mail" — readable inside these containers only
|
||||
chmod 644 /secrets/DB_PASSWORD /secrets/JWT_SECRET
|
||||
volumes:
|
||||
- secrets:/secrets
|
||||
|
||||
db:
|
||||
image: postgres:17-alpine
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
secrets-init:
|
||||
condition: service_completed_successfully
|
||||
environment:
|
||||
POSTGRES_DB: mailserver
|
||||
POSTGRES_USER: mail
|
||||
POSTGRES_PASSWORD_FILE: /run/mail-secrets/DB_PASSWORD
|
||||
volumes:
|
||||
- pgdata:/var/lib/postgresql/data
|
||||
- secrets:/run/mail-secrets:ro
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U mail -d mailserver"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
mem_limit: 256m
|
||||
|
||||
mail:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: backend/Dockerfile
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
expose:
|
||||
- "8080" # web client + API → domain in Jambotron
|
||||
- "3025" # SMTP, inside the network only
|
||||
environment:
|
||||
DB_HOST: db
|
||||
MAILSERVER_SECRETS_DIR: /run/mail-secrets
|
||||
MAIL_DOMAINS: ${MAIL_DOMAINS:-mail.test}
|
||||
MAIL_HOSTNAME: ${MAIL_HOSTNAME:-mail.test}
|
||||
DKIM_DOMAIN: ${MAIL_DOMAINS:-mail.test}
|
||||
MAIL_CATCH_ALL: ${MAIL_CATCH_ALL:-}
|
||||
OUTBOUND_MODE: "off"
|
||||
SMTP_AUTH_WITHOUT_TLS: "true" # SMTP is not reachable from outside the VM
|
||||
SPF_ENABLED: "false"
|
||||
DMARC_ENABLED: "false"
|
||||
volumes:
|
||||
- data:/app/data
|
||||
- secrets:/run/mail-secrets:ro
|
||||
mem_limit: 512m
|
||||
|
||||
volumes:
|
||||
secrets:
|
||||
pgdata:
|
||||
data:
|
||||
Reference in New Issue
Block a user