오늘은 웹서버인 Nginx에 대해서 정리해 보도록 하겠습니다.

1. NGINX 의 용도

주로 NodeJS같은 웹 애플리케이션 앞에 배치되어 사용되어 지는 NGINX는 주로 어떻게 사용되어 지는 것 일까요?

개인적으로 주요 용도는 아래 두가지를 볼 수 있을 것 같습니다.

 

1-1. 정적인 리소스를 Serve해 주는 것

유저로부터 어떠한 요청이 들어왔을 때,

이미지나 CSS같은 정적인 리소스(Static Content)에 대한 request들을 NGINX에게 맏기고,

동적으로 계산되거나 전달되어야 하는 것들은 NodeJS같은 애플리케이션 서버에게 맡깁니다.

마지막으로 데이터베이스에 대한 리퀘스트들을 위해서 DB서버를 사용하는 것이지요.

이렇게 분할해서 보다 효율적으로 서버를 관리하는 용도로 NGINX를 사용합니다.

 

1-2. Reverse Proxy Server로서 Request와 Response를 중개해 주는 것

Reverse Proxy Server로서 Request와 Response를 중개하는 Proxy서버로 동작하게 할 수 있는데요.

(Reverse Proxy Server에 대한 개념은 아래에서 정리하였습니다.)

여기에 플러스해서, NodeJS보다 더 강력한 보안이나 가속화 기능등을 추가적으로 적용할 수 있습니다.

 

위에서 정리한 용도로 사용하기 위해서 알아야 하는 개념들과,

적용 방법들에 대해서 이 글에서 정리해 보도록 하겠습니다.

 

2. NGINX와 관련된 개념들

2-1. Reverse Proxy

Reverse Proxy를 이해하기 위해서, 먼저 Forward Proxy의 도표를 보도록 하겠습니다.

왼쪽이 사용자들의 컴퓨터 인데요.

사용자가 Request를 보내면, Forward Proxy서버인 B가 받아서,

해당 Request를 C로 보내주고, C에서 받은 Response를 B가 다시 A에게 전달해 주는 것이 Forward Proxy의 흐름인데요.

 

이렇게 ForwardProxy는 회사나 특정기관에서,

firewall을 세워서 Internet접속에 제한을 두어 일부 인터넷만 사용하도록 할 때 사용합니다.

보안을 위해서 사용을 제한할 목적으로,

유저들의 컴퓨터가 인터넷에 접속하기 전에, 하나의 Proxy(중계 및 대리인)를 세워 두는 것 이지요.

Forward Proxy가 유저 컴퓨터들의 중개인으로

유저들의 행동을 보안 감독하기 위해서 사용되었다면,

Reverse Proxy는 아래 이미지 처럼,

어떤 서버에 request를 보낼지 중개인인 Proxy서버를 세워서

효율적이면서 좀더 안전하게 Request와 Response를 관리하기 위함에 있습니다.

중요한 행동을 하거나 데이터를 가지고 있는 서버에 도달하기전,

하나의 레이어가 생김으로서 보안적으로도 더욱 강해질 수 있는 것 이지요.

 

 

쉬운 애기를 장황하게 설명한 것 같은 느낌이 드는데요.

결국 서버들 앞에 중개 대리인(Proxy)을 하나 두어서,

Request와 Response를 릴레이 해주는 것 이구요.

Nginx를 이러한 proxy로 세워두고 사용하는 것 입니다.

 

2-2. Upstream 과 DownStream

네트워크에서 주고 받는 Request와 Response의 데이터를 흐르는 강물에 비유해 보겠습니다.

Upstream의 뜻은 강의 상류이구요. DownStream은 하류인데요.

 

데이터의 패킷의 흐름을 물과 비교해서 표현하면,

물이 흘러 내려가서 받는 곳이 DownStream(하류)이고,

윗쪽에서 물을 흘러 내려보내는 곳이 UpStream(상류)라고 하는 것입니다.

 

강물과 네트워크에서의 차이점이 있다면,

자연상태에서는 지형의 차이로인해 이것이 발생하기에,

상류인곳은 영원히 상류이고, 하류인 곳은 지형이 바뀌지 않는 한 영원히 하류인데요.

컴퓨터세상에서는 데이터를 보내는 쪽에서 흘러나가는 흐름이 Upstream이고,

데이터를 받는 쪽에서의 받는 흐름이 DownStream이 되므로,

