μ•ˆλ…•ν•˜μ„Έμš” Mambo μž…λ‹ˆλ‹€.

μ˜€λŠ˜μ€ μ›Ή μ„œλΉ„μŠ€ μΈν”„λΌμ—μ„œ λ¦¬λ²„μŠ€ ν”„λ‘μ‹œ ꡬ성을 μœ„ν•΄ μ‚¬μš©λ˜λŠ” Nginx와 ν•¨κ»˜ λ¦¬λ²„μŠ€ ν”„λ‘μ‹œμ— λŒ€ν•΄ μ•Œμ•„λ³΄κ³ μž ν•©λ‹ˆλ‹€.

Nginx

NginxλŠ” 정적 νŒŒμΌμ„ 배포할 수 μžˆλŠ” HTTP μ›Ή μ„œλ²„μž…λ‹ˆλ‹€. 졜근 μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ„œλ²„λ₯Ό λ°°ν¬ν•˜λŠ” 경우 λ‹¨λ…μœΌλ‘œ κ΅¬μ„±ν•˜μ§€ μ•Šκ³  Nginxλ₯Ό ν•¨κ»˜ μ‚¬μš©ν•©λ‹ˆλ‹€. μ•„λ§ˆμ‘΄ μ›Ή μ„œλΉ„μŠ€μ˜ Elastic Beanstalk ν™˜κ²½μ—μ„œλŠ” λ¦¬λ²„μŠ€ ν”„λ‘μ‹œ ꡬ성을 μœ„ν•˜μ—¬ Nginxλ₯Ό 기본적으둜 μ œκ³΅ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. μ΄λ ‡κ²Œ μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ„œλ²„ μ•žμ—μ„œ λ¨Όμ € νŠΈλž˜ν”½μ„ μ²˜λ¦¬ν•˜λ„λ‘ κ΅¬μ„±ν•˜λŠ” λ¦¬λ²„μŠ€ ν”„λ‘μ‹œλ₯Ό μ‚¬μš©ν•˜λŠ” μ΄μœ λŠ” λ¬΄μ—‡μΌκΉŒμš”?

λ¦¬λ²„μŠ€ ν”„λ‘μ‹œ

λ¦¬λ²„μŠ€ ν”„λ‘μ‹œλŠ” μ‚¬μš©μžμ˜ μš”μ²­μ— λŒ€ν•œ μ‚¬ν›„μ²˜λ¦¬λ₯Ό μˆ˜ν–‰ν•˜μ—¬ μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ„œλ²„λ‘œ νŠΈλž˜ν”½μ„ μ „λ‹¬λ˜λ„λ‘ ν•˜λŠ” 것을 λ§ν•©λ‹ˆλ‹€. λ¦¬λ²„μŠ€ ν”„λ‘μ‹œ κ΅¬μ„±μ˜ μž₯점은 μ‚¬μš©μžμ—κ²Œ μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ„œλ²„κ°€ μ‹€ν–‰λ˜λŠ” 아이피 λ˜λŠ” 포트λ₯Ό κ³΅κ°œν•˜μ§€ μ•Šκ±°λ‚˜ 잘λͺ»λœ μš”μ²­μ„ μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ„œλ²„κΉŒμ§€ μ „λ‹¬λ˜μ§€ μ•Šλ„λ‘ν•˜μ—¬ λ³΄ν˜Έν•  수 μžˆμŠ΅λ‹ˆλ‹€.

λ‘œλ“œ λ°ΈλŸ°μ‹±

λ¦¬λ²„μŠ€ ν”„λ‘μ‹œλ₯Ό κ΅¬μ„±ν•¨μœΌλ‘œμ¨ μ‚¬μš©μžλŠ” νŠΉμ • μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ„œλ²„λ‘œ 직접 μš”μ²­ν•˜λŠ” ꡬ쑰가 μ•„λ‹ˆλ―€λ‘œ λ™μ‹œμ— λ°œμƒν•˜λŠ” 수 λ§Žμ€ μ›Ή μš”μ²­μ„ 1개 μ΄μƒμœΌλ‘œ μ‹€ν–‰λœ λ‹€μˆ˜μ˜ μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ„œλ²„λ‘œ λ‘œλ“œλ°ΈλŸ°μ‹±(νŠΈλž˜ν”½μ„ λΆ„μ‚°) ν•¨μœΌλ‘œμ¨ μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ„œλ²„μ— λŒ€ν•œ λΆ€ν•˜λ₯Ό 쀄일 수 μžˆμŠ΅λ‹ˆλ‹€.

