메일 서버 구축하기

도메인이 있어서 무엇을 할 수 있을까 고민하다가 나만의 메일 서버가 있었으면 좋겠다는 생각이 들어 메일 서버 구축에 들어갔습니다. 메일 서버를 구축할 때 사용되는 프로그램은 postfix, opendkim, policyd-spf 그리고 dovecot입니다.

postfix

postfix logo

💡 Tips : Postfix 는 전자우편의 경로를 지정하고 전달하는 자유 오픈 소스 메일 전송 에이전트이다. wikipedia

이메일은 SMTP1) 프로토콜을 사용하여 메일 서버끼리 메일을 주고받습니다.

Install ⚙️

대부분의 리눅스 배포판에 패키지 관리자가 있습니다. 이를 이용하여 설치하면 쉽고 간단하게 설치할 수 있습니다. 설치 패키지는 아래와 같습니다.

  1. postfix

저는 Debian 11을 사용하고 패키지 관리자 apt를 사용하여 설치했습니다.

1
2
3
4
5
6
❯ apt install postfix
패키지 목록을 읽는 중입니다... 완료
의존성 트리를 만드는 중입니다... 완료
상태 정보를 읽는 중입니다... 완료
postfix is already the newest version (3.5.17-0+deb11u1).
0개 업그레이드, 0개 새로 설치, 0개 제거 및 0개 업그레이드 안 함.

Setting 💻

Port open

SMTP는 25번 포트를 사용합니다. 따라서 공유기 및 방화벽 설정이 필요합니다. 공유기는 포트포워딩2)을 이용해 공인 IP 25번 포트로 들어오는 데이터를 내부 IP 25번 포트로 설정하고 iptables 또는 firewall을 사용하신다면 각 방화벽에 맞는 명령어를 사용해 예외 처리해 주시면 됩니다.

💡 Tips SSL3)을 통해 메일을 주고받으려면 456번 포트도 Open해야 합니다.

/etc/postfix/master.cf

주석으로 처리된 미리 쓰여진 설정들이 있는데 필요한 설정을 주석 해제하여 활성화 합니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
smtp      inet  n       -       n       -       -       smtpd

submission inet n       -       n       -       -       smtpd
    -o syslog_name=postfix/submission
    -o smtpd_tls_security_level=encrypt
    -o smtpd_sasl_auth_enable=yes
    -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 milter_macro_daemon_name=ORIGINATING

policyd-spf unix - n n - - spawn
  user=nobody argv=/usr/bin/policyd-spf

/etc/postfix/main.cf

example.kr 도메인을 본인의 도메인으로 기입해 주세요.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# mail setting
smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
myhostname = example.kr
mydomain = example.kr
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
myorigin = $mydomain
mydestination = $myhostname, example.kr, example.example.kr, localhost.example.kr, localhost
relay_domains = $mydestination
relayhost =
mynetworks_style = host
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
mailbox_size_limit = 0
message_size_limit = 0
recipient_delimiter = +
inet_interfaces = all
inet_protocols = all
home_mailbox = Maildir/

# SSL setting
smtp_use_tls = yes
smtp_tls_security_level=may
smtp_tls_note_starttls_offer = yes
smtpd_use_tls = yes
smtpd_tls_cert_file=/etc/letsencrypt/live/example.kr/fullchain.pem
smtpd_tls_key_file=/etc/letsencrypt/live/example.kr/privkey.pem
smtpd_tls_security_level=may
smtpd_tls_loglevel = 1
smtpd_tls_received_header = yes

# 여기서부터는 opendkim과 dovecot의 추가 설정입니다.
# opendkim milter setting
smtpd_milters = inet:localhost:8891
non_smtpd_milters = $smtpd_milters
milter_default_action = accept
milter_protocol = 2
smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination, check_policy_service unix:private/policyd-spf

# dovecot cyrus setting
smtpd_sasl_path = private/auth
smtpd_sasl_type = dovecot
smtpd_sasl_auth_enable = yes
broken_sasl_auth_clients = yes
smtpd_sasl_security_options = noanonymous

Test 🧪

이제 postfix 서버를 켜서 telnet으로 아래 스크립트와 같이 테스트해볼 수 있습니다.

telnet example.kr 25 으로 연결한 후 helo example.kr을 프롬프트하여 error code가 250이 나오는지 확인하세요!

ehlo example.kr을 프롬프트하면 상세한 정보가 나옵니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
❯ telnet example.kr 25
Trying 127.0.1.1...
Connected to example.kr.
Escape character is '^]'.
220 example.kr ESMTP Postfix (Debian/GNU)
helo example.kr
250 example.kr
ehlo example.kr
250-example.kr
250-PIPELINING
250-SIZE
250-VRFY
250-ETRN
250-STARTTLS
250-AUTH PLAIN LOGIN CRAM-MD5
250-AUTH=PLAIN LOGIN CRAM-MD5
250-ENHANCEDSTATUSCODES
250-8BITMIME
250-DSN
250-SMTPUTF8
250 CHUNKING