어느하나가 영원히 Upstream일 수는 없습니다.

 

우리가 보통 어떤 파일을 다운로딩한다고 하는데요.

유저입장에서는 서버는 Upstream서버이고,

서버로부터 흘러나오는 데이터를 받는 것은 DownStream인 것 이지요.

 

아래는 간단한 nginx의 설정파일인 ngix.conf인데요.

"127.0.0.1"즉, 자신의 Localhost의 8000과 8001, 8002, 8003번 포트에

각각 upstream서버로서 http프로토콜의 리퀘스트를 보낸다는 의미입니다.

 

 

3. nginx.conf

Nginx와 그 모듈들이 동작하는 방식은 ConfigurationFile에 의해서 결정되는데요.

nginx.conf파일이 그것입니다.

이것의 위치는 아래 세가지 중 하나인데요.

설치방법에 따라서 디렉토리의 위치가 바뀌게 됩니다.

일반적으로 많이 사용하는 apt-get을 이용할 경우는 첫번째 "/etc/nginx"에서 찾을 수 있구요.

  • /etc/nginx
  • /usr/local/nginx/conf
  • /usr/local/etc/nginx.

위치를 잘 몰라서,

linux의 find명령어로 찾고자 한다면 아래 명령어를 이용해 주면 됩니다.

sudo find / -name nginx.conf

 

이 nginx.conf파일은 root계정만 수정이 가능하기 때문에,

수정하려고 접근할 때는 root계정이거나 su를 붙여주어야 합니다.

 

이제 nginx.conf파일을 설정해 보도록 하겠습니다.

여기서 설정할 값들은 아래 공식문서의 링크에서도 참조할 수 있습니다.

http://nginx.org/en/docs/ngx_core_module.html

 

3-1. work_processes

nginx의 실행가능한 worker 프로세스의 수를 지정해 줄 수 있습니다.

nginx는 master와 worker프로세스로 구성되어 지는데요.

공식문서에 의하면, 최적값은 cpu core에서부터 하드드라이브등 여러가지 요소에 의해서 결정되어 지는데요.

auto로 설정하면 자동으로 이 값을 찾아준다고 합니다.

worker_processes auto;

 

3-2. worker_rlimit_nofile

Worker process들에서 최대로 열린 파일들의 수를 제한할 수 있습니다.

이 수가 클수록 메인 프로세스를 재시작 할 필요가 없어진다고 합니다.

대신 열려 있는 파일의 수만큼 서버에 부하가 가겠지요.

worker_rlimit_nofile 65535;

 

 

3-2. events 블록내의 설정 값들

events 블록은 connection processing에 관한 설정 값들을 정의하는 곳 인데요.

자주쓰는 설정들을 보도록 하겠습니다.

 

A. worker_connections

events블록 내에서 설정하는 worker connections를 설정할 때는

proxy서버를 통해 연결된 커넥션들을 포함한 클라이언트들의 모든 커넥션들의 숫자를 고려해야 하구요.

 

잊지말아야 할 것은, 위에서 지정한,

worker_rlimit_nofile의 수를 넘어서면 않된다는 것 입니다.

events {
  worker_connections 65534;
}

 

B. use epoll

connection processing method를 정합니다.

standard는 select인데요. 조금더 효율적으로 바뀐 것이 epoll방식이라고 하는군요.

events {
  worker_connections 65534;
  use epoll;
}

 

C. multi_accept

off로 되어있으면, worker프로세스는 한번에 하나의 커넥션만을 허용합니다.

on으로 되어있다면, 모든 새로운 커넥션을 한번에 다 허용할 수 있습니다.

events {
  multi_accept on;
}

 

아래 단원에서 가장 중요하다고 할 수 있는,

nginx.conf파일 내의 HTTP블록의 설정에 관해서 정리해 보겠습니다.

 

4. Http블록

nginx에는 http와 관련된 여러가지 모듈이 있는데요.

이와 관련된 설정을 하는 곳 입니다.

 

4-1. Upstream

upstream 지시어는 upstream서버에 대해서 설정하기 위한 것인데요.

인자로 설정할 upstream서버의 이름을 넣어주면 됩니다.

서버들은 TCP이든 UNIX 도메인 소켓이든 모두 listen할 수 있습니다.

 

아래에서는 backend라는 이름으로, 내부의 nodeJS의 3000포트 서버로 연결시켜 주도록 하였네요.