λ¬Όλ‘ , 에픽 κ²Œμž„μ¦ˆμ˜ 340만 λ™μ ‘μž 이후 μ„œλΉ„μŠ€ λ‹€μš΄ κ΄€λ ¨ 사후 뢄석 λ‚΄μš©μ²˜λŸΌ λ¦¬λ²„μŠ€ ν”„λ‘μ‹œλ₯Ό κ΅¬μ„±ν•œλ‹€κ³ ν•΄μ„œ λͺ¨λ“  νŠΈλž˜ν”½μ„ 감당할 수 μžˆλŠ” 것은 μ•„λ‹™λ‹ˆλ‹€.

SSL μ˜€ν”„λ‘œλ“œ

Nginx둜 λ¦¬λ²„μŠ€ ν”„λ‘μ‹œλ₯Ό κ΅¬μ„±ν•¨μœΌλ‘œμ¨ μˆ˜ν–‰ν•  수 μžˆλŠ” μ‚¬ν›„μ²˜λ¦¬ 쀑 ν•˜λ‚˜λŠ” SSL μ˜€ν”„λ‘œλ“œμž…λ‹ˆλ‹€. λ¦¬λ²„μŠ€ ν”„λ‘μ‹œλ₯Ό μˆ˜ν–‰ν•˜λŠ” μ›Ή μ„œλ²„μ—μ„œ SSL μΈμ¦μ„œλ₯Ό κ΄€λ¦¬ν•˜κ³  SSL Termination을 μˆ˜ν–‰ν•¨μœΌλ‘œμ¨ μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ„œλ²„κ°€ νŠΈλž˜ν”½ μ•”ν˜Έν™”λ₯Ό μœ„ν•΄ μˆ˜ν–‰ν•˜λ˜ λΆ€ν•˜μ™€ 관리 포인트λ₯Ό 쀄일 수 μžˆμŠ΅λ‹ˆλ‹€.

정적 파일 μΊμ‹œ

μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ„œλ²„κ°€ λ°°ν¬ν•˜λŠ” 정적 νŒŒμΌμ— λŒ€ν•΄μ„œ Nginx 자체적으둜 μΊμ‹œν•˜μ—¬ 정적 νŒŒμΌμ„ 응닡할 수 μžˆμŠ΅λ‹ˆλ‹€. μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ„œλ²„λ‘œ μ „λ‹¬λ˜λŠ” νŠΈλž˜ν”½μ΄ λ§Žμ•„μ§ˆ 경우 정적 νŒŒμΌμ„ μ‘λ‹΅ν•˜κΈ° μœ„ν•œ μš”μ²­μ„ μ²˜λ¦¬ν•˜λŠ” 것도 뢀담이 될 수 μžˆμŠ΅λ‹ˆλ‹€. λ§Žμ€ νŠΈλž˜ν”½μ„ 적은 λ¦¬μ†ŒμŠ€λ₯Ό μ‚¬μš©ν•˜μ—¬ μ²˜λ¦¬ν•  수 μžˆλŠ” μ›Ή μ„œλ²„μ—μ„œ 정적 νŒŒμΌμ— λŒ€ν•œ μš”μ²­μ„ μ²˜λ¦¬ν•˜μ—¬ μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ„œλ²„μ˜ 뢀담을 쀄일 수 있게 λ©λ‹ˆλ‹€.

창천ν–₯λ‘œλ‹˜μ˜ Nginx Cache 문제 ν•΄κ²° μ‹œλ¦¬μ¦ˆμ²˜λŸΌ μΊμ‹œλ₯Ό 잘 ꡬ성해야할 수 μžˆμŠ΅λ‹ˆλ‹€.

Nginx 도컀 μ»¨ν…Œμ΄λ„ˆ ν•™μŠ΅

