Cài đặt Dovecot + Postfix trên CentOS Stream 9: Mail Server IMAP/POP3 bảo mật với SSL/TLS và SELinux

CentOS tutorial - IT technology blog
CentOS tutorial - IT technology blog

Mail server tự host — nhiều người sẽ nói “thôi dùng Google Workspace cho lành”. Nhưng nếu bạn cần kiểm soát hoàn toàn email nội bộ, tuân thủ data residency, hoặc đơn giản muốn hiểu hệ thống email thực sự hoạt động như thế nào — tự dựng vẫn là kỹ năng đáng học.

Mình đã setup mail server trong môi trường production nhiều lần. Lần đau nhất là khi CentOS 8 EOL, mình phải migrate gấp 5 server trong 1 tuần — trong đó có 2 server chạy mail. Bài học lớn nhất từ đợt đó: cấu hình Dovecot + Postfix cần được document cực kỹ, vì migrate mail server mà thiếu config detail là ác mộng thực sự.

So sánh các approach: Chọn MTA và MDA phù hợp

Approach 1: Postfix đơn thuần (SMTP only)

Postfix là MTA (Mail Transfer Agent) — chỉ lo việc gửi/nhận mail giữa các server. Nếu chỉ cần relay mail từ ứng dụng (WordPress gửi email thông báo, cronjob alert), Postfix alone là đủ.

  • Ưu: Đơn giản, ít component, dễ debug
  • Nhược: Không có giao thức IMAP/POP3 — người dùng không thể dùng mail client (Outlook, Thunderbird) để đọc mail trực tiếp

Approach 2: Dovecot + Postfix (tiêu chuẩn cho mail server thực sự)

Postfix nhận/gửi SMTP, Dovecot đảm nhận IMAP/POP3 để mail client kết nối đọc mail. Đây là combo được dùng rộng rãi nhất trong industry — từ shared hosting đến enterprise.

  • Ưu: Đầy đủ chức năng, hiệu năng cao, bảo mật tốt, tài liệu phong phú
  • Nhược: Cần cấu hình nhiều layer — đặc biệt phần SELinux trên CentOS hay làm người mới bí

Approach 3: All-in-one stack (iRedMail, Mailcow, Mailu)

Các stack này gom Postfix + Dovecot + SpamAssassin + Roundcube + web admin vào một script install hoặc Docker Compose.

  • Ưu: Setup nhanh, có web UI quản lý, anti-spam tích hợp sẵn
  • Nhược: Khó customize sâu, khi có lỗi khó debug vì quá nhiều layer — và thường conflict với cấu hình SELinux mặc định của CentOS

Phân tích: Tại sao nên chọn thủ công trên CentOS Stream 9?

Với mail server cho dưới 50 user hoặc môi trường học tập, setup thủ công Dovecot + Postfix giúp bạn hiểu từng layer — đặc biệt phần SELinux trên CentOS thường là “black box” với người mới. Khi gặp sự cố, bạn biết chính xác cần nhìn vào đâu.

Mình chọn CentOS Stream 9 sau trải nghiệm migration khỏi CentOS 8. Stream 9 ổn định hơn tiếng xấu của nó — với mail server không cần bleeding-edge packages, và RHEL compatibility là lợi thế lớn khi cần support enterprise sau này.

Hướng dẫn triển khai từng bước

Bước 1: Cài đặt Postfix và Dovecot

# Update hệ thống trước
sudo dnf update -y

# Cài Postfix và Dovecot
sudo dnf install -y postfix dovecot mailx

# Bật và khởi động dịch vụ
sudo systemctl enable --now postfix
sudo systemctl enable --now dovecot

Bước 2: Cấu hình Postfix

File cấu hình chính: /etc/postfix/main.cf. Mình luôn backup trước khi sửa — thói quen hình thành từ vụ migrate CentOS 8.

sudo cp /etc/postfix/main.cf /etc/postfix/main.cf.bak

Thêm/chỉnh sửa các tham số sau trong /etc/postfix/main.cf:

# Domain mail server
myhostname = mail.example.com
mydomain = example.com
myorigin = $mydomain

# Lắng nghe trên tất cả interfaces
inet_interfaces = all
inet_protocols = ipv4

# Domain nhận mail
mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain

# Mailbox format Maildir (tương thích với Dovecot)
home_mailbox = Maildir/

# SMTP Auth qua Dovecot SASL
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
smtpd_sasl_security_options = noanonymous

# TLS settings
smtpd_tls_cert_file = /etc/pki/tls/certs/mail.example.com.crt
smtpd_tls_key_file = /etc/pki/tls/private/mail.example.com.key
smtpd_use_tls = yes
smtpd_tls_auth_only = yes

# Anti-spam cơ bản
smtpd_recipient_restrictions =
    permit_mynetworks,
    permit_sasl_authenticated,
    reject_unauth_destination

Bước 3: Tạo SSL/TLS Certificate

Production dùng Let’s Encrypt. Lab/test dùng self-signed:

# Self-signed (chỉ cho môi trường test)
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout /etc/pki/tls/private/mail.example.com.key \
  -out /etc/pki/tls/certs/mail.example.com.crt \
  -subj "/C=VN/ST=HCM/L=HoChiMinh/O=Example/CN=mail.example.com"

sudo chmod 600 /etc/pki/tls/private/mail.example.com.key

# Production: dùng Let's Encrypt
sudo dnf install -y certbot
sudo certbot certonly --standalone -d mail.example.com
# Cert sẽ nằm tại /etc/letsencrypt/live/mail.example.com/

Bước 4: Cấu hình Dovecot