이렇게 메일 서버 postfix 구축은 끝이 났습니다. 하지만 이메일을 보내거나 받을 때 이처럼 서버에 접속하여 CLI환경에서 보낼 순 없겠죠?

또한 이메일의 Raw text는 사람이 보기 힘들 정도로 많은 양의 데이터와 알 수 없는 정보들이 가득합니다.

이메일 원본

저희는 메일의 제목과 송/수신자, 내용만 보면 되잖아요. 예쁘게 html으로 쓰인 내용을 달라

다행히 이메일 클라이언트4)는 이런 사용자의 요구에 맞게 예쁘게 잘 포장하여 이메일을 보여준답니다. 이런 이메일 클라이언트를 사용하려면 또 다른 서버가 필요합니다. 그것이 Dovecot

opendkim

메일을 주고받을 때 서명이라는 개념이 들어갑니다. 해당 메일이 인증된 도메인과 메일 서버에서 송신을 했는가 확인하는 것인데 이와 같은 서명이 들어가지 않는다면 대부분 메일 서버는 해당 메일을 스팸으로 간주하고 버려지거나 스팸 보관함에 넣습니다. 이런 불상사를 막기 위해 opendkim을 이용해서 메일을 보낼 때 자동으로 서명을 할 수 있게 설정할 겁니다!

install

아래 패키지를 설치합니다.

  1. postfix-policyd-spf-perl
  2. postfix-policyd-spf-python
  3. opendkim

setting

Key 생성하기

명령어를 프롬프트 하여 도메인과 매핑되는 키를 생성합니다.

opendkim-genkey -D /etc/opendkim/keys/example.kr -d example.kr -s domainkey

💡 Tips

-D Key path

-d Domain

-s Domain key 임의로 변경해 주세요.

만약 도메인 주소를 관리하는 사이트에서 Key 값이 너무 길어 텍스트 레코드 설정이 안되는 경우 -b 1024 옵션을 넣어 짧게 만들 수도 있습니다.

키 생성 후 키 파일의 소유권을 opendkim:opendkim으로 설정합니다.

/etc/opendkim.conf

아래 내용이 주석 처리되어 있으면 해제하고 없으면 추가해 주세요.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
AutoRestart Yes
AutoRestartRate 10/1h
Canonicalization relaxed/simple
ExternalIgnoreList refile:/etc/opendkim/TrustedHosts
InternalHosts refile:/etc/opendkim/TrustedHosts
KeyTable refile:/etc/opendkim/KeyTable
LogWhy Yes
Mode sv
PidFile /var/run/opendkim/opendkim.pid
SignatureAlgorithm rsa-sha256
SigningTable refile:/etc/opendkim/SigningTable
Socket inet:8891@localhost
Syslog Yes
SyslogSuccess Yes
TemporaryDirectory /var/tmp
UMask 022
UserID opendkim:opendkim

/etc/opendkim/TrustedHosts

1
2
3
127.0.0.1
localhost
example.kr

/etc/opendkim/KeyTable

1
pointer._domainkey.example.kr example.kr:pointer:/etc/opendkim/keys/example.kr/pointer.private

/etc/opendkim/SigningTable

1
*@example.kr pointer._domainkey.example.kr

DNS 설정

White domain 신청

이 곳에서 신청할 수 있습니다. 약 일주일 정도의 시간이 소요됩니다.

domain 레코드 등록

보통 도메인 등록 업체에서 Name server도 제공해 주는 경우가 많습니다. 저 같은 경우 HostingKR에서 구매했고 Name server도 해당 업체에서 기본으로 제공해 주는 것을 사용하고 있습니다.

바로 Name server에 특정 레코드를 추가해야 합니다. 모든 추가 레코드 유형은 TXT입니다.

  1. SPF5) 레코드
    • @ : "v=spf1 mx ip4:메일 서버 IP -all"
  2. opendkim 레코드
    • _dmarc : "v=DMARC1; p=reject adkim=s aspf=s; sp=reject"
    • domainkey._domainkey : KeyTable 내용

dovecot

dovecot logo

💡 Tips : Dovecot is an open-source IMAP and POP3 server for Unix-like operating systems, written primarily with security in mind.

이메일 클라이언트는 POP36) 또는 IMAP7) 라는 프로토콜을 사용하여 메일 서버와 이메일 클라이언트가 정보를 주고받습니다. 이 글에서 IMAP프로토콜 + SSL을 이용할 계획이며 포트는 993번을 사용합니다.

ProtocolMail update methodExplanation
POP3Export to local메일 서버에 있는 정보를 로컬로 내보냅니다.
내보내기 후 메일 서버의 메일은 삭제됩니다.
IMAPSynchronization메일 서버의 정보를 그대로 보여줍니다.
로컬에서 삭제하면 메일 서버의 메일도 삭제됩니다.

Install

마찬가지로 패키지 관리자를 이용하여 설치합니다. 설치할 패키지는 아래와 같습니다.

  1. dovecot-core
  2. dovecot-imapd
  3. cyrus-imapd
  4. cyrus-common

