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