Nginx 설정에 대해서

THXX·2023년 9월 18일
0

Nginx는 자랑스럽게 자신들을 "고성능 웹서버 및 리버스 프록시 서버"라고 소개한다.

아주 기고만장하지만 인정해야 한다. 모두들 몇 년 전부터 apache2에서 nginx로 넘어가기 시작했다.
그러나 이것을 어떻게 써야하는 지는 잘 모를 수 있다. 그러면 검색을 해야 한다. 이제부터 지옥이 시작된다.

nginx는 Virtual Host라는 것을 지원하므로 수많은 도메인 네임에 대해 대응할 수 있다. 주소표시줄에 도메인을 작성하여 어떠한 웹사이트에 들어간다고 가정하자. 예시로는 aaa.com, h1.aaa.com, h2.aaa.com으로 하자.

DNS 정보를 살펴봤더니 이 세 개의 도메인들, 싹 다 같은 IP에 연결되어 있다. 어떻게 도메인 주소를 이용하여 각각 다른 웹 서비스를 보여줄 수 있는 것인가?

이것이 고대의 Apache2에서부터 내려오는 Virtual Host의 기능이다. 도메인 주소, 즉 호스트네임을 이용하여 다른 정적 웹서비스를 서빙하거나 리버스 프록시를 가능케 한다.

실무 경험이 없는 나는 이 Virtual Host로 구성되는 설정이 Nginx 설정의 전부라고 할 수 없다. (경험의 부족으로 인해서 단언할 수 없다.) 그러나 Nginx를 만지면서 만진게 저것 밖에 없다.

이 글은 나의 기억을 기록하기 위함에 있는 것이지 남을 돕기 위한 그러한 글은 아니기 때문에 Nginx 설정의 모든 것을 알고 싶다면 공식 Documentation을 읽어보는 것이 좋겠다.

내 우분투 환경에서 Nginx 설정은

/etc/nginx/sites-available

에 존재한다.

그리고 실제 활성화되는 Nginx 설정을 구별하기 위해 Nginx는

/etc/nginx/sites-enabled

를 참조하여 해당 폴더 내에 있는 텍스트 파일들을 전부 Nginx 설정으로 import 한다.

보통의 작업 기전은 다음과 같다.
1. 커스텀 설정을 sites-available 폴더에 작성한다.
2. sites-enabled 폴더에 해당 설정에 링크되어 있는 심볼릭 링크를 만든다.

ln -s ../sites-available {LINKNAME}

