728x90
반응형
SMALL

참고자료

 

풀스택을 위한 도커와 최신 서버 기술(리눅스, nginx, AWS, HTTPS, flask 배포) [풀스택 Part3] 강의 | 잔재

잔재미코딩 DaveLee | 본 강의는 풀스택 강의 시리즈 Part3 강의로 최신 서버 기술과 도커 기술을 탄탄하게 익히는 강의입니다. 본 강의는 실질적으로 도커를 내 기술 스택에 포함시킬 수 있도록, 도

www.inflearn.com

 

웹 서버는 HTTP 요청을 받아서 해당 요청에 대한 응답을 해주는 프로그램이다. 대표적인 웹 서버로 Apache, Nginx가 있는데 요즘 점점 더 뜨고 있는 웹 서버가 Nginx인것 같아 공부해 보려고 한다. 웹 서버는 프로그램을 서버상에 설치해서, 특정 HTTP 요청에 따라 서비스를 제공해주는 방식으로 구현된다.

 

NginxApache보다 점점 추세가 좋아질까? 난 아래 구동 방식의 차이에서 나온다고 생각한다.

Apache 구동 방식

Prefork MPM(Multi Processing Module) 방식

→ HTTP 요청이 올 때마다, 프로세스를 복제하여 각각 별도 프로세스에서 해당 HTTP 요청 처리

 

Worker MPM(Multi Processing Module) 방식

→ 하나의 HTTP 연결 후, 여러 요청을 처리하기 위해 복제된 프로세스 내에서 여러 쓰레드를 생성하여, 여러 HTTP 요청을 처리하는 방식

 

그러니까 결론은, HTTP 요청이 많아지면 많아질수록 프로세스도 여러개 만들어지고 프로세스 내 쓰레드도 여러개가 만들어진다.

Nginx 구동 방식

Event Driven 방식

  • 하나의 프로세스로 동작하며, HTTP 요청을 event로 비동기식으로 처리한다.
  • 대부분의 HTTP 응답은 결국 HTML 파일을 제공하는 것이므로, IO 작업이다.
  • 따라서, IO 작업으로 event를 포워딩하고, 요청 순이 아닌 요청 작업이 끝난 순으로 처리한다.

이렇게 되면, HTTP 요청마다 프로세스든 쓰레드든 생성이 필요없으니 시스템 자원 관리에 장점이 있다.

보통 접속자가 많을 때, 시스템 자원 관리 효율성 때문에 Nginx가 이론적으로는 성능이 좋을 수 있는데, 어떤 요청이고 그 요청이 어떤 작업을 하느냐에 따라 성능의 차이는 천차만별이라 꼭 그렇지도 않다. 그리고 결론적으로 웹 서버는 다양한 추가 기능과 함께 동작한다. 예를 들면, 플러그인의 작업이라든가 해서, 종합적인 성능에는 큰 차이를 보이지 않는다. 

그러나, 개인적인 생각으로는, 요즘 같이 대규모 서비스로 대고객의 요청을 받아들이는 세상에서 프로세스나 쓰레드를 지속적으로 만들어내서 요청을 처리하는 방식은 아무래도 오버헤드가 생길 수 밖에 없다고 생각한다. 그래서 Nginx가 요즘 더 뜨는 추세가 아닌가 싶다.

 

간단하게 ApacheNginx의 구동방식을 이해해 보았다. 이제 Nginx를 직접 설정해보자.

 

Nginx 설치

우선, Linux 환경안에서 시작해보자. 그러기 위해 도커를 사용한다.

docker run -dit -p 80:8080 --name myos ubuntu:20.04
docker exec -it myos /bin/bash
  • 여기까지 진행하면 해당 컨테이너의 쉘로 들어오게 된다. 이 안에서 다음 명령어를 실행하자.

 

