#!/usr/bin/env bash # 사이트의 /mail 경로를 AriMail 웹 메일로 잇습니다(1.0.8, 요구사항 1) — root 로 실행: # sudo bash /repo/deploy/site-mail-path.sh [--path /mail] [--site ] # 예) 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/-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