λ„μ»€λŠ” μ–΄λ– ν•œ κΈ°μˆ μ„ ν•™μŠ΅ν•˜κΈ° μœ„ν•œ ν™˜κ²½μ„ κ΅¬μ„±ν•˜κΈ°μ— μ ν•©ν•œ λ„κ΅¬μž…λ‹ˆλ‹€. 도컀λ₯Ό μ‚¬μš©ν•˜μ—¬ μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ„œλ²„μ™€ ν•¨κ»˜ λ¦¬λ²„μŠ€ ν”„λ‘μ‹œλ₯Ό κ΅¬μ„±ν•˜λŠ” Nginxλ₯Ό 섀정해보며 ν•™μŠ΅ν•΄λ³΄λ„λ‘ ν•˜κ² μŠ΅λ‹ˆλ‹€.

μ €μ˜ ν•™μŠ΅ ν™˜κ²½μ€ λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€. ν™˜κ²½μ΄ λ‹€λ₯Έ 경우 λ‹€λ₯Έ 뢀뢄이 μ‘΄μž¬ν•  수 μžˆμœΌλ‹ˆ μ£Όμ˜ν•΄μ•Όν•©λ‹ˆλ‹€.

  • Docker version 20.10.8, build 3967b7d
  • Nginx 1.21.3
  • Amazon Corretto 11

그리고 ν•™μŠ΅μ— ν™œμš©λœ νŒŒμΌλ“€μ€ κΉƒν—ˆλΈŒμ— κ³΅μœ λ˜μ–΄μžˆμœΌλ‹ˆ μ°Έκ³ ν•˜μ…”λ„ μ’‹μŠ΅λ‹ˆλ‹€.

κΈ°λ³Έ μ»¨ν…Œμ΄λ„ˆ ν™˜κ²½

도컀 컴포즈λ₯Ό ν™œμš©ν•˜μ—¬ μŠ€ν”„λ§ λΆ€νŠΈ μ• ν”Œλ¦¬μΌ€μ΄μ…˜κ³Ό Nginxκ°€ κ΅¬λ™λ˜λ„λ‘ μ»¨ν…Œμ΄λ„ˆ ν™˜κ²½μ„ κ΅¬μ„±ν–ˆμŠ΅λ‹ˆλ‹€.

version: '3.8'
services: 
  nginx:
    image: nginx:1.21.3-alpine
    ports: 
      - 80:80
      - 443:443
  app:
    image: amazoncorretto:11-alpine
    ports:
      - 8080:8080
    command: 'java -jar /etc/app.jar'
    volumes:
      - ./demo-0.0.1-SNAPSHOT.jar:/etc/app.jar

도컀 컴포즈 λͺ…λ Ήμ–΄λ‘œ μ»¨ν…Œμ΄λ„ˆ ν™˜κ²½μ„ μ‹€ν–‰ν•©λ‹ˆλ‹€.

docker compose up -d
[+] Running 3/3
 - Network nginx_default    Created
 - Container nginx_nginx_1  Started
 - Container nginx_app_1    Started

제 컴퓨터 호슀트 νŒŒμΌμ— 127.0.0.1에 λŒ€ν•˜μ—¬ mambo.krκ°€ μ§€μ •λ˜μ–΄μžˆμœΌλ―€λ‘œ λ‹€μŒκ³Ό 같이 Nginxκ°€ 80ν¬νŠΈμ— λŒ€ν•œ μš”μ²­μ— λŒ€ν•΄ κΈ°λ³Έ νŽ˜μ΄μ§€λ₯Ό μ‘λ‹΅ν•˜μ˜€μŠ΅λ‹ˆλ‹€.

κΈ°λ³Έ Nginx μ„€μ •

도컀 컴포즈 λͺ…λ Ήμ–΄λ‘œ μ»¨ν…Œμ΄λ„ˆ μ§„μž… ν›„ 기본으둜 μ μš©λ˜μ–΄μžˆλŠ” Nginx 섀정을 확인해보도둝 ν•˜κ² μŠ΅λ‹ˆλ‹€.

docker compose exec nginx sh
/ # cat /etc/nginx/nginx.conf

80포트λ₯Ό μˆ˜μ‹ ν•˜λŠ” μ›Ή μ„œλ²„ 섀정은 /etc/nginx/conf.d/default.conf에 μœ„μΉ˜ν•˜κ³  μžˆμ—ˆμŠ΅λ‹ˆλ‹€. λ‹€μŒμ€ default.conf에 μ •μ˜λœ λ‚΄μš© 쀑 μΌλΆ€μž…λ‹ˆλ‹€.

/etc/nginx/conf.d # cat default.conf
server {
    listen       80;
    listen  [::]:80;
    server_name  localhost;

    #access_log  /var/log/nginx/host.access.log  main;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }
    # ...
}

