티스토리 뷰

SW 개발/CentOS

CentOS, NGINX 설치하기

지단로보트 2017. 4. 23. 04:29

개요

  • 현재 웹 서버의 대세라고 한다면 nginx라고 할 수 있다. 어지간한 스타트업 기업들은 대부분 애플리케이션 서버의 앞단에 nginx를 두는 구성을 선호한다. 특히 정적 컨텐츠에 대한 처리 능력이 굉장히 우수하다. 정적 파일들을 nginx로 서비스하고 서버 앞단에 CDN을 두는 형태가 일반적이다. 이번 글에서는 nginx를 설치하고 설정하는 방법을 설명하고자 한다.

NGINX 설치

  • 아래 순서로 nginx를 설치한다. 참고로 nginxEPEL 저장소에서 설치가 가능하다. 하지만 최신 버전을 사용하려면 아래와 같이 NGINX 저장소를 시스템에 추가한 후 설치해야 한다.
### nginx 설치
$ sudo nano /etc/yum.repos.d/nginx.repo
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/mainline/centos/6/$basearch/
gpgcheck=0
enabled=1

$ yum list nginx
nginx.x86_64 1.17.6-1.el6.ngx nginx

$ sudo yum --enablerepo=nginx install nginx

### 설치 직후에는 NGINX 서비스가 정지되어 있다.
$ sudo service nginx status
nginx is stopped

NGINX 환경설정

  • NGINX 환경설정 적용은 기본적으로 아래 경로의 파일을 수정하면 된다.
$ sudo nano /etc/nginx/nginx.conf
$ sudo nano /etc/nginx/conf.d/default.conf
  • 아래는 수정의 한 예이다.
