NCONF="$ROOT$BASE/nginx/conf"
mkdir -p "$NCONF/conf.d" "$ROOT$BASE/nginx/html/static"
echo "healthy" > "$ROOT$BASE/nginx/html/static/probe.txt"
APP="$NCONF/conf.d/app.conf"
cat > "$APP" <<EOF
upstream app_backend {
server 127.0.0.1:8080;
server 127.0.0.1:8081 backup;
keepalive 32;
}
EOF== 1. 폴더 준비 ==
WORK/app/nginx/conf
WORK/app/nginx/conf/conf.d
WORK/app/nginx/html
WORK/app/nginx/html/static
WORK/app/nginx/html/static/probe.txt
== 2. upstream 블록과 conf.d/app.conf 작성 ==
작성 완료: conf.d/app.conf$WORK 는 DRY_RUN=1 일 때만 붙는 임시 경로이고, 실제 서버에서는 $BASE 바로 아래에 씁니다. 두 서버 중 하나는 backup 이라 평소엔 첫 서버만 씁니다.
grep -n '^\s*location' "$APP" | mask
echo "== 4. proxy_pass 끝 슬래시 차이 =="
echo " 요청: /api/orders , location /api/ 기준"
echo " proxy_pass http://app_backend/; -> http://app_backend/orders (접두사 /api/ 를 떼어냄)"
echo " proxy_pass http://app_backend; -> http://app_backend/api/orders (접두사를 그대로 붙임)"
grep -n 'proxy_pass' "$APP" | mask== 3. location 매칭 우선순위 ==
1순위 = 정확히 일치, 찾으면 바로 멈춤 (예: = /health)
2순위 ^~ 접두사 일치 중 최長, 찾으면 정규식 검사 생략 (예: ^~ /static/)
3순위 ~ ~* 정규식, 설정 파일에 쓴 순서대로 첫 일치 사용 (예: ~ \.(php|cgi)$)
4순위 접두사 일반 접두사 중 가장 긴 것 (예: /ws/, /)
app.conf 에 정의된 location 블록:
13: location = /health {
17: location ^~ /static/ {
23: location ~ \.(php|cgi)$ {
27: location /ws/ {
35: location / {
== 4. proxy_pass 끝 슬래시 차이 ==
요청: /api/orders , location /api/ 기준
proxy_pass http://app_backend/; -> http://app_backend/orders (접두사 /api/ 를 떼어냄)
proxy_pass http://app_backend; -> http://app_backend/api/orders (접두사를 그대로 붙임)
28: proxy_pass http://app_backend;
36: proxy_pass http://app_backend/;grep -n으로 실제 파일에 쓴 순서를 눈으로 확인합니다. /ws/ 가 / 보다 먼저 매칭되는 이유는 더 긴 접두사이기 때문입니다.
for h in Host X-Real-IP X-Forwarded-For X-Forwarded-Proto; do
grep -q "proxy_set_header $h" "$APP" \
&& echo " 포함: $h" \
|| echo " 누락: $h"
done
grep -n 'timeout\|proxy_buffer' "$APP" | mask
grep -n 'client_max_body_size\|Upgrade\|Connection' "$APP" | mask== 5. 필수 프록시 헤더 ==
포함: Host
포함: X-Real-IP
포함: X-Forwarded-For
포함: X-Forwarded-Proto
== 6. 타임아웃과 버퍼 ==
44: proxy_connect_timeout 5s;
45: proxy_send_timeout 30s;
46: proxy_read_timeout 30s;
47: proxy_buffers 8 16k;
48: proxy_buffer_size 16k;
== 7. 업로드 한도와 웹소켓 ==
11: client_max_body_size 20m;
30: proxy_set_header Upgrade $http_upgrade;
31: proxy_set_header Connection "upgrade";
42: proxy_set_header Connection "";네 헤더가 모두 있는지 for 문으로 확인해 실수로 빠뜨리는 걸 미리 막습니다. Connection "" 은 일반 location 에서 keepalive 를 살리기 위한 설정입니다.
grep -n 'location \^~ /static/\|alias\|expires' "$APP" | mask
awk 'BEGIN{o=0;c=0}
{o+=gsub(/{/,"{"); c+=gsub(/}/,"}")}
END{
if (o==c) printf " 중괄호 짝 검사 통과: 여는 %d 닫는 %d\n", o, c
else { printf " 중괄호 불일치: 여는 %d 닫는 %d\n", o, c; exit 1 }
}' "$APP"
run "$BASE/nginx/sbin/nginx" -t -c "$NCONF/nginx.conf"
run systemctl reload nginx== 8. 정적 파일 분리 ==
17: location ^~ /static/ {
18: alias /app/nginx/html/static/;
19: expires 7d;
== 9. 설정 검증 ==
중괄호 짝 검사 통과: 여는 7 닫는 7
[dry] /app/nginx/sbin/nginx -t -c WORK/app/nginx/conf/nginx.conf
== 10. 설정 반영 ==
[dry] systemctl reload nginx
reload 는 워커 프로세스만 새로 띄워 연결이 끊기지 않습니다
배포 시 점검 페이지로 잠깐 바꾸는 절차는 리눅스 운영 05 참조중괄호 짝 검사는 nginx 바이너리 없이도 실행되는 최소한의 문법 확인입니다. 실제 서버에서는 이 검사 뒤에 nginx -t 까지 통과해야 reload 로 넘어갑니다.