IT 관련/우분투(Ubuntu) 이것저것

[왕초보] Banana Pi M5 메일 서버 호스팅 A to Z: 4단계 SSL, DKIM, 웹메일, 스팸필터 완벽 설정

islet2 2025. 5. 23. 21:29

 

[왕초보] Banana Pi M5 메일 서버 호스팅 A to Z: 4단계 - 웹메일, SSL 보안, 스팸 철벽 방어 3부까지 메일 송수신 기본 기능을 완성했습니다. 이제는 전문가처럼! SSL/TLS 암호화로 보안을 강화하고, DKIM/DMARC로 메일 신뢰도를 높이며, 웹메일로 편리함까지 더할 차례입니다. 스팸 걱정도 줄여보자고요!

지난 시간에는 Dovecot을 설정하여 메일을 수신하고 Thunderbird와 같은 클라이언트에서 확인할 수 있게 만들었습니다. 하지만 그때 "자체 서명된 인증서" 경고를 보셨을 거예요. 오늘은 이 문제를 해결하고, 더 나아가 스팸 메일로부터 우리 서버를 보호하며, 언제 어디서든 웹 브라우저로 메일을 확인할 수 있는 환경까지 구축해 보겠습니다. 조금 더 전문적인 내용이 포함되지만, 여러분은 이미 잘 해내고 계십니다! 💪

 

1. Let's Encrypt로 SSL/TLS 인증서 자동 발급 및 적용 🛡️

안전한 메일 통신을 위해 가장 먼저 해야 할 일은 SSL/TLS 인증서를 적용하여 모든 데이터를 암호화하는 것입니다. `docker-mailserver`는 무료 SSL/TLS 인증서 발급 기관인 Let's Encrypt를 매우 쉽게 지원합니다.

`docker-compose.yml` 수정:

`~/mailserver/docker-compose.yml` 파일을 열어 다음과 같이 수정합니다.


version: '3.8'

services:
  mailserver:
    image: mailserver/docker-mailserver:latest
    container_name: mailserver_instance
    hostname: mail.aaaaa.org
    domainname: aaaaa.org
    ports:
      - "25:25"
      - "80:80"      # Let's Encrypt HTTP-01 챌린지용 포트 (필수!)
      - "143:143"
      - "587:587"
      - "993:993"
      # - "465:465"  # SMTPS (필요시, 587 STARTTLS 권장)
    volumes:
      - ./config:/tmp/docker-mailserver/
      - ./data:/var/mail/
      - ./state:/var/mail-state/
      - /etc/localtime:/etc/localtime:ro
    environment:
      - SSL_TYPE=letsencrypt             # 변경: SSL 타입을 letsencrypt로
      - LETSENCRYPT_DOMAIN=mail.aaaaa.org  # 추가: 인증서 발급받을 도메인
      - LETSENCRYPT_EMAIL=여러분의이메일@example.com # 추가: Let's Encrypt 알림용 이메일 (실제 사용 중인 주소)
      - ENABLE_SPAMASSASSIN=0            # 우선은 0, 스팸 설정은 나중에
      - ENABLE_CLAMAV=0
      - ENABLE_POSTGREY=0
      - ENABLE_FAIL2BAN=1                # Fail2Ban 활성화 권장 (선택 사항)
      - ONE_DIR=1
      - DMS_DEBUG=0
      - TZ=Asia/Seoul
      # - PERMIT_DOCKER=network
    cap_add:
      - NET_ADMIN # Fail2Ban 등에 필요
    restart: always

  # 여기에 Roundcube 서비스 추가 예정

주요 변경 및 추가 사항:

  • `ports`: `"80:80"`을 추가했습니다. Let's Encrypt가 HTTP-01 방식으로 도메인 소유권을 확인하려면 외부에서 80번 포트로 접근이 가능해야 합니다. 공유기에서 Banana Pi의 80번 포트로 포트 포워딩이 되어 있는지 확인하세요!
  • `environment`:
    • `SSL_TYPE=letsencrypt`: SSL 타입을 `manual`에서 `letsencrypt`로 변경합니다.
    • `LETSENCRYPT_DOMAIN=mail.aaaaa.org`: 인증서를 발급받을 주 도메인(메일 서버 호스트명)을 지정합니다.
    • `LETSENCRYPT_EMAIL=여러분의이메일@example.com`: Let's Encrypt에서 인증서 만료 알림 등을 받을 수 있는 실제 이메일 주소를 입력합니다.
    • `ENABLE_FAIL2BAN=1`: 무차별 대입 공격 등을 막기 위해 Fail2Ban을 활성화하는 것이 좋습니다. (선택 사항)

컨테이너 재시작 및 로그 확인:

수정된 `docker-compose.yml`을 적용하기 위해 컨테이너를 재시작합니다.


cd ~/mailserver
docker-compose down
docker-compose up -d

잠시 후 로그를 확인하여 Let's Encrypt 인증서가 성공적으로 발급되었는지 확인합니다.


docker logs mailserver_instance

로그에 "Certificates /etc/letsencrypt/live/mail.aaaaa.org/fullchain.pem and /etc/letsencrypt/live/mail.aaaaa.org/privkey.pem created." 와 유사한 메시지가 보이면 성공입니다. 인증서는 `~/mailserver/config/letsencrypt/live/mail.aaaaa.org/` 경로에 저장됩니다.

메일 클라이언트 설정 업데이트:

이제 Thunderbird와 같은 메일 클라이언트 설정을 업데이트하여 암호화된 포트를 사용하도록 변경합니다.

  • 받는 서버 (IMAP):
    • 포트: `993`
    • 연결 보안: `SSL/TLS`
  • 보내는 서버 (SMTP):
    • 포트: `587` (동일)
    • 연결 보안: `STARTTLS` (동일하나, 이제 신뢰된 인증서 사용)

이제 연결 시 자체 서명 인증서 경고가 나타나지 않아야 합니다.

⚠️ 포트 80번 문제 해결
Let's Encrypt 인증서 발급/갱신 시점에 외부에서 여러분의 서버 IP (공인 IP)의 80번 포트로 HTTP 접근이 가능해야 합니다. 공유기 설정, ISP 정책(간혹 80번 포트 차단) 등을 확인하세요. 인증서가 이미 발급된 후에는 80번 포트 매핑을 제거해도 되지만, 3개월마다 갱신 시 다시 필요합니다. 계속 열어두거나 갱신 시에만 열도록 관리할 수 있습니다.

 

2. SPF, DKIM, DMARC 설정으로 메일 신뢰도 UP! 📨

내 서버에서 보낸 메일이 스팸으로 처리되지 않고 수신자에게 잘 도착하게 하려면, 그리고 다른 사람이 내 도메인을 사칭하여 메일을 보내는 것을 방지하려면 SPF, DKIM, DMARC 설정을 해야 합니다. 이들은 DNS에 TXT 레코드로 설정합니다.

SPF (Sender Policy Framework) - 복습:

1부에서 이미 기본적인 SPF 레코드를 Cloudflare에 추가했습니다. 다시 한번 확인합니다.

  • 유형: `TXT`
  • 이름: `@` (또는 `aaaaa.org`)
  • 내용: `v=spf1 mx -all` (또는 `v=spf1 a:mail.aaaaa.org -all` 처럼 직접 지정도 가능)

DKIM (DomainKeys Identified Mail):

DKIM은 메일에 디지털 서명을 추가하여 메일이 실제로 해당 도메인에서 발송되었고, 중간에 위변조되지 않았음을 증명합니다. `docker-mailserver`에서 DKIM을 활성화합니다.

1. `docker-compose.yml` 파일의 `mailserver` 서비스 `environment` 섹션에 다음을 추가하거나 수정합니다:


      - ENABLE_OPENDKIM=1
      - DKIM_SELECTOR=mail # 기본값은 mail, 변경 가능

2. 컨테이너를 재시작합니다: `docker-compose down && docker-compose up -d`

3. DKIM 키가 생성될 때까지 잠시 기다린 후 (로그에서 확인 가능), 호스트에서 DNS에 추가할 TXT 레코드 값을 확인합니다. 기본 경로는 `~/mailserver/config/opendkim/keys/aaaaa.org/mail.txt` 입니다. (`DKIM_SELECTOR`를 `mail`로 가정)


cat ~/mailserver/config/opendkim/keys/aaaaa.org/mail.txt

출력된 내용 (예: `mail._domainkey IN TXT "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQ...DAQAB"`)을 복사합니다.

4. Cloudflare DNS 설정에서 새 TXT 레코드를 추가합니다:

  • 유형: `TXT`
  • 이름: `mail._domainkey` (`DKIM_SELECTOR`가 `mail`인 경우)
  • 내용: 위에서 복사한 값 (예: `"v=DKIM1; k=rsa; p=MIGfM..."`) 큰따옴표 포함 또는 제외하고 입력 (Cloudflare UI에 따라 다름)

DMARC (Domain-based Message Authentication, Reporting, and Conformance):

DMARC는 SPF와 DKIM 검사 결과를 바탕으로, 인증에 실패한 메일을 어떻게 처리할지 (예: 격리, 거부) 도메인 소유자가 정책을 설정할 수 있게 합니다. 또한 보고 기능을 통해 내 도메인 이름으로 발송되는 메일 현황을 파악할 수 있습니다.

1. DMARC 보고서를 받을 이메일 주소를 만듭니다. (예: `dmarc-reports@aaaaa.org`). 이 주소는 실제 메일박스이거나 별칭일 수 있습니다. `docker-mailserver`를 사용한다면 `user-patches.sh` 등을 활용하거나, 2부에서 배운 `postfix-accounts.cf`에 추가하거나 `docker exec -ti mailserver_instance setup email add dmarc-reports@aaaaa.org somepassword` 명령으로 계정을 만들 수 있습니다.

2. Cloudflare DNS 설정에서 다음 TXT 레코드를 추가합니다:

  • 유형: `TXT`
  • 이름: `_dmarc` (또는 `_dmarc.aaaaa.org`)
  • 내용: `v=DMARC1; p=none; rua=mailto:dmarc-reports@aaaaa.org; ruf=mailto:dmarc-reports@aaaaa.org; fo=1`
    • `p=none`: 처음에는 `none` (모니터링만)으로 시작하여, 점차 `quarantine` (격리), `reject` (거부)로 강화합니다.
    • `rua=mailto:...`: 집계 보고서를 받을 이메일 주소.
    • `ruf=mailto:...`: 포렌식(실패 상세) 보고서를 받을 이메일 주소.
💡 DNS 전파 시간 & 테스트
새로운 DNS 레코드(DKIM, DMARC)가 전파되려면 시간이 걸릴 수 있습니다. 설정 후 MXToolbox와 같은 온라인 도구를 사용하여 SPF, DKIM, DMARC 레코드가 올바르게 설정되었는지 확인하고, 메일을 보내 테스트해 보세요. (예: mail-tester.com)

 

3. 웹메일 (Roundcube) 설치 및 설정 🌐

터미널이나 메일 클라이언트 없이 웹 브라우저만으로 메일을 확인하고 싶다면 웹메일이 필요합니다. 여기서는 인기 있는 오픈소스 웹메일인 Roundcube를 설치합니다. Roundcube는 별도의 Docker 컨테이너로 실행하고 `docker-mailserver`와 연동합니다.

`docker-compose.yml`에 Roundcube 서비스 추가:

`~/mailserver/docker-compose.yml` 파일에 다음 `roundcube` 서비스 정의를 추가합니다. `mailserver` 서비스와 같은 레벨에 추가합니다.


# ... (mailserver 서비스 정의 위 또는 아래) ...

  roundcube:
    image: roundcube/roundcubemail:latest
    container_name: roundcube_instance
    restart: always
    ports:
      - "8080:80" # 호스트의 8080 포트를 Roundcube 컨테이너의 80 포트로 연결
    volumes:
      - ./roundcube_data:/var/roundcube/config # 설정 파일 등 데이터 보존
      - ./roundcube_logs:/var/log/roundcube   # 로그 보존 (선택 사항)
    environment:
      - ROUNDCUBEMAIL_DEFAULT_HOST=ssl://mailserver_instance # IMAP 서버 (SSL/TLS 사용)
      - ROUNDCUBEMAIL_DEFAULT_PORT=993                       # IMAPS 포트
      - ROUNDCUBEMAIL_SMTP_SERVER=tls://mailserver_instance  # SMTP 서버 (STARTTLS 사용)
      - ROUNDCUBEMAIL_SMTP_PORT=587                          # SMTP Submission 포트
      - ROUNDCUBEMAIL_PLUGINS=archive,zipdownload,managesieve # 필요에 따라 플러그인 추가
      - ROUNDCUBEMAIL_SKIN=elastic                           # 테마 설정 (larry 또는 elastic)
      - TZ=Asia/Seoul
    depends_on:
      - mailserver # mailserver 컨테이너가 먼저 시작되도록 의존성 설정
    networks: # mailserver와 동일한 네트워크 사용 (기본값으로 compose가 생성하는 네트워크)
      default: {}

# networks: (파일 최하단에 추가, 이미 있다면 생략)
#   default:

주요 설정:

  • `ports`: 호스트의 `8080` 포트를 Roundcube 컨테이너의 `80` 포트로 연결합니다. 따라서 웹 브라우저에서 `http://여러분의BananaPi_IP:8080` 또는 `http://mail.aaaaa.org:8080` (DNS 및 포트포워딩 설정 시)으로 접속하게 됩니다.
  • `volumes`: Roundcube 설정 및 데이터를 유지하기 위해 볼륨을 설정합니다. 호스트에 `~/mailserver/roundcube_data` 디렉토리가 생성됩니다.
  • `ROUNDCUBEMAIL_DEFAULT_HOST=ssl://mailserver_instance`: IMAP 서버 주소를 `mailserver_instance` (같은 Docker 네트워크 내의 서비스 이름)로 지정하고, SSL 연결(`ssl://`)을 명시합니다.
  • `ROUNDCUBEMAIL_DEFAULT_PORT=993`: IMAPS 포트.
  • `ROUNDCUBEMAIL_SMTP_SERVER=tls://mailserver_instance`: SMTP 서버 주소를 지정하고, STARTTLS 연결(`tls://`)을 명시합니다.
  • `ROUNDCUBEMAIL_SMTP_PORT=587`: SMTP Submission 포트.
  • `depends_on: [mailserver]`: `mailserver` 컨테이너가 먼저 시작되도록 합니다.

Roundcube 실행 및 접속:


cd ~/mailserver
docker-compose up -d # mailserver 와 roundcube 모두 (재)시작

이제 웹 브라우저를 열고 `http://BananaPi_내부IP:8080` (예: `http://192.168.0.60:8080`) 또는 공유기에서 8080 포트를 포워딩했다면 `http://mail.aaaaa.org:8080`으로 접속합니다. Roundcube 로그인 화면이 나타나면 2부에서 생성한 이메일 계정 (`user1@aaaaa.org`)과 비밀번호로 로그인합니다.

💡 Roundcube HTTPS 접속은?
현재 Roundcube는 HTTP로 접속됩니다. HTTPS로 접속하려면 Nginx Proxy Manager나 Traefik 같은 리버스 프록시를 앞에 두고 SSL 인증서를 적용해야 합니다. 이는 이 가이드의 범위를 벗어나지만, 보안을 위해 장기적으로 고려해볼 만합니다.

 

4. 스팸 필터 (SpamAssassin) 활성화 🚫

원치 않는 스팸 메일을 걸러내기 위해 SpamAssassin을 활성화합니다.

`docker-compose.yml` 수정:

`mailserver` 서비스의 `environment` 섹션에서 `ENABLE_SPAMASSASSIN` 값을 `1`로 변경합니다.


# mailserver 서비스 environment 내부
      - ENABLE_SPAMASSASSIN=1  # 0에서 1로 변경
      # 필요시 추가 옵션:
      # - SA_TAG=5.0             # 스팸으로 간주할 점수 (기본값 5.0)
      # - SA_KILL=10.0           # 이 점수 이상이면 메일 거부 (신중히 사용, 기본값은 비활성)
      # - SA_USER_PREFS=1        # 사용자별 SpamAssassin 설정 허용 여부

컨테이너를 다시 시작합니다: `docker-compose up -d`

이제 수신되는 메일 헤더에 `X-Spam-Status`, `X-Spam-Level` 등의 정보가 추가됩니다. SpamAssassin은 메일을 분석하여 스팸 점수를 매기고, 일정 점수 이상이면 스팸으로 표시합니다. 기본적으로 스팸 메일을 자동으로 삭제하지는 않고, 제목에 `*****SPAM*****`과 같은 태그를 붙이거나 헤더 정보를 추가합니다. 메일 클라이언트나 Roundcube에서 필터 규칙을 만들어 스팸 메일을 특정 폴더로 이동시킬 수 있습니다.

 

4부 마무리 및 다음 단계 예고 📝

정말 엄청난 작업을 해내셨습니다! 이제 여러분의 Banana Pi 메일 서버는 SSL/TLS 암호화 통신을 하고, SPF/DKIM/DMARC로 무장하여 메일 신뢰도를 높였으며, 편리한 웹메일 인터페이스까지 갖추게 되었습니다. 스팸 필터 기본 설정도 마쳤고요. 이 정도면 어디 내놔도 부끄럽지 않은 개인 메일 서버라고 할 수 있겠습니다! 😎

하지만 여기서 멈추지 않습니다! 5부에서는 지금까지 구축한 메일 서버의 유지보수, 백업 전략, 고급 설정 팁, 그리고 발생할 수 있는 문제들에 대한 트러블슈팅 가이드를 다룰 예정입니다. 안정적이고 지속 가능한 나만의 메일 서버 운영을 위한 마지막 여정에 함께해주세요!

💡

4부 핵심 요약: 보안 & 편의기능 UP!

🛡️ SSL/TLS: Let's Encrypt로 통신 암호화 (`SSL_TYPE=letsencrypt`, 포트 80 개방). 클라이언트 설정 변경 (IMAPS 993).
📨 신뢰도 UP: SPF (재확인), DKIM (`ENABLE_OPENDKIM=1`, DNS TXT 레코드 추가), DMARC (DNS TXT 레코드 추가, `p=none` 시작).
🌐 웹메일: Roundcube Docker 컨테이너 추가, `docker-mailserver`와 연동 (IMAPS/SMTPS), 포트 8080 접속.
🚫 스팸차단: SpamAssassin 활성화 (`ENABLE_SPAMASSASSIN=1`) 및 기본 설정.

자주 묻는 질문 (FAQ) ❓

Q: Let's Encrypt 인증서 발급에 실패합니다. (Port 80 관련)
A: 👉 가장 흔한 원인은 외부에서 여러분의 서버 공인 IP의 80번 포트로 접근할 수 없기 때문입니다. 공유기에서 Banana Pi의 80번 포트로 정확히 포트 포워딩이 되었는지, ISP에서 80번 포트를 막고 있지는 않은지 (이 경우 다른 인증 방식을 고려하거나 ISP에 문의), Banana Pi 자체의 방화벽(`ufw`)에서 80번 포트가 열려있는지 확인하세요. `docker logs mailserver_instance`에서 자세한 오류 메시지를 확인하는 것도 중요합니다.
Q: DKIM 설정 후 `mail.txt` 파일 내용이 너무 길어서 DNS TXT 레코드에 다 안 들어갑니다.
A: 👉 DKIM 공개키는 매우 길 수 있습니다. 대부분의 DNS 서비스 제공자는 긴 TXT 레코드를 지원하지만, 간혹 제한이 있을 수 있습니다. Cloudflare의 경우 이 문제를 잘 처리합니다. 만약 다른 DNS 서비스를 사용 중이고 문제가 발생한다면, DNS 서비스 업체에 문의하거나, TXT 레코드를 여러 개의 작은 문자열로 나누어 입력하는 방법 (예: `"..." "..."`)이 통하는지 확인해보세요. `docker-mailserver`는 기본적으로 2048비트 키를 생성하는데, 필요하다면 1024비트 키를 사용하도록 설정을 변경할 수도 있지만 보안 강도는 낮아집니다.
Q: Roundcube 접속 시 IMAP/SMTP 서버에 연결할 수 없다고 나옵니다.
A: 👉 `docker-compose.yml`의 Roundcube 서비스 설정에서 `ROUNDCUBEMAIL_DEFAULT_HOST`와 `ROUNDCUBEMAIL_SMTP_SERVER` 값이 `ssl://mailserver_instance` 및 `tls://mailserver_instance`로 정확히 입력되었는지 확인하세요. `mailserver_instance`는 `docker-mailserver` 컨테이너의 서비스 이름입니다. 두 컨테이너가 동일한 Docker 네트워크에 있어야 합니다 (기본적으로 `docker-compose`가 생성하는 네트워크에 함께 속함). `docker logs roundcube_instance`와 `docker logs mailserver_instance` 로그를 함께 확인하여 오류 원인을 찾아보세요.