본문 바로가기

Virtualization & Deployment/Infrastructure

홈서버 구성기 (Node.js Express, MySQL)

반응형

간단한 게임을 만드는 중인데,

게임 결과(스코어)를 이름과 함께 저장해둘 서버를 만들고 싶었다.

이참에 집 컴퓨터를 서버로 운영해보면 좋은 경험이 될 거 같아서 하루 정도 꼬박 써서 구성해봤다.

다 하고 보니 생각보다 복잡하기도 했고,

무료로 서버를 만들고 싶은 사람에게 참고 자료가 될 수 있을 거 같아서 글로 남겨두고자 한다.

아래는 그 과정이다.

1. MySQL 설치

DB는 MySQL과 MongoDB 중 MySQL로 선택.

선택의 이유는

 

  • 정형 데이터에 강함 (정해진 구조: 이름, 점수, 날짜)
  • 정렬, 검색, 집계 (예: 점수 높은 순 정렬, 날짜별 통계)에서 강력함
  • JOIN이나 복잡한 쿼리를 나중에 확장하고 싶을 때 유리
  • 데이터 무결성 보장 (예: 이름은 꼭 있어야 한다 같은 제약 조건)

 

MySQL 홈페이지에 들어가 설치해주었다.

https://dev.mysql.com/downloads/installer/

 

MySQL :: Download MySQL Installer

MySQL Installer 8.0.42 Note: MySQL 8.0 is the final series with MySQL Installer. As of MySQL 8.1, use a MySQL product's MSI or Zip archive for installation. MySQL Server 8.1 and higher also bundle MySQL Configurator, a tool that helps configure MySQL Serve

dev.mysql.com

테이블을 눈으로 쉽게 확인하기 위한 MySQL Workbench도 추가로 설치해주었다.

2. 간단한 express 서버 구현 및 실행

localhost:3000으로 서버를 열어서 스코어 불러오기, 저장하기가 잘 되는지 먼저 확인했다.

처음엔 SQL 쿼리문을 직접 짰다가, ORM으로 편하게 작성하고 싶어서 sequelize를 도입했다.

https://sequelize.org/

 

Sequelize

Sequelize is a modern TypeScript and Node.js ORM for Oracle, Postgres, MySQL, MariaDB, SQLite and SQL Server, and more. Featuring solid transaction support, relations, eager and lazy loading, read replication and more.

sequelize.org

클라이언트 쪽에선 fetch 함수로 api를 간단히 작성했다.

둘이 정보를 잘 주고 받는 것을 확인했다!

3. 방화벽 규칙 추가 & 포트포워딩

이제 외부에서 내 컴퓨터와 통신을 할 수 있게 해야하므로, 방화벽에 규칙을 추가하고 포트포워딩도 해줘야 했다.

방화벽 규칙 추가

흔히들 그렇게 하듯이, 외부 포트와 내부 포트는 번호를 같게 설정했다.

포트포워딩

핸드폰으로 데이터 켜서 "우리집IP:3000"에 접속해보니 잘되었다.

방화벽, 포트포워딩 작업 모두 잘 되었다는 의미!

4. 중간 테스트

클라이언트측 코드의 BaseURL을 "우리집IP:3000"으로 바꿔주고 로컬 환경에서 테스트 해보니 역시 잘 돼서 깃허브에 푸시하고 배포 환경에서 테스트를 해봤는데..

상황 설명

  • 웹사이트는 https:// 로 안전하게(SSL 암호화) 접속했는데
  • 서버 요청은 http://로 안전하지 않은(암호화 안 된) 요청을 해서
  • 브라우저가 차단함

로컬에서 테스트할때는 클라이언트도 http였기 때문에 괜찮았던 모양.

 

그놈의 HTTPS 때문에 귀찮아졌다.

SSL 인증서를 받으려면 도메인 이름이 필요하다.

5. DuckDNS 등록

우리집에서 사용하는 공인 IP는 동적이라, 도메인을 사서 DNS에 등록해둔다고 해도 IP를 한 번씩 바꿔줘야 하는 상황이 올 거 같았다. 그래서 찾아보니, DDNS 서비스를 이용하면 도메인 이름과 관련 IP 주소를 자동으로 업데이트해준다는 것을 발견했다. 그리고 DDNS 서비스 제공자들 중에는 DuckDNS가 무료를 찾는 사람들한테 많이 쓰이는거 같았다. 뒤에 duckdns.org가 붙긴하지만 무료 도메인명에 DDNS 서비스까지? 이건 안 쓸 이유가 없다. (심지어 오리도 귀엽다)

https://www.duckdns.org/

 

Duck DNS

Duck DNS free dynamic DNS hosted on AWS news: login with Reddit is no more - legal request support us: become a Patreon

