DevOps и Резервирование 19 мин чтения 2026-10-23

Почтовый сервер Stalwart на Rust вместо связки Postfix и Dovecot: развертывание на VDS в Docker Compose с авто-DKIM, ACME и JMAP

Практический разбор развертывания Stalwart Mail Server на VDS в Docker Compose: архитектура v0.16 с единым config.json и JMAP-объектами, встроенный ACME вместо Certbot, автоматические DKIM-ключи, безопасный бэкап томов и чек-лист защиты домена от подделки писем.

Инженерная редакция SysKit Проверено инженерами SysKit.ru

Классическая почта на Linux десятилетиями собирается из конструктора: MTA Postfix принимает и маршрутизирует письма, Dovecot раскладывает их по ящикам по протоколам IMAP и POP3, OpenDKIM подписывает исходящий трафик, Rspamd и SpamAssassin фильтруют входящий спам, OpenLDAP или SQL хранят учётные записи, а связка из Certbot, Postfix-карт сертификатов и десятка конфигурационных файлов удерживает всё это вместе. Каждый демон обновляется отдельно, каждый имеет собственный синтаксис ошибок, и любое расхождение между ними превращается в письма, которые «уходят, но не доходят». Stalwart Mail Server предлагает иную инженерную модель: единый исполняемый файл, написанный на Rust, который одновременно является SMTP-, IMAP-, JMAP- и CalDAV/CardDAV-сервером, содержит встроенный веб-интерфейс администратора и автоматически управляет DKIM-ключами и TLS-сертификатами. В этом разборе мы развернём его на VDS в Docker Compose, разберём архитектурные изменения версии v0.16 и настроим защиту домена от подделки писем.

1. Почему связка Postfix и Dovecot требует слишком много внимания

Проблема классического почтового стека не в том, что он плохо работает: Postfix и Dovecot остаются промышленным стандартом и обслуживают миллионы доменов. Проблема в стоимости владения для команды из одного-двух человек:

  • Шесть и более независимых демонов. Postfix, Dovecot, OpenDKIM, Rspamd, ClamAV, Redis и Certbot обновляются по отдельности. Обновление одного компонента ломает совместимость с другим, а откат требует помнить последовательность версий.
  • Разрозненная конфигурация. Параметры ящиков живут в SQL или LDAP, параметры маршрутизации — в main.cf, параметры хранения — в dovecot.conf, DKIM-ключи — в файлах на диске, а сертификаты — в третьем месте. Единой точки правды нет.
  • Ручная синхронизация DKIM и TLS. Ротация ключей подписи и продление сертификатов требуют перезапуска нескольких служб в правильном порядке, иначе часть писем уходит без подписи или с просроченным сертификатом.
  • Отсутствие современного API. Управление ящиками возможно только через файлы или SQL-запросы. Автоматизировать выдачу почты новому сотруднику из CRM или панели поддержки без самописных скриптов практически невозможно.
Критерий Классический стек (Postfix + Dovecot + OpenDKIM) Stalwart v0.16.27
Компоненты 6–8 демонов и пакетов Один бинарник и один контейнер
Конфигурация Файлы в разных каталогах + SQL/LDAP Один config.json + настройки в БД как JMAP-объекты
Управление Правка файлов и SQL-запросы Веб-интерфейс, CLI и JMAP API
DKIM Ручная генерация и ротация ключей Автогенерация, ротация и публикация в DNS
TLS и ACME Certbot + hooks перезапуска служб Встроенный ACME: TLS-ALPN-01, HTTP-01, DNS-01
Современные протоколы IMAP4rev1, POP3, SMTP JMAP, IMAP4rev2, POP3, ManageSieve, CalDAV, CardDAV, WebDAV

2. Что представляет собой Stalwart и какие протоколы он закрывает

Проект stalwartlabs/stalwart распространяется по лицензии AGPL-3.0-only (расширенные корпоративные функции вынесены в отдельную коммерческую лицензию LicenseRef-SEL) и на момент публикации статьи имеет более 15 000 звёзд на GitHub. Сервер написан на Rust и собирается в один статически связанный исполняемый файл.

