분류 기타

NGINX 핸드북2

컨텐츠 정보

  • 조회 368 (작성일 )

본문

NGINX를 역방향 프록시로 사용하는 방법 


역방향 프록시로 구성되면 NGINX는 클라이언트와 백엔드 서버 사이에 위치합니다. 클라이언트는 NGINX에 요청을 보낸 다음 NGINX가 요청을 백엔드로 전달합니다.


백엔드 서버가 요청 처리를 마치면 NGINX로 다시 보냅니다. 차례로 NGINX는 클라이언트에 응답을 반환합니다.


전체 프로세스 동안 클라이언트는 실제로 요청을 처리하는 사람에 대해 전혀 알지 못합니다. 글쓰기가 복잡해 보이지만 스스로 해보면 NGINX가 얼마나 쉽게 만드는지 알게 될 것입니다.


역방향 프록시의 매우 기본적이고 비실용적인 예를 살펴 보겠습니다.


events {

}

http {

    include /etc/nginx/mime.types;

    server {
        listen 80;
        server_name nginx.test;

        location / {
                proxy_pass "https://nginx.org/";
        }
    }
}

구성의 유효성을 검사하고 다시로드 하는 것 외에도 이 데모가 시스템에서 작동하도록 하려면 호스트 파일에 이 주소를 추가해야 합니다.


192.168.20.20   nginx.test

이제 http://nginx.test를 방문하면 URI가 변경되지 않은 상태로 원래 https://nginx.org/ 사이트에서 환영을 받게 됩니다.


nginx-org-proxy.png 

사이트를 어느 정도 탐색 할 수 있어야 합니다. http://nginx.test/en/docs/를 방문하면 응답으로 http://nginx.org/en/docs/ 페이지가 표시됩니다.


보시다시피 기본 수준에서 proxy_pass 지시문은 클라이언트의 요청을 타사 서버에 전달하고 클라이언트에 대한 응답을 리버스 프록시 합니다.


NGINX를 사용한 Node.js 


이제 기본 역방향 프록시 서버를 구성하는 방법을 알았으므로 NGINX에 의해 역방향 프록시 된 Node.js 애플리케이션을 제공 할 수 있습니다. 이 기사와 함께 제공되는 저장소 내부에 데모 애플리케이션을 추가했습니다.


Node.js에 대한 경험이 있고 PM2를 사용하여 Node.js 애플리케이션을 시작하는 방법을 알고 있다고 가정합니다. 


/srv/nginx-handbook-projects에서 저장소를 이미 복제 한 경우 node-js-demo 프로젝트는 /srv/nginx-handbook-projects/node-js-demo 디렉토리에서 사용할 수 있습니다.


이 데모가 작동하려면 서버에 Node.js를 설치해야 합니다. 여기에 있는 지침에 따라 수행 할 수 있습니다.


데모 애플리케이션은 200 상태 코드와 JSON 페이로드로 응답하는 간단한 HTTP 서버입니다. 단순히 app.js 노드를 실행하여 애플리케이션을 시작할 수 있지만 더 좋은 방법은 PM2를 사용하는 것입니다.


모르는 분들을 위해 PM2는 Node.js 애플리케이션의 프로덕션에서 널리 사용되는 데몬 프로세스 관리자입니다. 자세히 알아 보려면 이 링크가 도움이 될 수 있습니다.


sudo npm install -g pm2를 실행하여 PM2를 전역으로 설치합니다. 설치가 완료된 후 /srv/nginx-handbook-projects/node-js-demo 디렉토리에 있는 동안 다음 명령을 실행합니다.


pm2 start app.js

# [PM2] Process successfully started
# ┌────┬────────────────────┬──────────┬──────┬───────────┬──────────┬──────────┐
# │ id │ name               │ mode     │ ↺    │ status    │ cpu      │ memory   │
# ├────┼────────────────────┼──────────┼──────┼───────────┼──────────┼──────────┤
# │ 0  │ app                │ fork     │ 0    │ online    │ 0%       │ 21.2mb   │
# └────┴────────────────────┴──────────┴──────┴───────────┴──────────┴──────────┘

또는 서버의 어느 곳에서나 pm2 start /srv/nginx-handbook-projects/node-js-demo/app.js를 수행 할 수도 있습니다. pm2 stop app 명령을 실행하여 응용 프로그램을 중지 할 수 있습니다.


애플리케이션은 지금 실행 중이어야 하지만 서버 외부에서 액세스 할 수 없어야 합니다. 애플리케이션이 실행 중인지 확인하려면 서버 내부에서 http://localhost : 3000에 get 요청을 보냅니다.


curl -i localhost:3000

# HTTP/1.1 200 OK
# X-Powered-By: Express
# Content-Type: application/json; charset=utf-8
# Content-Length: 62
# ETag: W/"3e-XRN25R5fWNH2Tc8FhtUcX+RZFFo"
# Date: Sat, 24 Apr 2021 12:09:55 GMT
# Connection: keep-alive
# Keep-Alive: timeout=5

# { "status": "success", "message": "You're reading The NGINX Handbook!" }

200 응답을 받으면 서버가 정상적으로 실행되고 있는 것입니다. 이제 NGINX를 역방향 프록시로 구성하려면 구성 파일을 열고 다음과 같이 콘텐츠를 업데이트합니다.


events {

}
  
http {
    listen 80;
    server_name nginx-handbook.test

    location / {
        proxy_pass http://localhost:3000;
    }
}

여기에 새로운 설명이 없습니다. 수신 된 요청을 포트 3000에서 실행되는 Node.js 애플리케이션에 전달하는 것입니다. 이제 외부에서 서버로 요청을 보내면 다음과 같은 응답을 받아야 합니다.


curl -i http://nginx-handbook.test

# HTTP/1.1 200 OK
# Server: nginx/1.18.0 (Ubuntu)
# Date: Sat, 24 Apr 2021 14:58:01 GMT
# Content-Type: application/json
# Transfer-Encoding: chunked
# Connection: keep-alive

# { "status": "success", "message": "You're reading The NGINX Handbook!" }

이것은 이와 같은 기본 서버에서 작동하지만 응용 프로그램의 요구 사항에 따라 실제 시나리오에서 작동하도록 몇 가지 지시문을 더 추가해야 할 수 있습니다.


