재고관리 프로그램 프로젝트를 진행하며 배포 과정에서 웹서버로 Nginx를 택하였고 Nginx Proxy 서버에 SSL 인증서를 등록하여 HTTPS를 적용하였다.
해당 과정을 잊지 않기 위해 블로깅하려고 한다. 이 글은 AWS EC2에 1차 배포가 되어있다는 가정 하에 작성된 글이다.
Route 53 도메인 구매 및 연결
1. gabia에서 원하는 도메인을 검색하여 구매한다.
2. 가비아 도메인 관리 페이지의 네임 서버를 설정하기 위해 AWS Route 53 대시보드에 접속한다.
3. Route 53 호스팅 영역에 접속하여 구입한 도메인을 등록해준다.
4. 생성 후 해당 호스팅영역의 레코드를 조회한다.
- 해당 초록박스에 포함되는 부분을 네임서버 설정에 작성해준다.
DNS 타입
- A 레코드
- A 레코드 추가 시 서브도메인이 생성되어 IP로 사이트를 연결할 수 있다.
- MX 레코드
- 메일 연결 시 사용
- 설정 시 주소 끝에 "." 을 반드시 입력
- CNAME 레코드
- 메일, 블로그 연결 등에 사용
- 한글 도메인은 사용 업체에 따라 메일을 지원하지 않을 수 있다.
- TXT 레코드
- SPF 레코드 입력 시 사용
- 사용 도메인 스팸 차단 방지 위해 SPF 레코드 등록 권장
- SRV 레코드
5. EC2 터미널 접속하여 /etc/nginx/sites-available
에 파일 생성
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| server {
server_name 도메인명;
root /var/www/<실행할 html파일이 위치한 디렉토리>;
index index.html index.htm;
location / {
add_header 'Access-Control-Allow-Origin' '*'; # cors 설정. spring에서 설정한 경우, 중복 설정 시 충돌되기때문에 해당 설정은 제외해야함
proxy_pass EC2 인스턴스 주소;
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;
}
}
|
6. /etc/nginx/sites-enabled
에 심볼릭 링크 생성
- default 파일을 변경했다면 생략해도 된다.
1
| cd /etc/nginx/sites-enabled
|
1
| sudo ln -s /etc/nginx/sites-available/5에서_생성한_파일
|
7. Nginx 재시작
1
2
| sudo service nginx restart
|
실행이 안될 시
nginx -t 명령어를 입력하여 설정 파일에 문법오류가 있는지 확인
SSL 적용
1. certbot 설치
1
| sudo apt-add-repository -r ppa:cerbot/cerbot
|
2. certbot의 Nginx 설치
- 필자는 Ubuntu 22.04를 사용해서 python3을 설치했다.
- Ubuntu 18.04이하인 경우 python-certbot-nginx로 설치하길 바란다.
1
| sudo apt install python3-certbot-nginx
|
3. SSL 인증서 발급
1
| sudo certbot --nginx -d 도메인명 -d www.도메인명
|
4. Nginx 설정 파일 변경
- ssl 인증서를 발급하게 되면 certbot이 자동으로 설정파일을 작성해준다.
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
| server {
# 포트 포워딩 설정
server_name 도메인명;
root /var/www/<실행할 html파일이 위치한 디렉토리>;
index index.html index.htm;
if ($host = 도메인명) {
return 301 http://$host$request_uri;
} # managed by Certbot
listen 80;
listen [::]:80;
return 404; # managed by Certbot
}
server {
# HTTPS configuration
listen 443 ssl;
listen [::]:443 ssl;
server_name 도메인명;
ssl_certificate /etc/letsencrypt/live/도메인명/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/도메인명/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
# React 프론트 서버 proxy
location / {
proxy_pass 프론트 배포 주소;
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 $scheme;
}
# Spring boot 백 서버 proxy
location /api {
proxy_pass 백 배포 주소;
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;
}
}
|
5. Nginx 재시작
1
| sudo service nginx restart
|
- 프론트 서버와 백 서버 모두 배포가 된 상태에서 해당 도메인으로 접속하게 되면 https로 접속되는걸 확인할 수 있다.
SSE 통신 Nginx 사용 시 주의
필자는 프로젝트에서 SSE 통신을 활용한 실시간 알림을 구현했다.
분명 로컬에서 정상 작동하는 걸 확인하고 배포를 진행했으나 SSE 통신에서 간헐적으로 500에러가 발생했다.
Nginx Reverse Proxy를 사용했기 때문에 아래와 같은 원인들로 SSE 통신 시 에러가 발생했던 것이다.
- Nginx는 Upstream으로 요청을 보낼 때,
HTTP/1.0
을 사용한다. HTTP/1.1
은 지속 연결이 기본이지만 Nginx에서 WAS로 요청을 보낼 때 사용하는 HTTP/1.0
은 Connection: close 헤더를 사용하여 지속 연결을 닫아버린다.- SSE 통신은 지속 연결이 되지 않으면 제대로 동작하지 않는다.
그래서 Nginx에 HTTP 버전을 1.1로, 헤더에 Connection ‘’ 로 변경해주는 설정이 추가로 필요했다.
Nginx 설정 파일에서의 프록시 부분에 이와 같은 설정을 추가해주었다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| # React 프론트 서버 proxy
location / {
proxy_pass 프론트 배포 주소;
...
proxy_set_header Connection ''; # 추가
proxy_http_version 1.1; # 추가
}
# Spring boot 백 서버 proxy
location /api {
proxy_pass 백 배포 주소;
...
proxy_set_header Connection ''; # 추가
proxy_http_version 1.1; # 추가
}
|
그리고 SSE 통신에서 서버는 응답에 Transfer-Encoding: chunked
를 사용하는데, Nginx의 proxy buffering 기능은 서버의 응답을 버퍼에 저장해두었다가 버퍼가 차거나, 서버가 응답 데이터를 모두 보내고 나면 전송하는 기능이기에 SSE 통신의 실시간성이 떨어지고 제대로 동작하지 않는 상황이 발생할 수 있다.
따라서 proxy buffering 기능을 비활성화 하는 것이 좋지만, Nginx의 설정파일에서 비활성화를 하게되면 SSE 이외의 모든 통신에서도 비활성화되기에 비효율적이라고 볼 수 있다.
그래서 필자는 SSE 구현 코드 내에서 응답 시에 X-Accel-Buffering: no
헤더를 추가해주었다.
1
2
3
4
5
6
7
8
9
10
11
| @Override
public SseEmitter connection(String lastEventId, HttpServletResponse response) {
...
response.setHeader("X-Accel-Buffering", "no");
...
return emitter;
}
|
참고 블로그
bitkunst.tistory.com
yeonyeon.tistory.com
tecoble.techcourse.co.kr