Руководство по установке и настройке почтового сервера для виртуальных пользователей с хранением их в БД. Ниже — пошаговый roadmap со всеми ключевыми конфигами. Это большой процесс, поэтому я разбил его на фазы — можно идти сверху вниз.
Фаза 0. Подготовка (КРИТИЧНО)
Без этого почта не будет доставляться, даже если всё работает.
- Домен и DNS (пример
example.com, mail-хостmail.example.com):A mail.example.com → <IP сервера>
MX example.com → mail.example.com (priority 10) - PTR (reverse DNS) — заказывается у хостера VPS в панели. Должен указывать на
mail.example.com. Без корректного PTR половина провайдеров (Gmail, Yandex, Outlook) будет отбивать письма или помещать их в спам. - Нужно проверить, что порт 25 наружу не заблокирован — у многих VPS (Hetzner, OVH, AWS, DigitalOcean) он закрыт по умолчанию. Запросите разблокировку.
- Hostname сервера
hostnamectl set-hostname mail.example.com
# /etc/hosts: 127.0.1.1 mail.example.com mail
# /etc/mailname: mail.example.com
Фаза 1. Установка пакетов
apt update && apt upgrade -y
apt install -y \
postfix postfix-mysql \
dovecot-core dovecot-imapd dovecot-pop3d dovecot-lmtpd dovecot-mysql \
mariadb-server \
apache2 libapache2-mod-php php php-mysql php-mbstring php-intl \
php-imagick php-zip php-curl php-xml php-gd \
certbot python3-certbot-apache \
opendkim opendkim-tools \
unzip wget
При установке Postfix выберите Internet Site, системное имя — mail.example.com.
Создайте виртуального пользователя для почты:
groupadd -g 5000 vmail
useradd -g vmail -u 5000 -d /var/vmail -m -s /usr/sbin/nologin vmail
Фаза 2. MariaDB + Postfixadmin
2.1 БД и пользователь
mysql_secure_installation # интерактивно
mysql -u root -p <<'SQL'
CREATE DATABASE postfixadmin CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'postfixadmin'@'localhost' IDENTIFIED BY 'СИЛЬНЫЙ_ПАРОЛЬ';
GRANT ALL PRIVILEGES ON postfixadmin.* TO 'postfixadmin'@'localhost';
FLUSH PRIVILEGES;
CREATE DATABASE roundcube CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'roundcube'@'localhost' IDENTIFIED BY 'ДРУГОЙ_ПАРОЛЬ';
GRANT ALL PRIVILEGES ON roundcube.* TO 'roundcube'@'localhost';
FLUSH PRIVILEGES;
SQL
2.2 Postfixadmin
На момент написания статьи версия 4.0.5 была самой свежей
cd /tmp
wget https://github.com/postfixadmin/postfixadmin/releases/download/v4.0.5/postfixadmin-v4.0.5-php84.tar.gz
tar xzf postfixadmin-v4.0.5-php84.tar.gz
mv postfixadmin-v4.0.5-php84 /var/www/postfixadmin
mkdir -p /var/www/postfixadmin/templates_c
chown -R www-data:www-data /var/www/postfixadmin
Конфиг /var/www/postfixadmin/config.local.php:
<?php
$CONF['configured'] = true;
$CONF['database_type'] = 'mysqli';
$CONF['database_host'] = 'localhost';
$CONF['database_user'] = 'postfixadmin';
$CONF['database_password'] = 'СИЛЬНЫЙ_ПАРОЛЬ';
$CONF['database_name'] = 'postfixadmin';
$CONF['setup_password'] = 'СГЕНЕРИРУЕТЕ_НА_SETUP.PHP';
// Хеширование: Dovecot-совместимое, современное
$CONF['encrypt'] = 'dovecot:SHA512-CRYPT';
// Структура: /var/vmail/domain/user/Maildir
$CONF['domain_path'] = 'YES';
$CONF['domain_in_mailbox'] = 'NO';
$CONF['default_aliases'] = [
'abuse' => 'hostmaster@example.com',
'hostmaster' => 'hostmaster@example.com',
'postmaster' => 'hostmaster@example.com',
'webmaster' => 'hostmaster@example.com',
];
Apache vhost /etc/apache2/sites-available/postfixadmin.conf — пока HTTP, HTTPS добавим после Let’s Encrypt:
<VirtualHost *:80>
ServerName mail.example.com
DocumentRoot /var/www/postfixadmin/public
<Directory /var/www/postfixadmin/public>
Require all granted
AllowOverride All
</Directory>
</VirtualHost>
a2ensite postfixadmin && a2enmod rewrite && systemctl reload apache2
Откройте http://mail.example.com/setup.php, сгенерируйте setup_password (двухэтапно: сначала setup-хеш, потом админ). После создания админа зайдите в /postfixadmin/ и создайте домен example.com.
Парольный хеш:
dovecot:SHA512-CRYPTтребует установленногоdoveadm(он придёт с dovecot-core). Postfixadmin сохранит хеш вида{SHA512-CRYPT}$6$....
Фаза 3. Postfix
3.1 MySQL-lookup файлы
/etc/postfix/mysql-virtual-mailbox-domains.cf:
user = postfixadmin
password = СИЛЬНЫЙ_ПАРОЛЬ
hosts = 127.0.0.1
dbname = postfixadmin
query = SELECT 1 FROM domain WHERE domain='%s' AND active='1'
/etc/postfix/mysql-virtual-mailbox-maps.cf:
user = postfixadmin
password = СИЛЬНЫЙ_ПАРОЛЬ
hosts = 127.0.0.1
dbname = postfixadmin
query = SELECT 1 FROM mailbox WHERE username='%s' AND active='1'
/etc/postfix/mysql-virtual-alias-maps.cf:
user = postfixadmin
password = СИЛЬНЫЙ_ПАРОЛЬ
hosts = 127.0.0.1
dbname = postfixadmin
query = SELECT goto FROM alias WHERE address='%s' AND active='1'
/etc/postfix/mysql-virtual-email2email.cf:
user = postfixadmin
password = СИЛЬНЫЙ_ПАРОЛЬ
hosts = 127.0.0.1
dbname = postfixadmin
query = SELECT goto FROM alias WHERE address='%s' AND active='1'
chmod 640 /etc/postfix/mysql-*.cf
chown root:postfix /etc/postfix/mysql-*.cf
3.2 main.cf (ключевые параметры)
myhostname = mail.example.com
mydomain = example.com
myorigin = $mydomain
inet_interfaces = all
inet_protocols = ipv4
mydestination = localhost
mynetworks = 127.0.0.0/8 [::1]/128
relay_domains =
compatibility_level = 3.6
# Виртуальные домены/ящики
virtual_mailbox_domains = mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf
virtual_mailbox_maps = mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf
virtual_alias_maps = mysql:/etc/postfix/mysql-virtual-alias-maps.cf,
mysql:/etc/postfix/mysql-virtual-email2email.cf
# Доставка через Dovecot LMTP
virtual_transport = lmtp:unix:private/dovecot-lmtp
# TLS
smtpd_tls_cert_file = /etc/letsencrypt/live/mail.example.com/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/mail.example.com/privkey.pem
smtpd_tls_security_level = may
smtp_tls_security_level = may
smtpd_tls_protocols = >=TLSv1.2
smtpd_tls_mandatory_protocols = >=TLSv1.2
# SASL через Dovecot
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
smtpd_sasl_security_options = noanonymous
smtpd_sasl_tls_security_options = noanonymous
# Restricts
smtpd_relay_restrictions = permit_mynetworks,
permit_sasl_authenticated,
defer_unauth_destination
smtpd_recipient_restrictions = permit_mynetworks,
permit_sasl_authenticated,
reject_unauth_destination
smtpd_helo_required = yes
# DKIM (добавим после настройки opendkim)
milter_default_action = accept
milter_protocol = 6
smtpd_milters = inet:localhost:8891
non_smtpd_milters = inet:localhost:8891
3.3 master.cf — включить submission 587 и smtps 465
Раскомментируйте/пропишите:
submission inet n - y - - smtpd
-o syslog_name=postfix/submission
-o smtpd_tls_security_level=encrypt
-o smtpd_sasl_auth_enable=yes
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
-o smtpd_relay_restrictions=permit_sasl_authenticated,reject
smtps inet n - y - - smtpd
-o syslog_name=postfix/smtps
-o smtpd_tls_wrappermode=yes
-o smtpd_sasl_auth_enable=yes
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
-o smtpd_relay_restrictions=permit_sasl_authenticated,reject
postfix check
systemctl restart postfix
Фаза 4. Dovecot
4.1 /etc/dovecot/dovecot-sql.conf.ext
driver = mysql
connect = host=127.0.0.1 dbname=postfixadmin user=postfixadmin password=СИЛЬНЫЙ_ПАРОЛЬ
default_pass_scheme = SHA512-CRYPT
password_query = \
SELECT username AS user, password \
FROM mailbox WHERE username = '%u' AND active = '1'
user_query = \
SELECT '/var/vmail/%d/%n' AS home, 5000 AS uid, 5000 AS gid \
FROM mailbox WHERE username = '%u' AND active = '1'
4.2 /etc/dovecot/conf.d/10-mail.conf
mail_location = maildir:/var/vmail/%d/%n/Maildir
mail_uid = vmail
mail_gid = vmail
first_valid_uid = 5000
first_valid_gid = 5000
mail_privileged_group = vmail
4.3 /etc/dovecot/conf.d/10-auth.conf
disable_plaintext_auth = yes
auth_mechanisms = plain login
!include auth-sql.conf.ext
(в auth-sql.conf.ext должно быть раскомментировано только !include /etc/dovecot/dovecot-sql.conf.ext)
4.4 /etc/dovecot/conf.d/10-ssl.conf
ssl = required
ssl_cert = </etc/letsencrypt/live/mail.example.com/fullchain.pem
ssl_key = </etc/letsencrypt/live/mail.example.com/privkey.pem
ssl_min_protocol = TLSv1.2
4.5 /etc/dovecot/conf.d/10-master.conf — сокеты для Postfix
service auth {
unix_listener /var/spool/postfix/private/auth {
mode = 0660
user = postfix
group = postfix
}
}
service lmtp {
unix_listener /var/spool/postfix/private/dovecot-lmtp {
mode = 0600
user = postfix
group = postfix
}
}
service imap-login {
inet_listener imap {
port = 143
}
inet_listener imaps {
port = 993
ssl = yes
}
}
4.6 /etc/dovecot/conf.d/20-lmtp.conf
protocol lmtp {
postmaster_address = postmaster@example.com
mail_plugins = $mail_plugins
}
4.7 Права и запуск
chown -R vmail:vmail /var/vmail
chmod -R 770 /var/vmail
# ВАЖНО: AppArmor может блокировать /var/vmail
# Проверьте /etc/apparmor.d/usr.sbin.dovecot — добавьте /var/vmail/** rwk
systemctl restart dovecot
systemctl restart postfix
Проверить, что /var/spool/postfix/private/auth и dovecot-lmtp появились.
Фаза 5. Let’s Encrypt
# Сначала убедитесь, что DNS уже работает
certbot --apache -d mail.example.com --agree-tos -m admin@example.com --redirect
Cron уже настроен пакетом certbot на автопродление. После получения сертификатов перезапустите postfix и dovecot (или настройте deploy-hook):
cat > /etc/letsencrypt/renewal-hooks/deploy/10-mail.sh <<'EOF'
#!/bin/sh
systemctl reload postfix dovecot
EOF
chmod +x /etc/letsencrypt/renewal-hooks/deploy/10-mail.sh
Фаза 6. DKIM + SPF + DMARC
6.1 OpenDKIM
mkdir -p /etc/opendkim/keys/example.com
opendkim-genkey -b 2048 -d example.com -s mail -D /etc/opendkim/keys/example.com
chown -R opendkim:opendkim /etc/opendkim/keys
/etc/opendkim.conf:
Domain example.com
KeyTable /etc/opendkim/key.table
SigningTable refile:/etc/opendkim/signing.table
ExternalIgnoreList /etc/opendkim/trusted.hosts
InternalHosts /etc/opendkim/trusted.hosts
Socket inet:8891@localhost
PidFile /run/opendkim/opendkim.pid
Mode sv
UserID opendkim:opendkim
/etc/opendkim/key.table:
mail._domainkey.example.com example.com:mail:/etc/opendkim/keys/example.com/mail.private
/etc/opendkim/signing.table:
*@example.com mail._domainkey.example.com
/etc/opendkim/trusted.hosts:
127.0.0.1
::1
localhost
systemctl enable --now opendkim
6.2 DNS-записи
Возьмите содержимое /etc/opendkim/keys/example.com/mail.txt и опубликуйте TXT на ДНС:
mail._domainkey.example.com TXT "v=DKIM1; k=rsa; p=MIIBIjANBg..."
SPF:
example.com TXT "v=spf1 mx ~all"
DMARC (начните с p=none, через пару недель можно переключить на quarantine):
_dmarc.example.com TXT "v=DMARC1; p=none; rua=mailto:dmarc@example.com; adkim=s; aspf=s"
Фаза 7. RoundCube
cd /tmp
wget https://github.com/roundcube/roundcubemail/releases/download/1.6.20/roundcubemail-1.6.20-complete.tar.gz
tar xzf roundcubemail-1.6.20-complete.tar.gz
mv roundcubemail-1.6.20 /var/www/roundcube
chown -R www-data:www-data /var/www/roundcube
Инициализировать схему БД:
bash
mysql -u root -p roundcube < /var/www/roundcube/SQL/mysql.initial.sql
Apache vhost /etc/apache2/sites-available/roundcube.conf:
Тут после получения сертификата перейдите на https, а пока
<VirtualHost *:80>
ServerName webmail.example.com
DocumentRoot /var/www/roundcube
<Directory /var/www/roundcube>
Require all granted
AllowOverride All
</Directory>
</VirtualHost>
Сконфигурируйте через http://webmail.example.com/installer/ (создайте config/config.inc.php), ключевые параметры:
db_dsnw—mysql://roundcube:ПАРОЛЬ@localhost/roundcubedefault_host—ssl://mail.example.comsmtp_server—ssl://mail.example.com(порт 465) илиtls://mail.example.com(587)imap_conn_options/smtp_conn_options— при self-signed (пока нет LE) поставитьverify_peer => false
После сохранения конфига удалите каталог installer:
rm -rf /var/www/roundcube/installer
Затем certbot --apache -d webmail.example.com.
Фаза 8. Firewall и защита
ufw allow 22/tcp
ufw allow 80,443/tcp
ufw allow 25,465,587/tcp
ufw allow 143,993/tcp
ufw enable
Fail2ban (крайне рекомендуется — защита от перебора):
apt install fail2ban
# /etc/fail2ban/jail.d/mail.conf
[dovecot]
enabled = true
maxretry = 5
findtime = 600
bantime = 3600
[postfix-sasl]
enabled = true
maxretry = 5
findtime = 600
bantime = 3600
Фаза 9. Тестирование
# 1. Проверить, что виртуальный домен и ящик видны Postfix
postmap -q example.com mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf
postmap -q user@example.com mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf
# 2. Логин через Dovecot
doveadm auth test user@example.com пароль
# 3. Отправка через swaks (apt install swaks)
swaks --to test@gmail.com --from user@example.com \
--server localhost:587 --auth LOGIN \
--auth-user user@example.com --auth-password пароль \
--tls
# 4. Приём снаружи — напишите на user@example.com из Gmail, проверьте /var/log/mail.log
# 5. Проверка DKIM/SPF/DMARC — отправьте письмо на check-auth@verifier.port25.com
Проверить «здоровье» домена: https://www.mail-tester.com (даёт оценку 0–10).
Фаза 10. Backup
Три вещи, которые надо бэкапить:
- MySQL —
mysqldump postfixadmin roundcube - Почта —
/var/vmail/(rsync / restic / borg) - Конфиги —
/etc/postfix /etc/dovecot /etc/opendkim /etc/letsencrypt
Пример cron:
0 3 * * * mysqldump --single-transaction postfixadmin roundcube | gzip > /backup/sql-$(date +\%F).sql.gz
30 3 * * * rsync -a --delete /var/vmail/ /backup/vmail/
Что важно помнить про репутацию
- PTR обязателен, иначе отправленные письма на Gmail/Яндекс/Outlook будут в спаме.
- HELO = mail.example.com, должно совпадать с PTR.
- SPF, DKIM, DMARC — без всех трёх в 2024+ крупные провайдеры режут письма.
- Не отправляйте массовые рассылки с этого сервера — репутация IP упадёт.
- Проверьте IP на blacklist: https://mxtoolbox.com/blacklists.aspx (особенно если IP «унаследован» вместе с арендой сервера).
- Для 50+ ящиков имеет смысл рассмотреть rspamd вместо opendkim — он даёт DKIM + антиспам + antivirus (ClamAV) в одном и более гибко настраивается. Но это отдельный шаг.
