Docs of Jace-Lab

Nginx Sample

Nginx Sample

현재 작성하신 Nginx 설정 파일 구조를 바탕으로 Gzip 압축(전송량 절감)과 Keepalive(커넥션 재사용) 설정을 녹여내어 최적화했습니다.

수많은 서브도메인 블록(server {})이 존재하므로, 공통 설정은 http {} 블록 수준(또는 이 파일의 최상단 글로벌 영역)에 정의하여 중복을 줄이고 유지보수하기 쉽게 구성하는 것이 정석입니다.


1. 최적화된 Nginx 설정 스크립트

현재 사용 중인 설정 파일의 최상단에 글로벌 최적화 설정을 추가하고, 아래 개별 serverupstream 블록들을 수정하시면 됩니다.

# =========================================================================
# [1] 글로벌 성능 및 전송량 최적화 (Gzip & Timeout 공통 세팅)
# =========================================================================

# 텍스트 기반 데이터 전송량 감소를 위한 Gzip 최적화
gzip on;
gzip_comp_level 5;                # CPU와 압축률의 최적 타협점
gzip_min_length 1024;             # 1KB 이상인 경우에만 압축 수행
gzip_proxied any;                 # 프록시된 모든 요청에 대해 압축 적용
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
gzip_vary on;                     # 브라우저 캐싱 호환성 향상

# 클라이언트와의 Keepalive 최적화
keepalive_timeout 65;             # 연결 유지 시간 (초)
keepalive_requests 200;           # 하나의 커넥션으로 최대 처리할 요청 수 (기본 100에서 확장)


# =========================================================================
# [2] Upstream 정의 (백엔드 Keepalive 풀 설정)
# =========================================================================

# 로컬에서 동작하는 포트별 백엔드 서비스를 그룹화하고 Keepalive 커넥션 풀을 할당합니다.
upstream local_3000 { server 127.0.0.1:3000; keepalive 32; }
upstream local_3001 { server 127.0.0.1:3001; keepalive 32; }
upstream local_3002 { server 127.0.0.1:3002; keepalive 32; }
upstream local_3003 { server 127.0.0.1:3003; keepalive 32; }
upstream local_3007 { server 127.0.0.1:3007; keepalive 32; }
upstream local_3008 { server 127.0.0.1:3008; keepalive 32; }
upstream local_3009 { server 127.0.0.1:3009; keepalive 32; }
upstream local_3010 { server 127.0.0.1:3010; keepalive 32; }
upstream local_4000 { server 127.0.0.1:4000; keepalive 32; }
upstream local_4009 { server 127.0.0.1:4009; keepalive 32; }
upstream local_8888 { server 127.0.0.1:8888; keepalive 32; }

# 기존에 있던 RustFS Upstream도 Keepalive 적용
upstream rustfs {
   least_conn;
   server 127.0.0.1:9000;
   keepalive 32;
}

upstream rustfs-console {
   least_conn;
   server 127.0.0.1:9001;
   keepalive 32;
}


# =========================================================================
# [3] Server 블록 최적화 (프록시 공통 헤더 및 프로토콜 적용)
# =========================================================================

# 1. jace.gnbiz.mywire.org
server {
  listen 443 ssl http2 default;
  listen [::]:443 ssl ipv6only=on;
  server_name jace.gnbiz.mywire.org;
  client_max_body_size 20M;

  location / {
    proxy_pass http://local_3000/;

    # 백엔드 Keepalive 및 표준 프록시 헤더 추가
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
  }
  ssl_certificate /etc/letsencrypt/live/gnbiz.mywire.org/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/gnbiz.mywire.org/privkey.pem;
}

# 2. gnbiz.mywire.org
server {
  listen 443 ssl http2;
  listen [::]:443 ssl;
  server_name gnbiz.mywire.org;
  client_max_body_size 20M;

  location / {
    proxy_pass http://local_3001;

    proxy_http_version 1.1;
    proxy_set_header Connection "";
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_redirect off;
  }
  ssl_certificate /etc/letsencrypt/live/gnbiz.mywire.org/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/gnbiz.mywire.org/privkey.pem;
}

# 3. intranet.gnbiz.mywire.org
server {
  listen 443 ssl http2;
  listen [::]:443 ssl;
  server_name intranet.gnbiz.mywire.org;
  client_max_body_size 20M;

  location / {
    proxy_pass http://local_3002;

    proxy_http_version 1.1;
    proxy_set_header Connection "";
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
  }
  ssl_certificate /etc/letsencrypt/live/gnbiz.mywire.org/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/gnbiz.mywire.org/privkey.pem;
}