Поддерживаемый набор протоколов закрывает практически все задачи корпоративной почты и групповой работы:

  • Почта и отправка: SMTP с поддержкой STARTTLS и implicit TLS, а также JMAP for Mail по спецификации RFC 8621 — современному JSON-протоколу, который заменяет IMAP в веб-клиентах.
  • Доступ к ящикам: IMAP4rev2 (RFC 9051) и IMAP4rev1 (RFC 3501), POP3 (RFC 1939) с расширением STLS.
  • Фильтрация на сервере: ManageSieve (RFC 5804) позволяет пользователю раскладывать письма по папкам правилами прямо на сервере, без клиента.
  • Календари, контакты и файлы: CalDAV, CardDAV и WebDAV — то есть корпоративный календарь и адресная книга работают из коробки, без Nextcloud.
  • Современные расширения JMAP: WebSocket-поток уведомлений (RFC 8887), управление вложениями Blob Management (RFC 9404) и квоты Quotas (RFC 9425).

💡 Совет инженера: зачем в почте JMAP

JMAP передаёт состояние ящика одним JSON-запросом вместо последовательности IMAP-команд и поддерживает push-уведомления через WebSocket. Для веб-клиента это означает мгновенное появление новых писем без опроса сервера каждые 30 секунд, а для мобильных приложений — заметно меньший расход трафика и батареи.

3. Архитектура версии v0.16: один файл конфигурации и JMAP-объекты в базе

Перед развертыванием необходимо понять главное архитектурное изменение, которое произошло в ветке v0.16. Оно ломает совместимость со всеми предыдущими версиями, и на нём спотыкаются администраторы, привыкшие к конфигурации v0.15.

В старых версиях сервер читал один или несколько TOML-файлов, причём часть настроек лежала на диске, а часть — в базе данных. Такая двойственность порождала реальные проблемы: в кластере каждый узел обязан был хранить собственную копию конфигурационного файла, и расхождение между копиями было легко внести, но почти невозможно отладить.

Начиная с v0.16 на диске лежит единственный компактный файл config.json, который описывает только хранилище данных (datastore) — то есть ту базу, в которой сервер держит всё остальное. Домены, учётные записи, правила маршрутизации, DKIM-подписи, бэкенды хранения, лимиты и антиспам-правила теперь хранятся внутри этого хранилища как JMAP-объекты. Управление ими идёт через JMAP management API, а веб-интерфейс и официальный CLI — это просто клиенты этого API.

Область Версии до v0.16 Версия v0.16.x
Формат конфигурации TOML, несколько файлов Один config.json (только datastore)
Где живут настройки Часть в файлах, часть в БД Полностью в БД как JMAP-объекты
API управления REST JMAP management API
Данные пользователей БД и блобы Без изменений в раскладке БД
Кластер Синхронизация файлов вручную Единая конфигурация по определению

⚠️ Важное предупреждение: миграция с v0.15 и ниже

Переход с v0.15.x на v0.16.x требует многошаговой процедуры: сначала сервер поднимают в режиме восстановления (recovery mode), затем официальным CLI проигрывают экспорт настроек и только после этого переключают службу на новый config.json. Данные пользователей — письма, календари, контакты и файлы — при этом остаются на месте, меняется только слой управления. Официальный порядок шагов описан в UPGRADING/v0_16.md репозитория, и пропускать их нельзя. В этой статье мы ставим сервер с нуля, поэтому процедура миграции не требуется.

4. Требования к VDS, порты и критичная проверка процессора

Почтовый сервер предъявляет к инфраструктуре требования, которых нет у обычного веб-проекта. Разберём их по порядку, начиная с самого коварного.

Проверка набора инструкций процессора (x86-64-v2)

Начиная с релиза v0.16.26 официальные x86_64-сборки и Docker-образы Stalwart требуют процессор с набором инструкций x86-64-v2, который включает SSE3, SSSE3, SSE4.1, SSE4.2 и POPCNT. На более старых процессорах сервер отказывается запускаться. Проблема в том, что виртуальные машины с обобщённой моделью процессора, например QEMU с типом «Common KVM processor», этот набор не предоставляют — контейнер запустится и сразу завершится с ошибкой.

Есть два способа решения. Первый — переключить тип процессора виртуальной машины на host или x86-64-v2-AES (в Proxmox это делается в настройках ВМ). Второй — использовать musl-сборку: Docker-теги с суффиксом -alpine, например stalwartlabs/stalwart:v0.16-alpine. Проверить поддерживаемые флаги на сервере можно одной командой:

