React.js + Node.js HTTPS 배포 ( AWS-EC2 + nginx + certbot )
포스트
취소

React.js + Node.js HTTPS 배포 ( AWS-EC2 + nginx + certbot )

해당 포스트는 AWS-EC2, nginx, certbot을 이용한 배포 방법에 대한 포스트입니다.

깊은 이해도를 갖고 설명하기 보다는 구글링을 통해서 찾은 방법들을 한곳에 모아서 정리하는 포스트입니다.
( nginx, certbot, ssl이 무엇인지는 이후에 공부하고 따로 포스팅할 예정입니다… 🥲 )

🐊 AWS-EC2

무료로 사용하기 위해서 AWS-EC2 프리티어를 이용해서 인스턴스를 생성하면 됩니다.
다른 블로그들에서 상세하게 설명해주기 때문에 간단한 부분은 넘어가겠습니다.

0️⃣ 보안 그룹

보안 그룹에서 아웃바운드 규칙은 모두 열어주고, 인바운드 규칙에서는 HTTPS, SSH의 접근 권한을 열어주는 게 좋습니다.
( 단, HTTPS가 적용되기 전에 확인하고 싶다면 HTTP를 열어주고 그게 안된다면 모든 접근을 허용하고 테스트 후 다시 닫는 게 좋습니다. )

보안 그룹

1️⃣ 탄력적 IP

탄력적 IP를 설정해줘야 IP가 고정되어 바뀌지 않아서 사용하기 편리합니다.
인스턴스를 생성했고 실행중이라면 탄력적 IP에 들어가면 생성한 인스턴스중에서 선택할 수 있습니다.
중요한 점은 탄력적 IP를 등록한 후에 인스턴스를 제거했다면 탄력적 IP도 릴리즈해야합니다.
연결된 인스턴스없이 탄력적 IP만 가지고 있으면 매일 약간의 돈을 지불해야합니다.

2️⃣ 접근 오류

만약 SSH로 접근할 때 WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! 오류가 발생한다면 아래와 같은 명령어를 입력하면 됩니다.
AWS 자체적으로 이전에 접근했던 IP와 다르기 때문에 막아주는 기능인 것 같습니다.

1
2
# 본인의 "퍼블릭 IPv4 DNS"로 입력
ssh-keygen -R ec2-3-39-81-82.ap-northeast-2.compute.amazonaws.com

🫠 설치

0️⃣ node

1
2
curl -sL https://deb.nodesource.com/setup_16.x | sudo bash -E -
sudo apt install -y nodejs

1️⃣ mysql

1
sudo apt install mysql-server

2️⃣ nginx

1
sudo apt-get install nginx

3️⃣ certbot

1
sudo snap install certbot --classic

🪪 HTTPS 적용

아래 과정을 수행하기 전에 탄력적 IP를 도메인을 얻은 사이트에 등록해야합니다.
그리고 서버도 접근 가능한 상태여야 이 도메인에 등록된 IP로 접근할 수 있구나를 판단해서 인증서를 발급받을 수 있습니다.

0️⃣ nginx 설정 파일에 도메인 작성

/etc/nginx/nginx.conf의 경로에 존재하는 nginx 설정 파일에 사용할 도메인을 미리 작성해둡니다.

1
2
# 1. nginx 설정 파일 열기
sudo vim /etc/nginx/nginx.conf
1
2
3
4
5
# 2. "http { ... }" 내부에 아래 코드 작성
server {
  # 여기에 사용할 도메인 작성
  server_name jslog.co.kr;
}

1️⃣ 인증서 발급

아래 명령어를 입력하면 도메인과 IP를 이용해서 현재 접근이 가능한 상태인지 확인하고 테스트한 후 인증서를 발급해줍니다.
( 인증서에 유효기한이 존재하기 때문에 끝나기전에 재발급받거나 자동 재발급 받는 명령어를 등록해야합니다. )

아래 명령어를 입력하면 몇 가지 조건을 확인하고 이메일 주소 및 사용할 도메인을 물어보는데 알아서 응답하면 됩니다.
nginx 설정 파일에 도메인을 작성했다면 알아서 해석해서 추천해줍니다.

1
sudo certbot --nginx

2️⃣ nginx 설정 파일 커스터마이징

성공했다면 /etc/nginx/nginx.confcertbot에서 인증서 사용을 위한 몇 가지 구문을 추가했을겁니다. ( #managed by Certbot )
해당 부분은 놔두고 필요한 부분만 추가하면 됩니다.

예를들면 저희는 nginx를 통해 인증서를 사용하기 때문에 모든 요청은 nginx를 거쳐서 실제 서버로 도달해야합니다.
( browser -> nginx -> server )

따라서 nginx에 접근이 오면 어디로 보내줘야 할지를 알려줘야 저희가 실행하는 서버를 사용할 수 있습니다.
그것을 작성하는 코드가 proxy_pass입니다.
코드와 코드의 주석으로 자세하게 설명하겠습니다.

1
2
# 1. nginx 설정 파일 열기
sudo vim /etc/nginx/nginx.conf

아래는 현재 배포해서 사용중인 /etc/nginx/nginx.conf 파일의 전체 코드입니다.
( 현재 실행중인 서버의 포트는 3050입니다. )

  • 중요한 부분
    1. server_name jslog.co.kr;
    2. listen 443
    3. location / { ... }
    4. proxy_pass http://localhost:3050;입니다.
  • server_name: 도메인 주소를 적는 부분
  • listen: 감시할 port를 적는 부분 ( 443https로 접근하는 경우를 감지 )
  • location /: /가 포함되는 path로 접근하는 경우 감지
  • proxy_pass: 대신 보여줄 것을 적는 곳 ( 리다이렉트(?) )
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
        worker_connections 768;
        # multi_accept on;
}

