코드 리뷰 봇
왜 만들었나
동기는 세 가지가 겹쳤다.
첫째로 LLM을 직접 붙여서 뭔가 만들어보고 싶었다. 비교도 해보고. 둘째로 예전에 GitHub API로 포트폴리오 서비스 만들다가 중단한 게 계속 마음에 걸렸다. 이번에 MVP라도 완성해보자 싶었다. 셋째로 Vercel + NCP + SSL/ALB 조합으로 배포 환경을 직접 설계해보는 게 목표였다.
Ollama 먼저 고려했다가 Gemini로 바꾼 이유


언젠가 꼭 써보고 싶었던 게 Ollama였다. 저비용 VM에서 경량 LLM을 직접 호스팅하면 재밌겠다 싶었다.
| 항목 | Ollama (Self-Hosted) | Gemini 2.5 Flash API |
|---|---|---|
| Resource 의존도 | 매우 높음 (GPU 필수) | 낮음 (API 서버에서 처리) |
| 운영 비용 | VM(GPU) 시간당 과금 (매우 비쌈) | 토큰 사용량 기반 과금 (저렴하고 명확함) |
| 속도 | 느림 (VM 성능에 의존) | 빠름 (API 응답 속도 우수) |
막상 테스트해보니 GPU 없이는 속도가 너무 느렸다. GPU 옵션을 붙이면 시간당 몇 천 원씩 나온다. 저코스트 VM을 쓰겠다는 전제 자체가 흔들렸다.
결국 Gemini 2.5 Flash API로 바꿨다. 빠르고 GPU 의존도 없고 토큰 기반 과금이라 비용 예측도 된다.
NCP를 고른 이유
지금까지 배포는 AWS에서만 해봤다. AWS 프리티어가 만료되면서 비용 부담이 생겼고. 마침 NCP 신규 가입 크레딧 10만 원이 있었다. 어차피 새 클라우드 경험이 필요했고 타이밍이 맞았다.
기술 스택
| 구분 | 기술 스택 | 설명 |
|---|---|---|
| Frontend | React, Vite | 빠른 UI 및 GitHub OAuth 2.0 흐름 제어 |
| Backend | JDK 21, Spring Boot 4.0, Spring Security | GitHub OAuth 처리, Gemini API 호출 및 비즈니스 로직 |
| AI Service | Google Gemini 2.5 Flash API | 코드 리뷰, 채팅 및 분석 리포트 생성 |
| Hosting 비용 | VM 시간당 약 330원, ALB 월 약 2.5만원, Domain 550원 | 비용을 최소화하며 인프라를 구축 |
아키텍처
백엔드가 NCP인데 프론트는 왜 Vercel에?
GitHub 푸시하면 알아서 빌드되고 배포된다. 글로벌 CDN이라 로딩도 빠르다. SSL도 자동 발급. 프론트를 NCP에 올려서 이걸 직접 챙길 이유가 없었다.
NCP 인프라 구성 과정
VPC, Subnet, ACG 잡기
서버 띄우기 전에 네트워크 기초부터 잡았다. VPC와 Subnet 생성은 과금이 안 되니 부담 없다.
git-code-reviewer-vpc이름으로 VPC 생성- 외부 통신이 필요하니 Public Subnet으로
public-subnet-1생성 code-reviewer-acg를 만들어 SSH(22)와 Spring Boot 포트(8080) 인바운드 허용
VM 스펙과 공인 IP
| 항목 | 상세 정보 | 비고 |
|---|---|---|
| 서버 스펙 | s2-g3a (vCPU 2EA, Memory 8GB) | Spring Boot 구동에 안정적인 사양 (시간당 330원) |
| OS | Ubuntu 22.04 base | 익숙한 리눅스 환경 선택 |
| 내부 IP | 10.0.1.6 | Subnet에 의해 자동 할당되는 사설 주소 |
| 공인 IP | 175.xx.xx.xx | VM 생성 시 할당하여 ALB 설정 전까지 직접 접속 및 테스트용으로 사용했다. |
JAR 올리고 실행하기
민감 정보는 .env.properties로 분리해서 전송했다.
# 로컬에서 빌드
./gradlew clean build -x test
# scp로 서버에 전송
scp git-code-reviewer-0.0.1-SNAPSHOT.jar root@[서버 공인 IP]:/root/
# NCP 서버에서 실행
nohup java -jar git-code-reviewer-0.0.1-SNAPSHOT.jar --spring.config.location=file:./.env.properties > nohup.out 2>&1 &
Mixed Content 문제와 ALB 도입
Vercel(HTTPS)에서 NCP(HTTP 8080)를 호출하자마자 Mixed Content Error가 났다. 예상했던 문제였다.
해결 순서는 이랬다.
- 가비아에서
code-reviewer.store도메인 구매. 550원짜리라 이쁘진 않지만 충분했다. - NCP Certificate Manager에서 SSL 인증서 발급 요청. 가비아 DNS에 CNAME 레코드 입력해서 소유권 검증.
- ALB 생성. 리스너는 HTTPS 443으로 받고 타겟 그룹은 내부 IP(
10.0.1.6)의 HTTP 8080으로 연결. - ALB에 할당된 공인 IP를 확인하고 가비아 DNS에서
api.code-reviewer.store의 A 레코드를 그 IP로 변경.
프론트엔드 마무리
Dashboard.js에서 API 주소를 교체하고 GitHub OAuth Callback URL도 맞춰 수정했다.
// 변경 전: 'http://175.45.204.50:8080/api'
// 변경 후: 'https://api.code-reviewer.store/api'
const api = axios.create({ baseURL: 'https://api.code-reviewer.store/api', ... });
코드 푸시하면 Vercel이 알아서 재배포한다. 이걸로 HTTPS 통신 환경이 완성됐다.
VPC & Subnet → VM 생성 & 공인 IP 할당 → ACG/UFW 방화벽 설정 → Certificate Manager에서 SSL 발급 → ALB 생성 & Listener(443) → Target Group(8080) 연결 → DNS A 레코드 업데이트
트러블슈팅
해결한 것들
| 문제 상황 | 해결책 | 교훈 |
|---|---|---|
| Mixed Content Error | 도메인 구매 후 NCP ALB에 SSL 인증서를 설정하고, API 호출 주소를 https://[도메인]으로 변경. | 돈이 들더라도 SSL Termination은 로드 밸런서에게 맡기는 것이 가장 안정적인 실무 공식이다. |
| GitHub Callback URL 오류 | GitHub OAuth App 설정을 최종 주소인 https://api.code-reviewer.store/callback 형태로 업데이트하여 보안 표준을 준수했다. | OAuth 표준에서는 인증 과정에 IP 주소나 HTTP를 사용하지 않는다. |
| Vercel "Not Found" | 프로젝트 루트에 vercel.json 파일을 생성하여 /auth/callback 같은 클라이언트 라우팅 경로를 index.html로 리다이렉트하는 설정을 추가. | React Router 같은 SPA를 정적 호스팅 플랫폼에 배포할 때는 라우팅 폴백 설정이 필수다. |
아직 남은 것
| 문제점 | 현재 상태 | 해야 할 것 |
|---|---|---|
| HTTP/8080 포트 공개 | NCP ACG에서 TCP 8080 포트를 0.0.0.0/0으로 전체 인바운드 허용 중. | ACG 규칙을 수정해서 8080은 ALB의 Private IP 대역에서만 허용하도록 제한해야 한다. 지금은 서버에 직접 접근이 가능한 상태다. |
돌아보며
Spring Boot 코드를 짜는 시간보다 NCP 콘솔에서 ACG 설정하고 DNS 레코드 맞추는 데 시간이 훨씬 많이 걸렸다. 어차피 Open API 연동이 대부분이기도 했고.
배운 게 두 가지다.
하나는 SSL Termination. Vercel에서 HTTP 백엔드를 못 쓴다는 문제 하나가 ALB 도입이라는 월 2.5만 원짜리 결정으로 이어졌다. 보안과 안정성은 결국 돈이다.
다른 하나는 NCP 자체. AWS는 콘솔이 익숙해서 VPC나 Subnet을 크게 의식 안 하고 썼는데. NCP에서 처음부터 설계하고 연결하다 보니 클라우드 네트워크 구조가 실제로 어떻게 돌아가는지 좀 더 보였다.
현재 AI 리뷰 결과는 휘발된다. DB를 붙이면 좀 쓸만한 서비스가 될 것 같다.