분실물 찾기 서비스 프로젝트를 진행 중인데, 로컬에서 잘 동작하던 chatting 기능이 운영 환경에서 먹통이 되는 문제가 발생했다.
하루를 통째로 사용해서 해결한 과정을 공유하고자 한다.
나는 Websocket을 쓸 때, Socket.io를 사용하지 않고 구현했다.
크게 3가지 설정을 해주면 해결할 수 있다.
기본적으로 아래 코드처럼 생성자를 추가할 것이다.
let socket = new WebSocket("ws://localhost:8080/ws");
운영 환경에서 동작하기 위해서는 localhost대신 도메인으로 교체해주어야한다.
나는 Thymeleaf를 사용했기 때문에, 아래와 같이 작성했다.
let socket = new WebSocket("ws://" + [[${url}]] + "/ws"); //ex) "ws://wanna-find.com/ws"
나의 경우 local과 prod의 url을 다르게 넣어주고자, 설정파일에 websocket.url값을 각각 다르게 적어주고, Controller에서 @Value
로 해당 값을 가져와, model에 넣어줘서 가져오도록 하였다. 상황에 따라 원하는 방식으로 url을 넣어주면 된다.
나의 경우 Nginx를 사용해 포워딩을 해주고 있기 때문에, 관련 설정을 추가해주어야 했다.
목표는 Client의 주소가 "ws://wanna-find.com/ws"라면, "http://localhost:8080/ws"로 포워딩해주는 것이다.
왜냐하면, WebSocketConfig에서 handler path가 아래과 같기 때문이다. 이에 따라 포워딩 결과를 맞춰서 설정해주면 된다.
//WebSocketConfig.java
@Configuration
@EnableWebSocket
@RequiredArgsConstructor
public class WebSocketConfig implements WebSocketConfigurer {
private final WebSocketHandler webSocketHandler;
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(webSocketHandler, "/ws").setAllowedOrigins("*");
}
}
그래서 EC2에 접속해서, Nginx설정 파일에 location을 추가해주면 된다.
//nginx 설정 편집
sudo vi /etc/nginx/nginx.conf
// /etc/nginx/nginx.conf
server {
server_name xxdomain.com www.xxdomain.com;
...
location /ws { #xxdomain.com/ws로 들어올 경우를 받음.
proxy_pass http://localhost:8080/ws; #포워딩 결과값
proxy_http_version 1.1; #꼭 추가
proxy_set_header Upgrade $http_upgrade; #꼭 추가
proxy_set_header Connection "Upgrade"; #꼭 추가
proxy_set_header Host $host; #꼭 추가
proxy_set_header X-Real-IP $remote_addr; #option
proxy_set_header X-Forwarded-Host $host; #option
proxy_set_header X-Forwarded-Server $host; #option
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;#option
}
...
}
받은 요청을 Nginx에서 리버스 포워딩하게 되는데, HTTP요청을 Upgrade함으로서 Websocket을 사용할 수 있다.
Websocket은 HTTP와 전혀 다른 프로토콜이지만, HTTP에서 유도된다.
WebSocket 핸드셰이크는 HTTP 업그레이드 기능을 사용하여 호환할 수 있다.
이를 통해 WebSocket 애플리케이션은 기존 인프라에 쉽게 맞출 수 있다.
예를 들어 WebSocket 애플리케이션은 표준 HTTP 포트 80 및 443을 사용할 수 있으므로, 기존 방화벽 규칙을 사용할 수 있다.
자세한 설명은 해당 링크 참고하면 좋을 것 같다.
Nginx를 이용한 WebSocket reverse proxy
이후, Nginx를 재실행해주고, 반영이 안된다 싶으면 application도 재배포해보기 바란다.
//Nginx 재시작
sudo service nginx restart
HTTPS 사이트에서 HTTP 사이트 요청 시 발생하는 보안 문제이다.
아래와 같은 문구가 개발자 도구 console 창에 떴다.
Mixed Content: The page at 'https://...' was loaded over HTTPS,
but requested an insecure script
'http://...'.
This request has been blocked; the content must be served over HTTPS
<head>
에 아래 한 줄을 추가하면 해결된다.
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
원인은 아무래도 wss://
가 아닌 ws://
를 사용해서거나, 포워딩을 http://
로 해서 발생한 문제 같다.
이렇게 EC2 Nginx 환경에서 WebSocket으로 Chatting 구현하는 법을 정리해보았다.
검색했을 때, Socket.io를 사용하는 방법만 많아서, 해결하는데 더 오랜 시간이 걸렸던 것 같다.
Socket.io를 사용하면, 더 많은 기능을 사용할 수 있다고 하니 추후에 리팩토링 해봐야겠다.
웹소켓 Socket.io와 WS의 차이
Nginx를 이용한 WebSocket reverse proxy
로컬에서는 잘만 되는 WebSocket 채팅 EC2에서는 외않뒈?
websocket과 ssl 사용을 위한 nginx 설정
Mixed content 문제 해결(https 사이트에서 http 사이트 요청 시 발생하는 보안 문제)