Postfix ile Sanal Kullanıcı ve Domain Yönetimi

Bir mail sunucusu kurarken en sık karşılaşılan ihtiyaçlardan biri, tek bir sunucu üzerinde birden fazla domain ve bu domainlere ait sanal kullanıcıları yönetebilmektir. Postfix bu konuda oldukça esnek bir yapı sunar; ancak doğru yapılandırılmadığında işler hızla karmaşık bir hal alabilir. Bu yazıda, Postfix ile sanal domain ve kullanıcı yönetimini adım adım, gerçek dünya senaryolarıyla ele alacağız.

Sanal Kullanıcı Yapısını Anlamak

Postfix’te “sanal” kavramı iki farklı şeyi ifade edebilir. Birincisi virtual alias domains, yani posta kutusuna sahip olmayan, sadece yönlendirme yapan domain yapısıdır. İkincisi ise virtual mailbox domains, yani gerçek posta kutularının tutulduğu yapıdır.

Çoğu senaryoda ihtiyacınız olan şey virtual mailbox yapısıdır. Örneğin sirketA.com ve sirketB.com domainlerini aynı sunucuda barındırmak ve her birinin kullanıcılarına ayrı posta kutuları vermek istiyorsanız, virtual mailbox tam da bu iş için vardır.

Kullanıcılar sistem kullanıcısı olmaz bu yapıda. Yani /etc/passwd dosyasında [email protected] diye bir kayıt görmezsiniz. Postfix, kullanıcı bilgilerini MySQL, PostgreSQL veya düz metin dosyalarından okuyabilir. Biz bu yazıda hem düz dosya hem de MySQL tabanlı yapıyı göstereceğiz.

Ön Hazırlık ve Sistem Gereksinimleri

Ubuntu 22.04 veya Debian 11 üzerinde ilerlediğimizi varsayıyorum. Önce gerekli paketleri yükleyelim:

apt update
apt install postfix postfix-mysql dovecot-core dovecot-imapd dovecot-pop3d 
    dovecot-mysql mysql-server -y

Kurulum sırasında Postfix yapılandırma türü sorulduğunda Internet Site seçin ve sistem mail adı olarak birincil domaininizi girin (örneğin mail.sirketA.com).

Posta kutularını tutacak sistem kullanıcısını ve dizinini oluşturalım. Bu kullanıcı gerçek bir login kullanıcısı olmayacak, sadece dosya sahipliği için kullanılacak:

groupadd -g 5000 vmail
useradd -g vmail -u 5000 vmail -d /var/mail/vhosts -s /sbin/nologin
mkdir -p /var/mail/vhosts
chown vmail:vmail /var/mail/vhosts
chmod 770 /var/mail/vhosts

MySQL Veritabanı Yapısını Kurma

Sanal kullanıcıları ve domainleri veritabanında tutmak, uzun vadede yönetimi çok kolaylaştırır. Özellikle onlarca domain ve yüzlerce kullanıcı söz konusu olduğunda düz dosya yöntemi yetersiz kalır.

CREATE DATABASE postfix_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'postfix_user'@'localhost' IDENTIFIED BY 'GucluBirSifre123!';
GRANT SELECT ON postfix_db.* TO 'postfix_user'@'localhost';
FLUSH PRIVILEGES;

USE postfix_db;

CREATE TABLE virtual_domains (
    id INT NOT NULL AUTO_INCREMENT,
    name VARCHAR(50) NOT NULL,
    PRIMARY KEY (id)
);

CREATE TABLE virtual_users (
    id INT NOT NULL AUTO_INCREMENT,
    domain_id INT NOT NULL,
    password VARCHAR(106) NOT NULL,
    email VARCHAR(100) NOT NULL,
    PRIMARY KEY (id),
    UNIQUE KEY email (email),
    FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE
);

CREATE TABLE virtual_aliases (
    id INT NOT NULL AUTO_INCREMENT,
    domain_id INT NOT NULL,
    source VARCHAR(100) NOT NULL,
    destination VARCHAR(100) NOT NULL,
    PRIMARY KEY (id),
    FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE
);

Şimdi örnek verilerimizi ekleyelim:

