nginx

What is NGINX

일반적으로 webserver라 하면 http 요청이 들어오면 필요한 작업을 수행하는 서버를 의미합니다.

즉, 브라우저에서 읽을 수 있는 html 파일 등을 전달해 주는 역할을 합니다.

하지만 단순한 정적파일의 제공으로는 동적 파일 렌더링등을 수행할 수 없기 때문에 webserver는 요청을 받으면 웹서버에서 요청을 받아 그 요청을 외부 프로그램에 넘겨주면, 외부 프로그램이 프로그램 파일을 읽어 html로 반환하는 단계를 거치게 되며, 이것을 CGI 라고 합니다.

대표적인 CGI 로는 php fpm 등이 있습니다.

* FAST CGI(Common Gateway Interface) 란 무엇인가?

FastCGI는 상호 작용 프로그램을 웹 서버와 통신하기 위한 바이너리 프로토콜이다.

FastCGI는 초기 공용 게이트웨이 인터페이스(CGI)의 변형이다.

FastCGI의 주 목적은 웹 서버와 CGI 프로그램 간 통신 시 발생되는 부하를 줄임으로써 서버가 한 번에 더 많은 웹 페이지 요청을 관리할 수 있게 하는 것이다.

* php-fpm

nginx가 요청을 받아 php인 경우 cgi 인 php fpm에게 요청을 전달하고 거기서 php 코드를 실행한 뒤에 요청을 다시 받아온다.

Forward Proxy & Reverse Proxy

NGINX 는 Web Server 로써 일반적으로 기업에서 서비스를 배포할 때 reverse proxy server의 역할을 수행한다.

Nginx 에 대해 설명하기 전에 먼저 forward proxy 와 reverse proxy의 개념부터 설명하고자 한다.

먼저, forward proxy server란 사용자가 원하는 정보를 좀 더 빨리 받게 하기 위해 중간에 요청을 가로채는 것이라 볼 수 있다. 가령 target.com 이라는 주소로 어떤 정보를 받아오고 싶은 유저가 있다고 생각해 보자.

이 유저는 주소창에 target.com 을 입력하고 데이터를 받아올 것이며, 이 유저는 자신이 보고 있는 정보가 target.com 에서 보낸 정보라고 생각할 것이다. 하지만 대부분의 경우 유저가 받아온 정보는 실제로 target.com에 있는 정보가 아닌 중간의 프록시 서버에서 이전에 받아놓은 target.com 의 정보를 전달해 주는 것이다.

이러한 proxy server 는 많은 이점을 제공해 주는데, 가령 우리가 목적으로 하는 target.com 의 경우 우리의 ip 주소에 대해서는 알수가 없고, 우리가 사용하는 proxy 서버의 url 에 대해서만 알 수 있다.(하지만 대부분의 경우 browser가 우리의 정보를 제공하기 때문에 사실상은 다 알수 있다..!)

또한, proxy server 는 이미 알고 있는 정보에 대해서 해당 데이터를 cache 하기 때문에 추가적인 요청 없이 바로 우리에게 원하는 정보를 전달해주기 때문제 네트워크 속도의 관점에서도 더욱 빠르게 동작한다.

NGINX 는 이러한 forward proxy 의 기능도 수행할 수 있지만, 대부분의 경우 reverse proxy 의 용도로 사용되는데, 이는 http server 의 보안 문제 해결과 로그 수집 등 여러 이점을 가지기 때문에 사용된다.

가령, 사용자는 proxy.com 이라는 url 로 요청을 주고 실제 서버의 위치인 target.com url 을 유저로 부터 접근을 불가능 하게 막고, 해당 서버를 VPN 에 구성함으로써 보안을 높일 수 있다.

How does it works?

NGINX 서버는 nginx 그룹의 nginx 라는 유저로 모든 프로세스를 실행한다.

요청이 들어오면 nginx 는 해당 요청의 hostname 을 보고 설정된 서버들 중 어떤 서버를 사용할지 선택한다.

NGINX 에는 다양한 서버 설정을 할 수 있으며 이는 /etc/nginx/conf.d/ 디렉토리에 수많은 conf 파일의 설정들 중에 어떤 서버 설정을 사용할지 결정하는데 있어 hostname 을 사용한다.

여기서 일치하는 hostname이 있다면 해당 설정대로 serving 하되, 만약 일치하는 hostname 이 없다면 default server 를 사용하며 이는 다음과 같이 server 에서 listen 하는 설정에 default_server 태그가 붙어있는 서버를 선택한다.

1
2
3
4
server {
listen 80 default_server;
server_name example.net www.example.net;
}

어떤 서버로 부터 serving 할지 결정되었다면, nginx 는 url 패스를 읽어들이고 이를 location 과 비교하여 일치하는 리소스를 찾는 작업을 거치게 된다. 때문에, nginx 에는 여러개의 location 을 설정할 수 있으며, 이 중에서 가장 긴 location path를 우선적으로 선택하게 된다.

1
2
3
4
5
6
7
server {
server_name localhost

location /path {
root /var/www/example;
}
}

Where to save resources

서버란 특정 리소스를 제공해주는 역할을 하며, 때문에 서버가 제공할 리소스를 저장하는 공간이 필요하다.

nginx 는 기본적으로 /usr/share/nginx 디렉토리 내에 기본적이 리소스들을 보관한다.