예를 들어 애플리케이션이 웹 소켓 연결을 처리하는 경우 다음과 같이 구성을 업데이트 해야 합니다.


events {

}
  
http {
    listen 80;
    server_name nginx-handbook.test

    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
    }
}

proxy_http_version 지시문은 서버의 HTTP 버전을 설정합니다. 기본적으로 1.0이지만 웹 소켓은 최소 1.1이어야 합니다. proxy_set_header 지시문은 백엔드 서버에서 헤더를 설정하는 데 사용됩니다. 이 지시문의 일반 구문은 다음과 같습니다.


proxy_set_header <header name> <header value>

따라서 proxy_set_header를 작성하여 업그레이드 $ http_upgrade; NGINX에 $ http_upgrade 변수의 값을 Upgrade라는 이름의 헤더로 전달하도록 지시하고 있습니다. Connection 헤더와 동일합니다.


웹 소켓 프록시에 대해 자세히 알고 싶다면 공식 NGINX 문서에 대한이 링크가 도움이 될 수 있습니다.


애플리케이션에 필요한 헤더에 따라 더 많이 설정해야 할 수 있습니다. 그러나 위에서 언급 한 구성은 Node.js 애플리케이션을 제공하는 데 매우 일반적으로 사용됩니다.


PHP With NGINX 


PHP와 NGINX는 빵과 버터처럼 함께 작동합니다. 결국 LEMP 스택의 E와 P는 NGINX와 PHP를 의미합니다.


PHP에 대한 경험이 있고 PHP 애플리케이션을 실행하는 방법을 알고 있다고 가정합니다. 


이 기사와 함께 제공되는 저장소에 데모 PHP 애플리케이션이 이미 포함되어 있습니다. /srv/nginx-handbook-projects 디렉토리에 이미 복제했다면 애플리케이션은 /srv/nginx-handbook-projects/php-demo 안에 있어야 합니다.


이 데모가 작동하려면 PHP-FPM이라는 패키지를 설치해야 합니다. 패키지를 설치하려면 다음 명령을 실행할 수 있습니다.


sudo apt install php-fpm -y

애플리케이션을 테스트하려면 /srv/nginx-handbook-projects/php-demo 디렉토리에서 다음 명령을 실행하여 PHP 서버를 시작합니다.


php -S localhost:8000

# [Sat Apr 24 16:17:36 2021] PHP 7.4.3 Development Server (http://localhost:8000) started

또는 서버의 어느 곳에서나 php -S localhost : 8000 /srv/nginx-handbook-projects/php-demo/index.php를 수행 할 수도 있습니다.


응용 프로그램은 포트 8000에서 실행되어야 하지만 서버 외부에서 액세스 할 수 없습니다. 확인하려면 서버 내부에서 http://localhost:8000에 get 요청을 보냅니다.


curl -I localhost:8000

# HTTP/1.1 200 OK
# Host: localhost:8000
# Date: Sat, 24 Apr 2021 16:22:42 GMT
# Connection: close
# X-Powered-By: PHP/7.4.3
# Content-type: application/json

# {"status":"success","message":"You're reading The NGINX Handbook!"}

200 응답을 받으면 서버가 정상적으로 실행되고 있는 것입니다. Node.js 구성과 마찬가지로 이제 요청을 localhost : 8000에 간단히 proxy_pass 할 수 있습니다.하지만 PHP를 사용하면 더 나은 방법이 있습니다.


PHP-FPM의 FPM 부분은 FastCGI Process Module을 나타냅니다. FastCGI는 바이너리 데이터 교환을 위한 HTTP와 같은 프로토콜입니다. 이 프로토콜은 HTTP보다 약간 빠르며 더 나은 보안을 제공합니다.


HTTP 대신 FastCGI를 사용하려면 다음과 같이 구성을 업데이트하십시오.


events {

}

http {

      include /etc/nginx/mime.types;

      server {

          listen 80;
          server_name nginx-handbook.test;
          root /srv/nginx-handbook-projects/php-demo;

          index index.php;

          location / {
              try_files $uri $uri/ =404;
          }

          location ~ \.php$ {
              fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
              fastcgi_param REQUEST_METHOD $request_method;
              fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
      }
   }
}

새로운 인덱스 지시문부터 시작하겠습니다. 아시다시피 NGINX는 기본적으로 제공 할 index.html 파일을 찾습니다. 그러나 데모 프로젝트에서는 index.php라고 합니다. 따라서 index index.php를 작성하여 NGINX에 index.php 파일을 대신 루트로 사용하도록 지시합니다.


이 지시문은 여러 매개 변수를 허용 할 수 있습니다. index index.php index.html과 같은 것을 작성하면 NGINX는 먼저 index.php를 찾습니다. 해당 파일을 찾지 못하면 index.html 파일을 찾습니다.


첫 번째 위치 컨텍스트 내의 try_files 지시문은 이전 섹션에서 본 것과 동일합니다. 끝에 = 404는 파일이 없는 경우 발생하는 오류를 나타냅니다.


두 번째 위치 블록은 주요 마법이 발생하는 장소입니다. 보시다시피 proxy_pass 지시문을 새로운 fastcgi_pass로 대체했습니다. 이름에서 알 수 있듯이 FastCGI 서비스에 요청을 전달하는 데 사용됩니다.


기본적으로 PHP-FPM 서비스는 호스트의 포트 9000에서 실행됩니다. 따라서 여기에서 한 것처럼 Unix 소켓을 사용하는 대신 http://localhost:9000에 직접 요청을 전달할 수 있습니다. 그러나 유닉스 소켓을 사용하는 것이 더 안전합니다.


여러 PHP-FPM 버전이 설치되어있는 경우 다음 명령을 실행하여 모든 소켓 파일 위치를 나열 할 수 있습니다.


sudo find / -name *fpm.sock

# /run/php/php7.4-fpm.sock
# /run/php/php-fpm.sock
# /etc/alternatives/php-fpm.sock
# /var/lib/dpkg/alternatives/php-fpm.sock

/run/php/php-fpm.sock 파일은 시스템에 설치된 최신 버전의 PHP-FPM을 나타냅니다. 버전 번호가 있는 것을 선호합니다. 이렇게 하면 PHP-FPM이 업데이트 되더라도 사용 중인 버전에 대해 확신 할 수 있습니다.