Setting

/etc/dovecot/dovecot.conf

사용할 프로토콜 IMTP사용을 위해 주석이 되어 있다면 해제해 주세요. Debian 11의 경우 /usr/share/dovecot/protocols.d/imapd.protocol 파일이 include되어있어 따로 설정할 것은 없었습니다.

/etc/dovecot/conf.d/10-auth.conf

아래 내용의 주석을 해제해 주세요.

1
2
3
4
5
6
disable_plaintext_auth = yes
    ...
auth_mechanisms = plain login cram-md5
    ...
!include auth-system.conf.ext
!include auth-checkpassword.conf.ext

/etc/dovecot/conf.d/10-master.conf

아래 코드의 주석을 찾아 수정해주세요.

1
2
3
4
5
6
# Postfix smtp-auth
  unix_listener /var/spool/postfix/private/auth {
    mode = 0660
        user = postfix
        group = postfix
  }

/etc/dovecot/conf.d/10-mail.conf

아래 코드를 찾아 수정해주세요.

1
mail_location = maildir:~/Maildir

/etc/dovecot/conf.d/10-ssl.conf

보안 연결을 위한 설정이며 letsencrypt 또는 다른 기관으로부터 받은 인증서를 설정해 주세요.

1
2
3
ssl = yes
ssl_cert = </etc/letsencrypt/live/example.kr/fullchain.pem
ssl_key = </etc/letsencrypt/live/example.kr/privkey.pem

/etc/dovecot/conf.d/auth-checkpassword.conf.ext

로그인 암호화 관련 설정입니다. 아래와 같이 설정해주세요.

1
2
3
4
passdb {
  driver = passwd-file
  args = scheme=cram-md5 /etc/dovecot/cram-md5.pwd
}

/etc/dovecot/cram-md5.pwd

Dovecot 접속에 필요한 로그인 정보를 암호화합니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
❯ touch /etc/dovecot/cram-md5.pwd
❯ chmod 0600 /etc/dovecot/cram-md5.pwd

❯ doveadm pw
Enter new password: 
Retype new password: 
{CRAM-MD5}26b633ec8bf9dd526293c5897400bddeef9299fad

❯ cat /etc/dovecot/cram-md5.pwd
username:26b633ec8bf9dd526293c5897400bddeef9299fad

Finish

모든 설치와 설정이 끝났습니다. postfix, opendkim 그리고 dovecot을 부팅이 되면 자동으로 켜지도록 initd 또는 systemd 설정을 해주시고 thunderbird를 설치하여 구축된 메일 서버에 접속 및 테스트를 해보시면 됩니다.

메일 서버 구축이 이렇게 힘든 줄 몰랐습니다. 지식이 없는 상태에서 무작정해보려고 하니 많은 시간과 노력이 들었습니다. 도메인이 있다면 한번쯤 나만의 메일 주소를 가져보는 것도 좋은 것 같고 하나하나 차분히 하시면 충분히 구축하실 수 있다고 생각이 됩니다.

각주

  1. 간이 전자 우편 전송 프로토콜(Simple Mail Transfer Protocol, SMTP)은 인터넷에서 이메일을 보내기 위해 이용되는 프로토콜이다. 사용하는 TCP 포트번호는 25번이다. 상대 서버를 지시하기 위해서 DNS의 MX레코드가 사용된다. wikipedia
  2. 포트 포워딩(영어: port forwarding) 또는 포트 매핑(영어: port mapping)은 컴퓨터 네트워크에서 패킷이 라우터나 방화벽과 같은 네트워크 게이트웨이를 가로지르는 동안 하나의 IP 주소와 포트 번호 결합의 통신 요청을 다른 곳으로 넘겨주는 네트워크 주소 변환(NAT)의 응용이다. wikipedia
  3. 전송 계층 보안(영어: Transport Layer Security, TLS, 과거 명칭: 보안 소켓 레이어/Secure Sockets Layer, SSL)는 컴퓨터 네트워크에 통신 보안을 제공하기 위해 설계된 암호 규약이다. wikipedia
  4. 이메일 클라이언트(또는 MUA[mail user agent])는 전자우편을 읽고 보낼 때 이용하는 컴퓨터 프로그램이다. wikipedia
  5. 메일서버 정보를 사전에 DNS에 공개 등록함으로써 수신자로 하여금 이메일에 표시된 발송자 정보가 실제 메일서버의 정보와 일치하는지를 확인할 수 있도록 하는 인증기술 KISA
  6. 포스트 오피스 프로토콜(Post Office Protocol, POP)은 응용 계층 인터넷 프로토콜 중 하나로, 원격 서버로부터 TCP/IP 연결을 통해 이메일을 가져오는데 사용된다. wikipedia
  7. 인터넷 메시지 접속 프로토콜(IMAP, Internet Message Access Protocol)은 응용 계층 인터넷 프로토콜 중 하나로, 원격 서버로부터 TCP/IP 연결을 통해 이메일을 가져오는데 사용된다. wikipedia