NodeJS와 Nginx 웹 서버

Nginx with nodejs

nginx를 사용해서 일반 웹 서비스와 node.js 애플리케이션을 연동하는 방법을 살펴보자.

Nginx 구성

Nginx 설치가 되었다고 가정한다.

nginx 구성 파일

/etc/nginx 밑에 가상 호스트 환경에 맞게 파일을 구성한다.

/etc/nginx/site-available/myhome.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
server {

listen 80 default_server;
server_name _;

index index.html index.htm index.nginx-debian.html;

location / {
proxy_set_header Host $http_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 X-NginX-Proxy true;

proxy_pass http://127.0.0.1:50000/;
proxy_redirect off;

try_files $uri $uri/ =404;
}

log_not_found off;

gzip on;
gzip_comp_level 2;
gzip_proxied any;
gzip_min_length 1000;
gzip_disable "MSIE [1-6]\.(?!.*SV1)";
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript text/x-js;
}

http 에 대한 구성

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
 http {
upstream my_node_app {
server 127.0.0.1:8000;

server {
listen 80;
server_name localhost domain.com;
access_log /var/log/nginx/my_node_app.log;
location ~ /static/ {
root /home/node/my_node_app;
if (!-f $request_filename) {
return 404;
}
}
location / {
proxy_pass http://my_node_app;
proxy_redirect off;

proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
}
}
}

nginx 구성을 재시작한다

1
2
3
$ cd /etc/nginx/sites-enabled
$ sudo ln -s /etc/nginx/sites-available/test.conf test.conf
$ sudo service nginx reload

Nginx with Node.js

nodejs 를 연동하기 위한 Proxy 구성을 추가한다.

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
server {

listen 80;
server_name test.example.com;

location / {
proxy_set_header Host $http_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 X-NginX-Proxy true;

proxy_pass http://127.0.0.1:52222/;
proxy_redirect off;
}

log_not_found off;

gzip on;
gzip_comp_level 2;
gzip_proxied any;
gzip_min_length 1000;
gzip_disable "MSIE [1-6]\.(?!.*SV1)";
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript text/x-js;
}

SSL

Nginx를 이용해 SSL 제공을 해주자.

Private SSL 설정

1
2
3
4
5
6
7
$ sudo mkdir /etc/nginx/ssl
$ cd /etc/nginx/ssl
$ sudo openssl genrsa -des3 -passout pass:x -out server.pass.key 2048
$ sudo openssl rsa -passin pass:x -in server.pass.key -out server.key
$ sudo rm server.pass.key
$ sudo openssl req -new -key server.key -out server.csr
$ sudo openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

Nginx 설정

/etc/nginx/site-available/yoursite.com

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
34
35
36
37
38
39
40
41
42
43
44
45
server {
listen 443 default;
server_name erp.yclean.co.kr;

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

ssl on;
ssl_certificate /etc/nginx/ssl/server.crt;
ssl_certificate_key /etc/nginx/ssl/server.key;
keepalive_timeout 60;

ssl_ciphers HIGH:!ADH:!MD5;
ssl_protocols SSLv3 TLSv1;
ssl_prefer_server_ciphers on;

proxy_buffers 16 64k;
proxy_buffer_size 128k;

location / {
proxy_pass http://127.0.0.1:8069;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
proxy_redirect off;

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 https;
}

location ~* /web/static/ {
proxy_cache_valid 200 60m;
proxy_buffering on;
expires 864000;
proxy_pass http://127.0.0.1:8069;
}
}

server {
listen 80;
server_name erp.yclean.co.kr;

add_header Strict-Transport-Security max-age=2592000;
rewrite ^/.*$ https://$host$request_uri? permanent;
}

http 리다이렉트

http://serverfault.com/questions/250476/how-to-force-or-redirect-to-ssl-in-nginx

1
2
3
4
5
server {
listen 80;
server_name signup.mysite.com;
rewrite ^ https://$server_name$request_uri? permanent;
}

The best way as it described in the official how-to is by using the return directive:

1
2
3
4
5
server {
listen 80;
server_name signup.mysite.com;
return 301 https://$server_name$request_uri;
}

site file 활셩화

1
2
3
$ sudo ln -s /etc/nginx/sites-available/yourOdooSite.com /etc/nginx/sites-enabled/yourOdooSite.com

$ sudo /etc/init.d/nginx restart

CORS

CORS(Cross-Origin resource sharing)은 웹 페이지 도메인 밖의 다른 도메인에서 제한된 웹 페이지를 자원을 허용하도록 하는 메커니즘이다.[^2]

You need to enable CORS on the server (localhost:8080). Check out this site: http://enable-cors.org/

All you need to do is add an HTTP header to the server:

1
Access-Control-Allow-Origin: http://localhost:3000

전체적으로 열어 주려

1
Access-Control-Allow-Origin: *

다음 같이 nginx 설정을 사용한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
et $cors '';
if ($http_origin ~ '^https?://(localhost|www\.yourdomain\.com|www\.yourotherdomain\.com)') {
set $cors 'true';
}

if ($cors = 'true') {
add_header 'Access-Control-Allow-Origin' "$http_origin" always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With' always;
# required to be able to read Authorization header in frontend
#add_header 'Access-Control-Expose-Headers' 'Authorization' always;
}

if ($request_method = 'OPTIONS') {
# Tell client that this pre-flight info is valid for 20 days
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}

Nginx와 Proxy 서비스

Nginx를 앞단에 두고 Proxy를 이용해 nodeJS, Djang, Angular 등의 서비스를 이용할 때, nginx나 backend 둘 중 한 곳에서 CORS를 활성화 해주면 된다.

Nginx에서 CORS

Nginx에서 CORS를 허용하려면 아래 설정을 사용할 수 있다. [^1]

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
location / {
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
#
# Custom headers and headers various browsers *should* be OK with but aren't
#
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
#
# Tell client that this pre-flight info is valid for 20 days
#
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
if ($request_method = 'POST') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
add_header 'Access-Control-Expose-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
}
if ($request_method = 'GET') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
add_header 'Access-Control-Expose-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
}
}

이와 비슷한 방법으로

https://gist.github.com/m4ttbrock/7337183

CORS node.js

https://enable-cors.org/server_expressjs.html

if your app is created with simple node.js set it in your response headers like

1
2
3
4
5
6
7
8
9
10
var http = require('http');

http.createServer(function (request, response) {
response.writeHead(200, {
'Content-Type': 'text/plain',
'Access-Control-Allow-Origin' : '*',
'Access-Control-Allow-Methods': 'GET,PUT,POST,DELETE'
});
response.end('Hello World\n');
}).listen(3000);

if your app is created with express framework
use a CORS middleware like

1
2
3
4
5
6
var allowCrossDomain = function(req, res, next) {
res.header('Access-Control-Allow-Origin', "*");
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type');
next();
}

cors module

cors 모듈을 이용할 수 있다.

https://github.com/expressjs/cors

Enable All CORS requets
1
2
3
var cors = require("cors");

app.use(cors());
Enable CORS for a Single Route
1
2
3
app.get("/products/:id", cors(), function (req, res, next) {
res.json({ msg: "This is CORS-enabled for a Single Route" });
});
Configuring CORS
1
2
3
4
5
6
7
8
var corsOptions = {
origin: "http://example.com",
optionsSuccessStatus: 200, // some legacy browsers (IE11, various SmartTVs) choke on 204
};

app.get("/products/:id", cors(corsOptions), function (req, res, next) {
res.json({ msg: "This is CORS-enabled for only example.com." });
});

참조

[^1]: CORS on Nginx
[^2]: Cross-origin resource sharing