Mailcow на VPS: пошта, яку приймає Gmail
Перевірте порт 25 до встановлення mailcow: блокування залишить пошту в черзі до відхилення. Налаштуйте DNS проти помилки Gmail 550 5.7.25 через PTR.
Що ви створюєте
Повноцінний поштовий сервер на власному сервері: SMTP для надсилання й отримання пошти, IMAP для синхронізації телефона та ноутбука, webmail-клієнт і фільтр спаму, який оцінює кожне повідомлення в обох напрямках. mailcow-dockerized об’єднує Postfix, Dovecot, Rspamd, webmail SOGo, MariaDB, Redis і ACME-клієнт в один стек Docker Compose, тому програмне забезпечення — не найскладніша частина. За пів години сервер уже працюватиме.
Найскладніше — усе, що його оточує. Електронна пошта — це єдиний сервіс, до якого решта інтернету активно ставиться з недовірою, якщо він працює на новому сервері. Різниця між «усе працює» та «Gmail мовчки відкидає кожне повідомлення» переважно визначається чотирма DNS-записами й одним параметром репутації IP-адреси, який ви не завжди можете повністю контролювати. Прочитайте наведені нижче передумови, перш ніж орендувати сервер. Якщо після цього ви вирішите, що покращення репутації не варте зусиль, це цілком обґрунтоване рішення: у нашому огляді того, що справді варто розгортати на власному сервері у 2026 році електронну пошту віднесено до категорії «лише якщо ви справді цього хочете» саме з цих причин.
Передумови — це і є проєкт
Якщо пропустити хоча б одну з них, ви надсилатимете пошту, яка не надійде. Нижче вони наведені приблизно в порядку частоти проблем, які через них виникають:
Вихідний порт 25 має бути відкритий. Ваш сервер доставляє пошту до Gmail і Microsoft через TCP-порт 25. Значна частина VPS- і cloud-провайдерів типово блокує вихідний порт 25 для боротьби зі спамом. Блокування відбувається без повідомлень: під час запуску помилок немає, усе виглядає справним, а пошта залишається відкладеною в черзі, доки Postfix не припинить спроби та не поверне її відправнику. У mailcow максимальний час зберігання в черзі становить п’ять днів. Перевірте порт до встановлення будь-яких компонентів. Якщо його заблоковано, єдиний спосіб вирішення — звернутися до провайдера з проханням відкрити порт. Деякі провайдери роблять це для облікових записів із достатньою історією використання, а деякі не відкривають його взагалі.
Чиста IP-адреса з прийнятною репутацією. Перерозподілені VPS-адреси часто вже внесені до blocklist через спам попереднього орендаря. Перед початком перевірте свою адресу через такий сервіс, як Spamhaus lookup або mxtoolbox. IP-адреса в blocklist означає відхилення, які неможливо виправити змінами в коді.
Керування DNS і правильний запис PTR. Ви повинні мати змогу додавати записи до зони свого домену, а також налаштувати зворотний DNS (PTR) для IP-адреси сервера, щоб він вказував на ім’я поштового хоста. PTR майже ніколи не налаштовується в панелі керування DNS. Цей запис належить власнику IP-адреси, тому його налаштовують у панелі керування VPS-провайдера або через support ticket.
6 GiB RAM і 2 vCPU — комфортний мінімум. Власний мінімум mailcow для приватного встановлення становить 6 GiB RAM і 1 GiB swap. Коли поштою користується кілька користувачів, рекомендовано мати 8 GiB. Якщо доступно менше ніж приблизно 2.5 GiB, generate_config.sh пропонує вимкнути антивірусний сканер ClamAV, щоб kernel не почав завершувати контейнери. Задокументований мінімум дискового простору для mailcow становить 20 GiB до збереження будь-якої пошти, тому на початку виділіть більше та залиште запас для збільшення поштових скриньок.
DNS-ім’я, а не сама IP-адреса. Виберіть ім’я хоста, наприклад mail.example.com. Це ім’я буде вашим MAILCOW_HOSTNAME, суб’єктом TLS-сертифіката, ціллю PTR і SMTP-банером. Використовуйте його однаково в усіх налаштуваннях.
Крок 1. Перевірте, чи відкритий вихідний порт 25
Зробіть це спочатку. Якщо перевірка не проходить, усе інше марне. На новому VPS спробуйте встановити SMTP-сеанс із реальним поштовим сервером:
sudo apt update && sudo apt install -y netcat-openbsd
nc -vz -w 5 gmail-smtp-in.l.google.com 25У разі успішного підключення результат з’явиться одразу:
Connection to gmail-smtp-in.l.google.com (142.250.x.x) 25 port [tcp/smtp] succeeded!Якщо порт заблокований, команда чекатиме повні п’ять секунд, а потім завершиться помилкою:
nc: connect to gmail-smtp-in.l.google.com port 25 (tcp) timed out: Operation now in progressНа новому VPS без власних правил вихідного firewall цей тайм-аут означає блокування на боці провайдера. Це мережевий фільтр провайдера, а не ваш firewall, тому локальні зміни його не усунуть. Створіть звернення: «Будь ласка, увімкніть вихідний TCP-порт 25 для мого VPS за адресою <IP>; я запускаю легітимний поштовий сервер». Не встановлюйте mailcow, доки команда не поверне результат "succeeded". Вхідний порт 25, через який інші сервери підключаються до вас, — це окремий напрямок і зазвичай він відкритий. Провайдери обмежують саме вихідний трафік.
Крок 2. Налаштуйте записи DNS
Зміни DNS потребують часу для поширення, тому опублікуйте все, що можливо, до встановлення. Припустімо, ваш домен — example.com, поштовий хост — mail.example.com, а IP-адреса — 10.0.0.10. У вашій зоні створіть:
mail.example.com. A 10.0.0.10
mail.example.com. AAAA 2001:db8::10 ; only if you have IPv6
example.com. MX 10 mail.example.com.
example.com. TXT "v=spf1 mx -all"
_dmarc.example.com. TXT "v=DMARC1; p=none; rua=mailto:postmaster@example.com"Запис SPF означає: «лише мій MX може надсилати пошту від імені цього домену, решту відхиляти». Почніть DMARC зі значення p=none, щоб переглядати звіти без відхилення власної пошти. Після підтвердження узгодженості політик змініть значення на p=quarantine, а потім на p=reject. Два записи навмисно не наведено: DKIM, який mailcow згенерує для вас на кроці 6, і PTR, який потрібно налаштувати зараз у панелі вашого провайдера.
Налаштуйте PTR (зворотний DNS) для 10.0.0.10 зі значенням mail.example.com — точним значенням MAILCOW_HOSTNAME. Саме цей запис найчастіше забувають, а великі провайдери перевіряють його та відхиляють пошту за його відсутності або невідповідності. Якщо в панелі немає поля rDNS, створіть ticket.
Крок 3. Встановлення Docker
mailcow потребує Docker Engine версії 24.0 або новішої та Docker Compose версії 2.0 або новішої. Плагін Compose (docker compose) є найпростішим варіантом, хоча mailcow також підтримує окремий бінарний файл docker-compose. Використовуйте офіційний convenience script від Docker, а не пакет Ubuntu docker.io, який взагалі не містить плагіна Compose:
curl -fsSL https://get.docker.com | sudo sh
sudo docker compose versionВи маєте побачити рядок Docker Compose version із версією v2.x або v5.x. Compose v5, випущений у 2025 році, функціонально ідентичний v2, тому обидві версії відповідають вимогам mailcow. Якщо docker compose version виводить docker: 'compose' is not a docker command, Docker Engine встановлено, але плагіна Compose немає. Встановіть плагін із репозиторію Docker, повторно виконайте наведений вище скрипт або скористайтеся нашим посібником з основ Docker Compose, який налаштовує обидва компоненти з власного apt-репозиторію Docker.
Крок 4. Клонуйте mailcow і згенеруйте конфігурацію
cd /opt
sudo git clone https://github.com/mailcow/mailcow-dockerized
cd mailcow-dockerized
umask
sudo ./generate_config.shПеревірка того, що umask виводить 0022, відповідає власним інструкціям mailcow зі встановлення, які задають umask 0022 перед клонуванням. mailcow не перевіряє це значення, а в новій root-сесії Ubuntu 24.04 воно вже має значення 0022. Далі скрипт запитує єдине важливе значення: повне доменне ім’я хоста. Введіть mail.example.com. Це значення має точно збігатися з вашим A-записом і PTR-записом. Скрипт записує його у mailcow.conf — єдиний файл середовища, який читає весь стек. Відкрийте цей файл, якщо потрібно змінити web-порти (HTTP_PORT, HTTPS_PORT) або вимкнути ClamAV на малопотужному сервері:
MAILCOW_HOSTNAME=mail.example.com
HTTP_PORT=80
HTTPS_PORT=443
SKIP_CLAMD=n # set to y to drop the virus scanner on a <2.5 GiB boxSKIP_FTS=y — ще один спосіб зменшити споживання пам’яті на сервері з малим обсягом RAM. Повнотекстовий пошук є другим найбільшим споживачем пам’яті за документацією mailcow. Його вимкнення позбавляє лише пошуку тексту повідомлень у webmail.
Не змінюйте HTTP_PORT=80 і HTTPS_PORT=443, якщо ці порти вже не використовує інший процес на хості. Вбудований ACME-клієнт mailcow за замовчуванням використовує перевірку HTTP-01. Для отримання сертифіката порт 80 має бути доступним з Інтернету. (У mailcow 2026-03 і новіших версіях можна використовувати перевірку DNS-01 за допомогою ACME_DNS_CHALLENGE=y. Вона не потребує порту 80, але потребує доступу до API вашого DNS-провайдера.) Саме тому проста схема не використовує окреме налаштування nginx і Certbot на тому самому сервері. mailcow самостійно випускає та поновлює TLS-сертифікати, а другий сервіс, який займає порти 80/443, порушить цю роботу. У документації mailcow описано альтернативу: прив’язати його web-слухачі локально за допомогою HTTP_BIND=127.0.0.1 HTTP_PORT=8080 HTTPS_BIND=127.0.0.1 HTTPS_PORT=8443, розмістити reverse proxy на портах 80 і 443, а якщо сертифікатами має керувати локальний Certbot — передати mailcow шлях до них і додати hook для поновлення. Для поштового сервера це означає більше компонентів, тому те саме обмеження стосується будь-якого іншого сервісу, якому потрібен публічний web-фронтенд: збірка на кшталт Halcyon, що перетворює бібліотеку Jellyfin на відеопрокат у стилі 90-х, яка очікує власний reverse proxy на 443, має працювати на іншому хості, якщо тільки ви не розмістите mailcow за цим проксі. Винятком є сервіс, якому взагалі не потрібен публічний web-порт: self-hosted relay RustDesk слухає лише власний діапазон портів від 21115 до 21119, тому може працювати на тому самому сервері, якщо запасу пропускної здатності достатньо.
Крок 5. Запустіть стек і увійдіть
sudo docker compose pull
sudo docker compose up -d
sudo docker compose psКоманда завантажує приблизно два десятки образів. Це може тривати кілька хвилин. Коли docker compose ps покаже, що кожен контейнер має стан running (або healthy), відкрийте https://mail.example.com/admin у браузері. Типові дані для входу адміністратора: ім’я користувача admin, пароль moohoo. Негайно змініть цей пароль в адміністративному інтерфейсі: System → Configuration, потім Access → Administrators. Якщо браузер попереджає про NET::ERR_CERT_AUTHORITY_INVALID, сертифікат ACME ще не видано. Перш ніж вважати конфігурацію несправною, перегляньте розділ нижче про помилку ACME. У перші одну-дві хвилини самопідписаний тимчасовий сертифікат є нормальним.
Крок 6. Додайте домен, поштову скриньку та опублікуйте DKIM
В адміністративному інтерфейсі відкрийте E-Mail → Configuration, на вкладці Domains натисніть Add domain і введіть example.com. Потім у розділі Mailboxes натисніть Add mailbox, щоб створити you@example.com із паролем. Це вже робоча поштова скринька, доступна через IMAP.
Тепер налаштуйте ключ DKIM. Перейдіть до System → Configuration, потім Options → ARC/DKIM keys. mailcow міг згенерувати ключ під час додавання домену. Якщо ключа немає, згенеруйте його там: виберіть домен, залиште селектор dkim, виберіть 2048-bit і натисніть Add. Скопіюйте довге значення TXT, яке відобразить система, і опублікуйте його як:
dkim._domainkey.example.com. TXT "v=DKIM1;k=rsa;t=s;s=email;p=MIIBIjANBgkqh...long-key...QAB"На сторінці Domains у mailcow є кнопка DNS. Вона показує всі записи, які очікує система, і позначає зеленим прапорцем або червоним хрестиком фактично опубліковані значення. Використовуйте цю сторінку як контрольний список і переконайтеся, що перед перевіркою доставлення всі рядки позначені зеленим. Червоний рядок DKIM після публікації зазвичай означає, що ключ неправильно розділено на частини TXT. Ключ 2048-bit довший за обмеження 255 символів для одного рядка TXT, тому вставте його як одне логічне значення, а DNS-провайдер нехай сам розділить його на частини.
Крок 7. Перевірте доставляння та отримайте 10/10
Перейдіть на mail-tester.com, скопіюйте випадкову адресу, яку він покаже, і надішліть на неї повідомлення з нової поштової скриньки. Увійдіть у вебпошту SOGo за адресою https://mail.example.com/SOGo і надішліть повідомлення звідти. Потім натисніть "Then check your score".
Прагніть отримати 10/10. Найчастіші причини зниження оцінки:
- SPF не узгоджений — запис
MX/SPF відсутній або IP-адреса відправника не охоплена ним. Повторно перевірте SPF TXT-запис. - Підпис DKIM не проходить перевірку — TXT-запис
dkim._domainkeyвідсутній, ще поширюється або пошкоджений. Це найпоширеніша проблема. - Немає PTR або PTR не збігається — зворотний DNS не повертає
mail.example.com. Виправте це в панелі провайдера. - IP-адресу внесено до blocklist — попередня репутація вашої IP-адреси. Подайте запит на видалення зі списку або попросіть чистішу IP-адресу.
Не надсилайте реальні повідомлення до Gmail або Outlook, доки оцінка не становитиме 10/10. Низька оцінка в поєднанні з новою IP-адресою може призвести до позначення вашого домену вже в перший день.
Крок 8. Підключіть поштовий клієнт
Налаштуйте Thunderbird, Apple Mail або телефон для підключення до сервера з такими параметрами. Для всіх клієнтів ім’я хоста сервера — mail.example.com:
- IMAP: порт 993, SSL/TLS (або 143 зі STARTTLS)
- SMTP submission: порт 465, SSL/TLS (або 587 зі STARTTLS)
- Ім’я користувача: повна адреса,
you@example.com - Пароль: пароль поштової скриньки, який ви встановили
Ніколи не надсилайте пошту з клієнта через порт 25. Цей порт призначений лише для обміну поштою між серверами. mailcow не надає через нього автентифіковане надсилання, тому підключення клієнта до цього порту буде відхилено. Якщо клієнт повідомляє Relay access denied, він намагається надсилати пошту через порт 25 або без автентифікації. Перемкніть його на порт 465 або 587 і вкажіть облікові дані поштової скриньки.
Крок 9. Резервуйте те, що справді важливо
mailcow має скрипт резервного копіювання, який створює знімки всіх томів зі станом. Запускайте його для зовнішнього диска або змонтованого віддаленого ресурсу:
sudo MAILCOW_BACKUP_LOCATION=/opt/mailcow-backups \
./helper-scripts/backup_and_restore.sh backup allall зберігає шість компонентів. Втрата будь-якого з них означає втрату даних: vmail (самі поштові скриньки), crypt (ключі для розшифрування vmail; без них цей том непридатний), mysql (MariaDB із доменами, користувачами, псевдонімами та налаштуваннями), redis (стан черги й кешу), rspamd (вивчені ознаки спаму та не-спаму) і postfix (поштова черга). Скрипт працює всередині допоміжного контейнера та записує стиснені архіви, тому резервні копії залишаються узгодженими навіть під час роботи всього стека. Автоматизуйте його за допомогою nightly cron job і додайте --delete-days 14, щоб видаляти старі набори. cron job, який перестав працювати, завершується без повідомлення, тому передавайте код завершення скрипту туди, де ви його точно помітите; self-hosted ntfy server приймає однорядковий curl із того самого cron entry і надсилає повідомлення про збій на ваш телефон у ніч, коли він стався. Відновлення виконується тим самим скриптом із restore: він показує знімки та дає змогу вибрати, що відновити. Резервна копія, з якої жодного разу не виконували тестове відновлення, — це лише припущення, а не резервна копія. Виконайте пробне відновлення на тимчасовому VPS.
Крок 10. Оновлення за розкладом
mailcow оновлюється власним скриптом. Скрипт отримує новий код, виконує міграцію mailcow.conf, попередньо завантажує образи та перезапускає контейнери в потрібному порядку:
cd /opt/mailcow-dockerized
sudo ./update.sh --check # reports whether an update exists, changes nothing
sudo ./update.sh # applies itСпочатку створіть резервну копію (Крок 9), оскільки міграцію схеми складно скасувати. Оновлення виходять часто та містять виправлення безпеки для daemon, доступних з Інтернету, тому не залишайте поштовий сервер без оновлень на місяці. Якщо після оновлення контейнер перейде в несправний стан, sudo docker compose logs --tail=50 <service>-mailcow назве daemon, який не зміг запуститися знову.
Нотатка про hardening
mailcow запускає власний сервіс netfilter (netfilter-mailcow), який блокує IP-адреси, що надсилають велику кількість запитів до портів пошти та webmail. Тому поштову частину системи захищено з коробки. Це не захищає SSH на самому хості: він і далі доступний ззовні та зазнає brute-force-атак. Для цього налаштування додатково використовуйте Fail2ban для моніторингу журналу автентифікації SSH і вхід лише за ключами. Захистіть адміністративний інтерфейс mailcow надійним паролем і, за можливості, закрийте до нього доступ із публічного інтернету або розмістіть його за VPN.
Типові причини з точними рядками
Поштові повідомлення накопичуються в черзі й не доставляються. Виконайте sudo docker compose exec postfix-mailcow postqueue -p або перегляньте поштову чергу в адміністративному інтерфейсі. Повідомлення залишаються відкладеними до п’яти днів, після чого Postfix повертає їх відправнику з таким повідомленням:
status=deferred (connect to gmail-smtp-in.l.google.com[142.250.x.x]:25: Connection timed out)Майже завжди це означає, що ваш провайдер блокує вихідний порт 25 (Крок 1). Вихідне правило у firewall самого хоста спричиняє такий самий тайм-аут, тому спочатку виключіть цю причину. Якщо на хості все гаразд, змінами конфігурації це не виправити — створіть звернення до провайдера. Причина не в DNS і не в TLS. Показовим є слово timed out для віддаленого MX на порту 25.
Gmail позначає всі повідомлення як спам або повертає їх відправнику. Відкрийте повідомлення в Gmail, виберіть «Show original» і перегляньте результати автентифікації. dkim=fail або dkim=none означає, що ваш запис dkim._domainkey TXT відсутній, пошкоджений або ще не поширився. Повторно опублікуйте його в точному вигляді, який показує сторінка ARC/DKIM, і дочекайтеся завершення TTL. spf=fail означає, що записи SPF/MX не охоплюють вашу IP-адресу. Відповідність параметрів має вирішальне значення: достатньо однієї невдалої перевірки, щоб повідомлення потрапило до спаму.
Великі провайдери відхиляють підключення. У повернутих повідомленнях або журналах Postfix є повідомлення Gmail про відхилення через PTR:
550-5.7.25 [10.0.0.10] The IP address sending this message does not have a PTR
550-5.7.25 record setup, or the corresponding forward DNS entry does not match
550 5.7.25 the sending IP. As a policy, Gmail does not accept messages from IPs
550 5.7.25 with missing PTR records.Код 550 5.7.25 означає, що зворотний DNS відсутній або не відповідає. Налаштуйте PTR для вашої IP-адреси як mail.example.com у панелі провайдера (Крок 2). Прямий запис (A) і зворотний запис (PTR) мають збігатися. Обидва записи повинні вказувати на те саме ім’я хоста, яке mailcow повідомляє іншим серверам.
Браузер показує попередження про сертифікат, яке не зникає. Контейнер acme-mailcow не зміг отримати справжній сертифікат. Перевірте його журнал:
sudo docker compose logs acme-mailcow | tail -n 40Рядок на кшталт Cannot validate any hostnames, skipping Let's Encrypt for 1 hour. або помилка challenge означає, що порт 80 недоступний з інтернету або запис A не вказує на цей сервер. Якщо ви опублікували запис AAAA, перевірте і його. mailcow спочатку перевіряє запис AAAA і пропускає перевірку A, якщо AAAA існує. Тому неправильний AAAA або маршрут IPv6, через який порт 80 недоступний, спричиняє помилку перевірки навіть за правильного запису A. Переконайтеся, що mail.example.com розв’язується в адресу цього сервера, відкрийте порти 80 і 443 у firewall хоста та перевірте, що інший процес не прослуховує ці порти. Після усунення причини перезапустіть клієнт командою sudo docker compose restart acme-mailcow, а не чекайте завершення годинної затримки повторної спроби.
FAQ
Чи справді варто самостійно хостити електронну пошту?
Якщо вам потрібні контроль над даними, необмежена кількість псевдонімів і повний контроль, так: mailcow надає професійний стек за ціною VPS. Але підтримка доставлення листів — це постійна робота: репутація IP-адреси, узгодженість DNS і моніторинг blocklist ніколи не закінчуються. Для критично важливої робочої адреси, де один день у папці спаму може завдати значних збитків, практичним вибором буде керований провайдер. Обирайте self-hosting, якщо для вас контроль важливіший за зручність і ви справді готові цим займатися. Якщо насправді ви хочете лише зберігати дані не на чужих серверах, а не обов’язково самостійно хостити пошту, почніть із сервісу, на роботу якого ніхто інший не може вплинути: для фотобібліотеки проблема доставлення взагалі не виникає, а в нашому порівнянні PhotoPrism та Immich наведено мінімальні вимоги до RAM і команди резервного копіювання для такого розгортання на VPS аналогічного типу.
Як дізнатися, чи заблоковано вихідний порт 25?
Запустіть nc -vz -w 5 gmail-smtp-in.l.google.com 25 на сервері. Повідомлення "succeeded!" означає, що порт відкритий. Повідомлення timed out після паузи означає, що порт заблоковано. Якщо на сервері немає власних правил вихідного firewall, блокування встановив ваш провайдер. Це найпоширеніша причина, через яку self-hosted сервер може приймати пошту, але не може її надсилати. Єдиний спосіб усунути блокування провайдера — попросити провайдера відкрити порт. Локальні налаштування цього не змінять.
Чому мої листи досі потрапляють у папку спаму Gmail?
Майже завжди причина полягає в неправильному ланцюжку автентифікації. У Gmail виберіть "Show original" і знайдіть spf=pass, dkim=pass та dmarc=pass. Значення dkim=fail вказує на відсутній або пошкоджений TXT-запис dkim._domainkey. Невідповідність PTR або нова IP-адреса без історії надсилання також погіршують ситуацію. Спочатку досягніть результату 10/10 на mail-tester.com, потім поступово підвищуйте обсяг надсилання: почніть із кількох повідомлень на день і збільшуйте кількість, а не надсилайте великий обсяг із першого дня.
Що саме потрібно резервно копіювати?
Запустіть backup_and_restore.sh backup all і зберігайте весь набір за межами сервера. Він містить vmail — поштові скриньки; crypt — ключі для їх розшифрування; базу даних MariaDB — домени, користувачів, псевдоніми та налаштування; Redis; дані, на яких Rspamd навчився; а також чергу Postfix. Том crypt часто пропускають. Без нього резервна копія vmail міститиме нерозбірливий зашифрований текст. Принаймні один раз перевірте відновлення на тестовому сервері.
Чи можна запустити mailcow на VPS із 2 GB RAM?
Комфортно — ні. generate_config.sh пропонує вимкнути ClamAV, якщо обсяг пам’яті менший приблизно за 2.5 GiB. Навіть із вимкненим ClamAV Rspamd, Dovecot, MariaDB та решта стека конкуруватимуть за пам’ять. За реального навантаження це призведе до використання swap і завершення процесів через OOM. Вважайте 6 GiB RAM плюс 1 GiB swap мінімумом для стабільного встановлення одним користувачем. Щойно сервісом почнуть користуватися більше ніж кілька людей, перейдіть на 8 GiB.