분류 기타

NGINX 핸드북

컨텐츠 정보

  • 조회 462 (작성일 )

본문

Igor Sysoev라는 젊은 러시아 개발자는 구형 웹 서버가 10,000 개 이상의 동시 요청을 처리 할 수 ​​없다는 점에 실망했습니다. 이것은 C10k 문제라고 하는 문제입니다. 이에 대한 대답으로 그는 2002 년에 새로운 웹 서버 작업을 시작했습니다.


NGINX2 절 BSD 라이센스 조건에 따라 2004 년에 처음 공개되었습니다. 2021 년 3 월 웹 서버 설문 조사에 따르면 NGINX는 총 4 억 1,960 만 개의 사이트로 시장의 35.3 %를 차지하고 있습니다.


DigitalOceanNGINXConfig와 같은 도구와 인터넷에 미리 작성된 풍부한 구성 파일 덕분에 사람들은 NGINX를 구성 할 때 이해하려고 하는 대신 많은 복사-붙여 넣기 작업을 수행하는 경향이 있습니다.


코드를 복사하는 것이 나쁘다는 말은 아니지만 이해하지 못한 채 코드를 복사하는 것은 큰 "아니오"입니다.


또한 NGINX는 제공할 응용 프로그램의 요구 사항과 호스트에서 사용 가능한 리소스에 따라 정확하게 구성해야 하는 소프트웨어 유형입니다.


그렇기 때문에 맹목적으로 복사하는 대신 복사하는 내용을 이해하고 미세 조정해야 합니다. 이것이 이 핸드북이 나오는 이유입니다.


전체 책을 읽은 후에는 다음을 수행 할 수 있습니다.


  • 널리 사용되는 도구에서 생성 된 구성 파일과 다양한 문서에 있는 구성 파일을 이해합니다.
  • NGINX를 웹 서버, 역방향 프록시 서버 및 로드 밸런서로 처음부터 구성합니다.
  • NGINX를 최적화하여 서버 성능을 극대화하십시오.

전제 조건 


  • Linux 터미널과 ls, cat, ps, grep, find, nproc, ulimit 및 nano와 같은 일반적인 Unix 프로그램에 대한 지식.
  • 가상 머신 또는 $ 5 가상 사설 서버를 실행할 수 있을 만큼 강력한 컴퓨터.
  • 웹 애플리케이션 및 JavaScript 또는 PHP와 같은 프로그래밍 언어에 대한 이해.


프로젝트 코드 


다음 저장소에서 예제 프로젝트의 코드를 찾을 수 있습니다.


https://github.com/fhsinchy/nginx-handbook-projects 


마스터 브랜치는 이 책에서 사용 된 모든 코드를 보유합니다.


NGINX 소개 


NGINX는 최신 웹의 증가하는 요구를 지원하기 위해 개발 된 고성능 웹 서버입니다. 높은 성능, 높은 동시성 및 낮은 리소스 사용에 중점을 둡니다. 대부분 웹 서버로 알려져 있지만 핵심적인 NGINX는 역방향 프록시 서버입니다.


그러나 NGINX가 시장에 나와있는 유일한 웹 서버는 아닙니다. 가장 큰 경쟁자 중 하나는 1995 년에 처음 출시 된 Apache HTTP Server (httpd)입니다. Apache HTTP Server가 더 유연하다는 사실에도 불구하고 서버 관리자는 두 가지 주요 이유로 NGINX를 선호하는 경우가 많습니다.


  • 더 많은 수의 동시 요청을 처리 할 수 ​​있습니다.
  • 적은 리소스 사용으로 더 빠른 정적 콘텐츠 전달을 제공합니다.

전체 Apache 대 NGINX 논쟁에 대해서는 더 이상 다루지 않겠습니다. 그러나 차이점에 대해 자세히 알고 싶다면 Justin Ellingwood의 훌륭한 기사가 도움이 될 수 있습니다.


실제로 NGINX의 요청 처리 기술을 설명하기 위해 Justin의 기사에서 두 단락을 인용하고 싶습니다.


Nginx는 대규모 사이트에 직면하게 될 동시성 문제에 대해 더 많이 인식하면서 Apache 이후에 등장했습니다. 이 지식을 활용하여 Nginx는 처음부터 비동기식 비 차단 이벤트 기반 연결 처리 알고리즘을 사용하도록 설계되었습니다. 


Nginx는 각각 수천 개의 연결을 처리 할 수 있는 작업자 프로세스를 생성합니다. 작업자 프로세스는 이벤트를 지속적으로 확인하고 처리하는 빠른 루핑 메커니즘을 구현하여 이를 수행합니다. 연결에서 실제 작업을 분리하면 새 이벤트가 트리거 된 경우에만 각 작업자가 연결에 관심을 가질 수 있습니다. 


이해하기가 조금 복잡해 보이더라도 걱정하지 마십시오. 내부 작업에 대한 기본적인 이해만으로도 충분합니다.


wQszK2rvq-1.png 


NGINX는 동적 프로그래밍 언어 프로세서를 포함하지 않기 때문에 리소스를 비교적 가볍게 유지하면서 정적 콘텐츠 전달 속도가 더 빠릅니다. 정적 콘텐츠에 대한 요청이 오면 NGINX는 추가 프로세스를 실행하지 않고 파일로 간단히 응답합니다.


그렇다고 NGINX가 동적 프로그래밍 언어 프로세서가 필요한 요청을 처리 할 수 ​​없다는 의미는 아닙니다. 이러한 경우 NGINX는 단순히 작업을 PHP-FPM, Node.js 또는 Python과 같은 별도의 프로세스에 위임합니다. 그런 다음 해당 프로세스가 작업을 마치면 NGINX는 응답을 다시 클라이언트로 프록시합니다.


_nT7rcdjG.png 


NGINX는 다양한 스크립팅 언어에서 영감을 얻은 구성 파일 구문 덕분에 구성하기가 훨씬 쉬워 져서 간단하고 유지 관리가 쉬운 구성 파일이 생성됩니다.


NGINX 설치 방법 


Linux 기반 시스템에 NGINX를 설치하는 것은 매우 간단합니다. Ubuntu를 플레이 그라운드로 실행하는 가상 사설 서버를 사용하거나 Vagrant를 사용하여 로컬 시스템에 가상 머신을 프로비저닝 할 수 있습니다.


대부분의 경우 로컬 가상 머신을 프로비저닝하는 것으로 충분하며 이것이 이 기사에서 사용할 방법입니다.


로컬 가상 머신을 프로비저닝하는 방법 


모르는 사람들을 위해 VagrantHashicorp의 오픈 소스 도구로 간단한 구성 파일을 사용하여 가상 머신을 프로비저닝 할 수 있습니다.


이 접근 방식이 작동하려면 VirtualBoxVagrant가 필요하므로 먼저 설치하십시오. 주제에 대해 약간의 워밍업이 필요한 경우 이 튜토리얼이 도움이 될 수 있습니다.


시스템 어딘가에 적절한 이름으로 작업 디렉토리를 만듭니다. 제 것은 ~/vagrant/nginx-handbook 디렉토리입니다.


작업 디렉토리 안에 Vagrantfile이라는 파일을 만들고 거기에 다음 내용을 넣으십시오.


Vagrant.configure("2") do |config|

    config.vm.hostname = "nginx-handbook-box"
  
    config.vm.box = "ubuntu/focal64"
  
    config.vm.define "nginx-handbook-box"
  
    config.vm.network "private_network", ip: "192.168.20.20"
  
    config.vm.provider "virtualbox" do |vb|
      vb.cpus = 1
      vb.memory = "1024"
      vb.name = "nginx-handbook"
    end
  
  end

이 Vagrantfile은 앞서 언급 한 구성 파일입니다. 여기에는 가상 머신 이름, CPU 수, RAM 크기, IP 주소 등과 같은 정보가 포함됩니다.


이 구성을 사용하여 가상 머신을 시작하려면 작업 디렉토리에서 터미널을 열고 다음 명령을 실행합니다.


vagrant up

