저번 포스트에서 리눅스 가상머신 준비를 마쳤습니다. 이번에는 아래 과정을 진행해보겠습니다.

  • Nginx 설치
  • 웹 어플리케이션 연결
  • 도메인 설정 (Optional)
  • SSL 인증서 설정 (Optional)

nginx 설치

  1. CentOS의 경우 nginx 설치는 yum으로 진행하면 됩니다. 운영체제에 따라 다르겠지만, CentOS가 아니라면 nginx의 공식 문서를 참고하여 설치하도록 합시다.
    sudo yum -y update && sudo yum -y install epel-release nginx
  2. 설치가 다 됐으면 nginx를 구동해봅시다. 시스템이 재시작됐을 때 자동으로 nginx를 시작하게 하고싶다면 enable을 해줘야 합니다.
    sudo systemctl enable nginx
    sudo systemctl start nginx
  3. 포트를 확인해봅시다. 80번 포트가 열려있는 것을 볼 수 있습니다. (그렇지 않다면 nginx가 제대로 실행되지 않았다는 것입니다.)
    ss -ntl | grep 80
    
    LISTEN     0      128          *:80                       *:*
    LISTEN     0      128         :::80                      :::*
  4. 이제 브라우저에서 가상머신의 공용 아이피로 접속했을 때 아래와 같이 nginx 기본 화면이 보입니다.

웹 어플리케이션 연결

이제 웹 어플리케이션을 연결하겠습니다. 기존에 운영하시는 프로젝트가 있다면 그대로 사용하면 되지만, 없다고 가정하여 Node 프로젝트 생성부터 진행해보겠습니다.

  1. node 환경 구성을 위해 nvm을 설치합니다. 아래처럼 nvm ls를 했을 때 정상적으로 출력된다면 성공입니다.
    curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.34.0/install.sh | bash
    source ~/.bashrc
    
    nvm ls
    
            N/A
    iojs -> N/A (default)
    node -> stable (-> N/A) (default)
    unstable -> N/A (default)
  2. node를 설치합니다. 별 이슈가 없다면 최신 stable 버전으로 설치합시다. 2019년 1월 기준으로 최신 버전은 v11.6.0이 되겠습니다.
    nvm install stable
    node --version
    
    v11.6.0
  3. node 프로젝트를 생성합니다.
    mkdir myapp
    cd myapp
    npm init
  4. package.json이 만들어졌다면, 서버 코드를 작성합니다. 이 때 구동에 필요한 npm 패키지도 같이 설치해줍시다.
    // 아래 내용을 app.js에 추가
    var express = require('express');
    var app = express();
    app.get('/', function (req, res) {
      res.send('Hello World!');
    });
    app.listen(3000, function () {
      console.log('Example app listening on port 3000!');
    });
    npm install express --save
    npm install -g pm2
    vi app.js
  5. 위에서 설치한 pm2를 이용해 서버를 구동합니다.
    pm2 start app.js --name myapp
  6. 이제 웹서버로 접속해봅니다. 가상머신의 public ip를 확인한 후에, http:public-ip:3000 주소로 브라우저에서 접속합니다.따라서 Nginx를 통해 80/443 -> 3000 리다이렉션을 수행하도록 리버스 프록시 설정을 추가하겠습니다.
  7. 위의 주소로 접속하면 타임아웃 현상이 발생 할 것입니다. 이는 3000번 포트에 대해서 인바운드 설정을 하지 않았기 때문입니다. 우리는 사용자가 3000번 포트가 아닌 80/443 포트를 통해 접근하기를 원합니다.
  8. 아래와 같이 myapp.conf에 다음과 같이 설정을 추가하고 Nginx를 재시작합니다. 에러가 발생할 경우 conf 파일에 오타가 있을 수 있으니 잘 확인합니다.
    sudo vi /etc/nginx/conf.d/myapp.conf
    # 아래 내용을 myapp.conf에 추가
    upstream backend {
        server localhost:3000;
    }
    server {
        listen       80;
        server_name  your_domain; # --> public ip 혹은 도메인 입력
        location / {
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $host;
            proxy_set_header Port $proxy_port;
            proxy_http_version 1.1;
            proxy_pass http://backend;
        }
    }
    sudo systemctl restart nginx
  9. 위에서 설정한 public ip로 브라우저에서 접속해봅시다.
    sudo cat /var/log/nginx/error.log | tail -1
    2019/01/20 08:40:29 [crit] 23637#0: *1 connect() to 127.0.0.1:3000 failed (13: Permission denied) while connecting to upstream, client: xxx.xxx.xxx.xx, server: xx.xxx.xx.xxx, request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:3000/", host: "xx.xxx.xx.xxx"
    위와 같은 에러가 나오는데, SELinux에서 httpd가 특정 주소로 네트워크 연결하는 것을 deny하는 이슈입니다. 이를 해결하기 위해 아래 명령어를 추가로 실행해줘야 합니다.
    sudo setsebool httpd_can_network_connect on
    sudo service httpd restart
  10. 502 Bad Gateway 에러가 나올 것입니다. Nginx 에러 로그를 살펴봅니다.
  11. 이제 다시 브라우저로 접속해봅니다. Hello World!라는 문구가 출력되면 정상적으로 연결 된 것입니다.

