본문 바로가기
배포/Nginx

Nginx설정파일을 이해해봅시다

by 졸린개발자 2022. 4. 21.

안녕하세요. 졸린개발자입니다.

 

nginx를 설치하고 나면, 웹 서버를 그대로 사용할 수도 있지만,

더 많은 기능을 사용하기 위해서는 nginx의 설정을 바꿔줘야합니다.

 

설정파일의 위치는 ubuntu 기준 /etc/nginx/nginx.conf입니다.

 

기본적으로 생성되는 이 파일의 내용을 이해해봅시다.

 

user www-data;

Nginx는 Master 프로세스와 Worker프로세스로 나누어집니다. 자세한 것은 구글링하면 더 많은 자료가 있습니다.

이 설정은 worker프로세스가 실행될때 이 user로 실행됨을 나타냅니다.

 

왜 root계정이나 사용자 계정으로 worker가 돌아가지않고 www-data와 같이 새로운 계정으로 권한이 주어지냐면,

권한을 최소로 주어, 악의적인 사용자들이 서버를 헤집고 다니는 것을 방지하기 위함입니다.

 

nginx의 취약점으로 인해, 웹서버로 해커가 침투했다고 하더라도, 계정이 www-data이기 때문에, 제한적인 일밖에 못하여 보안에 조금 더 안전해 질 수 있게 됩니다.

 

그럼 실제로 ubuntu에 이 계정이 있는지 살펴봅시다.

<그림1 ubuntu www-data계정확인>

실제로 있군요. 

 

그럼 Master 프로세스도 www-data계정으로 실행이 될까요?

<그림4 master process의 USER확인>

정답은 아닙니다. root계정으로 실행이 되는군요

 

왜 Master 프로세스는 root계정으로 실행이 될까요?

 

리눅스에서 1024번호 전의 포트는 root계정이 아니면 사용할 수가 없습니다.

0~1023 포트번호는 사용처가 정해진 예약된 포트번호라서 root가 아니면 사용할 수 없게 되어있습니다.

 

root계정으로 실행한 이유는 다양할 것 같은데,

그 중, 한가지 이유로 nginx는 80번 포트를 사용하기 위해서 라고 생각해주시면 되겠습니다.

 


worker_processes auto;

실제 요청을 수행할 worker process의 개수를 조정하는 변수입니다.

<그림2 auto설명>

auto로 설정된 경우, 할당할 수 있는 CPU의 개수로 자동으로 정해지는군요.

 

nginx의 공식 document에 따르면, cpu의 수로 worker process의 개수를 정하는 것을 추천한다고 합니다.

따라서 auto로 그냥 두시는 것을 추천합니다.

 


pid /run/nginx.pid;

Master process의 pid를 결정합니다. 

 

그런데 /run/nginx.pid 파일은 뭘까요? 한번 열어봅시다.

 

<그림3 /run/nginx.pid>

이 파일에 nginx Master process가 사용할 pid가 담겨있군요

 

더 찾아보니 /run폴더는 리눅스에서 process가 실행되면서 사용하는 파일들이 저장되어있다고 하는군요.

이 설정은 건들지 않는 편이 좋겠다고 생각이 드네요.

 