www.duckdns.org

회원가입/로그인 이후 원하는 도메인 이름을 기재 후 add domain 하는 것만으로 손쉽게 끝마쳤다.

그렇게 나온 도메인은 http://3jun.duckdns.org

마지막으로, 내 IP를 실시간으로 잘 반영할 수 있도록 5분에 한 번 갱신 요청을 보내야 한다.

# duckdns_update.bat
curl "https://www.duckdns.org/update?domains=3jun&token={내 토큰}&ip="

위와 같이 bat 파일을 만들어서 작업 스케줄러에 5분에 한번 보내도록 작업 스케줄러에 등록했다.

요청이 잘 가긴 하는데, 갈때마다 커맨드 창이 한 2초 떴다가 사라지는게 여간 거슬리는게 아니라 방법을 바꿨다.

'duckdns_hidden.vbs
Set WshShell = CreateObject("WScript.Shell")
WshShell.Run chr(34) & "C:\Users\lsj11\Desktop\USER\duckdns\duckdns_update.bat" & chr(34), 0
Set WshShell = Nothing

앞서 만든 duckdns_update.bat 파일을 창 없이 실행하도록 하는 vbs 파일이다.

최종적으로 작업스케줄러에 등록된 모습은 다음과 같다.

실행파일 wscript.exe / 경로 인자에 vbs파일 경로 넣기

참고로 위의 과정을 수행할때, 경로명에 한글이 있으면 안된다..ㅜ 이것 때문에 20분은 날린듯

6. HTTPS 설정

6.0. 포트 열기

다음의 6.1. 단계에서 Let's Encrypt 서버가 내 도메인에 접속해야하므로, 80번 포트를 열어둬야 한다. 이거 모르고 그냥 했다가

{
"type":"urn:ietf:params:acme:error:connection",
"detail":"59.11.201.30: Fetching http://3jun.duckdns.org/.well-known/acme-challenge/cJaaFndFS5zYTUH97TzG90PCx2EZzw_BU3uiBbbiPHw: Timeout during connect (likely firewall problem)",
"status":400,
"instance":null
}

이런 에러가 나서 뒤늦게 방화벽, 포트포워딩으로 80 포트를 열어줬다.

 

참고로, 뒤에 포트번호가 없는 경우, http는 기본적으로 80번 포트로 요청을 보내고, https는 443번 포트로 요청을 보낸다.

6.1. win-acme

인증서 발급도 DNS처럼 무료로 하고 싶어서 윈도우즈에서 Let's encrypt 사용법을 알아보는데, 리눅스와는 다르게 certbot 대신 win-acme라는걸 쓴다고 한다. https://www.win-acme.com/

 

win-acme

win-acme This is a ACMEv2 client for Windows that aims to be very simple to start with, but powerful enough to grow into almost every scenario. A very simple interface to create and install certificates on a local IIS server A more advanced interface for m

www.win-acme.com

홈페이지에 들어가 아래에 있는 zip파일을 받고 압축을 풀어준 다음,

cmd 관리자 권한으로 실행 > 압축 푼 폴더로 이동 > wacs.exe 실행

M을 눌러서 인증서 발급 절차를 시작한다.

왜 N이 아닌 M이냐면, N으로 하면 인증서들이 윈도우인증 어쩌구로 저장되는데, 그렇게 안하고 여러 pem 파일들로 받기 위함이다. (express에서 https로 서버 실행할때 이 파일들이 필요하다. 이 또한 처음엔 몰랐다가 겪어보고 알게된 사실..)

나머지는 대부분 초록색으로 표시된 추천 옵션 선택하면 된다.

호스트 입력할때 내 도메인 잘 입력해주고, 글 잘 읽으면서 눈치껏 선택하다보면 인증서가 발급된다.

6.2. 코드 수정

6.2.1. 백엔드

인증서를 적용하기 위한 코드를 추가해준다.

키 파일 경로를 그대로 노출시키는게 좀 꺼림칙해서 .env 파일로 빼주었다.

이 때 써야함..

어차피 https로 접속도 되겠다, 그냥 3000번 말고 443번으로 서버 포트를 변경해주었다.

https://3jun.duckdns.org 여기로 들어갈 수 있게 된것이다.

처음에 http:// { 길고 긴 우리집ip } :3000 이었던것에 비교하면 장족의 발전이 이뤄졌다.

6.2.2. 프론트엔드

BaseURL을 https://3jun.duckdns.org 로 바꿔주었다.

7. 중간 테스트 2

푸시하고 배포환경에서 테스트해보니 성공.

한 가지 문제라고 한다면 속도가 눈에 띄게 느렸다.

고작 점수 10개 가져오는데 1~2초 사이로 걸린듯..