# Bringing machine 'nginx-handbook-box' up with 'virtualbox' provider...
# ==> nginx-handbook-box: Importing base box 'ubuntu/focal64'...
# ==> nginx-handbook-box: Matching MAC address for NAT networking...
# ==> nginx-handbook-box: Checking if box 'ubuntu/focal64' version '20210415.0.0' is up to date...
# ==> nginx-handbook-box: Setting the name of the VM: nginx-handbook
# ==> nginx-handbook-box: Clearing any previously set network interfaces...
# ==> nginx-handbook-box: Preparing network interfaces based on configuration...
#     nginx-handbook-box: Adapter 1: nat
#     nginx-handbook-box: Adapter 2: hostonly
# ==> nginx-handbook-box: Forwarding ports...
#     nginx-handbook-box: 22 (guest) => 2222 (host) (adapter 1)
# ==> nginx-handbook-box: Running 'pre-boot' VM customizations...
# ==> nginx-handbook-box: Booting VM...
# ==> nginx-handbook-box: Waiting for machine to boot. This may take a few minutes...
#     nginx-handbook-box: SSH address: 127.0.0.1:2222
#     nginx-handbook-box: SSH username: vagrant
#     nginx-handbook-box: SSH auth method: private key
#     nginx-handbook-box: Warning: Remote connection disconnect. Retrying...
#     nginx-handbook-box: Warning: Connection reset. Retrying...
#     nginx-handbook-box: 
#     nginx-handbook-box: Vagrant insecure key detected. Vagrant will automatically replace
#     nginx-handbook-box: this with a newly generated keypair for better security.
#     nginx-handbook-box: 
#     nginx-handbook-box: Inserting generated public key within guest...
#     nginx-handbook-box: Removing insecure key from the guest if it's present...
#     nginx-handbook-box: Key inserted! Disconnecting and reconnecting using new SSH key...
# ==> nginx-handbook-box: Machine booted and ready!
# ==> nginx-handbook-box: Checking for guest additions in VM...
# ==> nginx-handbook-box: Setting hostname...
# ==> nginx-handbook-box: Configuring and enabling network interfaces...
# ==> nginx-handbook-box: Mounting shared folders...
#     nginx-handbook-box: /vagrant => /home/fhsinchy/vagrant/nginx-handbook

vagrant status

# Current machine states:

# nginx-handbook-box           running (virtualbox)

vagrant up 명령의 출력은 시스템에 따라 다를 수 있지만 vagrant 상태에 시스템이 실행 중이라고 표시되는 한 계속 진행할 수 있습니다.


이제 가상 머신이 실행 중이므로 SSH를 통해 가상 머신에 연결할 수 있습니다. 이렇게 하려면 다음 명령을 실행하십시오.


vagrant ssh nginx-handbook-box

# Welcome to Ubuntu 20.04.2 LTS (GNU/Linux 5.4.0-72-generic x86_64)
# vagrant@nginx-handbook-box:~$

모든 것이 올바르게 완료되면 가상 머신에 로그인해야 합니다. 이는 터미널의 vagrant @ nginx-handbook-box 행에 표시됩니다.


이 가상 머신은 로컬 머신의 http://192.168.20.20에서 액세스 할 수 있습니다. 호스트 파일에 항목을 추가하여 http : //nginx-handbook.test와 같은 사용자 지정 도메인을 가상 머신에 할당 할 수도 있습니다.


# on mac and linux terminal
sudo nano /etc/hosts

# on windows command prompt as administrator
notepad c:\windows\system32\drivers\etc\hosts

이제 파일 끝에 다음 줄을 추가합니다.

nginx-handbook.test    192.168.20.20

이제 브라우저의 http://nginx-handbook.test URI에서 가상 머신에 액세스 할 수 있습니다.


작업 디렉토리 내에서 다음 명령을 실행하여 가상 머신을 중지하거나 삭제할 수 있습니다.


# to stop the virtual machine
vagrant halt

# to destroy the virtual machine
vagrant destroy

더 많은 Vagrant 명령에 대해 배우고 싶다면 이 치트 시트가 유용 할 수 있습니다.


이제 시스템에 작동하는 Ubuntu 가상 머신이 있으므로 NGINX를 설치하기 만하면 됩니다.


가상 사설 서버를 프로비저닝하는 방법 


이 데모에서는 Vultr를 공급자로 사용하지만 DigitalOcean 또는 원하는 공급자를 사용할 수 있습니다.


공급자의 계정이 이미 있다고 가정하고 계정에 로그인하고 새 서버를 배포합니다.


ZUAu_Tpxx-2.jpg 


DigitalOcean에서는 일반적으로 물방울(droplet)이라고 합니다. 다음 화면에서 가까운 위치를 선택하십시오. 저는 방글라데시에 살고 있기 때문에 싱가포르를 선택했습니다.


zH08EnmGq.jpg 


다음 단계에서 운영 체제와 서버 크기를 선택해야 합니다. Ubuntu 20.04 및 가능한 가장 작은 서버 크기를 선택하십시오.


G8mEC13pp.jpg 


프로덕션 서버는 이보다 훨씬 더 크고 강력한 경향이 있지만 이 기사에서는 작은 서버로 충분합니다.


마지막으로, 마지막 단계로 nginx-hadnbook-demo-server와 같은 것을 서버 호스트와 레이블로 넣으십시오. 원하는 경우 비워 둘 수도 있습니다.


선택에 만족하면 지금 배포 버튼을 누르십시오.


배포 프로세스를 완료하는 데 다소 시간이 걸릴 수 있지만 완료되면 대시 보드에 새로 생성 된 서버가 표시됩니다.


server-list.png 


또한 상태에 주의하십시오. 준비 중 또는 중지됨이 아니라 실행 중이라고 표시되어야 합니다. 서버에 연결하려면 사용자 이름과 비밀번호가 필요합니다.


server-overview.png 


서버의 개요 페이지로 이동하면 서버의 IP 주소, 사용자 이름 및 비밀번호가 표시됩니다.


SSH를 사용하여 서버에 로그인하기 위한 일반 명령은 다음과 같습니다.


ssh <username>@<ip address>

따라서 내 서버의 경우 다음과 같습니다.


ssh root@45.77.251.108

# Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
# Warning: Permanently added '45.77.251.108' (ECDSA) to the list of known hosts.

# root@45.77.251.108's password: 
# Welcome to Ubuntu 20.04.2 LTS (GNU/Linux 5.4.0-65-generic x86_64)

# root@localhost:~#

이 서버에 계속 연결할 것인지 묻는 메시지가 표시됩니다. 예라고 대답하면 암호를 입력하라는 메시지가 표시됩니다. 서버 개요 페이지에서 비밀번호를 복사하여 터미널에 붙여 넣습니다.


모든 작업을 올바르게 수행했다면 서버에 로그인해야 합니다. 터미널에 root @ localhost 행이 표시됩니다. 여기서 localhost는 서버 호스트 이름이며 대소 문자가 다를 수 있습니다.


IP 주소로 이 서버에 직접 액세스 할 수 있습니다. 또는 사용자 지정 도메인을 소유하고 있는 경우에도 사용할 수 있습니다.


기사 전체에서 운영 체제의 호스트 파일에 테스트 도메인을 추가하는 것을 볼 수 있습니다. 실제 서버의 경우 DNS 공급자를 사용하여 해당 서버를 구성해야 합니다.


이 서버를 사용하는 동안에는 요금이 부과됩니다. 요금은 매우 적어야 하지만 어쨌든 경고합니다. 서버 개요 페이지에서 휴지통 아이콘을 누르면 언제든지 서버를 삭제할 수 있습니다.


image-90.png 


사용자 정의 도메인 이름을 소유 한 경우 이 서버에 하위 도메인을 할당 할 수 있습니다. 이제 서버 내부에 있으므로 NGINX를 설치하기 만하면 됩니다.


프로비저닝 된 서버 또는 가상 머신에 NGINX를 설치하는 방법 


서버 나 가상 머신에 로그인했다고 가정하면 가장 먼저 해야 할 일은 업데이트를 수행하는 것입니다. 이렇게 하려면 다음 명령을 실행하십시오.


sudo apt update && sudo apt upgrade -y

업데이트 후 다음 명령을 실행하여 NGINX를 설치합니다.


sudo apt install nginx -y

설치가 완료되면 NGINX가 자동으로 systemd 서비스로 등록되고 실행 중이어야 합니다. 확인하려면 다음 명령을 실행하십시오.

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)

상태가 실행 중이면 이동하는 것이 좋습니다. 그렇지 않으면 다음 명령을 실행하여 서비스를 시작할 수 있습니다.


sudo systemctl start nginx

마지막으로 모든 것이 제대로 작동하는지 시각적으로 확인하려면 즐겨 찾는 브라우저로 서버 / 가상 머신을 방문하면 NGINX의 기본 시작 페이지가 표시됩니다.

image-89.png 


NGINX는 일반적으로 /etc/nginx 디렉토리에 설치되며 다음 섹션의 대부분의 작업은 여기에서 수행됩니다.


축하합니다! NGINX를 서버 / 가상 머신에서 실행하고 있습니다. 이제 NGINX로 먼저 뛰어들 시간입니다.