# Проверка наличия инструкций x86-64-v2 (sse4_2 и popcnt обязательны)
grep -o -m1 -E 'sse4_2|ssse3|sse3' /proc/cpuinfo | sort -u
grep -m1 -o 'popcnt' /proc/cpuinfo

Если обе команды вернули значения — стандартный образ подойдёт. Если нет — берите -alpine, иначе контейнер будет перезапускаться по кругу без внятной ошибки в docker compose logs.

Сетевые порты почтового сервера

Порт Протокол Назначение и доступ
25 SMTP Приём писем от других серверов. Обязателен публично
465 SMTP over TLS Отправка из почтовых клиентов (implicit TLS)
587 SMTP Submission Отправка с аутентификацией (STARTTLS)
993 IMAPS Чтение почты клиентами по TLS
143 IMAP Чтение с апгрейдом до TLS через STARTTLS
4190 ManageSieve Серверные правила фильтрации почты
443 HTTPS / JMAP Веб-клиент, JMAP и ACME TLS-ALPN-01
8080 HTTP (админка) Первичная настройка. Только 127.0.0.1

Дополнительно нужны POP3-порты 110 и 995, если ящики читаются старыми клиентами. Все эти порты объявлены в EXPOSE официального Dockerfile, и ни один из них не следует держать закрытым, кроме административного 8080.

Существует ещё два требования, которые невозможно выполнить настройкой внутри сервера. Первое — обратная DNS-запись (PTR): она обязана указывать на то же имя, что и прямая A-запись почтового узла, иначе крупные провайдеры будут помечать письма как спам. Второе — разблокированный порт 25: многие российские хостеры по умолчанию его закрывают и открывают по обращению в поддержку, а некоторые запрещают исходящие соединения на 25 порт полностью. Перед оплатой тарифа уточните оба пункта.

5. Подготовка DNS, развертывание в Docker Compose и первый запуск

Начнём с DNS. Без корректных записей письма будут уходить в спам даже при идеально настроенном сервере, поэтому зафиксируем минимум до первого запуска контейнера.

; Основные записи для домена example.ru
mail.example.ru.        IN A     203.0.113.10
example.ru.             IN MX 10 mail.example.ru.
example.ru.             IN TXT   "v=spf1 mx -all"
_dmarc.example.ru.      IN TXT   "v=DMARC1; p=quarantine; rua=mailto:dmarc@example.ru"

; CAA разрешает выпуск сертификатов только Let's Encrypt
example.ru.             IN CAA 0 issue "letsencrypt.org"

Четыре момента, которые важно не перепутать. Запись MX указывает на имя узла, а не на IP-адрес. В SPF директива mx разрешает отправку со всех хостов, перечисленных в MX, а -all запрещает всё остальное — это строгий и правильный режим. Запись DMARC с политикой p=quarantine заставляет получателей отправлять неподписанные письма в спам. Запись CAA запрещает выпускать сертификаты на ваш домен любому удостоверяющему центру, кроме Let's Encrypt, что защищает от ошибочной или злонамеренной выдачи.

💡 Совет инженера: проверьте DNS до запуска

Убедитесь, что A-запись уже разошлась по резолверам, через DNS Lookup SysKit, а открытые порты после настройки файрвола проверьте сканером портов. Для обратной зоны PTR используйте определение IP и сверяйте результат с ответом провайдера.

Создание каталогов и прав доступа

Официальный образ работает не от root, а от непривилегированного пользователя stalwart с UID 2000. В Dockerfile за это отвечают директивы USER stalwart и VOLUME ["/etc/stalwart", "/var/lib/stalwart"], а право слушать привилегированные порты 25 и 443 выдано бинарнику через setcap cap_net_bind_service. Поэтому каталоги на хосте нужно заранее отдать этому UID, иначе контейнер не сможет записать базу:

# Каталоги для конфигурации и данных
mkdir -p /opt/stalwart/etc /opt/stalwart/data

# Владелец — UID/GID 2000, под которым работает процесс в контейнере
chown -R 2000:2000 /opt/stalwart

# Права: владелец читает и пишет, остальные не имеют доступа
chmod 750 /opt/stalwart /opt/stalwart/etc /opt/stalwart/data

Манифест Docker Compose