이제 나의 간단한 Nginx 설정을 보여주겠다. [data redacted: #]

server{
        return 301 https://$host$request_uri;
        listen 80;
        server_name h1.aaa.com;
        return 404;
}




server {
        listen 443 ssl;
        server_name h1.aaa.com;

        ssl_certificate #/fullchain.pem;
        ssl_certificate_key #/privkey.pem;

        root #;
        index index.html;

    location ~* \.(?:manifest|appcache|html?|xml|json)$ {
      expires -1;
      # access_log logs/static.log; # I don't usually include a static log
    }

    location ~* \.(?:css|js)$ {
      try_files $uri =404;
      expires 1y;
      access_log off;
      add_header Cache-Control "public";
    }

    # Any route containing a file extension (e.g. /devicesfile.js)
    location ~ ^.+\..+$ {
      try_files $uri =404;
    }

    # Any route that doesn't have a file extension (e.g. /devices)
    location / {
        try_files $uri $uri/ /index.html;
    }

}

아직 Nginx 설정에 대한 이해가 부족하므로 중요한 것만 찍고 넘어가겠다.

위 설정은 일단 두 개의 virtual host로 구성되어 있다. (server{ })
맨 위의 virtual host부터 보도록 하자.

server{
        return 301 https://$host$request_uri;
        listen 80;
        server_name h1.aaa.com;
        return 404;
}

전공 중 컴퓨터 네트워크 강의에서 F를 받지 않은 사람의 경우 위를 쉽게 이해할 수 있으리라 믿는다.

  • return 301: 이는 HTTP Response Code를 의미한다. 301... Moved Permenantly, 즉 영구 리다이렉트다. 그리고 옆은 리다이렉트 되는 주소이다.
  • listen 80: TCP 80 포트를 Listen하겠다는 것이다. 이는 HTTP다.
  • server_name h1.aaa.com: 해당 virtual host의 호스트네임으로 h1.aaa.com를 받는다.
  • return 404: 뭣도 안되면 그냥 404를 출력하라. 이 경우는 뭔가 문제로 인해서 리다이렉트가 안된 경우라고 생각하면 편하겠다.

리다이렉트 주소의 $host는 호스트네임을 의미하며, $request_uri 는 보통 호스트네임 옆에 붙는 /asdas.html 뭐 이런거다. (URI: Uniform Resource Identifier.)

종합하자면 이 virtual host의 존재 이유는 HTTP 프로토콜(TCP 80)로 해당 호스트에 접속할 경우 강제로 HTTPS로 리다이렉트 시켜주는 것이다.

이제 아래의 virtual host를 보자.

        listen 443 ssl;
        server_name h1.aaa.com;

        ssl_certificate #/fullchain.pem;
        ssl_certificate_key #/privkey.pem;

        root #;
        index index.html;

이번엔 443 포트를 listen한다. ssl을 이용하겠다고도 선언을 한다.
server_name은 위와 같다. (당연한 이야기이다)

이제 우리는 HTTPS 서비스를 클라이언트에게 제공해야 하므로 HTTPS 프로토콜이 이용하는 SSL 모듈에 인증서와 비밀키를 제공해야 한다. (ssl_certificate, ssl_certificate_key)
보통 certbot을 이용한 Let's Encrypt 인증 서비스를 많이들 이용한다.

  • root (경로) : 해당 virtual host가 리소스를 제공할 때 어디서 가져올 지를 정해준다. nginx를 최초 설치 시 보통 /var/www/(...)가 지정되어 있다.
  • index (파일명) : root 경로(/) 에 접근 시 어떤 파일에 먼저 접근해서 보여줄 지 정해준다. 위 예시는 index.html을 가져다 보내줄 것이다.

여기서 주의해야 할 점: root를 /var/www 로 정했다면, www-data:www-data로 해당 폴더의 소유권을 정해줘야 한다.
UNIX는 멀티-유저 오퍼레이팅 시스템이다. 이 점을 활용하는 Nginx는 따로 유저를 가지고 폴더에 접근을 하게 된다.
이 설정이 어디있는가? 바로 /etc/nginx/nginx.conf; Nginx의 메인 설정에 있다.


위와 같은 굵직굵직한 설정이 존재한다.

user www-data;

아주 중요하다. www-data 유저를 사용해서 파일에 접근하겠다는 뜻이기 때문이다.

사실은 이렇다. ps -aux | grep nginx의 결과이다.

맨 왼쪽이 유저를 나타내는 것임을 알 터이다. nginx의 worker process의 소유자가 www-data이다. 이로써 우리는 nginx가 멀티프로세싱 기반으로 만들어진 웹 서버이며 실제 일하는 놈들은 worker process임을 알게 되었다. master process 는 worker process 위에 군림할 것이다.
(위의 설정에서 worker_processes auto;를 보자. 이는 worker process의 수를 master process가 제한할 수 있음을 의미한다.)

이제 location에 대해서 설명해볼까?

    location ~* \.(?:manifest|appcache|html?|xml|json)$ {
      expires -1;
      # access_log logs/static.log; # I don't usually include a static log
    }

    location ~* \.(?:css|js)$ {
      try_files $uri =404;
      expires 1y;
      access_log off;
      add_header Cache-Control "public";
    }

    # Any route containing a file extension (e.g. /devicesfile.js)
    location ~ ^.+\..+$ {
      try_files $uri =404;
    }

    # Any route that doesn't have a file extension (e.g. /devices)
    location / {
        try_files $uri $uri/ /index.html;
    }

흉측하기 짝이 없지만 진정하고 읽으면 어느정도 이해할 수 있을 것이다.

location 뒤에 uri 경로가 나오는 데 이 떄 regexp를 이용하여 규칙을 정할 수 있는 것으로 보인다.
가령 두 번 째 것은 css 또는 js 파일을 접근할 때 적용될 규칙이리라.

  • try_files: 일단 해당 virtual host의 root 폴더에서 $uri 그대로 파일 있는 지 확인하고 있으면 전송한다. 없으면 404 NOT FOUND.
  • expires: 해당 파일의 캐쉬의 만료 기한을 정하는 듯 하다.
  • access_log (on|off); : 말 그대로 접근 로깅을 할 것이냐 여부이다. 할 거라면 경로를 정해준다. (/var/log/nginx에 저장될 것이다) 안 할거면 off다.
  • add_header (header_name) (value);: 간단하다. HTTP response 헤더에 원하는 대로 추가한다. 위는 Cache-Control을 public으로 설정했다. 아무튼 캐쉬에 관련된 설정임이 틀림없다.
  • 나머지는 다 주석으로 설명이 되어 있다. (good)

Nginx의 설정을 조금 알아보았다. 틀린 점이 있을 수 있다. 부디 이 미련한 짐승에게 지식을 설파하는 멋진 실무 개발자분이 있길 바랄 뿐이다.

profile
THXX FOR EVERYTHING

0개의 댓글