include /etc/nginx/modules-enabled/*.conf;

nginx에서는 모듈이란것이 있습니다. 

추가적인 기능을 더해주는것 같은데 자세히는 모르겠네요. 나중에 공부해봐야겠습니다.

 

어쨌든 이 줄은 모듈의 설정파일을 불러오는 것입니다.

 

 

events  { }

이벤트 블록입니다.

nginx는 효율적인 처리를 위해 비동기, 이벤트 방식으로 worker process를 구성합니다.

 

그래서 왠지 이름만 보면 event에 대한 설정을 해야할 것 같지만,

사실상 worker process구성이라고 봐도 무방하겠습니다.

 

 

worker_connections 768;
worker 하나에 붙을 수 있는 최대 커넥션수입니다.

따라서 (worker개수) * (worker_connectinons) = nginx의 최대 connection수 가 됩니다.

 

 

# multi_accept on;
이 설정은 주석처리가 되어있군요

그럼 default값이 있다는건데, document를 찾아봅시다

<그림5 multi_accept>

default는 off군요

 

이 설정값이 off이면, worker process는 한번에 하나의 connection만 작업 가능하게되고,

on이면, worker process가 여러개의 connection을 받을 수 있습니다.

 

 

http { }

http block은 http에 대한 설정이 있는 block입니다.

 

 

sendfile on;

sendfile이라는 함수를 쓸지 말지 결정하는 설정입니다.

os가 제공하는 read, write함수보다 성능이 더 좋은 것으로 알려져 있습니다.

 

 

tcp_nopush on;

linux에서 TCP_CORK옵션을 활성화하는 옵션입니다.

이 옵션을 활성화하게되면 MSS까지 패킷을 모아놨다가 한번에 발송하게 되는데,

이렇게 되면 일정 크기까지 모아야 해서, 응답시간이 늦어질 수 있습니다.

하지만 최대 200ms까지 지연되고 그 이후에는 강제로 보내지게 됩니다.

 


tcp_nodelay on;

linux에서 TCP_NODELAY옵션을 활성화하는 옵션입니다.

이 옵션을 활성화하면 패킷을 모으지않고 바로바로 전송하게 됩니다.

응답시간은 빨라지나 전체적인 서버의 throughput은 낮아질 수 있습니다.

 

 

tcp_nopush와 tcp_nodelay

두개의 설명을 보면, 두개는 서로 양립할 수 없는 옵션인 것을 눈치채셨을 것입니다.

하지만 두개다 on인데, 이러면 어떻게 되는 것일까요?

 

리눅스 커널 2.2까지는 두개의 옵션이 동시에 on이 불가능했습니다.

하지만 2.4부터 두개의 옵션이 다 켜져도 상관하지 않았고, 이러한 경우 TCP_CORK옵션이 우선적으로 켜지게 됩니다.

nginx에서는 tcp_nopush옵션이 우선된다고 봐도 무방할 것입니다.

 

 

keepalive_timeout 65;

커넥션을 유지할 초를 설정합니다.

너무 높게되면 http에서 커넥션을 오랫동안 지속하여, 다른 사용자들이 빠르게 접속할 수 없게 될 것입니다.

너무 낮게되면 사용자가 http요청을 빠르게 여러번 호출했을 때, connection을 다시 연결해야하는 overhead가 생길것입니다.

 

 

types_hash_max_size 2048;

hash table의 max size를 결정하는 옵션입니다

 

nginx에서는 server의 이름이나 MIME type 등, 각종 정보에 빠르게 접근하기 위해 hash table을 이용합니다.

 

이 설정은 그중, MIME type에 대한 hash table의 size를 결정합니다.

 

특별히 hash table의 size가 부족하여 에러가 나지 않는 이상, 조절할 필요는 없어보입니다.

 


# server_tokens off;

nginx는 기본적으로, http응답을 내릴때, nginx의 정보를 내리는데, 그것을 끄는 옵션입니다.

off가 되면, 서버의 정보를 내려주지 않습니다.

 

default는 on이여서 off가 되게 이것의 주석을 푸는것이 좋습니다.

서버의 정보만으로 해당 버전의 취약점을 알아내서 공격을 하는 경우도 있으므로, 이러한 정보를 최대한 노출시키지 않는것이 중요합니다.

 

그럼 직접 확인해봅시다.

크롬의 개발자도구의 network tab에서 response를 확인해보면 다음과 같이 나옵니다.

<그림6 server_tokens on>

server_tokens on인 상태에서는 이렇게 Server헤더에 정보를 내려주게 됩니다. Ubuntu라는 사실까지 알려주는군요.

 

그림 off하고 다시 reload해봅시다.

<그림7 server_tokens off>

off인 상태에서는 nginx의 버전정보, os의 정보가 없어지게 됩니다.

그런데 server가 nginx라는건 보여지는군요. 이부분도 같이 없어지면 좋겠는데, 나중에 개선되길 기대합니다.

 


# server_names_hash_bucket_size 64;

서버의 이름을 저장하는 hash table의 크기를 결정합니다.

 

nginx에서는 server의 이름이나 MIME type 등, 각종 정보에 빠르게 접근하기 위해 hash table을 이용합니다.

 

이 설정은 그중, 서버 이름에 대한 hash table의 size를 결정합니다.

 

근데 주석처리가 되어있군요. default 설정이 있는듯 합니다.

<그림8 server_names_hash_max_size>

default는 512로 설정되어있군요.

 


# server_name_in_redirect off;

이 옵션에 대해 알려면 우선 rewrite에 대한 것을 알아야합니다.

 

실제 우리가 요청을 하는 url과 처리하는 url이 다른것인데,

 

외부에서 www.example.com/project?projectid=2 

이런 url로 요청을 했다고 가정해봅시다.

 

그런데 사실 서버의 실제 파일위치는 /project/2 이런식으로 되어있으면, url과 실제 파일 위치와 다르기때문에,

서버에서 내부적으로 처리를 해주어야합니다.

 

그래서 이러한 내부적으로 /project?projectid=2를 /project/2로 바꿔주는 것이 rewrite입니다.

 

이러한 rewrite는 바깥에 보여지는 정보와 실제 정보가 다르기때문에 보안성이 향상됩니다.

 

그래서 이 옵션이 뭐냐면

이 옵션이 on이 되어있으면, server_name에 지정된 첫번째 host이름을 사용해서 redirect를 합니다.

만약 이 옵션이 off가 되어있으면, host헤더에 표시된 이름으로 redirect를 하게됩니다

 

<그림9 server_name_in_redirect>

default는 off군요. 

 

이 설정이 필요하면 켜시면 되겠습니다.

 


include /etc/nginx/mime.types;

nginx에서는 content-type을 결정하는 방법이 두가지 있습니다.

 

  1. 프록시를 사용하는 경우, 프록시에서 넘어온 content-type을 그대로 사용합니다.
  2. 프록시를 사용하지 않는 경우, URL의 확장자를 /etc/nginx/mime.types파일과 비교해서 가져옵니다.

2번째 경우에 사용할 파일을 include해주는 겁니다.

 

정적인 파일컨텐츠를 제공할때는 필수겠군요.

 


default_type appication/octet-stream;

response의 기본 type을 application/octect-stream으로 지정합니다.

 

자세한 내용은 찾아볼 수 없었지만,

아마 제 생각으로는 위의 mime.types파일에서 찾을 수 없는 확장자인 경우에 이렇게 보낼 것으로 생각됩니다.

나중에 실험을 해봐야겠군요.

 

 

 

##
# SSL Settings
##

SSL 세팅부분 입니다.

 


ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE

사용할 수 있는 ssl프로토콜의 종류를 지정합니다.

 

주석을 보시면 Dropping SSLv3라고 적혀있습니다.

찾아보니 SSLv3에는 보안문제가 있어서 버전이 빠져있다는군요.

 


ssl_prefer_server_ciphers on;

SSL협상 과정중, 서버가 선호하는 암호화를 할 수 있게 됩니다.

 

만약 이 설정이 off가 되어있다면 client가 선호하는 암호화를 진행하게 되는데, 

그렇게 되면 client에서 보안강도가 낮은 암호화를 선택할 수도 있습니다.

 

만약 크롬같은 높은 수준의 보안강도를 가지고 협상하는 client에서만 접속한다면

이 옵션을 off하여 클라이언트에서 원하는 좋은 성능을 가진 암호화를 선택하게 만들 수도 있겠습니다.

 


##
# Logging Settings
##

로깅 관련 설정 부분입니다.

 


access_log /var/log/nginx/access.log;

서버에 접근할 때 출력되는 로그를 저장하는 파일설정입니다.

 

좀 더 찾아보니, 여기서는 전역로그라서 이걸 끄고, server마다 따로 설정해 주는게 좋을것 같습니다

 


error_log /var/log/nginx/error.log;

nginx에 오류가 났을때 출력되는 로그파일 설정입니다.

 

좀 더 찾아보니, 여기서는 전역로그라서 이걸 끄고, server마다 따로 설정해 주는게 좋을것 같습니다

 

 

##
# Gzip Settings
##

gzip관련 설정입니다.

 


gzip on;

gzip을 켭니다

 

nginx에서 gzip을 켜게되면, http로 파일을 그냥 보내지 않고, gzip으로 압축해서 보내게 됩니다.

 


# gzip_vary on;

이 옵션을 켜게되면 Response Header에 Vary: Accept-Encoding이 추가됩니다.

 

 

# gzip_proxied any;

프록시나 캐시서버에서 요청을 할때 압축을 할지 선택합니다

 

off: 캐시서버에서 요청할경우 압축하지 않습니다

expired: expire되었을때만 압축합니다

no-cache: cache-control에 no-cache가 있을때만 압축합니다

no-store: cache-control에 no-store가 있을때만 압축합니다.

 

default값은 off입니다.

 


# gzip_comp_level 6;

gzip의 압축 level을 설정할 수 있습니다. 1~9까지 설정가능하며

default는 1입니다

 

comp level을 높이면, 압축률이 높아져 네트워크를 타는 시간이 짧아지지만,

cpu가 그만큼 일을 더 해야하고

 

comp level을 낮추면, 압축률이 낮아져 네트워크를 타는 시간이 높아지지만,

cpu가 일을 더 적게하게됩니다.

 


# gzip_buffers 16 8k;

gzip의 버퍼를 설정합니다. 왜 gzip에 버퍼가 필요한지는 gzip알고리즘을 더 찾아봐야 할 듯 합니다.

 

16은 버퍼의 개수를 의미하고

8k는 버퍼의 크기를 의미합니다

 

플랫폼에 따라 default값이 바뀝니다.

 


# gzip_http_version 1.1;

gzip을 수행할 http 최소 버전입니다

 

위의 주석을 풀면 최소 http 1.1부터 gzip압축이 적용됩니다

즉, http 0.9와 1.0은 gzip을 하지 않습니다

 

default값은 1.1입니다.

 


# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

 

gzip을 적용할 media type입니다.

이 옵션에 명기된 media type만 gzip이 적용됩니다.

 

default값은 text/html입니다.

 


##
# Virtual Host Configs
##

가상 호스트 설정입니다. 

 


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

server의 설정파일을 include합니다. 자세한건 나중에 더 찾아봐야겠네요

 


include /etc/nginx/sites-enabled/*;
server의 설정파일을 include합니다. 자세한건 나중에 더 찾아봐야겠네요

 

 

결론

오늘은 nginx 설정파일을 하나하나 뜯어보았습니다.

nginx에 대해 더 깊게 알게 된것 같군요.

 

그럼 긴 글 읽어주셔서 감사합니다.

 

 

참고한 출처

https://prohannah.tistory.com/136

https://askubuntu.com/questions/873839/what-is-the-www-data-user

https://whatisthenext.tistory.com/123

https://icarus8050.tistory.com/57

http://nginx.org/en/docs

https://unix.stackexchange.com/questions/134301/why-does-nginx-starts-process-as-root

https://extrememanual.net/9924

https://kanoos-stu.tistory.com/entry/Nginx

https://wiki.changwoo.pe.kr/research:nginx

https://stackoverflow.com/questions/3761276/when-should-i-use-tcp-nodelay-and-when-tcp-cork

https://stackoverflow.com/questions/22124098/is-there-any-significant-difference-between-tcp-cork-and-tcp-nodelay-in-this-use

https://velog.io/@gilchris/Nginx-proxy%EC%97%90%EC%84%9C-%EB%84%98%EC%96%B4%EC%98%A4%EB%8A%94-Content-Type-%EB%8D%AE%EC%96%B4%EC%93%B0%EA%B8%B0

https://yangbongsoo.tistory.com/4