http {
        server {
                # 도메인을 적는 부분
                server_name jslog.co.kr;

                # 감시할 port
                listen 443 ssl; # managed by Certbot
                ssl_certificate /etc/letsencrypt/live/jslog.co.kr/fullchain.pem; # managed by Certbot
                ssl_certificate_key /etc/letsencrypt/live/jslog.co.kr/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

                # 접근할 경로
                location / {
                        proxy_set_header HOST $host;
                        # proxy_pass "https로 접근이 오면 보여줄 포트";
                        proxy_pass http://localhost:3050;  # 여기에 현재 사용하는 포트 작성
                        proxy_redirect off;
                }
        }

        server {
                if ($host = jslog.co.kr) {
                        return 301 https://$host$request_uri;
                } # managed by Certbot

                server_name jslog.co.kr;
                listen 80;

                location / {
                        proxy_set_header HOST $host;
                        # proxy_pass "https로 접근이 오면 보여줄 포트";
                        proxy_pass http://localhost:3050;  # 여기에 현재 사용하는 포트 작성
                        proxy_redirect off;
                }

                return 404; # managed by Certbot
        }

        ##
        # Basic Settings
        ##

        sendfile on;
        tcp_nopush on;
        types_hash_max_size 2048;
        # server_tokens off;

        # server_names_hash_bucket_size 64;
        # server_name_in_redirect off;

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

        ##
        # SSL Settings
        ##

        ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
        ssl_prefer_server_ciphers on;

        ##
        # Logging Settings
        ##

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

        ##
        # Gzip Settings
        ##

        gzip on;

        # gzip_vary on;
        # gzip_proxied any;
        # gzip_comp_level 6;
        # gzip_buffers 16 8k;
        # gzip_http_version 1.1;
        # gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

        ##
        # Virtual Host Configs
        ##

        # include /etc/nginx/conf.d/*.conf;
        # include /etc/nginx/sites-enabled/*;
}


#mail {
#       # See sample authentication script at:
#       # http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript
#
#       # auth_http localhost/auth.php;
#       # pop3_capabilities "TOP" "USER";
#       # imap_capabilities "IMAP4rev1" "UIDPLUS";
#
#       server {
#               listen     localhost:110;
#               protocol   pop3;
#               proxy      on;
#       }
#
#       server {
#               listen     localhost:143;
#               protocol   imap;
#               proxy      on;
#       }
#}

server {}가 총 두 개가 있는데 그 이유는 https로 접근하는 경우, http로 접근하는 경우를 처리하기 위해서입니다.
http로 접근하는 경우는 https로 리다이렉트 시키도록 되어있습니다.

🗒️ AWS-EC2 사용할만한 명령어

0️⃣ pm2 명령어

백그라운드에서 node.js를 실행하기 위해서 사용하는 패키지입니다.
기본적으로 node index.js같은 명령어를 사용하면 해당 터미널을 이용할 수 없게 되며, 터미널을 종료하면 실행중인 javascript 파일도 같이 종료됩니다.
이런 문제를 극복하기 위해서 백그라운드에서 node를 실행하는 pm2를 사용합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 설치
sudo npm i -g pm2

# pm2 를 이용해서 "npm start"
pm2 start npm -- start

# 실행중인 프로세스 모니터링
pm2 monit

# 실행중인 프로세스 로그 확인
pm2 log

# 실행중인 프로세스 종료
pm2 kill

1️⃣ nginx 명령어

1
2
3
4
5
6
7
8
9
10
11
# 중지
sudo systemctl stop nginx

# 시작
sudo systemctl start nginx

# 다시 시작
sudo systemctl restart nginx

# 설정 파일 문법 확인
sudo nginx -t

2️⃣ mysql

기본적으로 사용하는 명령어입니다.

1
2
3
4
5
# 접근 ( root라는 유저로 접근하고 비밀번호를 입력하겠다는 의미 )
sudo mysql -u root -p

# 비밀번호 설정
ALTER user 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '변경 비밀번호';

3️⃣ 메모리 부족으로 npm run build가 안 되는 경우

1
2
3
sudo dd if=/dev/zero of=/mnt/swapfile bs=1M count=2048
sudo mkswap /mnt/swapfile
sudo swapon /mnt/swapfile

4️⃣ 메모리 누수 문제 해결

ubuntu에서 메모리 누수 문제 해결 포스트
이 방법은 근본적인 해결법이 아닙니다… 🥲

1
export NODE_OPTIONS=--max_old_space_size=800

📮 레퍼런스

  1. SSH 접근 오류 해결 포스트
  2. ubuntu에서 node.js 설치 참고 포스트
  3. ubuntu에서 mysql 설치 참고 포스트
  4. ubuntu에서 nginx 설치 참고 포스트
  5. ubuntu에서 certbot 설치 참고 포스트
  6. ubuntu에서 메모리 스왑 방법 포스트
  7. ubuntu에서 메모리 누수 문제 해결 포스트
  8. nodebird - inflearn
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.