환경 세팅
홈페이지 개발 사유
입사 후 회사 홈페이지를 보니 난리도 이런 난리가 없었다.
기존 홈페이지는 외주를 통해 구현된 워드프레스 기반 사이트였는데, 사이트를 접속하면 바로 성인 사이트 광고가 나오고 있었다.
이걸 제대로 디버깅하고 싶어도, 악성 스크립트가 매번 발생되는게 아니라 간헐적으로 어쩌다가 발생되도록 되어있다 보니 잡긴 쉽지 않았다.
뭐 현상을 보고나서 바로 알 수 있던 건 전형적인 워드프레스 보안 취약점 공격이라는 것이었다.
확인해 보니 악성 스크립트 코드를 포함시킨 이미지로 교체되어 있었고 해당 이미지가 로드되는 순간 브라우저에서 악성 스크립트가 발생되도록 처리되어 있음을 확인했다.
당연히 관리자 비밀번호도 넘어가도록 키로그처럼 아주 잘해놓은 것으로 보였다.
사내 확인 결과, 워드프레스를 기반으로 회사 사이트를 만들어주는 외주업체가 한두 달 전에 조치를 취해줬는데도 결국 이렇게 되었다고 한다.
관리자에 악성 스크립트를 방어해 주는 플러그인 같은 게 깔려있었는데 해당 외주업체에 물어보니 이것까지만 깔았다고 한다.
워드프레스 사이트를 유지보수 하며 항상 취약점 보안을 생각해 업데이트, 업그레이드를 할 생각을 안 했다는 걸 느낀 게, 담당자는 아무것도 모르는 디자이너였다.
제대로 된 개발자가 입사했으니 이젠 내 업무로 배정될 수도 있겠단 생각이 들어 제대로 만들어봐야겠단 생각에 회사에 외주가 아닌 자체적인 홈페이지 개발을 제안했고 지금 하고 있는 일도 꽤나 많고 급하다 보니 최소한의 시간을 들여 만들겠다 말씀을 드렸다.
급하게 공사 중 페이지를 만들어 배포했다.
기존 호스팅업체를 찾는 과정도 참 힘들었고, 찾고 보니 도메인이 회사 소유가 아닌 호스팅업체 소유라는 점도 어이가 없었다.
결국 별도의 회사도메인을 구매해 새로 진행하는 거로 승인받아 업무를 진행했다.
기존 워드프레스 사이트 로컬 구동
예상되는 악성코드를 포함한 이미지 및 스크립트는 제거 후, Docker를 통해 로컬에 띄어봤다.
글을 쓰는 현재는 로컬에 부담주기 싫어서 별도 proxmox lxd 컨테이너에 옮겨놓은 상태이다.
설정은 감안하고 보는 게 좋을 듯하다.
우선 동일 환경으로 구현해야 하기 때문에, PHP, Mysql 버전을 맞춰야 했다.
기존 홈페이지 호스팅에 설치된 워드프레스 관리자페이지에 들어가 확인해 보니 php 7.3, mysql5.7로 확인되었다.
어차피 phpmyadmin 같은 건 다 파일형식으로 빠져있을 테니까, DB를 덤프하고 아래와 같이 도커로 환경을 구성했다.
services:
wordpress:
image: wordpress:php7.3-apache
volumes:
- ./wordpress/www:/var/www/html
ports:
- "80:80"
environment:
WORDPRESS_DB_HOST: mysql:3306
WORDPRESS_DB_NAME: {동일 데이터베이스 명}
WORDPRESS_DB_USER: {계정}
WORDPRESS_DB_PASSWORD: {비밀번호}
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: {비밀번호}
MYSQL_DATABASE: {동일 데이터베이스명}
MYSQL_USER: {유저명}
MYSQL_PASSWORD: {비밀번호}
ports:
- "3306:3306"
volumes:
- ./db/mysql/data:/var/lib/mysql
- ./db/mysql/init:/docker-entrypoint-initdb.d
덤프 한 sql 파일은 db/mysql/init에 넣어줬다.
위 도커 컴포즈 설정을 보면 볼륨을 잡아준 걸 확인할 수 있다.
이제 컨테이너가 실행될 때 해당 쿼리를 기입해 줄 것이다.
docker-compose up -d 명령어로 도커를 띄우자 사이트가 정상적으로 동작하는 것을 확인할 수 있었다.
자 이제 기존 사이트가 어떻게 생겼나 직접 디벨로퍼 툴로 확인해 가며 개발할 수 있는 환경이 갖춰졌다.
개발
SSG로 배포하기엔 여러 방식이 있다.
단순히 html, js, css를 가지고 만드는 옛날 방식도 있지만, next.js로 구성하는 게 아무래도 손이 덜 간다.
리액트로 하는 것도 방법이지만, dom router를 일일이 지정해 주는 것조차도 귀찮고 내겐 시간이 얼마 없다.
약 3-4일 정도의 시간을 잡고 진행하는 부분인 만큼 빠르게 개발하기 위해서는 Next.js 는 내게 최고의 선택이었다.
왜 SSG 방식으로 배포하는가?
우선 SSG는 Static Site Generation의 약자이다.
빌드 시점에 모든 페이지가 미리 HTML 파일로 만들어져 배포되는 형식이다.
그냥 옛날부터 사용되는 방식으로, 우리가 아는 html, js, css도 결국 같은 방식이다.
Web application server 가 컴파일을 하거나, 서버에서 렌더링 하는 방식이 아니고 그냥 정적인 페이지를 그대로 불러오는 방식이다.
SSG를 선택한 이유는 Cafe24의 무제한 트래픽 방식의 일반 호스팅을 사용하기 위함이다.
괜히 ddos 등의 공격까지 고려해 보안까지 신경 써가며 클라우드 서버라도 사용한다면 물론 자유도도 높고 할 수 있는 건 많겠지만 그만큼 시간과 돈이 많이 든다.
일반적인 Naver Cloud Platform 기준 Server(VPC) 노멀 버전 (2 코어 8GB 메모리 정도? )만 해도 한 달에 적어도 아웃바운드 트래픽 이런거 다 무시한다 치고 그냥 시간당 사용료만 한달 약 16만 원 이상은 나오기 때문이다.
이깟 회사 홈페이지 하나 올릴 건데 16만 원을 매월 태우는 것만큼 아까운 게 없다.
데이터베이스 CURD 도 없고 단순 정보 노출이 다인 사이트에서 불필요하게 내부 Node.js 까지 돌릴 필요는 전혀 없기 때문이다.
게다가 React나 Next.js 에서 SSG로 개발한다 해서 문제 될만한 건 그렇게 많진 않다. 서버 사이드 렌더링을 제대로 못한다는 점 외에는 없다.
어차피 Next.js 에서 App Route 방식의 모든 컴포넌트는 "use client"로 구현할 것이기에 상관이 전혀 없었다.
Next.js SSG 배포 방법
Next.js로 SSG ( Static Site Generation )를 하는 방법은 매우 간단하다.
next.config.mjs 파일을 아래와 같이 설정하면 끝
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: false,
output: "export",
distDir: "dist",
images: { unoptimized: true },
};
export default nextConfig;
<Image> 태그를 써도 이미지 자동 optimized 기능은 SSG에선 사용되지 않기에 끄고,
reactStrictMode는 두 번씩 호출되는 게 개인적으론 싫어서 쓰고,
distDir 은 실제 파일이 떨어지는 경로이다.
output : "export" << 이 부분이 SSG 설정의 끝이다.
Next.js 사이트를 만들기 위한 dependency
{
"name": "homepage",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"@emotion/react": "^11.13.3",
"@emotion/styled": "^11.13.0",
"jotai": "^2.10.0",
"next": "14.2.15",
"react": "^18",
"react-dom": "^18",
"react-slick": "^0.30.2",
"sharp": "^0.33.5",
"slick-carousel": "^1.8.1"
},
"devDependencies": {
"@types/node": "^22",
"@types/react": "^18",
"@types/react-dom": "^18",
"@types/react-slick": "^0.23.13",
"eslint": "^9",
"eslint-config-next": "14.2.15",
"typescript": "^5"
}
}
신나게 개발을 진행했다.
그대로 똑같이 만드는데 워크데이 기준 3-4일 정도 걸린 것 같다.
Cafe24 배포
FTP로 접속해서 www 폴더 내부에 dist에 있는 모든 파일을 넣어주면 끝.
이슈
https://사이트주소/path1/path2/path3
위와 같은 주소를 그대로 복사 후 다시 붙여 넣기 하는 경우 혹은 새로고침 하는 경우 페이지가 뜨지 않는 이슈가 발생한다.
로컬에서 개발할 땐 모를 수밖에 없는 이유는 Node.js 기반으로 다 알아서 처리해주고 있기 때문에 라우팅처리를 잘해줬겠지만 순수 html와 같은 파일들로 빠져진 배포 상태에선 Node.js 기반이 아닌 단순 웹서버 상에서 로드될 뿐이다.
확인해 본 결과, cafe24의 경우. htaccess 파일을 통해 어느 정도 apache 서버의 기능을 컨트롤할 수 있었지만 다양한 방법으로 리다이렉트 처리를 하려 노력해 봐도 이슈를 해결하지 못했다.
차라리 직접 웹서버를 만질 수 있으면 proxy 처리를 할 텐데 아쉬울 뿐이다.
이슈 해결을 위해 검색하던 와중 stackOverFlow에서 한 유저가 기본 아파치 설정에서는 uri 맨 끝단에 / (슬래시)를 붙이지 않으면 파일로써 인식하고 이걸 방지하려면 뭘 수정해야한다. 이게 디폴트였다는는 지나가는 댓글 글에 힌트 삼아 아래와 같이 Next.js 에서 옵션을 추가했더니 이슈가 해결됐다.
해결방안
const nextConfig = {
reactStrictMode: false,
output: "export",
distDir: "dist",
images: { unoptimized: true },
trailingSlash: true, // 추가
};
/ 가 있으면 폴더로 인식하는 거니 각 라우팅 되는 엔드포인트마다 끝에 / 를 붙여주면 되는 부분이다.
예상대로 잘 해결되어 새로고침을 하던, 링크를 클릭해 넘어가던 이슈 없이 잘 해결된 모습을 확인할 수 있었다.
후기
SPA 방식은 그대로 유지되지만 SSG 배포방식이라 그런지 확실히 좀 더 빠르게 느껴진다.
이런저런 스트레스받을 필요 없이 vercel이나 S3 + Cloudfront 등 다른 클라우드 배포 서비스를 이용하면 이럴 필요 없이 알아서 잘 처리해 준다고 하는데 해보진 않았다. 기회가 있다면 언젠가 해보겠지.
Cafe24를 결정한 건 내가 어릴 때부터 많이 사용하던 호스팅업체 이기도 하지만 무제한 트래픽의 가격대가 매우 가성비 있다고 느껴졌기 때문에 이번 기회에 결정하게 됐다.
가격도 가격이지만 ddos 공격을 한번 당해 본 사람으로서 어떻게든 피할 수 없다면 금액이 안 나오는 방향으로 선택했을 뿐이다.
이건 회사꺼니까 하는거고 혹여나 내 사이트를 만든다면 cloudflare 에 올려야겠다. 무료에.. 심지어 ddos 보호까지 된다고 하니 안할 이유가 없지..
이제 이렇게 된 이상 앞으로 홈페이지도 내가 관리할 듯싶다. 괜히 하겠다고 한 건가.. 그냥 외주 맡길걸...
'자바스크립트 > React & Next.js' 카테고리의 다른 글
Next.JS 14 Jotai 사용 시 Detected multiple Jotai instances. 경고 (1) | 2024.01.03 |
---|