Dovecot có cấu trúc config theo thư mục /etc/dovecot/conf.d/ — mỗi file lo một phần. Khá clean so với Postfix monolithic config.

# /etc/dovecot/conf.d/10-mail.conf
mail_location = maildir:~/Maildir

# /etc/dovecot/conf.d/10-auth.conf
disable_plaintext_auth = yes
auth_mechanisms = plain login

# /etc/dovecot/conf.d/10-ssl.conf
ssl = required
ssl_cert = </etc/pki/tls/certs/mail.example.com.crt
ssl_key = </etc/pki/tls/private/mail.example.com.key
ssl_min_protocol = TLSv1.2

Cấu hình SASL socket để Postfix kết nối được vào Dovecot — thêm vào /etc/dovecot/conf.d/10-master.conf:

service auth {
  unix_listener /var/spool/postfix/private/auth {
    mode = 0660
    user = postfix
    group = postfix
  }
}

Bước 5: Xử lý SELinux — Phần hay bị bỏ qua nhất

Đây là điểm đau nhất khi setup mail server trên CentOS. SELinux block rất nhiều thứ mà người mới không ngờ tới, và lỗi thường im lặng — service chạy nhưng kết nối không thông.

Nguyên tắc vàng: Không bao giờ setenforce 0 để “fix” vấn đề trong production. Hãy dùng audit2allow để tạo policy đúng.

# Kiểm tra SELinux có đang block không
sudo ausearch -m avc -ts recent | grep -E 'dovecot|postfix'

# Các boolean cần bật
sudo setsebool -P allow_postfix_local_write_mail_spool 1

# Nếu Dovecot cần access file ngoài thư mục mặc định
sudo restorecon -Rv /etc/pki/tls/
sudo restorecon -Rv /var/spool/postfix/

# Tạo custom policy từ AVC denials (cách mạnh nhất)
sudo ausearch -m avc -ts recent | audit2allow -M postfix_dovecot_local
sudo semodule -i postfix_dovecot_local.pp

# Verify SELinux vẫn Enforcing sau khi fix
getenforce

Mẹo từ đợt migrate CentOS 8: mình xuất audit log từ server cũ, chạy audit2allow để gen policy sẵn, rồi import vào server mới trước khi restart service — tránh được cả buổi debug SELinux.

Bước 6: Mở port trên firewalld

# SMTP
sudo firewall-cmd --permanent --add-service=smtp        # port 25
sudo firewall-cmd --permanent --add-service=smtps       # port 465
sudo firewall-cmd --permanent --add-service=smtp-submission  # port 587

# IMAP và POP3
sudo firewall-cmd --permanent --add-service=imap        # port 143
sudo firewall-cmd --permanent --add-service=imaps       # port 993
sudo firewall-cmd --permanent --add-service=pop3        # port 110
sudo firewall-cmd --permanent --add-service=pop3s       # port 995

sudo firewall-cmd --reload
sudo firewall-cmd --list-services

Bước 7: Tạo user và kiểm tra

# Tạo mail user (không cần login shell)
sudo useradd -m -s /sbin/nologin mailuser
sudo passwd mailuser

# Tạo cấu trúc Maildir
sudo -u mailuser mkdir -p /home/mailuser/Maildir/{cur,new,tmp}

# Restart services
sudo systemctl restart postfix dovecot

# Gửi mail test nội bộ
echo "Test noi dung" | mail -s "Test Subject" [email protected]

# Kiểm tra mail đã vào chưa
sudo ls -la /home/mailuser/Maildir/new/

Xác minh kết nối IMAP và SMTP

# Test IMAP thủ công
telnet localhost 143
# Sau khi kết nối:
a LOGIN mailuser yourpassword
b SELECT INBOX
c LOGOUT

# Test SMTP với TLS (kiểm tra SASL auth)
openssl s_client -connect mail.example.com:587 -starttls smtp

Những lỗi hay gặp và cách xử lý

  • Postfix không nhận mail từ ngoài: Kiểm tra mydestinationinet_interfaces = all — thường quên tham số này
  • Dovecot từ chối login dù đúng password: 90% là SELinux. Chạy ausearch -m avc -ts recent trước khi debug thứ khác
  • Postfix log "SASL authentication failure": Kiểm tra đường dẫn socket trong main.cf (private/auth) khớp với 10-master.conf của Dovecot
  • Mail client báo SSL error: Với self-signed cert là bình thường — trust thủ công hoặc dùng Let’s Encrypt cho production
  • Permission denied trên Maildir: Chạy restorecon -Rv /home/mailuser/ để fix SELinux context

Checklist trước khi đưa vào production

  • systemctl status postfix dovecot — cả hai active và không có warning
  • Port 25, 587, 993, 995 lắng nghe: ss -tlnp | grep -E '25|587|993|995'
  • SELinux ở Enforcing: getenforce phải ra Enforcing
  • Test gửi/nhận mail thành công qua telnet
  • Kết nối từ Thunderbird với IMAPS port 993 thành công
  • Log sạch: sudo tail -f /var/log/maillog không có error liên tục
  • SPF/DKIM/DMARC đã cấu hình trên DNS (bắt buộc để không vào spam)

Mail server thủ công trên CentOS Stream 9 không phải thứ “cắm vào chạy ngay” — nhưng một khi hiểu được từng layer, từ SASL handshake đến SELinux policy, bạn sẽ debug được bất kỳ vấn đề email nào. Và quan trọng hơn, khi buộc phải migrate gấp như mình từng trải qua, bạn sẽ biết chính xác những gì cần backup và document lại.

Share: