generated from ttipo/project-base
9466a85daa
엔진의 DNS 조회(DNSBL · SPF · DKIM · DMARC · MX · PTR · TLSA)를 공용 · ISP DNS 가 아니라 이 서버의 리졸버로 푼다. Spamhaus 는 공용 DNS 를 거친 조회를 거부하고, DNSSEC 을 검증해야 엔진의 DANE 이 켜지기 때문이다. - mail-resolver: unbound 1.26.2(digest 고정 · 비-root · cap_drop ALL). mail 과만 닿는 internal 네트워크 mail-dns 와 바깥 길 mail-dns-egress. 사설 주소의 답 · 질의를 막는다. - setup: 바꾸기 전에 리졸버 네트워크 · 주소 · DNSSEC 을 확인한다(UDP 는 루트 SOA, TCP 는 루트 DNSKEY — UDP DNSKEY 는 루트 키 교체 기간에 잘려 오탐이 난다). 엔진 DNS 는 운영 Custom, 개발 System. Spamhaus 키가 있으면 시험 항목을 확인한 뒤 DQS 로 켜고 없으면 두 항목을 끈다. 키는 모든 출력에서 가린다. - mail 은 리졸버를 기다리되(required: false) 리졸버 오류 하나로 메일 전체가 서지 않게 한다. - README: 리졸버와 스팸 차단 목록, 운영 배포 차례, 리졸버 장애 때(리로드 거절 · restart 비상 길), DNSSEC 이 깨진 도메인의 예외. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
90 lines
5.1 KiB
Plaintext
90 lines
5.1 KiB
Plaintext
# ==========================================
|
|
# 메일 엔진 전용 재귀 DNS 리졸버 (unbound) — docker-compose.yml 의 mail-resolver 가 읽는다
|
|
#
|
|
# 엔진(Stalwart)의 DNS 조회 — 스팸 차단 목록(DNSBL) · SPF · DKIM · DMARC · MX · PTR · TLSA(DANE) — 를
|
|
# 공용 · ISP DNS 가 아니라 이 서버에서 루트부터 직접 푼다 (mail/README.md "DNS 리졸버와 스팸 차단 목록").
|
|
# - Spamhaus 는 공용 · ISP DNS 를 거친 조회를 거부한다(127.255.255.254). 이 리졸버는 서버 자신의 공인 IP 로 묻는다
|
|
# - DNSSEC 을 검증한다 — 엔진의 DANE 이 켜진다 (기동 로그 "DNS resolver cannot validate DNSSEC" 가 사라진다)
|
|
#
|
|
# 이미지 klutchell/unbound(distroless — 셸 없음)의 기본 설정을 이 파일로 통째로 바꾼다.
|
|
# compose 가 처음부터 비-root(101:102)로 띄우므로 이 파일은 그 사용자가 읽을 수 있어야 한다(644 — 저장소를 umask 077 로 클론하지 않는다).
|
|
# 바꾼 뒤에는 docker compose … up -d --force-recreate mail-resolver (설정 파일만 바뀌면 compose 가 다시 만들지 않는다)
|
|
# ==========================================
|
|
server:
|
|
# 컨테이너 — 앞에서 돌고, 사용자를 바꾸지 않고(처음부터 비-root), chroot 하지 않는다
|
|
do-daemonize: no
|
|
username: ""
|
|
chroot: ""
|
|
directory: "/var/unbound"
|
|
pidfile: ""
|
|
logfile: ""
|
|
use-syslog: no
|
|
# 1 = 동작 정보와 오류만. 조회 이름은 남기지 않는다 — DNSBL 조회 이름에 Spamhaus DQS 키가 들어간다
|
|
# (log-queries · log-replies · log-servfail · val-log-level 은 기본값(끔) 그대로 둔다)
|
|
verbosity: 1
|
|
|
|
# 받는 곳 — 컨테이너의 53 (UDP · TCP). 엔진은 TCP 도 쓸 수 있어야 DNSSEC 을 믿는다 (Stalwart 의 기동 확인)
|
|
# 이 컨테이너는 메일 엔진과의 전용 네트워크(mail-dns — 바깥 길 없음)와 자기 바깥 조회 길(mail-dns-egress)에만 붙고
|
|
# 호스트 포트를 열지 않는다 — 닿는 것은 메일 엔진뿐이다. (비-root 가 53 에 붙는 것은 도커가 컨테이너마다
|
|
# net.ipv4.ip_unprivileged_port_start=0 으로 두기 때문이다 — 권한(capability)은 모두 뺀다)
|
|
interface: 0.0.0.0
|
|
port: 53
|
|
do-ip4: yes
|
|
do-ip6: no
|
|
do-udp: yes
|
|
do-tcp: yes
|
|
|
|
# 묻는 쪽 — 사설 대역(도커 네트워크)과 자기 자신(healthcheck)만 받는다. 1차 막은 네트워크 구성(메일 엔진만 붙는다)이고, 이것은 그 뒤의 막이다 —
|
|
# 누가 53 을 호스트에 공개해도 바깥(공인 주소)에서 쓰는 열린 리졸버가 되지 않게
|
|
access-control: 0.0.0.0/0 refuse
|
|
access-control: 127.0.0.0/8 allow
|
|
access-control: 10.0.0.0/8 allow
|
|
access-control: 172.16.0.0/12 allow
|
|
access-control: 192.168.0.0/16 allow
|
|
|
|
# DNSSEC 검증 — 루트 신뢰 앵커는 이미지에 든 root.key(KSK-2017 · KSK-2024)다. RFC 5011 로 스스로 고쳐 쓰므로
|
|
# /var/unbound 는 쓸 수 있어야 한다(컨테이너 쓰기 계층 — read_only 로 두지 않는다). 이미지를 올리면 새 파일로 시작한다
|
|
module-config: "validator iterator"
|
|
auto-trust-anchor-file: "/var/unbound/root.key"
|
|
root-hints: "/var/unbound/root.hints"
|
|
harden-dnssec-stripped: yes
|
|
harden-glue: yes
|
|
harden-below-nxdomain: yes
|
|
|
|
# 조회 이름은 필요한 만큼만 위로 보낸다(QNAME minimisation — 기본값) — 루트 · .net 서버는 DQS 키가 든 이름 전체를 보지 못한다
|
|
qname-minimisation: yes
|
|
hide-identity: yes
|
|
hide-version: yes
|
|
|
|
# 사설 · 내부 주소로 풀리는 바깥 이름은 버린다 — 바깥 도메인의 MX 가 이 서버의 사설망(VPC · 도커 네트워크)을 가리켜
|
|
# 엔진이 그쪽으로 메일을 보내는 일이 없게.
|
|
# ⚠️ 127.0.0.0/8 은 넣지 않는다 — 스팸 차단 목록(DNSBL)은 127.0.0.x 로 답한다
|
|
private-address: 10.0.0.0/8
|
|
private-address: 172.16.0.0/12
|
|
private-address: 192.168.0.0/16
|
|
private-address: 169.254.0.0/16
|
|
private-address: 100.64.0.0/10
|
|
private-address: fc00::/7
|
|
private-address: fe80::/10
|
|
|
|
# 리졸버 자신도 사설 · 내부 주소의 DNS 서버에는 묻지 않는다(위 private-address 와 짝) — 바깥 도메인이 이름 서버(NS)의 주소(glue)를
|
|
# 사설 주소로 두어 이 리졸버가 VPC · 호스트 · 도커 네트워크(메일 엔진 포함)의 53 에 묻게 만드는 것을 막는다.
|
|
# 127.0.0.0/8 · ::1 은 기본값(do-not-query-localhost: yes)이 이미 막는다. 이 리졸버는 루트부터 직접 풀어 사설 주소에 물을 일이 없다
|
|
do-not-query-address: 10.0.0.0/8
|
|
do-not-query-address: 172.16.0.0/12
|
|
do-not-query-address: 192.168.0.0/16
|
|
do-not-query-address: 169.254.0.0/16
|
|
do-not-query-address: 100.64.0.0/10
|
|
do-not-query-address: fc00::/7
|
|
do-not-query-address: fe80::/10
|
|
|
|
# 크기 — 메일 서버 하나 몫 (compose 메모리 한도 128m 안)
|
|
num-threads: 1
|
|
msg-cache-size: 8m
|
|
rrset-cache-size: 16m
|
|
edns-buffer-size: 1232
|
|
so-rcvbuf: 0
|
|
so-sndbuf: 0
|
|
prefetch: yes
|
|
prefetch-key: yes
|