한 일

집 서버에서 봇을 처음 만들었다. 게임 파티를 모집·관리하는 카카오톡 봇, 파퀘봇이다. API 서버는 Express + MariaDB로 짰다. 카카오톡과는 “메신저봇R"이라는 안드로이드 앱 스크립트로 이었다. 핵심 명령은 파티 만들기(/생성), 들어가기(/참가), 나가기(/퇴장)다. 여기에 운영하면서 꼭 필요한 규칙들을 붙였다.

  • 명령어 접두사를 !에서 /로 바꿈
  • /참가는 본인만, /퇴출(파티장 강제 내보내기)은 파티장만 — 발화자가 누구인지 검증
  • 파티장이 나가면 다음 사람에게 자리를 자동으로 넘김
  • 출발 시간 입력, 다른 사람에게 파티장 넘기는 /위임
  • 24시간 지난 파티는 자동 삭제
  • 배포할 때 DB 구조 변경(마이그레이션)을 자동으로 적용

집 서버에 두지 않고 GCP(구글 클라우드)로 옮겼다. 혼자 켜둔 집 서버는 불안정하니, 클라우드에서 자동으로 돌게 만들었다.

  • Docker로 서버·DB·웹서버를 한 묶음으로 만듦
  • Terraform으로 클라우드 VM을 코드 한 번에 띄움 (고정 공인 IP 할당)
  • 전용 도메인을 연결하고, HTTPS 보안 인증서를 자동으로 발급받게 함
  • 집 서버 DB의 데이터를 클라우드 DB로 옮김
  • 매일 아침 10시에 클라우드 → 내 PC로 자동 백업 (4.9MB 정상 수신 확인)
  • 마지막으로 집 서버를 끄고, 실제 카톡방에서 명령들이 잘 도는지 확인

메시지를 모으고, 명령어 체계도 정리했다. 파티 관련 명령(/로 시작)이 아닌 일반 대화는 따로 모아 분석하기 시작했다. Redis에 메시지를 쌓고, 한국어 형태소 분석(조사 떼기 + 불용어 거르기)으로 자주 나오는 단어를 셌다. 통계 API로는 활성 파티 수, 누적 메시지 수, 최근 7일 발화자 수를 볼 수 있게 했다. 명령어도 더 자연스럽게 다듬었다. 닉네임을 따로 안 적어도 발화자 기준으로 동작하게 했다. /초대·/쫑(즉시 해산) 같은 명령도 새로 넣었다.

상태를 한눈에 보는 모니터링 화면(Grafana)을 붙였다. 총 수집 메시지, 활성 파티 수, 일별 메시지 추이, 명령어 사용량 같은 걸 그래프로 봤다. 더해서, 봇으로 들어오는 수상한 요청(/.env, /wp-login.php 같이 해킹 시도로 흔한 경로)을 감지하면 디스코드로 보안 알림을 보내게 했다.

막힌 것, 고친 것

두 번 크게 막혔고, 둘 다 원인을 정확히 짚어서 고쳤다.

  • API가 죽고 다시 켜지길 무한 반복. DB 컬럼 이름을 바꾸는 작업이, 이미 사라지고 없는 옛 컬럼(base_name)을 찾다가 실패한 게 원인이었다. 옛 컬럼이 없으면 그 단계만 건너뛰게 고쳐서(skipIfMissingColumn) 바로 살렸다. 일단 클라우드에서 급히 고친 뒤, 정식으로 PR을 올려 반영했다.
  • 모니터링 화면이 404로 안 열림. 웹서버(Caddy)가 옛 설정 파일을 계속 붙들고 있던 게 문제였다 — git으로 파일을 새로 받아도 컨테이너는 옛 파일을 보고 있었다. 컨테이너를 강제로 다시 만들어 복구했고, 다음부터는 설정이 실제로 바뀐 배포에서만 다시 만들도록 막아뒀다.

돌아보며

집 서버에 손으로 켜두던 작은 봇이었다. 그게 하루 만에 클라우드에서 알아서 배포되고, 백업되고, 감시되는 모습으로 바뀌었다. 그 모습을 보니 뿌듯했다. “내 컴퓨터에서만 돌던 것"이 “언제 어디서든 돌아가는 서비스"가 됐다. 이날을 시작점이라고 부르는 게 맞다.

솔직히 욕심을 냈다. 하루에 너무 많은 걸 한 번에 붙였다. 봇을 만들고, 옮기고, 데이터를 모으고, 화면까지 다는 일. 이걸 따로따로 했다면 더 안전했을 것이다. 그 탓에 두 번 크게 넘어졌다. API가 끝없이 죽고 켜지길 반복하는 로그를 볼 땐 마음이 급해졌다. 빨리 살려야 한다는 압박이 컸다. 원인을 모른 채 손대면 더 망가진다는 불안도 같이 왔다.

그래도 급할수록 화면을 닫고 “왜 죽었는지"부터 봤다. 그게 결국 가장 빠른 길이었다. 두 번 다 추측으로 건드리지 않았다. 로그가 가리키는 진짜 원인을 먼저 잡았다 — 사라진 옛 컬럼, 옛 설정을 붙든 컨테이너. 이걸 머리가 아니라 몸으로 배운 날이다. 다음엔 큰일을 하루에 몰지 않겠다고 다짐했다. 한 단계씩 끊어서 가야겠다.