도메인 설정 (Optional)

개인 서버를 운영하는 경우 대부분 자신만의 도메인 네임을 가지고 있습니다. 사용자가 서버의 아이피 주소를 외우고 다닐 리가 없을 뿐더러, 깔끔하지 않기 때문입니다. 다만, 이 과정은 선택사항이기 때문에 도메인 네임까지 설정할 필요가 없다고 생각하시는 분들은 가볍게 넘어가되, 공인 아이피로 접속해주시면 되겠습니다.

저는 AWS Route53을 사용하고 있습니다. 여기에 추가적으로 HTTPS 세팅을 하기 위해서는 SSL 인증서가 필요한데, Cloudflare를 통해 무료 사용 중입니다.

이는 best practice가 아니며, 각자 본인 취향에 맞게 구성해주시면 되겠습니다.

다만, 도메인 네임 대행 서비스는 업체마다 가격이 천차만별이고 서비스의 질도 다르기 때문에 잘 알아보고 선택하시는 것이 좋습니다. 아래는 Ropute53과 Cloudflare를 사용한 구성 방법입니다.

  1. AWS, Cloudflare에 각각 회원가입을 진행합니다.
  2. Route53에서 도메인 네임을 등록합니다. 등록까지 시간은 다소 걸리지만, 어려운 것은 없기 때문에 별도 설명하지 않겠습니다.
  3. Cloudflare에서 등록한 도메인으로 사이트를 추가하고, DNS 메뉴를 선택합니다.
  4. DNS Records 부분에서 다음과 같이 레코드를 추가합니다.
    • Type: A
    • Name: 자신의 도메인
    • Value: 가상머신의 public ip
    • TTL: Automatic
  5. Cloudflare Nameservers 부분의 네임서버 정보를 확인합니다.
  6. Route53에 Cloudflare의 네임서버를 추가합니다. Route53 사이드 메뉴 > Registered domains > 본인의 도메인 선택 > 우상단의 Add or edit name servers > 추가
  7. 브라우저에서 도메인으로 접속해봅니다. 도메인 등록의 경우 시간이 다소 걸리기 때문에 바로 접속되지 않을 수 있습니다.

HTTPS 설정 (Optional)

도메인 설정과 마찬가지로, HTTPS 설정은 부가적인 옵션이지만 권장되는 사항입니다. 도메인 설정이 완료된 상태에서 Cloudflare 공식 문서를 참고하여 아래 과정을 진행합니다.

  1. Cloudflare에 접속한 후 Crypto 메뉴를 선택합니다.
  2. Origin Certificates에서 Create Certificate를 누릅니다. 다이얼로그가 나타나면 본인의 도메인 네임 리스트를 입력합니다. 서브도메인을 위해 Asterisk를 포함한 도메인도 추가해줍니다.
     *.your-domain.com, your-domain.com
  3. Next를 누르면 Origin Certificate와 Private Key가 생성되는 것을 확인할 수 있습니다. 생성된 키와 인증서를 복사하여 서버에 추가해줍니다.주의 할 점으로, Private Key의 경우 한 번 발급되면 다시 보여주지 않기 때문에 로컬에 복사해두는 것이 좋습니다. 만약 분실할 경우 삭제 후 다시 발급해야 합니다.
    sudo vi /etc/ssl/certs/your-domain.com.key # --> Private Key 내용 추가
    sudo vi /etc/ssl/certs/your-domain.com.pem # --> Origin Certificate 내용 추가
  4. 서버의 Nginx 설정을 엽니다.
    sudo vi /etc/nginx/conf/conf.d/myapp.conf
  5. SSL 인증서 설정을 추가하고 Nginx를 재시작합니다.
    sudo systemctl restart nginx
    # 아래 내용을 myapp.conf에 추가
    upstream backend {
        server localhost:3000;
    }
    
    server {
        listen 80;
        server_name your_domain; # --> public ip 혹은 도메인 입력
        location / {
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $host;
            proxy_set_header Port $proxy_port;
            proxy_http_version 1.1;
            proxy_pass http://backend;
        }
    }
    
    server {
        listen       443;
        ssl        on;
        ssl_certificate         /etc/ssl/certs/your-domain.com.pem;
        ssl_certificate_key     /etc/ssl/certs/your-domain.com.key;
        server_name  your_domain;
        location / {
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $host;
            proxy_set_header Port $proxy_port;
            proxy_http_version 1.1;
            proxy_pass http://backend;
        }
    }
  6. 도메인에 https를 붙여서 접속해봅시다. 정상 접속이 된다면 설정이 마무리 된 것입니다.