카테고리 없음

[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가 다름에도 불구하고 무시된다. 그러므로 이러한 부분을 주의해서 사용해야 한다.