
배포 환경
클라우드 대신 집에 있는 미니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"]

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를 직접 써야 해요.

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 에서 직접 써보실 수 있습니다.