# 4. class.gnbiz.mywire.org
server {
  listen 443 ssl http2;
  listen [::]:443 ssl;
  server_name class.gnbiz.mywire.org;
  client_max_body_size 20M;

  location / {
    proxy_pass http://local_3003;

    proxy_http_version 1.1;
    proxy_set_header Connection "";
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_redirect off;
  }
  ssl_certificate /etc/letsencrypt/live/gnbiz.mywire.org/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/gnbiz.mywire.org/privkey.pem;
}

# 5. dashboard.gnbiz.mywire.org
server {
  listen 443 ssl http2;
  listen [::]:443 ssl;
  server_name dashboard.gnbiz.mywire.org;
  client_max_body_size 20M;

  location / {
    proxy_pass http://local_3007;

    proxy_http_version 1.1;
    proxy_set_header Connection "";
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
  }
  ssl_certificate /etc/letsencrypt/live/gnbiz.mywire.org/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/gnbiz.mywire.org/privkey.pem;
}

# 6. docs.gnbiz.mywire.org
server {
  listen 443 ssl http2;
  listen [::]:443 ssl;
  server_name docs.gnbiz.mywire.org;
  client_max_body_size 20M;

  location / {
    proxy_pass http://local_3008;

    proxy_http_version 1.1;
    proxy_set_header Connection "";
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
  }
  ssl_certificate /etc/letsencrypt/live/gnbiz.mywire.org/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/gnbiz.mywire.org/privkey.pem;
}

# 7. search.gnbiz.mywire.org
server {
  listen 443 ssl http2;
  listen [::]:443 ssl;
  server_name search.gnbiz.mywire.org;
  client_max_body_size 20M;

  location / {
    proxy_pass http://local_3009;

    proxy_http_version 1.1;
    proxy_set_header Connection "";
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
  }
  ssl_certificate /etc/letsencrypt/live/gnbiz.mywire.org/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/gnbiz.mywire.org/privkey.pem;
}

# 8. aligo.gnbiz.mywire.org
server {
  listen 443 ssl http2;
  listen [::]:443 ssl;
  server_name aligo.gnbiz.mywire.org;
  client_max_body_size 20M;

  location / {
    proxy_pass http://local_3010;

    proxy_http_version 1.1;
    proxy_set_header Connection "";
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
  }
  ssl_certificate /etc/letsencrypt/live/gnbiz.mywire.org/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/gnbiz.mywire.org/privkey.pem;
}

# 9. jupyter.gnbiz.mywire.org
server {
  listen 443 ssl http2; # 가독성을 위해 http2 통일 및 일렬 정렬
  listen [::]:443 ssl;
  server_name jupyter.gnbiz.mywire.org;
  client_max_body_size 20M;

  location / {
    proxy_pass http://local_8888/;

    # Jupyter Notebook 필수 웹소켓 및 Keepalive 지원
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
  }
  ssl_certificate /etc/letsencrypt/live/gnbiz.mywire.org/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/gnbiz.mywire.org/privkey.pem;
}

# 10. DISCORD 프록시 (HTTPS 통신이므로 ssl 전용 설정 켜두기)
server {
    listen 80;
    server_name discord.gnbiz.mywire.org;

    location / {
        proxy_pass https://discord.com;
        proxy_set_header Host discord.com;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        proxy_buffering off;
        proxy_ssl_server_name on;

        # 외부 통신 연결 최적화
        proxy_http_version 1.1;
        proxy_set_header Connection "";
    }
}

# 11. s3.gnbiz.mywire.org (RustFS / MinIO 추정)
server {
   listen       443 ssl http2; # http2 주석 제거 권장
   listen  [::]:443 ssl;
   server_name  s3.gnbiz.mywire.org;

   ssl_certificate /etc/letsencrypt/live/gnbiz.mywire.org/fullchain.pem;
   ssl_certificate_key /etc/letsencrypt/live/gnbiz.mywire.org/privkey.pem;

   ignore_invalid_headers off;
   client_max_body_size 0; # 대용량 파일 핸들링용 유지
   proxy_buffering off;
   proxy_request_buffering off;

   # S3 API 구간
   location /api {
      proxy_set_header Host $http_host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto $scheme;

      proxy_connect_timeout 300;
      proxy_http_version 1.1;

      # 웹소켓과 keepalive가 혼재할 수 있으므로 명시적 설정 제거 혹은 업스트림 대응
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
      chunked_transfer_encoding off;

      proxy_pass http://rustfs; # 명확하게 명시한 upstream 사용
   }

   # Console 구간
   location / {
      proxy_set_header Host $http_host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto $scheme;

      proxy_connect_timeout 300;
      proxy_http_version 1.1;

      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
      chunked_transfer_encoding off;

      proxy_pass http://rustfs-console; # 명확하게 명시한 upstream 사용
   }
}