apt-get update
apt-get install nginx
apt-get install vim

 

  • Nginx를 설치할 때 특정 버전을 명시하고 싶으면 nginx=XXX로 설치하면 된다. 
  • 설정 파일을 다루기 위해 vim도 설치해주자.

 

만약, 특정 버전이 어떻게 되는지 궁금하면 다음 명령어를 입력한다.

apt list -a nginx

 

아무튼 nginx 설치를 하면 다음과 같이 지역을 고르라고 나온다. Asia/Seoul로 하면 된다.

 

Nginx 설정 파일

nginx의 기본 설정 파일은 `nginx.conf` 파일이다. 이 파일의 경로를 찾기 위해 다음 명령어를 입력하자.

find -name nginx.conf

 

나의 경우 이 경로 `./etc/nginx/nginx.conf`에 있다. 이 파일을 vim으로 열어보자.

vi ./etc/nginx/nginx.conf

 

다음과 같이 보여질 것이다.

  • 상단에 `user`는 이 웹 서버를 실행할 수 있는 권한이 있는 사람을 의미한다. 그룹이 될 수도 있고 개인이 될 수도 있다. 굳이 건드리지 말자.
  • 상단에 `worker_processes`nginx의 워커 프로세스 수를 설정한다. 요청을 처리하는 nginx의 개별 프로세스 수를 나타내며, auto로 지정되어 있으면 nginx는 시스템의 CPU 코어수에 맞춰 자동으로 적절한 수의 프로세스를 생성한다. 이 부분도 굳이 건드리지 말자.  
  • 상단에 `pid`nginx의 메인 프로세스 ID를 저장하는 파일의 경로를 의미한다. 이 nginx가 실행될 때 해당 파일에 자신의 PID를 기록한다.
  • 상단에 `include`는 지정된 경로에 있는 파일을 이 설정 파일에 포함시킨다. 그래서 여러개의 설정 파일을 쉽게 관리할 수 있게 해준다.
"어? nginx는 이벤트 비동기 처리 방식으로 요청별로 프로세스가 늘어나는 방식이 아니라면서요?" → 아주 좋은 질문이다. 말처럼 nginx는 이벤트 비동기 처리 방식으로 요청을 처리하지만, 하나의 프로세스만으로 모든 요청을 효과적으로 처리할 수는 없다. 생각을 해보라. 프로세스가 하나만 도는데 요청이 만건이다. 그럼 프로세스는 하나라 CPU는 남아도는데 하나의 프로세스가 모든 요청을 처리해야 하면 정말 비효율적으로 요청을 처리하는 것이다.  그래서, 워커 프로세스를 CPU 코어 수에 맞춰(예를 들면 4개) 만들어 두면 4개의 프로세스가 무수히 들어오는 요청에 대해 이벤트 비동기 처리를 하게 되고 그러면 하나의 프로세스보다는 훨씬 더 효율적으로 처리할 수 있게 된다. 그래서 auto로 지정하면 CPU 코어수에 맞춰 적절하게 프로세스를 생성한다. 

 

그 다음 그 아래 있는 http 블록이 가장 중요하고, 이 블록이 전체 웹 서버 기본 설정 블록이다.

http 블록 하단에 보면 여기도 `include`가 있다. 일반적으로 nginx 웹 서버를 하나 띄우고 얘가 관리하는 서비스가 하나가 아니라 여러개이다. 그리고 그 각각의 서비스는 별도의 설정 파일로 관리하고 저렇게 `include`로 해당 설정 파일을 포함시킨다. 

 

그래서 일반적으로, `/etc/nginx/conf.d/xxxsite.conf` 이렇게 사이트(서비스)별로 설정파일을 따로 분리하여 설정한 후 저렇게 포함시킨다.

 

그리고 `/etc/nginx/site-enabled/*``include`로 포함시켰는데 이 역시 해당 경로의 모든 것들을 다 포함시킨다는 의미가 된다. 한번 이 두개의 경로를 직접 들어가보자.

 

`/etc/nginx/conf.d/` 이 경로에는 아무것도 없다. 당연한 게 일단 우리가 만든 서비스도 없고 뭐 아무것도 없기 때문에 없는게 당연하다. 그리고 `/etc/nginx/site-enabled/` 이 경로에는 다음과 같이 default가 하나 있다.

이게 이제 nginx 설치하고 80으로 진입하면 기본으로 보여주는 사이트이다. 한번 저 default 파일을 열어보면,

  • 이렇게 보여지는데, 이 server 블록이 결국 http 블록안에 포함되어서 여러 서비스(서버)가 설정될 수 있게 된다. (왜냐? 이 경로의 모든 파일을 다 include 시킨 것을 위에서 확인했으니까)
  • 그래서 http { ... server {} server {} server {} ... } 뭐 이런 모양으로 이제 구성이 된다. 

그리고 이 sites-enabled 경로에서 `ls -al` 명령어를 쳐보면, 다음과 같이 default 파일은 심볼릭 링크가 걸려있음을 알 수 있다.

그러니까 실질적으로 저 파일이 위치하는 경로는 이 sites-enabled가 아니라, sites-available에 있다. 한번 들어가보면 다음과 같다.

"근데, 왜? 왜 이렇게 해놓은거지 구조를?"

의아하다. 실질적으로 default 파일의 경로는 sites-available에 있으면 nginx.conf 파일에서 includesites-available로 하면 될 것을 굳이 sites-enabled로 해놓고 default 파일을 심볼릭 링크를 걸어 둔 이유가 무엇일까? 

 

추측컨데, 개발자의 의도는 'available'(이용가능한) 사이트와 'enabled'(현재 활성화) 된 사이트를 구분하고 싶었던 것 아닐까? 그래서 "서비스로 띄울 사이트들을 일단은 available에 올려두고, 이 중에 enabled 시킨 것들만 서비스하게 하자." 이런 의도가 있지 않았나 싶다. 

 

server 블록

이제 default 파일에서 봤던 server 블록 내부를 이해해보자. 이 블록 전체는 다음과 같이 생겼다.

server {
        listen 80 default_server;
        listen [::]:80 default_server;

        # SSL configuration
        #
        # listen 443 ssl default_server;
        # listen [::]:443 ssl default_server;
        #
        # Note: You should disable gzip for SSL traffic.
        # See: https://bugs.debian.org/773332
        #
        # Read up on ssl_ciphers to ensure a secure configuration.
        # See: https://bugs.debian.org/765782
        #
        # Self signed certs generated by the ssl-cert package
        # Don't use them in a production server!
        #
        # include snippets/snakeoil.conf;

        root /var/www/html;

        # Add index.php to the list if you are using PHP
        index index.html index.htm index.nginx-debian.html;

        server_name _;

        location / {
                # First attempt to serve request as file, then
                # as directory, then fall back to displaying a 404.
                try_files $uri $uri/ =404;
        }

        # pass PHP scripts to FastCGI server
        #
        #location ~ \.php$ {
        #       include snippets/fastcgi-php.conf;
        #
        #       # With php-fpm (or other unix sockets):
        #       fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
        #       # With php-cgi (or other tcp sockets):
        #       fastcgi_pass 127.0.0.1:9000;
        #}

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #       deny all;
        #}
}

 

가장 첫번째로 보이는 이 부분이다.

listen 80 default_server;
listen [::]:80 default_server;
  • 어떤 포트를 잡을지를 의미한다. 이 서버는 80포트와 매핑한다. 이 포트를 변경하면 해당 포트로 이 서버를 매핑한다.
  • nginxhttp 블록안에 여러개의 server 블록을 가진다고 했다. default_server; 이 부분은 해당 포트(80)으로 들어온 요청이 특정 서버 블록과 매칭되지 않을 때 기본적으로 처리할 서버임을 의미한다. 예를 들어 도메인이나 호스트 이름이 매칭되지 않는 경우 nginx는 이 default_server로 정의된 서버 블록을 사용해서 요청을 처리하게 된다.
  • [::]:80 이 부분은 IPv6 주소를 의미한다.
