Если честно, я так долго откладывал написание этой заметки, что контекст уже слегка потерян… Но я все-таки решил ее написать, как напоминание о моей лени и наставление писать такие вещи сразу. Ну и чтобы опыта было побольше, хех
Для начала постановка задачи: поднять собственный email сервер рофла ради. При этом homelab у меня состоит из двух устройств: VPS сервера в качестве gateway (nginx + пару мелких сервисов) и основной машины за серым IP (где и поднималась почта), соединненных wg туннелем.
В качестве почты был выбран mailcow-dockerized, который меня заинтересовал простотой (я наигрался с ручной настройкой почты и хотелось чего-то коробочного), впрочем, не без минусов.
- В стандартном docker-compose используется их кастомный контейнер unbound, который не завелся и я переписал compose на стандартный
- В целом mailcow поднимает очень много лишних контейнеров(итого их порядка 30) и сетап получается вообще не минималистичным, из-за чего потом хочется его сменить на что-то адекватнее
- Плохая конфигурируемость компонент: например, я столкнулся что дефолтные настройки rspamd отправляют в спам все подряд, при этом поменять в UI их можно только для существующих аккаунтов, и нельзя поставить дефолтный для новых аккаунтов. Пришлось ручками править конфиг rspamd
Были и нюансы двух серверного сетапа:
- Пришлось криво настраивать проброс сертификата с gateway vps для домена m.foxido.dev на основной сервер, ибо получить от let’s encrypt его может только gateway, а нужен он на основном (scp + cron go brrr)
- Приходится прокидывать почтовые порты NAT’ом (destinatio nat) с gateway на основной сервер
# /etc/nftables snippet
...
chain prerouting {
type nat hook prerouting priority -100;
ip daddr <vps ip> dnat to <wg main ip> : tcp dport map {465 : 465, 993 : 993, 25 : 25 , <some other stuff>}
ip6 daddr <vps ipv6> dnat to <wg main ipv6> : tcp dport map {465 : 465, 993 : 993, 25 : 25, <some other stuff>}
}
...
Но основная проблема была в SPF и reverse ip. Поскольку все получатели ожидали письмо с m.foxido.dev, то есть ip gateway’я, они отвергали письма с ip основного сервера. Значит, надо завернуть траффик с этих контейнеров на gateway vps как через vpn, при этом не трогая весь остальной трафик)
Решалось это:
- Настройкой кастомной таблицы маршрутизации
ip route add <wg subnet> dev mcn table 1000
ip route add default via <gateway wg addr> dev mcn table 1000
# я добавил вообще все маршруты, но по идее это не нужно
# ...
# если пакет вышел из интерфейса docker-compose для mailcow —
# — надо использовать кастомную таблицу маршрутизации
ip rule add iif br-mailcow lookup 1000
-
Настойкой NAT в nftables и AllowedIPs в Wireguard
AllowedIPs = 0.0.0.0/0
на основном сервере, чтобы сам wireguard не отбрасывал пакеты (Важно: при этом настройка wg производится не через wg-quick, ибо wg-quick увидев 0.0.0.0 в AllowedIPs завернет туда вообще все)- NAT на gateway — чтобы маскировать исходящий трафик
- Где-то тут я еще стратегически проиграл и зачем-то сделал NAT на основном сервере, вроде чтобы не менять AllowedIPs на нули на gateway
-
Автоматизацией всех этих скриптов при запуске системы (systemd go brrrr)
На этом короткая заметка все, я точно ее допишу и подправлю. Но выложить лучше сразу, так, на всякий (хехе)