본문으로 건너뛰기

© 2026 Molayo

Qiita헤드라인2026. 06. 03. 16:58

Claude Code에 "변경하면 자동으로 배포해줘"라고 부탁했더니, Stop 후크로 자동 배포 환경을 구축한 이야기

요약

Claude Code의 Stop hook과 Memory 기능을 활용하여 코드 변경 시 자동으로 운영 환경에 배포되는 자동화 환경을 구축한 사례를 다룹니다. 배포 과정에서 발생한 보안 위험(민감 정보 노출)과 경로 설정 오류를 해결하며 얻은 실무적인 교훈을 공유합니다.

핵심 포인트

  • Stop hook을 이용한 자동 배포 메커니즘 구현
  • 배포 전 DryRun을 통한 민감 정보 노출 방지 필수
  • Claude Memory를 활용한 영구적인 동작 규칙 설정
  • 스크립트 주석보다 실제 서버 환경(ls 명령) 확인의 중요성

사내 툴(브라우저에서 동작하는 자료 생성 앱)을 Claude Code로 개수하고 있었을 때,

"매번 수동으로 배포하는 게 귀찮다. 변경하면 알아서 운영 환경으로 올려줬으면 좋겠다"라고 통째로 맡겼던 기록입니다.

최종적으로 **"Claude Code가 응답을 마칠 때마다, 변경 사항이 있으면 자동으로 운영 배포를 수행한다"**는 환경이

Stop 후크(Stop hook)를 통해 완성되었습니다. 도중에 배포 대상을 크게 잘못 지정하거나, PowerShell의 글자 깨짐 문제로 고생하기도 했기에, 그 과정을 거의 그대로 남깁니다.

환경: Windows 11 / PowerShell 5.1 / Claude Code (Opus 4.7) / ConoHa(Plesk) + SSH 배포

"이 변경 사항을 운영 환경에 올려줘"라고 부탁하자, Claude는 프로젝트 내의 deploy.ps1

(scp로 업로드하는 스크립트)를 찾아냈다.

곧바로 실행하지 않고, 먼저 **DryRun(업로드 대상 확인만 수행)**을 실행한 것이 좋았다.

업로드 대상 목록에 다음과 같은 파일들이 섞여 있었다.

이하나_서버정보.md ← 서버 인증 정보!
.playwright-mcp\...yml ← 검증 중 발생한 임시 파일
WebTan제안슬라이드스킬_팀배포판\...

이하나_서버정보.md공개 디렉토리에 업로드된다는 것은 = https://~/이하나_서버정보.md

누구나 열람할 수 있는 상태라는 뜻이었다. 배포 제외 목록이 허술했던 것이다.

배움: 배포는 반드시 DryRun부터. "무엇이 올라가는가"를 목록으로 확인한 뒤에 운영 환경을 실행할 것.

실행하려고 하니 mkdir: Permission denied로 실패.

조사해 보니, deploy.ps1의 업로드 대상 경로가 실제 서버 구성과 전혀 맞지 않았다.

스크립트의 가정실제
서버 종류ConoHa WING
Web 루트public_html/ 직하
대상 디렉토리public_html/shiryou-maker

find로 서버를 찾아도 shiryou-maker를 찾을 수 없었다. "과거에 배포했던 URL"을 물어보고 나서야 판명된 사실은 다음과 같다.

  • 실제 경로는 public_html/<서브도메인명>/shiryo-maker이다.
  • 게다가 디렉토리 이름이 shiryo-maker로 철자가 틀려 있었다 (u가 없음).

shiryou로 찾고 있었기 때문에 계속 "미배포" 상태라고 오판하고 있었던 것이다.

함정: 스크립트의 주석("ConoHa WING")을 맹신하지 말 것. ssh로 실제 ls를 실행하여 구성을 확인할 것. 철자 한 글자 차이는 검색에 걸리지 않는다.

올바른 경로와 제외 목록으로 deploy.ps1을 수정하고, DryRun을 통해 업로드 대상이 필요한 6개 파일뿐임을 확인한 뒤 배포했다.

여기서 한마디.

"기본적으로 이 프로젝트 폴더 내의 모든 것은 배포를 전제로 동작했으면 좋겠다"

이것은 **"변경이 끝나면 일일이 묻지 말고 바로 배포해도 좋다"**라는 영구적인 규칙에 대한 요청이다.

Claude는 이를 메모리(Memory, 영구 설정)에 저장하여, 이후에는 확인 없이 배포하게 되었다.

이 부분이 가장 큰 고비였다. 나는 다음과 같이 질문했다.

"메모리에 저장한다는 것은, 창을 다시 열면 또 바뀌기도 하나요?"

돌아온 설명이 이해하기 쉬웠기에 요약한다.