HTTP를 통해 요청을 전달하는 것과 달리 FPM을 통해 요청을 전달하려면 추가 정보를 전달해야 합니다.


FPM 서비스에 추가 정보를 전달하는 일반적인 방법은 fastcgi_param 지시문을 사용하는 것입니다. 최소한 프록시가 작동하려면 요청 메서드와 스크립트 이름을 백엔드 서비스에 전달해야 합니다.


fastcgi_param REQUEST_METHOD $ request_method; 요청 메소드를 백엔드 및 fastcgi_param SCRIPT_FILENAME $ realpath_root $ fastcgi_script_name에 전달합니다. 줄은 실행할 PHP 스크립트의 정확한 위치를 전달합니다.


이 상태에서 구성이 작동합니다. 테스트하려면 서버를 방문하십시오. 다음과 같은 메시지가 표시됩니다.


500-on-fastcgi.png 

글쎄, 이상 하군. 500 오류는 어떤 이유로 NGINX가 충돌했음을 의미합니다. 여기에서 오류 로그가 유용 할 수 있습니다. error.log 파일의 마지막 항목을 살펴 보겠습니다.


tail -n 1 /var/log/nginx/error.log

# 2021/04/24 17:15:17 [crit] 17691#17691: *21 connect() to unix:/var/run/php/php7.4-fpm.sock failed (13: Permission denied) while connecting to upstream, client: 192.168.20.20, server: nginx-handbook.test, request: "GET / HTTP/1.1", upstream: "fastcgi://unix:/var/run/php/php7.4-fpm.sock:", host: "nginx-handbook.test"

NGINX 프로세스가 PHP-FPM 프로세스에 대한 액세스 권한이 거부 된 것 같습니다.


권한 거부 오류가 발생하는 주된 이유 중 하나는 사용자 불일치입니다. NGINX 작업자 프로세스를 소유 한 사용자를 살펴보십시오.


tail -n 1 /var/log/nginx/error.log

# 2021/04/24 17:15:17 [crit] 17691#17691: *21 connect() to unix:/var/run/php/php7.4-fpm.sock failed (13: Permission denied) while connecting to upstream, client: 192.168.20.20, server: nginx-handbook.test, request: "GET / HTTP/1.1", upstream: "fastcgi://unix:/var/run/php/php7.4-fpm.sock:", host: "nginx-handbook.test"

NGINX 프로세스가 PHP-FPM 프로세스에 대한 액세스 권한이 거부 된 것 같습니다.


권한 거부 오류가 발생하는 주된 이유 중 하나는 사용자 불일치입니다. NGINX 작업자 프로세스를 소유 한 사용자를 살펴보십시오.


ps aux | grep nginx

# root         677  0.0  0.4   8892  4260 ?        Ss   14:31   0:00 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
# nobody     17691  0.0  0.3   9328  3452 ?        S    17:09   0:00 nginx: worker process
# vagrant    18224  0.0  0.2   8160  2552 pts/0    S+   17:19   0:00 grep --color=auto nginx

보시다시피 프로세스는 현재 아무도 소유하지 않습니다. 이제 PHP-FPM 프로세스를 검사하십시오.


# ps aux | grep php

# root       14354  0.0  1.8 195484 18924 ?        Ss   16:11   0:00 php-fpm: master process (/etc/php/7.4/fpm/php-fpm.conf)
# www-data   14355  0.0  0.6 195872  6612 ?        S    16:11   0:00 php-fpm: pool www
# www-data   14356  0.0  0.6 195872  6612 ?        S    16:11   0:00 php-fpm: pool www
# vagrant    18296  0.0  0.0   8160   664 pts/0    S+   17:20   0:00 grep --color=auto php

반면에 이 프로세스는 www-data 사용자가 소유합니다. 이것이 NGINX가 이 프로세스에 대한 액세스를 거부하는 이유입니다.


이 문제를 해결하려면 다음과 같이 구성을 업데이트하십시오.


user www-data;

events {

}

http {

      include /etc/nginx/mime.types;

      server {

          listen 80;
          server_name nginx-handbook.test;
          root /srv/nginx-handbook-projects/php-demo;

          index index.php;

          location / {
              try_files $uri $uri/ =404;
          }

          location ~ \.php$ {
              fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
              fastcgi_param REQUEST_METHOD $request_method;
              fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
      }
   }
}

사용자 지시문은 NGINX 작업자 프로세스의 소유자를 설정합니다. 이제 NGINX 프로세스를 다시 한 번 검사합니다.


# ps aux | grep nginx

# root         677  0.0  0.4   8892  4264 ?        Ss   14:31   0:00 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
# www-data   20892  0.0  0.3   9292  3504 ?        S    18:10   0:00 nginx: worker process
# vagrant    21294  0.0  0.2   8160  2568 pts/0    S+   18:18   0:00 grep --color=auto nginx

의심 할 여지없이 이 프로세스는 이제 www-data 사용자가 소유합니다. 서버에 요청을 보내 작동하는지 확인합니다.


# curl -i http://nginx-handbook.test

# HTTP/1.1 200 OK
# Server: nginx/1.18.0 (Ubuntu)
# Date: Sat, 24 Apr 2021 18:22:24 GMT
# Content-Type: application/json
# Transfer-Encoding: chunked
# Connection: keep-alive

# {"status":"success","message":"You're reading The NGINX Handbook!"}

JSON 페이로드가 포함 된 200 상태 코드를 받으면 괜찮습니다.


이 간단한 구성은 데모 애플리케이션에 적합하지만 실제 프로젝트에서는 몇 가지 추가 매개 변수를 전달해야 합니다.


이러한 이유로 NGINX에는 fastcgi_params라는 부분 구성이 포함되어 있습니다. 이 파일에는 가장 일반적인 FastCGI 매개 변수 목록이 포함되어 있습니다.


cat /etc/nginx/fastcgi_params

# fastcgi_param  QUERY_STRING       $query_string;
# fastcgi_param  REQUEST_METHOD     $request_method;
# fastcgi_param  CONTENT_TYPE       $content_type;
# fastcgi_param  CONTENT_LENGTH     $content_length;

# fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
# fastcgi_param  REQUEST_URI        $request_uri;
# fastcgi_param  DOCUMENT_URI       $document_uri;
# fastcgi_param  DOCUMENT_ROOT      $document_root;
# fastcgi_param  SERVER_PROTOCOL    $server_protocol;
# fastcgi_param  REQUEST_SCHEME     $scheme;
# fastcgi_param  HTTPS              $https if_not_empty;

# fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
# fastcgi_param  SERVER_SOFTWARE    nginx/$nginx_version;

# fastcgi_param  REMOTE_ADDR        $remote_addr;
# fastcgi_param  REMOTE_PORT        $remote_port;
# fastcgi_param  SERVER_ADDR        $server_addr;
# fastcgi_param  SERVER_PORT        $server_port;
# fastcgi_param  SERVER_NAME        $server_name;

# PHP only, required if PHP was built with --enable-force-cgi-redirect
# fastcgi_param  REDIRECT_STATUS    200;

보시다시피 이 파일에는 REQUEST_METHOD 매개 변수도 포함되어 있습니다. 수동으로 전달하는 대신이 파일을 구성에 포함 할 수 있습니다.


user www-data;

events {

}

http {

      include /etc/nginx/mime.types;

      server {

          listen 80;
          server_name nginx-handbook.test;
          root /srv/nginx-handbook-projects/php-demo;

          index index.php;

          location / {
              try_files $uri $uri/ =404;
          }

          location ~ \.php$ {
              fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
              fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
              include /etc/nginx/fastcgi_params;
      }
   }
}

서버는 동일하게 작동해야 합니다. fastcgi_params 파일 외에도 약간 다른 매개 변수 세트를 포함하는 fastcgi.conf 파일을 볼 수도 있습니다. 나는 당신이 그것의 행동과 약간의 불일치로 인해 그것을 피하는 것이 좋습니다.


NGINX를 로드 밸런서로 사용하는 방법 


NGINX의 리버스 프록시 설계 덕분에 로드 밸런서로 쉽게 구성 할 수 있습니다.


이 기사와 함께 제공되는 저장소에 이미 데모를 추가했습니다. /srv/nginx-handbook-projects/디렉토리에 이미 저장소를 복제 한 경우 데모는 /srv /nginx-handbook-projects/load-balancer-demo/디렉토리에 있어야 합니다.


실제 시나리오에서는 여러 서버에 분산 된 대규모 프로젝트에 부하 분산이 필요할 수 있습니다. 그러나 이 간단한 데모를 위해 서버 번호와 200 상태 코드로 응답하는 매우 간단한 Node.js 서버 3 개를 만들었습니다.


이 데모가 작동하려면 서버에 Node.js가 설치되어 있어야 합니다. 이 링크에서 설치하는 데 도움이 되는 지침을 찾을 수 있습니다.


이 외에도 이 데모에서 제공하는 Node.js 서버를 데몬화 하려면 PM2가 필요합니다.


아직 설치하지 않은 경우 sudo npm install -g pm2를 실행하여 PM2를 설치합니다. 설치가 완료되면 다음 명령을 실행하여 세 개의 Node.js 서버를 시작합니다.


pm2 start /srv/nginx-handbook-projects/load-balancer-demo/server-1.js

pm2 start /srv/nginx-handbook-projects/load-balancer-demo/server-2.js

pm2 start /srv/nginx-handbook-projects/load-balancer-demo/server-3.js

pm2 list

# ┌────┬────────────────────┬──────────┬──────┬───────────┬──────────┬──────────┐
# │ id │ name               │ mode     │ ↺    │ status    │ cpu      │ memory   │
# ├────┼────────────────────┼──────────┼──────┼───────────┼──────────┼──────────┤
# │ 0  │ server-1           │ fork     │ 0    │ online    │ 0%       │ 37.4mb   │
# │ 1  │ server-2           │ fork     │ 0    │ online    │ 0%       │ 37.2mb   │
# │ 2  │ server-3           │ fork     │ 0    │ online    │ 0%       │ 37.1mb   │
# └────┴────────────────────┴──────────┴──────┴───────────┴──────────┴──────────┘

3 개의 Node.js 서버가 각각 localhost : 3001, localhost : 3002, localhost : 3003에서 실행되어야 합니다.


이제 다음과 같이 구성을 업데이트하십시오.


events {

}

http {

    upstream backend_servers {
        server localhost:3001;
        server localhost:3002;
        server localhost:3003;
    }

    server {

        listen 80;
        server_name nginx-handbook.test;

        location / {
            proxy_pass http://backend_servers;
        }
    }
}

서버 컨텍스트 내부의 구성은 이미 본 것과 동일합니다. 그러나 업스트림 컨텍스트는 새로운 것입니다. NGINX의 업스트림은 단일 백엔드로 취급 할 수 있는 서버 모음입니다.


따라서 PM2를 사용하기 시작한 세 대의 서버는 단일 업스트림에 배치 할 수 있으며 NGINX가 이들 사이의 부하를 분산하도록 할 수 있습니다.


구성을 테스트하려면 서버에 여러 요청을 보내야 합니다. bash에서 while 루프를 사용하여 프로세스를 자동화 할 수 있습니다.


while sleep 0.5; do curl http://nginx-handbook.test; done

# response from server - 2.
# response from server - 3.
# response from server - 1.
# response from server - 2.
# response from server - 3.
# response from server - 1.
# response from server - 2.
# response from server - 3.
# response from server - 1.
# response from server - 2.

키보드에서 Ctrl + C를 눌러 루프를 취소 할 수 있습니다. 서버의 응답에서 알 수 있듯이 NGINX는 서버의 부하를 자동으로 분산합니다.


물론 프로젝트 규모에 따라 부하 분산은 이보다 훨씬 더 복잡 할 수 있습니다. 그러나 이 기사의 목표는 시작하는 것이며 이제 NGINX를 사용한 로드 밸런싱에 대한 기본적인 이해가 있다고 생각합니다. pm2 stop server-1 server-2 server-3 명령을 실행하여 실행 중인 세 서버를 중지 할 수 있습니다 (여기서는 좋은 생각입니다).