server 블둝을 톡해 80포트λ₯Ό μˆ˜μ‹ (listen)ν•˜μ˜€κ³  루트 경둜(/)에 λŒ€ν•œ μš”μ²­μ„ /usr/share/nginx/html에 μœ„μΉ˜ν•œ index.htmlμ΄λΌλŠ” 정적 νŒŒμΌμ„ μ‘λ‹΅ν•˜λ„λ‘ μ •μ˜λ˜μ–΄μžˆμŠ΅λ‹ˆλ‹€.

μ‚¬μš©μž μ •μ˜ Nginx μ„€μ •

기본으둜 μ μš©λ˜μ–΄μžˆλŠ” nginx.confλ₯Ό λ³Όλ₯¨μœΌλ‘œ μ§€μ •ν•˜μ—¬ μ‚¬μš©μž μ •μ˜ν•  수 μžˆλ„λ‘ ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€. 도컀 컴포즈 λ¬Έμ„œμ— Nginx μ„œλΉ„μŠ€μ— λ³Όλ₯¨μ„ μ§€μ •ν•˜μ—¬ 둜컬 파일둜 μ €μž₯λ˜μ–΄μžˆλŠ” nginx.confλ₯Ό μ§€μ •ν•˜κ² μŠ΅λ‹ˆλ‹€.

version: '3.8'
services: 
  nginx:
    image: nginx:1.21.3-alpine
    ports: 
      - 80:80
      - 443:443
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
  #app:
  #  ...

호슀트의 443포트λ₯Ό Nginx μ„œλΉ„μŠ€μ— λ°”μΈλ”©ν•˜μ˜€μœΌλ―€λ‘œ 443포트λ₯Ό μˆ˜μ‹ ν•˜λ„λ‘ μ •μ˜ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

