메일 서버 구축
- Postfix와 Dovecot를 활용한 메일 서버 구축
- SMTP - Postfix
- IMAP - Dovecot
- LMTP를 사용하여 로컬 메일 전송
- MySQL을 사용하여 SASL auth login user credential 저장
- bind9를 사용하여 DNS 설정
Configuration
DNS 서버 설정
- 로컬 도메인 설정을 위해 bind를 사용하여 DNS 서버 구축
-
설치
$ dnf install bind -y ... $ systemctl enable --now named
-
설정
/etc/named.conf
- listen-on port 53 { 127.0.0.1; }; + listen-on port 53 { any; }; ... - allow-query { localhost; }; + allow-query { any; };
/etc/named.rfc1912.zones
+ zone "linux.cju" IN { + type master; + file "cju.zone"; + }; + zone "67.0.168.192.in-addr.arpa" IN { + type master; + file "cju.rev"; + };
+ /var/named/cju.zone
$TTL 1D @ IN SOA linux.cju. hostmaster.linux.cju. ( 2024121201 ; serial 1D ; refresh 1H ; retry 1W ; expire 3H ) ; minimum NS ns.linux.cju. A 192.168.0.67 MX 10 mail.linux.cju. ns A 192.168.0.67 mail A 192.168.0.67 www A 192.168.0.67
+ /var/named/cju.rev
$TTL 1D @ IN SOA ns.linux.cju. hostmaster.linux.cju. ( 0 ; serial 1D ; refresh 1H ; retry 1W ; expire 3H ) ; minimum NS ns.linux.cju. PTR linux.cju. PTR ns.linux.cju. PTR mail.linux.cju. PTR www.linux.cju.
MySQL 설정
- 사용자 정보 저장
-
설치
$ dnf install mysql mysql-server ... $ systemctl enable --now mysqld ... $ mysql ... mysql>
-
설정
-
MySQL
ALTER USER 'root'@'localhost' IDENTIFIED BY 'root'; create user 'mailrl'@'%' identified by 'mailrl'; grant all privileges on *.* to 'mailrl'@'%' with grant option; create database myapp; use myapp; create table if not exists users ( username varchar(64) primary key, password varchar(106) not null ); create table if not exists aliases ( source varchar(64) not null, destination varchar(64) not null );
-
bash
$ doveadm pw -s SHA512-CRYPT -p cju {SHA512-CRYPT}$6$0xA0c83AfYxE.5mX$jsJrZ3.zKNmmDWBls7t7Qn/drAHyrapqEGKqWqeCaonCelTIymU8BxZCiZNEPg2FWcnup9AjO/4nGVaqpC.aR. $ doveadm pw -s SHA512-CRYPT -p test {SHA512-CRYPT}$6$C2NsWemSpft6OVPJ$Yfl8H6nS5InTX.LeLe59Zr9u8vWF6dFc6UGcqswdOgPyz/5FxCFGCxQXdTGwMoqWYMYfWoFxueAyusguulPsk0
-
MySQL
insert into users(username,password) values('cju','$6$0xA0c83AfYxE.5mX$jsJrZ3.zKNmmDWBls7t7Qn/drAHyrapqEGKqWqeCaonCelTIymU8BxZCiZNEPg2FWcnup9AjO/4nGVaqpC.aR.'); insert into users(username,password) values('test','$6$C2NsWemSpft6OVPJ$Yfl8H6nS5InTX.LeLe59Zr9u8vWF6dFc6UGcqswdOgPyz/5FxCFGCxQXdTGwMoqWYMYfWoFxueAyusguulPsk0');
-
Postfix 설정
-
설치
$ dnf install postfix postfix-mysql -y ... $ systemctl enable --now postfix
-
설정
/etc/postfix/main.cf
- #myhostname = host.domain.tld + myhostname = mail.linux.cju - #mydomain = domain.tld + mydomain = linux.cju - #myorigin = $mydomain + myorigin = $mydomain - inet_interfaces = localhost + inet_interfaces = all - mydestination = $myhostname, localhost.$mydomain, localhost + mydestination = + biff = no + append_dot_mydomain = no + smtpd_sasl_type = dovecot + smtpd_sasl_path = private/auth + smtpd_sasl_auth_enable = yes + smtpd_sasl_local_domain = $myhostname + virtual_transport = lmtp:unix:private/dovecot-lmtp + virtual_mailbox_domains = $mydomain + virtual_mailbox_maps = mysql:/etc/postfix/mysql-mailbox.cf + virtual_alias_maps = mysql:/etc/postfix/mysql-alias.cf
+ /etc/postfix/mysql-mailbox.cf
user = mailrl password = mailrl hosts = localhost dbname = myapp query = SELECT 1 from users where CONCAT(username, '@', 'linux.cju')='%s';
+ /etc/postfix/mysql-alias.cf
user = mailrl password = mailrl hosts = localhost dbname = myapp query = SELECT destination FROM aliases WHERE source='%s'
/etc/postfix/master.cf
- #submission inet n - n - - smtpd - # -o syslog_name=postfix/submission - # -o smtpd_tls_security_level=encrypt - # -o smtpd_sasl_auth_enable=yes - # -o smtpd_tls_auth_only=yes - # -o smtpd_reject_unlisted_recipient=no + submission inet n - n - - smtpd + -o syslog_name=postfix/submission + -o smtpd_tls_security_level=encrypt + -o smtpd_sasl_auth_enable=yes + -o smtpd_tls_auth_only=yes + -o smtpd_reject_unlisted_recipient=no - # -o smtpd_recipient_restrictions= - # -o smtpd_relay_restrictions=permit_sasl_authenticated,reject - # -o milter_macro_daemon_name=ORIGINATING - #smtps inet n - n - - smtpd - # -o syslog_name=postfix/smtps - # -o smtpd_tls_wrappermode=yes - # -o smtpd_sasl_auth_enable=yes - # -o smtpd_reject_unlisted_recipient=no + -o smtpd_recipient_restrictions= + -o smtpd_relay_restrictions=permit_sasl_authenticated,reject + -o milter_macro_daemon_name=ORIGINATING + smtps inet n - n - - smtpd + -o syslog_name=postfix/smtps + -o smtpd_tls_wrappermode=yes + -o smtpd_sasl_auth_enable=yes + -o smtpd_reject_unlisted_recipient=no - # -o smtpd_recipient_restrictions= - # -o smtpd_relay_restrictions=permit_sasl_authenticated,reject - # -o milter_macro_daemon_name=ORIGINATING + -o smtpd_recipient_restrictions= + -o smtpd_relay_restrictions=permit_sasl_authenticated,reject + -o milter_macro_daemon_name=ORIGINATING
-
적용
$ postfix check # check config error $ postfix reload postfix/postfix-script: refreshing the Postfix mail system
Dovecot 설정
-
설치
$ dnf install dovecot dovecot-mysql -y ... $ systemctl enable --now dovecot
-
설정
- shell
$ mkdir -p /var/mail/linux.cju
/etc/dovecot/dovecot.conf
- #protocols = imap pop3 lmtp submission + protocols = imap pop3 lmtp - #listen = *, :: + listen = *, ::
/etc/dovecot/conf.d/10-mail.conf
- #mail_location = + mail_location = maildir:/var/mail/%d/%n - #mail_privileged_group = + mail_privileged_group = mail - first_valid_uid = 1000 - #last_valid_uid = 0 + first_valid_uid = 8 // $ id mail + last_valid_uid = 8
+ /etc/dovecot/dovecot-sql.conf.ext
driver = mysql connect = host=127.0.0.1 dbname=myapp user=mailrl password=mailrl default_pass_scheme = SHA512-CRYPT user_query = SELECT CONCAT('/var/mail/linux.cju/',username) AS home, 'mail' AS uid, 'mail' AS gid FROM users WHERE username='%n' password_query = SELECT password FROM users WHERE username='%n';
/etc/dovecot/conf.d/10-auth.conf
- #disable_plaintext_auth = yes + disable_plaintext_auth = yes - auth_mechanisms = plain + auth_mechanisms = plain login - !include auth-system.conf.ext - #!include auth-sql.conf.ext + #!include auth-system.conf.ext + !include auth-sql.conf.ext
/etc/dovecot/conf.d/10-master.conf
service lmtp { - unix_listener lmtp { - #mode = 0666 + unix_listener /var/spool/postfix/private/dovecot-lmtp { + mode = 0666 + user = postfix + group = postfix } service auth { unix_listener auth-userdb { - #mode = 0666 - #user = - #group = + mode = 0666 + user = mail + group = mail } # Postfix smtp-auth - #unix_listener /var/spool/postfix/private/auth { - # mode = 0666 - #} + unix_listener /var/spool/postfix/private/auth { + mode = 0660 + user = postfix + group = postfix + } service auth-worker { - #user = root + user = mail }
-
적용
$ doveconf 1>/dev/null # check config error $ doveadm reload
Test
-
SMTP/SMTPS
# SMTP $ telnet mail.linux.cju 25 # SMTPS $ openssl s_client --connect mail.linux.cju:465 ... 220 mail.linux.cju ESMTP Postfix > ehlo linux.cju ... 250-AUTH PLAIN LOGIN ... > auth login 334 VXNlcm5hbWU6 > Y2p1QGxpbnV4LmNqdQ== # echo 'cju@linux.cju' | base64 334 UGFzc3dvcmQ6 > Y2p1 # echo 'cju' | base64 235 2.7.0 Authentication successful > mail from:<cju@linux.cju> 250 2.1.0 Ok > rcpt to:<test@linux.cju> 250 2.1.5 Ok > data 354 End data with <CR><LF>.<CR><LF> > subject:Hello test! > This is cju! > thx.. > . 250 2.0.0 Ok: queued as 3D748B0539 > quit 221 2.0.0 Bye
Image
-
IMAP/IMAPS
# IMAP $ telnet mail.linux.cju 143 # IMAPS $ openssl s_client --connect mail.linux.cju:993 * OK [CAPABILITY IMAP4rev1 SASL-IR LOGIN-REFERRALS ID ENABLE IDLE LITERAL+ AUTH=PLAIN AUTH=LOGIN] Dovecot ready. > a1 login test@linux.cju test a1 OK [CAPABILITY IMAP4rev1 SASL-IR LOGIN-REFERRALS ID ENABLE IDLE SORT SORT=DISPLAY THREAD=REFERENCES THREAD=REFS THREAD=ORDEREDSUBJECT MULTIAPPEND URL-PARTIAL CATENATE UNSELECT CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES WITHIN CONTEXT=SEARCH LIST-STATUS BINARY MOVE SNIPPET=FUZZY PREVIEW=FUZZY PREVIEW STATUS=SIZE SAVEDATE LITERAL+ NOTIFY SPECIAL-USE] Logged in > a2 list "" "*" * LIST (\HasNoChildren) "." INBOX a2 OK List completed (0.001 + 0.000 secs). > a3 examine INBOX * FLAGS (\Answered \Flagged \Deleted \Seen \Draft) * OK [PERMANENTFLAGS ()] Read-only mailbox. * 3 EXISTS * 3 RECENT * OK [UNSEEN 1] First unseen. * OK [UIDVALIDITY 1734058789] UIDs valid * OK [UIDNEXT 2] Predicted next UID a3 OK [READ-ONLY] Examine completed (0.001 + 0.000 secs). > a4 fetch 1 body[] * 1 FETCH (BODY[] {598} Return-Path: <cju@linux.cju> Delivered-To: test@linux.cju Received: from mail.linux.cju by mail.linux.cju with LMTP id cketB5ejW2ckKwAAOJi4uQ (envelope-from <cju@linux.cju>) for <test@linux.cju>; Fri, 13 Dec 2024 12:01:43 +0900 Received: from linux.cju (mail.linux.cju [IPv6:fe80::5054:ff:feb4:5be9]) by mail.linux.cju (Postfix) with ESMTPSA id 51F32AE9C3 for <test@linux.cju>; Fri, 13 Dec 2024 12:01:09 +0900 (JST) subject:Hello test! Message-Id: <20241213030117.51F32AE9C3@mail.linux.cju> Date: Fri, 13 Dec 2024 12:01:09 +0900 (JST) From: cju@linux.cju This is cju! thx.. ) a4 OK Fetch completed (0.001 + 0.000 secs). > a5 logout * BYE Logging out a5 OK Logout completed (0.001 + 0.000 secs).
Image