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를 받지 않은 사람의 경우 위를 쉽게 이해할 수 있으리라 믿는다.
리다이렉트 주소의 $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를 /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 파일을 접근할 때 적용될 규칙이리라.
Nginx의 설정을 조금 알아보았다. 틀린 점이 있을 수 있다. 부디 이 미련한 짐승에게 지식을 설파하는 멋진 실무 개발자분이 있길 바랄 뿐이다.