메모리 (preference)후크 (hook)
사라지는가사라지지 않음 (파일 영구 저장)
성질Claude가 읽고 "따르는" 지침
확실성기본적으로 따르지만 100%는 아님

즉, "무슨 일이 있어도 확실하게, 변경하면 자동 배포"를 보장하고 싶다면 메모리가 아니라 **hook (settings.json의 자동 실행 설정)**으로 만들어야 한다는 것이다.

나는 "그럼 (후크로)"라고 즉시 결정했다.

후보는 두 가지다.

  • PostToolUse (Write/Edit 마다): 1번의 편집마다 배포 → 연속 편집 시 여러 번 실행되어 느림
  • Stop (응답을 마쳤을 때): 1턴에 1번만 → 모든 편집이 끝난 후 1번 배포 ◎

후자를 선택. 단, Stop은 **아무것도 변경하지 않은 답변에서도 발화(Trigger)**하므로,

그대로 매번 scp를 하면 불필요한 재업로드가 발생한다.

그래서 배포 대상 6개 파일의 업데이트 시각을 "이전 배포 시각(마커)"와 비교하여,

변경이 있을 때만 deploy.ps1

을 호출하는 래퍼(Wrapper)를 만들었다.

# deploy-hook.ps1 (요점)
$Marker = Join-Path $Root ".deploy-marker"
$Watch = @("config.js","convert.php","favicon.png","index.html",
...

처음에 스크립트의 systemMessage를 일본어로 작성했더니 다음과 같은 결과가 나왔다.

Unexpected token '繝輔ぃ繧、繝ォ螟画峩讀懃衍・・' in expression or statement.

원인은 에디터가 BOM 없는 UTF-8로 저장했고, Windows PowerShell 5.1이 이를 시스템의 ANSI (Shift-JIS)로 읽었기 때문이다. 일본어 주석/문자열이 모두 깨졌다.

대처: 후크에서 호출하는 .ps1은 ASCII로만 작성한다 (메시지도 영어로).

이렇게 하면 문자 인코딩 사고를 근본적으로 회피할 수 있다.

{
"hooks": {
"Stop": [
...

등록 전에 파이프 테스트 (후크로 전달되는 JSON을 수동으로 흘려넣기)로 동작을 확인했다.

shell
echo '{}' | powershell.exe -NoProfile -ExecutionPolicy Bypass -File "...\deploy-hook.ps1"
# 1회차: 6개 파일 배포 및 JSON 출력 / 2회차: 변경 사항 없음으로 무음 → OK

설정했는데도 다음 변경 사항이 자동 배포되지 않았다. 운영 환경을 확인하니 예전 상태 그대로였다.

원인은 Claude Code의 설정 워처(Watcher)가 후크 추가 직후에는 재로드하지 않기 때문이다.

해결 방법은 간단하다.

  • /hooks를 한 번 열거나 (설정이 재로드됨)
  • Claude Code를 재시작한다

/hooks를 열면 상단에 "2 hooks configured"라고 뜨며, 이때 처음으로 후크가 유효해졌다.

(이 메뉴 자체는 읽기 전용이다. Esc로 닫기만 하면 된다.)

로컬에서 index.html 등을 편집
│ Claude Code가 응답을 마침 (Stop 이벤트)
▼
...
  • 변경이 없는 답변에서는 스킵 (불필요한 재업로드 없음)

  • 기밀 파일, 임시 파일, 배포물은 배포에서 제외

  • "배포를 전제로 동작함"이라는 방침은 메모리(Memory)에도 기록 → 다른 세션에서도 인계됨

  • 배포는 DryRun부터. 공개 디렉토리에 기밀 파일이 섞이는 사고를 미연에 방지할 수 있다.

  • 스크립트의 주석을 너무 믿지 말 것. 실제 서버를 ssh ls로 확인하라. 철자 한 글자 차이는 검색에 나오지 않는다.

  • "확실한 자동 실행"은 메모리가 아니라 후크다. 메모리는 "따라야 할 지침"이고, 후크는 "실행되는 메커니즘"이다.

  • 후크에서 호출하는 PowerShell은 ASCII로만 작성할 것. PS 5.1의 BOM 없는 UTF-8 깨짐 현상을 회피한다.

  • Stop 후크는 추가 직후에는 무효하다. /hooks를 열거나 재시작하여 활성화한다.

"귀찮으니까 자동화해줘"라고 통째로 맡겼을 뿐인데, 이 정도까지 설계와 검증을 포함해서 해주는 것은 큰 도움이 된다.

특히 DryRun 과정에서 기밀 파일을 감지하고 멈춰준 것이 가장 고마웠다.

AI 자동 생성 콘텐츠

본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0