Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
454 lines
60 KiB
Markdown
454 lines
60 KiB
Markdown
# AriMail(mail.arihakdang.com) 설치·운영
|
|
|
|
> 1.0.0 부터 프로젝트 이름은 **AriMail**, 저장소는 https://source.ibit.kr/OZ-Group/AriMail 입니다(내용은 같고 이름만 바뀜).
|
|
> 운영 설정(Resend 키 등)은 환경 파일이 아니라 **설정 파일 + 초기 설정 페이지**(10절)에서 다루고, 수·발신은 Resend 또는 **내장 Haraka**(12절)로 할 수 있습니다.
|
|
|
|
www.arihakdang.com 과 **같은 서버(187.53.133.173), 같은 실행 계정(`arihakdang`), 같은 Node(`/opt/arihakdang-node`)** 에서 돌아갑니다.
|
|
관리자 계정은 www 의 `users` 테이블을 읽기 전용으로 읽어 인증하므로 별도 계정·비밀번호가 없습니다.
|
|
사용자 이름 `admin` / `admin@arihakdang.com` 은 메일함 소유 관리자의 별칭입니다. 소유자는 `MAILBOX_OWNER_LOGIN`(www 로그인 ID 또는 이메일) →
|
|
이메일이 메일함 주소인 관리자 → 유일한 활성 관리자 순으로 정합니다. 관리자가 둘 이상이면 `MAILBOX_OWNER_LOGIN` 을 꼭 지정하세요.
|
|
|
|
```
|
|
Resend 수신(admin@arihakdang.com)
|
|
├─ 웹훅 email.received ──▶ POST https://mail.arihakdang.com/api/webhooks/resend (즉시)
|
|
└─ GET /emails/receiving ──▶ 1시간마다 동기화 (보충)
|
|
│ 원본(.eml)·첨부·정제 본문을 SQLite 에 기한 없이 보관
|
|
├─ 웹 메일함 https://mail.arihakdang.com/ (보기·답장·발송)
|
|
├─ IMAP mail.arihakdang.com:993 (TLS) / 143 (STARTTLS)
|
|
├─ POP3 mail.arihakdang.com:995 (TLS) / 110 (STLS 또는 일반 접속)
|
|
└─ SMTP 제출 mail.arihakdang.com:465 (TLS) / 587 (STARTTLS)
|
|
로그인 비밀번호로 인증 → 서버 내부 RESEND_API_KEY 로 Resend API 발송
|
|
```
|
|
|
|
## 1. DNS 와 인증서
|
|
|
|
1. Cloudflare DNS 에 `mail` A 레코드 → `187.53.133.173`, **프록시 끔(DNS only, 회색 구름)**.
|
|
POP3 포트(110/995)는 Cloudflare 프록시를 지나지 못하고, 메일 클라이언트는 공개 CA 인증서를 요구합니다.
|
|
그래서 이 호스트만 원본 IP 가 공개됩니다. www 의 Cloudflare 전용 차단(444)은 이 vhost 에 적용하지 않습니다.
|
|
2. 서버에서 인증서 발급:
|
|
```bash
|
|
sudo apt install -y certbot
|
|
sudo mkdir -p /var/www/letsencrypt
|
|
sudo certbot certonly --webroot -w /var/www/letsencrypt -d mail.arihakdang.com
|
|
```
|
|
발급 후 `sudo bash deploy/setup.sh` 를 다시 실행하면 갱신 훅(`deploy/letsencrypt-deploy-hook.sh.in` 에서 만든 `/etc/letsencrypt/renewal-hooks/deploy/arihakdang-mail.sh`)이 인증서 사본을
|
|
`/etc/arihakdang-mail/tls/` 에 서비스 계정 권한으로 만들고, nginx(443)와 POP3(995/STLS)가 같은 인증서를 씁니다.
|
|
certbot 이 갱신할 때마다 훅이 사본을 갱신하고 서비스를 재시작합니다.
|
|
(프로세스도 1시간마다 인증서 파일을 다시 읽으므로 재시작 없이도 새 인증서가 적용됩니다.)
|
|
3. 방화벽에 110, 995(POP3)와 143, 993(IMAP) TCP 를 엽니다. 80/443 은 www 와 공유합니다.
|
|
|
|
## 2. 서버 준비와 배포
|
|
|
|
```bash
|
|
sudo bash deploy/setup.sh # 디렉터리, 환경 파일(배포에 필요한 값만), systemd, nginx, 내장 Haraka 준비
|
|
sudo -u arihakdang /srv/arihakdang-mail/repo/deploy/deploy.sh # 끝에 "초기 설정 페이지" 주소(토큰 포함)가 출력됩니다
|
|
journalctl -u arihakdang-mail -n 50 --no-pager
|
|
```
|
|
|
|
1.0.0 부터 **환경 파일에 Resend 키를 적지 않습니다.** 배포가 끝나면 출력된 초기 설정 페이지 주소(`http(s)://<서버>:8791/?token=…`)를 열어
|
|
수·발신 방식과 키를 채우세요(10절). 값이 비어 있어도 배포는 실패하지 않고, 저장하면 재시작 없이 적용됩니다.
|
|
|
|
배포 스크립트는 `git reset --hard origin/main` → 테스트 → `releases/<시각>` 복사 → DB 백업·마이그레이션 →
|
|
`current` 링크 교체 → 재시작 순서이며, 재시작에 실패하면 이전 릴리스로 되돌립니다.
|
|
서버에는 `source.ibit.kr` 자격 증명을 두지 않습니다. 작업 PC 에서 번들을 만들어 올리고 번들로 배포합니다.
|
|
|
|
```bash
|
|
git bundle create /tmp/mail-gateway.bundle main && scp /tmp/mail-gateway.bundle hostinger:/tmp/
|
|
ssh hostinger 'sudo install -o arihakdang -g arihakdang -m 644 /tmp/mail-gateway.bundle /srv/arihakdang-mail/source.bundle && sudo -u arihakdang env SOURCE_BUNDLE=/srv/arihakdang-mail/source.bundle /srv/arihakdang-mail/repo/deploy/deploy.sh'
|
|
```
|
|
|
|
배포 스크립트의 재시작에는 sudoers 규칙이 필요합니다(`setup.sh` 가 `/etc/sudoers.d/arihakdang-mail` 로 만듭니다).
|
|
|
|
`deploy/` 의 systemd 유닛·nginx·certbot 훅·환경 파일은 0.8.18 부터 `.in` 템플릿이며, `setup.sh` 가 사이트 설정(`deploy/sites/<이름>.env`, 기본 `arihakdang`)으로
|
|
채워 설치합니다. 다른 도메인에 설치하는 방법은 8절, 설치 옵션(로그인 방식 `LOGIN_MODE`, 시스템 제한 `LIMIT_*`)은 9절을 보세요.
|
|
|
|
## 3. Resend 웹훅
|
|
|
|
1. Resend 대시보드 → **Webhooks → Add Endpoint**
|
|
- URL: `https://mail.arihakdang.com/api/webhooks/resend`
|
|
- Events: `email.received`
|
|
2. 만들어진 엔드포인트의 **Signing Secret(`whsec_…`)** 을 초기 설정 페이지(또는 `/admin` → 메일 서비스 설정)의 Resend 카드 "웹훅 서명 비밀키" 에 넣고 저장합니다(재시작 불필요, 1.0.0).
|
|
(0.9.x 까지는 `gateway.env` 의 `RESEND_WEBHOOK_SECRET` 이었습니다. 남아 있는 값은 1.0.0 첫 시작 때 설정 파일로 가져갑니다.)
|
|
3. 웹훅은 본문을 담지 않으므로 게이트웨이가 `GET /emails/receiving/{id}` 로 전문·헤더·첨부·원본(raw) 을 받아 저장합니다.
|
|
서명이 없거나 틀리면 401, 저장에 실패하면 500 을 돌려주어 Resend 가 재시도합니다.
|
|
4. 웹훅과 무관하게 **1시간마다** 수신·발송 목록을 확인해 빠진 메일을 보충합니다(관리자 페이지 → 서버 상태의 "지금 동기화"로 즉시 실행).
|
|
한 번에 받은 메일 500건·보낸 메일 200건(최신순)까지 거슬러 올라갑니다.
|
|
웹 메일함 목록을 열어 두면 1분마다 **빠른 확인**을 합니다. 최신 메일부터 보다가 이미 저장한 메일을 만나면 멈추므로 Resend 호출이 한두 번에 그칩니다.
|
|
|
|
## 4. 보관·중복 방지
|
|
|
|
- 받은 메일과 보낸 메일은 **기한 없이** 보관합니다(0.8.0 에서 30일 제한과 `RETENTION_DAYS` 설정을 없앴습니다).
|
|
메일은 휴지통에서 **영구 삭제**할 때만 원본·첨부와 함께 지워지고, Resend 목록에 남아 있어도 다시 가져오지 않습니다(tombstone).
|
|
- 저장 공간은 SQLite 파일(`/srv/arihakdang-mail/data/mail-gateway.sqlite`)이 계속 커지므로 디스크 사용량을 가끔 확인하세요.
|
|
왼쪽 패널 아래에 메일함별 사용량이 보입니다.
|
|
- POP3 로 **RETR(내려받기)** 하거나 클라이언트가 **DELE** 한 메일은 `pop_deliveries` 에 기록되어 같은 계정에 다시 내려주지 않습니다.
|
|
서버 저장본은 유지되어 웹에서 계속 볼 수 있고, 필요하면 메일 상세의 "POP 전달 기록 초기화"로 다시 내려받게 할 수 있습니다.
|
|
- 계정마다 따로 기록하므로 관리자가 두 명이면 각자 한 번씩 받습니다.
|
|
|
|
## 4a. 웹 메일함 사용법
|
|
|
|
- **왼쪽 패널**: 메일 쓰기 버튼, 받은 메일함(읽지 않음 수)·중요 표시·보낸 메일함·임시 보관함·휴지통, 보기 필터(읽지 않음·첨부), 설정(관리자에게는 관리자 페이지 링크), 저장 사용량(적용 중인 메일함 최대 크기가 있으면 막대와 비율).
|
|
0.9.0 부터 **누구나 자기 메일함만** 봅니다. 예전의 "관리자가 다른 계정의 메일함을 열어 보는" 기능(상단 메일함 선택)은 없앴고, 관리자 권한은 관리자 페이지의 계정·설정 관리에만 쓰입니다.
|
|
- **로그인 화면 → 회원 가입**(0.9.0~): 관리자가 켜 두었으면 접속 단추 아래에 "회원 가입" 이 보입니다. 로그인 ID(= 메일 주소의 앞부분)·이름·비밀번호(2회, 눈 단추)를 넣으면 계정이 생기며,
|
|
관리자 설정에 따라 바로 쓰거나 "관리자 승인 후 사용"(승인 전 로그인하면 "가입 승인을 기다리는 계정입니다") 입니다.
|
|
- **목록**: 체크박스로 여러 통을 골라 삭제·복원·읽음/읽지 않음·이동을 한 번에 처리합니다. ☆ 를 누르면 중요 표시(IMAP `\Flagged` 와 공유)입니다. 상단 검색은 보낸 사람·제목·본문을 찾습니다.
|
|
- **읽기 창**: 답장·전체 답장·전달·삭제·이동·중요·읽지 않음, 원본(.eml) 내려받기, 상세 정보(헤더·POP 전달 기록), 외부 이미지 표시(기본 차단).
|
|
- **로그인 화면**: 오른쪽 위 (?) 를 누르면 접속 안내 팝업(이 도메인의 메일 서비스, 부여받은 계정 또는 도메인을 포함한 이메일 주소로 로그인, 웹 접속 계정과 같은 아이디·비밀번호)이 뜹니다.
|
|
- **설정 → 내 비밀번호 변경**(0.9.0~): 현재 비밀번호를 넣고 새 비밀번호를 두 번 같게 입력합니다(눈 단추로 글자 확인). 바꾸면 세션이 모두 끝나 새 비밀번호로 다시 로그인합니다.
|
|
www 관리자 계정은 www 사이트에서 관리하므로 이 카드가 안내문으로만 보입니다.
|
|
- **설정 → 메일함 사용량·제한**(0.9.0~): 사용량(MIME 기준)과 적용 중인 메일함 최대 크기, 첨부 한 개 최대 크기, 한 메일의 받는 사람 수를 보여 줍니다.
|
|
- **설정**: 화면 기본값(외부 이미지), **메일 프로그램 접속 허용(POP3 / IMAP)** 스위치, IMAP·SMTP·POP 설정 안내. 끈 서비스는 그 계정의 메일 프로그램 로그인을 거부합니다(웹 메일·SMTP 는 영향 없음).
|
|
관리자가 서비스 자체를 껐으면 스위치가 비활성화되고 "관리자가 서비스를 껐습니다" 가 붙습니다.
|
|
- **설정 → 메일 전달**(0.8.16~): "받은 메일을 아래 주소로 전달" 을 체크하고 전달 주소(쉼표로 구분, 최대 5개)를 넣고 저장하면 이 메일함으로 받는 모든 메일을 그 주소로 보냅니다.
|
|
체크를 풀고 저장하면 전달하지 않습니다. 전달 중이면 체크 상자 옆에 "현재 메일은 다음 주소로 전달되고 있습니다" 가 굵게 보입니다.
|
|
원본은 받은 메일함에 그대로 남습니다. 전달 메일의 보내는 사람은 자기 메일함 주소(발송 서비스가 우리 도메인만 허용)이고 Reply-To 가 원래 발신자라 전달받은 쪽에서 답장하면 원래 보낸 사람에게 갑니다.
|
|
첨부·본문 이미지도 함께 가며(첨부 합계 25MB 까지), 전달 메일에는 `X-Ari-Auto-Forwarded` 헤더가 붙어 두 메일함이 서로를 전달 대상으로 두어도 한 번만 전달됩니다.
|
|
전달 주소에서 온 메일, 72시간이 지난 뒤 동기화가 뒤늦게 가져온 메일은 전달하지 않습니다. 전달 메일은 보낸 메일함에 쌓지 않고 메일 상세 정보의 "자동 처리" 줄에 기록만 남깁니다.
|
|
- **설정 → 자동 응답**(0.8.16~): 응답 제목(비우면 `Re: 원래 제목`)과 메시지를 쓰고, 기간을 **기한 제한 없음** 또는 **기간 지정**(시작·종료 날짜와 시간, 시작을 비우면 즉시)으로 정해 저장합니다.
|
|
기간 선택과 시작·종료 상자는 항상 보이며(기한 제한 없음이면 시각 상자는 비활성), 켜고 끄는 것은 "자동 응답 사용" 체크 상자와 저장 버튼입니다.
|
|
켜져 있으면 체크 상자 옆에 "메일이 수신되면 자동으로 아래 메일을 발신자에게 회신합니다." 가 굵게 보이고(지정 기간 밖이면 기간 안내가 덧붙음), 작동 중이면 왼쪽 패널 아래에도 "자동 응답 작동 중" 이 보입니다.
|
|
같은 상대에게는 24시간에 한 번만 보내고, 자동 발송 메일(`Auto-Submitted`, `Precedence: bulk/list`, 메일링 리스트, no-reply·mailer-daemon 발신)과 72시간 지난 메일에는 응답하지 않습니다.
|
|
자동 응답에는 `Auto-Submitted: auto-replied` 가 붙어 상대 서버의 자동 응답과 핑퐁이 생기지 않습니다. 보낸 자동 응답은 보낸 메일함에 남고 원래 메일에는 "답장함"(IMAP `\Answered`) 표시가 붙습니다.
|
|
- **메일 쓰기**: 참조 토글, 서식 도구(실행취소·글꼴·크기·굵게/기울임/밑줄/취소선·글자색·강조(기본 8색 팔레트 → 더 많은 색상은 브라우저 색상 선택창)·정렬·목록·들여쓰기·링크·인용·구분선·이미지·서식 지우기·HTML 편집),
|
|
파일 첨부(파일당 상한은 관리자 설정, 합계 20MB), 본문 이미지 삽입·붙여넣기·끌어놓기(발송 시 cid 인라인 첨부로 변환), 4초 간격 자동 임시 저장.
|
|
보내는 주소는 로그인 계정의 메일함 주소입니다.
|
|
- **참조 / 숨은 참조**(0.9.5): 받는 사람 줄 오른쪽의 "참조" 와 "숨은 참조" 를 각각 누르면 그 입력 줄이 열립니다. 숨은 참조도 초안에 저장되고 발송됩니다(받는 사람·참조에게는 보이지 않음).
|
|
- **대용량 첨부**(0.9.3~, 관리자가 켠 경우): "☁ 대용량 첨부" 로 올린 파일은 메일에 붙지 않고 서버에 보관되며 본문 끝에 **다운로드 링크** 블록이 붙어 나갑니다.
|
|
올리는 동안 칩 자리에 진행 막대·퍼센트·보낸 양/전체가 보이고 ✕ 로 취소할 수 있습니다(0.9.5). nginx 가 요청을 막으면(413) 그 사실을 따로 알립니다.
|
|
일반 첨부 상한을 넘는 파일을 첨부하거나 끌어 놓으면 자동으로 대용량으로 올라갑니다. 대용량 파일이 하나라도 있으면 **발송 조건(보관 일수·다운로드 횟수)** 줄이 보이며 둘 다 반드시
|
|
관리자 상한 이내로 정해야 합니다(제한 없는 발송 불가, 기본값은 상한). 받는 사람은 링크를 열면 랜딩 페이지(파일 이름·크기·남은 횟수·기한)를 보고 "다운로드" 단추를 눌러 받습니다
|
|
(단추를 누를 때만 횟수가 줄어 메일 보안 장치가 링크를 미리 열어도 소진되지 않음). 기한이 지나거나 횟수를 다 쓰면 파일이 서버에서 지워지고 링크는 "만료" 페이지가 됩니다.
|
|
보낸 메일함에서 메일을 열면 파일마다 남은 횟수·기한이 보이고 ✕ 로 링크를 끊을(파일 즉시 삭제) 수 있습니다.
|
|
|
|
## 4b. 관리자 페이지 (`https://mail.arihakdang.com/admin`)
|
|
|
|
관리자 페이지는 **`/admin` 주소로 고정**되어 있고(0.8.4~), 웹 메일과 **별도의 로그인**을 거칩니다. 로그인 정보는 같습니다
|
|
(www.arihakdang.com 관리자 계정 = 별칭 admin, 또는 역할이 관리자인 게이트웨이 계정). 세션 쿠키가 다르므로(`mg_admin`)
|
|
웹 메일에 로그인돼 있어도 관리자 페이지는 다시 로그인해야 하고, 관리자 세션으로는 메일 API 를 쓸 수 없습니다. 웹 메일의 설정 메뉴에는
|
|
관리자에게만 "관리자 페이지 ↗" 링크가 보입니다. 일반 계정으로 `/admin` 에 로그인하면 "관리자 역할 계정만" 안내와 함께 거부됩니다.
|
|
|
|
**계정 관리**
|
|
- 계정 항목: 로그인 ID(영문 소문자·숫자·`.`·`_`·`-`, 2~64자), 이름, 비밀번호(아래 비밀번호 정책을 따름), 역할(관리자/사용자), 상태(사용/정지), 메일 프로그램 접속(POP3 / IMAP 허용).
|
|
- **비밀번호 재설정**(0.9.0): 다른 계정의 비밀번호는 계정을 열어 **한 번만 입력**하고 눈 단추로 확인한 뒤 저장합니다(0.8.25 의 두 번 입력·현재 비밀번호 확인은 설정 화면의 "내 비밀번호 변경" 으로 옮겼습니다).
|
|
**자기 계정**을 열면 비밀번호 칸 대신 "도구 → 설정에서 바꾸세요" 안내만 보이며, API 로 시도해도 `self_password_settings` 로 거부됩니다.
|
|
- **메일함 최대 크기**(0.9.0): 계정마다 MB 로 지정합니다(0 = 관리자 기본값·시스템 값). 시스템 제한(설치 시 `LIMIT_MAILBOX_BYTES`)이 있으면 그 이내만 저장됩니다.
|
|
적용값은 "계정별 → 관리자 기본값 → 시스템" 중 가장 작은 0 아닌 값이며, 목록의 "저장 사용량" 열에 사용량 / 적용값이 보입니다.
|
|
- **승인 대기 계정**(0.9.0): 회원 가입으로 만들어진 계정은 상태가 "승인 대기" 로 보이고, 계정을 열면 **승인**(상태를 사용으로) / **거절**(계정 삭제) 단추가 있습니다.
|
|
- **비밀번호 정책**(0.8.24~): 계정 관리 화면 아래 "비밀번호 정책" 카드에서 최소 글자 수(6~64, 기본 6)와 영문 대·소문자 혼용 / 숫자 포함 / 특수문자 포함 요구를 각각 켜고 끕니다.
|
|
예전에는 10자 이상이 코드에 고정돼 있었습니다. 정책은 새로 정하는 비밀번호(계정 추가·수정, 명령줄 도구)에만 적용되고 기존 비밀번호에는 소급하지 않습니다.
|
|
규칙에 어긋나면 어느 항목이 어긋났는지("비밀번호가 정책에 맞지 않습니다: 8자 이상, 숫자 포함")를 알려 줍니다.
|
|
- **메일함 주소는 입력하지 않습니다.** 항상 `로그인 ID@arihakdang.com` 으로 자동 지정됩니다(예: `info` → `info@arihakdang.com`). 0.8.4 이전에 만든 계정은 등록된 주소를 유지합니다.
|
|
- 만든 계정은 웹 메일함·IMAP·POP·SMTP 에 **로그인 ID 또는 메일함 주소 + 비밀번호**로 접속하며 자기 메일함의 메일만 봅니다.
|
|
- 수신 메일은 받는 사람 주소가 등록된 메일함으로 들어옵니다(기본 메일함 admin@ + 활성 계정의 메일함).
|
|
- POP3 / IMAP 허용을 끄면 그 계정의 메일 프로그램 로그인을 거부합니다(`-ERR [SYS/PERM] POP access is disabled`, `NO [UNAVAILABLE] IMAP access is disabled`). 사용자도 웹 메일 설정에서 직접 켜고 끌 수 있습니다.
|
|
- 비밀번호를 바꾸거나 정지하면 해당 계정의 웹 세션이 즉시 종료됩니다. 계정을 삭제해도 메일함의 메일은 남습니다.
|
|
- www 관리자 계정(admin 행) 자체는 www 관리자 화면에서 관리하며 여기서는 POP/IMAP 허용만 바꿉니다.
|
|
|
|
**회원 가입 / 메일 제한 / POP·IMAP 서비스**(0.9.0, 계정 관리 화면 아래 카드)
|
|
- 회원 가입: "로그인 화면에서 회원 가입 받기" 와 가입 계정의 사용 시점(즉시 사용 / 관리자 승인 후 사용). 끄면 관리자가 만든 계정만 메일을 쓸 수 있습니다(`POST /api/signup` 은 404).
|
|
- 메일 제한: 계정별 기본 메일함 크기, 첨부 한 개 최대 크기(MIME 기준), 한 메일의 받는 사람 수. 각 값은 시스템 제한 이내만 저장되며(`limit_exceeds_system`), 0 은 시스템 값을 따릅니다.
|
|
그 아래 "시스템 설정" 에 설치 시 정한 `LIMIT_*` 값이 읽기 전용으로 보입니다(9절).
|
|
- POP3 / IMAP 서비스: 서비스 자체를 켜고 끕니다. 끄면 모든 계정의 POP(또는 IMAP) 로그인이 `-ERR [SYS/PERM] POP service is disabled by the administrator` / `NO [UNAVAILABLE] IMAP service is disabled by the administrator` 로 거부됩니다.
|
|
- 일반 접속 로그인 허용(0.9.7, 기본 켬): 110/143 포트에서 STARTTLS 없이 보낸 비밀번호로 로그인을 받을지. 끄면 CAPA 에서 `USER` 가 빠지고(IMAP 은 `LOGINDISABLED`) `-ERR [SYS/PERM] use STLS or port 995 before login` / `NO [PRIVACY] use STARTTLS or port 993 before login` 으로 거부합니다. 995/993·웹 메일·SMTP 에는 영향이 없고, 바꾼 값은 다음 접속부터 적용됩니다.
|
|
|
|
**대용량 첨부파일**(0.9.3, 카드)
|
|
- "대용량 첨부파일 기능 사용" 스위치와 파일 한 개 최대 크기(MB)·보관 최대 기간(일)·다운로드 최대 횟수. 세 값은 **비울 수 없고(무제한 불가)** 시스템 상한(`LIMIT_LARGE_FILE_*`, 9절) 이내여야 하며
|
|
기본값은 시스템 상한의 50%(1GB/30일/20회 → 512MB/15일/10회)입니다. 기본은 꺼짐. 카드에 현재 서버에 보관 중인 파일 수·용량이 보입니다(서버 상태의 현황에도 표시).
|
|
- **nginx**(0.9.5): 업로드 경로 `/api/files` 는 `client_max_body_size 0` + `proxy_request_buffering off`, 다운로드 `/dl/` 는 버퍼링 없이 1시간 시간 제한으로 프록시합니다(템플릿 `deploy/nginx/*.conf.in`).
|
|
이미 설치된 서버의 vhost 는 `sudo bash deploy/nginx-apply.sh <APP_DIR>/site.env`(site.env 가 없으면 `deploy/sites/<이름>.env`)로 다시 적용합니다 — 환경 파일·인증서는 건드리지 않고 vhost 파일만 바꿔 쓰고(이전 설정은 `.bak-<시각>`) `nginx -t` 뒤 reload 합니다.
|
|
0.9.3 까지는 server 블록의 `client_max_body_size 32m` 때문에 32MB 가 넘는 대용량 파일이 nginx 에서 413 으로 끊겼습니다.
|
|
- 파일은 `<APP_DIR>/data/files/<id>`(또는 `FILES_DIR`)에 있으며 만료·횟수 소진·링크 끊기·버려진 초안(하루 뒤)은 1시간마다 정리됩니다. 메일함 용량 제한(`LIMIT_MAILBOX_BYTES`)에는 들지 않습니다.
|
|
|
|
**서버 상태**: **메일 현황**(0.9.0: 일일·주간·월간 발신/수신/수발신 통수 — Asia/Seoul 기준, 월간은 1일~말일; 메일 계정·총 메일함 사용량·이달 통수를 시스템 제한과 견준 "8개 사용 중 / 최대 10개 (80%)";
|
|
사용자별 메일함 사용량과 적용 중인 최대 크기), 서비스 포트·TLS 인증서·POP/IMAP 스위치 상태, Resend 웹훅·동기화 기록·저장 통계·POP 전달 기록, "지금 동기화" 버튼. 사용량은 모두 MIME 기준(저장 원본 크기)입니다.
|
|
|
|
## 5. IMAP 사용법
|
|
|
|
IMAP 은 서버의 메일함을 그대로 보여 주는 방식입니다. 읽음·삭제·이동이 웹 메일함, 다른 기기와 함께 공유되므로
|
|
휴대폰과 PC 에서 같은 메일함을 쓰려면 POP 대신 IMAP 을 권장합니다.
|
|
|
|
| 항목 | 값 |
|
|
|---|---|
|
|
| 받는 메일 서버 | `mail.arihakdang.com`, 포트 993 (SSL/TLS) 또는 143 (STARTTLS) |
|
|
| 사용자 이름 / 비밀번호 | `admin` 또는 `admin@arihakdang.com` (www 관리자 로그인 ID·이메일도 가능) / www 관리자 로그인 비밀번호 |
|
|
| 메일함 | `INBOX`(받은), `Sent`(보낸), `Drafts`(초안), `Trash`(휴지통). 새 폴더는 만들 수 없습니다. |
|
|
| 보내는 메일 서버 | `mail.arihakdang.com`, 포트 465 (SSL/TLS) 또는 587 (STARTTLS). 받는 서버와 같은 계정이므로 "받는 서버 설정 사용"을 켜도 됩니다. |
|
|
|
|
설정 순서: 계정 추가 → 수동 설정(IMAP) → 받는 서버에 위 값 입력 → 보내는 서버에 같은 호스트·계정과 465/587 입력 →
|
|
보낸 메일 복사본은 `Sent`, 임시 저장은 `Drafts`, 삭제는 `Trash` 폴더를 쓰도록 지정(대부분 자동 인식).
|
|
|
|
동작 규칙:
|
|
- 클라이언트에서 읽으면 웹 메일함도 읽음으로 바뀝니다(`\Seen` ↔ read_at). 깃발(`\Flagged`), 답장함(`\Answered`)은 서버에 저장됩니다.
|
|
- 클라이언트의 삭제는 `Trash` 로 이동입니다. `Trash` 에서 다시 삭제(EXPUNGE)하면 영구 삭제되며 같은 메일을 다시 가져오지 않습니다.
|
|
- 클라이언트가 `Sent`/`Drafts` 에 올린 메일(APPEND)은 원본 그대로 저장되어 웹 메일함에도 보입니다.
|
|
- IDLE 을 지원하므로 새 메일이 오면 10초 안에 클라이언트에 알립니다.
|
|
- 서버의 메일은 기한 없이 보관되므로 IMAP 에서도 계속 보입니다. 지우려면 클라이언트에서 삭제 후 `Trash` 를 비우세요.
|
|
- 지원 명령: IMAP4rev1 전체 기본 명령, LITERAL+, IDLE, UIDPLUS, MOVE, SPECIAL-USE, NAMESPACE, ID, UNSELECT, ENABLE. CREATE/RENAME/DELETE 는 거부합니다.
|
|
|
|
확인:
|
|
```bash
|
|
openssl s_client -connect mail.arihakdang.com:993 -quiet # * OK [CAPABILITY ...] 가 보여야 함
|
|
```
|
|
|
|
## 6. 메일 클라이언트 설정
|
|
|
|
| 항목 | 값 |
|
|
|---|---|
|
|
| 받는 메일(IMAP, 권장) | `mail.arihakdang.com`, 포트 993 (SSL/TLS) 또는 143 (STARTTLS, 또는 일반 접속*) |
|
|
| 받는 메일(POP3) | `mail.arihakdang.com`, 포트 995 (SSL/TLS) 또는 110 (STARTTLS, 또는 일반 접속*) |
|
|
| 보내는 메일(SMTP) | `mail.arihakdang.com`, 포트 465 (SSL/TLS) 또는 587 (STARTTLS), 인증: 일반 비밀번호 |
|
|
| 사용자 이름 | `admin` 또는 `admin@arihakdang.com` (www 관리자 로그인 ID·이메일도 가능). 게이트웨이 계정은 그 로그인 ID |
|
|
| 비밀번호 | 웹 메일 로그인 비밀번호 (받는 서버·보내는 서버 모두 같음) |
|
|
| 보내는 사람 | 계정의 메일함 주소(예: `admin@arihakdang.com`). 다른 주소는 서버가 거부합니다(관리자는 게이트웨이의 모든 메일함 주소 가능). |
|
|
|
|
\* 일반 접속(암호화 없이 110/143 에 비밀번호를 보내는 방식)은 관리자 페이지 → 계정 관리 → "POP / IMAP 서비스" 카드의 **일반 접속 로그인 허용** 스위치(0.9.7, 기본 켬)를 따릅니다.
|
|
Gmail 의 "다른 계정에서 메일 확인(POP3)" 은 110 포트에서 STLS 를 쓰지 않고 바로 로그인하므로 이 스위치가 꺼져 있으면 Gmail 이 "사용자 이름과 비밀번호가 일치하지 않음" 으로 보여 줍니다.
|
|
가능하면 Gmail 에서 "보안 연결(SSL) 사용" 을 켜고 995 를 쓰세요. 환경 변수 `POP_ALLOW_PLAINTEXT=1` 은 관리자 설정과 무관하게 항상 허용(진단용)이고, 그 밖의 값은 관리자 설정을 따릅니다.
|
|
|
|
POP3 로 받아도 서버 저장본은 지우지 않으며("서버에 메시지 복사본 남기기" 옵션과 무관) 웹에서 영구 삭제할 때까지 남습니다.
|
|
SMTP 로 보낸 메일은 곧바로 웹의 보낸 메일함에 저장됩니다. 메일 프로그램이 IMAP `Sent` 에 사본을 올려도 Message-ID 로 한 통으로 합칩니다.
|
|
|
|
### SMTP 제출 서버 (0.8.1~)
|
|
|
|
0.8.0 까지는 메일 프로그램이 Resend SMTP 에 직접 접속하며 **Resend API 키를 SMTP 비밀번호로** 썼습니다.
|
|
키가 사용자 PC 와 메일 프로그램 설정에 퍼지는 문제를 없애려고, 게이트웨이가 SMTP 제출 서버(`server/smtp.mjs`)를 직접 엽니다.
|
|
|
|
- 포트 465(접속 즉시 TLS)·587(STARTTLS). 인증서는 POP·IMAP 과 같은 파일이고, 인증(AUTH PLAIN/LOGIN)은 TLS 위에서만 받습니다.
|
|
- 계정·비밀번호는 웹 메일·IMAP·POP 과 같습니다. 인증한 사용자는 자기 메일함 주소로만 보낼 수 있습니다(헤더 From 과 봉투 MAIL FROM 모두 검사).
|
|
- 받은 원본을 해석해 **서버의 `RESEND_API_KEY` 로 Resend API(`POST /emails`)** 를 호출합니다. 숨은 참조는 봉투(RCPT)에만 있는 주소로 판단합니다.
|
|
같은 원본을 다시 보내면 멱등 키로 한 번만 발송합니다.
|
|
- 한도: 한 통 30MB(원본 기준), 받는 사람 50명. 인증 실패는 IP 당 15분 20회.
|
|
- 인증하지 않은 접속은 MAIL 단계에서 거부하므로 오픈 릴레이가 아닙니다. 외부 메일을 받는 MX 도 아닙니다(수신은 Resend).
|
|
- 환경 변수: `SMTP_PORT`(기본 587), `SMTPS_PORT`(기본 465), `SMTP_DISABLED=1`(끄기), `SMTP_ALLOW_PLAINTEXT=1`(진단용 평문 인증 허용).
|
|
- 기존에 메일 프로그램에 넣어 둔 Resend API 키는 더는 필요 없습니다. Resend 대시보드에서 그 키를 폐기하세요(서버 환경 파일의 키와 다른 키였다면).
|
|
|
|
## 7. 문제 확인
|
|
|
|
```bash
|
|
journalctl -u arihakdang-mail -n 100 --no-pager # 동기화·웹훅·POP 로그
|
|
curl -s http://127.0.0.1:8790/api/health
|
|
openssl s_client -connect mail.arihakdang.com:995 -quiet # +OK ... POP3 ready 가 보여야 함
|
|
```
|
|
|
|
- 메일 화면 상단의 연결 상태가 `mail_auth_failed` 이면 `RESEND_API_KEY` 가 폐기·변경된 것입니다.
|
|
- 연결 상태가 `mail_domain_unverified`(1.0.11~)이면 Resend 가 발신 도메인을 검증하지 못한 것입니다. 관리자 › 서버 상태(또는 전체 설정 화면 › 자동 설정)에 **어느 DNS 레코드가 없거나 값이 다른지**
|
|
문장으로 보입니다(예: `검증 실패 — 값이 다른 레코드: TXT resend._domainkey.<도메인> (지금 p=… / 필요 p=…)`). 값이 다르면 다른 Resend 계정·예전 등록의 값이니 표의 값으로 바꾸세요.
|
|
바꾸면 1시간마다 도는 자동 재검증이 Resend 에 검증을 다시 요청합니다(`RESEND_AUTO_VERIFY=0` 으로 끔). `mail_domain_missing` 은 Resend 계정에 도메인이 없는 것 — 자동 설정 실행.
|
|
`mail_forbidden` 은 그 밖의 403(키 권한 등)에만 씁니다.
|
|
- 관리자 페이지 → 서버 상태의 웹훅 처리 내역이 비어 있으면 Resend 엔드포인트 URL·이벤트·Signing Secret 을 확인합니다.
|
|
- 995/993 이 열리지 않으면 인증서 경로(`POP_TLS_CERT/KEY`)와 `arihakdang` 계정의 읽기 권한을 확인합니다.
|
|
- POP 이 "되다말다" 하면 `journalctl` 의 `POP3` 줄을 봅니다(0.9.7~): `POP3 평문 로그인 거부`(110 에서 STLS 없이 로그인 → 일반 접속 로그인 허용 스위치 확인),
|
|
`POP3 접속 거부 … 다른 세션 … 사용 중`(같은 계정의 다른 메일 프로그램이 아직 연결돼 있음 → `-ERR [IN-USE]`, 그 세션이 끝나면 바로 됨),
|
|
`POP3 종료 … RETR n·DELE m … (quit|timeout|error:…)`(세션 요약 — `timeout` 은 10분 동안 명령이 없어 끊은 것, `error:` 는 상대가 연결을 끊은 것).
|
|
- 화면에 "처리하지 못했습니다 (코드)" 가 보이면 괄호 안 코드가 서버 오류 코드입니다(0.8.25~). 배포 직후라면 화면이 서버 버전(`X-App-Version`)을 보고 스스로 새로 고치므로 보통 한 번만 보입니다.
|
|
- 메일 전달·자동 응답이 나가지 않으면 메일 상세 정보의 "자동 처리" 줄을 봅니다. `전달하지 않음 — …` 은 규칙상 건너뛴 것(되풀이 방지·72시간 지난 메일·같은 상대 24시간 안 응답 등)이고,
|
|
`전달 실패 / 자동 응답 실패` 는 발송 서비스 오류입니다(`journalctl` 에 `메일 전달 실패` / `자동 응답 실패` 로 남음). 기록은 DB 의 `auto_actions` 표에 있습니다.
|
|
|
|
## 8. 다른 도메인에 독립 설치 (예: mail.heart-m.com)
|
|
|
|
0.8.18 부터 www 사이트 없이 **독립 실행(standalone)** 으로 다른 서버·도메인에 설치할 수 있습니다. 설치는 mail.heart-m.com(115.68.193.164, 실행 계정 `webmaster`)을 기준으로 적습니다.
|
|
|
|
1. **사이트 설정 파일** `deploy/sites/heart-m.env` — 서비스 이름(`heart-mail`), 실행 계정, 경로(`/srv/heart-mail`, `/etc/heart-mail`), Node 경로, 포트, 호스트, 기본 메일함(`admin@heart-m.com`),
|
|
탭 제목(`SITE_TITLE`, 비우면 서비스 이름과 같음), `LOGIN_MODE=standalone`(0.9.0 설치 옵션, 9절). 새 사이트 파일은 0.9.0 부터 `deploy/new-site.sh` 로 만듭니다:
|
|
```bash
|
|
bash deploy/new-site.sh cafe --host mail.cafe.heart-m.com --mailbox admin@cafe.heart-m.com --user webmaster \
|
|
--limit-accounts 20 --limit-mailbox 500M --limit-attachment 20M # 기본은 --login standalone, 제한 0 = 없음
|
|
bash deploy/new-site.sh shop --host mail.shop.test --mailbox admin@shop.test --login www --www-db /srv/shop/data/shop.sqlite # www 연동
|
|
```
|
|
왼쪽 위 서비스 이름은 0.8.25 부터 메일 도메인에서 자동으로 정합니다(heart-m.com → "HEART-M 메일", cafe.heart-m.com → "CAFE 메일"). `SITE_BRAND` 는 더 쓰지 않습니다(남아 있어도 무시).
|
|
2. **서버 준비(root)**: 실행 계정이 있어야 하고(`id webmaster`), Node 22.13+ 를 `NODE_BIN` 경로에 둡니다(패키지 저장소 없이 nodejs.org 바이너리를 푸는 방식).
|
|
```bash
|
|
curl -fsSLO https://nodejs.org/dist/v22.23.3/node-v22.23.3-linux-x64.tar.xz && sudo mkdir -p /opt/heart-mail-node \
|
|
&& sudo tar -xJf node-v22.23.3-linux-x64.tar.xz -C /opt/heart-mail-node --strip-components=1
|
|
git bundle create /tmp/mail-gateway.bundle main && scp /tmp/mail-gateway.bundle heart:/tmp/ # 작업 PC 에서
|
|
sudo install -o webmaster -g webmaster -m 644 /tmp/mail-gateway.bundle /srv/heart-mail/source.bundle # 서버에서(디렉터리는 setup.sh 가 만들지만 번들은 먼저 둬도 됨)
|
|
sudo env SITE=heart-m SOURCE_BUNDLE=/srv/heart-mail/source.bundle bash /path/to/repo/deploy/setup.sh
|
|
```
|
|
`setup.sh` 는 `/srv/heart-mail/{repo,releases,data}`, `/srv/heart-mail/site.env`, `/etc/heart-mail/gateway.env`, `heart-mail.service`, sudoers, nginx vhost(`mail.heart-m.com.conf`), certbot 훅을 만듭니다.
|
|
3. **환경 파일** `/etc/heart-mail/gateway.env` 에 `RESEND_API_KEY` 와 `RESEND_WEBHOOK_SECRET` 를 채웁니다(heart-m.com 이 Resend 에 수신·발신 도메인으로 등록되어 있어야 함).
|
|
Resend 웹훅 엔드포인트는 `https://mail.heart-m.com/api/webhooks/resend`(3절과 같음).
|
|
4. **배포**: `sudo -u webmaster env SOURCE_BUNDLE=/srv/heart-mail/source.bundle /srv/heart-mail/repo/deploy/deploy.sh` — 테스트·릴리스 복사·마이그레이션·재시작·health.
|
|
이후 갱신도 같은 명령입니다(번들만 새로 올림).
|
|
5. **첫 관리자 계정** (0.8.24~): 독립 실행이고 계정이 하나도 없으면 서버가 시작할 때 **`admin` / `adminpasswd`** 관리자 계정(기본 메일함 admin@heart-m.com 의 주인)을 자동으로 만들고
|
|
journal 에 안내를 남깁니다. `https://mail.heart-m.com/admin` 에 그 비밀번호로 로그인하면 "초기 비밀번호 사용 중" 경고가 보이며, 계정 관리에서 admin 계정을 열어 비밀번호를 바꾸면 사라집니다.
|
|
초기 비밀번호는 비밀번호 정책과 무관하게 글자 수 하한(6)만 적용됩니다(예전에는 10자 규칙 때문에 짧은 초기 비밀번호를 만들 수 없었음).
|
|
셸에서 비밀번호를 재설정하거나 계정을 추가하려면:
|
|
```bash
|
|
sudo -u webmaster env $(sudo grep -E '^(DB_FILE|MAILBOX)=' /etc/heart-mail/gateway.env | xargs) \
|
|
/opt/heart-mail-node/bin/node /srv/heart-mail/current/server/user-cli.mjs passwd admin # 또는 add <login> [--admin] / list
|
|
# 비밀번호는 단말에서 숨겨 입력(또는 PASSWORD=... 환경 변수 / --password-stdin). 규칙은 관리자 페이지의 비밀번호 정책을 따릅니다.
|
|
```
|
|
나머지 계정은 `https://mail.heart-m.com/admin` 에서 만듭니다.
|
|
6. **DNS 와 인증서**: `mail.heart-m.com` A 레코드를 115.68.193.164 로 바꿉니다(프록시 없이). DNS 가 바뀌기 전에는 nginx 가 80 포트(ACME 챌린지)만 열고 나머지는 503 이며,
|
|
`heart-mail-tls.timer` 가 15분마다 A 레코드를 확인해 이 서버를 가리키면 certbot(webroot)으로 발급 → `setup.sh` 재실행 → 443·995/993/465 TLS 를 켜고 타이머를 끕니다.
|
|
바로 하려면 `sudo bash /srv/heart-mail/repo/deploy/tls-when-ready.sh /srv/heart-mail/site.env`. 갱신은 certbot 타이머와 훅이 맡습니다.
|
|
7. **확인**: `curl -s http://127.0.0.1:8790/api/health`, `journalctl -u heart-mail -n 50 --no-pager`, `systemctl list-timers heart-mail-tls.timer`.
|
|
메일 프로그램 설정값은 6절과 같되 호스트가 `mail.heart-m.com`, 사용자 이름이 게이트웨이 계정의 로그인 ID 또는 `로그인ID@heart-m.com` 입니다.
|
|
|
|
## 9. 설치 옵션: 로그인 방식과 시스템 제한 (0.9.0~)
|
|
|
|
설치·배포 때 사이트 설정 파일(`deploy/sites/<이름>.env`, `new-site.sh` 가 만듦)에서 정합니다. `setup.sh` 가 **처음 한 번** `gateway.env` 를 만들 때 이 값을 넣으므로,
|
|
이미 설치된 서버에서 바꾸려면 `<ETC_DIR>/gateway.env` 를 직접 고치고 `systemctl restart <서비스>` 합니다(mail.heart-m.com 의 환경 파일은 0.9.0 배포에서 건드리지 않았으며,
|
|
값이 없으면 모두 "제한 없음" 과 `standalone` 으로 동작합니다).
|
|
|
|
**로그인 방식 `LOGIN_MODE`** — 독립 실행이 기본 설치 형태입니다.
|
|
- `standalone`(기본): www 사이트와 연동하지 않습니다. 첫 관리자 `admin / adminpasswd` 가 자동으로 생기고, 계정은 관리자 페이지(또는 회원 가입)로 만듭니다. `WWW_DB_FILE` 은 무시됩니다.
|
|
- `www`: www 사이트 DB(`WWW_DB_FILE`, 필수)로 관리자를 인증합니다(mail.arihakdang.com). 경로가 없으면 서비스가 시작하지 않습니다.
|
|
- 값이 없으면 0.8.x 처럼 `WWW_DB_FILE` 유무로 정합니다(기존 서버 호환).
|
|
|
|
**시스템 제한 `LIMIT_*`** — 메일 시스템 전체의 상위 설정입니다. 관리자 페이지에서는 볼 수만 있고, 관리자가 정하는 값(계정별 메일함 크기, 첨부 크기, 받는 사람 수)은 이 값 이내로만 저장됩니다. **모두 0 이면 제한 없음.**
|
|
|
|
| 변수 | 뜻 | 어긋나면 |
|
|
|---|---|---|
|
|
| `LIMIT_ACCOUNTS` | 허용 가능한 메일 계정 수(정지·승인 대기 포함) | 계정 추가·회원 가입이 `account_limit_reached` 로 거부 |
|
|
| `LIMIT_TOTAL_BYTES` | 모든 메일함을 합친 최대 용량 | 수신은 `storage_full` 로 건너뜀(공간이 생기면 다음 동기화가 가져옴), 발송은 거부 |
|
|
| `LIMIT_MAILBOX_BYTES` | 개별 메일함 최대 용량(관리자·계정별 값의 상한) | 그 메일함 수신 건너뜀(`quota_exceeded`), 웹·SMTP 발송 거부(`452 4.2.2`), IMAP APPEND `NO [OVERQUOTA]` |
|
|
| `LIMIT_ATTACHMENT_BYTES` | 첨부 파일 한 개 최대 크기(관리자 값의 상한, 내장 상한 25MB) | 웹 첨부·전달 복사 `attachment_too_large`, SMTP `552 5.3.4` |
|
|
| `LIMIT_RECIPIENTS` | 한 메일의 받는 사람 수(참조·숨은 참조 포함, 내장 상한 50) | 웹 발송 `too_many_recipients`, SMTP `452 4.5.3` |
|
|
| `LIMIT_MONTHLY_MESSAGES` | 월간(1일~말일, Asia/Seoul) 최대 수발신 통수(보낸 + 받은) | 발송 거부(`monthly_limit_exceeded`, SMTP `550 5.7.1`), 자동 전달·자동 응답 건너뜀(limit) |
|
|
|
|
**대용량 첨부파일 상한(0.9.3)** — 다른 `LIMIT_*` 와 달리 **무제한이 없습니다**. 비우거나 0 이면 기본값이 적용됩니다.
|
|
|
|
| 변수 | 뜻 | 기본값 |
|
|
|---|---|---|
|
|
| `LIMIT_LARGE_FILE_BYTES` | 대용량 파일 한 개 최대 크기(관리자 설정의 상한) | `1G` |
|
|
| `LIMIT_LARGE_FILE_DAYS` | 보관 최대 기간(일) | `30` |
|
|
| `LIMIT_LARGE_FILE_DOWNLOADS` | 다운로드 최대 횟수 | `20` |
|
|
| `FILES_DIR` | 파일 저장 디렉터리(비우면 DB 옆 `files/`) | |
|
|
|
|
크기 값은 바이트 또는 `K`/`M`/`G` 접미사(`500M`, `2G`)이며 **MIME 변환 뒤의 크기** 기준입니다. 메일은 저장·전송될 때 첨부가 base64 로 바뀌어 약 1.37배가 되므로
|
|
사용량(저장된 원본 `.eml` 크기)과 모든 제한을 그 크기로 셉니다. 첨부 파일을 올릴 때는 파일 크기 × 4/3 을 제한과 비교합니다.
|
|
메일 현황의 시간대는 `STATS_TIMEZONE`(기본 `Asia/Seoul`)으로 바꿀 수 있습니다.
|
|
|
|
## 10. 설정 파일과 초기 설정 페이지 (1.0.0)
|
|
|
|
설정은 두 층입니다.
|
|
|
|
| 층 | 어디에 | 무엇 | 바꾸는 방법 |
|
|
|---|---|---|---|
|
|
| 배포 설정 | `/etc/<서비스>/gateway.env` (systemd EnvironmentFile) | DB 경로, 포트, 기본 메일함·공개 호스트, 로그인 방식, 시스템 제한 `LIMIT_*`, TLS 사본 경로, `SETUP_PORT`, `HARAKA_DIR` | root 가 파일을 고치고 서비스 재시작 |
|
|
| 운영 설정 | `<APP_DIR>/data/config.json` (실행 계정만 읽음) | 수·발신 방식, Resend API 키·웹훅 비밀키, SMTP 중계 서버, 내장 Haraka(포트·DKIM), 발신 표시 이름, 탭 제목, 통계 시간대, 동기화 주기 | **초기 설정 페이지** 또는 `/admin` → **메일 서비스 설정**. 저장 즉시 적용(재시작 없음) |
|
|
|
|
- **왜 나눴나**: 운영 설정은 처음 배포할 때 알 수 없거나(키를 아직 만들지 않음) 배포 자체에는 필요하지 않습니다. 비어 있어도 배포는 성공해야 하고, 채울 때 root 작업과 재시작이 없어야 합니다.
|
|
- **기존 서버**: 설정 파일이 없으면 첫 시작 때 환경 파일에 있던 값(`RESEND_API_KEY` 등)을 그대로 읽어 설정 파일을 만듭니다. 환경 파일은 그대로 두어도 됩니다.
|
|
그 뒤로는 설정 파일 값이 우선합니다(설정 파일에서 지운 값은 환경 파일 값으로 되살아나지 않음). 설정 화면의 각 항목 아래에 출처(설정 파일 / 환경 파일 값 / 기본값)가 보입니다.
|
|
- **초기 설정 페이지**: 게이트웨이가 전용 포트(`SETUP_PORT`, 기본 **8791**, 모든 주소)에서 엽니다. 접속에는 데이터 디렉터리의 `setup-token`(배포 계정만 읽음)이 필요하며,
|
|
`deploy.sh` 가 끝에 전체 주소(`…:8791/?token=…`)를 출력하고 `data/setup-url.txt` 에도 남깁니다. 틀린 토큰은 IP 당 15분 10회만 받습니다.
|
|
메일 포트 인증서(`POP_TLS_CERT`)를 읽을 수 있으면 HTTPS 로, 없으면 HTTP 로 엽니다(새 서버는 인증서 전이라 HTTP — 토큰이 노출되므로 설정이 끝나면 토큰 파일을 바꾸거나 `SETUP_PORT=0` 으로 끌 수 있음).
|
|
방화벽을 쓰면 8791 을 열어야 합니다(`sudo ufw allow 8791/tcp`). 운영 중에는 `https://<호스트>/setup`(관리자 세션)으로 같은 화면을 엽니다.
|
|
- **화면 구성**: 현재 상태(수·발신 방식, 발신 서비스 연결, Haraka, 설정 파일) → ① 수·발신 방식 → ② Resend → ③ SMTP 중계 서버 → ④ 내장 Haraka(DKIM 키 생성, DNS 레코드, 서비스 상태·로그) → ⑤ 사이트 정보 → ⑥ 마무리(점검표, 완료 표시, systemd 아래면 재시작).
|
|
고른 방식에 필요한 카드만 보입니다. 비밀값은 가려서 보이며(`re_••••abcd`) 입력 칸을 비워 두면 그대로, "비우기" 를 누르면 지워집니다.
|
|
- **API**: `GET/PUT /api/setup/config`, `POST /api/setup/check {what:'outbound'|'haraka'}`, `POST /api/setup/dkim`, `POST /api/setup/restart`. 전용 포트는 `X-Setup-Token`(또는 `?token=`), 웹 서버는 관리자 세션 + `X-Mail-Scope: admin`.
|
|
|
|
## 11. 발송 모듈 (1.0.0)
|
|
|
|
발송은 `server/providers/index.mjs` 의 `sendMail(env, payload, key)` 한 곳을 거치며, 설정의 **발신 방식(outbound)** 이 모듈을 고릅니다.
|
|
|
|
| 발신 방식 | 모듈 | 설명 |
|
|
|---|---|---|
|
|
| `resend` | `providers/resend.mjs` | Resend REST API(예전과 같음). 도메인이 Resend 에 검증되어 있어야 함 |
|
|
| `haraka` | `providers/smtp.mjs` → 127.0.0.1:`HARAKA_RELAY_PORT`(2525) | 내장 Haraka 의 로컬 제출 포트로 넘기면 Haraka 가 받는 쪽 MX 에 직접 배달(12절) |
|
|
| `smtp` | `providers/smtp.mjs` → `SMTP_RELAY_HOST:PORT` | 외부 SMTP 중계 서버(587 STARTTLS / 465 TLS / 인증 선택). 보낸 사람 도메인을 그 서버가 허용해야 함 |
|
|
|
|
메시지 객체는 Resend 요청과 같은 모양(from, to, cc, bcc, reply_to, subject, text, html, headers, attachments[{filename, content(base64), content_type, content_id}])이라
|
|
웹 발송(store.mjs)·SMTP 제출 서버(smtp.mjs)·자동 전달/응답(automation.mjs)은 어느 모듈을 쓰는지 모릅니다. SMTP 쪽은 `mime.mjs` 의 `buildEml` 로 원본을 만들고(Bcc 는 봉투에만),
|
|
의존성 없는 SMTP 클라이언트(`providers/smtp-client.mjs`)로 보냅니다. 오류 코드는 공통(`mail_not_configured` / `mail_auth_failed` / `mail_rejected` / `mail_rate_limited` / `mail_provider_unavailable`)이라
|
|
화면 문구와 SMTP 제출 서버의 응답 변환이 그대로 동작합니다. 새 발송 서비스를 더하려면 `providers/<이름>.mjs` 에 같은 모양의 send 를 만들고 `index.mjs` 에 한 줄씩 더합니다.
|
|
|
|
수신 방식(inbound)은 `resend`(웹훅 + 동기화) 또는 `haraka`(12절)입니다. Resend 동기화는 Resend 를 쓰는 방향만 훑습니다(수신이 Haraka 면 받은 메일 목록은 보지 않음).
|
|
|
|
## 12. 내장 Haraka (1.0.0)
|
|
|
|
[Haraka](https://haraka.github.io/)(Node.js 메일 서버)를 함께 띄워 **Resend 없이** 메일을 받거나(MX) 보낼 수 있습니다. 조합은 자유입니다(예: 수신 Haraka + 발신 Resend).
|
|
|
|
- **설치**: 저장소의 `haraka/package.json`(Haraka 3.3.4 + `haraka-plugin-dkim`)을 `deploy/haraka-apply.sh` 가 `<APP_DIR>/haraka` 에 npm 으로 설치하고 systemd 서비스 `<APP_NAME>-haraka` 를 등록합니다.
|
|
새 사이트는 `setup.sh` 가 자동으로 부르고, 기존 사이트는 한 번 실행합니다: `sudo bash <APP_DIR>/repo/deploy/haraka-apply.sh`(인터넷 필요, 환경 파일·데이터는 건드리지 않음).
|
|
- **동작**: 관리 프로세스 `haraka/run.mjs` 가 항상 떠 있으면서 설정 파일을 5초마다 보고, 수신 또는 발신 방식이 `haraka` 이면 Haraka 설정(`<APP_DIR>/haraka/config/*`, 플러그인 `plugins/arimail.js`)을 만들어
|
|
Haraka 를 자식 프로세스로 띄우고, 아니면 끕니다. 상태는 `data/haraka-status.json` 에 써서 설정 화면·서버 상태에 보입니다. 로그: `journalctl -u <APP_NAME>-haraka -f`.
|
|
- **수신**: Haraka 가 `HARAKA_PORT`(25)로 받아 RCPT 단계에서 게이트웨이에 메일함이 있는지 확인하고(없는 사용자는 550), DATA 가 끝나면 원본을 `POST /api/inbound/haraka`(로컬, 토큰 인증)로 넘깁니다.
|
|
게이트웨이는 Resend 경로와 같은 규칙으로 저장합니다(중복·영구 삭제·용량·사본·자동 전달/응답). 메일함이 가득 차면 452 로 보낸 쪽이 나중에 다시 보냅니다.
|
|
DNS 의 **MX** 를 이 서버(`HARAKA_HOSTNAME`, 기본 공개 호스트 이름)로 바꾸고 방화벽에서 25 를 열어야 합니다.
|
|
- **발신**: 게이트웨이가 127.0.0.1:`HARAKA_RELAY_PORT`(2525, 로컬 전용)로 넘기면 Haraka 가 받는 쪽 MX 에 직접 배달하고 실패는 재시도·반송합니다.
|
|
설정 화면에서 **DKIM 키 만들기** 를 누르면 RSA 2048 키가 설정 파일에 저장되고 Haraka 가 서명합니다. 화면의 **SPF·DKIM(·DMARC) TXT 레코드**를 DNS 에 올리고, 서버 IP 의 역방향 DNS(PTR)가
|
|
메일 서버 이름을 가리키게 호스팅 업체에 요청하세요(없으면 스팸 분류가 잦습니다). STARTTLS 는 메일 포트 인증서(`POP_TLS_CERT`)를 그대로 씁니다.
|
|
- **환경 변수**: `HARAKA_DIR`(설치 위치), `HARAKA_LOGLEVEL`(기본 info). 그 밖의 값(포트·호스트 이름·DKIM)은 설정 파일에 있습니다.
|
|
|
|
## 13. 자동 설정과 DNS 모듈 (1.0.5)
|
|
|
|
설정 화면의 **자동 설정** 카드가 수·발신 방식과 도메인에 맞는 준비 상태를 진단하고(`GET /api/setup/plan`), 자동으로 할 수 있는 일은 **자동 설정 실행**(`POST /api/setup/plan/run`) 한 번으로 처리합니다(`server/provision.mjs`).
|
|
단계마다 상태(완료 / 자동 실행 가능 / 반영 대기 / 사용자 작업 / 오류 / 참고)와 안내 문구가 붙고, 사람이 해야 하는 단계는 입력 칸이나 단추를 함께 보여 줍니다.
|
|
|
|
| 구성 | 자동으로 하는 일 | 사용자가 하는 일(안내) |
|
|
|---|---|---|
|
|
| Resend 수·발신 | 도메인 등록(지역 `RESEND_REGION`)과 발송/수신 기능 맞춤, 요구 DNS 레코드(DKIM TXT·`send` CNAME·수신 MX) 적용(DNS 모듈이 있을 때), 검증 요청과 상태 추적(`pending`/`verified`/`failed`/`temporary_failure`), 수신 웹훅 생성과 **서명 비밀키 자동 저장** | API 키 입력, DNS 모듈이 없으면 표의 레코드를 직접 넣고 "반영 확인", 웹훅 비밀키를 잃었으면 입력 또는 "웹훅 새로 만들기" |
|
|
| 내장 Haraka | DKIM 키 생성, MX/SPF/DKIM 레코드 적용(기존 SPF 가 있으면 우리 메커니즘만 끼워 넣음), 실행 상태·PTR 확인 | `deploy/haraka-apply.sh` 실행(설치), 방화벽 25 개방, 호스팅 업체에 PTR 요청 |
|
|
| 외부 SMTP 중계 | 접속·인증 확인 | 접속 정보 입력 |
|
|
|
|
- **DNS 모듈**(`server/dns/`, 요구사항 1): `DNS_PROVIDER` 가 `google`(Google Cloud DNS, 서비스 계정 JSON) 또는 `route53`(AWS Route 53, 액세스 키)이면 존을 자동으로 찾아 레코드를 UPSERT 합니다(외부 의존성 없이 OAuth2 JWT / SigV4 서명 구현).
|
|
`none` 이면 자동 적용 없이 표의 레코드를 보여 주고 공개 리졸버(8.8.8.8 / 1.1.1.1)로 반영 여부만 확인합니다. DMARC 는 권장 레코드로 보여 주되 자동으로 넣지 않습니다(기존 정책을 덮어쓰지 않기 위해).
|
|
권한: Google 은 프로젝트의 "DNS 관리자", AWS 는 `route53:ListHostedZonesByName/GetHostedZone/ListResourceRecordSets/ChangeResourceRecordSets`.
|
|
- **Resend 모듈**(`server/providers/resend.mjs`, 요구사항 3): 도메인 목록·등록·기능 변경·검증, 웹훅 목록·생성·삭제를 담당합니다. 자동 설정은 이 모듈만 통해 Resend 를 바꿉니다.
|
|
- **검증 실패 진단과 자동 재검증**(1.0.11): Resend 도메인이 `failed` 면 레코드마다 공개 DNS 조회로 "없음(전파 대기)" 과 "값이 다름(바꿔야 함)" 을 구분해 단계 문구와 표의 "지금 값" 으로 보여 줍니다.
|
|
Resend 자신이 verified 라고 하는 레코드는 우리 조회 값이 달라도 정상으로 봅니다(예: 예전 수신 MX 값). 레코드가 모두 보이면 정기 동기화 주기(기본 1시간)마다 검증을 자동으로 다시 요청하므로
|
|
"지금 검증 요청" 을 누르지 않아도 됩니다. 발신 상태(`/api/mail/status`, 서버 상태 화면)도 `mail_domain_unverified`(원인 문장 `detail`, 레코드별 `records`) / `mail_domain_missing` 으로 구분합니다.
|
|
- **상황별 안내**: 인증 정보 없음·형식 오류·권한 없음·존 없음·연결 실패(DNS), 키 거부·권한·요청 제한(Resend), 미설치·서비스 꺼짐·실행 대기·PTR 불일치(Haraka) 등 각 단계의 `detail` 에 원인과 다음 할 일이 적힙니다. 모든 단계가 끝나면 "메일 사용 준비가 끝났습니다" 를 알립니다.
|
|
|
|
## 14. 다중 도메인과 전체 설정 화면 (1.0.7)
|
|
|
|
한 서버(한 프로세스)가 여러 도메인의 메일 서비스를 섬깁니다(`server/domains.mjs`). 도메인마다 계정·세션·메일·설정 파일·파일 저장소가 따로이고, 로그인과 계정 관리는 도메인 단위입니다.
|
|
|
|
| | 기본 도메인 | 추가 도메인 |
|
|
|---|---|---|
|
|
| 정해지는 곳 | 환경 파일(`MAILBOX`·`PUBLIC_HOST`·`LOGIN_MODE`·`WWW_DB_FILE`·`DB_FILE`) | 전체 설정 화면의 **도메인** 카드(재시작 없음) |
|
|
| 데이터 | `data/mail-gateway.sqlite`, `data/config.json`, `data/files/` (예전 그대로) | `data/domains/<도메인>/{mail.sqlite, config.json, files/}` |
|
|
| 웹 메일 주소 | `PUBLIC_HOST` (+ 등록부의 추가 호스트) | 등록한 호스트 이름(기본 `mail.<도메인>`) — nginx vhost 와 인증서는 `sudo bash deploy/domain-nginx.sh <호스트>` |
|
|
| 로그인 방식 | 환경 파일 | `local`(자체 계정, 첫 관리자 `admin` 자동 생성) 또는 `www`(연결된 웹 서비스의 SQLite `users` 표로 관리자 인증) |
|
|
| 메일 프로그램 | `PUBLIC_HOST`:993/995/465/587 | 같은 서버 이름(기본 도메인 호스트)에 `아이디@도메인` 으로 로그인 — 인증서가 하나이므로 |
|
|
|
|
- **등록부** `data/domains.json`: 1.0.7 로 올린 서버는 첫 시작에 기본 도메인만 담아 만들고(데이터 이동 없음) 예전과 똑같이 동작합니다. 추가 도메인의 설정 파일은 기본 도메인의 설정에서 API 키·DNS 인증 정보·SMTP 중계·Haraka 포트·시간대를 복사해 시작할 수 있습니다.
|
|
- **요청 → 도메인**: HTTP 는 Host(X-Forwarded-Host). 등록된 호스트 이름과 같거나 도메인의 하위 이름이면 그 도메인, IP·localhost 는 기본 도메인. 모르는 호스트에는 "메일 서비스가 존재하지 않습니다", 중지한 도메인에는 "메일 서비스가 활성화되지 않았습니다"(관리자에게 요청) 화면을 줍니다. 메일 프로그램은 로그인 ID 의 `@도메인`(없으면 TLS SNI 호스트, 그래도 없으면 기본 도메인).
|
|
- **전체 설정 화면**: 기본 도메인의 전용 포트(`https://<PUBLIC_HOST>:8791/?token=…`, 배포 출력에 주소). 맨 위 도메인 카드에서 추가·수정·중지/사용·삭제(등록 해제만, 디렉터리는 남김)하고, 행의 "선택" 으로 고른 도메인의 설정을 아래 카드에서 바꿉니다. 추가 도메인의 호스트 이름으로 이 포트에 오면 열리지 않습니다(기본 도메인 주소 안내). 관리자 페이지의 `/setup` 은 자기 도메인만.
|
|
- **서버에 하나뿐인 것**(기본 도메인 설정을 따름): 메일 포트·인증서, 내장 Haraka 의 수신/제출 포트·메일 서버 이름·게이트웨이 토큰. Haraka 는 수신 방식이 haraka 인 모든 도메인을 받고(받는 사람 주소로 나눔), 발신 haraka + DKIM 키가 있는 도메인마다 `config/dkim/<도메인>/` 키로 서명합니다.
|
|
- **www 연동 도메인**: 그 SQLite 파일을 서비스 계정이 읽을 수 있어야 하며 systemd 의 `ReadWritePaths`(사이트 설정 `EXTRA_RW`)에 그 디렉터리(WAL 의 -shm 파일 때문)가 있어야 합니다.
|
|
- 추가 도메인의 명령줄 계정 도구: `DB_FILE=<APP_DIR>/data/domains/<도메인>/mail.sqlite MAILBOX=admin@<도메인> node server/user-cli.mjs …`
|
|
- API: `GET/POST /api/setup/domains`, `PATCH/DELETE /api/setup/domains/<도메인>`(전용 포트 전용), 그 밖의 `/api/setup/*` 에 `?domain=<도메인>`. 오류: `domain_exists`, `host_taken`, `www_db_unreadable`, `primary_domain`, `domain_not_found`, `validation`(field).
|
|
|
|
## 15. webmaker 인증 모드와 사이트의 /mail 경로 (1.0.8)
|
|
|
|
웹메이커(WebHosting_AI_agent, `https://source.ibit.kr/OZ-Group/WebHosting_AI_agent`)의 사용자 계정으로 AriMail 에 로그인하게 하는 로그인 방식입니다(`server/webmaker.mjs`). 웹메이커의 **사용자 파일을 읽기 전용으로 참조**해 같은 방식(scrypt)으로 비밀번호를 검사하므로 계정을 따로 만들거나 메일 비밀번호를 따로 정하지 않습니다. 웹 메일·IMAP·POP·SMTP 모두 같은 비밀번호이며, 도메인마다 따로 켭니다.
|
|
|
|
| 웹메이커 쪽 | AriMail 계정 (도메인 D) | 역할 |
|
|
|---|---|---|
|
|
| 사이트 회원 중 로그인 ID 가 있는 계정(사이트 관리자 페이지 › 계정 추가, `modules/<사이트>.json` members.loginId) | `loginId@D` | 일반 |
|
|
| 사이트 소유자(`sites/<사이트>.json` ownerId → `users.json`) | `소유자ID@D` | 일반(웹메이커 관리자이기도 하면 관리자) |
|
|
| 웹메이커 관리자(`users.json` role=admin, 보통 `admin`) | `admin@D` | 관리자 |
|
|
| (도메인에 대응하는 사이트가 없을 때) 웹메이커의 모든 회원 | `아이디@D` | 관리자는 관리자, 나머지 일반 |
|
|
|
|
- 도메인 D 에 대응하는 사이트: 등록부의 `siteId` → 웹메이커 `domains.json` 의 서브 도메인 등록(name=D, siteId) → 사이트의 `domains` 목록 → 사이트의 메일 도메인(`webmail.domain`) 순으로 찾습니다. 같은 로그인 ID 가 겹치면 사이트 회원 → 소유자 → 플랫폼 관리자 순으로 먼저 찾은 쪽이 그 주소를 씁니다. 승인이 취소된 회원(approved=false)은 로그인할 수 없습니다.
|
|
- 예: 웹메이커에서 `site.ariweb.net` 사이트를 만들고 AriMail 에 도메인 `site.ariweb.net`(로그인 방식 webmaker)을 추가하면 `admin@site.ariweb.net`(웹메이커 admin 비밀번호)으로 바로 수·발신하고, 사이트 관리자 페이지에서 사용자 `user` 를 추가하면 `user@site.ariweb.net` 도 같은 비밀번호로 씁니다.
|
|
- 웹메이커에서 비밀번호를 바꾸거나 계정을 지우면 바로 반영됩니다(스냅샷 3초 캐시, 로그인 실패 시 한 번 다시 읽음). 웹메이커 계정의 이름·비밀번호·역할은 AriMail 에서 바꿀 수 없고(관리자 페이지에 읽기 전용 행), POP/IMAP 허용과 메일함 크기만 둡니다. 게이트웨이 계정(관리자 페이지에서 만든 것)은 함께 쓸 수 있되 웹메이커 계정과 같은 로그인 ID 는 만들 수 없습니다. webmaker 모드 도메인에는 초기 관리자 admin/adminpasswd 를 만들지 않습니다.
|
|
|
|
### 켜는 방법
|
|
|
|
1. **파일 읽기 권한**: 웹메이커 데이터(`DATA_ROOT`, 예 `/data/webmaker`)는 보통 웹메이커 서비스 계정(예: master)만 읽을 수 있고(0600/0700) 웹메이커가 파일을 다시 쓸 때마다 권한이 돌아옵니다. 같은 서버라면 root 로 한 번:
|
|
```bash
|
|
sudo bash /srv/<사이트>/repo/deploy/webmaker-access.sh /data/webmaker
|
|
```
|
|
root 소유 사본 `/usr/local/lib/arimail/webmaker-snapshot.mjs`(node 22+)와 **systemd 소켓 도우미**(`arimail-webmaker-<슬러그>.socket` + `@.service`: `/run/arimail-webmaker/data-webmaker.sock` 에 접속하면 웹메이커 소유 계정으로 스냅샷 JSON 을 써 줌, 소켓은 AriMail 계정 그룹만 0660)를 설치하고 실행 계정으로 읽어 봅니다. AriMail 서비스 유닛은 `NoNewPrivileges=yes` 라 sudo 가 동작하지 않으므로 소켓 방식이 기본이고, systemd 가 없는 서버는 `--sudo`(sudoers 규칙 한 줄, 그 디렉터리 인수만 허용)로 설치합니다. AriMail 실행 계정이 직접 읽을 수 있는 디렉터리면 이 단계는 필요 없습니다.
|
|
2. **도메인 설정**: 전체 설정 화면(§14)의 도메인 카드에서 추가·수정 → 로그인 방식 **웹메이커(webmaker) 계정과 연동**, 웹메이커 데이터 디렉터리 `/data/webmaker`, 파일을 읽을 계정 `master`(1단계를 했을 때 — 소켓 도우미가 있으면 소켓, 없으면 sudo 도우미를 씀), 사이트 ID 는 보통 비움. 등록부에는 `auth: { mode:'webmaker', webmakerDir, webmakerUser, siteId }` 로 저장됩니다. 기본 도메인은 환경 파일(`/etc/<app>/gateway.env`)에 `LOGIN_MODE=webmaker`, `WEBMAKER_DIR=/data/webmaker`, 선택 `WEBMAKER_USER=master`, `WEBMAKER_SITE=<32자리>` 를 적고 재시작합니다.
|
|
3. 확인: 관리자 페이지(웹메이커 admin 으로 로그인)의 계정 목록에 "웹메이커 계정" 행이 보입니다. 파일을 못 읽으면 도메인 목록과 계정 목록에 "읽기 실패" 와 사유가 보이고, 마지막으로 읽은 스냅샷이 있으면 그것으로 계속 동작합니다.
|
|
|
|
### 사이트 주소의 /mail 로 웹 메일 열기
|
|
|
|
서브 도메인 사이트(`site.ariweb.net`)는 메일용 호스트 이름(`mail.site.ariweb.net`)을 따로 두기 어렵습니다(와일드카드 인증서가 한 단계만 덮음). 그런 도메인은 사이트 주소의 `/mail` 아래를 웹 메일로 씁니다.
|
|
|
|
1. 도메인의 호스트 항목에 `site.ariweb.net/mail` 처럼 **호스트/경로** 를 적습니다(같은 호스트 이름을 경로만 달리해 두 번 적을 수는 없음).
|
|
2. 사이트의 nginx 설정에 조각을 넣습니다(root): `sudo bash deploy/site-mail-path.sh site.ariweb.net` (또는 설정 파일 경로). `deploy/nginx/mail-path.conf.in` 을 `/etc/nginx/snippets/<app>-mail-path.conf` 로 채우고 443 server 블록에 `include` 를 더합니다 — `location ^~ /mail/ { proxy_pass http://127.0.0.1:<포트>/; proxy_set_header X-Forwarded-Prefix /mail; … }`. 게이트웨이는 Host 로 도메인을, `X-Forwarded-Prefix`(없으면 등록부의 경로)로 화면의 기준 경로(`<html data-base="/mail/">`)를 압니다. 웹메이커는 사이트를 다시 발행할 때 vhost 파일(`wh-<사이트ID>.conf`)을 다시 쓰므로 그때 이 명령을 다시 실행하거나 웹메이커의 vhost 템플릿에 같은 include 를 넣어 둡니다. 사이트 폴더의 `mail/index.html`(웹메이커의 안내 파일)은 프록시가 먼저 받으므로 영향이 없습니다.
|
|
3. `https://site.ariweb.net/mail/` 이 웹 메일, `/mail/admin` 이 관리자 페이지, `/mail/setup` 이 설정 화면입니다. 세션 쿠키는 `Path=/mail` 로 한정됩니다.
|
|
4. **보안 참고**: 이 방식은 웹 메일이 사이트와 같은 출처(origin)를 씁니다. 사이트에 스크립트를 넣을 수 있는 사람(사이트 소유자)은 그 사이트를 방문한 로그인 사용자의 메일 API 를 같은 출처에서 부를 수 있으므로, 사이트 소유자를 믿을 수 없는 도메인은 별도 호스트 이름(`mail.<도메인>`, `domain-nginx.sh`)을 쓰세요. 메일 프로그램은 §14 와 같이 기본 도메인의 서버 이름에 `아이디@site.ariweb.net` 으로 접속합니다.
|
|
|
|
## 16. 메일 사용량 정보 제공 API (1.0.9)
|
|
|
|
웹메이커 같은 외부 관리 시스템이 도메인·계정별 디스크 사용량·메일 수·발송량을 읽는 읽기 전용 API 입니다. 전체 설정 화면(기본 도메인)의 **사용량 API** 카드에서 키를 만들면 켜지고(한 번만 표시), 접속 허용 IP 를 적어 웹메이커 서버만 부를 수 있게 합니다. 호출은 `GET /api/usage`(전체) · `GET /api/usage/<도메인>`(상세)에 `Authorization: Bearer <키>`. 자세한 응답 필드·보안 장치·웹메이커 쪽 예제는 [docs/USAGE-API.md](USAGE-API.md).
|
|
|