keepalive를 하는 이유는 proxy서버로부터, 다시 로컬의 nodejs서버로 연결될 때,

접속이 다시 생성됨으로 인한 비효율을 막기 위해서 입니다.

upstream backend {
  server 127.0.0.1:3000;
  keepalive 32;
}

 

 

http의 keepalive에 대해 잘 모르시는 분들을 위해서 간단히 정리하자면,

원래 http는 원래 데이터 전송을 받기 위해 서버에 접속해서 받은 다음,

connection을 끊어버리는데요.

예외적으로 connection을 유지하도록 일정시간을 인자값으로 주는 것 입니다.

대신 이 시간만큼의 동시접속자 수가 늘게 되므로,

서버의 Capacity를 고려해 주어야 겠지요.

 

4-2. types

request의 MIME 타입들에 대해 파일이름을 매칭시켜줍니다.

확장자는 대소문자 구분하지 않구요.

 

아래 github에서 다양한 Mime타입들을 볼 수 있습니다.

https://github.com/nginx/nginx/blob/master/conf/mime.types

 

마지막 라인에서와 같이 default_type도 설정해 줄 수 있습니다.

 

types {
    application/octet-stream bin exe dll;
    application/octet-stream deb;
    application/octet-stream dmg;
    
    default_type application/octet-stream;
}

 

4-3. include와 default_type

core_module에 있는 설정으로,

include는 다른 파일을 가져올 수 있습니다.

아래의 mime.types와 같이 위에서 정의한 types를 파일로 빼내서,

include지시어를 이용해 가져올 수 있는 것 이지요.

아래에서는 types의 default_type도 정의해 주었네요.

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

 

 

4-4. keepalive_timeout 

위에서 upstream에 대해 보면서, keepalive에 대해 알아보았는데요.

keepalive로 무한정 접속을 연결시켜 놓다보면,

서버를 사용하지 않는 혹은 못하는 Connection까지 모두 keep하고 있으므로 자원의 손실이 발생하게 되는데요.

그래서 keepalive_timeout를 이용해서, 일정시간이 지나도록 요청이 없으면 Connection을 끊도록 할 수 있습니다.

 

인자로 들어간 숫자는 keepalive 클라이언트 커넥션을 열어둘 시간을 적는 것인데요.

아래에서는 5초를 설정하였습니다. 5초내에 다른 request가 없으면, Connection은 끊어집니다.

0으로 넣는다면 disable 시키는 것과 같습니다.

keepalive_timeout 5;

 

4-5. reset_timedout_connection

timed out커넥션을 리셋할 것인지에 대한 여부를 on또는 off시킬 수 있습니다.

디폴트 값은 off이구요.

timed out된 keep-alive커넥션은 클로즈드되게 됩니다.

reset_timedout_connection on;

 

4-6. gzip

최근의 브라우저들이 거의 다 gzip을 지원하고 있기 때문에, text데이터들을 압축해서 전송해주는 gzip을 쓰는 것이 좋겠지요.

gzip과 관련된 사항은 ngx_http_gzip_module에 정의되어 있는데요.

다음과 같은 값들을 설정할 수 있습니다.

 

A. gzip_min_length

압축할 최소 길이인데요. Content-Length헤더에 기록된 값과 비교하여서 압축할지를 정합니다.

default는 20byte로 되어 있습니다.

 

B. gzip_comp_level

압축레벨을 말합니다. 보통 3~4정도가 적당하다고 합니다.

너무 높으면 서버에 무리가 오기때문이에요.

 

C. gzip_types

압축할 타입에 대해서 정의하는 것 입니다. text/plain이나 application/json같은 타입을 정의해서 사용합니다.

 

D. gzip_proxied

nginx가 proxy서버로서 동작할 때 압축을 할 것인지에 대한 설정 인데요.

nginx는 request헤더 필드의 Via 값을 보고, proxy서버로서 동작하는 지를 판단합니다.

디폴트값은 off인데요.

 

아래 코드의 expired 는 response헤더에 Expires필드 값이 있을 때 압축하라는 이야기이구요.

no-cache, no-store, private은 response헤더에 Cache-Control이 no-cache, no-store, private일 때 압축하라는 것 입니다.

auth는 request헤더값이 Authorization필드를 가지고 있을 때 압축하라는 것 이구요.

 

gzip            on;
gzip_comp_level 3;
gzip_min_length 1000;

gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;

gzip_proxied expired no-cache no-store private auth;

 

 

