Files
moonwell-web/docs/mail-server.md
T

260 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Почта MoonWell
Для `support@moon-well.online` и `no-reply@moon-well.online` используется отдельный контейнер
[Stalwart Mail Server](https://stalw.art/). Он предоставляет SMTP, IMAP,
антиспам, DKIM и административный интерфейс. Данные и конфигурация хранятся
в именованных Docker volumes и переживают пересоздание контейнера.
## Что требуется от сервера
- постоянный публичный IPv4-адрес;
- возможность принимать TCP-соединения на порты `25`, `465`, `587`, `993`;
- разрешённый исходящий TCP-порт `25`;
- PTR/rDNS для IP со значением `mail.moon-well.online`;
- доступ к управлению DNS-зоной `moon-well.online`.
Без корректного PTR исходящие сообщения часто попадают в спам. Некоторые
хостинги блокируют исходящий порт 25 — это нужно проверить до настройки.
## Первый запуск
```bash
./scripts/mail-server.sh init
```
Проверь значения в `.env.mail`. Затем создай DNS-запись:
```text
mail.moon-well.online. A <публичный IPv4 сервера>
```
Запусти сервер:
```bash
./scripts/mail-server.sh up
./scripts/mail-server.sh credentials
```
Административный HTTP-порт намеренно доступен только на loopback-интерфейсе.
Открой туннель со своего компьютера:
```bash
ssh -L 8081:127.0.0.1:8081 <пользователь>@<сервер>
```
После этого открой `http://127.0.0.1:8081/admin` и войди с временными
реквизитами из команды `credentials`.
## Мастер Stalwart
Используй следующие значения:
- Server hostname: `mail.moon-well.online`
- Default email domain: `moon-well.online`
- Automatically obtain TLS certificate: включено
- Generate email signing keys: включено
- Storage: локальный RocksDB
- Directory: Internal Directory
- Logging: Console
Если DNS размещён у поддерживаемого Stalwart провайдера, подключи его в
последнем шаге. Тогда сертификат выпускается через DNS-01 без занятия
публичного порта 443. Иначе понадобится отдельно передать серверу TLS-сертификат
или временно предоставить ему порт 443 для ACME-проверки.
Сохрани постоянные реквизиты администратора, показанные мастером, и
перезапусти контейнер:
```bash
./scripts/mail-server.sh restart
```
Создай обычный пользовательский аккаунт `support@moon-well.online`.
Административный аккаунт нельзя использовать в почтовом клиенте.
Для приложения создай отдельный SMTP-аккаунт `no-reply@moon-well.online`
с правом отправки от этого адреса. Laravel использует его для подтверждения
email и восстановления пароля. Пароль хранится только в `.env` приложения;
в репозиторий его добавлять не нужно. Ящик поддержки остаётся отдельным.
В панели Stalwart открой `Management → Directory → Accounts` и создай
обычный пользовательский аккаунт (роль User):
- имя: `no-reply`;
- домен: `moon-well.online`;
- основной email: `no-reply@moon-well.online`;
- отображаемое имя: `MoonWell`;
- пароль: отдельный случайный пароль для SMTP.
В версиях панели с полем полного логина укажи `no-reply@moon-well.online`.
Названия полей могут отличаться между версиями; итоговый адрес и SMTP-логин
должны быть `no-reply@moon-well.online`. Не выдавай этому аккаунту роль
администратора. Отдельные MX/SPF/DKIM-записи для нового ящика не нужны —
используется уже настроенный домен.
[Создание аккаунтов в документации Stalwart](https://www.stalw.art/docs/faq/accounts/).
## DNS после мастера
В панели Stalwart открой:
`Management → Domains → Domains → moon-well.online → View DNS Zone file`
Перенеси предложенные записи в DNS-панель. В обязательный минимум входят:
- MX;
- SPF;
- DKIM;
- DMARC;
- записи автоконфигурации, которые предложит Stalwart.
Значение DKIM нужно брать только из созданной установки: ключ генерируется
индивидуально. Не копируй DKIM из примеров.
## Настройка почтового клиента
```text
Адрес: support@moon-well.online
IMAP-сервер: mail.moon-well.online
IMAP-порт: 993
Шифрование IMAP: SSL/TLS
SMTP-сервер: mail.moon-well.online
SMTP-порт: 465
Шифрование SMTP: SSL/TLS
SMTP-аутентификация: включена
Логин: support@moon-well.online
```
## Подключение Laravel
После создания `no-reply@moon-well.online` укажи в production `.env`:
```dotenv
APP_URL=https://moon-well.online
MAIL_MAILER=smtp
MAIL_SCHEME=smtps
MAIL_HOST=mail.moon-well.online
MAIL_PORT=465
MAIL_USERNAME=no-reply@moon-well.online
MAIL_PASSWORD=<пароль ящика>
MAIL_FROM_ADDRESS=no-reply@moon-well.online
MAIL_FROM_NAME="${APP_NAME}"
```
Затем сбрось и пересобери кэш конфигурации:
```bash
docker compose -f compose.prod.yaml exec -T --user app app php artisan optimize:clear
docker compose -f compose.prod.yaml exec -T --user app app php artisan config:cache
```
Если используется SSH-туннель к БД ядра, добавь
`-f compose.prod.ssh-tunnel.yaml` к обеим командам. Для Sail используй
`docker compose exec -T laravel.test php artisan …`.
`MAIL_HOST` — публичное имя с действительным TLS-сертификатом. Приложение
может отправлять письма на опубликованный Stalwart порт 465, даже если его
контейнер находится в другой Docker-сети. Не отключай проверку сертификата
и не подменяй имя на `stalwart` при использовании публичного сертификата.
При доставке нового кода выполни миграции (`php artisan migrate --force`).
Новые регистрации на сайте и через API лаунчера требуют подтверждения
почты; существующие и импортированные аккаунты сохраняют доступ.
Подтверждение не требует предварительного входа. Повторное письмо доступно
на `/email/verify`, восстановление — на `/forgot-password`. Обе ссылки
действуют 60 минут; ссылка восстановления одноразовая. Пароль меняется
в `web.users`, как при смене пароля в кабинете; игровые SRP-данные остаются
под управлением механизма билетов лаунчера.
Локально можно оставить `MAIL_MAILER=log`: тогда письма записываются в лог.
Для проверки реальной доставки используй свой аккаунт: зарегистрируй его,
подтверди почту, затем запроси восстановление. В обоих письмах отправитель
должен быть `MoonWell <no-reply@moon-well.online>`, а ссылки вести на `APP_URL`.
## Логотип сайта, писем и отправителя
Иконки сайта находятся в `public/branding/`, многоразмерный favicon —
в `public/favicon.ico`. Шаблон уведомлений использует
`public/branding/moonwell-mail-logo.png` как встроенное CID-изображение:
логотип прикрепляется к письму, а не загружается с чужого сервера.
Для значка рядом с отправителем подготовлен векторный логотип SVG Tiny P/S:
`https://moon-well.online/branding/moonwell-bimi.svg`.
В DNS-панели REG.RU добавляется запись:
```text
Тип: TXT
Имя: default._bimi
Значение: v=BIMI1; l=https://moon-well.online/branding/moonwell-bimi.svg;
```
Полное имя записи — `default._bimi.moon-well.online`. Нужен только один
BIMI TXT для этого имени. Запись применяется ко всем отправителям домена,
включая `support` и `no-reply`. Публиковать её следует после загрузки SVG
на production. Текущая политика DMARC `p=reject` соответствует требованию
BIMI; ослаблять её не требуется.
Это самостоятельная BIMI-запись без сертификата: наличие записи не
гарантирует отображение логотипа у получателя. Gmail требует дополнительно
VMC или CMC от удостоверяющего центра. После выпуска сертификата его цепочка
PEM размещается по HTTPS, а в TXT добавляется `a=https://…/certificate.pem`.
Обычный TLS-сертификат сайта или SMTP не заменяет VMC/CMC.
Требования: [Google Workspace](https://knowledge.workspace.google.com/admin/security/set-up-bimi),
[формат SVG BIMI Group](https://bimigroup.org/creating-bimi-svg-logo-files/).
Проверка после публикации DNS:
```bash
dig +short TXT default._bimi.moon-well.online
curl --fail --head https://moon-well.online/branding/moonwell-bimi.svg
```
## Резервное копирование
В бэкап должны попадать оба именованных volume:
- `stalwart-config`;
- `stalwart-data`.
Перед восстановлением используй ту же minor-версию образа Stalwart, что указана
в `compose.mail.yaml`.
## TLS на production-сервере
На production сертификат выпускает системный Certbot через Nginx. Контейнер
получает read-only каталог `MAIL_TLS_DIR` и использует:
```text
/run/stalwart-tls/fullchain.pem
/run/stalwart-tls/privkey.pem
```
Deploy-hook Certbot копирует обновлённые файлы в этот каталог и перезапускает
только контейнер Stalwart, чтобы он перечитал сертификат.
Hook устанавливается из `scripts/deploy-mail-certificate.sh`.
Certbot запускает deploy-hook для каждого обновлённого сертификата. Скрипт
проверяет, что сертификат покрывает `mail.moon-well.online`
(`MAIL_TLS_HOSTNAME`), и пропускает сертификаты других сайтов. Иначе
обновление сертификата основного сайта подменит сертификат SMTP/IMAP.
Внешний HTTPS-доступ к панели и JMAP проксируется через Nginx. Готовая
конфигурация находится в `ops/nginx-mail.conf`; внутренний HTTP-порт Stalwart
остаётся доступен только на `127.0.0.1`.
После установки сертификата его нужно добавить в Stalwart и выбрать как
сертификат по умолчанию. Для HTTP-настроек за Nginx также включается
`useXForwarded`, чтобы автоматические блокировки применялись к реальному
адресу клиента, а не к Docker gateway.
Если Nginx возвращает 502, а Stalwart работает и пишет
`security.ip-blocked ... remoteIp = <Docker gateway>`, проверь блокировку
адреса шлюза Docker в `Settings → Security → Blocked IPs`. Сними блокировку
только с этого адреса и добавь именно его в `Allowed IPs`, затем перезагрузи
настройки. Адрес шлюза можно узнать через `docker inspect`. HTTP-порт
Stalwart должен оставаться доступным только на loopback-интерфейсе хоста;
Nginx передаёт реальный адрес клиента в HTTP-заголовках. Не добавляй весь
интернет в разрешённые адреса и не отключай auto-ban.