root /var/www/html;

# Add index.php to the list if you are using PHP
index index.html index.htm index.nginx-debian.html;
  • `root`는 웹 서버에서 요청된 파일을 찾기 위한 기본 디렉토리를 설정하는 지시어다. `/var/www/html`은 이 서버 블록에 대한 웹 컨텐츠가 저장된 디렉토리 경로이다. 즉, 클라이언트가 웹 서버에 요청을 보내면, nginx는 해당 파일을 /var/www/html 디렉토리에서 찾는다. 
  • 예를 들어, 클라이언트가 http://example.com/page.html을 요청하면, nginx/var/www/html/page.html을 찾는다.
  • 이 경로는 웹 서버의 기본 웹 컨텐츠 폴더로 많이 사용된다. 웹 사이트의 HTML, 이미지, CSS 파일 등이 이 디렉토리에 위치하게 된다.
  • `index`nginx가 디렉토리 요청을 처리할 때 사용할 기본 인덱스 파일을 지정하는 지시어다.
  • 예를 들어, 클라이언트가 http://example.com/처럼 디렉토리만 요청했을 때, nginx는 자동으로 해당 디렉토리에서 설정된 인덱스 파일을 찾아서 제공한다. 
  • `index` 지시어 뒤에 나열된 파일들은 기본 인덱스 파일의 우선순위를 나타낸다. 왼쪽에서부터 가장 먼저 찾는 파일을 반환한다. 
  • 나의 경우 해당 경로에 다음 파일이 있다.

server_name _;

location / {
        # First attempt to serve request as file, then
        # as directory, then fall back to displaying a 404.
        try_files $uri $uri/ =404;
}
  • `server_name _;`nginx가 이 서버 블록에서 처리할 도메인 이름이나 호스트 이름을 지정하는 것이다. 여기서 `_`는 특별한 의미를 가지고 있지 않으며, 일반적으로 매칭되지 않은 모든 요청에 대해 이 서버 블록이 처리되도록 설정할 때 사용된다.
  • 그러니까 만약, `server_name cwchoiit.org www.cwchoiit.org;` 이런식으로 되어 있으면 이 서버 블록은 이 도메인으로 들어오는 요청만 처리하는 것이다. 
  • location 블록은 nginx가 특정 요청 경로(URI)에 대해 어떻게 처리할지를 정의하는 부분이다. 예를 들어 아래와 같이 작성할 수가 있다.
location /blog {
	root /var/www;
}
location /flask {
	root /var/www;
}
location / {
	try_files $uri $uri/ =404;
}
  • 그럼 요청이 `/blog/xxx`로 들어오면 저 location /blog {...} 로 처리하는 것이고, `/flask/xxx`로 들어오면 저 location /flask {...}로 처리하는 것이다.
  • try_files $uri $uri/ =404; 이 부분은 try_files부터 살펴보면, 이 try_filesnginx가 요청된 리소스를 찾을 때 여러 경로를 시도하도록 지시하는 명령어다. 
  • $uri, $uri/ 는 각각 요청된 URI와 그 디렉토리 경로를 의미한다. 이 지시어는 아래 순서로 파일을 찾는다.
    • $uri: 요청된 URI에 해당하는 파일이 있는지 확인한다. 예를 들어, 클라이언트가 /about.html을 요청했을 때, /var/www/html/about.html 파일이 있는지 확인한다. 
    • $uri/: 요청된 URI가 디렉토리일 경우, 해당 디렉토리가 있는지 확인한다. 예를 들어, /about/으로 요청이 들어오면 /var/www/html/about/ 디렉토리가 있는지 확인한다.
    • =404: 만약, 위 두가지 방법으로도 파일이나 디렉토리를 찾을 수 없다면, 404 오류를 반환한다. 

 