4-7. client_body_timeout

client의 request body를 읽을 때의 timeout을 정의합니다.

기본값은 60s로 되어  있습니다.

client가 아무것도 전송하지 않는다면, 408로 request Time-out을 발생시킵니다.

client_body_timeout 25;

 

4-8. send_timeout

client에게 response를 전송할 때의 timeout값을 설정합니다.

여기서 설정한 시간안에 client가 아무것도 전송받지 못하면,

connection이 closed됩니다. 기본값은  60초로 되어 있습니다.

send_timeout 3;

 

4-9. access_log

아래와 같이 access로그에 대한 설정을 할 수 있습니다.

access_log logs/access.log main;

 

하나의 로그레벨에 다양한 파일을 기록할 수 있는데요.

디폴트 값은 "access_log logs/access.log combined;" 인데요.

유저수가 많은 대형 서비스의 경우는 access 로그를 작성하는 것이 부담이 될 수 있으므로,

off로 해놓는 것도 생각해 볼수 있는 옵션입니다.

access_log off;

 

아래에서는 http블록내에서 사용하는 server블록에 대해서 정리해 보도록 하겠습니다.

 

5. server 블록

여기서는 가상 서버에 대해서 정의할 수 있는데요.

ip주소를 기반으로 해도되고, server_name을 기반으로 해도 됩니다.

server블록의 코드가 어떨지 가볍게 한번 보고 가도록 하겠습니다.

 

 

 

server블록에 들어가는 지시어들을 하나씩 보도록 하겠습니다.

5-1. Location

Location은 ngx_http_core_module에 정의되어 있는 중요한 지시어인데요.

request URI에 따른 설정을 하는 곳 입니다.

URI에 대한 매칭은 텍스트 값을 prefix로 하여서 매칭하거나,

주어진 정규식을 이용해서 매칭할 수 있는데요.

 

정규식 패턴에 사용되는 기호를 보면 다음과 같은데요.

=

패턴과 정확하게 일치 할 때 사용. URI검색시 가장 우선순위가 높습니다.

$host정보에 /test.png로 정확하게 매치가 될 때 사용합니다.

하지만, 만약 "=/test"와 같이 사용할 경우,

"$host/test"는 일치하여서 매칭이 되지만, "$host/test/"는 매칭되지 않아버리므로,

주의를 기울여서 사용해야 합니다.

~

대소문자를 구별하여 정규표현식과 일치할 때 사용

보통은 아래의 기호를 더 많이 사용하게 됩니다.

~*

대소문자 구별하지 않고 정규표현식과 일치할 때 사용

ex) location ~* \.(gif|jpg|jpeg)$ {   return 200 "found" }

^~ 지정한 패턴으로 시작할 때 사용.
 

아무기호도 없이 텍스트를 사용하면,  prefix로 사용해서 해당 텍스트로 시작하는 URI를 찾는다.

@name

이름을 붙여서, location 블럭을 정의한다.

내부 요청에 의해서만 접근할 수 있는데요.

아래와 같이 사용될 수 있습니다.

 

location {

    try_files $uri @mylabel; 

}
location @mylabel { return 404 "Not Found"}

 

아래에서는 해당 정규식에 해당하는 경우,

URL의 루트에 /api-server/public을 붙여주구요.

expires와 add_header지시어를 이용해 파일의 헤더를 수정해 주었습니다.

location ~ ^/(images|javascript|js|css|flash|media|static)/  {
  root /api-server/public;
  expires max;
  add_header  Cache-Control public;
}

 

참고로 위에서 사용된 expiresadd_header는 헤더 필드에 “Expires” 와 “Cache-Control”을 추가해 주기 위해 사용되었습니다.

expires max의 의미는 expires와 Cache-Control을 10년으로 설정해 줍니다.

아래는 웹에서 다운로드 받은 어떤 이미지의 cache-control인데요.

위에서 expires max라고 하면 아래와 같이 설정됩니다.

Cache-Control을 public으로 하면, 어떤 응답에 의한 캐시건 Cache된다는 것인데요.

no-cache라고 하면, 캐시된 복사본을 사용자에게 보여주기 전에, 재검증을 위해 요청을 서버로 보냅니다.

 

 

5-2. Header정보 세팅

위에서 expires와 같은 header를 세팅해 보았는데요.

이들은 ngx_http_headers_module에 포함되어 있는데요. 좀 더 알아보도록 하겠습니다.

 

