Files
AriWeb-Suite/modules/arimail/deploy/site-mail-path.sh
T

65 lines
5.7 KiB
Bash
Executable File

#!/usr/bin/env bash
# 사이트의 /mail 경로를 AriMail 웹 메일로 잇습니다(1.0.8, 요구사항 1) — root 로 실행:
# sudo bash <APP_DIR>/repo/deploy/site-mail-path.sh <nginx 설정 파일 | 사이트 호스트 이름> [--path /mail] [--site <site.env 경로>]
# 예) sudo bash deploy/site-mail-path.sh site.ariweb.net # sites-enabled 에서 server_name 에 그 이름이 있는 설정 파일을 찾음
# sudo bash deploy/site-mail-path.sh /etc/nginx/sites-enabled/wh-0aa8….conf
#
# 왜 필요한가
# 웹메이커가 만든 서브 도메인 사이트(site.ariweb.net)는 메일용 호스트 이름(mail.site.ariweb.net)을 따로 두기 어렵습니다(와일드카드 인증서가 한 단계만 덮음).
# 그래서 그 사이트 주소의 /mail 아래를 게이트웨이로 넘겨 https://site.ariweb.net/mail/ 이 그 도메인의 웹 메일이 되게 합니다. 게이트웨이는 Host 로 도메인(테넌트)을
# 고르고 X-Forwarded-Prefix 로 화면의 기준 경로를 압니다. 전체 설정 화면의 호스트 항목에는 "site.ariweb.net/mail" 처럼 경로까지 적습니다.
#
# 하는 일
# 1) deploy/nginx/mail-path.conf.in 을 포트·경로로 채워 /etc/nginx/snippets/<APP_NAME>-mail-path.conf 로 둡니다(여러 사이트가 같은 조각을 include).
# 2) 지정한 설정 파일의 443 server 블록마다 그 조각의 include 줄을 넣습니다(이미 있으면 그대로, 80 전용 블록은 건드리지 않음 — https 로의 301 이 유지되게).
# 바꾸기 전 사본(<파일>.bak-<시각>)을 남기고 nginx -t 가 실패하면 되돌립니다.
# 3) nginx 를 다시 읽습니다.
# 주의: 웹메이커는 사이트를 다시 발행할 때 그 vhost 파일(wh-<사이트ID>.conf)을 다시 쓰므로 include 줄이 사라질 수 있습니다. 그때는 이 명령을 다시 실행하거나,
# 웹메이커의 vhost 템플릿(lib/deploy.js vhostBlock)에 같은 include 를 넣어 두세요. 게이트웨이 설정·데이터는 건드리지 않습니다.
set -euo pipefail
[ "$(id -u)" = 0 ] || { echo 'root 로 실행하세요' >&2; exit 1; }
. "$(dirname "$0")/lib.sh"
TARGET=""; MAIL_PATH=/mail; SITE_FILE=""
while [ $# -gt 0 ]; do
case "$1" in
--path) MAIL_PATH="$2"; shift 2 ;;
--site) SITE_FILE="$2"; shift 2 ;;
-h|--help) sed -n '2,20p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
*) [ -z "$TARGET" ] || { echo "알 수 없는 인수: $1" >&2; exit 1; }; TARGET="$1"; shift ;;
esac
done
[ -n "$TARGET" ] || { echo "nginx 설정 파일이나 사이트 호스트 이름을 주세요(--help)" >&2; exit 1; }
printf '%s' "$MAIL_PATH" | grep -Eq '^/[A-Za-z0-9._~-]+(/[A-Za-z0-9._~-]+)*$' || { echo "경로 형식이 아닙니다: $MAIL_PATH (예: /mail)" >&2; exit 1; }
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"
# 설정 파일 찾기: 파일 경로면 그대로, 아니면 sites-enabled 에서 server_name 줄에 그 호스트가 있는 파일(하나여야 함).
if [ -f "$TARGET" ]; then CONF="$TARGET"; else
HOST_LC="$(printf '%s' "$TARGET" | tr 'A-Z' 'a-z')"
mapfile -t FOUND < <(grep -lE "^[[:space:]]*server_name[[:space:]]+([^;]*[[:space:]])?${HOST_LC//./\\.}([[:space:];]|$)" /etc/nginx/sites-enabled/*.conf /etc/nginx/sites-enabled/* /etc/nginx/conf.d/*.conf 2>/dev/null | sort -u || true)
[ "${#FOUND[@]}" -gt 0 ] || { echo "server_name 에 $HOST_LC 가 있는 nginx 설정을 찾지 못했습니다(사이트를 먼저 발행하세요)" >&2; exit 1; }
[ "${#FOUND[@]}" -eq 1 ] || { echo "설정 파일이 여럿입니다 — 파일 경로를 직접 주세요: ${FOUND[*]}" >&2; exit 1; }
CONF="${FOUND[0]}"
fi
SNIPPET="/etc/nginx/snippets/$APP_NAME-mail-path.conf"; INCLUDE=" include $SNIPPET;"
mkdir -p /etc/nginx/snippets
sed -e "s|@PORT@|$PORT|g" -e "s|@MAIL_PATH@|$MAIL_PATH|g" "$DEPLOY_DIR/nginx/mail-path.conf.in" > "$SNIPPET"; chmod 644 "$SNIPPET"
echo "▶ $CONF 의 443 블록에 $MAIL_PATH → 127.0.0.1:$PORT (조각 $SNIPPET)"
BAK="$CONF.bak-$(date +%Y%m%d-%H%M%S)"; cp -p "$CONF" "$BAK"
# server 블록 단위로 읽어 443 을 듣고 include 가 없는 블록의 닫는 괄호 앞에 include 를 넣습니다. 블록은 "server {" 로 열리고 첫 칸의 "}" 로 닫힙니다(웹메이커·AriMail 템플릿 모두 이 꼴).
awk -v inc="$INCLUDE" -v snippet="$SNIPPET" '
/^[[:space:]]*server[[:space:]]*\{[[:space:]]*$/ { inblock = 1; buf = ""; ssl = 0; has = 0 }
inblock {
buf = buf $0 "\n"
if ($0 ~ /^[[:space:]]*listen[^;]*[^0-9]443([^0-9]|$)/) ssl = 1
if (index($0, snippet)) has = 1
if ($0 ~ /^\}[[:space:]]*$/) { if (ssl && !has) { sub(/\}[[:space:]]*\n$/, inc "\n}\n", buf); added++ } printf "%s", buf; inblock = 0 }
next
}
{ print }
END { if (inblock) printf "%s", buf; if (!added) print "(이미 적용되어 있거나 443 블록이 없음)" > "/dev/stderr" }
' "$BAK" > "$CONF"
# 닫는 괄호를 못 찾아 블록이 잘리는 일이 없도록 줄 수를 비교합니다(include 줄만 늘어야 함). 사본은 성공해도 남겨 둡니다.
[ "$(wc -l < "$CONF")" -ge "$(wc -l < "$BAK")" ] || { cp -p "$BAK" "$CONF"; echo "✖ 설정 파일 구조를 해석하지 못해 되돌렸습니다(블록 닫는 괄호가 첫 칸에 있어야 함): $CONF" >&2; exit 1; }
if nginx -t; then systemctl reload nginx; echo "✔ https://<사이트 호스트>$MAIL_PATH/ 준비 완료(사본 $BAK). 전체 설정 화면의 도메인 호스트 항목에 \"<사이트 호스트>$MAIL_PATH\" 를 넣으세요."
else cp -p "$BAK" "$CONF"; echo "✖ nginx 설정 검사 실패 — 원래 파일로 되돌렸습니다($BAK 는 남김)" >&2; exit 1; fi