📑 이 챕터에서 다룰 내용
코드를 수정할 때마다 SSH 접속 → git pull → npm build → pm2 restart를 매번 반복하면 금방 지칩니다.
GitHub Actions를 설정해두면 git push 한 번으로 이 모든 과정이 자동으로 완료됩니다.
1탄 v2 메타 원칙 "R4 자동 회복"의 봇 적용이에요.
- 예상 시간: 1시간
- GitHub repository 초기화 + .env 보호
- SSH deploy 키 설정 (read-only + push 분리)
- GitHub Actions workflow — Node.js·Python 봇
- pm2 reload 무중단 배포
- 5분 롤백 시나리오
먼저 봇 코드를 GitHub에 올립니다. private repository 권장이에요. .env가 절대 push되지 않도록 반드시 확인하세요.
cd ~/tsv-bot git init git add . git commit -m "Initial commit" # GitHub 새 repo 생성 (private 권장) git remote add origin git@github.com:junho/tsv-bot.git git branch -M main git push -u origin main
.env절대 push 금지 —.gitignore에 반드시 포함- 만약 실수로 push했다면 즉시:
- Discord 토큰 reset
- Anthropic API 키 revoke + 재발급
- git history 정리 (BFG 또는 git filter-repo 사용)
GitHub Actions가 서버에 SSH 접속해서 배포하려면 전용 키가 필요해요. deploy 용 키와 GitHub Actions용 키를 분리해서 권한을 최소화합니다.
# 서버에서 deploy 전용 ssh 키 생성 ssh-keygen -t ed25519 -C "github-deploy@tsv-bot" -f ~/.ssh/deploy_key -N "" # 공개키 GitHub에 등록 cat ~/.ssh/deploy_key.pub # → GitHub Repo Settings → Deploy keys → Add deploy key # → Title: "TSV Bot Server", Allow write access X (read-only) # 서버 ~/.ssh/config 설정 cat >> ~/.ssh/config << 'EOF' Host github.com-tsv-bot HostName github.com User git IdentityFile ~/.ssh/deploy_key EOF # 테스트 ssh -T github.com-tsv-bot # Hi junho/tsv-bot! You've successfully authenticated. # clone path 변경 cd ~ mv tsv-bot tsv-bot-old git clone git@github.com-tsv-bot:junho/tsv-bot.git cd tsv-bot # .env 복사 (push X) cp ../tsv-bot-old/.env . chmod 600 .env # logs 복사 (선택) cp -r ../tsv-bot-old/logs . # 빌드 + 재시작 npm install npm run build pm2 restart tsv-discord-bot
Repository Secret 등록
SSH_HOST:144.24.123.45(서버 Public IP)SSH_USER:ubuntuSSH_PRIVATE_KEY: GitHub Actions용 별도 개인키 내용SSH_PORT:22
deploy 키 재생성 (push 권한 분리)
GitHub Actions runner가 서버에 SSH 접속할 때 사용할 별도 키를 만들어요. deploy 키(read-only)와 분리해서 권한을 최소화합니다.
# 로컬 (또는 GitHub Actions runner)용 별도 키 # 서버에서 생성 → 공개키 ~/.ssh/authorized_keys에 추가 → 개인키 GitHub Secret ssh-keygen -t ed25519 -C "github-actions" -f ~/.ssh/gha_key -N "" cat ~/.ssh/gha_key.pub >> ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys # 개인키 보기 → GitHub Secret 등록 cat ~/.ssh/gha_key # 전체 내용을 GitHub Secret SSH_PRIVATE_KEY로 등록
.github/workflows/deploy.yml
# .github/workflows/deploy.yml
name: Deploy to Production
on:
push:
branches: [main]
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Setup SSH
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
- name: Add server to known_hosts
run: |
mkdir -p ~/.ssh
ssh-keyscan -p ${{ secrets.SSH_PORT }} \
${{ secrets.SSH_HOST }} >> ~/.ssh/known_hosts
- name: Deploy to server
run: |
ssh -p ${{ secrets.SSH_PORT }} \
${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} \
'cd ~/tsv-bot && \
git pull origin main && \
npm ci && \
npm run build && \
pm2 reload tsv-discord-bot && \
echo "✅ Deploy completed"'
- name: Notify Discord
if: success()
run: |
curl -H "Content-Type: application/json" \
-d '{"content":"✅ TSV 디스코드 봇 배포 완료 — '"$(date +%Y-%m-%d_%H:%M)"'"}' \
${{ secrets.DISCORD_DEPLOY_WEBHOOK }}
workflow_dispatch를 추가하면 GitHub Actions 탭에서 수동으로 배포를 트리거할 수 있어요. 긴급 배포나 테스트할 때 유용합니다.
Telegram 봇(Python)도 별도 workflow 파일을 만들어요. src/** 또는 requirements.txt가 변경될 때만 배포합니다.
# .github/workflows/deploy-tg.yml
name: Deploy Telegram Bot
on:
push:
branches: [main]
paths:
- 'src/**'
- 'requirements.txt'
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup SSH
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
- name: Add server to known_hosts
run: |
mkdir -p ~/.ssh
ssh-keyscan ${{ secrets.SSH_HOST }} >> ~/.ssh/known_hosts
- name: Deploy
run: |
ssh ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} \
'cd ~/tsv-tg-bot && \
git pull origin main && \
source .venv/bin/activate && \
uv pip install -r requirements.txt && \
sudo systemctl restart tsv-tg-bot && \
echo "✅ Telegram bot deployed"'
# pm2 restart vs pm2 reload # - restart: 봇 종료 후 재시작 (몇 초간 중단) # - reload: 새 프로세스 시작 후 기존 종료 (무중단) # pm2 reload tsv-discord-bot # → cluster mode에서만 진정한 무중단 # → fork mode는 reload ≈ restart # 봇은 connection 유지가 핵심 → reload가 최소 영향
systemd reload (Python)
# systemd reload — 자동 재시작 + Restart=always 효과 sudo systemctl reload-or-restart tsv-tg-bot # 또는 graceful restart 봇 코드 안에서: # - SIGTERM 받으면 현재 요청 끝낸 후 종료 # - python-telegram-bot 자체가 graceful shutdown 지원
pm2를 cluster mode로 실행하면 pm2 reload가 진정한 무중단으로 동작해요. 기존 연결을 처리하는 동안 새 프로세스가 올라오고, 완료 후 기존 프로세스가 종료됩니다.
Discord 봇 특성상 WebSocket 재연결이 발생하지만, 사용자 입장에서는 거의 알아채지 못하는 수준이에요.
배포 후 봇이 작동하지 않으면 5분 안에 이전 상태로 복구할 수 있어야 합니다.
# 배포 후 봇 작동 X 시 빠른 롤백 # 1. 이전 커밋으로 되돌리기 ssh ubuntu@your-ip cd ~/tsv-bot git log --oneline -5 # 이전 커밋 확인 git checkout <prev-commit-hash> # 2. 빌드 + 재시작 npm ci npm run build pm2 reload tsv-discord-bot # 3. 작동 확인 후 origin에 force push (긴급 시만) # 또는 새 정정 commit 푸시 (권장)
git push --force는 팀원이 있거나 이미 배포된 이력이 있을 때 문제를 일으킬 수 있어요.
가능하면 새 정정 commit을 만들어서 정상적으로 push하는 방식을 권장합니다. LogOnTable에 배포 시점과 문제를 트레이스해두세요.
배포는 단순한 명령어 실행이 아니에요. 시리즈 메타 원칙 R4 안전 의식을 배포 흐름에도 적용합니다.
npm run build 오류 없음 확인 → npm test (있으면) → 봇 로컬 작동 검증!ask 안녕) → Sentry 에러 없음 확인 → 매일 리포트 cron 작동 확인- 1️⃣ GitHub repo: private repo + .env 절대 push 금지 + .gitignore 일관
- 2️⃣ SSH 키 분리: deploy 키 (read-only) + GitHub Actions 키 (authorized_keys) 권한 분리
- 3️⃣ Node.js workflow: push → checkout → build → ssh deploy → pm2 reload → Discord 알림
- 4️⃣ Python workflow: src·requirements.txt 변경 시만 배포 → systemctl restart
- 5️⃣ pm2 reload: restart보다 최소 중단 — cluster mode에서 진정한 무중단
- 6️⃣ 롤백: git checkout + rebuild + reload — 5분 안에 복구 가능
- 7️⃣ 메타 일관: R4 자동 회복 → 자동 배포 + 자동 재시작 / E1 다층 보호 → secret + deploy 키 분리
이 별책부록 9편을 마친 여러분께 축하드립니다. 아래가 지금 여러분의 운영 상태입니다.
[인프라]
- Oracle Cloud Singapore Always Free (월 $0)
- Ampere A1: 4 OCPU + 24GB RAM
- Ubuntu 24.04 + 보안 6단계 (ssh·ufw·fail2ban·자동 업데이트·swap·idle 보호)
[봇]
- Node.js 디스코드 봇: pm2 + Position C 5차원
- Python Telegram 봇: systemd + Position C 5차원
- 두 봇 동시 운영 + SSH 종료해도 봇이 계속 살아있는 환경
[모니터링]
- Sentry (에러 자동 추적)
- Anthropic API 사용량 추적 (LogOnTable)
- 매일 운영 리포트 (cron 09:30 KST)
- 사용자 cooldown 5초
[배포]
- GitHub Actions 자동 deploy
- pm2 reload + systemctl restart 무중단
- 5분 롤백 가능
[비용]
- Oracle Cloud: $0/월
- Anthropic API: 사용량만큼 (~$5~30/월 추정)
- Sentry: $0/월 (무료 5K events)
- 도메인 (선택): $10/년
- 합계: ~$5~30/월 (사용량에 따라)
[시리즈 메타 원칙 일관 달성]
- Position C 5차원 (footer + system prompt + 자동 검출 user + 자동 검출 response + /about·/terms·/privacy)
- E4 LogOnTable 4요소 (timestamp·user·question·status)
- E5 환각 방지 + 자동 검출
- E2 Day 0 시스템 (자동 재시작 + 부팅 자동 시작 + SSH 종료 영향 없음)
- R4 자동 회복 → 봇 자동 배포 + 자동 재시작
이 별책부록도 "끝점"이 아니라 "시작점"입니다. 디스코드·Telegram 봇 인프라가 갖춰진 지금부터 TSV·AlbaFlow·viewLab 등 모든 1인 운영 프로젝트에 봇을 적용할 수 있어요. Phase 3 (다국어·6 페르소나·모바일 앱) 진입 시 봇도 함께 진화합니다.
페이지를 넘기시지요. 이제는 운영자가 아닌 봇이 함께 작동하는 환경에서 만나뵙겠습니다.