A. 헤더정보 추가

아래와 같이 add_header지시어를 이용해서 expires커스텀한 헤더정보를 추가할 수 있습니다.

location =/test.jpg {
	add_header   expires  modified +24h;
	add_header   custom_header  "custom_header_test"
}

 

5-3. allow and deny

아래의 경우를 보면 182.16.100.0에 대해서만 접근을 허락하고,

나머지에서 접근하면 모두 deny시켰습니다.

따라서 해당하지 않는 ip에서 접근할 경우에는 403 forbidden 을 return해 줍니다.

server {
      listen   80;
      server_name .internal.io;

      location /private {
	      allow 182.16.100.0/8;
    	  deny all;
      }
}

 

 

5-4. server_name

ngx_http_core_module에 정의되어 있는 server_name은

가상 서버의 이름을 정할 때 사용합니다.

 

첫번째 이름이 primary서버 네임이 되는데요.

server { 
	server_name example.com www.example.com; 
}

 

아래와 같이 하면, 앞에 test.example.com같은 이름과 단순한 example.com도 사용할 수 있습니다.

아무래도 아래와 같은 형태로 많이 사용하게 되겠지요.

 

server {
    server_name .example.com;
}

 

필요할 경우는 정규식을 server_name에 사용할 수도 있는데요.

이때는 위의 location에서 했던 것처럼, "~"을 앞에 붙여 줍니다.

 

5-5. listen

listen은 IP를 위한 address와 port번호를 설정할 수 있구요.

UNIX도메인을 위한 path를 설정해 줄 수도 있습니다.

아래와 같은 설정이 모두 가능한데요. port번호가 적혀있지 않을때는 80포트를 listen하게 됩니다.

listen 127.0.0.1:8000;
listen localhost:3000;
listen 127.0.0.1;
listen 443; #for https
listen *:8000;

IPv6 주소도 아래와 같이 사용할 수 있습니다.

listen [::]:8000;
listen [::1];

 

5-6. SSL관련한 설정

ssl관련해서 아래와 같이,

인증서와 private key와 timeout을 설정해 줄 수 있습니다.

server {
   ssl_certificate      cert/example.com.chained.crt;
   ssl_certificate_key  private/example.com.key;
   ssl_session_timeout  60;
}

 

5-7. rewrite하는 방법

nginx에서 rewrite를 하는 방법으로는,

지시어인 rewrite를 하는 방법과 return을 하는 두가지 방법이 있는데요.

되도록 return을 사용하는 것을 권장한다고 합니다

 

A. return

return을 사용하면 processing을 멈추고, code가 주어지면 해당 코드와 함게 client에게 return 해 줍니다.

return code
return code URL
return URL

실제 return으로 작성한 코드를 보겠습니다.

 

참고로, nginx에서 $scheme변수는 http인지 https인지를 나타내 주고요.

$request_uri는 뒤에 변수들이 붙어있는 request URI를 의미합니다.

예를들면, "www.oldDomain.com/test?score=88"에서 .com 뒷부분을 의미합니다.

301은 Moved Permanently(영원히 이동)을 의미합니다.

server {
    listen 80;
    listen 443 ssl;
    server_name www.oldDomain.com;
    return 301 $scheme://www.newDomain.com$request_uri;
}

 

 

특히 3xx로 code를 return하려면 이도한 url을 인자로 꼭 넣어주어야 겠지요.

이외의 1xx, 2xx, 4xx, 5xx code로 return하는 경우라면 url은 꼭 필요하지는 않은데요.,

response의 body에 아래와 같은 방법으로 text를 전달할 수도 있습니다.

예를 들어서, 유효하지 않은 인증 token을 가지고 있는 클라이언트에게, 아래와 같이 보낼 수 있겠지요.

return 401 "token이 expire되어서 접근이 제한되었습니다."

 

이번에는 http로 들어오는 url을 모두 https로 이동시켜 보겠습니다.

301코드와 함께 심플하게 할 수 있었습니다.

server {
	listen 80;
	server_name .test.com;
	location / {
    	return 301 https://$host$request_uri;
    }
}

 

B. rewrite

rewrite은 server, location, if블록에서 사용할 수 있는데요.

다음과 같은 문법을 따릅니다.

마지막 flag값으로는 last, break, redirect, permanent가 있습니다.

마지막 permanent의 값은 301코드와 함께, 영원히 redirect시키는 flag입니다.