Nginx server 블록 수정 후 재실행

맨 처음에 도커 컨테이너 실행할 때 매핑한 포트 기억하는가? 80:8080으로 매핑했다. 즉, 외부에서 80으로 들어오면 컨테이너는 8080에 매칭시킨다는 의미가 된다. 그래서 이 default 파일의 포트를 8080으로 수정해보자.

server {
        listen 8080 default_server;
        listen [::]:8080 default_server;
        
        ...
        
}

이렇게 수정을 하자. 즉, 이제 이 default server 블록은 8080 포트를 리슨한다. 그리고 이 default 파일을 http 블록에서 include하고 있기 때문에 웹 서버가 서비스하고 있는 상태이다. 이렇게 설정 파일을 수정했으면 nginx를 재실행해야 한다.

service nginx restart

 

이 명령어를 실행해서 재실행하고 나서, 내 브라우저를 열어서 그냥 `localhost`로 접속해보자.

그럼 이렇게 nginx 기본 페이지가 보여진다! 이 파일이 바로 default가 보여주는 서비스인 것이다. 그리고 어떠한 URI도 붙이지 않았으니, root 경로의 index 파일을 찾을 것이고 그 index 파일은 다음과 같이 생겼다.

 

index.nginx-debian.html

이 HTML이 보여진 것이다. 이 HTML을 수정해보면? 그대로 적용될 것이다.

그럼 이번에는 location을 다음과 같이 수정해보자.

default

 location /blog {
        root /var/www;
}

location /flask {
        root /var/www;
}

location / {
        # First attempt to serve request as file, then
        # as directory, then fall back to displaying a 404.
        try_files $uri $uri/ =404;
}
  • 이제 외부에서 요청을 했을 때 `/blog/a.html`로 요청을 하면 저 location /blog {...} 정의대로 처리가 된다. 
    • /var/www/blog/a.html 파일을 찾을것이다.
  • 이제 외부에서 요청을 했을 때 `/flask/b.html`로 요청을 하면 저 location /flask {...} 정의대로 처리가 된다.
    • /var/www/flask/b.html 파일을 찾을 것이다.
  • 만약, `/bbb/c.html`로 호출하면? 그렇다. 아무것도 매칭이 안됐으니 location / {...} 정의대로 처리가 된다.
    • location / {...} 에는 root가 정의되지 않았으니 글로벌로 정의된 위쪽의 root /var/www/html을 사용할 것이고 찾는 경로는 /var/www/html/bbb/c.html을 찾을것이다.

 

이렇게 설정을 한 후 `/var/www` 경로에서 blog, flask 폴더를 하나씩 만들자.

# /var/www

mkdir blog
mkdir flask

 

그리고 이 각각의 폴더에 `/var/www/html` 경로에 있는 index.nginx-debian.html 파일을 복사해서 index.html 파일로 만들자.

# /var/www/html

cp index.nginx-debian.html ../blog/index.html
cp index.nginx-debian.html ../flask/index.html

 

그리고 각각의 index.html 파일의 타이틀을 blog!!!, flask!!!로 변경하고 nginx를 재실행 해보자.

 

 

그럼 우선 `localhost`로 접속하면 다음과 같이 보일것이다.

 

이번엔 `localhost/flask`로 접속하면 이렇게 보일것이다.

왜냐? `/flask/`로 요청이 들어오면 location 설정값에 의해 /var/www/flask 디렉토리를 찾고, 그 이후에 붙은 URI가 없으니 index 파일을 찾을것이므로.

 

같은 이유로 `localhost/blog`로 접속하면 이렇게 보여질 것이다.

 

정리를 하자면

이렇게 기본적인 nginx의 구동 방식, 설정 파일에 대해 알아보았다.

728x90
반응형
LIST

'Nginx' 카테고리의 다른 글

Nginx - Reverse Proxy 설정  (6) 2024.09.19

+ Recent posts