http {
    server {
        listen 443 ssl;
        server_name localhost 127.0.0.1 mambo.kr;
        ssl_certificate /etc/nginx/server.crt;
        ssl_certificate_key /etc/nginx/server.key;
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers HIGH:!aNULL:!MD5;

        location / {
            proxy_pass http://app:8080;
        }
    }
    include /etc/nginx/conf.d/*.conf;
}

도컀 컴포즈둜 μ»¨ν…Œμ΄λ„ˆ ν™˜κ²½μ„ λ‹€μ‹œ μ‹€ν–‰ν•˜λ©΄ μ •μƒμ μœΌλ‘œβ€¦

nginx: [emerg] no "events" section in configuration

였λ₯˜κ°€ λ°œμƒν–ˆλ„€μš”. nginx.conf에 events 블둝은 ν•„μˆ˜λ‘œ μ‘΄μž¬ν•΄μ•Όν•˜λŠ” λ“― ν•©λ‹ˆλ‹€.

ν”„λ‘œμ„ΈμŠ€ 및 처리 μ˜΅μ…˜

NginxλŠ” λ§ˆμŠ€ν„° ν”„λ‘œμ„ΈμŠ€μ™€ μ›Œμ»€ ν”„λ‘œμ„ΈμŠ€λ‘œ κ΅¬μ„±λ˜μ–΄ μ‹€μ œλ‘œ μš”μ²­μ„ μ²˜λ¦¬ν•˜λŠ” 것은 μ›Œμ»€ ν”„λ‘œμ„ΈμŠ€κ°€ λ‹΄λ‹Ήν•©λ‹ˆλ‹€. μ‚¬μš©κ°€λŠ₯ν•œ CPU μ½”μ–΄ 수 만큼 μ›Œμ»€ ν”„λ‘œμ„ΈμŠ€λ₯Ό ν• λ‹Ήν•˜λŠ”κ²Œ μ’‹μœΌλ©° μ›Œμ»€ ν”„λ‘œμ„ΈμŠ€λ³„λ‘œ μ‚¬μš©ν•  수 μžˆλŠ” μ΅œλŒ€ μ—΄λ¦° 파일 개수 μ œν•œμ„ μ„€μ •ν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.

worker_processes auto;
worker_cpu_affinity auto;
worker_rlimit_nofile 65536;

events {
    worker_connections 1024;
    use epoll;
    multi_accept on;
}

Optimizations - Event Models

μš΄μ˜μ²΄μ œλ³„ 효율적인 μ—°κ²° 처리 방식이 있으며 λ¦¬λˆ…μŠ€ 컀널 2.6+μ—μ„œλŠ” epoll을 μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

Nginx μ„œλΉ„μŠ€ μ»¨ν…Œμ΄λ„ˆκ°€ μ •μƒμ μœΌλ‘œ μ‹€ν–‰λ˜μ§€ μ•Šμ€ μƒνƒœμ΄λ―€λ‘œ 도컀 컴포즈둜 μ»¨ν…Œμ΄λ„ˆ ν™˜κ²½μ„ μ‹€ν–‰ν•΄μ•Όν•©λ‹ˆλ‹€.

docker compose up -d
[+] Running 2/2
 - Container nginx_nginx_1  Started
 - Container nginx_app_1    Running

잘 μ‹€ν–‰λœκ²ƒμœΌλ‘œ λ³΄μ΄λ‹ˆ https://mambo.kr으둜 접속해보도둝 ν•˜κ² μŠ΅λ‹ˆλ‹€.

443 포트둜 μš”μ²­λœ νŠΈλž˜ν”½μ΄ Nginxλ₯Ό κ²½μœ ν•˜μ—¬ 8080포트둜 μ‹€ν–‰λœ μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ„œλ²„λ‘œ μ „λ‹¬λ˜κ³  응닡을 λ°›μ•˜μŠ΅λ‹ˆλ‹€. λ°”λ‘œ 이것을 λ¦¬λ²„μŠ€ ν”„λ‘μ‹œλΌκ³  ν•©λ‹ˆλ‹€.

λ¦¬λ²„μŠ€ ν”„λ‘μ‹œ

λ¦¬λ²„μŠ€ ν”„λ‘μ‹œλ₯Ό κ΅¬μ„±ν•˜λ©΄ μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ„œλ²„λŠ” μ–΄λ””μ„œ μš”μ²­ν–ˆλŠ”μ§€μ— λŒ€ν•œ 정보λ₯Ό μ•Œ 수 μ—†μŠ΅λ‹ˆλ‹€. κ·Έλž˜μ„œ Nginx와 같은 λ¦¬λ²„μ‹œ ν”„λ‘μ‹œλ₯Ό κ΅¬μ„±ν•˜λŠ” μ›Ή μ„œλ²„μ—μ„œλŠ” ν”„λ‘μ‹œ κ΄€λ ¨ 헀더λ₯Ό ν•¨κ»˜ μ „λ‹¬ν•˜μ—¬ μ–΄λ””μ„œ μš”μ²­λ˜μ—ˆλŠ”μ§€λ₯Ό 전달할 수 μžˆλ„λ‘ μ„€μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

http {
    server {
        listen 443 ssl;
        server_name localhost 127.0.0.1 mambo.kr;
        ssl_certificate /etc/nginx/server.crt;
        ssl_certificate_key /etc/nginx/server.key;
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers HIGH:!aNULL:!MD5;

        location / {
            proxy_pass http://app:8080;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }
    include /etc/nginx/conf.d/*.conf;
}

μ›Ήμ†ŒμΌ“ ν”„λ‘μ‹œ

HTTP 1.1 ν”„λ‘œν† μ½œμ€ Hop-By-Hop이라고 ν•˜λŠ” Upgrade 헀더λ₯Ό μ‚¬μš©ν•˜μ—¬ 컀λ„₯μ…˜μ„ λ³€κ²½ν•˜λŠ” λ§€μ»€λ‹ˆμ¦˜μ„ μ œκ³΅ν•©λ‹ˆλ‹€. Upgrading to a WebSocket connectionκ³Ό WebSocket proxying λ¬Έμ„œλ₯Ό μ°Έκ³ ν•˜μ—¬ λ‹€μŒκ³Ό 같이 μ›Ήμ†ŒμΌ“ ν”„λ‘μ‹œμ— λŒ€ν•œ 섀정을 ꡬ성할 수 μžˆμŠ΅λ‹ˆλ‹€.

server {
    location /ws/ {
        proxy_pass http://backend;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_read_timeout 65s;
    }
}

ν”„λ‘μ‹œ μ„œλ²„λŠ” 기본적으둜 60초 이내에 μ „λ‹¬λ˜λŠ” 데이터가 μ—†λŠ” 경우 연결을 ν•΄μ§€ν•©λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄, 1λΆ„λ§ˆλ‹€ μ›Ήμ†ŒμΌ“μœΌλ‘œ μ „λ‹¬λ˜λŠ” 데이터가 μžˆλŠ” 경우λ₯Ό μœ„ν•΄ proxy_read_timeout을 μ‘°μ •ν•΄μ•Όν•©λ‹ˆλ‹€.

이벀트 슀트림 ν”„λ‘μ‹œ

λ¦¬λ²„μŠ€ ν”„λ‘μ‹œ κ΅¬μ„±μ—μ„œ SSE(Server Sent Event)와 같은 이벀트 μŠ€νŠΈλ¦Όμ„ μ‚¬μš©ν•˜λŠ” 경우 버퍼링 μ˜΅μ…˜μ„ λΉ„ν™œμ„±ν™” ν•΄μ•Όν•©λ‹ˆλ‹€.

server {
    location / {
        proxy_buffering off;
        proxy_cache off;
    }
}

HTTPS λ¦¬λ‹€μ΄λ ‰νŠΈ

일반 HTTPλ₯Ό μ‚¬μš©ν•˜μ—¬ 80포트둜 μš”μ²­ν•œ 것을 HTTPSλ₯Ό μ‚¬μš©ν•˜λ„λ‘ μœ λ„ν•˜κΈ° μœ„ν•΄μ„œ HTTPS λ¦¬λ‹€μ΄λ ‰νŠΈ 응닡을 μ μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

server {
    listen 80;
    server_name _;
    return 301 https://$host$request_uri;
}

정적 파일 배포

μΆ”κ°€μ μœΌλ‘œ 정적 파일이 ν¬ν•¨λœ 폴더λ₯Ό λ³Όλ₯¨μœΌλ‘œ μ§€μ •ν•˜μ—¬ Nginxμ—μ„œ 정적 νŒŒμΌμ„ 응닡할 수 μžˆλ„λ‘ μ„€μ •ν•˜κ² μŠ΅λ‹ˆλ‹€.

version: '3.8'
services: 
  nginx:
    image: nginx:1.21.3-alpine
    ports: 
      - 80:80
      - 443:443
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
      - ./server.crt:/etc/nginx/server.crt
      - ./server.key:/etc/nginx/server.key
      - ./static:/etc/nginx/static
worker_processes auto;
worker_cpu_affinity auto;
worker_rlimit_nofile 65536;

events {
    worker_connections 1024;
    use epoll;
    multi_accept on;
}

http {
    server {
        listen 80;
        server_name _;
        return 301 https://$host$request_uri;
    }

    server {
        listen 443 ssl;
        server_name localhost 127.0.0.1 mambo.kr;
        ssl_certificate /etc/nginx/server.crt;
        ssl_certificate_key /etc/nginx/server.key;
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers HIGH:!aNULL:!MD5;

        location / {
            proxy_pass http://app:8080;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }

        location /dist/ {
            alias /etc/nginx/static/;
            limit_except GET {
                deny all;
            }
        }
    }
    include /etc/nginx/conf.d/*.conf;
}

정적 νŒŒμΌκΉŒμ§€ 응닡할 수 μžˆλ„λ‘ μ„€μ •ν•˜μ˜€μŠ΅λ‹ˆλ‹€.

Nginx μ„€μ • μ΅œμ ν™”

μ‚¬μš©μž μ •μ˜ν•œ Nginx μ„€μ •λ§ŒμœΌλ‘œλ„ λ¦¬λ²„μŠ€ ν”„λ‘μ‹œ 및 정적 νŒŒμΌμ„ λ°°ν¬ν•˜λŠ”λ°μ—λŠ” λ¬Έμ œκ°€ μ—†μŠ΅λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ Nginxμ—μ„œλŠ” 더 효율적으둜 λ™μž‘ν•  수 μžˆλ„λ‘ λ‹€μ–‘ν•œ μ˜΅μ…˜μ„ μ œκ³΅ν•©λ‹ˆλ‹€. μ—¬λŸ¬κ°€μ§€ μ˜΅μ…˜λ“€μ„ μ μš©ν•΄λ³΄λ©΄μ„œ μ΅œμ ν™”ν•΄λ³΄λ„λ‘ ν•©μ‹œλ‹€.

Nginx μ„€μ • μ΅œμ ν™”μ— λŒ€ν•΄μ„œλŠ” λ‹€μŒμ˜ 글을 μ°Έκ³ ν•˜λ©΄ μ’‹μŠ΅λ‹ˆλ‹€.

TCP μ˜΅μ…˜

Nginx Optimization: understanding sendfile, tcp_nodelay and tcp_nopushμ—μ„œλŠ” TCP μ˜΅μ…˜μ„ μ§€μ •ν•˜λŠ” μ΄μœ μ— λŒ€ν•΄μ„œ μ„€λͺ…ν•©λ‹ˆλ‹€. λ„€νŠΈμ›Œν¬ ν™˜κ²½μ΄ λΉ λ₯Έ 경우 TCP μŠ€νƒμ—μ„œ Nagle μ•Œκ³ λ¦¬μ¦˜μ„ μ‚¬μš©ν•˜λŠ” 것이 λΉ„νš¨μœ¨μ μΌ 수 μžˆλ‹€κ³  ν•©λ‹ˆλ‹€.

http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
}

μ••μΆ• μ˜΅μ…˜

μ›Ή μš”μ²­μ— λŒ€ν•œ 응닡 데이터λ₯Ό μ••μΆ•ν•˜λŠ” 것은 λ„€νŠΈμ›Œν¬ λΉ„μš©μ„ 쀄이고 λΉ λ₯΄κ²Œ 응닡할 수 μžˆλŠ” 쒋은 λ°©λ²•μž…λ‹ˆλ‹€. μ„œλ²„ μ„±λŠ₯에 따라 μ••μΆ• λ ˆλ²¨μ„ μ΅œλŒ€ν•œμœΌλ‘œ μ§€μ •ν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€. λ˜ν•œ, μž‘μ€ 크기에 데이터에 λŒ€ν•˜μ—¬ 압좕을 μ‹œλ„ν•˜λŠ” 것도 λΉ„νš¨μœ¨μ μž…λ‹ˆλ‹€.

http {
    gzip on;
    gzip_min_length 1k;
    gzip_comp_level 9;
    gzip_vary on;
    gzip_disable msie6;
    gzip_proxied expired no-cache no-store private auth;
    gzip_types
        # text/html is always compressed by HttpGzipModule
        text/css
        text/javascript
        text/xml
        text/plain
        application/javascript
        application/json
        application/xml
        font/truetype
        font/opentype
        application/vnd.ms-fontobject
        image/svg+xml;
}

일반적으둜 ν…μŠ€νŠΈ μœ ν˜•μ˜ 데이터λ₯Ό μ••μΆ•ν•˜λ„λ‘ μ§€μ •ν•©λ‹ˆλ‹€.

둜그 μ˜΅μ…˜

λͺ¨λ“  μš”μ²­μ— λŒ€ν•΄ μ•‘μ„ΈμŠ€ 둜그λ₯Ό μ €μž₯ν•˜λŠ” 것은 λΉ„νš¨μœ¨μ μœΌλ‘œ I/Oλ₯Ό λ°œμƒμ‹œν‚¬ 수 μžˆμŠ΅λ‹ˆλ‹€.

error_log /var/log/nginx/error.log crit;
http {
    access_log off;
    server {
        listen 80;
        access_log /var/log/nginx/access.log;
    }
}

λ³΄μ•ˆ μ˜΅μ…˜

λ§Žμ€ μ‚¬λžŒλ“€μ΄ server_tokens μ˜΅μ…˜μ„ λΉ„ν™œμ„±ν™”ν•˜μ—¬ 응닡 헀더에 Nginx 버전을 λͺ…μ‹œν•˜μ§€ μ•Šλ„λ‘ ꢌμž₯ν•©λ‹ˆλ‹€. κ³΅κ²©μžλŠ” Nginx의 νŠΉμ • 버전을 μ•Œ 수 μ—†μœΌλ―€λ‘œ 더 λ§Žμ€ 취약점에 λŒ€ν•œ 곡격을 μ‹œλ„ν•΄μ•Όν•©λ‹ˆλ‹€.

http {
    server_tokens off;
}

ν΄λΌμ΄μ–ΈνŠΈ μ˜΅μ…˜

μ—°κ²° μœ μ§€ ν΄λΌμ΄μ–ΈνŠΈ μˆ˜μ™€ μ΅œλŒ€ μœ μ§€ μ‹œκ°„ 그리고 ν΄λΌμ΄μ–ΈνŠΈ μš”μ²­ 크기λ₯Ό μ‘°μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

http {
    keepalive_timeout 65;
    keepalive_requests 10000;
    client_max_body_size 100m;
}

λ¦¬λˆ…μŠ€ 컀널 νŒŒλΌλ―Έν„°

Nginx μ˜΅μ…˜μ„ μ§€μ •ν•˜λ”λΌλ„ μ‹€μ œλ‘œ ν—ˆμš©ν•  수 μžˆλŠ”μ§€ λ¦¬λˆ…μŠ€ 컀널 νŒŒλΌλ―Έν„°λ₯Ό κ²€ν† ν•΄μ•Όν•  수 μžˆμŠ΅λ‹ˆλ‹€.

Nginx μ„€μ • 마무리

μ•Œμ•„λ³Έ λ‚΄μš©μ„ μ‘°ν•©ν•˜λ©΄ λ‹€μŒκ³Ό 같이 Nginx 섀정을 μ •μ˜ν•  수 있게 λ©λ‹ˆλ‹€.

user nginx;

# ν”„λ‘œμ„ΈμŠ€ μ˜΅μ…˜
worker_processes auto;
worker_cpu_affinity auto;
worker_rlimit_nofile 65536;

events {
    worker_connections 1024;
    use epoll;
    multi_accept on;
}

pid /var/run/nginx.pid;
error_log /var/log/nginx/error.log crit;
#thread_pool backend threads=32 max_queue=65536;

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    access_log off;

    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;

    upstream backend {
        server app:8080;
        keepalive 128;
    }

    # HTTPS λ¦¬λ‹€μ΄λ ‰νŠΈ
    server {
        listen 80;
        server_name _;
        return 301 https://$host$request_uri;
    }

    # HTTPS 및 HTTP2 지원
    server {
        listen 443 ssl http2;
        server_name localhost 127.0.0.1 mambo.kr;
        ssl_certificate /etc/nginx/server.crt;
        ssl_certificate_key /etc/nginx/server.key;
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers HIGH:!aNULL:!MD5;

        # λ¦¬λ²„μŠ€ ν”„λ‘μ‹œ
        location / {
            proxy_pass http://backend;
            proxy_redirect off;
            proxy_buffering off;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

            #aio threads=backend;
            access_log /var/log/nginx/access.log;
        }

        # λ¦¬λ²„μŠ€ μ›Ήμ†ŒμΌ“ ν”„λ‘μ‹œ
        location /ws/ {
            proxy_pass http://backend;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            # hop-by-hop
            proxy_http_version 1.1;
            proxy_set_header Connection "upgrade";
            proxy_set_header Upgrade $http_upgrade;
            proxy_read_timeout 65s;
        }

        location /dist/ {
            alias /etc/nginx/static/;
            limit_except GET {
                deny all;
            }
        }
    }

    # Optimization
    server_tokens off;

    keepalive_timeout 65s;
    client_max_body_size 100m;

    # TCP μ˜΅μ…˜
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;

    # Gzip μ••μΆ• μ˜΅μ…˜
    gzip on;
    gzip_min_length 10k;
    gzip_comp_level 9;
    gzip_vary on;
    gzip_disable msie6;
    gzip_proxied expired no-cache no-store private auth;
    gzip_types
        # text/html is always compressed
        text/css
        text/javascript
        text/xml
        text/plain
        application/javascript
        application/json
        application/xml
        font/truetype
        font/opentype
        application/vnd.ms-fontobject
        image/svg+xml;

    # 파일 리슀트 λΉ„ν™œμ„±ν™”
    autoindex off;

    include /etc/nginx/conf.d/*.conf;
}

도컀 컴포즈λ₯Ό μ‚¬μš©ν•˜μ—¬ μ‹€ν–‰λ˜μ–΄μžˆλŠ” Nginx ν”„λ‘œμ„ΈμŠ€μ— λ³€κ²½λœ 섀정을 λ°˜μ˜ν•˜λ©΄μ„œ λ§ˆμΉ˜λ„λ‘ ν•˜κ² μŠ΅λ‹ˆλ‹€.

docker compose exec nginx nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

docker compose exec nginx nginx -s reload
2021/09/25 09:38:03 [notice] 34#34: signal process started

κ°μ‚¬ν•©λ‹ˆλ‹€.