rewrite 정규식 변경될url <옵셔널한 flag>

 

다음과 같이 location블록을 사용한다면,

"https://test.com"과 그 뒤에 붙어있는 uri를 영원히 이동시키는 것으로 되어 있습니다.

위에서 return문으로 했던 것 처럼,

http로 들어온 request를 https로 보내주고 있습니다.

위에서 언급했던 것처럼, 가능하면 return 문을 사용하는 것이,

정규식을 사용하는 rewrite보다는 효율적이라고 합니다.

listen 80;
server_name .test.com;
server {
  location / {
      rewrite  ^ https://test.com$request_uri permanent;
  }
}

 

5-8 proxy_pass

proxy_pass는 ngx_http_proxy_module에 정의되어 있는데요.

nginx가 proxy로서 동작할 때,

request를 중계받는 서버의 protocol과 address 그리고 location에 매핑될 URI를 설정합니다.

protocol에서는 http혹은 https인지를 정해주어야 하구요.

address는 domain name이나 ip주소와 port를 정해 주면 됩니다.

아래코드에서는 http://backend/care 로 위에서 정리해 보았던,

upstream서버인 backend로 보내주었습니다.

upstream backend {
  server 127.0.0.1:3000;
  keepalive 32;
}
server {
  listen 80;
  server_name test.com;
  location /care {
    proxy_pass http://backend/care
    proxy_http_version 1.1;
    proxy_set_header Connection "";
  }
}

 

 

# proxy_set_header

nginx가 proxy로 중계할 때,

중계받는 nodejs같은 서버에 request header를 다시 재정의해서 전달할 때 사용합니다.

host는 nginx의 변수인 $host를 사용하면 되구요.

이외의 header는 아래와 같이 해주면 됩니다.

참고로, Connection은 upstream서버를 사용하기 위한 설정으로,

필요하지 않으면 사용하지 않아도 됩니다

 

참고로 X-Forwarded-For는 프락시 환경에서, HTTP Server 에 요청한 clinet 의 IP를 식별하기 위한 헤더이구요.

X-Real-IP를 사용하기도 합니다.

X-Forwarded-Proto는 클라이언트가 프록시에 접속할 때, 사용했던 프로토콜(HTTP 또는 HTTPS)이 무엇인지 확인하는 헤더입니다.

upstream backend {
  server 127.0.0.1:3000;
  keepalive 32;
}
server {
  listen 80;
  server_name test.com;
  location /care {
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Connection "";
    proxy_http_version 1.1;
     
    proxy_pass http://backend/care 
  }
}

 

5-9. try_files

try_files는 인자로 해당 파일을 찾을 수 있는 몇개의 path들을 넣을 수 있는데요.

먼저 정의된 path부터 해당 파일이 있는지 찾아서, request 요청을 처리하는데 사용합니다.

아래에서는 request할 때 들어온, uri경로에서 찾아보고,

없으면, /images/default.gif로 redirect 해 줍니다.

location /images/ {
    try_files $uri /images/default.gif;
}

 

"$uri"같은 변수를 사용해서 현재 request로 들어온 요청위치에서 찾을 수도 있습니다.

또한 "=404"처럼 code를 마지막 path뒤에 붙여서 사용할 수 있습니다.

아래에서는 uri경로를 먼저 찾고 없으면, 그 하위의 index.html을 찾은다음,

없어므녀 $uri.html을 404코드와 함께 redirect할 수 잇습니다.

location / {
    try_files $uri $uri/index.html $uri.html =404;
}

 

@를 이용해서 labelling을 할 수도 있습니다.

예를 들면, 아래에서는 lastone이라는 label을 붙여서,

try_files 에서 최종 redirection위치로 설정하였습니다.

location {
	try_files $uri @lastone;
	
}

location @lastone {
	return 404 "Not Found"
}

 

 

5-10. 서버버전 숨기기와 more_clear_headers

nginx를 사용하면, Server헤더에 nginx/1.10.1과 같은 정보가 남는데요.

서버의 정보를 숨긴다고 보안이 완벽해지지는 않지만,

가능하다면 하는 것이 좋겠지요.

아래와 같은 코드를 http블록에 추가하면 서버의 버전을 숨길 수 있습니다.

하지만 버전정보를 숨기는 것 만으로는 부족하겠지요.

http {
	server_tokens off;
}

 

 

