외주를 진행하던 중에 배포 관련해서 요청 사항이 들어왔다.
일단, 저희 쪽에서 EC2는 만들어 드릴께요~
EC2 두개 드릴테니까 하나는 서버 용으로, 그리고 나머지 하나는 프런트 배포용으로 사용해주세요.
음... 일단 배포 환경을 만들어 주신다니... 땡큐지~
그럼 일단 서버부터 해볼까?
해서 정말 어렵지 않게 서버(spring boot) 배포까지는 끝냈다.
하지만... 문제가 있었으니...
바로 외주사 측의 추가 요청사항들이었다...
아 근데 저희 로드 벨런서는 안쓸꺼에요
그리고 프런트는 배포해야 하는데, 하나의 메인 루트 도메인에, 서브 도메인을 나눠서 두 개의 페이지를 운영해주세요
아 그리고 Route 53으로 ec2에 연결하는 것은 안될꺼에요
DNS 서비스 업체랑 컨택하셔서 A레코드 연결 해주시고, DB는 RDS로 사용할께요
원래 항상 하던 방식으로 로드벨런서 설정하고, EC2 인스턴스 생성 후에 연결하는 것이 불가능한 상황이 생겨버린 것이다!
하지만 개발은 끝났고 배포한 하면 되는데 그만한다고 할 수 없는 노릇이니... 일단은 방법을 찾아보기로 했다.
외주사 측에서 바라는 것은 https://test.com 이 메인 도메인이면, https://test.com/phone 을 서브 도메인으로 하여 두 개의 React 코드를 하나의 ec2 인스턴스에서 돌리는 것이었다.
이를 해결하기 위해 여러개의 방법을 찾아보았는데,
그렇게 Nginx를 기반으로 한 프런트 배포를 하게 되었다!
일단 Nginx를 사용하기 위해서 nginx를 설치했고, nginx.conf 파일을 아래처럼 기본적인 세팅을 진행했다.
listen 443 ssl;
server_name '도메인 주소';
ssl_certificate '.pem 파일 위치';
ssl_certificate_key 'privatekey 파일 위치';
location / {
root 'build 폴더 위치';
try_files $uri $uri/ /index.html;
}
location /phone {
alias '서브도메인 build 폴더 위치';
try_files $uri $uri/ /phone/index.html;
}
}
이렇게 설정하고 바로 되면 얼마나 좋았겠을까...
도대체가 메인 도메인(https://test.com) 화면과, 서브 도메인(https://test.com/phone) 화면이 흰화면으로 뜨고 제대로 작동하지 않는 것이었다...
일단 내가 했던 방법은, nginx.conf파일 코드에 문제가 있는지 확인해보는 것이었다.
일단 아래 코드를 사용해서 nginx 프로세스의 사용자를 확인해보았다.
ps aux | grep nginx
그 결과 디렉토리 사용자가 ec2-user로 설정되어 있는 것을 확인했고, Nginx가 디렉토리 에 접근하지 못하는 것을 해결하기 위해 아래와 같이 권한을 주었다.
sudo chown -R nginx:nginx /path/to/directory
sudo chmod -R 755 /path/to/directory
그 다음에 nginx 설정 파일 테스트 후에 재시작을 해주었다.
sudo nginx -t # 설정 파일 테스트
sudo systemctl restart nginx
근데 여기부터가 진짜 지옥이었다...
https://test.com/phone 은 무슨 짓을 해도 당최 화면이 뜨지 않는 것이었다...
페이지에서 network log도 확인해보니 아무런 문제도 없고 200을 띄우고 있었다, 그래서 조금 더 원초적인 문제일 것으로 생각했다.
그래서 SELinux가 켜져 있을 가능성을 생각하여, SELinux를 완전히 종료시키고 서버를 돌려보았음에도 동일하게 흰 화면밖에 뜨지 않았다.
라는 생각에 바로 /phone 도메인을 배포할 때 사용했던 build 파일의 디렉토리를 main 도메인의 배포 디렉토리로 옮겨서 테스트 해보았다.
그런데... 왠걸...
/phone 도메인에서는 흰 화면을 띄우던 build 파일이 파일 디렉토리만 마꿔 메인 도메인에서 배포를 하니 너무나도 잘 돌아가는 것이었다...
이렇게 단언해서 판단한것이 나의 가장 큰 실책이었다.
이 시점부터 build 파일에는 문제가 없다고 가정하고, 에러 로그를 계속하며 확인하며 config 파일을 수정하는 것에만 시간을 쏟았다.
그런데 진짜 암만 봐도 config에는 문제가 없는 것 같았다.
그래서 처음부터 차근차근 짚고 넘어갔다.
내가 배포하고 있었던 방식은, npm run build를 사용해서 react의 build 파일을 메인 도메인 react 코드와, 서브 도메인 react 코드에서 각각 만들고, filezilla로 ec2에 접근해 파일을 옮긴 후에 nginx로 돌리는 형식이었다.
그렇다면, nginx에서 해볼 수 있는 것은 다 해보았고, ec2 설정 또한 확인해보았다.
react 코드에서 자체적으로 라우팅 해주는 것은 제대로 한 것을 확인했으니...
그렇다면 남은 것은 filezilla에서 ec2로 넘기는 과정에서 이슈가 생겼을 가능성과 build 과정에서의 문제인데
일단 filezilla에서 넘어오는 파일의 무결성은 build 파일의 디렉토리 스왑으로 이미 확인한 바가 있었다.
본인은 백엔드 개발을 하고 있고, npm에 대해 깊게 알고 있지는 않았다.
분명히 build 과정에서 문제가 생겼을 것이 자명했기에... npm run build에 대해서 조금 더 찾아보았다.
코드 번들링 하고, 코드 압축 후에 환경설정하고 정적파일을 생성한다...
흠... 여기까지는 알고 있는 것과 다른 부분이 없었다.
그렇게 생성되는 파일은 아래와 같았다.
build/
├── index.html # 앱의 진입점 HTML 파일
├── static/
│ ├── css/ # 최적화된 CSS 파일
│ ├── js/ # 번들링된 JavaScript 파일
│ ├── media/ # 이미지, 폰트 등 정적 리소스
└── asset-manifest.json # 리소스 매니페스트 (파일 경로 정보)
자주 봤던 그 파일 구조인데, 평소에는 보이지 않았던 거슬리는 부분이 하나 있었다.
이 파일에 담겨있는 정보들을 확인해 보니 정적 파일 경로 정보를 제공하고 동적으로 로드될 청크 파일들의 경로를 관리하는 역할을 하고 있었다.
그리고 이 파일의 내부를 확인하니...
{
"files": {
"main.js": "/static/js/main.abcdef.js",
"main.css": "/static/css/main.123456.css",
"runtime-main.js": "/static/js/runtime-main.654321.js",
"index.html": "/index.html"
},
"entrypoints": [
"/static/js/runtime-main.654321.js",
"/static/js/main.abcdef.js",
"/static/css/main.123456.css"
]
}
여기서 문제점을 발견했다.
무엇이 문제였던 것 같은가?
문제점은 바로 asset-manifest.json 파일에서 Public url 경로를
"main.js": "/static/js/main.abcdef.js" 로 설정하고 있었다는 점이었다.
우리는 서브 도메인을 /phone으로 설정했으니, 정적 파일의 제공 또한 /phone으로 가야함이 맞다.
즉 이 부분이 "main.js": "/affiliate/static/js/main.abcdef.js"으로 수정되야 했던 것이었다.
이를 확인하고, 나는 바로 public url을 반영하여 build를 진행했다.
PUBLIC_URL=/phone npm run build
우리가 nginx.confing에서 하위 경로를 /phone으로 설정했으니 build 시에 public url을 /phone으로 지정해주어야 정적 리소스들을 로드할 때의 기본 경로를 /phone으로 지정해줄 수 있는 것이었다.
설레이는 마음으로 이를 인스턴스에 올렸고, 페이지의 캐시를 지우고 다시 시도하니...
정말 손발이 발발 떨렸던 것 같다...
정말 배포를 해면서 너무 많은 것을 느꼈는데...
깊은 공부의 필요성을 느끼면서 동시에 넓은 공부의 필요성을 느꼈던 것 같다.
백엔드라고 npm run build를 몰라도 되는 것이 아니고, 그렇다고 npm run build가 어떻게 돌아가는지 모르고 남발하면 안되었듯이, 깊고 넓은 공부를 해야겠다고 다짐하게 되는 시간이었다.
그리고 무엇보다 크게 배운 것은, 눈에 보이는 현상만으로 섣불리 원인을 판단하지 말자는 것이었다.
나의 경우에 build 파일이 잘 돌아가는 것을 확인하고 환경의 문제일 것이라고 단언했던 부분이 잘못이었다.
그보다 더 근본적인 문제가 있을것이라고 생각하기까지는 무려 하루라는 긴 시간이 있었다.
좀 더 시야를 넓혔다면 더 쉽게 문제를 해결할 수 있지 않았을까?