generated from ttipo/project-base
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b43b747107 | |||
| 34d63cf740 | |||
| e664217485 |
+56
-20
@@ -1318,6 +1318,7 @@ alias dcx='docker compose exec postfix-mailcow'
|
||||
1. **postscreen 예외** — `data/conf/postfix/custom_postscreen_whitelist.cidr` 에 `<MX1_IP>/32 permit` (재시작 없이 다시 읽는다). 새 IP 가 차단 목록 하나에만 있어도 postscreen 에서 끊길 수 있다.
|
||||
Forwarding Hosts 에는 넣지 않는다 — 넣으면 그 IP 의 메일은 스팸 검사 · 위조 판정 없이 들어온다.
|
||||
2. **Fail2ban 예외** — System → Configuration → Options → Fail2ban parameters → "Allowlisted networks/hosts" 에 `<MX1_IP>` (imapsync 로그인 실패가 쌓여 mx1 IP 가 막히면 SMTP 도 끊긴다).
|
||||
mailcow 가 mx1 을 사설 주소로 보면 막히지 않아 필요 없다 — IMAP(993)은 앞단 터널 주소 `10.9.0.1` 로 보였고(2026-11-03), 25 는 보지 않았다. 넣어도 해는 없다([imapsync › 원본](#원본--mailcow-마스터-계정)의 접속 주소).
|
||||
3. **새 서버 setup** — 위 "env 와 실행". 이때부터 새 서버의 owner@ 가 동료에게 보낼 수 있다(mailcow 는 아직 owner 앞 메일을 자기 사서함에 넣는다).
|
||||
4. **반대 방향부터 시험** — 새 서버의 owner@(웹메일)로 동료에게 한 통. 실사용자에게 영향이 없는 방향이라 먼저 한다:
|
||||
```bash
|
||||
@@ -1455,7 +1456,7 @@ mailcow 를 거친 메일은 SPF · DMARC 결과가 없고(`Authentication-Resul
|
||||
| 5. 메일 이전 1차 | [imapsync](#imapsync) — 한 사람으로 먼저(`--justlogin` · 폴더 맞춤), 그다음 주소 목록 전부 | 사람마다 `Detected 0 errors` · 폴더별 수 · 「이전 현황」의 메일함 사용량 |
|
||||
| 6. MX 전환 | `arasystem.it.kr MX 10 mx1.arasystem.it.kr` 로 교체. mailcow 는 **계속 켜 둔다** (전파 중에는 mailcow 로도 들어온다). **이때부터 9 까지 직원은 새 서버에 들어오지 못한다** — 짧게(예: 금요일 저녁 ~ 월요일 아침) | 외부에서 보낸 메일이 새 엔진 로그에 수신 |
|
||||
| 7. 마지막 imapsync | TTL 이 지나 mailcow 에 새 수신이 없어진 뒤 같은 명령을 한 번 더(차이분 — 이미 옮긴 메일은 건너뛴다). 그 전에 직원에게 mailcow 를 그만 쓰게 알린다 | mailcow 로그에 새 수신 없음 · 사람마다 `Detected 0 errors` |
|
||||
| 8. 이전 마치기 | 마지막 imapsync 뒤 5분쯤 지나 운영 도구 「메일 이전 › 이전 마치기」(주소 빈 값 — 이전 중인 계정 모두) → 주소 · 임시 비밀번호 표가 **한 번** 보인다. mailcow 메일함은 `Disallow login`, 마스터 계정 두 줄 · 서버 B 의 비밀번호 파일 지우기([imapsync](#imapsync) 단계 8) | 「이전 현황」이 비었다 |
|
||||
| 8. 이전 마치기 | 마지막 imapsync 뒤 5분쯤 지나 운영 도구 「메일 이전 › 이전 마치기」(주소 빈 값 — 이전 중인 계정 모두) → 주소 · 임시 비밀번호 표가 **한 번** 보인다. mailcow 메일함은 `Disallow login`, 마스터 계정 두 값 비우기 · 서버 B 의 비밀번호 파일 지우기([imapsync](#imapsync) 단계 8) | 「이전 현황」이 비었다 |
|
||||
| 9. 임시 비밀번호 나눠 주기 | 직원에게 직접(말 · 쪽지). 직원은 첫 로그인 때 새 비밀번호를 정하고, 회사 정책이면 2단계 인증을 켠다 | 직원이 웹메일에 들어온다 |
|
||||
| 10. 병행 1~2주 후 정리 | SPF 에서 `ip4:46.250.248.43` 제거, `dkim._domainkey` 삭제, mailcow 중지. 필요하면 `mail.arasystem.it.kr` 을 새 호스트로 옮기고(인증서 포함) `MAIL_PUBLIC_URL` 변경 | — |
|
||||
|
||||
@@ -1493,18 +1494,18 @@ mailcow 를 거친 메일은 SPF · DMARC 결과가 없고(`Authentication-Resul
|
||||
이전 중인 계정은 운영 도구 메뉴 `11. 메일 이전` 이 다룬다 — `1. 이전 현황` · `2. 이전용 비밀번호 다시 만들기` · `3. 이전 마치기`(2 · 3 은 `주소 (빈 값이면 이전 중인 계정 모두): `).
|
||||
"이전 중"은 엔진 비밀번호 만료가 미래(30일 안)이면서 운영 도구의 실행 기록에서 마지막으로 건 비밀번호가 이전용인 계정이다(계약 6절 "메일 이전").
|
||||
엔진의 **비밀번호 기본 만료**(`x:Authentication` 의 `passwordDefaultExpiry` — 관리 화면의 인증 설정)는 켜지 않는다 — 켜면 직원 비밀번호가 주기적으로 만료되고, 끈 뒤에도 그동안 바꾼 비밀번호의 만료가 남는다. 운영 도구는 켜져 있으면 첫 화면에 알린다.
|
||||
- 근거는 아래 [개발에서 확인한 것](#개발에서-확인한-것-imapsync--2026-11-02) — mailcow 를 흉내 낸 Dovecot → 개발 엔진. **운영 mailcow · 서버 B 에서는 아직 돌려 보지 않았다** — 단계 5 의 첫 사람으로 확인한다.
|
||||
- 근거는 아래 [개발에서 확인한 것](#개발에서-확인한-것-imapsync--2026-11-02) — mailcow 를 흉내 낸 Dovecot → 개발 엔진. **운영 mailcow · 서버 B 에서는 아직 돌려 보지 않았다** — 준비의 "원본 로그인만"과 단계 5 의 첫 사람으로 확인한다.
|
||||
|
||||
#### 차례 (단계 번호는 [전환 절차](#arasystemitkr-전환-절차-mailcow--stalwart)의 것)
|
||||
|
||||
| 단계 | 할 일 | 비고 |
|
||||
| --- | --- | --- |
|
||||
| 준비 | mailcow 마스터 계정 고정(아래 "원본") · mailcow Fail2ban 예외에 새 서버 IP · 서버 B 에 마스터 비밀번호 파일 · 주소 목록(아래 "돌리는 곳") | Fail2ban 예외는 [파일럿 공존](#파일럿-공존-mailcow-와-함께--한-사람-먼저)의 mailcow 절차 2 와 같다 — imapsync 로그인 실패가 쌓여 그 IP 가 막히면 새 서버 → mailcow 의 SMTP 도 끊긴다 |
|
||||
| 준비 | 단계 2 며칠 전 — mailcow 마스터 계정 고정(아래 "원본") · 서버 B 에 마스터 비밀번호 파일 · **원본 로그인만 미리**(아래 "돌리는 곳"의 준비 줄 — 대상 계정 없이) · 주소 목록 | 원본 쪽 문제(마스터 · 인증서 · 앞단 길)를 계정을 만들기 전에 고친다 — 단계 2 부터는 짧게 이어야 한다(아래). mailcow 의 Fail2ban 예외는 필요 없다 — mailcow 는 바깥 접속을 모두 앞단 터널 주소(사설 `10.9.0.1`)로 보고, 사설 주소는 막지 않는다(아래 "원본"의 접속 주소) |
|
||||
| 2 | 계정 만들기 — 운영 도구 「입사」를 한 사람씩(모두를 한 실행에서), 옮겨 올 메일 y. 처음 보이는 이전용 비밀번호를 **그 자리에서** 서버 B 의 비밀번호 파일로(아래 — 다시 볼 수 없다) | 「메일 이전 › 이전 현황」에 이전 중인 계정 · 끝나는 때 · 메일함 사용량이 보인다 |
|
||||
| 5 | imapsync 1차 — **한 사람으로 먼저**(`--justlogin` · 엔진이 본 접속 주소 · 1차 · 아래 "사람마다 확인할 것"), 그다음 주소 목록 전부 | 메일이 많으면 MX 전날에 — 단계 7 의 차이분이 짧아진다 |
|
||||
| 6 | MX 바꾸기 | 이때부터 단계 9 까지 직원은 새 서버에 들어오지 못한다(비밀번호를 아직 받지 않았다) |
|
||||
| 7 | **마지막 imapsync** — TTL 이 지나 mailcow 에 새 수신이 없어진 뒤 같은 명령 | 그사이 mailcow 에 온 메일 · 바뀐 읽음 표시만 옮긴다. 직원에게는 그 전에 mailcow 를 그만 쓰게 알린다 — 이 뒤에 mailcow 에서 한 일은 옮겨지지 않는다 |
|
||||
| 8 | **마지막 imapsync 가 끝나고 5분쯤 지난 뒤** 운영 도구 「메일 이전 › 이전 마치기」 — 주소 빈 값(이전 중인 계정 모두). 그다음 mailcow 정리 — 메일함을 `Disallow login (incoming mail is still accepted)` 로, 마스터 계정 두 줄 지우기, 서버 B 의 비밀번호 파일 지우기 | 사람마다 직원용 임시 비밀번호(만료 — 첫 로그인 때 바꾸기), imapsync 의 로그인 기록 지우기. 끝에 주소 · 임시 비밀번호 표가 **한 번** 보인다. 5분을 기다리는 까닭 — 엔진 웹훅은 1초씩 묶어 보내고 실패하면 5분까지 다시 보낸다, 그 전에 하면 늦게 온 IMAP 로그인 몇 줄이 직원의 로그인 기록에 남는다. mailcow 메일함은 지우거나 Inactive 로 두지 않는다(파일럿 mailcow 절차 9 와 같다) |
|
||||
| 8 | **마지막 imapsync 가 끝나고 5분쯤 지난 뒤** 운영 도구 「메일 이전 › 이전 마치기」 — 주소 빈 값(이전 중인 계정 모두). 그다음 mailcow 정리 — 메일함을 `Disallow login (incoming mail is still accepted)` 로, 마스터 계정 두 값 비우기(아래 "원본"), 서버 B 의 비밀번호 파일 지우기 | 사람마다 직원용 임시 비밀번호(만료 — 첫 로그인 때 바꾸기), imapsync 의 로그인 기록 지우기. 끝에 주소 · 임시 비밀번호 표가 **한 번** 보인다. 5분을 기다리는 까닭 — 엔진 웹훅은 1초씩 묶어 보내고 실패하면 5분까지 다시 보낸다, 그 전에 하면 늦게 온 IMAP 로그인 몇 줄이 직원의 로그인 기록에 남는다. mailcow 메일함은 지우거나 Inactive 로 두지 않는다(파일럿 mailcow 절차 9 와 같다) |
|
||||
| 9 | 임시 비밀번호 나눠 주기 — 직원에게 직접(말 · 쪽지) | 직원은 첫 로그인 때 새 비밀번호를 정하고, 회사 정책이면 2단계 인증을 켠다(계약 6절 "제한된 세션") |
|
||||
|
||||
- **단계 6 ~ 9 는 짧게 잡는다** — 예: 금요일 저녁 MX → 토요일 마지막 imapsync · 이전 마치기 → 월요일 아침 나눠 주기. 그동안 바깥 메일은 새 서버에 쌓이고, 직원은 단계 7 전까지 mailcow 를 그대로 쓸 수 있다.
|
||||
@@ -1520,27 +1521,50 @@ mailcow 는 dovecot-mailcow 를 다시 띄울 때마다 **무작위** 마스터
|
||||
mailcow 문서 "Static master user"(<https://docs.mailcow.email/manual-guides/Dovecot/u_e-dovecot-static_master/>, 몇 해 된 글):
|
||||
|
||||
```bash
|
||||
# mailcow 호스트 — 설치 폴더(/opt/mailcow-dockerized)의 mailcow.conf 에 두 줄. 둘 다 값이 있어야 한다(하나라도 비면 무작위로 만든다)
|
||||
# mailcow 호스트(사무실 PC 의 WSL 셸) — mailcow.conf 는 root 소유라 sudo 로 연다: sudo nano /opt/mailcow-dockerized/mailcow.conf
|
||||
# 두 줄은 mailcow 기본 설정에 빈 값으로 이미 있다(DOVECOT_MASTER_USER= · DOVECOT_MASTER_PASS=). 둘 다 값을 넣는다 — 하나라도 비면 무작위로 만든다
|
||||
DOVECOT_MASTER_USER=<이름> # 로그인 이름에는 @mailcow.local 이 저절로 붙는다
|
||||
DOVECOT_MASTER_PASS=<비밀번호> # 영문 · 숫자로 길게
|
||||
docker compose up -d # dovecot-mailcow 가 다시 만들어진다
|
||||
DOVECOT_MASTER_PASS=<비밀번호> # 영문 · 숫자만(특수 문자 금지 — mailcow 설정의 주석) · 길게 — 그 PC 에서 openssl rand -hex 24 로 만들어 비밀번호 관리자에 둔다
|
||||
# 그리고 설치 폴더에서 다시 띄운다 — 두 값을 받는 dovecot-mailcow 만 다시 만들어진다
|
||||
cd /opt/mailcow-dockerized && sudo docker compose up -d
|
||||
```
|
||||
|
||||
- IMAP 로그인 이름은 `<직원 주소>*<이름>@mailcow.local`(예 `hong@arasystem.it.kr*migrator@mailcow.local` — `@` 가 둘), 비밀번호는 `DOVECOT_MASTER_PASS` 다.
|
||||
**IMAP 전용** — SOGo(mailcow 웹메일) 로그인에는 쓰지 못한다.
|
||||
- 끝나면(단계 8) 두 줄을 지우고 `docker compose up -d` — 무작위로 돌아간다. 마스터 비밀번호는 모든 메일함을 연다.
|
||||
- `mailcow.conf` 는 **mailcow 호스트** — mailcow 컨테이너가 도는 사무실 PC(바깥 `mail.arasystem.it.kr` 은 Contabo 앞단을 거쳐 이 PC 로 온다)에 있다. 운영자가 그 PC 에 들어가 고친다
|
||||
(2026-11-02 사용자 확인 — 파일럿 때 적은 "관리 화면만"([파일럿 공존](#파일럿-공존-mailcow-와-함께--한-사람-먼저)의 "SSH 가 없을 때")은 원격으로 들어갈 길 이야기다).
|
||||
설치 폴더는 compose 가 기록한 작업 폴더로 찾는다 — 값(비밀번호)은 출력하지 않고 이름만 본다:
|
||||
- 다시 띄우는 동안 직원의 IMAP · 웹메일(SOGo)이 잠깐 끊긴다 — 메일 프로그램은 다시 잇고, 들어오는 메일은 postfix 가 붙잡았다가 넘긴다. 한가한 때에 한다.
|
||||
- 마스터 비밀번호는 모든 메일함을 연다 — 고정은 단계 2 며칠 전(원본 로그인을 미리 볼 수 있게)부터 단계 8 까지만 둔다.
|
||||
끝나면(단계 8) 두 값을 비우고(줄은 둔다) 같은 명령으로 다시 띄운다 — 무작위로 돌아간다.
|
||||
- `mailcow.conf` 는 **mailcow 호스트** — mailcow 컨테이너가 도는 사무실 PC(Windows 의 WSL — 설치 폴더 `/opt/mailcow-dockerized`, 바깥 `mail.arasystem.it.kr` 은 Contabo 앞단을 거쳐 이 PC 로 온다)에 있다.
|
||||
운영자가 그 PC 의 WSL 셸에서 고친다(2026-11-02 사용자 확인 — 파일럿 때 적은 "관리 화면만"([파일럿 공존](#파일럿-공존-mailcow-와-함께--한-사람-먼저)의 "SSH 가 없을 때")은 원격으로 들어갈 길 이야기다).
|
||||
이전하는 동안 그 PC 가 절전 · 재부팅되면 mailcow 가 멈춰 imapsync 가 끊긴다 — 전원 연결 시 절전 안 함으로 둔다.
|
||||
`mailcow.conf` 는 root 만 읽고 저장소도 root 소유라 확인 명령은 sudo 로 한다 — 값(비밀번호)은 출력하지 않는다(`git config safe.directory` 는 건드리지 않는다):
|
||||
```bash
|
||||
# mailcow PC 에서 (리눅스 셸 · docker 를 쓸 수 있는 사용자)
|
||||
sudo docker inspect "$(sudo docker ps -qf name=dovecot-mailcow)" --format '{{ index .Config.Labels "com.docker.compose.project.working_dir" }}'
|
||||
cd <위 폴더> && grep -o '^#\?DOVECOT_MASTER_[A-Z]*' mailcow.conf # 줄이 있는지 · 주석인지만
|
||||
git log -1 --format='%cd %h' --date=short # mailcow 판(커밋 날짜)
|
||||
# mailcow PC 의 WSL 셸에서 (sudo 를 쓸 수 있는 사용자)
|
||||
sudo docker inspect "$(sudo docker ps -qf name=dovecot-mailcow)" --format '{{ index .Config.Labels "com.docker.compose.project.working_dir" }}' # → /opt/mailcow-dockerized
|
||||
sudo awk -F= '/^DOVECOT_MASTER_(USER|PASS)=/ { print $1, ($2 == "" ? "비어 있음" : "값 있음") }' /opt/mailcow-dockerized/mailcow.conf # 값 대신 비었는지만. 아무것도 안 나오면 줄이 없거나 주석
|
||||
sudo git -C /opt/mailcow-dockerized log -1 --format='%cd %h' --date=short # mailcow 판(커밋 날짜)
|
||||
```
|
||||
- **확인하지 않은 것** — imapsync 가 붙는 `mail.arasystem.it.kr:993` 이 Contabo 앞단을 어떻게 지나 사무실 PC 의 mailcow 에 닿는지 —
|
||||
mailcow 가 보는 접속 주소가 서버 B 의 IP 가 아니라 앞단의 주소라면 Fail2ban 예외도 그 주소여야 하고, 그 주소가 막히면 모든 직원의 메일 프로그램이 함께 막힌다(첫 사람의 `--justlogin` 뒤 mailcow 관리 화면의 로그인 기록에서 그 주소를 본다).
|
||||
운영 mailcow 판에서 이 설정이 문서대로인지(같은 꼴로 인증에 실패했다는 커뮤니티 글이 있다 — 해결 기록 없음. 그래서 한 사람의 `--justlogin` 으로 먼저 본다),
|
||||
운영(2026-11-03 확인): 설치 폴더 `/opt/mailcow-dockerized`, 판 2026-05-12(`32156a33`), 두 줄은 주석 없이 **빈 값**이다(아직 아무도 고정하지 않았다).
|
||||
"값 있음"이면 누군가 이미 고정해 둔 것이다 — 바꾸기 전에 그 값을 쓰는 곳(백업 스크립트 등)이 있는지 알아본다.
|
||||
- **mailcow 가 보는 접속 주소 — 바깥 접속은 모두 `10.9.0.1`**(2026-11-03 운영 — 최근 7일 로그인 줄 · 지금 연결 모두): `mail.arasystem.it.kr:993` 은 Contabo 앞단에서 터널을 지나
|
||||
이 PC 의 mailcow 에 닿고, mailcow 는 그 터널 주소 하나로 본다(공인 주소는 0 — 서버 B 도 같은 길이다). 안쪽 `172.22.1.248` 은 SOGo(웹메일), `172.22.1.8` 은 mailcow 안의 다른 컨테이너(7일에 3만 8천 줄 — 상태 점검으로 보인다)다.
|
||||
- mailcow 의 Fail2ban(netfilter-mailcow — 기본 10분에 실패 10번이면 30분)은 **사설 · 루프백 주소는 막지 않는다**(Python `ipaddress` 의 `is_private` · `is_loopback` — mailcow 원본 `data/Dockerfiles/netfilter/main.py`).
|
||||
그래서 **서버 B 를 Fail2ban 예외에 넣을 필요가 없다**. 거꾸로 지금 mailcow 는 바깥에서 오는 IMAP 무차별 대입을 IP 로 막지 못한다(전환 뒤 새 엔진은 실제 주소로 막는다).
|
||||
- 남는 것은 Dovecot 의 늦추기다 — 실패가 있었던 주소의 다음 로그인을 늦춘다(최대 15초). 바깥 접속이 모두 한 주소라 imapsync 의 실패가 쌓이면 바깥 직원의 로그인도 함께 늦어진다 — 실패를 되풀이하지 않는다.
|
||||
- 이 mailcow 의 docker 로그(json-file · 회전 없음 · Dovecot 만 428MB)는 `--since` 만 주면 **0줄**이다 — 처음부터 읽다가 중간의 읽지 못하는 줄(10-24 재시작 무렵으로 보인다)에서 docker 가 말없이 멈춘다.
|
||||
`--tail` 은 끝에서부터 읽어 된다 — 아래처럼 늘 `--tail` 을 준다. 앞단을 바꾸는 등 다시 볼 때:
|
||||
```bash
|
||||
# 최근 10만 줄(끝에서부터 — 본 범위의 처음 · 끝 시각도 나온다)의 로그인 줄이 어떤 주소였는지. 공인 주소는 세기만 하고 보이지 않는다
|
||||
sudo docker logs -t --tail 100000 "$(sudo docker ps -qf name=dovecot-mailcow)" 2>&1 | awk -v front=46.250.248.43 'NR == 1 { a = substr($1, 1, 19) } { z = substr($1, 1, 19) } /-login: / && match($0, /rip=[0-9A-Fa-f:.]+/) { ip = substr($0, RSTART + 4, RLENGTH - 4); if (ip == front) f++; else if (ip ~ /^(10\.|172\.(1[6-9]|2[0-9]|3[01])\.|192\.168\.|127\.|100\.(6[4-9]|[7-9][0-9]|1[01][0-9]|12[0-7])\.|::1$|[Ff][CcDd]|[Ff][Ee]80:)/) p[ip]++; else { if (!(ip in g)) d++; if (++g[ip] > m) m = g[ip]; n++ } } END { print "본 줄", NR, "· 처음", a, "· 끝", z; for (ip in p) print "내부", ip, p[ip] "줄"; print "앞단", front, f + 0, "줄"; print "그 밖의 공인", d + 0, "곳", n + 0, "줄 · 가장 많은 한 곳", m + 0, "줄" }'
|
||||
# 지금 붙어 있는 IMAP · POP3 연결의 주소(로그 없이 — Dovecot 이 아는 연결)
|
||||
sudo docker exec "$(sudo docker ps -qf name=dovecot-mailcow)" doveadm -f flow who -1 2>&1 | grep -oE 'ip=[0-9A-Fa-f:.]+' | cut -d= -f2 | awk -v front=46.250.248.43 '$0 == front { f++; next } /^(10\.|172\.(1[6-9]|2[0-9]|3[01])\.|192\.168\.|127\.|100\.(6[4-9]|[7-9][0-9]|1[01][0-9]|12[0-7])\.|::1$|[Ff][CcDd]|[Ff][Ee]80:)/ { p[$0]++; next } { if (!($0 in g)) d++; if (++g[$0] > m) m = g[$0]; n++ } END { for (ip in p) print "내부", ip, p[ip] "개"; print "앞단", front, f + 0, "개"; print "그 밖의 공인", d + 0, "곳", n + 0, "개 · 가장 많은 한 곳", m + 0, "개" }'
|
||||
# 준비의 "원본 로그인만"(서버 B — 아래 "돌리는 곳") 뒤 15분 안에 — 마스터 로그인만 골라 그 주소(10.9.0.1 이면 예상대로). 직원의 평소 로그인은 나오지 않는다
|
||||
sudo docker logs --since 15m --tail 20000 "$(sudo docker ps -qf name=dovecot-mailcow)" 2>&1 | awk '/Master user logging in as / { m = $NF; next } m != "" && index($0, "Login: user=<" m ">") { if (match($0, /rip=[0-9A-Fa-f:.]+/)) print m, substr($0, RSTART + 4, RLENGTH - 4); m = "" }'
|
||||
```
|
||||
100.64–100.127.x(Tailscale 같은 공유 주소)는 사설로 치지 않아 Fail2ban 이 막을 수 있다 — 앞단을 바꿔 바깥 접속이 그런 주소나 공인 주소 하나로 보이게 되면 그 주소가 예외에 있는지 본다(막히면 바깥 직원 모두가 함께 막힌다).
|
||||
세 명령은 Dovecot 2.3 의 로그 · doveadm 꼴(`imap-login: Login: user=<…>, …, rip=…` · `Master user logging in as …` · `username=… proto=… pid=… ip=…`)로 맞췄다 — 개발 흉내(Dovecot 2.3.21.1)의 실제 출력과 mailcow 꼴 표본으로,
|
||||
우분투 · 데비안의 기본 awk 인 mawk 1.3.4 에서 시험했다(2026-11-03). 앞의 둘은 운영 mailcow 에서도 돌렸다. mailcow 는 지금 원본 compose 에서도 `dovecot:2.3.21.1-2` 다.
|
||||
- **확인하지 않은 것** — 운영 mailcow 판(2026-05-12)에서 이 설정이 문서대로인지(같은 꼴로 인증에 실패했다는 커뮤니티 글이 있다 — 해결 기록 없음. 그래서 준비의 "원본 로그인만"으로 먼저 본다),
|
||||
메일함 편집의 **Allowed protocols** 에서 IMAP 이 꺼진 메일함이 마스터로도 막히는지(그래서 mailcow 접근 줄이기는 마지막 imapsync 뒤 — 단계 8).
|
||||
- 개발 흉내(Dovecot 2.3 에 같은 꼴 — 구분자 `*` · 마스터 이름 `migrator@mailcow.local`)에서는 imapsync 가 그 이름을 그대로 넘겨 Dovecot 이 `Master user logging in as kim@legacy.test` 로 받았다.
|
||||
mailcow 에 없는 메일함은 마스터로도 `NO [AUTHORIZATIONFAILED] Authorization failed` 다.
|
||||
@@ -1575,6 +1599,17 @@ imapsync_one() { # $1 = 직원 주소, 그 뒤는 덧붙일 옵션
|
||||
--automap --syncinternaldates --addheader --nolog --noreleasecheck "${@:2}" </dev/null
|
||||
}
|
||||
|
||||
# 준비 — 원본 로그인만 미리: 대상 계정 없이 두 쪽 모두 mailcow 로 --justlogin(이전용 비밀번호 파일이 아직 없어도 된다).
|
||||
# 끝 줄이 `Exiting with return value 0` 이면 된다 — 아니면 grep 없이 다시 보고 아래 "실패할 때"로(되풀이하지 않는다 — 한 번에 실패가 둘이고, Dovecot 이 바깥 직원 모두와 같은 주소의 로그인을 늦춘다).
|
||||
# 된 뒤 15분 안에 mailcow PC 에서 서버 B 가 어떤 주소로 보였는지 본다(예상 10.9.0.1 — 위 "원본"의 접속 주소)
|
||||
A=hong@arasystem.it.kr
|
||||
sudo docker run --rm --network host --user 65534:65534 --cap-drop ALL --security-opt no-new-privileges --read-only --tmpfs /tmp --tmpfs /var/tmp \
|
||||
--mount type=bind,src=/root/imapsync/mailcow-master.pass,dst=/run/secrets/master,readonly \
|
||||
"$IMAPSYNC_IMAGE" imapsync \
|
||||
--host1 mail.arasystem.it.kr --port1 993 --ssl1 --sslargs1 SSL_verify_mode=1 --user1 "$A*$MASTER" --passfile1 /run/secrets/master \
|
||||
--host2 mail.arasystem.it.kr --port2 993 --ssl2 --sslargs2 SSL_verify_mode=1 --user2 "$A*$MASTER" --passfile2 /run/secrets/master \
|
||||
--justlogin --nolog --noreleasecheck </dev/null | grep -E '^(Host[12]: success login|Host[12] failure|Exiting with)'
|
||||
|
||||
# 단계 5 — 한 사람으로 먼저: 두 서버에 로그인만 → 엔진이 본 접속 주소(remoteIp)가 B_IP 인지 → 1차
|
||||
imapsync_one hong@arasystem.it.kr --justlogin
|
||||
sudo docker logs --since 5m "${PROJECT_NAME}-mail" 2>&1 | grep auth.success | grep imaps | tail -1
|
||||
@@ -1622,7 +1657,7 @@ sudo rm -f /root/imapsync/mailcow-master.pass /root/imapsync/migration.pass
|
||||
| `… SSL connect attempt failed … certificate verify failed` · `hostname verification failed` (10) | 인증서 — 자체 서명이거나 이름이 다르다(`--add-host` 없이 주소로 붙음) | 위 `--host2` · 인증서 |
|
||||
|
||||
- 같은 실패를 모두에게 되풀이하지 않는다 — 엔진은 IP 마다 인증 실패 하루 100회면 그 IP 를 막는다(자동 차단 — 위 "setup 스크립트가 하는 일" 4. 서버 B 의 사설 IP 는 신뢰 대역 밖이다).
|
||||
한 사람에서 실패하면 멈추고 고친다. mailcow 쪽은 Fail2ban 이다(준비의 예외).
|
||||
한 사람에서 실패하면 멈추고 고친다. mailcow 쪽은 Fail2ban 이 막지 않지만(서버 B 도 사설 `10.9.0.1` 로 보인다) Dovecot 이 그 주소 — 바깥 직원 모두 — 의 로그인을 늦춘다(위 "원본"의 접속 주소).
|
||||
- 한쪽 로그인이 실패해도 imapsync 는 다른 쪽 로그인을 해 본 뒤 끝난다(`--justlogin` 에서 봤다) — 출력의 `Err 1/2` 처럼 실패가 둘로 보이면 먼저 나온 것부터 본다.
|
||||
|
||||
#### 개발에서 확인한 것 (imapsync — 2026-11-02)
|
||||
@@ -1634,6 +1669,7 @@ mailcow 를 흉내 낸 Dovecot(`dovecot/dovecot:2.3.21.1@sha256:547d28f9a893c93a
|
||||
| 무엇 | 결과 |
|
||||
| --- | --- |
|
||||
| 원본 로그인 | `<주소>*migrator@mailcow.local` 을 imapsync 가 그대로 넘겼다. 원본에 없는 메일함은 마스터로도 `NO [AUTHORIZATIONFAILED]` |
|
||||
| 원본 로그인만(준비) | 두 쪽을 같은 원본 · 같은 마스터 로그인으로 준 `--justlogin` 을 imapsync 가 받는다 — `Host1: success login` · `Host2: success login` · `Exiting with return value 0`(2026-11-03). Dovecot 로그는 로그인마다 `Master user logging in as <주소>` 다음 `Login: user=<주소>, …, rip=<imapsync 주소>` |
|
||||
| 폴더 맞춤 | INBOX → Inbox(`inbox`) · Sent → Sent Items(`sent`) · Drafts → Drafts(`drafts`) · Trash → Deleted Items(`trash`) · Junk → Junk Mail(`junk`) — **따로 생긴 폴더 없음, `--f1f2` 가 필요 없었다**. Archive 는 보통 폴더 "Archive"(role 없음) |
|
||||
| 폴더마다 메일 수 | 원본과 같다 (메일 14 · 5통, 폴더 8 · 7개) |
|
||||
| 받은 때 | 모두 같다 — 2025년 내부 날짜가 초까지 그대로(JMAP `receivedAt`) |
|
||||
@@ -1651,7 +1687,7 @@ mailcow 를 흉내 낸 Dovecot(`dovecot/dovecot:2.3.21.1@sha256:547d28f9a893c93a
|
||||
|
||||
- **개발과 운영이 다른 점** — 대상 인증서가 자체 서명이라 `--sslargs2 SSL_verify_mode=0` 으로 돌렸고, imapsync 를 잠시 앱 네트워크에 붙여 `mail:993` 으로 갔다(엔진은 신뢰 대역 주소로 본다 — 운영에서는 하지 않는다).
|
||||
원본은 시험 CA 로 `SSL_verify_mode=1` 이었다.
|
||||
- **확인하지 않은 것** — 운영 mailcow 의 마스터 계정 · Allowed protocols, 서버 B 의 길(`--network host` + `--add-host` 와 엔진이 보는 주소), 운영의 양 · 시간, 직원이 만든 실제 폴더 이름.
|
||||
- **확인하지 않은 것** — 운영 mailcow(2026-05-12 판)의 마스터 계정과 서버 B 도 `10.9.0.1` 로 보이는지(준비의 "원본 로그인만"으로 본다) · Allowed protocols, 서버 B 의 길(`--network host` + `--add-host` 와 엔진이 보는 주소), 운영의 양 · 시간, 직원이 만든 실제 폴더 이름.
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user