최대 성능을 위해 NGINX를 최적화 하는 방법 


이 기사 섹션에서는 서버에서 최대 성능을 얻는 여러 방법에 대해 알아 봅니다.


이러한 방법 중 일부는 응용 프로그램에 따라 다르므로 응용 프로그램 요구 사항을 고려하여 조정이 필요할 수 있습니다. 그러나 그들 중 일부는 일반적인 최적화 기술이 될 것입니다.


이전 섹션과 마찬가지로 이 섹션에서는 구성 변경이 자주 발생하지 않으므로 매번 구성 파일을 확인하고 다시로드 하는 것을 잊지 마십시오.


작업자 프로세스 및 작업자 연결을 구성하는 방법 


이전 섹션에서 이미 언급했듯이 NGINX는 각각 수천 개의 요청을 처리 할 수 있는 여러 작업자 프로세스를 생성 할 수 있습니다.


sudo systemctl status nginx

# ● nginx.service - A high performance web server and a reverse proxy server
#      Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
#      Active: active (running) since Sun 2021-04-25 08:33:11 UTC; 5h 45min ago
#        Docs: man:nginx(8)
#    Main PID: 3904 (nginx)
#       Tasks: 2 (limit: 1136)
#      Memory: 3.2M
#      CGroup: /system.slice/nginx.service
#              ├─ 3904 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
#              └─16443 nginx: worker process

보시다시피, 현재 시스템에는 NGINX 작업자 프로세스가 하나만 있습니다. 그러나 이 번호는 구성 파일을 약간 변경하여 변경할 수 있습니다.


worker_processes 2;

events {

}

http {

    server {

        listen 80;
        server_name nginx-handbook.test;

        return 200 "worker processes and worker connections configuration!\n";
    }
}

기본 컨텍스트에 작성된 worker_process 지시문은 생성 할 작업자 프로세스 수를 설정합니다. 이제 NGINX 서비스를 다시 확인하면 두 개의 작업자 프로세스가 표시됩니다.


sudo systemctl status nginx

# ● nginx.service - A high performance web server and a reverse proxy server
#      Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
#      Active: active (running) since Sun 2021-04-25 08:33:11 UTC; 5h 54min ago
#        Docs: man:nginx(8)
#     Process: 22610 ExecReload=/usr/sbin/nginx -g daemon on; master_process on; -s reload (code=exited, status=0/SUCCESS)
#    Main PID: 3904 (nginx)
#       Tasks: 3 (limit: 1136)
#      Memory: 3.7M
#      CGroup: /system.slice/nginx.service
#              ├─ 3904 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
#              ├─22611 nginx: worker process
#              └─22612 nginx: worker process

작업자 프로세스 수를 설정하는 것은 쉽지만 최적의 작업자 프로세스 수를 결정하려면 약간 더 많은 작업이 필요합니다.


작업자 프로세스는 본질적으로 비동기 적입니다. 즉, 하드웨어가 가능한 한 빨리 들어오는 요청을 처리합니다.


이제 서버가 단일 코어 프로세서에서 실행된다고 생각해보십시오. 작업자 프로세스 수를 1로 설정하면 해당 단일 프로세스가 CPU 용량의 100 %를 사용합니다. 그러나 2로 설정하면 두 프로세스가 각각 CPU의 50 %를 활용할 수 있습니다. 따라서 작업자 프로세스 수를 늘린다 고해서 성능이 향상되는 것은 아닙니다.


최적의 작업자 프로세스 수를 결정하는 경험적 규칙은 작업자 프로세스 수 = CPU 코어 수입니다.


듀얼 코어 CPU가 있는 서버에서 실행 중인 경우 작업자 프로세스 수를 2로 설정해야 합니다. 쿼드 코어에서는 4로 설정해야 합니다.


Linux에서 서버의 CPU 수를 결정하는 것은 매우 쉽습니다.


nproc

# 1

저는 단일 CPU 가상 머신에 있으므로 nproc은 CPU가 하나임을 감지합니다. 이제 CPU 수를 알았으니 이제 남은 일은 구성에 번호를 설정하는 것뿐입니다.


모든 것이 훌륭하지만 서버를 업스케일하고 CPU 번호가 변경 될 때마다 서버 구성을 수동으로 업데이트해야 합니다.


NGINX는이 문제를 처리하는 더 나은 방법을 제공합니다. 작업자 프로세스 수를 자동으로 설정하기 만하면 NGINX가 CPU 수에 따라 자동으로 프로세스 수를 설정합니다.


worker_processes auto;

events {

}

http {

    server {

        listen 80;
        server_name nginx-handbook.test;

        return 200 "worker processes and worker connections configuration!\n";
    }
}

NGINX 프로세스를 다시 한 번 검사합니다.


sudo systemctl status nginx

# ● nginx.service - A high performance web server and a reverse proxy server
#      Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
#      Active: active (running) since Sun 2021-04-25 08:33:11 UTC; 6h ago
#        Docs: man:nginx(8)
#     Process: 22610 ExecReload=/usr/sbin/nginx -g daemon on; master_process on; -s reload (code=exited, status=0/SUCCESS)
#    Main PID: 3904 (nginx)
#       Tasks: 2 (limit: 1136)
#      Memory: 3.2M
#      CGroup: /system.slice/nginx.service
#              ├─ 3904 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
#              └─23659 nginx: worker process

작업자 프로세스의 수는 이 서버에 최적이기 때문에 다시 하나로 돌아갑니다.


작업자 프로세스 외에도 작업자 연결도 있는데, 이는 단일 작업자 프로세스가 처리 할 수 있는 최대 연결 수를 나타냅니다.


작업자 프로세스 수와 마찬가지로 이 수는 CPU 코어 수 및 운영 체제에서 코어 당 열 수 있는 파일 수와도 관련이 있습니다.


이 번호를 찾는 것은 Linux에서 매우 쉽습니다.


ulimit -n

# 1024

이제 번호를 얻었으므로 남은 것은 구성에서 설정하는 것입니다.


worker_processes auto;

events {
    worker_connections 1024;
}

http {

    server {

        listen 80;
        server_name nginx-handbook.test;

        return 200 "worker processes and worker connections configuration!\n";
    }
}