하지만, 해당 디렉토리의 리소스들은 nginx 가 전역적으로 사용하기 위한 50x.html 과 같은 에러 페이지 리소스 등을 비롯한 nginx 어플리케이션 레벨에서의 리소스를 저장하는 공간이므로 실제 서버의 리소스는 이곳에 보관하지 않도록 한다.

대신, /var/www/example.com/ 디렉토리를 컨벤션으로 사용한다.

Basic Configuration

NGINX 의 세부 설정은 /etc/nginx/nginx.conf 파일에서 관리된다.

하지만, 이 설정파일은 NGINX 서버 자체에 대한 설정파일로써 웹서비스를 서비스한다면 이 환경 설정은 반드시 etc/nginx/conf.d/example.com.conf 과 같은 파일에 설정을 해야 한다.

nginx.conf 파일에서는 nginx 에서 발생하는 error 및 access log 의 저장 위치를 설정하고, 설정파일들의 위치를 명시하여 다른 설정파일을 적용하는 등, 특정 server에 종속된 것이 아니라 nginx 어플리케이션 자체의 설정을 해 준다.

간혹 apache 서버를 사용하던 유저들은 아파치 서버 양식인 /etc/apache/sites-available 와 유사하게 etc/nginx/sites-available 에 서버 설정을 하는 경우가 있는데 이는 좋지 않은 패턴이니 지양하도록 한다.

nginx.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
user  nginx;
worker_processes auto;

error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
worker_connections 1024;
}


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

log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

access_log /var/log/nginx/access.log main;

sendfile on;
#tcp_nopush on;

keepalive_timeout 65;

#gzip on;

include /etc/nginx/conf.d/*.conf;


server_tokens off;
}

기본적으로 nginx 는 /etc/nginx/conf.d/default.conf 에서 최초의 웹 서버 설정을 해주는데, 별도의 설정파일을 추가한 이후에는 default.conf 파일을 제거하거나 중복된 설정을 없애 주어야 한다. 그렇지 않으면 해당 파일이 default configuration 으로 동작하여 사용자가 한 설정을 덮어써서 설정 내용이 반영이 되지 않게 된다.

개발자는 다음과 같이 example.com.conf 와 같은 설정파일을 작성할 수 있으며 여러 개의 서버와 location 을 지정하고, error page 및 proxy 등 다양한 설정을 할 수 있다.

/etc/nginx/conf.d/example.com.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
server {

error_page 500 502 503 504 /50x.html;

location / {
proxy_pass localhost:80
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}

location /50x.html {
root /usr/share/nginx/html;
}

gzip on;
gzip_comp_level 3;
gzip_types text/plain text/css application/javascript image/*;

}

Serving static file and access to local file system

다음과 같이 특정 url 에 파일 시스템 경로를 mapping 함으로써 특정 url 이 정적 파일들을 서빙하게 할 수 있다.

1
2
3
4
5
server {
location /images {
root /var/data/images
}
}

위 코드는 /image 로 오는 요청을 file system 에 매핑하여 요청자가 직접 file system 경로를 통해 리소스를 받아올 수 있게 해준다. 만약 특정 파일 형태만 정적 파일 시스템에 접근하도록 하고 싶은 경우 다음과 같이 regular expression 을 통해 해결 할 수 있다.

1
2
3
4
5
server {
location ~\.(gif|jpg|png) {
root /var/data/images
}
}

Reverse Proxy

NGINX 서버는 간편하게 Reverse Proxing 을 할 수 있게 해 주며, 다음과 같은 간단한 설정을 통해 reverse proxy 서버를 구축할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
server {
server_name localhost default_server;

location /example1/proxy {
proxy_pass http://naver.com;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}

위 예제는 localhost/example1/proxy 로 들어온 요청을 http://naver.com/example1 로 proxing 해주는 설정파일이다.

Subdomain

서비스를 출시할때 흔히 다음과 같은 서브 도메인 양식을 가지고 리소스에 접근할 필요가 있게 된다.

가령 관리자 페이지를 위한 admin.example.com 이라던가 혹은 개발서버를 위한 dev.example.com 과 같이 여러 subdomain 이 필요하게 된다. nginx 는 host name 을 인식하여 간편하게 subdomain 을 reverse proxing 해주며 다음과 같은 세팅을 통해 간편하게 이를 적용할 수 있다.

다음 예제는 localhost 환경에서 앞에 example1 이라는 prefix 를 주고, 이를 reverse proxing 해주는 설정파일이다.

1
2
3
4
5
6
7
8
server {
server_name example.localhost

location / {
root /var/www/example2.com;
}

}

SSL

많은 서비스들은 http 프로토콜의 보안을 위해 https 프로토콜을 사용하며 이를 위해서는 443 port 를 통한 SSL 레벨에서의 통신이 필요하다.

이러한 요청을 처리하기 위해서는 다음과 같이 443 port 를 ssl 레벨에서 listen 해야 한다.

1
2
3
4
server{
listen [::]:80;
listen [::]:443 ssl;
}

GZIP

NGINX 는 통신시에 데이터를 줄이기 위해 gzip 압축을 통한 리소스 압축을 제공한다.

이는 다음과 같은 설정을 통해 할 수 있다.

1
2
3
4
5
6
server {
...
gzip on;
gzip_comp_level 3;
gzip_types text/plain text/css application/javascript image/*;
}
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×