브라우저를 통해 https://3jun.duckdns.org 에 직접 접속하는 것도 꽤 오래 걸렸다.

https://{우리집ip} 에 접속하면 시간이 오래 걸리지 않은걸 보아 DuckDNS 쪽의 문제 같았다.

그렇게 다른 방법을 찾아보게 되었다.

8. iptime  DDNS

검색하던 중 알게된 iptime DDNS. 포트포워딩을 하러 들어갔던 iptime 관리자 메뉴 한구석엔 DDNS 기능이 숨어있었다. 설정이 꽤 오래걸렸던 DuckDNS지만, 과감히 포기하고 갈아탔다. 호스트 이름과 사용자 ID만 입력하니 간편하게 등록이 됐다.

바로 사용이 가능했던건 아니고, 접속상태에 "정상 등록"이 뜨기 전 "등록중" 상태가 꽤 오래 갔던 것으로 기억한다.

iptime DDNS의 속도는 다행히 이전보다 빨랐다.

9. 인증서 재발급

3jun.duckdns.org에서 3jun.iptime.org로 갈아탔으니 인증서도 다시 발급 받아야했다.

앞선 6번 과정을 다시 거쳤는데, 문제가 발생했다.

{
"type":"urn:ietf:params:acme:error:caa",
"detail":"During secondary validation: While processing CAA for 3jun.iptime.org: CAA record for iptime.org prevents issuance",
"status":null,
"instance":null
}

이게 무슨 의미냐면, iptime.org 도메인의 CAA 레코드(인증서 발급 정책)가 네가 SSL 인증서를 발급 받는 걸 막고 있다는 것이고, 다시 말해, iptime.org 도메인은 Let's encrypt로 인증서를 발급 받을 수 없다는 것을 의미했다. 이 정책을 바꿀려면 도메인의 소유자여야 하는데, iptime.org는 내 소유의 도메인도 아니기 때문에, 결국 win-acme로는 인증서를 받을 수 없었다.

참고로, CAA 레코드는 도메인 주인이 "우리 도메인에 SSL 인증서는 어떤 회사만 발급할 수 있어" 라고 지정해놓는 거라고 한다.

10. 도메인 구매

결국 내가 생각해낸 방법은 다음과 같다.

도메인을 산다 > 도메인을 iptime DDNS에 연결한다

이러면 DNS를 두 단계 거치는 비효율이 생기긴 하지만 내가 직접 IP를 수정하지 않아도 되는거 아닌가? 라는 생각이었다.

그렇게 가비아에서 도메인을 구매했다.

https://www.gabia.com/?utm_source=google-gdn&utm_medium=performanceMax&utm_campaign=%EA%B0%80%EB%B9%84%EC%95%84&utm_term=%EA%B0%80%EB%B9%84%EC%95%84

 

웹을 넘어 클라우드로. 가비아

그룹웨어부터 멀티클라우드까지 하나의 클라우드 허브

www.gabia.com

3jun.store 를 500원 주고.

그리고는 레코드 설정을 해주었다.

ㅋㅋㅋㅋㅋㅋㅋ

 

나중에 알게 된건 @ 즉 루트 도메인은 CNAME으로 설정해두면 안된다더라.

일단은 다른 용도로 쓰일 일이 없고 문제없이 동작해서 냅두려고 한다.

10.1. CNAME은 왜 서브도메인용으로 써야 할까?

CNAME 레코드는 "이 도메인은 다른 도메인에 완전히 위임한다"는 뜻으로, 만약 example.com (루트 도메인)에 CNAME을 걸면 그 도메인에 다른 레코드(MX 레코드, TXT 레코드, NS 레코드 등) 를 추가할 수 없게 된다.
그런데 루트 도메인(example.com)은 이메일(MX 레코드), 도메인 이름 서버(NS 레코드), 기타 필요한 정보들을 반드시 추가해야 한다.
그래서 루트 도메인에는 CNAME을 쓰면 안 되고, 서브도메인 http://www.example.com, blog.example.com 같은 데만 쓴다.

11. 마무리

3jun.store로 인증서를 재발급 받았고, 이번엔 제대로 발급이 됐다. 접속도 잘 되었기에 프론트, 백 코드 모두 일부 수정해주었고, 그렇게 내가 만든 게임에 홈서버 붙이기는 일단락되었다.

https://3jun.store

 

https://3jun.store

 

3jun.store

이 홈 서버를 어디에 사용할지도 많이 고민해보면 좋을거 같고, 오래 켜둘 수 있는 하드웨어를 찾아 그곳에서 서버를 실행해주면 더욱 좋을 거 같다.

CNAME 문제도 가급적 빨리 해결해봐야겠다.

반응형