services:
  stalwart:
    image: stalwartlabs/stalwart:v0.16.27
    container_name: stalwart
    restart: unless-stopped
    hostname: mail.example.ru
    environment:
      # Имя узла и публичный адрес веб-клиента
      STALWART_HOSTNAME: mail.example.ru
      STALWART_PUBLIC_URL: https://mail.example.ru
    ports:
      # SMTP: приём писем из интернета
      - "25:25"
      # SMTP Submission: отправка из клиентов
      - "465:465"
      - "587:587"
      # IMAP и ManageSieve
      - "143:143"
      - "993:993"
      - "4190:4190"
      # HTTPS для веб-клиента, JMAP и ACME TLS-ALPN-01
      - "443:443"
      # Админка только на локальной петле: доступ через SSH-туннель
      - "127.0.0.1:8080:8080"
    volumes:
      # Конфигурация (config.json) и данные (база, блобы)
      - ./etc:/etc/stalwart
      - ./data:/var/lib/stalwart
    mem_limit: 2g
    cpus: 2.0
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

Обратите внимание на три инженерных решения. Порт 8080 привязан к 127.0.0.1: панель первичной настройки не должна быть доступна из интернета ни при каких обстоятельствах, а работать с ней мы будем через SSH-туннель (механику обхода файрвола контейнерами мы разбирали в статье Docker обходит UFW на Linux). Лимиты mem_limit и cpus заданы на верхнем уровне сервиса, без режима Swarm, поэтому действуют в обычном docker compose. Логи ограничены по размеру, иначе журнал контейнера способен занять весь диск при интенсивном почтовом потоке.

Отдельно про порт 443. Stalwart занимает его сам, потому что встроенный ACME-клиент поддерживает проверку TLS-ALPN-01, которая проходит именно на 443 порту. Если на этом же сервере уже работает Nginx или Caddy на 443, порт нужно освободить либо переключить ACME на проверку DNS-01 — об этом ниже.

Первый запуск и вход в панель настройки

# Запуск контейнера
cd /opt/stalwart
docker compose up -d

# Ожидание инициализации хранилища
docker compose ps
docker compose logs -f stalwart

При первом старте сервер поднимается в bootstrap-режиме: он создаёт хранилище и генерирует временный пароль администратора, который выводится в лог. Официальный установщик Stalwart прямо указывает, что забрать его нужно из журнала службы, а завершить настройку — в браузере на порту 8080. Для Docker команда поиска пароля выглядит так:

# Извлечение временного пароля администратора из логов контейнера
docker compose logs stalwart | grep -A8 'bootstrap mode'

Панель слушает только локальную петлю, поэтому открываем к ней SSH-туннель со своей рабочей машины:

# Проброс 8080 порта сервера на локальный компьютер
ssh -L 8080:127.0.0.1:8080 root@203.0.113.10

После этого в браузере открываем http://127.0.0.1:8080/admin, вводим логин admin и пароль из логов. Мастер настройки предложит указать имя домена, создать первую учётную запись и задать постоянный пароль администратора. Вместо поиска пароля в журнале можно сразу зафиксировать его переменной окружения STALWART_RECOVERY_ADMIN=admin:ВашПароль — она поддерживается официальным установщиком и удобна при автоматизированном развертывании.

⚠️ Важное предупреждение: смените временный пароль сразу

Пароль из bootstrap-режима действует до первой смены и записан в журнал контейнера открытым текстом. Если журнал успел уйти в систему централизованного сбора логов, пароль считается скомпрометированным. Смените его в первый же вход в панель, а старые записи журнала удалите.

Рекомендуемые VDS-провайдеры

Отказоустойчивые сервера с быстрыми NVMe и каналом до 1 Гбит/с

Выбор редакции
⚡

Timeweb Cloud — Быстрые NVMe VDS

Быстрые NVMe-накопители для базы почты и вложений, безлимитный трафик и понятная процедура открытия порта 25 по запросу в поддержку.

Конфигурация
2 vCPU 3.3 ГГц • 2 ГБ RAM • 40 ГБ NVMe • Трафик без лимита
Премиум Tier III
🔷

Selectel — Инфраструктура Tier III

Отказоустойчивые дата-центры в РФ, приватные сети и прогнозируемая задержка диска — важно для почтовой базы под нагрузкой.

Конфигурация
2 vCPU • 4 ГБ RAM • 60 ГБ NVMe • Приватная сеть
Быстрый старт
🟠