worker_connections 지시문은 구성에서 작업자 연결 수를 설정합니다. 이벤트 컨텍스트로 작업하는 것도 이번이 처음입니다.


이전 섹션에서 이 컨텍스트는 일반 수준에서 NGINX가 사용하는 값을 설정하는 데 사용된다는 것을 언급했습니다. 작업자 연결 구성이 그러한 예 중 하나입니다.


정적 콘텐츠를 캐시하는 방법 


서버를 최적화하는 두 번째 기술은 정적 콘텐츠를 캐싱하는 것입니다. 제공하는 애플리케이션에 관계없이 스타일 시트, 이미지 등과 같은 일정한 양의 정적 콘텐츠가 항상 제공됩니다.


이 콘텐츠는 자주 변경되지 않을 가능성이 있으므로 일정 시간 동안 캐시 하는 것이 좋습니다. NGINX는 이 작업도 쉽게 만듭니다.


worker_processes auto;

events {
    worker_connections 1024;
}

http {

    include /env/nginx/mime.types;

    server {

        listen 80;
        server_name nginx-handbook.test;

        root /srv/nginx-handbook-demo/static-demo;
        
        location ~* \.(css|js|jpg)$ {
            access_log off;
            
            add_header Cache-Control public;
            add_header Pragma public;
            add_header Vary Accept-Encoding;
            expires 1M;
        }
    }
}

~ *. (css | js | jpg) $ 위치를 작성하면 NGINX가 .css, .js 및 .jpg로 끝나는 파일을 요청하는 요청을 일치 시키도록 지시합니다.


내 응용 프로그램에서는 사용자가 다른 형식을 제출하더라도 일반적으로 이미지를 WebP 형식으로 저장합니다. 이렇게 하면 정적 캐시를 구성하는 것이 훨씬 쉬워집니다.


add_header 지시문을 사용하여 클라이언트에 대한 응답에 헤더를 포함 할 수 있습니다. 이전에는 백엔드 서버에 대한 지속적인 요청에서 헤더를 설정하는 데 사용되는 proxy_set_header 지시문을 보았습니다. 반면에 add_header 지시문은 응답에 주어진 헤더 만 추가합니다.


Cache-Control 헤더를 public으로 설정하면 이 콘텐츠를 어떤 방식 으로든 캐시 할 수 있음을 클라이언트에 알리는 것입니다. Pragma 헤더는 Cache-Control 헤더의 이전 버전 일 뿐이며 거의 동일한 작업을 수행합니다.


다음 헤더 인 Vary는 이 캐시 된 콘텐츠가 다를 수 있음을 클라이언트에 알리는 역할을 합니다.


Accept-Encoding의 값은 클라이언트가 허용하는 콘텐츠 인코딩에 따라 콘텐츠가 달라질 수 있음을 의미합니다. 이것은 다음 섹션에서 더 자세히 설명 될 것입니다.


마지막으로 expires 지시문을 사용하면 Expires 헤더를 편리하게 설정할 수 있습니다. expires 지시문은 이 캐시가 유효한 기간이 걸립니다. 1M으로 설정하면 NGINX에 한 달 동안 콘텐츠를 캐시하도록 지시하는 것입니다. 10m 또는 10 분, 24 시간 또는 24 시간 등으로 설정할 수도 있습니다.


이제 구성을 테스트하기 위해 서버에서 the-nginx-handbook.jpg 파일에 대한 요청을 보냈습니다.


curl -I http://nginx-handbook.test/the-nginx-handbook.jpg

# HTTP/1.1 200 OK
# Server: nginx/1.18.0 (Ubuntu)
# Date: Sun, 25 Apr 2021 15:58:22 GMT
# Content-Type: image/jpeg
# Content-Length: 19209
# Last-Modified: Sun, 25 Apr 2021 08:35:33 GMT
# Connection: keep-alive
# ETag: "608529d5-4b09"
# Expires: Tue, 25 May 2021 15:58:22 GMT
# Cache-Control: max-age=2592000
# Cache-Control: public
# Pragma: public
# Vary: Accept-Encoding
# Accept-Ranges: bytes

보시다시피 헤더가 응답에 추가되었으며 모든 최신 브라우저가 이를 해석 할 수 있어야 합니다.


응답 압축 방법 


오늘 보여 드릴 최종 최적화 기술은 매우 간단합니다. 응답을 압축하여 크기를 줄입니다.


worker_processes auto;

events {
    worker_connections 1024;
}

http {
    include /env/nginx/mime.types;

    gzip on;
    gzip_comp_level 3;

    gzip_types text/css text/javascript;

    server {

        listen 80;
        server_name nginx-handbook.test;

        root /srv/nginx-handbook-demo/static-demo;
        
        location ~* \.(css|js|jpg)$ {
            access_log off;
            
            add_header Cache-Control public;
            add_header Pragma public;
            add_header Vary Accept-Encoding;
            expires 1M;
        }
    }
}

아직 익숙하지 않은 경우 GZIP은 응용 프로그램에서 파일 압축 및 압축 해제를 위해 사용하는 널리 사용되는 파일 형식입니다. NGINX는 이 형식을 활용하여 gzip 지시문을 사용하여 응답을 압축 할 수 있습니다.


http 컨텍스트에서 gzip을 작성하여 NGINX에 응답을 압축하도록 지시합니다. gzip_comp_level 지시문은 압축 수준을 설정합니다. 매우 높은 숫자로 설정할 수 있지만 더 나은 압축을 보장하지는 않습니다. 1-4 사이의 숫자를 설정하면 효율적인 결과를 얻을 수 있습니다. 예를 들어 3으로 설정하는 것이 좋습니다.


기본적으로 NGINX는 HTML 응답을 압축합니다. 다른 파일 형식을 압축하려면 매개 변수로 gzip_types 지시문에 전달해야 합니다. gzip_types text/css text/javascript를 작성합니다. MIME 유형의 text/css 및 text/javascript를 사용하여 모든 파일을 압축하도록 NGINX에 지시하는 것입니다.


NGINX에서 압축을 구성하는 것만으로는 충분하지 않습니다. 클라이언트는 압축되지 않은 응답 대신 압축 된 응답을 요청해야 합니다. add_header Vary Accept-Encoding을 기억하시기 바랍니다. 캐싱에 대한 이전 섹션의 줄. 이 헤더는 클라이언트가 수락하는 내용에 따라 응답이 달라질 수 있음을 클라이언트에게 알려줍니다.