NGINX의 구성 파일 소개 


웹 서버로서 NGINX의 역할은 클라이언트에 정적 또는 동적 콘텐츠를 제공하는 것입니다. 그러나 해당 콘텐츠가 제공되는 방식은 일반적으로 구성 파일에 의해 제어됩니다.


NGINX의 구성 파일은 .conf 확장자로 끝나며 일반적으로 /etc/nginx/ 디렉토리에 있습니다. 이 디렉토리로 이동하여 모든 파일 목록을 가져 오는 것으로 시작하겠습니다.


cd /etc/nginx

ls -lh

# drwxr-xr-x 2 root root 4.0K Apr 21  2020 conf.d
# -rw-r--r-- 1 root root 1.1K Feb  4  2019 fastcgi.conf
# -rw-r--r-- 1 root root 1007 Feb  4  2019 fastcgi_params
# -rw-r--r-- 1 root root 2.8K Feb  4  2019 koi-utf
# -rw-r--r-- 1 root root 2.2K Feb  4  2019 koi-win
# -rw-r--r-- 1 root root 3.9K Feb  4  2019 mime.types
# drwxr-xr-x 2 root root 4.0K Apr 21  2020 modules-available
# drwxr-xr-x 2 root root 4.0K Apr 17 14:42 modules-enabled
# -rw-r--r-- 1 root root 1.5K Feb  4  2019 nginx.conf
# -rw-r--r-- 1 root root  180 Feb  4  2019 proxy_params
# -rw-r--r-- 1 root root  636 Feb  4  2019 scgi_params
# drwxr-xr-x 2 root root 4.0K Apr 17 14:42 sites-available
# drwxr-xr-x 2 root root 4.0K Apr 17 14:42 sites-enabled
# drwxr-xr-x 2 root root 4.0K Apr 17 14:42 snippets
# -rw-r--r-- 1 root root  664 Feb  4  2019 uwsgi_params
# -rw-r--r-- 1 root root 3.0K Feb  4  2019 win-utf

이 파일 중에는 nginx.conf라는 이름이 있어야 합니다. 이것은 NGINX의 기본 구성 파일입니다. cat 프로그램을 사용하여 이 파일의 내용을 볼 수 있습니다.


cat 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;
# #    }
# #}

우와! 그것은 많은 것입니다. 현재 상태에서 이 파일을 이해하는 것은 악몽이 될 것입니다. 이제 파일 이름을 바꾸고 비어있는 새 파일을 만들어 보겠습니다.

# renames the file
sudo mv nginx.conf nginx.conf.backup

# creates a new file
sudo touch nginx.conf

나는 당신이 무엇을 하고 있는지 절대적으로 알지 못한다면 원본 nginx.conf 파일을 편집하지 않는 것이 좋습니다. 학습 목적으로 이름을 바꿀 수 있지만 나중에 실제 시나리오에서 서버를 구성하는 방법을 보여 드리겠습니다.


기본 웹 서버를 구성하는 방법 


책의 이 섹션에서는 기본 정적 웹 서버를 처음부터 구성하여 마침내 손을 더럽힐 것입니다. 이 섹션의 목표는 NGINX 구성 파일의 구문과 기본 개념을 소개하는 것입니다.


첫 번째 구성 파일을 작성하는 방법 


nano 텍스트 편집기를 사용하여 새로 생성 된 nginx.conf 파일을 열어 시작합니다.


sudo nano /etc/nginx/nginx.conf

책 전체에서 nano를 텍스트 편집기로 사용할 것입니다. 원한다면 더 현대적인 것을 사용할 수 있지만 실제 시나리오에서는 다른 것 대신 서버에서 nano 또는 vim을 사용하여 작업 할 가능성이 높습니다. 따라서 이 책을 나노 기술을 연마 할 기회로 사용하십시오. 또한 공식 치트 시트는 필요할 때마다 상담 할 수 있습니다.


파일을 연 후 다음과 같이 내용을 업데이트합니다.


events {

}

http {

    server {

        listen 80;
        server_name nginx-handbook.test;

        return 200 "Bonjour, mon ami!\n";
    }

}

REST API를 빌드 한 경험이 있다면 200 번 반환 "Bonjour, mon ami! \ n"에서 추측 할 수 있습니다. 서버가 상태 코드 200과 "Bonjour, mon ami!"라는 메시지로 응답하도록 구성된 줄입니다.


지금은 그 이상을 이해하지 못하더라도 걱정하지 마십시오. 이 파일을 한 줄씩 설명 하겠지만 먼저 이 구성이 작동하는지 살펴 보겠습니다.


구성 파일의 유효성을 검사하고 다시 로드하는 방법 


새 구성 파일을 작성하거나 이전 구성 파일을 업데이트 한 후 먼저 파일에 구문 오류가 있는지 확인해야 합니다. nginx 바이너리에는 옵션 -t가 포함되어 있습니다.


sudo nginx -t

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

구문 오류가 있는 경우 이 명령은 줄 번호를 포함하여 오류에 대해 알려줍니다.


구성 파일은 괜찮지만 NGINX는 이를 사용하지 않습니다. NGINX가 작동하는 방식은 구성 파일을 한 번 읽고 이를 기반으로 계속 작동하는 것입니다.


구성 파일을 업데이트하는 경우 NGINX에 구성 파일을 다시 로드하도록 명시적으로 지시해야 합니다. 이를 수행하는 두 가지 방법이 있습니다.


  • sudo systemctl restart nginx 명령을 실행하여 NGINX 서비스를 다시 시작할 수 있습니다.
  • sudo nginx -s reload 명령을 실행하여 NGINX에 다시 로드 신호를 보낼 수 있습니다.

-s 옵션은 NGINX에 다양한 신호를 보내는 데 사용됩니다. 사용 가능한 신호는 stop, quit, reload 및 reopen입니다. 방금 언급 한 두 가지 방법 중 입력이 적기 때문에 두 번째 방법을 선호합니다.


nginx -s reload 명령을 실행하여 구성 파일을 다시 로드 한 후에는 간단한 get 요청을 서버에 전송하여 작동 중인 것을 볼 수 있습니다.


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

# HTTP/1.1 200 OK
# Server: nginx/1.18.0 (Ubuntu)
# Date: Wed, 21 Apr 2021 10:03:33 GMT
# Content-Type: text/plain
# Content-Length: 18
# Connection: keep-alive

# Bonjour, mon ami!

서버는 상태 코드 200과 예상 메시지로 응답합니다. 여기까지 오신 것을 축하합니다! 이제 설명 할 시간입니다.


NGINX에서 지시어 및 컨텍스트를 이해하는 방법 


여기에 작성한 몇 줄의 코드는 단순 해 보이지만 NGINX 구성 파일의 가장 중요한 두 가지 용어를 소개합니다. 그것들은 지시문과 문맥입니다.


기술적으로 NGINX 구성 파일 내의 모든 것은 지시문입니다. 지시문에는 두 가지 유형이 있습니다.

  • 간단한 지시어
  • 블록 지시문

간단한 지시문은 지시문 이름과 listen, return 등의 공백으로 구분 된 매개 변수로 구성됩니다. 단순 지시문은 세미콜론으로 끝납니다.


블록 지시문은 세미콜론으로 끝나는 대신 추가 명령을 묶는 중괄호 {}로 끝나는 점을 제외하면 단순 지시문과 유사합니다.


내부에 다른 지시문을 포함 할 수 있는 블록 지시문을 컨텍스트, 즉 이벤트, http 등이라고 합니다. NGINX에는 네 가지 핵심 컨텍스트가 있습니다.


  • events {} – 이벤트 컨텍스트는 NGINX가 일반 수준에서 요청을 처리하는 방법에 관한 전역 구성을 설정하는 데 사용됩니다. 유효한 구성 파일에는 하나의 이벤트 컨텍스트 만 있을 수 있습니다.
  • http {} – 이름에서 알 수 있는 http 컨텍스트는 특히 서버가 HTTP 및 HTTPS 요청을 처리하는 방법에 관한 구성을 정의하는 데 사용됩니다. 유효한 구성 파일에는 http 컨텍스트가 하나만 있을 수 있습니다.
  • server {} – 서버 컨텍스트는 http 컨텍스트 내에 중첩되며 단일 호스트 내에서 특정 가상 서버를 구성하는 데 사용됩니다. http 컨텍스트 내에 중첩 된 유효한 구성 파일에 여러 서버 컨텍스트가 있을 수 있습니다. 각 서버 컨텍스트는 가상 호스트로 간주됩니다.
  • main – 기본 컨텍스트는 구성 파일 자체입니다. 앞서 언급 한 세 가지 문맥 외에 작성된 모든 것은 주요 문맥에 있습니다.