Beget — Простой старт для домена

Готовые шаблоны Ubuntu 24.04, оплата для юридических лиц с полным пакетом закрывающих документов и настройка PTR через панель.

Конфигурация
2 vCPU • 2 ГБ RAM • 40 ГБ NVMe • Быстрый запуск

6. TLS-сертификаты через встроенный ACME без Certbot

Классический путь получения сертификата на почтовом сервере выглядит так: Certbot выпускает файлы, затем Postfix и Dovecot перезапускаются, чтобы подхватить их, а задача продления через deploy-hook должна сработать в правильном порядке. Любой сбой в этой цепочке даёт просроченный сертификат и отказ клиентов подключаться.

Stalwart решает задачу иначе: ACME-клиент встроен в сам сервер, а поддерживаемые типы проверки владения доменом реализованы непосредственно в коде — TLS-ALPN-01, HTTP-01, DNS-01 и DNS-PERSIST-01. Сервер сам обновляет сертификаты по запросу и показывает их детали в панели.

Тип проверки Что требуется Когда выбирать
TLS-ALPN-01 Свободный порт 443 Выделенный почтовый VDS без веб-сервера
HTTP-01 Свободный порт 80 Порт 443 занят, а 80 свободен
DNS-01 API DNS-провайдера Порты 80 и 443 заняты или закрыты
DNS-PERSIST-01 Долгоживущая TXT-запись Провайдер без API, ручное управление зоной

Ветка DNS-01 работает не только вручную: сервер умеет сам управлять записями MX, TXT, CNAME, SRV, CAA и TLSA в зоне. Из поддерживаемых провайдеров в актуальном релизе заявлены Route53, Google Cloud DNS, Bunny, Porkbun и DNSimple, а для собственных DNS-серверов есть динамическое обновление зоны по RFC 2136 с подписью SIG(0). Дополнительно поддерживаются записи CAA с параметром accounturi и публикация TLSA — что закрывает тему DANE для тех, кто её использует.

💡 Совет инженера: проверьте цепочку сертификата после выпуска

Убедитесь, что сервер отдаёт полную цепочку и корректные сроки, через проверку SSL-сертификата. Если сайт и почта живут на одном VDS, почтовый сервер должен занимать отдельный поддомен, иначе TLS-ALPN-01 не сможет ответить на проверку.

7. Подпись домена: DKIM, SPF и DMARC под контролем

Три механизма отвечают за то, поверит ли почтовый сервер получателя письму с вашего домена. SPF перечисляет IP-адреса, которым разрешено отправлять почту. DKIM подтверждает целостность письма криптографической подписью. DMARC сообщает, что делать с письмами, не прошедшими обе проверки, и является главным сигналом для борьбы с подделкой домена.

В старом стеке DKIM-ключ генерируют утилитой opendkim-genkey, публикуют TXT-запись вручную, а при ротации повторяют процедуру и не забывают перезапустить фильтр. Stalwart закрывает этот цикл автоматически: ключи генерируются при подключении домена, хранятся в базе данных, ротируются по расписанию, а публикация записи выполняется через тот же DNS-провайдер, что настроен для ACME. Дополнительно сервер умеет игнорировать небезопасные подписи при проверке DKIM, что снижает число ложных срабатываний на письмах отправителей с устаревшим 512-битным ключом.

Порядок настройки домена в панели

  1. Добавьте домен в разделе управления доменами и укажите имя вида example.ru.
  2. Создайте DKIM-подпись: селектор, размер ключа и алгоритм. Панель сразу покажет готовую запись TXT.
  3. Опубликуйте запись в DNS: вручную, либо подключив провайдера и включив автоматическое управление.
  4. Проверьте результат отправкой тестового письма на сервис проверки спама и убедитесь, что подпись проходит и SPF выравнивается.
  5. Ужесточите DMARC: начните с политики p=none, соберите отчёты о неполадках, и только потом переключитесь на quarantine или reject.

⚠️ Важное предупреждение: не включайте reject сразу

Политика p=reject, включённая в первый же день, отрезает легитимные рассылки: каталоги почтовых адресов, сервисы уведомлений и CRM отправляют письма через собственные серверы, и без собранных отчётов вы не узнаете, какие из них сломались. Начните с none и подождите две недели реальных отчётов.