INSERT INTO virtual_domains (name) VALUES ('sirketA.com'), ('sirketB.com');

-- Şifre hash'i oluşturmak için: doveadm pw -s SHA512-CRYPT
INSERT INTO virtual_users (domain_id, password, email) VALUES
    (1, '{SHA512-CRYPT}$6$rounds=5000$örnek_hash_buraya', '[email protected]'),
    (1, '{SHA512-CRYPT}$6$rounds=5000$başka_hash', '[email protected]'),
    (2, '{SHA512-CRYPT}$6$rounds=5000$üçüncü_hash', '[email protected]');

INSERT INTO virtual_aliases (domain_id, source, destination) VALUES
    (1, '[email protected]', '[email protected]'),
    (2, '[email protected]', '[email protected]');

Gerçek şifre hash’i oluşturmak için şu komutu kullanın:

doveadm pw -s SHA512-CRYPT
# Komutu çalıştırın, şifreyi girin, çıkan hash'i kopyalayın

Postfix MySQL Sorgularını Yapılandırma

Postfix’in veritabanından okuma yapabilmesi için sorgu dosyaları oluşturmanız gerekiyor. Bu dosyalar /etc/postfix/ altına konur:

# /etc/postfix/mysql-virtual-mailbox-domains.cf
cat > /etc/postfix/mysql-virtual-mailbox-domains.cf << 'EOF'
user = postfix_user
password = GucluBirSifre123!
hosts = 127.0.0.1
dbname = postfix_db
query = SELECT 1 FROM virtual_domains WHERE name='%s'
EOF

# /etc/postfix/mysql-virtual-mailbox-maps.cf
cat > /etc/postfix/mysql-virtual-mailbox-maps.cf << 'EOF'
user = postfix_user
password = GucluBirSifre123!
hosts = 127.0.0.1
dbname = postfix_db
query = SELECT CONCAT(SUBSTRING_INDEX(email,'@',-1),'/',SUBSTRING_INDEX(email,'@',1),'/') FROM virtual_users WHERE email='%s'
EOF

# /etc/postfix/mysql-virtual-alias-maps.cf
cat > /etc/postfix/mysql-virtual-alias-maps.cf << 'EOF'
user = postfix_user
password = GucluBirSifre123!
hosts = 127.0.0.1
dbname = postfix_db
query = SELECT destination FROM virtual_aliases WHERE source='%s'
EOF

Bu dosyaların izinlerini kısıtlayın, içinde şifre var:

chmod 640 /etc/postfix/mysql-virtual-*.cf
chown root:postfix /etc/postfix/mysql-virtual-*.cf

Ana Postfix Yapılandırması

/etc/postfix/main.cf dosyasını düzenleyelim. Mevcut içeriği tamamen değiştirmek yerine ilgili satırları bulup güncelleyin:

# Temel ayarlar
myhostname = mail.sirketA.com
myorigin = /etc/mailname
mydestination = localhost
relayhost =
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = all
inet_protocols = all

# Sanal domain ve kullanıcı ayarları
virtual_transport = lmtp:unix:private/dovecot-lmtp
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

# Sanal posta kutusu için UID/GID
virtual_minimum_uid = 100
virtual_uid_maps = static:5000
virtual_gid_maps = static:5000
virtual_mailbox_base = /var/mail/vhosts

# SMTP Auth için SASL
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
smtpd_sasl_security_options = noanonymous

# TLS ayarları
smtpd_tls_cert_file = /etc/letsencrypt/live/mail.sirketA.com/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/mail.sirketA.com/privkey.pem
smtpd_use_tls = yes
smtpd_tls_security_level = may
smtp_tls_security_level = may

/etc/postfix/master.cf dosyasında submission (587) portunu etkinleştirin:

# master.cf içinde şu satırları uncomment edin veya ekleyin
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

Dovecot Yapılandırması

Dovecot hem IMAP/POP3 sunucusu görevini üstlenecek hem de Postfix ile LMTP üzerinden konuşacak. Temel Dovecot yapılandırmasını düzenleyelim:

# /etc/dovecot/dovecot.conf
protocols = imap pop3 lmtp