# 12. jace1.mywire.org 에코시스템
server {
  server_name jace1.mywire.org;
  listen 443 ssl http2;

  location / {
    proxy_pass http://local_4000;
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
  }
  ssl_certificate /etc/letsencrypt/live/jace1.mywire.org/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/jace1.mywire.org/privkey.pem;
}

server {
  server_name docs.jace1.mywire.org;
  listen 443 ssl http2;

  location / {
    proxy_pass http://local_4009;
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
  }
  ssl_certificate /etc/letsencrypt/live/jace1.mywire.org/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/jace1.mywire.org/privkey.pem;
}

# =========================================================================
# [4] HTTP ➡️ HTTPS 리다이렉트 블록들 (기존 구조 보존)
# =========================================================================
server {
  if ($host = gnbiz.mywire.org) { return 301 https://$host$request_uri; }
  listen 80 default;
  listen [::]:80 default;
  server_name gnbiz.mywire.org;
  return 404;
}
server {
  if ($host = dashboard.gnbiz.mywire.org) { return 301 https://$host$request_uri; }
  listen 80;
  listen [::]:80;
  server_name dashboard.gnbiz.mywire.org;
  return 404;
}
server {
  if ($host = jupyter.gnbiz.mywire.org) { return 301 https://$host$request_uri; }
  server_name jupyter.gnbiz.mywire.org;
  listen 80;
  return 404;
}

2. 주요 변경 및 최적화 포인트 설명

① 글로벌 Gzip 압축 활성화 (데이터량 절감 핵심)

  • 파일 최상단에 gzip on; 설정을 추가했습니다. JSON 데이터(application/json), 텍스트, 자바스크립트 등 프록시를 통해 나가는 API 결과물을 온더플라이로 압축하여 대역폭 소모를 대폭 줄입니다.
  • 압축률은 CPU 부하가 크지 않고 효율이 좋은 gzip_comp_level 5;로 세팅했습니다.
  • 이미지 파일이나 이미 인코딩된 대용량 이진 데이터(S3 업/다운로드 등)는 Gzip이 알아서 압축 대상에서 제외하므로 성능 낭비가 없습니다.

② Upstream을 활용한 Backend Keepalive 구현 (CPU 및 연결 지연 개선)

  • Nginx에서 백엔드 앱(예: Node.js, RustFS 등)으로 proxy_pass 할 때 원래는 매번 새로운 TCP 소켓 커넥션을 맺고 끊었습니다.
  • 이를 개선하기 위해 각 포트마다 upstream 풀을 생성하고 keepalive 32;를 지정했습니다. Nginx가 로컬 백엔드 서버와 최대 32개의 상시 통신 통로를 유지하므로, 서버의 CPU 오버헤드와 API 응답 지연 시간이 극적으로 감소합니다.
  • 백엔드 Keepalive를 작동시키기 위해 각 location / 마다 아래의 필수 프로토콜 명시를 적용했습니다.
proxy_http_version 1.1;
proxy_set_header Connection "";

③ 누락된 Proxy 헤더 표준화 및 정리

  • 기존 설정에서 일부 서버 블록(예: intranet, dashboard, docs 등)에는 Host, X-Real-IP, X-Forwarded-For 같은 중요 헤더들이 누락되어 있어 백엔드 앱이 클라이언트의 실제 IP나 도메인명을 파악하기 어려운 상태였습니다. 최적화 과정에서 모든 블록에 표준 프록시 헤더를 누락 없이 채워 넣었습니다.

④ HTTP/2 적극 활성화

  • 주석 처리되어 있거나 일부 빠져있던 http2 선언을 SSL 리슨 포트(listen 443 ssl http2;)에 명시했습니다. 클라이언트와 Nginx 구간의 멀티플렉싱 통신을 극대화하여 프론트엔드 자원 로딩 속도를 가속화합니다.

3. Brotli 사용 가능 여부 팁 (선택 사항)

만약 데이터량을 Gzip보다 한 단계 더 획기적으로(약 20% 이상 추가) 줄이고 싶다면 Brotli가 좋은 대안입니다.

다만, Brotli는 Nginx에 기본 탑재되어 있지 않아 OS 패키지(예: nginx-mod-http-brotli)를 별도로 설치하거나 Nginx를 소스 컴파일해야 활성화할 수 있습니다. 만약 우분투/데비안 환경에서 Brotli 모듈이 설치되어 있다면 최상단 글로벌 영역에 아래 설정을 Gzip과 함께 추가해주시면 완벽히 호환됩니다.

# Brotli 모듈이 설치되어 있을 경우 글로벌 영역에 추가 가능
brotli on;
brotli_comp_level 4; # 동적 API 압축용 적정 레벨
brotli_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

설정을 모두 수정한 후에는 반드시 터미널에서 구문 체크를 하신 후 Nginx를 재시작해 주세요.

sudo nginx -t
sudo systemctl reload nginx

On this page