NGINX의 컨텍스트를 다른 프로그래밍 언어의 범위처럼 처리 할 수 ​​있습니다. 그들 사이에는 상속 감도 있습니다. 공식 NGINX 문서에서 지시문의 알파벳순 색인을 찾을 수 있습니다.


구성 파일 내에 여러 서버 컨텍스트가 있을 수 있다고 이미 언급했습니다. 그러나 요청이 서버에 도달하면 NGINX는 이러한 컨텍스트 중 요청을 처리해야 하는 컨텍스트를 어떻게 알 수 있습니까?


수신 지시문은 구성 내에서 올바른 서버 컨텍스트를 식별하는 방법 중 하나입니다. 다음 시나리오를 고려하십시오.


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

        return 200 "hello from port 80!\n";
    }


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

        return 200 "hello from port 8080!\n";
    }
}

이제 http : //nginx-handbook.test : 80에 요청을 보내면 "Hello from port 80!"을 받게 됩니다. 응답으로. http : //nginx-handbook.test : 8080에 요청을 보내면 "Hello from port 8080!"이 표시됩니다. 응답으로 :


curl nginx-handbook.test:80

# hello from port 80!

curl nginx-handbook.test:8080

# hello from port 8080!

이 두 서버 블록은 요청이 번호 중 하나에 도달하면 응답을 기다리는 두 사람이 전화 수신기를 들고 있는 것과 같습니다. 해당 번호는 수신 지시문으로 표시됩니다.


listen 지시문과 별도로 server_name 지시문도 있습니다. 가상 라이브러리 관리 애플리케이션의 다음 시나리오를 고려하십시오.


http {
    server {
        listen 80;
        server_name library.test;

        return 200 "your local library!\n";
    }


    server {
        listen 80;
        server_name librarian.library.test;

        return 200 "welcome dear librarian!\n";
    }
}

이것은 가상 호스트 개념의 기본적인 예입니다. 동일한 서버에서 서로 다른 서버 이름으로 두 개의 개별 응용 프로그램을 실행하고 있습니다.


http://library.test에 요청을 보내면 "로컬 라이브러리!"가 표시됩니다. 응답으로. http://librarian.library.test에 요청을 보내면 "사서 님 환영합니다!"라는 메시지가 표시됩니다. 응답으로.


curl http://library.test

# your local library!

curl http://librarian.library.test

# welcome dear librarian!

이 데모가 시스템에서 작동하도록 하려면 다음 두 도메인 이름도 포함하도록 호스트 파일을 업데이트해야 합니다.


192.168.20.20   library.test
192.168.20.20   librarian.library.test

마지막으로 return 지시문은 사용자에게 유효한 응답을 반환합니다. 이 지시문은 두 개의 매개 변수, 즉 상태 코드와 리턴 될 문자열 메시지를 사용합니다.


NGINX를 사용하여 정적 콘텐츠를 제공하는 방법 


이제 NGINX 용 기본 구성 파일을 작성하는 방법을 잘 이해 했으므로 일반 텍스트 응답 대신 정적 파일을 제공하도록 구성을 업그레이드 해 보겠습니다.


정적 콘텐츠를 제공하려면 먼저 서버에 저장해야 합니다. ls를 사용하여 서버의 루트에 있는 파일과 디렉토리를 나열하면 거기에서 /srv라는 디렉토리를 찾을 수 있습니다.


ls -lh /

# lrwxrwxrwx   1 root    root       7 Apr 16 02:10 bin -> usr/bin
# drwxr-xr-x   3 root    root    4.0K Apr 16 02:13 boot
# drwxr-xr-x  16 root    root    3.8K Apr 21 09:23 dev
# drwxr-xr-x  92 root    root    4.0K Apr 21 09:24 etc
# drwxr-xr-x   4 root    root    4.0K Apr 21 08:04 home
# lrwxrwxrwx   1 root    root       7 Apr 16 02:10 lib -> usr/lib
# lrwxrwxrwx   1 root    root       9 Apr 16 02:10 lib32 -> usr/lib32
# lrwxrwxrwx   1 root    root       9 Apr 16 02:10 lib64 -> usr/lib64
# lrwxrwxrwx   1 root    root      10 Apr 16 02:10 libx32 -> usr/libx32
# drwx------   2 root    root     16K Apr 16 02:15 lost+found
# drwxr-xr-x   2 root    root    4.0K Apr 16 02:10 media
# drwxr-xr-x   2 root    root    4.0K Apr 16 02:10 mnt
# drwxr-xr-x   2 root    root    4.0K Apr 16 02:10 opt
# dr-xr-xr-x 152 root    root       0 Apr 21 09:23 proc
# drwx------   5 root    root    4.0K Apr 21 09:59 root
# drwxr-xr-x  26 root    root     820 Apr 21 09:47 run
# lrwxrwxrwx   1 root    root       8 Apr 16 02:10 sbin -> usr/sbin
# drwxr-xr-x   6 root    root    4.0K Apr 16 02:14 snap
# drwxr-xr-x   2 root    root    4.0K Apr 16 02:10 srv
# dr-xr-xr-x  13 root    root       0 Apr 21 09:23 sys
# drwxrwxrwt  11 root    root    4.0K Apr 21 09:24 tmp
# drwxr-xr-x  15 root    root    4.0K Apr 16 02:12 usr
# drwxr-xr-x   1 vagrant vagrant   38 Apr 21 09:23 vagrant
# drwxr-xr-x  14 root    root    4.0K Apr 21 08:34 var

이 /srv 디렉토리는 이 시스템에서 제공하는 사이트 별 데이터를 포함합니다. 이제 이 디렉토리로 이동하여 이 책과 함께 제공되는 코드 저장소를 복제하십시오.


cd /srv

sudo git clone https://github.com/fhsinchy/nginx-handbook-projects.git

nginx-handbook-projects 디렉토리 안에 총 4 개의 파일을 포함하는 static-demo라는 디렉토리가 있어야 합니다.


ls -lh /srv/nginx-handbook-projects/static-demo

# -rw-r--r-- 1 root root 960 Apr 21 11:27 about.html
# -rw-r--r-- 1 root root 960 Apr 21 11:27 index.html
# -rw-r--r-- 1 root root 46K Apr 21 11:27 mini.min.css
# -rw-r--r-- 1 root root 19K Apr 21 11:27 the-nginx-handbook.jpg

이제 제공 할 정적 콘텐츠가 있으므로 다음과 같이 구성을 업데이트합니다.


events {

}