예를 들어, 서버에서 mini.min.css 파일의 압축되지 않은 버전을 요청하려면 다음과 같이 할 수 있습니다.


curl -I http://nginx-handbook.test/mini.min.css

# HTTP/1.1 200 OK
# Server: nginx/1.18.0 (Ubuntu)
# Date: Sun, 25 Apr 2021 16:30:32 GMT
# Content-Type: text/css
# Content-Length: 46887
# Last-Modified: Sun, 25 Apr 2021 08:35:33 GMT
# Connection: keep-alive
# ETag: "608529d5-b727"
# Expires: Tue, 25 May 2021 16:30:32 GMT
# Cache-Control: max-age=2592000
# Cache-Control: public
# Pragma: public
# Vary: Accept-Encoding
# Accept-Ranges: bytes

보시다시피 압축에 관한 것은 없습니다. 이제 파일의 압축 버전을 요청하려면 추가 헤더를 보내야 합니다.


curl -I -H "Accept-Encoding: gzip" http://nginx-handbook.test/mini.min.css

# HTTP/1.1 200 OK
# Server: nginx/1.18.0 (Ubuntu)
# Date: Sun, 25 Apr 2021 16:31:38 GMT
# Content-Type: text/css
# Last-Modified: Sun, 25 Apr 2021 08:35:33 GMT
# Connection: keep-alive
# ETag: W/"608529d5-b727"
# Expires: Tue, 25 May 2021 16:31:38 GMT
# Cache-Control: max-age=2592000
# Cache-Control: public
# Pragma: public
# Vary: Accept-Encoding
# Content-Encoding: gzip

응답 헤더에서 볼 수 있듯이 Content-Encoding은 이제 gzip으로 설정되어 파일의 압축 된 버전입니다.


이제 파일 크기의 차이를 비교하려면 다음과 같이 할 수 있습니다.


cd ~
mkdir compression-test && cd compression-test

curl http://nginx-handbook.test/mini.min.css > uncompressed.css

curl -H "Accept-Encoding: gzip" http://nginx-handbook.test/mini.min.css > compressed.css

ls -lh

# -rw-rw-r-- 1 vagrant vagrant 9.1K Apr 25 16:35 compressed.css
# -rw-rw-r-- 1 vagrant vagrant  46K Apr 25 16:35 uncompressed.css

압축되지 않은 파일 버전은 46K이고 압축 된 버전은 9.1K로 거의 6 배 더 작습니다. 스타일 시트가 훨씬 더 클 수 있는 실제 사이트에서 압축을 사용하면 응답을 더 작고 빠르게 만들 수 있습니다.


기본 구성 파일을 이해하는 방법 


이전 섹션에서 이름을 바꾼 원본 nginx.conf 파일을 기억하시기 바랍니다. 데비안 위키에 따르면,이 파일은 그들이 하는 일을 정확히 알지 못한다면 서버 관리자가 아닌 NGINX 관리자가 변경해야 합니다.


그러나 전체 기사를 통해 이 파일에서 서버를 구성하는 방법을 배웠습니다. 그러나 이 섹션에서는 nginx.conf 파일을 변경하지 않고 서버를 구성하는 방법에 대해 설명합니다.


먼저 수정 된 nginx.conf 파일을 삭제하거나 이름을 바꾸고 원래 파일을 다시 가져 오십시오.


sudo rm /etc/nginx/nginx.conf

sudo mv /etc/nginx/nginx.conf.backup /etc/nginx/nginx.conf

sudo nginx -s reload

이제 NGINX는 원래 상태로 돌아갑니다. sudo cat /etc/nginx/nginx.conf 파일을 실행하여 이 파일의 내용을 다시 한 번 살펴 보겠습니다.


user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
	worker_connections 768;
	# multi_accept on;
}

