지난 편에서 AWS Amplify 백엔드까지 만들어 봤는데요, 마지막 연습문제에서 논의한 것처럼 가령 prisma를 사용한다던지 하는 이유로 API 서버를 EC2에서 express로 수행하는 경우, Mixed Contents 오류가 발생하는 것을 보았습니다. AWS Amplify로 호스팅된 앱 주소가 https로 시작, 즉 HTTPS(secure HTTP) 프로토콜인데, 앱 안에서 http://나 일반 웹소켓(ws://) 등을 연결하는 경우 기대하는 보안 수준(HTTPS)에 어긋나므로 허용하지 않겠다는 의미입니다. 보통 로그는 다음과 같습니다.
APIs.ts:444 Mixed Content: The page at 'https://dev.aaaaaaaaaa.amplifyapp.com/' was loaded over HTTPS, but attempted to connect to the insecure WebSocket endpoint 'ws://3.33.x.xx:444/ws/'. This endpoint should be available via WSS. Insecure access is deprecated.
지금까지는 이럴 때 Chrome 주소창 옆에 있는 자물쇠 모양을 클릭해서 Site settings - Security and Privacy - Permissions - Insecure content를 Block에서 Allow해주면 되긴 했는데 deprecated된 기능이므로 이제부터는 앱 자체가 HTTPS 요건을 만족하도록 해야 합니다.
즉, EC2에 올린 우리 express 서버에서 웹 소켓을 열 때, 일반 웹소켓(ws://)가 아닌, 시큐어 웹소켓(wss://)을 열어야 하는데요, 지금부터 wss를 어떻게 만드는지 살펴보겠습니다.
인증서
소수의 성질을 이용한 비대칭 암호화에서는 두 개의 키 페어(public key와 private key)를 사용하는데요, 개략적으로 설명하자면 연결된 서버가 제공하는 인증서를 받아 그 안에 public key로 내가 보내는 데이터를 암호화해서 보내면 암호문은 오직 서버가 가진 private key로만 풀 수 있게 됩니다.
우리가 지금 서버를 만들고 있기 때문에 우리만의 인증서가 필요한데요, 인증서란 내가 맘대로 만드는 것이 아니라 공신력을 가진 기관이 인증해준다는 의미입니다. AWS Amplify로 호스팅된 사이트를 열고 주소창 자물쇠를 눌러 certificate 정보를 보면, 아래와 같이 issued by Amazon, 즉 아마존이 인증해줬다는 의미죠.
AWS에서도 인증서를 발급 받을 수 있지만 유료입니다.
대신 Let's encrypt를 통해서 무료 인증서를 발급 받아 볼 텐데요, 이때 현재 AWS EC2 서버를 가리키는 도메인이 필요합니다. 아쉽게도 EC2에서 기본 제공되는 ec2-3-33-xxxxxx.ap-northeast-2.compute.amazonaws.com을 사용할 수 없으므로(let's encrypt에서 거절됨) Freenom에서 1년짜리 무료 도메인을 받아 EC2와 연동합니다.
- sudo install nginx certbot python3-certbot-nginx
- sudo certbot --nginx -d rubendomain.ml -d www.rubendomain.ml
발생했던 오류들
- no valid A records ~~~ - Freenom 반영에 시간이 좀 걸리니 5분쯤 후에 해 보세요.
- firewall ~~~ - AWS EC2 Security group 설정에서 80 포트가 열려있어야 합니다.
- too many failed authorizations recently ~~~ - 너무 많이 시도했을 때 발생하는 오류로 1시간 후 다시 도전합니다.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations! You have successfully enabled rubendomain.ml
You should test your configuration at:
https://www.ssllabs.com/ssltest/analyze.html?d=rubendomain.ml
https://www.ssllabs.com/ssltest/analyze.html?d=www.rubendomain.ml
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/rubendomain.ml/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/rubendomain.ml/privkey.pem
Your cert will expire on 2022-01-01. To obtain a new or tweaked
version of this certificate in the future, simply run certbot again
with the "certonly" option. To non-interactively renew *all* of
your certificates, run "certbot renew"
- If you like Certbot, please consider supporting our work by:
인증서가 완료되면 위와 같은 로그가 나오는데요, /etc/letsencrypt/live/rubendomain.ml/ 폴더 안에 인증서와 private key가 설치됩니다. 이제 이 인증서와 키를 가지고 HTTPS/WSS Node.js express를 만들어 봅시다.
Express HTTPS/WSS
try {
const fs = require('fs');
const path = require('path');
const dir = '/etc/letsencrypt/live/rubendomain.ml/';
const options = {
ca: fs.readFileSync(path.resolve(dir, 'fullchain.pem')),
key: fs.readFileSync(path.resolve(dir, 'privkey.pem')),
cert: fs.readFileSync(path.resolve(dir, 'cert.pem'))
};
const httpsServer = require('https').createServer(
options,
function (request, response) {
console.log('Received request for ' + request.url);
response.writeHead(404);
response.end();
});
httpsServer.listen(8000, function () {
console.log('HTTPS Server is listening on port ' + 8000);
});
} catch (err) {
console.log("FAILED to provide HTTPS");
console.log(err);
}
혹시 문제가 있나요?
- AWS EC2 Security group에서 443(https) 및 8000 포트가 열려있는지 확인해 보세요.
Tip. React 프록시 설정 - setupProxy.js vs axios.interceptors
React 앱에서 프록시 설정할 때 사용하는 setupProxy.js는 AWS Amplify에서 사용할 수 없습니다.
AWS Amplify 콘솔 - App settings - Rewrites and redirects를 활용하는 방법도 있을지 모르겠지만 잘 모르겠고,
axios.interceptors를 이용하면 아래와 같이 쉽게 프록시 설정, 즉 기본 주소를 변경할 수 있습니다.
axios.interceptors.request.use(config => {
config.url = 'http://3.33.xx.xx' + config.url;
return config;
});
이럴 때 자주 발생하는 오류가 CORS(Cross-Origin Resource Sharing)인데요, 접속한 사이트에서 외부 어딘가로 접속할 때 발생하는 오류인데요, 이를 허용하려면 require('cors') 및 express(cors) 코드를 추가하면 됩니다.
마치며
지금까지 AWS Amplify를 적용해 보았는데요,
이 프로젝트를 그대로 새로운 개발환경(PC)로 옮겼을 때도 잘 되는지 검증해봅시다.
References
참고했던 글들을 링크합니다.
- 인증서를 새로 설치할 때 https://xxcv.tistory.com/6
'IT > Network & OS' 카테고리의 다른 글
[AWS] IoT + React App + Amplify (0) | 2022.02.23 |
---|---|
[AWS] IoT (0) | 2022.02.21 |
[AWS] Amplify (0) | 2022.02.09 |
[AWS] RDS MySQL Prisma (0) | 2022.02.06 |
[AWS] EC2 (0) | 2022.02.05 |