"headers-more-nginx-module"모듈을 사용하여서 서버 정보를 없애주려고 하는데요.

아쉽게도 기본적으로 nginx와 함께 설치되는 모듈이 아니므로,

따로 설치해 주어야 합니다.

아래 github에서 설치가이드를 볼 수 있구요.

>> https://github.com/openresty/headers-more-nginx-module#more_clear_headers

 

아래와 같이 헤더 정보들을 삭제할 수 있습니다.

more_clear_headers  'Server';
more_clear_headers  'X-Powered-By';
more_clear_headers  'X-Runtime';
more_clear_headers  'ETag';

 

5-11. limit_except

location내부에서 허용하기로 한 HTTP 메소드만 사용하도록 합니다.

아래와 같이, GET메소드를 사용하도록 하면, HEAD메소드도 허가하는 것이 됩니다.

선택할 수 있는 HTTP메소드들은,

GET, HEAD, POST, PUT, DELETE, MKCOL, COPY, MOVE, OPTIONS, PROPFIND, PROPPATCH, LOCK, UNLOCK,  PATCH 등입니다.

limit_except GET {
    allow 192.168.1.0/32;
    deny  all;
}

 

5-12. stub_status

stub_status 지시어를 이용하면,

현재 active한 클라이언트의 접속수 같은, nginx의 status정보를 얻을 수 있습니다.

해당 지시어가 들어있는 모듈은 기본 모듈에 의해서 빌드되지 않기 때문에,

--with-http_stub_status_module 로 enable시켜 주어야 합니다.

 

아래에서는 basic_status로 접근해오면 기본적인 status정보를 보여주도록 하였는데요.

내부망에서만 접속되도록 allow와 deny를 설정하였습니다.

server {
	location /basic_status {
        stub_status on;
        allow 127.0.0.1;
        deny all;    
    }
}

 

5-13. charset

특정한 charset을 response헤더에 값으로 넣어 줍니다.

아래에서는 utf-8을 사용하여 주었습니다.

server {
   charset utf-8;
}

 

6. 용도에 따른 Server 설정

위에서 nginx.conf파일을 설정하는 방법들을 알아보았는데요.

이번에는 nginx의 용도에 따라서 server를 설정해 보면서,

위에서 했던 것들을 다시 정리해 보도록 하겠습니다.

6-1. static Content 적용

A. 디렉토리 구조

만약 아래의 위치들에 html파일과 image파일이 있다고 가정해 보겠습니다.

/data/www index.html 파일이 존재
/data/images 이미지 파일들이 존재

 

B. nginx.conf

먼저 nginx.conf파일을 열어서,  아래와 같이 http블록과 server블록 아래에,

"/" 접두어에 대한 location블록을 아래와 같이 설정해 줍니다.

이것은 request의 URI가 "/"로 시작하는 경우에 파일을 연결시키기 위해서,

root인 "/data/www"를 URI에 붙여줍니다.

참고로 "/"는 가능한 가장 짧은 접두어가 될 텐데요.

다른 route를 다 찾아보고 없으면 마지막으로 여기로 보내주겠지요.

 

그러니까, 유저가 test.com으로 접근한 경우에,

nginx가 해당 정적파일과 연결시켜주기 위해서,

root인 "/data/www"를 URI에 붙여주어서, index.html파일로 연결시켜 주는 것 이지요.

 

http {
    server {
    	location / {
 		   root /data/www;
		}
    }
}

 

위에서는 image파일들도 있으므로,

여기도 routing을 해 주어야 겠습니다.

아래와 같이 location키워드 뒤에, 접두어를 "/images/"로 적어주고,

root를 적어주면, 마찬가지로 요청할 때 들어온 URI에 /data를 붙여서

"/data/images/파일"로 연결시켜 주는 것 이지요.

 

http {
    server {
    	location / {
 		   root /data/www;
		}
        
        location /images/ {
        	root /data;
    	}
    }
}

 

 

현재는 호스트주소나 포트는 적어주지 않은 상태인데요.

이때는 "http://localhost/"에 포트는 80으로 매칭되어 집니다.

 

만약 요청한 파일이 없다면 404 error를 발생시킵니다.

그리고 만약 /images/가 매칭되지 않는 모든 URI는 전부

첫번째 location키워드로 정의했던,

/data/www/를 URI에 붙여서 접근하게 됩니다.

 

6-2. Proxy Server 적용

Nginx는 Reverse Proxy Server로 많이 사용되어 지는데요.

