
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가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기