Что проверить после настройки

  • Отсутствие в блок-листах. Проверьте IP через проверку URI в чёрных списках: попадание в SPI, Spamhaus или Barracuda означает, что письма будут отклоняться до попытки доставки.
  • Корректность PTR. Обратная запись должна совпадать с прямым именем узла, а не просто существовать.
  • Непустые записи SPF и DMARC. Частая ошибка — опечатка в имени _dmarc или использование дефиса вместо подчёркивания.
  • Прохождение подписи. В тестовом письме заголовок Authentication-Results должен содержать dkim=pass и spf=pass.
  • Отсутствие открытого релея. Проверьте, что отправка без аутентификации через 25 порт запрещена, иначе сервер за считанные часы попадёт в рассылочные базы.

8. Резервное копирование, обновления и мониторинг

Почтовый сервер — это данные, которые невозможно восстановить из репозитория. Письма, календари и контакты существуют только в двух каталогах, объявленных как тома официального образа: /etc/stalwart с файлом config.json и /var/lib/stalwart с базой данных и вложениями. Копировать их «на горячую» из работающего контейнера нельзя: база данных в момент записи находится в промежуточном состоянии, и архив получится неконсистентным.

#!/usr/bin/env bash
set -euo pipefail

BACKUP_DIR="/var/backups/stalwart"
STAMP="$(date +%Y%m%d-%H%M%S)"
ARCHIVE="${BACKUP_DIR}/stalwart-${STAMP}.tar.gz"

mkdir -p "${BACKUP_DIR}"

# Гарантированно возвращаем контейнер в строй при любом исходе
cleanup() {
  docker compose -f /opt/stalwart/docker-compose.yml unpause \
    >/dev/null 2>&1 || true
}
trap cleanup EXIT

# Замираем контейнер: файлы на диске становятся консистентными
docker compose -f /opt/stalwart/docker-compose.yml pause

tar -czf "${ARCHIVE}" \
  -C /opt/stalwart etc data

# Проверяем читаемость архива до отправки в хранилище
tar -tzf "${ARCHIVE}" >/dev/null

echo "Создан архив: ${ARCHIVE}"

# Хранение локальных копий: 14 дней
find "${BACKUP_DIR}" -name 'stalwart-*.tar.gz' -mtime +14 -delete

Скрипт замораживает контейнер на время чтения файлов, а конструкция trap ... EXIT гарантирует, что при любой ошибке — включая падение tar — сервер будет разморожен. Без этой страховки прерванный бэкап оставит почту недоступной до ручного вмешательства.

Готовый архив отправляйте в объектное хранилище, а не на тот же диск: выгрузку в S3 удобно собрать по рецепту из нашего материала о шифрованных бэкапах VDS и Docker в S3. Отдельно проверяйте, что архив действительно разворачивается на тестовой машине — непроверенный бэкап не считается бэкапом.

Проверка работоспособности и мониторинг

Образ содержит встроенный HEALTHCHECK, который обращается к эндпоинту /healthz/live с заголовком X-Forwarded-For, поэтому состояние контейнера сразу видно в docker compose ps. Проверить службу снаружи можно той же командой, что использует сам образ:

# Проверка живости сервера с локальной петли
curl -fsS -H "X-Forwarded-For: 127.0.0.1" http://127.0.0.1:8080/healthz/live

# Альтернатива по HTTPS, если веб-клиент уже настроен
curl -fsSk https://127.0.0.1:443/healthz/live

Эндпоинт /healthz/live отвечает, если процесс жив, — этого достаточно для внешнего мониторинга доступности. Полноценный контроль почтового трафика строится иначе: настройте внешний чекер, который раз в несколько минут подключается по IMAPS к тестовому ящику, и отдельный чекер, отправляющий письмо на внешний адрес и проверяющий его приход. Мониторинг одного лишь порта не увидит ситуацию, когда сервер принимает соединения, но не может доставить письмо из-за проблем с DNS-резолвером или блокировки на стороне получателя.

Обновление версии

# Загрузка нового образа и перезапуск с сохранением томов
cd /opt/stalwart
docker compose pull
docker compose up -d

# Проверка, что контейнер не ушёл в цикл перезапуска
docker compose ps
docker compose logs --tail=50 stalwart