# /etc/dovecot/conf.d/10-mail.conf
mail_location = maildir:/var/mail/vhosts/%d/%n
mail_privileged_group = vmail

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

# 10-auth.conf içinde auth-system.conf.ext satırını yorum satırı yapın
# !include auth-system.conf.ext  -> bunu yorum satırı yapın
# Alttaki satırın yorumunu kaldırın:
!include auth-sql.conf.ext

SQL kimlik doğrulama dosyasını oluşturalım:

# /etc/dovecot/conf.d/auth-sql.conf.ext
passdb {
  driver = sql
  args = /etc/dovecot/dovecot-sql.conf.ext
}

userdb {
  driver = static
  args = uid=vmail gid=vmail home=/var/mail/vhosts/%d/%n
}
# /etc/dovecot/dovecot-sql.conf.ext
driver = mysql
connect = host=127.0.0.1 dbname=postfix_db user=postfix_user password=GucluBirSifre123!
default_pass_scheme = SHA512-CRYPT
password_query = SELECT email as user, password FROM virtual_users WHERE email='%u'

Son olarak Dovecot socket ayarlarını Postfix ile uyumlu hale getirin:

# /etc/dovecot/conf.d/10-master.conf içinde
service lmtp {
  unix_listener /var/spool/postfix/private/dovecot-lmtp {
    mode = 0600
    user = postfix
    group = postfix
  }
}

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

Test ve Doğrulama

Yapılandırmayı test etmeden önce servisleri yeniden başlatın:

systemctl restart postfix dovecot
systemctl status postfix dovecot

Postfix’in domain sorgusunu doğru yapıp yapmadığını test edin:

postmap -q "sirketA.com" mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf
# Çıktı: 1 olmalı

postmap -q "[email protected]" mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf
# Çıktı: sirketA.com/ahmet/ olmalı

postmap -q "[email protected]" mysql:/etc/postfix/mysql-virtual-alias-maps.cf
# Çıktı: [email protected] olmalı

Mail gönderme testini yapalım:

# Yerel test için
echo "Test mesaji" | mail -s "Test" [email protected]

# Mail log'larını izleyin
tail -f /var/log/mail.log

SMTP bağlantısını manuel test edebilirsiniz:

telnet mail.sirketA.com 25
# veya
openssl s_client -connect mail.sirketA.com:587 -starttls smtp

Düz Dosya Yöntemi (Küçük Kurulumlar İçin)

Eğer veritabanı kurmak istemiyorsanız ve kullanıcı sayınız azsa, düz metin dosyaları da kullanabilirsiniz. Bu yöntem 10-15 kullanıcıya kadar olan kurulumlar için makul bir seçenek.

# /etc/postfix/virtual_domains
sirketA.com    OK
sirketB.com    OK
# /etc/postfix/virtual_mailbox
[email protected]    sirketA.com/ahmet/
[email protected]   sirketA.com/mehmet/
[email protected]     sirketB.com/ayse/
# /etc/postfix/virtual_aliases
[email protected]      [email protected]
[email protected]    [email protected]

Dosyaları hash’leyin ve main.cf’yi güncelleyin:

postmap /etc/postfix/virtual_domains
postmap /etc/postfix/virtual_mailbox
postmap /etc/postfix/virtual_aliases

# main.cf içinde şu şekilde referans verin:
virtual_mailbox_domains = hash:/etc/postfix/virtual_domains
virtual_mailbox_maps = hash:/etc/postfix/virtual_mailbox
virtual_alias_maps = hash:/etc/postfix/virtual_aliases

Önemli not: Düz dosya yönteminde her değişiklikten sonra postmap komutunu çalıştırmayı ve postfix reload yapmayı unutmayın. Bu adımı atlamak en sık yapılan hatalardan biridir.

Yaygın Sorunlar ve Çözümleri

Posta kutusu dizini oluşturulmuyor: Dovecot’un mail_location ayarındaki dizin yapısı ve vmail kullanıcısının izinlerini kontrol edin.

ls -la /var/mail/vhosts/
# vmail:vmail sahipliği olmalı