http {

	##
	# Basic Settings
	##

	sendfile on;
	tcp_nopush on;
	tcp_nodelay on;
	keepalive_timeout 65;
	types_hash_max_size 2048;
	# server_tokens off;

	# server_names_hash_bucket_size 64;
	# server_name_in_redirect off;

	include /etc/nginx/mime.types;
	default_type application/octet-stream;

	##
	# SSL Settings
	##

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

	##
	# Logging Settings
	##

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

	##
	# Gzip Settings
	##

	gzip on;

	# gzip_vary on;
	# gzip_proxied any;
	# gzip_comp_level 6;
	# gzip_buffers 16 8k;
	# gzip_http_version 1.1;
	# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

	##
	# Virtual Host Configs
	##

	include /etc/nginx/conf.d/*.conf;
	include /etc/nginx/sites-enabled/*;
}


#mail {
#	# See sample authentication script at:
#	# http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript
# 
#	# auth_http localhost/auth.php;
#	# pop3_capabilities "TOP" "USER";
#	# imap_capabilities "IMAP4rev1" "UIDPLUS";
# 
#	server {
#		listen     localhost:110;
#		protocol   pop3;
#		proxy      on;
#	}
# 
#	server {
#		listen     localhost:143;
#		protocol   imap;
#		proxy      on;
#	}
#}

이제 별다른 문제없이 이 파일을 이해할 수 있습니다. 기본 컨텍스트 사용자 www-data;에서 worker_processes 자동; 선을 쉽게 알아볼 수 있어야 합니다.


라인 pid /run/nginx.pid; NGINX 프로세스에 대한 프로세스 ID를 설정하고 /etc/nginx/modules-enabled/*.conf를 포함합니다. / etc / nginx / modules-enabled / 디렉토리에 있는 모든 구성 파일을 포함합니다.


이 디렉토리는 NGINX 동적 모듈을 위한 것입니다. 이 기사에서는 동적 모듈을 다루지 않았으므로 건너 뛰겠습니다.


이제 http 컨텍스트 내에서 기본 설정 아래에 적용된 몇 가지 일반적인 최적화 기술을 볼 수 있습니다. 이러한 기술이 수행하는 작업은 다음과 같습니다.


  • sendfile on; 정적 파일에 대한 버퍼링을 비활성화 합니다.
  • tcp_nopush on; 하나의 패킷으로 응답 헤더를 보낼 수 있습니다.
  • tcp_nodelay on; Nagle의 알고리즘을 비활성화하여 정적 파일 전달 속도를 높입니다.

keepalive_timeout 지시문은 연결을 열린 상태로 유지하는 기간을 나타내고 types_hash_maxsize 지시문은 유형 해시 맵의 크기를 설정합니다. 기본적으로 mime.types 파일도 포함됩니다.


SSL 설정은 이 기사에서 다루지 않았기 때문에 생략하겠습니다. 로깅 및 gzip 설정에 대해서는 이미 논의했습니다. 주석이 달린 gzip과 관련된 일부 지시문을 볼 수 있습니다. 수행 중인 작업을 이해하는 한 이러한 설정을 사용자 지정할 수 있습니다.


메일 컨텍스트를 사용하여 NGINX를 메일 서버로 구성합니다. 지금까지 웹 서버로서 NGINX에 대해서만 이야기 했으므로 이 부분도 건너 뛰겠습니다.


이제 가상 호스트 설정 아래에 다음과 같은 두 줄이 표시됩니다.


##
# Virtual Host Configs
##

include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;

이 두 줄은 NGINX가 /etc/nginx/conf.d/ 및 / etc / nginx / sites-enabled / 디렉토리에 있는 모든 구성 파일을 포함하도록 지시합니다.


이 두 줄을 본 후에 사람들은 종종 이 두 디렉터리를 구성 파일을 저장하기에 이상적인 장소로 삼지 만, 그것은 옳지 않습니다.


가상 호스트에 대한 구성 파일을 저장하기 위한 다른 디렉토리 /etc/nginx/sites-available/이 있습니다. /etc/nginx/sites-enabled/ 디렉토리는 /etc/nginx/sites-available/ 디렉토리에서 파일에 대한 심볼릭 링크를 저장하기 위한 것입니다.


실제로 예제 구성이 있습니다.


ln -lh /etc/nginx/sites-enabled/

# lrwxrwxrwx 1 root root 34 Apr 25 08:33 default -> /etc/nginx/sites-available/default

보시다시피 디렉토리에는 /etc/nginx/sites-available/default 파일에 대한 심볼릭 링크가 있습니다.


아이디어는 /etc/nginx/sites-available/ 디렉토리에 여러 가상 호스트를 작성하고 이들 중 일부를 /etc/nginx/sites-enabled/ 디렉토리에 심볼릭 링크하여 활성화하는 것입니다.


이 개념을 설명하기 위해 간단한 정적 서버를 구성 해 보겠습니다. 먼저 기본 가상 호스트 심볼릭 링크를 삭제하고 프로세스에서 이 구성을 비활성화 합니다.


sudo rm /etc/nginx/sites-enabled/default

ls -lh /etc/nginx/sites-enabled/

# lrwxrwxrwx 1 root root 41 Apr 25 18:01 nginx-handbook -> /etc/nginx/sites-available/nginx-handbook

sudo touch /etc/nginx/sites-available/nginx-handbook을 실행하여 새 파일을 만들고 거기에 다음 내용을 넣으십시오.


server {
    listen 80;
    server_name nginx-handbook.test;

    root /srv/nginx-handbook-projects/static-demo;
}

/etc/nginx/sites-available/ 디렉토리 내의 파일은 기본 http 컨텍스트 내에 포함되도록 되어 있으므로 서버 블록 만 포함해야 합니다.


이제 다음 명령을 실행하여 /etc/nginx/sites-enabled/ 디렉토리에 이 파일에 대한 심볼릭 링크를 만듭니다.


sudo ln -s /etc/nginx/sites-available/nginx-handbook /etc/nginx/sites-enabled/nginx-handbook

ls -lh /etc/nginx/sites-enabled/

# lrwxrwxrwx 1 root root 34 Apr 25 08:33 default -> /etc/nginx/sites-available/default
# lrwxrwxrwx 1 root root 41 Apr 25 18:01 nginx-handbook -> /etc/nginx/sites-available/nginx-handbook

구성 파일의 유효성을 검사하고 다시로드 하기 전에 로그 파일을 다시 열어야 합니다. 그렇지 않으면 권한 거부 오류가 발생할 수 있습니다. 이것은 이전 nginx.conf 파일을 교체 한 결과로 이번에는 프로세스 ID가 다르기 때문에 발생합니다.


sudo rm /var/log/nginx/*.log

sudo touch /var/log/nginx/access.log /var/log/nginx/error.log

sudo nginx -s reopen

마지막으로 구성 파일을 확인하고 다시로드 합니다.


sudo nginx -t

# nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
# nginx: configuration file /etc/nginx/nginx.conf test is successful

sudo nginx -s reload

서버를 방문하면 좋은 오래된 The NGINX Handbook 페이지가 표시됩니다.


image-100.png 


서버를 올바르게 구성했지만 여전히 이전 NGINX 시작 페이지가 표시되는 경우 강제 새로 고침을 수행하십시오. 브라우저는 종종 오래된 자산을 유지하고 약간의 정리가 필요합니다.


고급 NGINX 개념에 대한 시리즈 


서버 구성은 방대한 주제이며 이 기사의 목표는 NGINX의 기본 사항을 교육하는 것이었습니다. 그러나 내가 빠뜨린 중요하고 고급 주제가 있습니다.


이것은 HTTP2 프로토콜 구성, FastCGI 마이크로 캐싱, 속도 제한, SSL 인증서 서명, 동적 모듈 등과 같은 주제를 설명하는 여러 기사를 블로그에 작성할 계획이기 때문입니다.


이렇게 하면 시리즈는 참조하기 쉽고 기본 사항을 제대로 이해 한 사람들을 대상으로 하는 기사 모음이 됩니다.


따라서 https://farhan.info/를 주시하십시오. 2 ~ 3 주 이내에 첫 번째 기사가 나오기를 바라고 있습니다.


결론 


이 기사를 읽어 주신 시간에 대해 진심으로 감사드립니다. 즐거운 시간을 보내고 NGINX의 모든 필수 사항을 배웠기를 바랍니다.


https://www.freecodecamp.org/news/the-nginx-handbook/