### NGINX의 Reverse Proxy 설정을 변경
$ sudo nano /etc/nginx/conf.d/default.conf
server {
  listen 80 default_server; # NGINX의 서비스 포트를 지정한다. 기본값은 80이다. 80 포트로 오는 모든 HTTP 요청을 NGINX가 처리한다.
  listen [::]:80 default_server;
  server_name _; # NGINX는 HTTP 요청 헤더의 Host 필드 값과 일치하는 server_name에 대해서만 서비스를 라우트한다. '_'로 지정하면 Host 필드 값과 상관없이 모두 라우트한다.n
  access_log /var/log/nginx/access.log;   # 액세스 로그 파일이 생성될 경로를 지정한다.

  # /static 으로 들어오는 요청은 /var/www/html/static/ 디렉토리의 파일을 정적 제공
  location /static {
    root /var/www/html/static/;
    index index.html;
  }

  # / 로 들어오는 요청을 ReDirect한다. ReWrite와는 다르다.
  location / {
    return 301 http://jsonobject.tistory.com
  }

  # /nodejs/hello 로 들어오는 요청을 로컬 3000 포트로 분기
  location /nodejs/hello {
    proxy_pass http://127.0.0.1:3000;
}

### 방화벽에서 80, 443 포트를 개방
$ sudo nano /etc/sysconfig/iptables
-A INPUT -p tcp -m state --state NEW -m tcp -dport 80 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp -dport 443 -j ACCEPT

### 방화벽을 재시작한다.
$ sudo service iptables restart

### NGINX를 재시작한다.
$ sudo service nginx restart
Stopping nginx:                                            [FAILED]
Starting nginx:                                            [  OK  ]

정적 파일 서비스 적용

  • 단순히 정적 파일 서비스를 제공하기 위한 설정은 아래와 같다. 대상 디렉토리에 실행 권한 설정이 필요하다. [관련 링크]
# 403 Forbidden 오류가 발생하지 않도록 대상 디렉토리에 실행 권한 부여
$ sudo chmod +x /home
$ sudo chmod +x /home/static

$ sudo nano /etc/nginx/conf.d/default.conf
server {
    server_name static.jsonobject.com;
    access_log /var/log/nginx/access.log;

    location / {
        root /home/static/;
        index index.html;
  }
}

$ sudo service nginx restart

멀티 도메인 리버스 프록시 적용

  • 한 서버에서 각각의 도메인을 가진 복수개의 서비스를 실행하고, 앞단의 NGINX가 이러한 멀티 도메인에 대한 리버스 프록시 구성을 할 수 있다. 아래 예는 내부적으로 8080 포트에서 실행 중인 서비스를 foo.jsonobject.com 요청에 맵핑해주고, 8081 포트에서 실행 중인 서비스를 bar.jsonobject.com 요청에 맵핑해준다.
$ sudo nano /etc/nginx/nginx.conf
server_names_hash_bucket_size 64;

$ sudo nano /etc/nginx/conf.d/default.conf
server {
  listen 80;
  server_name foo.jsonobject.com;

  location / {
    proxy_pass http://127.0.0.1:8080;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
}

server {
  listen 80;
  server_name bar.jsonobject.com;

  location / {
    proxy_pass http://127.0.0.1:8081;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
}

HTTPS 적용

  • CertBot 클라이언트를 설치하면 Let’s Encrypt 무료 SSL 인증서를 자동으로 설치하고, NGINX 환경설정까지 자동 적용할 수 있다. 적용 예는 아래와 같다. 주의할 점은 적용 시점에 이미 대상 도메인에 대한 DNS 질의가 가능해야 성공적으로 적용된다.
# EPEL 저장소 설치
$ sudo yum install epel-release

# Certbot 클라이언트 설치
$ cd /opt
$ sudo wget https://dl.eff.org/certbot-auto
$ sudo mv certbot-auto /usr/local/bin/certbot-auto
$ sudo chown root /usr/local/bin/certbot-auto
$ sudo chmod 0755 /usr/local/bin/certbot-auto

# Amazon EC2 인스턴스의 경우, 아래 작업 필요
$ sudo nano /usr/local/bin/certbot-auto
# 변경 전
elif [ -f /etc/redhat-release ]; then
# 변경 후
elif [ -f /etc/redhat-release ] || grep 'cpe:.*:amazon_linux:2' /etc/os-release > /dev/null 2>&1; then

# Certbot 클라이언트 실행
# NGINX에 인증서를 설치하고, HTTPS로 접속되도록 자동 설정 실행
# 방화벽에서 80 포트가 개방되어 있어야 정상적으로 인증서가 다운로드
$ sudo /usr/local/bin/certbot-auto --nginx
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator nginx, Installer nginx
Enter Email address (used for urgent renewal ans security notices): *****
Congratulations! You have successfully enabled https://someyourdomain.com

# 기존 443 포트를 사용 중인 모든 프로세스 종료
$ sudo fuser -k 443/tcp
$ sudo rm /etc/httpd/conf.d/ssl.conf
$ sudo service httpd restart
$ sudo service nginx restart

# NGINX 재시작
$ sudo service nginx restart

# 인증서 자동 갱신 크론잡 등록
$ crontab -e
0 0,12 * * * root python -c 'import random; import time; time.sleep(random.random() * 3600)' && /usr/local/bin/certbot-auto renew
  • 자동 적용 내용 살펴보면 server 블록에 아래 내용이 추가되는 것을 확인할 수 있다.
server {
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/someyourdomain.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/someyourdomain.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}

server.access_log, server.error_log

  • NGINX 1.7.1 버전부터 syslog를 이용한 로그 전송을 지원한다. 아래와 같이 설정이 가능하다. Graylog에 연동하는 예도 있다. [링크]
access_log syslog:server={syslog_hostname}:{port};
error_log syslog:server={syslog_hotname}:{port};
  • 자신이 원하는 커스텀 로그를 전송하고자 한다면 설정 예는 아래와 같다. log_format 옵션을 JSON으로 작성하려면 NGINX 1.11.8 이상을 요구한다.
$ sudo nano /usr/local/nginx/conf/nginx.conf
http {
    log_format graylog escape=json '{ "version": "1.1", '
        '"host": "$host", '
        '"short_message": "$request", '
        '"timestamp": "$time_iso8601", '
        '"level": 6, '
        '"_request_user_agent": "$http_user_agent", '
        '"_request_ip_address": "$remote_addr", '
        '"_request_total_bytes": $body_bytes_sent, '
        '"_request_method": "$request_method", '
        '"_request_path": "$request", '
        '"_request_query_string": "$args", '
        '"_process_time_ms": $request_time, '
        '"_response_status": $status, '
        '"_upstream_cache_status": "$upstream_cache_status", '
        '"_upstream_addr": "$upstream_addr", '
        '"_http_x_forwarded_for": "$http_x_forwarded_for", '
        '"_http_referer": "$http_referer", '
        '"_web_server": "NGINX" }';

    server {
        access_log syslog:server=graylog.example.com:12201 graylog;
    }
}

# nginx.conf 문법 검사
$ sudo /usr/sbin/nginx -t
# NGINX 재시작
$ sudo /usr/sbin/nginx -s reload
$ sudo service nginx status

HTTP 로드 밸런싱

http {
    upstream some-app-server {
        server 127.0.0.1:9090;
        server 127.0.0.1:9091;
        server 127.0.0.1:9092 backup;
    }

    server {
        listen 80;
        server_name localhost;

        location /v1 {
            proxy_pass http://some-app-server;
            proxy_connect_timeout 1000ms;
            proxy_read_timeout 10000ms;
        }
    }
}
  • http.upstream {server-group} 블록에는 리버스 프록시의 목적지가 되는 서버 그룹을 지정할 수 있다. 서버 그룹을 지정하면 각 서버로 로드 밸런싱이 수행된다.
  • 서버 뒤에 backup을 붙이면 평소에는 로드 밸런싱의 대상에서 제외되어 있다가, 지정된 모든 서버가 proxy_connect_timeout, proxy_read_timeout에 명시한 시간을 초과할 경우 대체 서버 역할을 수행하게 된다. 백업 서버마저 연결 또는 응답에 실패할 경우 클라이언트 측에 최종적으로 504 Gateway Timeout 오류를 응답한다.
  • http.server.location {request_path} 블록에 proxy_pass http://{server-group}을 명시하면 앞서 작성한 서버 그룹으로 로드 밸런싱이 실행된다.
  • {request_path}는 로드 밸런싱 대상이 되는 애플리케이션에도 동일하게 구현되어 있어야 한다. 위의 경우 /v1으로 시작하는 모든 요청에 대해 애플리케이션에 구현된 /v1 경로로 프록싱한다.
  • 각 서버가 proxy_connect_timeout에 지정한 시간 동안 연결이 되지 않을 경우(대개 애플리케이션이 셧다운된 경우) 연결 실패로 간주하고 백업 서버에 연결을 수행한다. 백업 서버마저 응답이 없으면 클라이언트 측에 504 Gateway Timeout 오류를 응답한다.
  • 각 서버가 연결 성공 후 proxy_read_timeout에 지정한 시간 동안 요청에 대한 응답을 하지 않을 경우(대개 부하로 인해 요청에 대한 처리가 지연 중인 상황) 실패로 간주하고 백업 서버에 요청을 수행한다. 백업 서버마저 응답이 없으면 클라이언트 측에 504 Gateway Timeout 오류를 응답한다.

TCP 로드 밸런싱

stream {
    upstream some-db-server {
        server 127.0.0.1:3306;
        server 127.0.0.1:3307;
    }

    server {
        listen 3306;
        proxy_pass some-db-server;
    }
}

SSE 로드 밸런싱

  • 백엔드의 앞단의 NGINX 리버스 프록시가 존재할 경우, 아래와 같이 SSE 설정을 최적화할 수 있다. [관련 링크1] [관련 링크2]
server {
  listen 8080;

  location / {
    proxy_pass https://api.foobar.com;
    proxy_set_header Connection '';
    proxy_http_version 1.1;
    proxy_buffering off;
    proxy_cache off;
    chunked_transfer_encoding off;
  }
}

HTTP 응답 데이터 압축 활성화

$ sudo nano /etc/nginx/nginx.conf
http {
    ...
    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_proxied expired no-cache no-store private auth;
    gzip_types application/json;
    gzip_disable "MSIE [1-6]\.";
    ...
}
  • gzip 옵션을 활성화하면 HTTP 응답을 압축하여 요청 클라이언트에게 전달하게 된다. CPU 부하는 증가하지만 네트워크 트래픽은 감소되는 효과가 있다. (잘만 활용하면 드라마틱한 아웃바운드 트래픽 감소를 체감할 수 있다.)
  • gzip_min_length 옵션은 지정한 바이트 이상의 응답 크기를 가질 때만 압축한다. 압축의 효과가 적은 작은 크기의 응답에서 압축을 생략하여 CPU 부하를 줄일 수 있다.
  • gzip_types 옵션은 압축할 응답 컨텐츠 타입을 지정할 수 있다. 여기에 속하지 않은 컨텐츠 타입은 압축하지 않는다.
  • gzip 옵션이 정상적으로 적용되면 아래 응답 헤더가 추가되어 클라이언트에서 인지할 수 있다.
  • content-encoding: gzip

NGINX 핫 리로드

  • NGINX에서 가장 유의해야할 점이 바로 핫 리로드이다. 변경된 설정을 반영하려면 리로드 또는 재시작이 필요하다. 기존 서비스의 다운 타임 없이 변경된 설정을 핫 리로드하려면 아래와 같이 명령어를 실행하면 된다. 후자를 권장한다.
# 다운 타임 없이 리로드, 변경된 설정이 반영되지 않음
$ sudo service nginx reload

# 다운 타임 없이 리로드, 변경된 설정을 즉각 반영, 오류가 발생할 경우 이전 설정이 유지됨
$ sudo /usr/sbin/nginx -s reload

참고글

댓글
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
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
글 보관함