Порядок обновления прост, но требует осторожности в двух местах. Первое: перед сменой тега образа сделайте бэкап и проверьте, что новая версия не находится в мажорной ветке с ломающими изменениями — переход между семействами версий Stalwart требует отдельной процедуры. Второе: помните о требовании x86-64-v2. Если сервер работает на musl-сборке -alpine, обновляйтесь строго на теги с тем же суффиксом, иначе после docker compose pull контейнер перестанет стартовать на старом процессоре.

⚠️ Важное предупреждение: сначала бэкап, потом pull

docker compose pull необратимо заменяет локальный образ, и откатиться на предыдущую версию можно только повторной загрузкой конкретного тега. Зафиксируйте текущую версию в переменной STALWART_VERSION в .env и подставляйте её в манифест — тогда откат сводится к смене одной строки.

9. Чек-лист подготовки почтового сервера к промышленной эксплуатации

Параметр Требование Зачем
Процессор x86-64-v2 или тег -alpine Иначе контейнер не стартует с v0.16.26
Админка 8080 127.0.0.1:8080:8080 + SSH-туннель Защита от обхода UFW через iptables Docker
Bootstrap-пароль Сменён при первом входе Он записан в журнал открытым текстом
PTR Совпадает с A-записью Без него крупные провайдеры режут почту
SPF, DKIM, DMARC Все три опубликованы Защита домена от подделки писем
Открытый релей Отправка только после аутентификации Иначе сервер попадает в блок-листы за сутки
Бэкап pause → tar → unpause → S3 Консистентность базы и вложений

Stalwart убирает главную причину, из-за которой компании годами не решаются держать собственный почтовый сервер: необходимость поддерживать полдесятка независимых демонов и вручную синхронизировать DKIM-ключи с TLS-сертификатами. Один процесс, одна база настроек и встроенный ACME-клиент превращают эту задачу из постоянного сопровождения в разовое развертывание. Остаётся то, что не решается никакой автоматизацией: корректная обратная DNS-запись, разблокированный порт 25 и дисциплина резервного копирования.

🎯 Разверните почтовый сервер на подготовленной инфраструктуре

Для Stalwart достаточно компактного VDS с быстрым NVMe-диском: база почты чувствительна к задержкам записи, а вложения занимают основную часть дискового пространства. Выбирайте провайдера, который открывает порт 25 и настраивает PTR по обращению в поддержку.

Вопросы и ответы (FAQ)

Популярные вопросы вебмастеров и сисадминов по данной теме

Можно ли поставить Stalwart на сервер, где уже работает Nginx на 443 порту?
Да, но нужно сменить тип ACME-проверки. Встроенный клиент поддерживает четыре варианта: TLS-ALPN-01 (занимает 443), HTTP-01 (занимает 80), DNS-01 (работает через API DNS-провайдера) и DNS-PERSIST-01 (долгоживущая TXT-запись). Если 443 и 80 заняты веб-сервером, выберите DNS-01 — тогда для почтового узла достаточно отдельного поддомена вроде mail.example.ru, а сертификат выпускается без освобождения портов.
Что делать, если контейнер Stalwart перезапускается по кругу сразу после docker compose up?
В девяти случаях из десяти причина в наборе инструкций процессора. Начиная с релиза v0.16.26 официальные x86_64-образы требуют x86-64-v2 (SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT), и виртуальные машины с обобщённой моделью процессора, например QEMU «Common KVM processor», этот набор не предоставляют. Решение: либо переключить тип процессора ВМ на host или x86-64-v2-AES, либо взять musl-сборку с суффиксом тега -alpine. Проверить флаги можно командой grep -o -m1 -E 'sse4_2|popcnt' /proc/cpuinfo.
Данные писем останутся целыми при обновлении Stalwart с ветки v0.15 на v0.16?
Данные остаются на месте: раскладка базы (письма, календари, контакты, файлы, блобы) в v0.16 не менялась, меняется только слой конфигурации и управления. Однако обновление требует многошаговой процедуры из официального файла UPGRADING/v0_16.md: поднять сервер в recovery-режиме, проиграть экспорт настроек через официальный CLI и только затем переключить службу на новый config.json. Пропуск шагов оставляет сервер в невосстановимом состоянии, поэтому перед процедурой обязателен бэкап обоих томов.

Читайте также в блоге SysKit

Смежные руководства и полезные технические статьи