http {

    server {

        listen 80;
        server_name nginx-handbook.test;

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

}

리턴 지시문이 이제 루트 지시문으로 대체 된 것을 제외하면 코드는 거의 동일합니다. 이 지시문은 사이트의 루트 디렉토리를 선언하는 데 사용됩니다.


root /srv/nginx-handbook-projects/static-demo를 작성하면 이 서버에 요청이 들어 오면 NGINX에 /srv/nginx-handbook-projects/static-demo 디렉토리에서 제공 할 파일을 찾도록 지시하는 것입니다. NGINX는 웹 서버이기 때문에 기본적으로 index.html 파일을 제공 할만큼 똑똑합니다.


이것이 작동하는지 봅시다. 업데이트 된 구성 파일을 테스트하고 다시 로드하고 서버를 방문하십시오. 다소 깨진 HTML 사이트로 맞이해야 합니다.


image-91.png 


NGINX가 index.html 파일을 올바르게 제공했지만 세 개의 탐색 링크 모양으로 판단하면 CSS 코드가 작동하지 않는 것 같습니다.


CSS 파일에 문제가 있다고 생각할 수 있습니다. 그러나 실제로 문제는 구성 파일에 있습니다.


NGINX의 정적 파일 유형 처리 


현재 직면하고 있는 문제를 디버깅 하려면 CSS 파일에 대한 요청을 서버에 보냅니다.


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

# HTTP/1.1 200 OK
# Server: nginx/1.18.0 (Ubuntu)
# Date: Wed, 21 Apr 2021 12:17:16 GMT
# Content-Type: text/plain
# Content-Length: 46887
# Last-Modified: Wed, 21 Apr 2021 11:27:06 GMT
# Connection: keep-alive
# ETag: "60800c0a-b727"
# Accept-Ranges: bytes

Content-Type에 주의를 기울이고 text/css가 아닌 text/plain이 어떻게 표시되는지 확인하십시오. 이는 NGINX가 이 파일을 스타일 시트 대신 일반 텍스트로 제공함을 의미합니다.


NGINX는 기본적으로 index.html 파일을 찾을 수 있을 만큼 똑똑하지만 파일 유형을 해석하는 데 있어서는 꽤 멍청합니다. 이 문제를 해결하려면 구성을 다시 한 번 업데이트하십시오.


events {

}

http {

    types {
        text/html html;
        text/css css;
    }

    server {

        listen 80;
        server_name nginx-handbook.test;

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

코드에 대한 유일한 변경 사항은 http 블록 내에 중첩 된 새로운 유형 컨텍스트입니다. 이름에서 이미 추측했듯이 이 컨텍스트는 파일 유형을 구성하는 데 사용됩니다.


이 컨텍스트에서 text/html html을 작성하면 NGINX에 html 확장자로 끝나는 text/html로 파일을 구문 분석하도록 지시하는 것입니다.


HTML이 잘 구문 분석되고 있기 때문에 CSS 파일 유형을 구성하는 것으로 충분하다고 생각할 수 있지만 그렇지 않습니다.


구성에 유형 컨텍스트를 도입하면 NGINX는 훨씬 더 멍청 해지고 사용자가 구성한 파일 만 구문 분석합니다. 따라서 이 컨텍스트에서 text/css css 만 정의하면 NGINX는 HTML 파일을 일반 텍스트로 구문 분석하기 시작합니다.


새로 업데이트 된 구성 파일을 확인하고 다시로드하고 서버를 다시 방문하십시오. CSS 파일에 대한 요청을 다시 보내면 이번에는 파일을 text/css 파일로 구문 분석해야 합니다.


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

# HTTP/1.1 200 OK
# Server: nginx/1.18.0 (Ubuntu)
# Date: Wed, 21 Apr 2021 12:29:35 GMT
# Content-Type: text/css
# Content-Length: 46887
# Last-Modified: Wed, 21 Apr 2021 11:27:06 GMT
# Connection: keep-alive
# ETag: "60800c0a-b727"
# Accept-Ranges: bytes

시각적 확인을 위해 서버를 방문하면 이번에는 사이트가 더 좋아 보일 것입니다.

image-92.png 


구성 파일을 올바르게 업데이트하고 다시로드 했는데 여전히 이전 사이트가 표시되는 경우 강제 새로 고침을 수행합니다.


부분 구성 파일을 포함하는 방법 


유형 컨텍스트 내에서 파일 유형을 매핑하는 것은 소규모 프로젝트에서는 작동 할 수 있지만 더 큰 프로젝트에서는 번거롭고 오류가 발생하기 쉽습니다.

NGINX는 이 문제에 대한 솔루션을 제공합니다. /etc/nginx 디렉토리에 있는 파일을 다시 나열하면 mime.types라는 파일이 표시됩니다.


ls -lh /etc/nginx

# drwxr-xr-x 2 root root 4.0K Apr 21  2020 conf.d
# -rw-r--r-- 1 root root 1.1K Feb  4  2019 fastcgi.conf
# -rw-r--r-- 1 root root 1007 Feb  4  2019 fastcgi_params
# -rw-r--r-- 1 root root 2.8K Feb  4  2019 koi-utf
# -rw-r--r-- 1 root root 2.2K Feb  4  2019 koi-win
# -rw-r--r-- 1 root root 3.9K Feb  4  2019 mime.types
# drwxr-xr-x 2 root root 4.0K Apr 21  2020 modules-available
# drwxr-xr-x 2 root root 4.0K Apr 17 14:42 modules-enabled
# -rw-r--r-- 1 root root 1.5K Feb  4  2019 nginx.conf
# -rw-r--r-- 1 root root  180 Feb  4  2019 proxy_params
# -rw-r--r-- 1 root root  636 Feb  4  2019 scgi_params
# drwxr-xr-x 2 root root 4.0K Apr 17 14:42 sites-available
# drwxr-xr-x 2 root root 4.0K Apr 17 14:42 sites-enabled
# drwxr-xr-x 2 root root 4.0K Apr 17 14:42 snippets
# -rw-r--r-- 1 root root  664 Feb  4  2019 uwsgi_params
# -rw-r--r-- 1 root root 3.0K Feb  4  2019 win-utf

이 파일의 내용을 살펴 보겠습니다.


cat /etc/mime.types

# types {
#     text/html                             html htm shtml;
#     text/css                              css;
#     text/xml                              xml;
#     image/gif                             gif;
#     image/jpeg                            jpeg jpg;
#     application/javascript                js;
#     application/atom+xml                  atom;
#     application/rss+xml                   rss;

#     text/mathml                           mml;
#     text/plain                            txt;
#     text/vnd.sun.j2me.app-descriptor      jad;
#     text/vnd.wap.wml                      wml;
#     text/x-component                      htc;

#     image/png                             png;
#     image/tiff                            tif tiff;
#     image/vnd.wap.wbmp                    wbmp;
#     image/x-icon                          ico;
#     image/x-jng                           jng;
#     image/x-ms-bmp                        bmp;
#     image/svg+xml                         svg svgz;
#     image/webp                            webp;

#     application/font-woff                 woff;
#     application/java-archive              jar war ear;
#     application/json                      json;
#     application/mac-binhex40              hqx;
#     application/msword                    doc;
#     application/pdf                       pdf;
#     application/postscript                ps eps ai;
#     application/rtf                       rtf;
#     application/vnd.apple.mpegurl         m3u8;
#     application/vnd.ms-excel              xls;
#     application/vnd.ms-fontobject         eot;
#     application/vnd.ms-powerpoint         ppt;
#     application/vnd.wap.wmlc              wmlc;
#     application/vnd.google-earth.kml+xml  kml;
#     application/vnd.google-earth.kmz      kmz;
#     application/x-7z-compressed           7z;
#     application/x-cocoa                   cco;
#     application/x-java-archive-diff       jardiff;
#     application/x-java-jnlp-file          jnlp;
#     application/x-makeself                run;
#     application/x-perl                    pl pm;
#     application/x-pilot                   prc pdb;
#     application/x-rar-compressed          rar;
#     application/x-redhat-package-manager  rpm;
#     application/x-sea                     sea;
#     application/x-shockwave-flash         swf;
#     application/x-stuffit                 sit;
#     application/x-tcl                     tcl tk;
#     application/x-x509-ca-cert            der pem crt;
#     application/x-xpinstall               xpi;
#     application/xhtml+xml                 xhtml;
#     application/xspf+xml                  xspf;
#     application/zip                       zip;

#     application/octet-stream              bin exe dll;
#     application/octet-stream              deb;
#     application/octet-stream              dmg;
#     application/octet-stream              iso img;
#     application/octet-stream              msi msp msm;

#     application/vnd.openxmlformats-officedocument.wordprocessingml.document    docx;
#     application/vnd.openxmlformats-officedocument.spreadsheetml.sheet          xlsx;
#     application/vnd.openxmlformats-officedocument.presentationml.presentation  pptx;

#     audio/midi                            mid midi kar;
#     audio/mpeg                            mp3;
#     audio/ogg                             ogg;
#     audio/x-m4a                           m4a;
#     audio/x-realaudio                     ra;

#     video/3gpp                            3gpp 3gp;
#     video/mp2t                            ts;
#     video/mp4                             mp4;
#     video/mpeg                            mpeg mpg;
#     video/quicktime                       mov;
#     video/webm                            webm;
#     video/x-flv                           flv;
#     video/x-m4v                           m4v;
#     video/x-mng                           mng;
#     video/x-ms-asf                        asx asf;
#     video/x-ms-wmv                        wmv;
#     video/x-msvideo                       avi;
# }

파일에는 긴 파일 유형 및 확장자 목록이 포함되어 있습니다. 구성 파일 내에서 이 파일을 사용하려면 다음과 같이 구성을 업데이트하십시오.


events {

}

http {

    include /etc/nginx/mime.types;

    server {

        listen 80;
        server_name nginx-handbook.test;

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

}

이전 유형 컨텍스트는 이제 새로운 include 지시어로 대체되었습니다. 이름에서 알 수 있듯이 이 지시문을 사용하면 다른 구성 파일의 내용을 포함 할 수 있습니다.


구성 파일의 유효성을 검사하고 다시로드 한 다음 mini.min.css 파일에 대한 요청을 다시 한 번 보냅니다.


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

# HTTP/1.1 200 OK
# Server: nginx/1.18.0 (Ubuntu)
# Date: Wed, 21 Apr 2021 12:29:35 GMT
# Content-Type: text/css
# Content-Length: 46887
# Last-Modified: Wed, 21 Apr 2021 11:27:06 GMT
# Connection: keep-alive
# ETag: "60800c0a-b727"
# Accept-Ranges: bytes

기본 구성 파일을 이해하는 방법에 대한 아래 섹션에서는 include를 사용하여 가상 서버 구성을 모듈화 하는 방법을 보여줍니다.


NGINX의 동적 라우팅 


이전 섹션에서 작성한 구성은 매우 간단한 정적 콘텐츠 서버 구성이었습니다. 클라이언트가 방문하고 응답하는 URI에 해당하는 사이트 루트의 파일과 일치하는 것이 전부였습니다.


따라서 클라이언트가 index.html, about.html 또는 mini.min.css와 같이 루트에 존재하는 파일을 요청하면 NGINX는 파일을 반환합니다. 그러나 http : //nginx-handbook.test/nothing과 같은 경로를 방문하면 기본 404 페이지로 응답합니다.


image-93.png 

책의 이 섹션에서는 위치 컨텍스트, 변수, 리디렉션, 재 작성 및 try_files 지시문에 대해 학습합니다. 이 섹션에는 새로운 프로젝트가 없지만 여기서 배우는 개념은 다음 섹션에서 필요합니다.


또한 이 섹션에서는 구성이 매우 자주 변경되므로 업데이트 할 때마다 구성 파일을 확인하고 다시로드 하는 것을 잊지 마십시오.


위치 일치 


이 섹션에서 논의 할 첫 번째 개념은 위치 컨텍스트입니다. 다음과 같이 구성을 업데이트하십시오.


events {

}

http {

    server {

        listen 80;
        server_name nginx-handbook.test;

        location /agatha {
            return 200 "Miss Marple.\nHercule Poirot.\n";
        }
    }
}

루트 지시문을 새 위치 컨텍스트로 대체했습니다. 이 컨텍스트는 일반적으로 서버 블록 내에 중첩됩니다. 서버 컨텍스트 내에 여러 위치 컨텍스트가 있을 수 있습니다.


http://nginx-handbook.test/agatha에 요청을 보내면 200 개의 응답 코드와 Agatha Christie가 만든 문자 목록을 받게 됩니다.


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

# HTTP/1.1 200 OK
# Server: nginx/1.18.0 (Ubuntu)
# Date: Wed, 21 Apr 2021 15:59:07 GMT
# Content-Type: text/plain
# Content-Length: 29
# Connection: keep-alive

# Miss Marple.
# Hercule Poirot.

이제 http://nginx-handbook.test/agatha-christie에 요청을 보내면 동일한 응답을 받게 됩니다.


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

# HTTP/1.1 200 OK
# Server: nginx/1.18.0 (Ubuntu)
# Date: Wed, 21 Apr 2021 15:59:07 GMT
# Content-Type: text/plain
# Content-Length: 29
# Connection: keep-alive

# Miss Marple.
# Hercule Poirot.

이는 위치 /agatha를 작성하여 NGINX에 "agatha"로 시작하는 모든 URI와 일치하도록 지시하기 때문에 발생합니다. 이러한 종류의 일치를 접두사 일치라고 합니다.


정확한 일치를 수행하려면 다음과 같이 코드를 업데이트해야 합니다.


events {

}

http {

    server {

        listen 80;
        server_name nginx-handbook.test;

        location = /agatha {
            return 200 "Miss Marple.\nHercule Poirot.\n";
        }
    }

}

위치 URI 앞에 = 기호를 추가하면 NGINX가 URL이 정확히 일치하는 경우에만 응답하도록 지시합니다. 이제 /agatha가 아닌 다른 곳에 요청을 보내면 404 응답을 받게 됩니다.


curl -I http://nginx-handbook.test/agatha-christie

# HTTP/1.1 404 Not Found
# Server: nginx/1.18.0 (Ubuntu)
# Date: Wed, 21 Apr 2021 16:14:29 GMT
# Content-Type: text/html
# Content-Length: 162
# Connection: keep-alive

curl -I http://nginx-handbook.test/agatha

# HTTP/1.1 200 OK
# Server: nginx/1.18.0 (Ubuntu)
# Date: Wed, 21 Apr 2021 16:15:04 GMT
# Content-Type: text/plain
# Content-Length: 29
# Connection: keep-alive

NGINX의 또 다른 종류의 일치는 정규식 일치입니다. 이 일치를 사용하여 복잡한 정규 표현식에 대해 위치 URL을 확인할 수 있습니다.


events {

}

http {

    server {

        listen 80;
        server_name nginx-handbook.test;

        location ~ /agatha[0-9] {
        	return 200 "Miss Marple.\nHercule Poirot.\n";
        }
    }

}

이전에 사용 된 = 기호를 ~ 기호로 바꾸면 NGINX에 정규식 일치를 수행하도록 지시하는 것입니다. 위치를 ~/agatha [0-9]로 설정하면 NIGINX는 "agatha"단어 뒤에 숫자가 있는 경우에만 응답합니다.


curl -I http://nginx-handbook.test/agatha

# HTTP/1.1 404 Not Found
# Server: nginx/1.18.0 (Ubuntu)
# Date: Wed, 21 Apr 2021 16:14:29 GMT
# Content-Type: text/html
# Content-Length: 162
# Connection: keep-alive

curl -I http://nginx-handbook.test/agatha8

# HTTP/1.1 200 OK
# Server: nginx/1.18.0 (Ubuntu)
# Date: Wed, 21 Apr 2021 16:15:04 GMT
# Content-Type: text/plain
# Content-Length: 29
# Connection: keep-alive

정규식 일치는 기본적으로 대소 문자를 구분합니다. 즉, 문자를 대문자로 입력하면 위치가 작동하지 않습니다.


curl -I http://nginx-handbook.test/Agatha8

# HTTP/1.1 404 Not Found
# Server: nginx/1.18.0 (Ubuntu)
# Date: Wed, 21 Apr 2021 16:14:29 GMT
# Content-Type: text/html
# Content-Length: 162
# Connection: keep-alive

대소 문자를 구분하지 않으려면 ~ 기호 뒤에 *를 추가해야 합니다.


events {

}

http {

    server {

        listen 80;
        server_name nginx-handbook.test;

        location ~* /agatha[0-9] {
        	return 200 "Miss Marple.\nHercule Poirot.\n";
        }
    }

}

그러면 NGINX에 유형 감도를 해제하고 어쨌든 위치를 일치 시킬 것입니다.


curl -I http://nginx-handbook.test/agatha8

# HTTP/1.1 200 OK
# Server: nginx/1.18.0 (Ubuntu)
# Date: Wed, 21 Apr 2021 16:15:04 GMT
# Content-Type: text/plain
# Content-Length: 29
# Connection: keep-alive

curl -I http://nginx-handbook.test/Agatha8

# HTTP/1.1 200 OK
# Server: nginx/1.18.0 (Ubuntu)
# Date: Wed, 21 Apr 2021 16:15:04 GMT
# Content-Type: text/plain
# Content-Length: 29
# Connection: keep-alive

NGINX는 이러한 일치에 우선 순위 값을 할당하며 정규식 일치는 접두사 일치보다 우선 순위가 높습니다.


events {

}

http {

    server {

        listen 80;
        server_name nginx-handbook.test;

		location /Agatha8 {
        	return 200 "prefix matched.\n";
        }
        
        location ~* /agatha[0-9] {
        	return 200 "regex matched.\n";
        }
    }

}

이제 http://nginx-handbook.test/Agatha8에 요청을 보내면 다음 응답을 받게 됩니다.


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

# HTTP/1.1 200 OK
# Server: nginx/1.18.0 (Ubuntu)
# Date: Thu, 22 Apr 2021 08:08:18 GMT
# Content-Type: text/plain
# Content-Length: 15
# Connection: keep-alive

# regex matched.

그러나 이 우선 순위는 약간 변경 될 수 있습니다. NGINX의 최종 일치 유형은 우선 접두사 일치입니다. 접두사 일치를 우선 순위로 바꾸려면 위치 URI 앞에 ^ ~ 수정자를 포함해야 합니다.


events {

}

http {

    server {

        listen 80;
        server_name nginx-handbook.test;

		location ^~ /Agatha8 {
        	return 200 "prefix matched.\n";
        }
        
        location ~* /agatha[0-9] {
        	return 200 "regex matched.\n";
        }
    }

}

이제 http://nginx-handbook.test/Agatha8에 요청을 보내면 다음 응답을 받게 됩니다.


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

# HTTP/1.1 200 OK
# Server: nginx/1.18.0 (Ubuntu)
# Date: Thu, 22 Apr 2021 08:13:24 GMT
# Content-Type: text/plain
# Content-Length: 16
# Connection: keep-alive

# prefix matched.

이번에는 접두사 일치가 승리합니다. 따라서 모든 일치 항목의 우선 순위 내림차순 목록은 다음과 같습니다.


 MATCH

 MODIFIER

 Exact

 =

 Preferential Prefix

 ^~

 REGEX

 ~ or ~*

 Prefix

 None


NGINX의 변수 


NGINX의 변수는 다른 프로그래밍 언어의 변수와 유사합니다. set 지시문을 사용하여 구성 파일 내에서 새 변수를 선언 할 수 있습니다.


set $<variable_name> <variable_value>;

# set name "Farhan"
# set age 25
# set is_working true

변수는 세 가지 유형이 될 수 있습니다.

  • String
  • Integer
  • Boolean

선언 한 변수 외에도 NGINX 모듈 내에 포함 된 변수가 있습니다. 변수의 알파벳순 색인은 공식 문서에서 사용할 수 있습니다.


작동 중인 일부 변수를 보려면 다음과 같이 구성을 업데이트하십시오.


events {

}

http {

    server {

        listen 80;
        server_name nginx-handbook.test;

        return 200 "Host - $host\nURI - $uri\nArgs - $args\n";
    }

}

이제 서버에 요청을 보내면 다음과 같은 응답을 받아야 합니다.


# curl http://nginx-handbook.test/user?name=Farhan

# Host - nginx-handbook.test
# URI - /user
# Args - name=Farhan

보시다시피 $host 및 $uri 변수는 루트 주소와 루트에 상대적인 요청 된 URI를 각각 보유합니다. 보시다시피 $args 변수는 모든 쿼리 문자열을 포함합니다.


쿼리 문자열의 리터럴 문자열 형식을 인쇄하는 대신 $arg 변수를 사용하여 개별 값에 액세스 할 수 있습니다.


events {

}

http {

    server {

        listen 80;
        server_name nginx-handbook.test;
        
        set $name $arg_name; # $arg_<query string name>

        return 200 "Name - $name\n";
    }

}

이제 서버의 응답은 다음과 같아야 합니다.


curl http://nginx-handbook.test?name=Farhan

# Name - Farhan

여기서 설명한 변수는 ngx_http_core_module에 포함되어 있습니다. 구성에서 변수에 액세스 할 수 있으려면 변수가 포함 된 모듈로 NGINX를 빌드해야 합니다. 소스에서 NGINX를 빌드하고 동적 모듈을 사용하는 것은 이 기사의 범위를 약간 벗어납니다. 그러나 나는 내 블로그에 반드시 그것에 대해 쓸 것입니다.


Redirects and Rewrites 


NGINX의 리디렉션은 다른 플랫폼의 리디렉션과 동일합니다. 리디렉션의 작동 방식을 보여 주려면 다음과 같이 구성을 업데이트하십시오.


events {

}

http {

    include /etc/nginx/mime.types;

    server {

        listen 80;
        server_name nginx-handbook.test;

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

        location = /index_page {
                return 307 /index.html;
        }

        location = /about_page {
                return 307 /about.html;
        }
    }
}

이제 http : //nginx-handbook.test/about_page에 요청을 보내면 http : //nginx-handbook.test/about.html로 리디렉션 됩니다.


curl -I http://nginx-handbook.test/about_page

# HTTP/1.1 307 Temporary Redirect
# Server: nginx/1.18.0 (Ubuntu)
# Date: Thu, 22 Apr 2021 18:02:04 GMT
# Content-Type: text/html
# Content-Length: 180
# Location: http://nginx-handbook.test/about.html
# Connection: keep-alive

보시다시피 서버는 상태 코드 307로 응답했으며 위치는 http://nginx-handbook.test/about.html을 나타냅니다. 브라우저에서 http://nginx-handbook.test/about_page를 방문하면 URL이 자동으로 http://nginx-handbook.test/about.html로 변경되는 것을 볼 수 있습니다.


그러나 재 작성 지시문은 약간 다르게 작동합니다. 사용자에게 알리지 않고 내부적으로 URI를 변경합니다. 작동 상태를 보려면 다음과 같이 구성을 업데이트하십시오.


events {

}

http {

    include /etc/nginx/mime.types;

    server {

        listen 80;
        server_name nginx-handbook.test;

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

        rewrite /index_page /index.html;

        rewrite /about_page /about.html;
    }
}

이제 http://nginx-handbook/about_page URI로 요청을 보내면 200 응답 코드와 about.html 파일에 대한 HTML 코드를 받게 됩니다.


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

# HTTP/1.1 200 OK
# Server: nginx/1.18.0 (Ubuntu)
# Date: Thu, 22 Apr 2021 18:09:31 GMT
# Content-Type: text/html
# Content-Length: 960
# Last-Modified: Wed, 21 Apr 2021 11:27:06 GMT
# Connection: keep-alive
# ETag: "60800c0a-3c0"
# Accept-Ranges: bytes

# <!DOCTYPE html>
# <html lang="en">
# <head>
#     <meta charset="UTF-8">
#     <meta http-equiv="X-UA-Compatible" content="IE=edge">
#     <meta name="viewport" content="width=device-width, initial-scale=1.0">
#     <title>NGINX Handbook Static Demo</title>
#     <link rel="stylesheet" href="mini.min.css">
#     <style>
#         .container {
#             max-width: 1024px;
#             margin-left: auto;
#             margin-right: auto;
#         }
# 
#         h1 {
#             text-align: center;
#         }
#     </style>
# </head>
# <body class="container">
#     <header>
#         <a class="button" href="index.html">Index</a>
#         <a class="button" href="about.html">About</a>
#         <a class="button" href="nothing">Nothing</a>
#     </header>
#     <div class="card fluid">
#         <img src="./the-nginx-handbook.jpg" alt="The NGINX Handbook Cover Image">
#     </div>
#     <div class="card fluid">
#         <h1>this is the <strong>about.html</strong> file</h1>
#     </div>
# </body>
# </html>

브라우저를 사용하여 URI를 방문하면 URL이 변경되지 않은 상태에서 about.html 페이지가 표시됩니다.


rewrite.png 


URI 변경이 처리되는 방식 외에도 리디렉션과 재 작성 간에 또 다른 차이점이 있습니다. 재 작성이 발생하면 서버 컨텍스트가 NGINX에 의해 재평가 됩니다. 따라서 재 작성은 리디렉션보다 비용이 많이 드는 작업입니다.


여러 파일을 시도하는 방법 


이 섹션에서 보여줄 마지막 개념은 try_files 지시문입니다. 단일 파일로 응답하는 대신 try_files 지시문을 사용하여 여러 파일이 있는지 확인할 수 있습니다.


events {

}

http {

    include /etc/nginx/mime.types;

    server {

        listen 80;
        server_name nginx-handbook.test;

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

        try_files /the-nginx-handbook.jpg /not_found;

        location /not_found {
                return 404 "sadly, you've hit a brick wall buddy!\n";
        }
    }
}

보시다시피 새로운 try_files 지시어가 추가되었습니다. try_files /the-nginx-handbook.jpg / not_found; 요청이 수신 될 때마다 루트에서 the-nginx-handbook.jpg라는 파일을 찾도록 NGINX에 지시합니다. 존재하지 않는 경우 / not_found 위치로 이동하십시오.


이제 서버를 방문하면 이미지가 표시됩니다.


image-94.png 


그러나 blackhole.jpg와 같이 존재하지 않는 파일을 시도하도록 구성을 업데이트하면 "슬프게도 벽돌 벽 친구를 맞았습니다!"라는 메시지와 함께 404 응답이 표시됩니다.


이제 이런 식으로 try_files 지시문을 작성할 때 문제는 어떤 URL을 방문하든 요청이 서버에서 수신되고 the-nginx-handbook.jpg 파일이 디스크에서 발견되는 한 NGINX가 이를 다시 전송한다는 것입니다. .


try-files.png 


이것이 바로 try_files가 $uri NGINX 변수와 함께 자주 사용되는 이유입니다.


events {

}

http {

    include /etc/nginx/mime.types;

    server {

        listen 80;
        server_name nginx-handbook.test;

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

        try_files $uri /not_found;

        location /not_found {
                return 404 "sadly, you've hit a brick wall buddy!\n";
        }
    }
}

try_files $uri / not_found; 클라이언트가 요청한 URI를 먼저 시도하도록 NGINX에 지시합니다. 해당 항목을 찾지 못하면 다음 항목을 시도하십시오.


이제 http://nginx-handbook.test/index.html을 방문하면 이전 index.html 페이지가 표시됩니다. about.html 페이지도 마찬가지입니다.


image-95.png 


하지만 존재하지 않는 파일을 요청하면 / not_found 위치에서 응답을 받게 됩니다.


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

# HTTP/1.1 404 Not Found
# Server: nginx/1.18.0 (Ubuntu)
# Date: Thu, 22 Apr 2021 20:01:57 GMT
# Content-Type: text/plain
# Content-Length: 38
# Connection: keep-alive

# sadly, you've hit a brick wall buddy!

이미 눈치 채 셨을 수 있는 한 가지는 서버 루트 http://nginx-handbook.test를 방문하면 404 응답을 받게 된다는 것입니다.


이는 서버 루트에 도달 할 때 $uri 변수가 기존 파일과 일치하지 않으므로 NGINX가 대체 위치를 제공하기 때문입니다. 이 문제를 해결하려면 다음과 같이 구성을 업데이트하십시오.


events {

}

http {

    include /etc/nginx/mime.types;

    server {

        listen 80;
        server_name nginx-handbook.test;

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

        try_files $uri $uri/ /not_found;

        location /not_found {
                return 404 "sadly, you've hit a brick wall buddy!\n";
        }
    }
}

try_files 작성 $uri $uri / /not_found; 먼저 요청 된 URI를 시도하도록 NGINX에 지시하고 있습니다. 그래도 작동하지 않으면 요청 된 URI를 디렉터리로 시도하고 NGINX가 디렉터리로 끝날 때마다 자동으로 index.html 파일을 찾기 시작합니다.


이제 서버를 방문하면 index.html 파일이 제대로 표시됩니다.


image-95.png 


try_files는 다양한 변형에서 사용할 수 있는 일종의 지시문입니다. 다음 섹션에서는 몇 가지 다른 변형을 만나게 될 것이지만 이 지침의 다른 사용법에 대해 인터넷에서 직접 조사해 보는 것이 좋습니다.


NGINX에 로그 


기본적으로 NGINX의 로그 파일은 /var/log/nginx에 있습니다. 이 디렉토리의 내용을 나열하면 다음과 같은 내용이 표시 될 수 있습니다.


ls -lh /var/log/nginx/

# -rw-r----- 1 www-data adm     0 Apr 25 07:34 access.log
# -rw-r----- 1 www-data adm     0 Apr 25 07:34 error.log

두 파일을 비우는 것으로 시작하겠습니다.


# delete the old files
sudo rm /var/log/nginx/access.log /var/log/nginx/error.log

# create new files
sudo touch /var/log/nginx/access.log /var/log/nginx/error.log

# reopen the log files
sudo nginx -s reopen

다시 열기 신호를 NGINX로 보내지 않으면 이전에 열린 스트림에 로그를 계속 기록하고 새 파일은 빈 상태로 유지됩니다.


이제 액세스 로그에 항목을 만들려면 서버에 요청을 보냅니다.


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

# HTTP/1.1 200 OK
# Server: nginx/1.18.0 (Ubuntu)
# Date: Sun, 25 Apr 2021 08:35:59 GMT
# Content-Type: text/html
# Content-Length: 960
# Last-Modified: Sun, 25 Apr 2021 08:35:33 GMT
# Connection: keep-alive
# ETag: "608529d5-3c0"
# Accept-Ranges: bytes

sudo cat /var/log/nginx/access.log 

# 192.168.20.20 - - [25/Apr/2021:08:35:59 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.68.0"

보시다시피 access.log 파일에 새 항목이 추가되었습니다. 서버에 대한 모든 요청은 기본적으로 이 파일에 기록됩니다. 그러나 access_log 지시문을 사용하여 이 동작을 변경할 수 있습니다.


events {

}

http {

    include /etc/nginx/mime.types;

    server {

        listen 80;
        server_name nginx-handbook.test;
        
        location / {
            return 200 "this will be logged to the default file.\n";
        }
        
        location = /admin {
            access_log /var/logs/nginx/admin.log;
            
            return 200 "this will be logged in a separate file.\n";
        }
        
        location = /no_logging {
            access_log off;
            
            return 200 "this will not be logged.\n";
        }
    }
}

/admin 위치 블록 내의 첫 번째 access_log 지시문은 NGINX에 이 URI의 모든 액세스 로그를 /var/logs/nginx/admin.log 파일에 쓰도록 지시합니다. / no_logging 위치 내의 두 번째는 이 위치에 대한 액세스 로그를 완전히 끕니다.


구성을 확인하고 다시로드 합니다. 이제 이러한 위치로 요청을 보내고 로그 파일을 검사하면 다음과 같은 내용이 표시됩니다.


curl http://nginx-handbook.test/no_logging
# this will not be logged

sudo cat /var/log/nginx/access.log
# empty

curl http://nginx-handbook.test/admin
# this will be logged in a separate file.

sudo cat /var/log/nginx/access.log
# empty

sudo cat /var/log/nginx/admin.log 
# 192.168.20.20 - - [25/Apr/2021:11:13:53 +0000] "GET /admin HTTP/1.1" 200 40 "-" "curl/7.68.0"

curl  http://nginx-handbook.test/
# this will be logged to the default file.

sudo cat /var/log/nginx/access.log 
# 192.168.20.20 - - [25/Apr/2021:11:15:14 +0000] "GET / HTTP/1.1" 200 41 "-" "curl/7.68.0"

반면에 error.log 파일은 실패 로그를 보유합니다. error.log에 항목을 만들려면 NGINX 충돌을 만들어야 합니다. 이렇게 하려면 다음과 같이 구성을 업데이트하십시오.


events {

}

http {

    include /etc/nginx/mime.types;

    server {

        listen 80;
        server_name nginx-handbook.test;

        return 200 "..." "...";
    }

}

아시다시피 return 지시문은 두 개의 매개 변수 만 사용하지만 여기서는 세 개를 제공했습니다. 이제 구성을 다시로드 하면 오류 메시지가 표시됩니다.


sudo nginx -s reload

# nginx: [emerg] invalid number of arguments in "return" directive in /etc/nginx/nginx.conf:14

오류 로그의 내용을 확인하고 메시지도 여기에 있어야 합니다.


sudo cat /var/log/nginx/error.log 

# 2021/04/25 08:35:45 [notice] 4169#4169: signal process started
# 2021/04/25 10:03:18 [emerg] 8434#8434: invalid number of arguments in "return" directive in /etc/nginx/nginx.conf:14

오류 메시지에는 수준이 있습니다. 오류 로그의 알림 항목은 무해하지만 비상 또는 긴급 항목은 즉시 처리해야 합니다.


8 가지 수준의 오류 메시지가 있습니다.


  • debug – 문제가 어디에 있는지 확인하는 데 도움이 되는 유용한 디버깅 정보입니다.
  • info – 읽을 필요는 없지만 알아두면 좋은 정보 메시지입니다.
  • notice – 주목할만한 정상적인 일이 발생했습니다.
  • warn – 예상치 못한 일이 발생했지만 걱정할 필요가 없습니다.
  • error – 무언가 실패했습니다.
  • crit – 비판적으로 해결해야 할 문제가 있습니다.
  • alert – 프롬프트 조치가 필요합니다.
  • emerg – 시스템이 사용할 수 없는 상태이며 즉각적인 주의가 필요합니다.


기본적으로 NGINX는 모든 수준의 메시지를 기록합니다. error_log 지시문을 사용하여 이 동작을 재정의 할 수 있습니다. 경고 할 메시지의 최소 수준을 설정하려면 다음과 같이 구성 파일을 업데이트하십시오.


events {

}

http {

    include /etc/nginx/mime.types;

    server {

        listen 80;
        server_name nginx-handbook.test;
	
    	error_log /var/log/error.log warn;

        return 200 "..." "...";
    }

}

구성의 유효성을 검사하고 다시로드 하면 지금부터 경고 수준 이상의 메시지 만 기록됩니다.


cat /var/log/nginx/error.log

# 2021/04/25 11:27:02 [emerg] 12769#12769: invalid number of arguments in "return" directive in /etc/nginx/nginx.conf:16

이전 출력과 달리 여기에는 알림 항목이 없습니다. emerg는 warn보다 높은 수준의 오류이므로 기록 된 것입니다.


대부분의 프로젝트에서는 오류 구성을 그대로 두는 것이 좋습니다. 내가 가진 유일한 제안은 경고 할 최소 오류 수준을 설정하는 것입니다. 이렇게 하면 오류 로그에서 불필요한 항목을 볼 필요가 없습니다.


그러나 NGINX에서 사용자 지정 로깅에 대해 자세히 알아 보려면 공식 문서에 대한이 링크가 도움이 될 수 있습니다.


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