ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Nginx] Nginx 예시 및 설정시 주의사항
    카테고리 없음 2023. 8. 6. 00:00

    1. Nginx 예시/샘플 설정

     

    [ Nginx 설정 파일들 ]

    실무에서 사용되는 Nginx 설정은 꽤나 복잡한데, 이를 아래와 같이 분리하였습니다.

    • mime.types: Nginx 서버에서 처리할 MIME 타입 모음
    • upstream.conf: upstream(서버 그룹)을 모아둔 설정 파일
    • header.conf: 요청을 다른 서버로 프록시할 때, 전달해주는 헤더 설정 파일
    • ssl.conf: SSL과 관련된 설정 파일, SSL 인증서 파일을 경로로 참조함
    • ssl-server.conf: SSL 요청(443 포트)로 들어오는 요청과 관련된 서버 블럭 설정 파일
    • http-server.conf: Http 요청(80 포트)로 들어오는 요청과 관련된 서버 블럭 설정 파일
    • nginx.conf: Nginx 서버에서 참고하는 설정 파일로 다른 설정 파일들을 include 함

     

    mime.types

    Nginx 서버에서 처리할 MIME 타입

    types {
        text/html                                        html htm shtml;
        text/css                                         css;
        text/xml                                         xml;
        image/gif                                        gif;
        image/jpeg                                       jpeg jpg;
        application/javascript                           js;
        application/atom+xml                             atom;
        application/rss+xml                              rss;
    
        ...
    }

     

    upstream.conf

    upstream(서버 그룹)을 모아둔 설정 파일

    # upstream은 nginx가 받은 요청을 넘겨 줄 서버 지시자
    # keepalive는 upstream 접속에 사용될 connection 수
    
    upstream tomcat-mangkyu {
        server 127.0.0.1:8523;
        keepalive 10;
    }
    
    upstream jp1-mangkyu {
        server jp1-github.mangkyu.com;
        keepalive 10;
    }

     

    header.conf

    요청을 다른 서버로 프록시할 때, 전달해주는 헤더 설정 파일

    proxy_pass_header Server;               # 프록시할 때 Server 헤더를 전달할 지 결정함(기본적으로 전달하지 않음)
    proxy_set_header Host $http_host;       # 프록시할 때 Host 헤더를 설정함

     

    ssl.conf

    SSL과 관련된 설정 파일, SSL 인증서 파일을 경로로 참조함

    listen 443 ssl http2;
    
    ssl_certificate       ./ssl/cert.pem;
    ssl_certificate_key   ./ssl/key.pem;
    
    ssl_protocols  TLSv1.2 TLSv1.3;
    ssl_ciphers    AES128:RC4:AES256:!ADH:!aNULL:!DH:!EDH:!eNULL:!LOW:!SSLv2:!EXP:!NULL;
    ssl_prefer_server_ciphers   on;

     

    ssl-server.conf

    SSL 요청(443 포트)로 들어오는 요청과 관련된 서버 블럭 설정 파일

    # https 443으로 들어온 요청에 대한 proxy pass 연결 부분
    server {
    	include ssl.conf;                                                        # ssl 관련 설정 추가
    	server_name github.mangkyu.com kr1-github.mangkyu.com;                   # 이 server 블럭에서 처리할 도메인명들
    	access_log  ./logs/nginx/access_ssl_mangkyu.log  main;                   # 파일로 로그 기록
    	error_log   ./logs/nginx/error.log   error;                              # 파일로 에러 로그 기록
    
        # ~*은 정규 표현식을 사용하여 요청된 URI와 지정된 패턴을 비교하는 정규식 매칭 연산자
    
        # /actuator로의 요청은 외부에서 접근시 보안 이슈가 있으므로, 내부에서만 접근 가능하도록 제한함(SpringBoot Actuator를 사용하지 않는다면 제거)
        location ^~ /actuator {
            return 404;
        }
    
        # hello와 그 하위의 path에 대해 톰캣 서버로 proxy
    	location ~* ^/(hello/) {
    
            # 쿠키에 있는 MANGKYU_LOC 값이 jp1이면 jp1-mangkyu upstream으로 proxy
            if ($cookie_WORKS_RE_LOC = 'jp1') {
    	    	proxy_pass https://jp1-mangkyu;
    	    	break;
            }
    
            proxy_pass http://tomcat-mangkyu$uri$is_args$args;
            break;
        }
    
        # 그 외의 path로 접근한 경우에는 404 반환
        location / {
            return 404;
            break;
        }
    
        error_page 400 /html/404.html;
        error_page 401 /html/404.html;
        error_page 403 /html/404.html;
        error_page 404 /html/404.html;
        error_page 405 /html/404.html;
        error_page 500 /html/404.html;
        error_page 501 /html/404.html;
        error_page 502 /html/404.html;
        error_page 503 /html/404.html;
    }

     

    http-server.conf

    Http 요청(80 포트)로 들어오는 요청과 관련된 서버 블럭 설정 파일

    # http 80으로 들어온 요청에 대한 proxy pass 연결 부분
    server {
        listen       80;  	                                   # 80번 요청에 대한 listen
        server_name github.mangkyu.com kr1-github.mangkyu.com; # 이 server 블럭에서 처리할 도메인명들
        access_log  ./logs/nginx/access_mangkyu.log  main;     # 파일로 로그 기록
    
        # ~*은 정규 표현식을 사용하여 요청된 URI와 지정된 패턴을 비교하는 정규식 매칭 연산자
    
        # /actuator로의 요청은 외부에서 접근시 보안 이슈가 있으므로, 내부에서만 접근 가능하도록 제한함(SpringBoot Actuator를 사용하지 않는다면 제거)
        location ^~ /actuator {
            return 404;
        }
    
        # /api 그 하위의 path에 대해 https로 rewrite
        location ~* ^/(api/) {
            rewrite ^(.*) https://$http_host$1 permanent;
        }
    
        # 그 외의 path로 접근한 경우에는 404 반환
        location / {
            return 404;
            break;
        }
    
        error_page 400 /html/404.html;
        error_page 401 /html/404.html;
        error_page 403 /html/404.html;
        error_page 404 /html/404.html;
        error_page 405 /html/404.html;
        error_page 500 /html/404.html;
        error_page 501 /html/404.html;
        error_page 502 /html/404.html;
        error_page 503 /html/404.html;
    
    }

     

    nginx.conf

    Nginx 서버에서 참고하는 설정 파일로 다른 설정 파일들을 include 함

    ## CPU Core에 맞는 적절한 Work Process를 할당함
    worker_processes  auto;
    
    ## Worker Process가 수용할 수 있는 Connection 개수
    events {
        worker_connections  4000;
    }
    
    http {
        include       mime.types;               # 해당 http 블럭에서 처리할 mime type 모음, 기본으로 octet_stream을 사용함
        default_type  application/octet-stream; # octet_stream은 file이나 data의 content-type을 식별하기 어려운 경우에 사용할 수 있는 기본 타입임
    
        sendfile       on;                      # 디스크에서 네트워크로 파일을 전송할 때 sendfile()이라는 system call을 사용할지 여부를 결정함
        tcp_nopush     on;                      # TCP 패킷을 가능한 빨리 전송할 지(on) 또는 조금 기다렸다가 모아서 전송할 지(off)를 결정함
    
        keepalive_timeout  65;                  # keep-alive connection는 유휴 상태의 keep-alive 커넥션이 얼마나 오래 유지될지를 결정함(default 75)
        keepalive_requests 100;                 # keep-alive requests는 단일 keep-alive 커넥션이 최대 몇 개의 요청을 전송할 수 있는지를 결정함(default 100)
    
        gzip          on;                       # gzip 압축을 활성화함
    
        send_timeout       15s;                 # send_timeout는 nginx가 WAS로 요청을 보내고, 응답을 기다리는 시간임(default 60s)
        resolver_timeout   5s;                  # resolver_timeout는 DNS를 찾는 것을 완료하기까지 기다리는 시간임(default 30s)
    
    
        large_client_header_buffers 20 32k;     # 요청 헤더를 읽을 때 사용되는 버퍼의 최대 개수와 크기(default 4, 8k), 초과 시 414 에러 반환
        client_header_buffer_size   8k;         # 요청 헤더를 저장하기 위한 버퍼 크기(default 1k), 초과 시 414 에러 반환 ex)쿠키 크기가 커질 경우
        client_max_body_size        100M;       # 요청 바디의 최대 크기(default 1M), 초과 시 413 에러 반환
        client_body_buffer_size     1M;         # 요청 바디를 저장하기 위한 버퍼 크기(default 8k), 초과 시 버퍼 데이터를 메모리에서 디스크로 저장함
        output_buffers 20 32k;                  # 응답 바디를 저장하기 위한 버퍼 크기(default 1, 32k), 32K짜리 버퍼 1개를 응답에 사용하겠다는 의미임
    
        ignore_invalid_headers off;             # 요청 헤더에 유효하지 않은 헤더가 있을 경우 무시할지 결정함
        server_tokens off;                      # 응답 헤더에 nginx 버전 정보를 넣을지 결정함
        autoindex off;                          # 요청 경로 대상이 디렉토리인 경우, 파일 리스팅을 할지 여부(off 시 403 에러 반환)
    
        # 요청을 다른 서버로 프록시할 때, 헤더를 세팅해줌
        include header.conf
    
        # nginx 로그 포맷
        log_format  main  '$remote_addr $remote_user "$request" '
                       '$status $body_bytes_sent "$http_referer" "$request_time" '
                       '"$http_user_agent" ';
    
        include upstream.conf;      # upstream(서버 그룹)을 모아둔 설정 파일
        include http-server.conf;   # Http 요청(80번 포트)로 들어오는 경우 처리하는 서버 블럭
        include ssl-server.conf;    # SSL 요청(443 포트)로 들어오는 경우 처리하는 서버 블럭
    
    }

     

     

    2. Nginx 설정 시의 주의사항

    [ server_name 주의사항 ]

    nginx는 요청이 들어오면 먼저 어느 서버 블록이 요청을 처리할 지 판단하게 되는데, server_name에 설정된 값이 이를 결정한다. 예를 들어, 80번 포트에 대한 3개의 서버 블록이 존재하는 상황이라고 하자.

    server {
        listen      80;
        server_name mangkyu.org www.mangkyu.org;
        ...
    }
    
    server {
        listen      80;
        server_name mangkyu.net www.mangkyu.net;
        ...
    }
    
    server {
        listen      80;
        server_name mangkyu.com www.mangkyu.com default_server;
        ...
    }

     

    nginx는 요청 헤더의 “Host” 값을 바탕으로 어느 서버에 요청을 라우팅할지 결정한다. 그리고 만약 매칭되는 server_name이 없거나 Host 헤더 값이 없다면, 해당 포트의 default 서버로 요청을 보내게 되고, 만약 default로 지정된 server_name이 없다면 위에서부터 가장 먼저 매칭되는 서버 블록이 처리하게 된다. Host 헤더 필드가 없는 경우에 요청을 drop 시키려면 다음과 같이 설정할 수도 있다.

    server {
        listen      80;
        server_name "";
        return      444;
    }

    하나의 서버에 여러 개의 DNS가 매핑되는 상황에서 nginx를 설정하려다 보면 원하지 않는 server 블록이 요청을 처리하게 되는 문제가 발생할 수 있다. 이러한 경우에는 server_name이 올바르게 매핑되는지 확인해보면 된다.

     

    [ proxy_set_header 주의사항 ]

    proxy_pass 시에 추가적인 헤더를 전달하기 위해서는 proxy_set_header를 사용해야 하며, http, server, location 블록에서 사용할 수 있다. 만약 별도의 설정이 없다면 아래의 2가지 헤더를 기본적으로 갖게 된다.

    proxy_set_header Host       $proxy_host;
    proxy_set_header Connection close;

     

    proxy_set_header는 기본적으로 상위 수준의 설정을 상속받는다. 즉, 상위 블록에 해당 설정이 있다면 하위 블록에서도 사용하게 되는 것이다. 예를 들어 proxy_set_header가 http 또는 server 블록에 존재한다면, location 블록에서도 이를 사용할 수 있다.

    하지만 하위 수준의 블록에서 proxy_set_header를 해준다면, 상위 수준의 블록에 존재하는 proxy_set_header는 날라가고 해당 블록의 proxy_set_header만 남게 된다.

    예를 들어 다음과 같은 server 블록이 있다고 하자. 서로 다른 2개의 key(Hello, MangKyu)를 갖는 proxy_set_heade가 각각 server 블록과 locatino 블록에 존재한다. 이 경우에 전달되는 헤더는 어떤 것이 있을까?

     server {
        listen       80;
        server_name  localhost;
        
        # 상위 블록에 존재하는 설정은 key가 다름에도 불구하고 무시됨
        proxy_set_header Hello "Hello";
        
        location / {
            proxy_set_header MangKyu "MangKyu";
            proxy_pass http://developers;
        }        
        
        ...
    }

     

    여기서 proxy_pass로 전달되는 헤더는 MangKyu 뿐이다. 왜냐하면 더 좁은 블록인 location에 proxy_set_header가 존재하므로, 상위 블록들의 proxy_set_header 설정들은 무시되기 때문이다. 상위 블록에 존재하는 proxy_set_header 설정은 key와 하위 블록에 존재하는 key가 다름에도 불구하고 무시된다. 그러므로 이러한 부분을 주의해서 사용해야 한다.

     

    댓글

Designed by Tistory.