git push 하나로 서버가 알아서 빌드하고 배포하게 만들었다
Webhook으로 자동 배포 파이프라인 구축
#인프라 #CICD #GitHub #Webhook
포트폴리오 사이트 만들고 제일 귀찮았던 건 배포였다. 코드 좀 고치고 → 서버 접속 → git pull → npm install → 빌드 → dist 복사. 이걸 매번 손으로 하다 보니 사소한 수정 하나 올리는 것도 일이 됐다. 그래서 GitHub에 push만 하면 서버가 알아서 다 하도록 자동 배포를 붙였다. 이 글에선 Webhook으로 이 파이프라인을 어떻게 짰는지 정리해본다. 전체 흐름 동작은 이렇게 흘러간다. 1. 로컬에서 GitHub로 push 2. GitHub가 서버의 /webhook/deploy로 요청을 쏨 3. 서버가 git pull → npm install → build → dist 복사를 자동 실행 4. 성공이든 실패든 이메일로 알림 즉 내가 하는 건 git push 하나뿐이고, 나머지는 서버가 알아서 한다. Webhook 받는 엔드포인트 GitHub는 push가 일어나면 설정해둔 URL로 POST를 보낸다. 서버엔 그걸 받을 엔드포인트만 하나 열어두면 된다. app.post('/webhook/deploy', (req, res) = { const signature = req.headers['x-hub-signature-256']; // webhook secret 검증 if (process.env.WEBHOOK_SECRET) { const hmac = crypto.createHmac('sha256', process.env.WEBHOOK_SECRET); const digest = 'sha256=' + hmac.update(JSON.stringify(req.body)).digest('hex'); if (signature !== digest) { return res.status(401).json({ error: 'Invalid signature' }); } } res.json({ message: '배포 시작' }); deploy(); // 실제 배포는 비동기로 }); 여기서 신경 쓴 건 서명 검증 이다. 이 엔드포인트는 인터넷에 그냥 열려 있으니까, 아무나 호출하면 마음대로 배포를 트리거할 수 있다. 그래서 GitHub가 보내는 x-hub-signature-256 헤더를 WEBHOOK_SECRET으로 직접 계산한 값이랑 비교해서, 진짜 GitHub가 보낸 요청인지 확인한다. 그리고 응답은 검증 끝나면 바로 보내고, 실제 배포는 뒤에서 따로 돌린다. 빌드는 수십 초씩 걸리는데 그동안 GitHub를 기다리게 하면 타임아웃이 나기 때문이다. 실제 배포 로직 배포 함수는 그냥 내가 손으로 치던 명령어를 순서대로 실행하는 거다. execSync로 하나씩 돌린다. async function deploy() { process.chdir(PORTFOLIO_DIR); // 1. 최신 코드 받기 execSync('git pull'); // 2. 의존성 설치 execSync('npm install'); // 3. 빌드 execSync('npm run build'); // 4. 빌드 결과물을 서빙 디렉토리로 복사 execSync(`cp -r dist/. ${DIST_DIR}/`); await sendMail('배포 성공', output); } 막혔던 건 private 저장소 인증 처음에 git pull에서 막혔다. private 저장소라 서버에서 그냥 pull하면 인증을 요구한다. 그래서 GitHub Personal Access Token 을 발급받아서, remote URL에 토큰을 끼워 넣는 방식으로 풀었다. const githubToken = process.env.GITHUB_TOKEN; if (githubToken) { const urlWithToken = remoteUrl.replace( /https:\/\/(.*@)?github\.com\//, `https://${githubToken}@github.com/` ); execSync(`git remote set-url origin "${urlWithToken}"`); } 토큰은 .env에만 넣고 코드엔 안 박았다. 이런 토큰이 코드에 같이 커밋되면 그 자체가 보안 사고라서, 인증 정보는 무조건 환경변수로 빼는 게 맞다. 이메일 알림이 생각보다 중요했다 자동 배포의 함정은 내가 배포 과정을 안 보게 된다는 거다. 빌드가 실패해도 모르고 넘어갈 수 있다. 그래서 배포 끝나면 성공이든 실패든 로그를 통째로 이메일로 보내게 했다. 이게 있으니까 "push 했는데 사이트가 왜 안 바뀌지?" 싶을 때 메일함만 열어보면 어디서 깨졌는지 바로 보인다. 자동화는 결국 "사람이 안 봐도 되게" 만드는 건데, 그러려면 문제 생겼을 때 알려주는 장치가 꼭 같이 있어야 한다. 만들고 나서 이거 붙이고 나서 배포가 그냥 git push가 됐다. 심리적으로도 코드 고치는 게 훨씬 가벼워졌다. 예전엔 "이거 고치면 또 배포해야 하는데…" 하고 미루던 사소한 수정들을, 이제는 그냥 push하고 끝낸다. 거창한 CI/CD 도구를 쓴 것도 아니다. Webhook 엔드포인트 하나랑 명령어 몇 개를 순서대로 돌리는 스크립트가 전부다. 근데 이 작은 자동화가 개발 흐름 전체를 바꿔놨다.