정적인 리소스, 다이내믹한 Request, DB Request등을 구분해서

각각에 맞는 서버에 요청을 하게 되겠지요.

아래 코드와 같이, server블록을 열고, 포트와 root를 적어줍니다.

이번에는 8080포트를 listen하구요. (위에 적어준대로 port 정의하지 않으면 80포트가 디폴트로 listen됩니다.)

 

들어오는 request들은 모두 "/data/up1"을 URI에 붙여줍니다.

server {
    listen 8080;
    root /data/up1;

    location / {
    }
}

 

그래픽 확장자가 이미지 파일로 끝나는 파일에 대해서는 아래와 같이,

uri에 "/data/images"를 붙여서 연결시켜주는데요.

한가지 참고할 것은 정규표현식을 쓸때는 아래와 같이,

"~ "로 시작해서 정규표현식을 기술해 주어야 한다는 점 입니다.

 

Request중 나머지 "/"로 시작되는 URI들은

proxy_pass라는 키워드를 이용해서 proxy서버로서

localhost의 3000번 포트로 연결시켜 줍니다.

예를 들면, 내부 네트워크의 nodejs가 3000 포트를 listen하고 있고 그곳으로 연결시킬 수 있겠지요.

 

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

    location ~ \.(gif|jpg|png)$ {
        root /data/images;
    }
}

 

이렇게 설정을 다 바꾸었다면, 꼭 nginx를 reload시켜 주어야 합니다.

 

7. NGINX에서 URL에 따른 변수들

아래와 같은 URL이 있다고 가정해 보겠습니다.

http://example.com/score/index?type=number&id=68

이 URL을 기반으로 NGINX에서 사용할 수 있는 변수들이 있는데요.

그 중에서도 많이 사용하는 것들은 아래 값들이 있습니다.

 

7-1. $host, $uri, $args

$host변수는 서버의 IP나 도메인을 가르킵니다.

그리고 $uri변수에는 호스트명과 파라미터는 제외됩니다.

$args는 아래와 같지만, 만약, type변수만을 알고 싶을 때는,

$args_type으로 접근할 수도 있습니다.

$host : example.com
$uri : /score/index
$args : type=number&id=68

 

 

7-2. $server_addr, $server_name, $server_port

server와 관련된 다음 변수들도 많이 사용되는데요.

각각 주소나 네임 및 포트번호를 가지고 있습니다.

 

  • $server_addr : 서버주소
  • $server_name: 서버네임
  • $server_port: 서버의 포트

 

 

이 밖에도 많은 변수가 있는데요.

아래의 공식문서 링크에서 접근할 수 있는 모든 변수들이 나와있습니다.

http://nginx.org/en/docs/varindex.html

 

 

8. 실행과 정지 및 Reload

nginx를 실행하는 방법은 간단한데요.

nginx가 설치되어 있는 폴더에서 nginx를 실행해 주면 됩니다.

예를 들면, /usr/bin폴더에 설치되어 있다면 아래와 같이 해주면 되는 것 이지요.

/usr/bin/nginx

 

nginx가 실행되고 나면, 다음과 같은 규칙을 따르는데요.

nginx -s <stop이나 quit같은 시그널 키워드>

 

여기서 사용할 수 있는 시그널 키워드는 다음과 같은 것들이 있습니다.

  • stop — fast shutdown
  • quit — graceful shutdown
  • reload — reloading the configuration file
  • reopen — reopening the log files

 

한가지 주의할 것은, 위의 시그널 키워드 명령어는

nginx를 start한 유저로부터 시작되어야 한다는 점 입니다.

예를 들어, configuration file을 변경하고 나서, 적용시키기 위해 reload하기 위해서는,

아래와 같이 해 주면 되겠지요.

nginx -s reload

 

9. Log나 ErrorLog파일의 위치

Nginx의 Log파일은 access.log이구요.

ErrorLog파일은 error.log 인데요.

위치는 각각 "/usr/local/nginx/logs" 또는 "/var/log/nginx" 에 위치하고 있습니다.

 

이상으로 NGINX에 대해서 정리해 보았는데요.

더 좋은 방법이나 설명이 있다면 이 글에서 업데이트 하도록 하겠습니다.

728x90

'NGINX' 카테고리의 다른 글

NGINX에 대한 정리 #Upstream #Reverse Proxy #Proxy_pass  (0) 2020.04.21

+ Recent posts