Files
AriWeb-Suite/modules/arimail/deploy/domain-nginx.sh
T

55 lines
4.7 KiB
Bash
Executable File

#!/usr/bin/env bash
# 추가 도메인의 웹 메일 호스트에 nginx vhost 와 Let's Encrypt 인증서를 준비합니다(1.0.7, 요구사항 1) — root 로 실행:
# sudo bash <APP_DIR>/repo/deploy/domain-nginx.sh mail.example.com [site.env 경로]
#
# 왜 필요한가
# 도메인 자체는 전체 설정 화면(기본 도메인의 8791 포트)에서 추가하면 게이트웨이가 바로 받기 시작하지만, 브라우저가 https://mail.example.com/ 으로
# 오려면 nginx 가 그 이름(server_name)과 인증서를 알아야 합니다. 이 스크립트는 기존 사이트의 nginx 템플릿(deploy/nginx/*.in)을 그 호스트 이름으로 채워
# 같은 게이트웨이 포트(PORT)로 넘기는 vhost 를 만들고 certbot 으로 인증서를 받습니다. 게이트웨이 설정·환경 파일·데이터는 건드리지 않습니다.
#
# 하는 일
# 1) 인증서가 없으면 80 전용(ACME 챌린지) vhost 로 시작하고, DNS(호스트 → 이 서버 IP)가 맞으면 certbot certonly --webroot 로 발급합니다.
# DNS 가 아직 안 바뀌었으면 안내만 하고 끝납니다(DNS 가 바뀐 뒤 다시 실행).
# 2) 인증서가 있으면 443 vhost(mail.conf.in)로 바꾸고 nginx 를 다시 읽습니다. 갱신 뒤 nginx 재적재용 certbot 훅도 둡니다.
# 참고: 메일 프로그램 포트(IMAP/POP/SMTP)의 인증서는 기본 도메인 것 하나이므로, 추가 도메인의 사용자도 메일 프로그램에는 기본 도메인의 호스트 이름으로 접속합니다
# (웹 메일의 "메일 프로그램 설정" 화면이 그 이름을 안내합니다).
set -euo pipefail
[ "$(id -u)" = 0 ] || { echo 'root 로 실행하세요' >&2; exit 1; }
. "$(dirname "$0")/lib.sh"
TARGET_HOST="$(printf '%s' "${1:?웹 메일 호스트 이름(예: mail.example.com)}" | tr 'A-Z' 'a-z')"
printf '%s' "$TARGET_HOST" | grep -Eq '^([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$' || { echo "호스트 이름 형식이 아닙니다: $TARGET_HOST" >&2; exit 1; }
SITE_FILE="${2:-}"
if [ -z "$SITE_FILE" ]; then APP_GUESS="$(cd "$DEPLOY_DIR/../.." && pwd)"; if [ -f "$APP_GUESS/site.env" ]; then SITE_FILE="$APP_GUESS/site.env"; else SITE_FILE="$DEPLOY_DIR/sites/${SITE:-arihakdang}.env"; fi; fi
load_site "$SITE_FILE"
[ "$TARGET_HOST" != "$MAIL_HOST" ] || { echo "$TARGET_HOST 는 기본 도메인의 호스트입니다(setup.sh / nginx-apply.sh 가 관리)." >&2; exit 1; }
# 템플릿의 @MAIL_HOST@ 자리를 이 호스트로 채웁니다(나머지 변수 — 포트·로그 이름·ACME 경로 — 는 사이트 설정 그대로).
MAIL_HOST="$TARGET_HOST"; export MAIL_HOST
TARGET="/etc/nginx/sites-available/$TARGET_HOST.conf"
apply() { render "$1" "$TARGET"; chmod 644 "$TARGET"; ln -sfn "$TARGET" "/etc/nginx/sites-enabled/$TARGET_HOST.conf"; nginx -t; systemctl reload nginx; }
echo "▶ 추가 도메인 호스트: $TARGET_HOST (사이트 $SITE, 게이트웨이 포트 $PORT)"
if [ ! -d "/etc/letsencrypt/live/$TARGET_HOST" ]; then
apply "$DEPLOY_DIR/nginx/mail.http-only.conf.in"
echo " 80 포트(ACME) 설정 적용. 인증서를 발급합니다…"
RESOLVED="$(getent ahostsv4 "$TARGET_HOST" 2>/dev/null | awk '{print $1}' | sort -u || true)"
MINE="$(ip -4 -o addr show scope global | awk '{print $4}' | cut -d/ -f1 | sort -u)"
MATCH=""; for a in $RESOLVED; do for b in $MINE; do [ "$a" = "$b" ] && MATCH="$a"; done; done
if [ -z "$MATCH" ]; then
echo " $TARGET_HOST 가 아직 이 서버를 가리키지 않습니다 (DNS: ${RESOLVED:-없음} / 서버: $MINE)."
echo " DNS 의 A 레코드를 이 서버로 바꾼 뒤 같은 명령을 다시 실행하세요. 그때까지 https 는 열리지 않습니다."
exit 0
fi
mkdir -p "$ACME_WEBROOT"
ACCOUNT_FLAG=""; ls /etc/letsencrypt/accounts/*/directory/*/regr.json >/dev/null 2>&1 || ACCOUNT_FLAG="--register-unsafely-without-email"
certbot certonly --webroot -w "$ACME_WEBROOT" -d "$TARGET_HOST" --non-interactive --agree-tos --keep-until-expiring $ACCOUNT_FLAG
fi
apply "$DEPLOY_DIR/nginx/mail.conf.in"
# 갱신 훅: 이 호스트의 인증서가 갱신되면 nginx 만 다시 읽습니다(메일 포트는 기본 도메인 인증서를 쓰므로 게이트웨이 재시작 불필요).
mkdir -p /etc/letsencrypt/renewal-hooks/deploy
cat > "/etc/letsencrypt/renewal-hooks/deploy/$APP_NAME-$TARGET_HOST.sh" <<HOOK
#!/bin/sh
# AriMail 추가 도메인($TARGET_HOST) 인증서 갱신 뒤 nginx 재적재
case "\${RENEWED_LINEAGE:-}" in */$TARGET_HOST*) systemctl reload nginx || true ;; esac
HOOK
chmod 755 "/etc/letsencrypt/renewal-hooks/deploy/$APP_NAME-$TARGET_HOST.sh"
echo "✔ https://$TARGET_HOST/ 준비 완료. 전체 설정 화면에서 이 호스트를 가진 도메인을 추가(또는 호스트 목록에 넣기)했는지 확인하세요."