Краткий вывод: Развертывание связки почтовый сервер mailcow и nextcloud на vps сокращает прямые операционные расходы бизнеса на 74–86% при парке от 20 до 100 активных рабочих мест, ликвидирует юридические риски блокировки данных по AUP/ITAR и исключает бесконтрольную индексацию корпоративной тайны LLM-моделями провайдеров. Автономный хостинг возвращает инженерам детерминированный контроль над криптографическими ключами, дисковыми p99-задержками базы MariaDB/PostgreSQL и сетевыми политиками фильтрации без привязки к подушевым лицензиям.
Содержание
- Аппаратные требования и сайзинг: Независимая корпоративная инфраструктура на VPS в 2026 году
- Критерии выбора VPS для почты: чистый IP, порт 25 и обязательная запись PTR (rDNS)
- Сравнительная матрица почтовых серверов: Mailcow vs iRedMail vs Mail-in-a-Box vs SaaS
- Настройка DNS записей для идеальной доставляемости 10/10 (Deliverability)
- Пошаговая установка Mailcow: dockerized почтовый сервер с Rspamd и SOGo
- Развертывание корпоративного диска Nextcloud на том же сервере или выделенной ноде
- Интеграция Nextcloud и Mailcow: единое офисное пространство
- Безопасность и отказоустойчивость: защита от перебора паролей и бэкапы
- Часто задаваемые вопросы (FAQ)
Аппаратные требования и сайзинг: Независимая корпоративная инфраструктура на VPS в 2026 году
Причины исхода из публичных SaaS-платформ
Корпоративная миграция с Google Workspace, Microsoft 365 и Notion на собственный изолированный стек обусловлена тремя критическими факторами:
- Неконтролируемая инфляция per-seat подписок. Линейное масштабирование затрат по формуле
N_сотрудников × $14–$36/месделает добавление каждого нового ящика или файлового хранилища финансово токсичным. Для компании из 50 человек годовой счет за базовый офисный пакет составляет от $8 400 до $21 600 без учета внешнего резервного копирования. - Риски внезапного аннулирования учетных записей. Алгоритмический комплаенс публичных облаков замораживает тенанты целиком при подозрении на нарушение AUP (Acceptable Use Policy), сбоях в банковском процессинге или геополитических санкциях. Отсутствие прямого доступа к файловой системе (
/var/vmail, каталогам Nextcloud) лишает системного администратора возможности снять аварийный дамп. - CLOUDA Act и сбор данных для RAG-пайплайнов. Положения US CLOUD Act обязывают гиперскейлеров предоставлять доступ к закрытым ключам и почтовой переписке по экстерриториальным ордерам. Параллельно провайдеры внедряют телеметрию и парсинг пользовательских вложений для тюнинга собственных моделей машинного обучения, нарушая NDA заказчиков.
Сравнительный анализ: SaaS-гиганты vs Self-Hosted VPS (расчет на 50–100 пользователей)
| Параметр оценки | Microsoft 365 / Google Workspace (SaaS) | Mailcow Dockerized + Nextcloud Hub (VPS) | Инженерное преимущество Self-Hosted |
|---|---|---|---|
| Стоимость (50 пользователей/год) | $8 400 – $18 000 (от $14/юзер/мес) | $1 080 – $1 440 (аренда KVM VPS + S3 Backup) | Экономия от $7 300/год (87%) |
| Стоимость (100 пользователей/год) | $16 800 – $36 000 | $1 800 – $2 400 (выделенный сервер / VDS) | Экономия от $15 000/год (89%) |
| Физический контроль данных | Отсутствует. Данные размазаны по мультитенентным кластерам | Полный. Файлы лежат на зашифрованных LUKS-разделах хоста | Прямой доступ к сырым блочным устройствам и ZFS/Btrfs снепшотам |
| Владение TLS/DKIM ключами | Ключи генерируются и хранятся на стороне вендора | RSA 2048/4096 / ed25519 в /opt/mailcow-dockerized/data |
Исключена MITM-дешифрация на пограничных прокси провайдера |
| Гарантии производительности I/O | Динамическое регулирование (throttling), скрытые квоты API | Гарантированный пул IOPS (от 15 000 IOPS на NVMe) | Отсутствие «noisy neighbors» при правильном выборе ноды |
| Защита от комплаенс-бана | Нулевая. Блокировка тенанта без права выгрузки архива | Абсолютная. Асинхронная репликация на резервный хостинг | RPO < 15 минут, RTO < 1 часа при наличии холодного резерва |
Аппаратный сайзинг и профиль серверных ресурсов
Связка компонентов Mailcow (Postfix, Dovecot, ClamAV, Rspamd, SOGo, Redis, MariaDB) и Nextcloud (PHP-FPM 8.3, PostgreSQL/MariaDB, Redis transactional locking) создает смешанный тип нагрузки: интенсивный I/O на мелких блоках (индексы Dovecot dovecot.index.cache, транзакции блокировок Nextcloud) и высокое потребление оперативной памяти демоном сигнатур антивируса clamd.
Рекомендованная конфигурация под нагрузку
- Штат 20–30 пользователей:
- CPU: 4 vCPU (KVM, без оверселлинга, порог Steal Time
%st$\le 1.0\%$). - RAM: 16 GB ECC RAM (ClamAV удерживает в RSS-памяти 1.8–2.2 GB; MariaDB buffer pool — 4 GB; Nextcloud PHP-FPM workers — 4 GB; Redis — 1 GB).
- Storage: 250–500 GB NVMe в RAID-1. Случайное чтение/запись 4K блоками: не менее 8 000 IOPS, latency p99 $\le 2.5\text{ ms}$.
- Штат 50–100 пользователей:
- CPU: 8 vCPU (выделенные vCPU или Bare-Metal нода на AMD EPYC / Ryzen 9).
- RAM: 32–64 GB ECC RAM.
- Storage: Двухуровневая топология: быстрый локальный массив 1 TB NVMe (RAID-1/10) под операционную систему, базы данных и индексы плюс монтирование объектного хранилища S3 (MinIO/Ceph/Wasabi) через
s3fs/интеграцию Primary Object Storage Nextcloud под тяжелые файлы.
# Предварительный стресс-тест дисковой подсистемы хоста перед развертыванием
# Замер latency p99 на мелких блоках 4KB (критично для баз MariaDB и Redis)
fio --name=randwrite --ioengine=libaio --iodepth=16 --rw=randwrite \
--bs=4k --direct=1 --size=2G --numjobs=2 --runtime=60 --group_reporting
Низкоуровневая оптимизация ядра Linux под стек Mailcow + Nextcloud
По умолчанию стандартные параметры дискового кэша и очередей сетевого сокета Linux приводят к накоплению «грязных» страниц в оперативной памяти с последующими микрофризами Dovecot и MariaDB во время сброса буферов на диск.
Файл конфигурации /etc/sysctl.d/99-corporate-stack.conf:
# Минимизация вытеснения страниц демонов в SWAP (критично для стабильности ClamAV и Redis)
vm.swappiness = 10
# Агрессивный фоновый сброс грязных страниц для ликвидации пиковых дисковых задержек
vm.dirty_background_ratio = 5
vm.dirty_ratio = 10
# Удержание метаданных файловой системы (dentry/inode cache) для быстрого обхода Maildir
vm.vfs_cache_pressure = 50
# Расширение очередей сетевого стека для обработки SMTP-сессий и входящих WebSocket-соединений
net.core.somaxconn = 4096
net.ipv4.tcp_max_syn_backlog = 8192
# Защита от OOM-killer и исчерпания файловых дескрипторов
fs.file-max = 2097152
Применение параметров в runtime:
sysctl --system
Для предотвращения падения стека из-за утечек памяти в сторонних плагинах Nextcloud или при резком наплыве спам-трафика в ClamAV, изоляция ресурсов фиксируется в docker-compose.override.yml почтового сервера через подсистему cgroups v2:
version: '2.1'
services:
clamd-mailcow:
deploy:
resources:
limits:
memory: 3000M
reservations:
memory: 2048M
restart: always
redis-mailcow:
deploy:
resources:
limits:
memory: 1024M
Подобная архитектура обеспечивает автономность, непрерывность бизнес-процессов и гарантирует детерминированную работу сервисов без риска внезапного изменения лицензионной политики внешних вендоров.
Критерии выбора VPS для почты: чистый IP, порт 25 и обязательная запись PTR (rDNS)
Развертывание стека, где объединены почтовый сервер mailcow и nextcloud на vps, начинается не с запуска docker compose up -d, а с жесткого аудита сетевой инфраструктуры хостинг-провайдера на уровне L3/L4. Почтовый протокол SMTP (RFC 5321) — одна из наиболее консервативных и регулируемых частей интернета. Ошибки в выборе виртуальной машины приведут к тому, что исходящие сообщения будут молча отбрасываться граничными шлюзами Google Workspace, Microsoft 365 и Mail.ru с кодами 550 5.7.1 или 554 Message rejected еще на этапе TCP-рукопожатия.
Выбор инстанса для связки Mailcow + Nextcloud опирается на три фильтра: доступность исходящего трафика на порт 25/TCP, репутацию выделенного IPv4/IPv6 адреса и возможность делегирования обратной зоны DNS (rDNS).
Фильтр №1: Доступность исходящего TCP-порта 25 (Egress SMTP)
Более 90% бюджетных IaaS/VPS-провайдеров (Hetzner Cloud, DigitalOcean, Linode/Akamai, Vultr, Scaleway) по умолчанию дропают исходящие пакеты на порт 25/TCP на уровне граничных маршрутизаторов (Border Gateway) или правил eBPF/iptables гипервизора.
Причина — борьба со спам-ботнетами: аренда инстанса за $3 на скомпрометированную карту с последующей генерацией миллионов писем наносит колоссальный удар по автономной системе (ASN) провайдера, отправляя целые префиксы /24 и /20 в списки Spamhaus.
Техническое разграничение: Клиентские порты отправки587/TCP(STARTTLS) и465/TCP(SMTPS Implicit) предназначены исключительно для аутентифицированной доставки писем от почтового клиента (MUA) к серверу (MSA). Входящие письма сервер принимает на25/TCP, но для отправки почты внешнему миру ваш MTA (Postfix в составе Mailcow) обязан инициировать соединение на удаленный сервер именно через порт 25/TCP. Если исходящий 25-й порт закрыт, сервер не сможет доставить ни одного письма напрямую.
Перед развертыванием контейнеров проверьте сетевую доступность шлюзов через сокет ядра:
# Тест доступности исходящего 25/TCP через сырой сокет bash
timeout 5 bash -c '</dev/tcp/aspmx.l.google.com/25' && echo "Port 25 OPEN" || echo "Port 25 FILTERED/BLOCKED"
# Альтернативная диагностика через netcat с замером времени ответа
nc -zv -w 5 aspmx.l.google.com 25
Если утилита возвращает Connection timed out или Operation now in progress, трафик блокируется файрволом провайдера. На этом этапе существует два сценария: 1. Тикет в техническую поддержку: Запрос снятия блокировки («Unblock outbound port 25 for self-hosted mail server»). Провайдеры уровня Hetzner или Linode требуют подтверждения личности (KYC), подтвержденного домена и возраста аккаунта от 30 дней. 2. Отказ провайдера: Если хостер на уровне Terms of Service (AUP) запрещает почтовый трафик (например, OVH на линейках Starter/Kimsufi), такой VPS непригоден для автономного сервера. Настройка SMTP-релея через сторонние сервисы (SendGrid, Postmark) лишает смысла локальный стек Mailcow и увеличивает задержки передачи данных (latency p99).
Фильтр №2: Репутация IPv4-пула и аудит черных списков (DNSBL/RBL)
В условиях дефицита IPv4 провайдеры циклически выдают освободившиеся адреса новым арендаторам. Высока вероятность получить IP, который предыдущий владелец использовал для спама, фишинга или криптомайнинга.
Перед настройкой почтовых сервисов выполните автоматизированный аудит IP-адреса по базам Spamhaus ZEN (объединяет SBL, XBL, PBL), Barracuda Reputation Block List (BRBL) и UCEPROTECT:
#!/usr/bin/env bash
# Скрипт реверс-запроса к ключевым DNSBL серверам
CURRENT_IP=$(curl -s -4 https://ifconfig.co)
REVERSED_IP=$(echo "$CURRENT_IP" | awk -F. '{print $4"."$3"."$2"."$1}')
RBL_LIST=(
"zen.spamhaus.org"
"b.barracudacentral.org"
"bl.spamcop.net"
"dnsbl.sorbs.net"
"psbl.surriel.com"
)
echo "Проверка IP: $CURRENT_IP (обратная зона: $REVERSED_IP)"
for rbl in "${RBL_LIST[@]}"; do
result=$(dig +short "${REVERSED_IP}.${rbl}")
if [ -n "$result" ]; then
echo -e "\e[31m[BLOCKED]\e[0m в $rbl -> Код возврата: $result"
else
echo -e "\e[32m[CLEAN]\e[0m в $rbl"
fi
done
Интерпретация кодов Spamhaus ZEN: * 127.0.0.2 (SBL) — прямой спам-источник. Крайне тяжело поддается делистингу без смены провайдера. * 127.0.0.4–7 (XBL) — машина инфицирована эксплойтом или находится в составе ботнета. * 127.0.0.10–11 (PBL) — Policy Block List. Диапазон помечен провайдером как динамический/пользовательский пул (не предназначен для серверов). Для снятия метки требуется активная запись PTR от хостера.
Если IP числится в Spamhaus SBL или Barracuda, запрашивайте у хостера немедленную замену IP-адреса до начала настройки Mailcow. Попытка прогрева заблокированного IP приведет к немедленному попаданию домена в базы постоянных репутационных фильтров Gmail (Google Postmaster Tools).
Фильтр №3: Делегирование PTR-записи (Reverse DNS / rDNS)
Обратная запись DNS связывает IP-адрес с каноническим доменным именем (FQDN). Почтовые серверы принимающей стороны реализуют строгую проверку FCrDNS (Forward-Confirmed Reverse DNS) согласно стандарту RFC 5321:
[SMTP Connection Received from 203.0.113.10]
│
▼
1. Query PTR (203.0.113.10) ─────────► mail.example.com
│
▼
2. Query A (mail.example.com) ───────► 203.0.113.10
│
▼
3. Match Check: IP == IP? ──────────► PASS (Accept SMTP HELO)
IP != IP? ──────────► FAIL (550 5.7.1 Drop connection)
Без настроенной PTR-записи серверы Gmail возвращают ошибку: 550-5.7.25 The IP address sending this message does not have a PTR record, or the corresponding forward DNS entry does not point to the sending IP.
Правила формирования rDNS:
- Запись PTR настраивается исключительно в панели управления провайдера хостинга (владельца автономной системы и блока LIR), а не у регистратора домена.
- Имя в PTR обязано совпадать с параметром
myhostnameвpostfix/main.cf(в Mailcow это переменнаяMAILCOW_HOSTNAMEв файлеmailcow.conf, напримерmail.example.com). - Прямая A-запись для
mail.example.comдолжна резолвиться в тот же IP-адрес. - Для IPv6 (если стек включен) обязательна отдельная PTR-запись для исходящего IPv6-адреса, иначе шлюзы Gmail отклонят входящее v6-соединение.
Проверка валидности FCrDNS через терминал:
# 1. Проверяем PTR для IPv4
dig -x $(curl -s -4 https://ifconfig.co) +short
# 2. Проверяем обратное соответствие A-записи
dig +short A mail.example.com
Если вывод первой команды не равен mail.example.com. или не совпадает с выводом второй — отправлять почту нельзя.
Сравнительный анализ хостинг-провайдеров для Mailcow + Nextcloud
Совмещенный стек Mailcow + Nextcloud требователен к ресурсам. Антивирус ClamAV в связке с парсером Rspamd потребляет от 1.5 до 2.5 ГБ RAM, а PHP-FPM пулы и СУБД MariaDB для Nextcloud требуют быстрого дискового ввода-вывода (IOPS) и низкой латентности CPU.
| Провайдер | Порт 25/TCP (Egress) | Настройка PTR (rDNS) | Риск «грязных» подсетей | Требования к CPU/IOPS | Пригодность под стек |
|---|---|---|---|---|---|
| Hetzner Cloud | Заблокирован по умолчанию. Открытие через тикет спустя 30 дней после верификации аккаунта. | Мгновенно через Cloud Console / API для IPv4 и IPv6 (/64). |
Низкий (строгий KYC, быстро банят спамеров). | Выделенные vCPU (CCX) или Shared (CPX). Latency NVMe p99 < 1.2 ms. CPU Steal (%st) < 0.2%. |
Отличная (при условии подтвержденного аккаунта). |
| Netcup | Открыт по умолчанию на большинстве инстансов (RS-серия) либо открывается по запросу. | Панель Customer Control Panel (CCP). Полная поддержка v4/v6. | Средний/Низкий. Мониторят спам-активность. | Серия Root Server (RS) с гарантированными ядрами KVM. Высокий IOPS. | Идеальная для тяжелого стека (Mail + Nextcloud). |
| DigitalOcean | Закрыт жестко для новых аккаунтов. Разблокировка через саппорт практически невозможна. | Через сетевой интерфейс дроплета (автоматически привязывается к имени). | Высокий (массовый abuse от тестовых дроплетов). | Shared CPU подвержены троттлингу при пиках ClamAV (Steal Time до 8%). | Не рекомендуется (высокий риск блокировки 25 порта). |
| Vultr | Закрыт по умолчанию. Открывается тикетом с указанием домена, DKIM, SPF и бизнес-целей. | Поддерживается в панели для всех инстансов. | Высокий (подсети часто попадают в UCEPROTECT-L2). | NVMe инстансы обладают высоким IOPS, но базовая стабильность сети плавает. | Удовлетворительно (требуется ручная смена IP при браке). |
| Selectel / Timeweb (РФ) | Открыт по умолчанию либо открывается без задержек по запросу без KYC. | Доступна смена PTR в веб-интерфейсе для IPv4. | Минимальный внутри РФ, но возможны блокировки западными спам-базами. | Высокая производительность дисковой подсистемы. Минимальный ping до серверов Mail.ru и Yandex. | Высокая (для целевой аудитории внутри юрисдикции РФ). |
Аппаратные лимиты ядра и гипервизора
При совмещении почты и облачного хранилища критичны параметры виртуализации. Избегайте контейнерной виртуализации OpenVZ / LXC: в ней ограничены возможности тюнинга сетевых сокетов ядра и изолированных сетевых пространств имен (network namespaces) для Docker. Допустима только честная аппаратная виртуализация KVM с доступом к модулям ядра.
Контролируйте метрику CPU Steal Time (%st в выводе top или vmstat 1): * Значение %st выше 1.5% означает оверселлинг со стороны хостера. * В моменты пиковой нагрузки Nextcloud (индексация файлов) или сканирования входящего архива модулем ClamAV задержка обработки пакетов процессами Postfix превысит таймаут SMTP-сессии (smtpd_timeout = 300s), что приведет к аварийному разрыву очередей с кодом 451 4.3.0 Mail server temporarily unavailable.
Перед установкой настройте сетевой стек операционной системы через /etc/sysctl.d/99-mail-network.conf:
# Защита от переполнения очереди соединений при входящих волнах почты
net.core.somaxconn = 4096
net.ipv4.tcp_max_syn_backlog = 4096
# Расширение диапазона локальных портов для одновременных SMTP-сессий
net.ipv4.ip_local_port_range = 10240 65535
# Уменьшение времени ожидания закрытия сокета (борьба с TIME_WAIT)
net.ipv4.tcp_fin_timeout = 15
# Обязательно для корректной маршрутизации мостов Docker (bridge)
net.ipv4.ip_forward = 1
Применение параметров:
sysctl --system
Только после соблюдения этих сетевых условий и верификации сетевых фильтров сервер готов к развертыванию контейнеров Mailcow и Nextcloud.
Сравнительная матрица почтовых серверов: Mailcow vs iRedMail vs Mail-in-a-Box vs SaaS
Выбор архитектуры для развертывания почты на собственном инстансе упирается в компромисс между эксплуатационными накладными расходами (Ops overhead), изоляцией компонентов ядра и контролем над сквозным пайплайном обработки сообщений (MTA/MDA).
В сценарии, когда разворачивается почтовый сервер mailcow и nextcloud на vps, ключевым фактором становится воспроизводимость окружения, предсказуемость потребления памяти подсистемой фильтрации и возможность бесшовной интеграции учетных записей без деградации I/O хоста.
Ниже представлена детальная техническая декомпозиция актуальных решений для самостоятельного хостинга в сравнении с управляемыми облачными провайдерами.
Сравнительная таблица характеристик и архитектурных отличий
| Критерий | Mailcow: dockerized | iRedMail (Open Source Core) | Mail-in-a-Box (MiaB) | Корпоративный SaaS (Workspace / Proton) |
|---|---|---|---|---|
| Базовая архитектура | Микросервисная, декларативный docker compose (~18 контейнеров) |
Монолитная установка bash-скриптом на хост-ОС (deb/rpm) | Монолитный bash-скрипт жесткой конфигурации (только Ubuntu LTS) | Проприетарная закрытая распределенная инфраструктура |
| RAM (Минимум / Production) | 2.5 GiB (без ClamAV) / 4–6 GiB (с ClamAV + Solr) | 2 GiB / 4 GiB | 1 GiB / 2 GiB | 0 (клиентский стек не требует серверных ресурсов) |
| Веб-почта и Groupware | SOGo (полный стек CalDAV, CardDAV, Microsoft ActiveSync / EAS) | Roundcube (по умолчанию) или SOGo (ручная сборка) | Roundcube (базовый IMAP, без нативного EAS) | Проприетарный веб-интерфейс, синхронизация через Google Sync / API |
| Движок антиспама | Rspamd (C/Lua, асинхронный event-loop, ML-классификаторы, Redis) | Amavisd-new + SpamAssassin (Perl) или Rspamd (в новых ветках) | Postgrey + SpamAssassin (тяжелый оверхед Perl-воркеров) | Закрытые нейросетевые спам-фильтры на стороне вендора |
| Антивирусный стек | ClamAV в изолированном контейнере с возможностью отключения | ClamAV системным сервисом clamd (высокий риск OOM хоста) |
Отсутствует или базовые правила SpamAssassin | Скрытый потоковый сигнатурный и эвристический анализ |
| Аутентификация и 2FA/MFA | FIDO2 / WebAuthn (аппаратные YubiKey), TOTP на уровне админки и SOGo | TOTP через сторонние плагины Roundcube; FIDO2 отсутствует «из коробки» | Базовый TOTP в панели управления; ограниченный Webmail | Полный спектр: FIDO2/WebAuthn, push-токены, passkeys, SAML/SSO |
| Стратегия резервного копирования | Атомарные дампы томов: встроенный скрипт backup_and_restore.sh, интеграция с Restic/Borg |
Разрозненные bash-скрипты: mysqldump + tar/rsync директории /var/vmail |
Встроенный инкрементальный бэкап на базе duplicity (локально / S3) |
Недоступно прямое снятие RAW-дампов, экспорт через Google Takeout / MBOX |
| Совместное размещение с Nextcloud | Идеально: изолированная Docker-сеть, общий reverse-proxy, встроенный OAuth2-провайдер | Требует ручной правки виртуальных хостов Nginx хоста и сокетов PHP-FPM | Конфликт портов: MiaB монопольно захватывает bind9/NSD и 80/443 порты | Только внешняя интеграция почты по протоколам IMAP/SMTP |
| TCO (Стоимость владения) | $10–25/мес за VPS (фиксированная цена за терабайты данных) | $10–20/мес за VPS + платная подписка на админку iRedAdmin-Pro | $5–15/мес за VPS (ограничение по типам нагрузок) | $6–18 за каждого пользователя ежемесячно |
Архитектурный анализ компонентов
1. Фильтрация контента: Rspamd (C/Lua/Redis) против SpamAssassin (Perl)
Критическое узкое место любого почтового сервера под нагрузкой — задержка анализа сообщений (p99 latency) на уровне Milter/LMTP.
- Mailcow (Rspamd): Архитектура построена на неблокирующем вводе-выводе (
epoll/kqueue). Rspamd выполняет скоринг заголовков, регулярные выражения и сетевые DNSBL-запросы параллельно. Обучение классификатора Байеса и нейронной сети (модульneural) вынесено в Redis-бэкенд. Использование двухслойного перцептрона позволяет адаптировать веса символов динамически на лету. Всплеск нагрузки в 100 входящих писем/сек не вызывает лавинообразного создания процессов, сохраняя p99 latency в пределах 70–110 мс. - iRedMail / MiaB (SpamAssassin): Монолитная обработка на Perl. При входящем потоке писем Amavisd форкает форвардные воркеры (
amavisd child processes), каждый из которых потребляет 80–150 МБ резидентной памяти (RSS). При попадании на хост с высоким показателем CPU Steal Time (%st > 5%) или медленным дисковым I/O обработка пачки писем быстро утилизирует память хоста, вызывая срабатываниеkernel: oom-killer.
# Диагностика задержки Rspamd и проверка доступности модели в Redis:
docker compose exec redis-mailcow redis-cli -a "mailcow_redis_password" info memory
docker compose exec rspamd-mailcow rspamc stat
2. Проблема оверхеда памяти ClamAV и управление cgroups
Сигнатурная база ClamAV (main.cvd, daily.cvd) при распаковке и компиляции дерева сигнатур требует единовременно от 1.1 до 1.4 GiB RAM.
В монолитных дистрибутивах (iRedMail) неконтролируемый запуск freshclam и перезагрузка демона clamd нередко роняют соседние процессы (например, базу MySQL/MariaDB). В архитектуре Mailcow контейнер clamd изолирован лимитами cgroups. На инстансах с ограниченным объемом памяти (менее 4 ГБ) ClamAV безболезненно отключается переменной окружения без нарушения работы цепочки postfix -> rspamd -> dovecot:
# mailcow.conf
# Отключение тяжелого демона сканирования для инстансов до 4GB RAM:
SKIP_CLAMD=y
Если сканирование обязательно, в docker-compose.override.yml задается жесткий лимит по cgroups v2, предотвращающий деградацию хоста:
version: '2.1'
services:
clamd-mailcow:
deploy:
resources:
limits:
memory: 1800M
reservations:
memory: 1200M
Для стабильной работы баз данных и очередей Redis в ядре хоста обязательно выставляется параметр:
# /etc/sysctl.d/99-mail-stack.conf
vm.overcommit_memory = 1
fs.file-max = 2097152
3. Веб-интерфейс и протоколы синхронизации: SOGo против Roundcube
- Mailcow (SOGo): Предоставляет полноценную реализацию протокола Microsoft ActiveSync (EAS версии 14.0/16.0). Мобильные клиенты iOS/Android получают нативную двухстороннюю синхронизацию писем, папок, календарей и контактов «из коробки» без использования сторонних костылей. Под капотом SOGo использует
memcachedдля кэширования сессий блокировок, минимизируя нагрузку на реляционную СУБД. - Roundcube (iRedMail / MiaB): Классический легковесный MUA (Mail User Agent), работающий строго по протоколам IMAP/SMTP. Он не умеет отдавать ActiveSync без глубокой настройки внешнего сервиса
Z-Push. Для работы с контактами и календарями на мобильных устройствах пользователю приходится вручную настраивать раздельные подключения по CalDAV и CardDAV, что усложняет эксплуатацию.
4. Безопасность периметра и MFA
Mailcow нативно интегрирует WebAuthn (FIDO2) на уровне Nginx-proxy и UI-слоя. Пользователь может привязать аппаратные ключи YubiKey, Titan Security Key или биометрию платформы (TouchID/Windows Hello), исключая перехват сессий через фишинг.
В iRedMail и MiaB поддержка двухфакторной аутентификации ограничена стандартными TOTP-генераторами (Google Authenticator) через плагины, а администрирование алиасов и карантина в открытой версии iRedMail заблокировано в CLI — полнофункциональный интерфейс доступен только в платной версии iRedAdmin-Pro ($249+/год).
5. Механика резервного копирования и Disaster Recovery
Восстановление почтовой системы после сбоя хоста зависит от атомарности состояния очередей и Maildir/mdbox:
- Mailcow: Скрипт
helper-scripts/backup_and_restore.shвыполняет консистентный срез: переводит хранилище Dovecot в режим чтения (doveadm backup), снимает транзакционный бинарный дамп базы MariaDB черезmysqldump --single-transaction --quickи упаковывает persistent volumes (DKIM-ключи, конфигурации Rspamd, письма). Возможна прямая репликация сообщений в реальном времени через протокол Dovecot dsync:
# Синхронизация почтовых ящиков на резервный хост через doveadm
doveadm -D -v sync -u "[email protected]" ssh [email protected] doveadm
- Mail-in-a-Box: Жестко завязан на утилиту
duplicity. Бэкап инкрементальный, с шифрованием GPG, но процесс восстановления монолитный: развернуть чистую ОС строго поддерживаемой версии Ubuntu, запустить инсталлятор и выполнить команду восстановления. Шаг в сторону по версии дистрибутива ломает процесс. - iRedMail: Администратор вынужден самостоятельно писать shell-скрипты для синхронизации
/var/vmail/, отслеживания прав доступа UID/GID (vmail:vmail) и экспорта баз пользователей OpenLDAP/PostgreSQL.
Итог выбора
- Mailcow — безальтернативный выбор для продакшн-инсталляций, где почта живет на одном VPS рядом с Nextcloud или другими корпоративными сервисами. Изоляция в Docker защищает систему от взаимной порчи зависимостей Python/PHP, а стек Rspamd + SOGo покрывает все требования к антиспаму и удобству мобильных клиентов.
- iRedMail подходит системным администраторам старой школы, которым требуется встроить Postfix/Dovecot в существующую инфраструктуру централизованного каталога OpenLDAP на bare-metal сервере без оверхеда контейнеризации.
- Mail-in-a-Box рассчитан исключительно на запуск выделенного single-purpose сервера «поставил и забыл», где хостинг одного домена не требует глубокого тюнинга фильтрации и модификации системного веб-сервера.
- Корпоративный SaaS оправдан только при полном отсутствии штатного DevOps-инженера для контроля спам-репутации IP-адресов и готовности платить ежемесячную подписку за каждого сотрудника без контроля над приватными ключами шифрования.
Настройка DNS записей для идеальной доставляемости 10/10 (Deliverability)
Разворачивая автономный почтовый сервер mailcow и nextcloud на vps, инженер сталкивается с жесткой политикой входящей фильтрации Tier-1 почтовых провайдеров (Google Workspace, Microsoft 365, Fastmail, Яндекс 360). Спам-фильтры SpamAssassin, Rspamd и проприетарные нейросетевые скореры Gmail отбрасывают почту с кодами 550 5.7.1 или отправляют письма в спам-папку при малейшем расхождении в криптографических подписях или сетевой идентификации хоста.
Для достижения эталонного скора 10/10 на валидаторах уровня mail-tester.com требуется монолитная связка записей: FCrDNS, MX, SPF, DKIM-2048, DMARC в терминальном режиме reject и DANE/TLSA на базе DNSSEC.
[ Отправка письма с VPS (Mailcow Postfix) ]
│
▼
┌─────────────────────────────────────────┐
│ FCrDNS: PTR (IP) <==> A (mail.domain) │ ───► Не совпадает? ──► [ 550 PTR Drop ]
└──────────────────┬──────────────────────┘
│ Валидно
▼
┌─────────────────────────────────────────┐
│ SPF: strict ip4/ip6 (RFC 7208: -all) │ ───► Не в пуле IP? ──► [ SPF Hardfail ]
└──────────────────┬──────────────────────┘
│ Валидно
▼
┌─────────────────────────────────────────┐
│ DKIM: RSA-2048 (Rspamd Selector) │ ───► Хэш поврежден? ──► [ DKIM Fail ]
└──────────────────┬──────────────────────┘
│ Валидно
▼
┌─────────────────────────────────────────┐
│ DMARC: p=reject; aspf=s; adkim=s │ ───► Расхождение? ──► [ DMARC Reject ]
└──────────────────┬──────────────────────┘
│ Валидно
▼
┌─────────────────────────────────────────┐
│ DANE: TLSA 3 1 1 (DNSSEC Chain of Trust)│ ───► Подмена TLS? ──► [ MITM Block ]
└──────────────────┬──────────────────────┘
│ Валидно
▼
[ Inbox: Скоринг 10/10 ]
1. FCrDNS и MX: Фундамент сетевого рукопожатия
До парсинга заголовков письма принимающий MTA выполняет проверку Forward-Confirmed reverse DNS (FCrDNS). Если строка HELO/EHLO, отдаваемая Postfix, не резолвится в IP-адрес отправки, либо PTR-запись хостинга не возвращает исходный FQDN, соединение сбрасывается на фазе сокета.
Установите PTR-запись в панели хостинга для IPv4 и IPv6:
198.51.100.24.in-addr.arpa. IN PTR mail.example.com.
4.2.0.0...1.0.0.2.ip6.arpa. IN PTR mail.example.com.
В authoritative DNS-зоне основного домена прописываются прямые A/AAAA-записи почтового шлюза и MX-маршрутизация:
; Хост почтового кластера
mail.example.com. 3600 IN A 198.51.100.24
mail.example.com. 3600 IN AAAA 2001:db8:1::24
; Почтовый маршрутизатор (MX) для обслуживаемого домена
example.com. 3600 IN MX 10 mail.example.com.
Точка на конце FQDN обязательна во избежание аппендинга зоны (предотвращает превращение записи в mail.example.com.example.com).
2. SPF (Sender Policy Framework): Лимит 10 DNS Lookups и жесткий отказ
Запись SPF специфицируется согласно RFC 7208. Распространенная ошибка — использование мягкого флага ~all (SoftFail) вместо жесткого -all (Fail), либо перегрузка механизма конструкциями include:, a, mx, вызывающими каскадные DNS-запросы. RFC 7208 §4.6.4 строго ограничивает лимит DNS-запросов числом 10. Превышение лимита возвращает статус PermError, уничтожающий скоринг доставляемости.
Исключите механизмы a и mx — они добавляют от 20 до 80 мс latency p99 при валидации сессии удаленным почтовым демоном. Указывайте прямые CIDR-диапазоны интерфейсов:
example.com. 3600 IN TXT "v=spf1 ip4:198.51.100.24 ip6:2001:db8:1::24 -all"
Директива -all однозначно инструктирует шлюз получателя уничтожать любые сообщения, поступившие с адресов вне указанных подсетей.
3. DKIM (DomainKeys Identified Mail): RSA-2048 и чанкинг UDP
Для защиты целостности тела и служебных заголовков письма применяется асимметричная криптография (RFC 6376). Селектор по умолчанию в Mailcow — dkim. Ключи длиной 1024 бит сегодня компрометируются современными мощностями и помечаются Google как ненадежные. Минимальный стандарт — RSA 2048 бит.
Генерация ключевой пары вручную через OpenSSL (если не используется автогенерация Rspamd UI):
# Генерация закрытого ключа без шифрования паролем
openssl genrsa -out dkim_private.key 2048
# Извлечение открытого ключа в формат PEM
openssl rsa -in dkim_private.key -pubout -outform PEM -out dkim_public.pem
# Извлечение чистой base64-строки для DNS TXT
grep -v '^-' dkim_public.pem | tr -d '\n' > dkim_record.txt
Поскольку длина публичного ключа RSA-2048 превышает лимит одного 255-байтового текстового блока в UDP DNS-ответе (RFC 1035), TXT-запись разбивается на несколько строковых фрагментов внутри круглых скобок. DNS-сервер склеивает их на лету:
dkim._domainkey.example.com. 3600 IN TXT (
"v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0Y3w"
"QvT2Nq4kL5m8RzP+7d8YkP+6H4b9N7w1e3K...[длинная base64-строка]..."
"5m2R7T9kL+8v9wIDAQAB"
)
4. DMARC: Политика терминального реджекта и строгая унификация
DMARC (RFC 7489) связывает SPF и DKIM с адресом в заголовке From:, предотвращая атаки спуфинга и CEO-fraud. Для идеальной репутации статус p=none (только мониторинг) недопустим — спам-фильтры ранжируют домены с политикой none с понижающим коэффициентом.
Устанавливайте бескомпромиссную блокировку p=reject со строгим выравниванием (Strict Alignment) идентификаторов:
_dmarc.example.com. 3600 IN TXT "v=DMARC1; p=reject; sp=reject; adkim=s; aspf=s; pct=100; rua=mailto:[email protected]; ruf=mailto:[email protected]; fo=1"
Разбор директив: * p=reject; sp=reject; — немедленный реджект на уровне MTA невалидных писем как для корневого домена, так и для всех субдоменов. * adkim=s; aspf=s; — строгий режим (Strict). Домен в DKIM-теге d= и домен в SPF Envelope Sender обязаны побайтово совпадать с заголовком From:, использование поддоменов без отдельной авторизации запрещено. * pct=100; — применение политики к 100% входящего потока. * fo=1 — генерация forensic-отчетов (RUF) при сбое хотя бы одного механизма аутентификации (SPF или DKIM).
5. DANE и TLSA: Криптографическое связывание TLS через DNSSEC
DANE (DNS-based Authentication of Named Entities, RFC 6698) защищает протокол SMTP от перехвата и атак класса STARTTLS Stripping. Наличие валидной TLSA-записи гарантирует, что удаленный сервер не согласится на понижение соединения до plaintext при передаче данных.
Предварительное условие: доменная зона обязана быть подписана DNSSEC у регистратора.
Для контейнера Nginx/Postfix в Mailcow TLSA-запись привязывается к сертификату Let's Encrypt. Сгенерируйте SHA-256 дайджест открытого ключа X.509 сертификата (Usage 3, Selector 1, Matching type 1):
# Извлечение SPKI-хэша из текущего боевого сертификата Mailcow
openssl x509 -in /opt/mailcow-dockerized/data/assets/ssl/cert.pem -noout -pubkey \
| openssl pkey -pubin -outform DER \
| openssl dgst -sha256 -hex \
| awk '{print $2}'
Полученный 64-символьный хэш помещается в DNS-запись порта 25 TCP:
_25._tcp.mail.example.com. 3600 IN TLSA 3 1 1 e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
Параметры 3 1 1: * 3 (Domain-issued certificate): Сертификат проверяется напрямую, минуя публичные центры сертификации. * 1 (SubjectPublicKeyInfo): Проверяется хэш открытого ключа (позволяет продлевать сертификат без смены TLSA, если закрытый ключ сохраняется). * 1 (SHA-256): Алгоритм хеширования дайджеста.
6. Системный аудит и валидация через CLI и mail-tester.com
Внутренний резолвер Mailcow на базе Unbound может страдать от переполнения сокетных буферов UDP при валидации каскада DNS-ответов под нагрузкой. Перед диагностикой скорректируйте сетевые лимиты ядра Linux хоста через sysctl:
# Увеличение сетевых буферов для исключения дропа тяжелых DNSSEC пакетов
sudo sysctl -w net.core.rmem_max=8388608
sudo sysctl -w net.core.wmem_max=8388608
sudo sysctl -w net.ipv4.udp_rmem_min=16384
Верификация развернутой конфигурации из терминала:
# 1. Проверка FCrDNS
dig -x 198.51.100.24 +short
dig A mail.example.com +short
# 2. Проверка синтаксиса и резолва SPF
dig TXT example.com +short | grep "v=spf1"
# 3. Аудит корректности склейки чанков DKIM
delv @1.1.1.1 TXT dkim._domainkey.example.com
# 4. Проверка цепочки DNSSEC и TLSA-записи
delv @8.8.8.8 TLSA _25._tcp.mail.example.com +rtrace
Завершающий тест на mail-tester.com
- Сгенерируйте проверочный адрес на сервисе (например,
[email protected]). - Отправьте письмо из веб-интерфейса SOGo (входит в Mailcow) или с привязанного клиента Nextcloud Mail. Письмо обязано содержать реальную тему, текстовое тело и HTML-часть (multipart/alternative).
- При анализе отчета лог SpamAssassin должен показать чистый результат без штрафных баллов:
DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU(-0.1 за валидность)SPF_PASS(-0.001)DMARC_PASS(-0.1)- Отсутствие IP в ключевых черных списках (Spamhaus ZEN, Barracuda, Invaluement).
- Результат: 10/10 points. Почтовый кластер обладает максимальной криптографической валидностью, гарантируя доставку в Primary Inbox крупнейших почтовых операторов мира.
Пошаговая установка Mailcow: dockerized почтовый сервер с Rspamd и SOGo
Mailcow представляет собой оркестрированный стек из двух десятков Docker-контейнеров (Dovecot, Postfix, Rspamd, ClamAV, SOGo, Unbound, Nginx, MariaDB, Redis и сопутствующие сервисы). Развертывание такой связки требует строгого контроля за системными ресурсами хоста. Если почтовый сервер mailcow и nextcloud на vps запускаются на одном физическом или виртуальном сервере, малейшая нехватка оперативной памяти приведет к срабатыванию OOM Killer ядра Linux. В первую очередь под удар попадает процесс ClamAV (потребляющий от 1.2 до 1.5 ГБ RSS-памяти для базы сигнатур) либо база данных MariaDB, что вызывает каскадную деградацию почтового узла.
1. Подготовка хоста, Docker Engine и тюнинг подсистем ядра
Для стабильной работы стека требуется дистрибутив Linux с поддержкой cgroups v2 (Debian 12 или Ubuntu 24.04 LTS). Перед установкой пакетов необходимо скорректировать параметры подсистемы виртуальной памяти ядра через sysctl, чтобы Redis и СУБД не сталкивались с ошибками аллокации памяти при форках фонового сброса снапшотов на диск (bgsave):
cat << 'EOF' > /etc/sysctl.d/99-mailcow.conf
# Разрешение оверкоммита для Redis и MariaDB
vm.overcommit_memory = 1
# Предотвращение исчерпания таблиц дескрипторов соединений
net.core.somaxconn = 4096
net.ipv4.tcp_max_syn_backlog = 4096
# Поддержка полнотекстового поиска Dovecot FTS (Solr/Lucene, если включен)
vm.max_map_count = 262144
EOF
sysctl --system
Удалите устаревшие пакеты и установите официальный репозиторий Docker Engine. Использование штатных пакетов docker.io из репозиториев дистрибутива не рекомендуется из-за отставания версий Docker Compose v2:
apt-get update && apt-get remove -y docker docker-engine docker.io containerd runc
apt-get install -y ca-certificates curl gnupg lsb-release git
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/$(. /etc/os-release; echo "$ID")/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
chmod a+r /etc/apt/keyrings/docker.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/$(. /etc/os-release; echo "$ID") \
$(. /etc/os-release; echo "$VERSION_CODENAME") stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
apt-get update && apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Проверьте активность демона и версию плагина compose: docker compose version. Убедитесь, что метрика CPU Steal Time (%st в vmstat 1 или top) на гипервизоре хостера не превышает 3–5%. Если CPU перегружен «соседями», скачки latency p99 при проверке Rspamd milter-скриптов будут приводить к тайм-аутам соединений Postfix по директиве smtpd_milters.
2. Клонирование репозитория и запуск мастера конфигурации
Установка выполняется в системный каталог /opt. Репозиторий mailcow-dockerized содержит скрипты автогенерации окружения, файлы оверлеев и базовые манифесты compose.
umask 0022
cd /opt
git clone https://github.com/mailcow/mailcow-dockerized
cd mailcow-dockerized
Запустите интерактивный генератор базового окружения:
./generate_config.sh
В процессе выполнения скрипт запросит Fully Qualified Domain Name (FQDN). Укажите имя хоста, назначенное для почтового узла (например, mail.domain.tld). Скрипт сгенерирует криптографические ключи, пароли для внутренней базы данных MariaDB, секреты сессий и запишет файл mailcow.conf.
3. Тонкая настройка mailcow.conf для совместной работы с веб-сервисами
Поскольку на целевом хосте часто разворачивается не только почта, но и совмещенный стек веб-приложений (включая Nextcloud на Apache/PHP-FPM или Nginx), Mailcow не должен монопольно занимать публичные порты 0.0.0.0:80 и 0.0.0.0:443. Веб-интерфейс Mailcow и протоколы CalDAV/CardDAV/ActiveSync через SOGo должны перенаправляться на локальные петлевые порты (loopback interface), за которыми будет стоять внешний reverse-proxy.
Откройте mailcow.conf и внесите следующие корректировки:
# Домен почтового сервера
MAILCOW_HOSTNAME=mail.domain.tld
# Привязка HTTP/HTTPS к локальному интерфейсу на нестандартные порты
# Это исключает конфликты за порты 80/443 с фронтенд-прокси хоста
HTTP_PORT=8080
HTTP_BIND=127.0.0.1
HTTPS_PORT=8443
HTTPS_BIND=127.0.0.1
# Часовой пояс контейнеров
TZ=Europe/Moscow
# Ветка релизов (master - стабильная)
[email protected]
# Оптимизация оперативной памяти:
# Если на инстансе доступно менее 6 ГБ RAM, отключите ClamAV.
# Антивирусная проверка требует значительного объема RSS-памяти.
# Фильтрация спама через Rspamd (эвристики, DNSBL, Bayes, DKIM) продолжит работать штатно.
SKIP_CLAMAV=n
Если размер оперативной памяти на VPS жестко ограничен 4 ГБ, переведите SKIP_CLAMAV=y. В противном случае пиковая нагрузка при сканировании вложений крупного размера приведет к принудительному завершению контейнеров процессом ядра oom-reaper.
4. Инициализация контейнеров и валидация стека
Загрузите образы контейнеров и запустите инфраструктуру в фоновом режиме:
docker compose pull
docker compose up -d
Процесс первого старта инициализирует внутренние тома, миграции схемы MariaDB, генерирует самоподписанные сертификаты для внутреннего взаимодействия и запускает цепочку правил iptables в пространстве имен сетевого драйвера Mailcow (mailcowdockerized_mailcow-network).
Проверьте статус готовности всех контейнеров:
docker compose ps
Все компоненты (dovecot-mailcow, postfix-mailcow, rspamd-mailcow, sogo-mailcow, nginx-mailcow, unbound-mailcow) должны иметь статус Up (healthy). Если какой-либо сервис циклически перезапускается (Restarting), проверьте его stdout/stderr:
docker compose logs --tail=100 -f postfix-mailcow
docker compose logs --tail=100 -f dovecot-mailcow
Для проверки сетевого стека выполните диагностику привязки локальных портов через утилиту ss:
ss -tulpn | grep -E ':(25|465|587|993|995|8080|8443)'
Порты SMTP (25, 465, 587) и IMAP/POP3 (993, 995) должны слушаться демонами Postfix и Dovecot на интерфейсе 0.0.0.0, а порты 8080 и 8443 — исключительно на 127.0.0.1.
5. Первичная аутентификация, выпуск DKIM и создание ящиков
После завершения инициализации веб-интерфейс Mailcow доступен по адресу http://127.0.0.1:8080 (или через настроенный обратный прокси https://mail.domain.tld).
- Первый вход: Используйте стандартные реквизиты администратора:
- Пользователь:
admin - Пароль:
moohooСразу после входа перейдите в раздел Edit Administrator и смените дефолтный пароль на криптостойкий (от 20 символов). - Добавление почтового домена:
- Откройте вкладку Configuration → Mail Setup → Domains → нажмите Add domain.
- В поле Domain укажите корневой домен (например,
domain.tld). - Задайте лимиты дискового пространства (Default quota per mailbox) и максимальное количество почтовых ящиков.
- Убедитесь, что активны чекбоксы Enable SOGo и Force inbound DKIM verification. Нажмите Add domain and restart SOGo.
- Генерация ключей DKIM / ARC:
- Перейдите во вкладку Configuration → Mail Setup → ARC/DKIM keys.
- Проверьте наличие созданного ключа для добавленного домена. Если ключ не сгенерирован автоматически, выберите длину ключа 2048 bit, селектор
dkimи нажмите Add. - Скопируйте полученную открытую часть открытого ключа (начинается с
v=DKIM1; k=rsa; p=MIIB...). Данная строка предназначена для внесения в TXT-запись DNS-зоны (dkim._domainkey.domain.tld). - Создание почтового ящика:
- Перейдите в Configuration → Mail Setup → вкладка Mailboxes → кнопка Add mailbox.
- Задайте левую часть адреса (Username, например,
devops), выберите привязанный домен и установите персональную квоту хранилища (Maildir quota). - Сохраните конфигурацию. С этого момента ящик готов к приему и отправке корреспонденции через протоколы IMAP/Submission или веб-клиент SOGo (
https://mail.domain.tld/SOGo).
Развертывание корпоративного диска Nextcloud на том же сервере или выделенной ноде
Совместное размещение сервисов, когда почтовый сервер mailcow и nextcloud на vps делят единый пул вычислительных ресурсов, требует жесткого разграничения подсистем памяти и дискового ввода-вывода. Почтовый стек Mailcow с активными демонами ClamAV, Apache Solr и Dovecot утилизирует от 4 до 6 ГБ RAM в базовом состоянии. Добавление Nextcloud Enterprise-стека (PHP-FPM, PostgreSQL 16 и Redis) поднимает рабочий порог потребления до 10–12 ГБ RAM.
Если виртуальный сервер функционирует в условиях оверселлинга гипервизора KVM, где показатель CPU Steal Time (%st в выводе top или vmstat 1) превышает 3–5%, или лимит дисковых IOPS на блочном устройстве ограничен отметкой 1000–1500 операций, совместная нагрузка приведет к взаимной деградации сервисов. Неконтролируемый сброс dirty pages базы данных PostgreSQL и дисковые блокировки IMAP-индексов Dovecot вызовут рост latency p99 дисковой подсистемы свыше 800 мс. В критический момент ядро Linux активирует OOM Killer (out of memory: kill process), принудительно завершая clamd либо процессы баз данных.
Для инсталляций с числом активных пользователей свыше 25–30 человек рекомендуется вынос Nextcloud на выделенную ноду. Если развертывание выполняется на одном мощном VPS (минимум 8 vCPU, 16 ГБ ECC RAM, NVMe-накопитель), изоляция должна обеспечиваться механизмами cgroups v2 и строгим распределением сетевых сокетов: Mailcow удерживает внешние порты 80/443, проксируя вызовы к виртуальному хосту Nextcloud через внутренний upstream.
Архитектурный стек Docker Compose: Nextcloud + PostgreSQL 16 + Redis
Связка строится на официальном FPM-образе Nextcloud под управлением Nginx/Caddy в роли фронтенда, транзакционной СУБД PostgreSQL 16 и Redis в роли брокера распределенных блокировок (transactional file locking).
Создайте рабочую директорию и структуру каталогов:
mkdir -p /opt/nextcloud/{html,db,redis,config}
cd /opt/nextcloud
Листинг docker-compose.yml с жестким ограничением ресурсов через спецификацию deploy.resources:
version: '3.8'
networks:
nextcloud-net:
driver: bridge
ipam:
config:
- subnet: 172.28.0.0/24
# Если Nextcloud на одном сервере с Mailcow, подключаем внешнюю сеть mailcow-dockerized_mailcow-network
mailcow-bridge:
external: false
services:
db:
image: postgres:16-alpine
container_name: nextcloud-db
restart: always
volumes:
- /opt/nextcloud/db:/var/lib/postgresql/data
environment:
POSTGRES_DB: nextcloud
POSTGRES_USER: nc_user
POSTGRES_PASSWORD: StrongPostgresPassword123!
command: >
postgres
-c shared_buffers=1024MB
-c effective_cache_size=3072MB
-c maintenance_work_mem=256MB
-c checkpoint_completion_target=0.9
-c wal_buffers=16MB
-c default_statistics_target=100
-c random_page_cost=1.1
-c work_mem=16MB
-c min_wal_size=1GB
-c max_wal_size=4GB
-c max_connections=120
deploy:
resources:
limits:
memory: 3072M
networks:
- nextcloud-net
redis:
image: redis:7.2-alpine
container_name: nextcloud-redis
restart: always
command: >
redis-server
--requirepass StrongRedisPassword123!
--maxmemory 512mb
--maxmemory-policy volatile-lru
--save ""
--appendonly no
volumes:
- /opt/nextcloud/redis:/data
deploy:
resources:
limits:
memory: 768M
networks:
- nextcloud-net
app:
image: nextcloud:29-fpm-alpine
container_name: nextcloud-app
restart: always
depends_on:
- db
- redis
volumes:
- /opt/nextcloud/html:/var/www/html
- /opt/nextcloud/config:/var/www/html/config
- /mnt/storage/data:/var/www/html/data
environment:
POSTGRES_HOST: db
POSTGRES_DB: nextcloud
POSTGRES_USER: nc_user
POSTGRES_PASSWORD: StrongPostgresPassword123!
REDIS_HOST: redis
REDIS_HOST_PASSWORD: StrongRedisPassword123!
PHP_MEMORY_LIMIT: 2048M
PHP_UPLOAD_LIMIT: 16G
deploy:
resources:
limits:
memory: 4096M
networks:
- nextcloud-net
cron:
image: nextcloud:29-fpm-alpine
container_name: nextcloud-cron
restart: always
volumes:
- /opt/nextcloud/html:/var/www/html
- /opt/nextcloud/config:/var/www/html/config
- /mnt/storage/data:/var/www/html/data
entrypoint: /cron.sh
depends_on:
- app
networks:
- nextcloud-net
Тюнинг системных параметров ядра и памяти PHP
Nextcloud в процессе обработки тяжелых синхронизаций генерирует всплески системных вызовов mmap и операций с файловыми дескрипторами. На хосте задаются лимиты в /etc/sysctl.d/99-nextcloud.conf:
# Устранение предупреждения Redis о фоновой перезаписи памяти без OOM-ошибки
vm.overcommit_memory = 1
# Расширение очереди подключений TCP сокетов для сетевого стека PHP-FPM
net.core.somaxconn = 2048
# Увеличение лимита inotify во избежание сбоев демонов индексации
fs.inotify.max_user_watches = 524288
fs.file-max = 2097152
Примените изменения без перезагрузки:
sysctl -p /etc/sysctl.d/99-nextcloud.conf
Для PHP-FPM пула критично предотвратить исчерпание воркеров при медленных клиентах. В смонтированном каталоге создается файл переопределения /opt/nextcloud/html/custom-php.ini:
memory_limit = 2048M
upload_max_filesize = 16G
post_max_size = 16G
max_execution_time = 3600
max_input_time = 3600
; OPcache production settings
opcache.enable=1
opcache.interned_strings_buffer=32
opcache.max_accelerated_files=10000
opcache.memory_consumption=256
opcache.save_comments=1
opcache.revalidate_freq=60
opcache.validate_timestamps=0
В пуле менеджера процессов www.conf задаются жесткие рамки динамического масштабирования:
pm = dynamic
pm.max_children = 64
pm.start_servers = 16
pm.min_spare_servers = 8
pm.max_spare_servers = 24
pm.max_requests = 1000
Настройка кэширования и распределенных блокировок в Redis
Отказ от Redis или попытка использовать механизм блокировок на базе штатной таблицы СУБД (oc_file_locks) приводит к деградации PostgreSQL при параллельной синхронизации каталогов с тысячами мелких файлов. В config.php активируются пулы распределенной памяти и блокировок:
'memcache.local' => '\OC\Memcache\APCu',
'memcache.distributed' => '\OC\Memcache\Redis',
'memcache.locking' => '\OC\Memcache\Redis',
'redis' => [
'host' => 'redis',
'port' => 6379,
'password' => 'StrongRedisPassword123!',
'timeout' => 1.5,
],
'filelocking.enabled' => true,
'filelocking.ttl' => 3600,
Проверка статуса блокировок в Redis выполняется из терминала:
docker exec -it nextcloud-redis redis-cli -a StrongRedisPassword123! info stats
Интеграция дисковых массивов и S3 Object Storage
При использовании локального блочного хранилища файловая система должна монтироваться с опциями, исключающими обновление метаданных доступа при чтении. Запись в /etc/fstab:
UUID=xxxx-xxxx-xxxx /mnt/storage ext4 noatime,nodiratime,data=writeback,barrier=0,nobh 0 2
Если локальный VPS ограничен по объему NVMe, масштабирование выполняется подключением совместимого с AWS S3 объектного хранилища (MinIO, Ceph RadosGW, Wasabi) в качестве Primary Storage. Это разгружает локальный диск от бинарных объектов, оставляя на сервере только базу метаданных, кэш превью и сессии.
Для активации S3 как основного хранилища в /opt/nextcloud/config/storage.config.php прописывается конфигурация:
<?php
$CONFIG = [
'objectstore' => [
'class' => '\\OC\\Files\\ObjectStore\\S3',
'arguments' => [
'bucket' => 'corp-nextcloud-data',
'autocreate' => false,
'key' => 'S3_ACCESS_KEY_IDENTIFIER',
'secret' => 'S3_SECRET_ACCESS_KEY_VALUE',
'hostname' => 's3.eu-central-1.provider.com',
'port' => 443,
'use_ssl' => true,
'region' => 'eu-central-1',
'use_path_style' => false,
],
],
];
При первичном переходе на S3 база данных берет на себя сопоставление путей urn:oid:... к объектам хранилища, что полностью нивелирует проблему исчерпания inode на локальной файловой системе Linux при размещении сотен тысяч мелких документов.
Интеграция Nextcloud и Mailcow: единое офисное пространство
Разворачивая почтовый сервер mailcow и nextcloud на vps в рамках единого хоста или приватного кластера, архитектурно нецелесообразно изолировать их в раздельные пользовательские интерфейсы. Mailcow берет на себя роль headless-ядра коммуникаций (MTA Postfix, MDA Dovecot, фильтрация спама через Rspamd и антивирус ClamAV), а Nextcloud выступает единой точкой входа (Front-end Groupware) для работы с корреспонденцией, корпоративными календарями встреч и адресными книгами.
Такая связка исключает дублирование веб-интерфейсов (тяжелый SOGo в составе Mailcow можно перевести в минимальный режим или отключить для экономии RAM) и обеспечивает сквозную синхронизацию данных на рабочие станции и мобильные устройства сотрудников.
1. Сетевая связность и конфигурация Nextcloud Mail
Прямое обращение Nextcloud к внешнему FQDN Mailcow через публичный IP-адрес порождает hairpinning NAT, лишние накладные расходы на повторное TLS-рукопожатие внутри одного сервера и риски блокировок со стороны fail2ban (Netfilter-контейнера Mailcow) при всплесках IMAP-аутентификации.
Оптимальное решение — объединение контейнеров в общую Docker-сеть типа bridge:
# Подключение контейнера Nextcloud к внутренней сети Mailcow
docker network connect mailcowdockerized_mailcow-network nextcloud-app
Внутри общей сети Dovecot доступен напрямую по сервисному имени dovecot-mailcow (порт 143 для STARTTLS или 993 для TLS/SSL), а Postfix — по имени postfix-mailcow (порт 587).
Для автоматического развертывания почтовых ящиков у пользователей исключите ручной ввод параметров через веб-интерфейс. Конфигурация приложения mail задается на уровне ядра Nextcloud через утилиту occ:
# Включение и принудительная предконфигурация Nextcloud Mail
docker exec -u www-data nextcloud-app php occ app:enable mail
# Установка глобальных параметров почтового сервера
docker exec -u www-data nextcloud-app php occ config:app:set mail imap-server --value="dovecot-mailcow"
docker exec -u www-data nextcloud-app php occ config:app:set mail imap-port --value="993"
docker exec -u www-data nextcloud-app php occ config:app:set mail imap-ssl-mode --value="ssl"
docker exec -u www-data nextcloud-app php occ config:app:set mail smtp-server --value="postfix-mailcow"
docker exec -u www-data nextcloud-app php occ config:app:set mail smtp-port --value="587"
docker exec -u www-data nextcloud-app php occ config:app:set mail smtp-ssl-mode --value="tls"
При совмещении аккаунтов через общий LDAP/Active Directory или протокол OAuth2 пользователь при первом входе в Nextcloud получает автоматически инициализированный почтовый ящик без запроса паролей к Dovecot.
Чтобы Dovecot не обрывал соединения Nextcloud при массовой проверке папок несколькими воркерами PHP-FPM, скорректируйте лимит одновременных сессий с одного IP в data/conf/dovecot/extra.conf со стороны Mailcow:
mail_max_userip_connections = 50
remote 172.22.1.0/24 {
mail_max_userip_connections = 200
}
2. Маршрутизация CalDAV/CardDAV и Service Discovery в Nginx
Синхронизация календарей и контактов выполняется движком SabreDAV, встроенным в Nextcloud. Для корректной работы мобильных клиентов критически важно настроить механизм Service Discovery на внешнем обратном прокси (Nginx), иначе клиенты завершат поиск эндпоинтов с ошибкой 404/405.
Стандарты RFC 6764 и спецификации Apple требуют перенаправления запросов .well-known на точки входа WebDAV:
# Конфигурация Nginx Reverse Proxy для Nextcloud
server {
server_name cloud.company.ltd;
listen 443 ssl http2;
# Service Discovery для CalDAV и CardDAV
location = /.well-known/carddav {
return 301 https://$host/remote.php/dav/;
}
location = /.well-known/caldav {
return 301 https://$host/remote.php/dav/;
}
# Проксирование трафика в контейнер Nextcloud
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Увеличение таймаутов для длительных PROPFIND/REPORT запросов
proxy_read_timeout 1800s;
proxy_send_timeout 1800s;
proxy_buffers 64 4k;
}
}
3. Интеграция с клиентскими устройствами (iOS / Android)
iOS / iPadOS / macOS
Операционные системы Apple поддерживают CalDAV и CardDAV нативно без стороннего ПО. Благодаря корректным редиректам .well-known, настройка сводится к добавлению единой учетной записи: 1. Перейдите в Настройки → Календарь (или Контакты) → Учетные записи → Добавить учетную запись → Другое. 2. Выберите Учетная запись CalDAV (или CardDAV). 3. В поле Сервер достаточно указать базовый домен: cloud.company.ltd. 4. В полях Пользователь и Пароль необходимо использовать не основной системный пароль, а сгенерированный в профиле Nextcloud App Password (Пароль приложения). Это защищает основную сессию при компрометации смартфона и обходит ограничения Two-Factor Authentication (2FA).
Для парка корпоративных устройств целесообразно выгружать профиль конфигурации .mobileconfig через MDM-систему (SimpleMDM, Apple Configurator), где параметры CalDAV/CardDAV прописываются в XML-структуре com.apple.caldav.account.
Android
Платформа Android не имеет встроенного стека WebDAV на уровне ОС. Стандартом для промышленной эксплуатации является открытый клиент DAVx⁵: 1. Приложение устанавливается из Google Play или репозитория F-Droid. 2. Авторизация настраивается через опцию Вход по URL и имени пользователя: * Базовый URL: https://cloud.company.ltd/remote.php/dav/ * Логин и сгенерированный App Password. 3. DAVx⁵ вычитывает адресные книги и календари по протоколу WebDAV Sync (RFC 6578), регистрирует их в системных провайдерах Android (android.provider.ContactsContract и android.provider.CalendarContract), после чего встречи отображаются в любом стандартном календаре смартфона. 4. В настройках энергосбережения Android для DAVx⁵ отключается оптимизация аккумулятора (Doze Mode), иначе периодическая синхронизация будет замораживаться системой при выключенном экране.
4. Тюнинг производительности ядра и runtime под синхронизацию
Протоколы CalDAV/CardDAV генерируют специфическую нагрузку: большое количество мелких HTTP-запросов методами PROPFIND, REPORT, PROPPATCH. Если 50 сотрудников одновременно открывают мобильные клиенты в начале рабочего дня, сервер сталкивается со штормом соединений.
Отказ от AJAX в пользу системного демона Nextcloud
По умолчанию фоновые задачи Nextcloud (включая проверку почты Mail и индексацию изменений в календарях) запускаются в режиме AJAX при посещении страниц пользователями. Переведите фоновые процессы на системный таймер Linux (systemd):
# Проверка и установка режима Cron в Nextcloud
docker exec -u www-data nextcloud-app php occ background:cron
Создайте юнит systemd на хосте (/etc/systemd/system/nextcloud-cron.service):
[Unit]
Description=Nextcloud background jobs runner
After=docker.service
[Service]
Type=oneshot
ExecStart=/usr/bin/docker exec -u www-data nextcloud-app php -f /var/www/html/cron.php
И таймер (/etc/systemd/system/nextcloud-cron.timer) с интервалом в 5 минут:
[Unit]
Description=Run Nextcloud cron every 5 minutes
[Timer]
OnBootSec=2min
OnUnitActiveSec=5min
[Install]
WantedBy=timers.target
systemctl daemon-reload && systemctl enable --now nextcloud-cron.timer
Транзакционная блокировка в памяти (Redis)
Вычисление повторяющихся событий календаря (Recurrence Rules, RRULE) в CalDAV создает паразитные блокировки в базе данных (MariaDB/PostgreSQL). Обязательно выносите управление распределенными локами в Redis. В конфигурационном файле config/config.php Nextcloud:
'memcache.local' => '\OC\Memcache\APCu',
'memcache.distributed' => '\OC\Memcache\Redis',
'memcache.locking' => '\OC\Memcache\Redis',
'redis' => [
'host' => 'redis-mailcow', // или локальный контейнер Redis
'port' => 6379,
'timeout' => 1.5,
],
Параметры ядра Linux (sysctl)
Для стабильной обработки сотен параллельных TLS-соединений на VPS без переполнения очередей сокетов внесите правки в /etc/sysctl.d/99-dav-latency.conf:
# Увеличение длины очереди соединений
net.core.somaxconn = 4096
net.ipv4.tcp_max_syn_backlog = 8192
# Быстрая утилизация сокетов в состоянии TIME_WAIT
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15
# Буферизация TCP-пакетов
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
Примените параметры: sysctl --system.
Мониторинг узких мест
Контролируйте задержки I/O и состояние контейнеров: * Метрика p99 latency: Запросы REPORT и PROPFIND в Nginx-логах не должны превышать 120–150 мс. Всплески свыше 500 мс сигнализируют о нехватке памяти PHP-FPM (pm.max_children) или отсутствии индексов в таблицах oc_calendarobjects / oc_cards. * CPU Steal Time (%st): Запустите vmstat 1 или mpstat -P ALL 1. Если на виртуальном сервере %st превышает 3–5%, гипервизор урезает циклы vCPU. В таких условиях тайм-ауты IMAP IDLE в Nextcloud Mail и фоновый опрос DAV неизбежно приводят к сбросу TCP-сессий на мобильных устройствах. * Изоляция cgroups v2: Ограничьте память воркеров Nextcloud, чтобы внезапный синк тяжелых почтовых вложений через встроенный клиент не активировал Linux OOM Killer против демонов базы данных или Postfix:
# Пример ограничения ресурсов для сервиса в docker-compose.override.yml
services:
nextcloud-app:
deploy:
resources:
limits:
memory: 2048M
reservations:
memory: 512M
Правильная связка внутренних сетей и тюнинг очередей SabreDAV обеспечивают бесшовную работу сотрудников: мобильные календари обновляются мгновенно через push-нотификации и дельты WebDAV Sync, а почтовый веб-клиент Nextcloud взаимодействует с Mailcow без лишних сетевых трансформаций и задержек.
Безопасность и отказоустойчивость: защита от перебора паролей и бэкапы
Эксплуатация связки почтовый сервер mailcow и nextcloud на vps в открытом интернете неизбежно сталкивается с двумя векторами деградации: круглосуточным распределенным брутфорсом портов аутентификации (Submission 587, IMAP 993, Web UI) и риском аппаратной потери блочного устройства хостера. Безопасность стека требует изоляции сетевого трафика на уровне ядра Linux и детерминированного процесса консистентной репликации данных в изолированное холодное хранилище.
Встроенный Fail2ban и Netfilter: подавление распределенного брутфорса
В архитектуре Mailcow защита от подбора паролей вынесена в специализированный контейнер netfilter-mailcow. В отличие от классического демона fail2ban, работающего через парсинг файлов на хосте, контейнер слушает стрим логов аутентификации Postfix, Dovecot и SOGo через Redis-паблишер (redis-mailcow) и напрямую взаимодействует с подсистемой Netfilter ядра хоста.
Для применения правил контейнеру требуются Linux capabilities CAP_NET_ADMIN и CAP_NET_RAW. Netfilter создает в таблице filter хоста выделенные цепочки MAILCOW, перехватывая пакеты до их попадания в стандартные цепочки Docker DNAT (PREROUTING).
Проблема подмены Source IP в Docker Bridge
При развертывании за внешним reverse proxy (Nginx, HAProxy, Traefik) или некорректной настройке Docker userland-proxy реальный IP-адрес атакующего маскируется IP-шлюзом моста (обычно 172.22.1.1). Если Netfilter заблокирует этот адрес, изолируются все внутренние сервисы Mailcow и Nextcloud.
Для сохранения исходного IP клиента в mailcow.conf и конфигурации демона Docker обязательно проверяется трансляция адресов:
# Проверка сохранения клиентского IP в цепочках iptables хоста
iptables -t nat -L POSTROUTING -n -v | grep -E "172.22.1.0/24|MASQUERADE"
В /opt/mailcow-dockerized/mailcow.conf задаются жесткие лимиты срабатывания. Для борьбы с ротационными ботнетами, распределяющими попытки перебора по подсетям /24, включается агрессивная маска блокировки:
# /opt/mailcow-dockerized/mailcow.conf
# Период блокировки в секундах (86400 = 24 часа)
FAIL2BAN_BAN_TIME=86400
# Окно анализа попыток (600 секунд = 10 минут)
FAIL2BAN_FIND_TIME=600
# Количество неудачных попыток до триггера
FAIL2BAN_MAX_ATTEMPTS=3
# Агрессивная блокировка: при бане одного IP изолируется вся подсеть класса C
FAIL2BAN_NETMASK_IPV4=24
FAIL2BAN_NETMASK_IPV6=64
При интенсивных атаках сотни ботов способны исчерпать таблицу отслеживания соединений conntrack ядра хоста, вызывая дропы легитимных сессий (kernel: nf_conntrack: table full, dropping packet). Значение параметра поднимается через sysctl:
# /etc/sysctl.d/99-security.conf
net.netfilter.nf_conntrack_max = 1048576
net.netfilter.nf_conntrack_tcp_timeout_syn_recv = 30
net.netfilter.nf_conntrack_tcp_timeout_established = 600
Применение: sysctl -p /etc/sysctl.d/99-security.conf.
Управление заблокированными хостами и аудит очередей выполняются непосредственно через контейнер Netfilter:
# Просмотр активных блокировок в цепи MAILCOW
docker compose exec netfilter-mailcow iptables -L MAILCOW -n -v --line-numbers
# Ручная принудительная разблокировка ошибочно забаненного IP инженера
docker compose exec netfilter-mailcow fail2ban-client set mailcow-auth unbanip 203.0.113.42
Двухфакторная аутентификация: WebAuthn, TOTP и пароли приложений
Аутентификация по связке логин-пароль не защищает инфраструктуру от компрометации через фишинг и уязвимости рабочих станций сотрудников. Реализация 2FA в связке Mailcow и Nextcloud разделяется на два контура: Web-интерфейс и почтовые протоколы синхронизации.
WebAuthn (FIDO2) против TOTP
Для входа в панель администрирования Mailcow и почтовый клиент SOGo приоритетом является аппаратный стандарт WebAuthn (FIDO2/YubiKey). Криптографическая привязка открытого ключа к конкретному доменному имени Origin делает бесполезными MITM-прокси (например, Evilginx2): браузер передает открытый ключ только тому домену, который указан в SSL-сертификате.
Второй эшелон защиты — программные генераторы TOTP (RFC 6238, SHA-1/SHA-256, 30-секундный шаг). Активация выполняется в свойствах почтового ящика через административную панель (Почтовые ящики -> Редактировать -> Двухфакторная аутентификация).
Проблема легаси-протоколов (IMAP/SMTP) и App Passwords
Протоколы RFC 3501 (IMAP4rev1) и RFC 5321 (SMTP) исторически не поддерживают интерактивный ввод второго фактора. Включение 2FA на основном аккаунте блокирует прямую авторизацию в почтовых клиентах (Thunderbird, Apple Mail, Outlook), если не используется громоздкий механизм SASL XOAUTH2.
Решение — выпуск изоляционных паролей приложений (App Passwords) с гранулярными правами: 1. Основной мастер-пароль защищен FIDO2/TOTP и используется исключительно для входа в веб-интерфейс SOGo/Nextcloud. 2. Для каждого клиентского устройства генерируется псевдослучайный токен длиной 32 символа. 3. В базе данных mailcowdockerized_mysql-vol-1 токен хэшируется алгоритмом SHA512-CRYPT (5000 раундов) и сопоставляется разрешенным протоколам (например: доступ только к IMAP без права отправки по SMTP). В случае компрометации телефона отозвать токен можно в один клик без смены основного пароля учетной записи.
Автоматическое резервное копирование почты и баз данных в холодное хранилище
Резервное копирование почтового хранилища нельзя сводить к простому запуску rsync на живой директории /var/lib/docker/volumes/mailcowdockerized_vmail-vol-1/_data. Если Dovecot в процессе копирования изменит состояние папок (например, переместит сообщение из new в cur или выполнит EXPUNGE), итоговый снимок окажется битым (inconsistent state), а индексы dovecot.index и dovecot.index.cache будут повреждены.
Для консистентного создания снепшота используется штатный оркестратор бэкапов Mailcow с последующей передачей зашифрованных дедуплицированных чанков в холодное S3-совместимое объектное хранилище через BorgBackup.
Создание production-скрипта резервного копирования
Скрипт выполняет сброс буферов баз данных MariaDB/Redis, блокирует состояние почтовых ящиков через Dovecot, упаковывает данные алгоритмом zstd и передает в удаленный репозиторий с ограничением I/O нагрузки (чтобы p99 latency дисковых операций Dovecot не превышало 15 мс во время работы бэкапа):
#!/usr/bin/env bash
# /opt/scripts/mailcow_cold_backup.sh
set -Eeuo pipefail
export BORG_REPO="ssh://[email protected]:23/./mailcow_borg"
export BORG_PASSPHRASE="GENERATE_A_STRONG_RANDOM_PASSPHRASE_HERE"
BACKUP_DIR="/opt/backup/mailcow_temp"
MAILCOW_DIR="/opt/mailcow-dockerized"
LOG_FILE="/var/log/mailcow_backup.log"
exec >> "${LOG_FILE}" 2>&1
echo "[$(date -u +'%Y-%m-%dT%H:%M:%SZ')] Starting automated cold backup pipeline..."
# Очистка предыдущих временных дампов
rm -rf "${BACKUP_DIR}" && mkdir -p "${BACKUP_DIR}"
# 1. Фиксация консистентного состояния баз и Dovecot через встроенный helper
# Переменные окружения подавляют диалоговые окна
cd "${MAILCOW_DIR}"
BACKUP_LOCATION="${BACKUP_DIR}" \
DATE=now \
THRESHOLD_DAYS=0 \
helper-scripts/backup_and_restore.sh backup all --delete-days 0
# 2. Ограничение дискового I/O (ionice) и CPU (nice) для исключения просадок почтового демона
# Выполняется передача во внешнее зашифрованное хранилище с дедупликацией
ionice -c2 -n7 nice -n 19 borg create \
--verbose \
--stats \
--compression zstd,6 \
--exclude-caches \
"${BORG_REPO}::mailcow-{now:%Y-%m-%d_%H%M%S}" \
"${BACKUP_DIR}" \
"${MAILCOW_DIR}/mailcow.conf"
# 3. Политика ротации (Pruning): сохраняем 7 ежедневных, 4 еженедельных, 6 ежемесячных снимков
borg prune \
--list \
--keep-daily 7 \
--keep-weekly 4 \
--keep-monthly 6 \
"${BORG_REPO}"
# 4. Удаление локального временного дампа
rm -rf "${BACKUP_DIR}"
echo "[$(date -u +'%Y-%m-%dT%H:%M:%SZ')] Backup successfully encrypted, synced and rotated."
Автоматизация запуска через systemd timer
Использование классического cron не позволяет надежно изолировать ресурсы и отслеживать OOM Killer. Контроль выполнения делегируется systemd:
Файл юнита сервиса:
# /etc/systemd/system/mailcow-backup.service
[Unit]
Description=Mailcow Cold Storage Backup Service
After=docker.service network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/opt/scripts/mailcow_cold_backup.sh
# Ограничение потребления ресурсов через cgroups
CPUWeight=20
IOWeight=20
MemoryMax=1.5G
StandardOutput=journal
StandardError=journal
Файл таймера:
# /etc/systemd/system/mailcow-backup.timer
[Unit]
Description=Run Mailcow Cold Storage Backup nightly at 03:00 UTC
[Timer]
OnCalendar=*-*-* 03:00:00 UTC
RandomizedDelaySec=600
Persistent=true
[Install]
WantedBy=timers.target
Активация расписания:
chmod 700 /opt/scripts/mailcow_cold_backup.sh
systemctl daemon-reload
systemctl enable --now mailcow-backup.timer
systemctl list-timers --all | grep mailcow-backup
Использование задержки RandomizedDelaySec=600 размывает пиковую нагрузку на канал и дисковые массивы хранилища при наличии нескольких обслуживаемых серверов, гарантируя предсказуемость дискового ввода-вывода хоста.
Часто задаваемые вопросы (FAQ)
Сколько оперативной памяти требуется для Mailcow?
Минимум 4 GB RAM. Если включен антивирусный сканер ClamAV (потребляет 1.5–2 GB RAM), рекомендуется сервер с 6–8 GB RAM.
Что делать, если хостер блокирует исходящий порт 25?
Напишите в тикеты хостера запрос на открытие 25 порта, указав домен и подтвердив соблюдение антиспам-политики. Если хостер отказывает — используйте SMTP Relay (например, SendGrid, Postmark) либо смените хостинг.
Попадут ли письма на Gmail и Mail.ru без попадания в спам?
При наличии чистой подсети IP, корректной PTR-записи, валидных записей SPF, DKIM и DMARC письма получают оценку 10/10 на mail-tester и доставляются во входящие.
Как восстановить почту при аварии сервера?
Mailcow содержит встроенный скрипт backup_and_restore.sh, позволяющий восстановить полную конфигурацию, базы и письма одной командой на новом сервере.