본문 바로가기

개발기/플레이톡

4편: 미니PC 홈서버에 Docker Compose로 배포하기

반응형

GMK G3 모델

배포 환경

클라우드 대신 집에 있는 미니PC를 서버로 사용했습니다.

  • OS: Rocky Linux 9.4
  • 기존 서비스: 세이브더버니즈 테스트 페이지가 이미 올라가 있었고, nginx가 Docker Compose로 돌고 있는 상태
  • 목표: 기존 서비스 건드리지 않고 playtalk 추가

Railway 같은 클라우드 서비스도 고려했지만, 이미 홈서버가 있고 외부 접속도 되는 상태라 굳이 쓸 이유가 없었어요.

Docker Compose 구조

서버가 React 빌드 파일도 같이 서빙하는 단일 컨테이너 구조로 갔습니다. 프론트/백엔드를 분리하면 Socket.io CORS 설정이 복잡해지거든요.

# docker-compose.yml
services:
  app:
    build: .
    container_name: playtalk-app
    restart: always
    ports:
      - "4000:4000"
    env_file:
      - .env
    volumes:
      - ./data:/app/server/data  # 통계/랭킹 데이터 영속성

 

포트는 4000번으로 잡았어요. 기존 세이브더버니즈 백엔드가 3000번을 쓰고 있어서 충돌을 피하기 위해서입니다.

# Dockerfile
FROM node:20-alpine

WORKDIR /app

# 클라이언트 빌드
COPY client/package*.json ./client/
RUN cd client && npm install
COPY client/ ./client/
RUN cd client && npm run build

# 서버 설정
COPY server/package*.json ./server/
RUN cd server && npm install
COPY server/ ./server/

# 빌드 결과물을 서버 public 폴더로 복사
RUN cp -r client/dist server/public

EXPOSE 4000
CMD ["node", "server/src/index.js"]

 

playtalk-app컨테이너가 실행중이다

nginx 리버스 프록시 설정

기존 nginx가 Docker Compose 컨테이너로 돌고 있어서, 세이브더버니즈 docker-compose.yml에 playtalk 서버 블록을 추가했습니다.

server {
    listen 80;
    server_name playtalk.kr www.playtalk.kr;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    server_name playtalk.kr www.playtalk.kr;

    ssl_certificate /etc/letsencrypt/live/playtalk.kr/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/playtalk.kr/privkey.pem;

    location / {
        proxy_pass http://192.168.x.x:4000;  # 내부 IP 사용
        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;
        proxy_cache_bypass $http_upgrade;
    }
}

한 가지 주의할 점이 있었어요. nginx 컨테이너에서 localhost:4000으로 proxy_pass를 설정하면 안 됩니다. nginx와 playtalk가 서로 다른 Docker 네트워크에 있어서 localhost로 찾을 수가 없거든요. 미니PC의 내부 IP를 직접 써야 해요.

도메인으로 playtalk.kr 에 접속한 모습

SSL 인증서

Let's Encrypt certbot으로 발급했습니다. nginx가 컨테이너 안에 있어서 순서가 중요했어요.

# 1. nginx 컨테이너 중지 (80포트 비워야 함)
docker compose stop nginx

# 2. certbot으로 인증서 발급
sudo certbot certonly --standalone -d playtalk.kr -d www.playtalk.kr

# 3. nginx 재시작
docker compose start nginx

인증서는 /etc/letsencrypt/live/playtalk.kr/에 생성됩니다. 이걸 nginx 컨테이너 볼륨으로 마운트해서 사용했어요.

 

환경변수 관리

민감한 정보는 전부 .env 파일로 관리합니다.

PORT=4000
ADMIN_ID=
ADMIN_PASSWORD=
ADMIN_ALLOWED_IPS=

.env는 .gitignore에 추가해서 GitHub에 올라가지 않도록 했어요. 서버에서 직접 파일을 생성해서 값을 채워넣는 방식입니다.

 

관리자 대시보드 (thunderbox)

/admin 같은 뻔한 경로는 봇이 제일 먼저 긁는 경로라 /thunderbox로 설정했습니다.

 

관리자 대시보드

기능은 심플하게:

  • 현재 접속자 수
  • 매칭된 방 수
  • 대기 중 유저 수
  • 게임별 플레이 중인 방 수
  • 일간/주간/월간/누적 접속자 통계

IP 화이트리스트로 허용된 IP만 접근 가능하게 했고, nginx 리버스 프록시 뒤에 있어서 IP 감지를 x-real-ip → x-forwarded-for → remoteAddress 순으로 처리했습니다.

배포 업데이트 방법

코드 수정 후 배포하는 방법은 간단합니다.

# 맥에서
git add .
git commit -m "기능 추가"
git push origin main

# 미니PC 서버에서
git pull
docker compose up -d --build

--build 옵션이 중요해요. 코드 변경사항을 반영해서 이미지를 새로 빌드하는 거라 빠뜨리면 안 됩니다.

 

다음 편에서는

오픈 후기를 다룹니다. 커뮤니티 홍보 시도, 반응, 구글 애널리틱스 데이터, 그리고 앞으로 계획을 정리해볼게요.

👉 playtalk.kr 에서 직접 써보실 수 있습니다.

 

 

 

반응형