“Relay access denied” hatası: Bu hata genellikle virtual_mailbox_domains sorgusunun boş döndüğü anlamına gelir. Veritabanı bağlantısını ve sorguyu kontrol edin:

mysql -u postfix_user -p postfix_db -e "SELECT * FROM virtual_domains;"

SASL auth çalışmıyor: Dovecot auth socket yolunun doğru olduğunu ve izinlerin Postfix tarafından okunabilir olduğunu kontrol edin:

ls -la /var/spool/postfix/private/auth

Log takibi için:

journalctl -u postfix -f
# veya
tail -f /var/log/mail.log | grep -E "error|warning|reject"

Yeni Kullanıcı ve Domain Ekleme

Sistemi kurduktan sonra yeni kullanıcı eklemek oldukça basit. MySQL yöntemiyle:

# Yeni domain ekle
mysql -u root -p postfix_db -e "INSERT INTO virtual_domains (name) VALUES ('sirketC.com');"

# Yeni kullanıcı şifresi oluştur
SIFRE_HASH=$(doveadm pw -s SHA512-CRYPT -p 'KullanicininSifresi')

# Yeni kullanıcı ekle
mysql -u root -p postfix_db -e "
INSERT INTO virtual_users (domain_id, password, email) 
VALUES (
    (SELECT id FROM virtual_domains WHERE name='sirketC.com'),
    '$SIFRE_HASH',
    '[email protected]'
);"

Düz dosya yönteminde ise dosyayı düzenleyip postmap ve postfix reload çalıştırmanız yeterli.

Güvenlik Önerileri

Kurulumu tamamladıktan sonra birkaç önemli güvenlik adımı atmak gerekiyor:

  • Rate limiting: Brute force saldırılarına karşı Fail2ban kurun ve Postfix/Dovecot için jail’ler tanımlayın.
  • SPF, DKIM ve DMARC: DNS kayıtlarınızı mutlaka ekleyin, aksi halde gönderdiğiniz postalar spam kutusuna düşer.
  • TLS zorunluluğu: Submission portu için smtpd_tls_security_level = encrypt ayarını kullanın.
  • Posta kutusu boyutu: mailbox_size_limit ve message_size_limit değerlerini ihtiyacınıza göre ayarlayın.
  • Veritabanı şifresi: Yapılandırma dosyalarındaki şifrelerin sadece root ve postfix kullanıcıları tarafından okunabildiğinden emin olun.
# Fail2ban postfix jail örneği
cat >> /etc/fail2ban/jail.local << 'EOF'
[postfix]
enabled = true
port = smtp,465,submission
filter = postfix
logpath = /var/log/mail.log
maxretry = 5
bantime = 3600

[dovecot]
enabled = true
port = pop3,pop3s,imap,imaps,submission,465,sieve
filter = dovecot
logpath = /var/log/mail.log
maxretry = 5
bantime = 3600
EOF

systemctl restart fail2ban

Sonuç

Postfix ile sanal kullanıcı ve domain yönetimi, ilk bakışta karmaşık görünse de adımları doğru takip ettiğinizde oldukça sağlam ve ölçeklenebilir bir yapı elde ediyorsunuz. MySQL tabanlı yöntem, özellikle birden fazla domain ve çok sayıda kullanıcı söz konusu olduğunda açık ara daha iyi bir yönetim deneyimi sunuyor. Düz dosya yöntemi ise basit ve az kullanıcılı kurulumlar için hala geçerli bir seçenek.

Bu yapının üzerine bir web arayüzü eklemek isterseniz PostfixAdmin projesine bakmanızı öneririm. Hem domain hem kullanıcı yönetimini browser üzerinden yapabiliyorsunuz ve bizim oluşturduğumuz veritabanı şemasıyla uyumlu çalışıyor.

Kurulum sonrasında mutlaka mail akışını gerçek bir adresten test edin, log dosyalarını düzenli takip edin ve özellikle TLS sertifika yenileme süreçlerini otomatize etmeyi unutmayın. Bir mail sunucusu, sertifikası süresi geçmiş olduğunda çok can sıkıcı sorunlar yaratabilir.

Yorum yapın