“진짜 유저가 접근 가능한 배포, 나도 해봤다”
개발자 포트폴리오에서 코드 구현만큼 중요한 건, 서비스를 실제 운영 환경에 띄울 수 있는 배포 경험이다.
그래서 이번에는 “로컬에서만 되는 게 아니라, 진짜 유저가 접근 가능한 서비스”를 만드는 걸 목표로 EC2에 프론트와 백엔드를 배포했다.
보안 설정, 포트 바인딩, CORS 이슈 대응 등도 직접 다루며 실제 운영에서 고려해야 할 요소들을 경험할 수 있었다.
✨ 프로젝트 개요: Share & Reward 시스템
이번 프로젝트는 상품 링크를 공유하고, 친구가 클릭하면 포인트를 받는 리워드 시스템을 구현한 것이다.
실제 서비스를 운영하는 것처럼 EC2 서버에 배포하고, 브라우저에서 접근 가능한 형태로 구성해봤다.
| 프로젝트명 | Share & Reward |
| 기술 스택 | React (Vite), Spring Boot, Kafka |
| 배포 대상 | 프론트 (80 포트), 백엔드 API (8081 포트) |
| 구현 기능 | 공유 링크 생성, 클릭 추적, 리워드 지급 이벤트 처리 |
🧩 기술 스택 선택 이유
▶ 왜 AWS EC2를 썼을까?
항목이유
| ✅ 저렴한 비용 | 프리 티어 (t2.micro)로 테스트용 서버 운영 가능 |
| ✅ 퍼블릭 IP 제공 | 도메인 없이도 외부에서 접근 가능 |
| ✅ 직접 제어 가능 | 인바운드 포트, 디렉토리 구조, Docker 등 자유도 높음 |
➡️ 초보 개발자도 실제 클라우드 환경에서 배포 경험을 쌓기에 아주 적합하다.
▶ 왜 Docker로 배포했을까?
항목이유
| ✅ 환경 일관성 | 로컬에서 만든 이미지를 그대로 서버에서 실행 |
| ✅ 프로세스 격리 | 프론트/백엔드 컨테이너 분리 가능 |
| ✅ 간편한 재배포 | docker pull + docker run으로 배포 끝 |
➡️ CI/CD가 없어도 운영 가능한 실전형 수동 배포를 경험할 수 있다.
✈️ EC2 인스턴스 준비하기
1. EC2 생성
- Ubuntu 20.04 이상 선택
- 인스턴스 유형: t2.micro (프리티어)
- 보안 그룹 설정:
- 22 (SSH): 본인 IP만 허용
- 80 (HTTP): 전체 허용
- 8081 (API 테스트용): 전체 허용 또는 특정 IP
2. EC2 접속 (Windows 기준)
ssh -i "C:/Users/yourname/your-key.pem" ubuntu@<퍼블릭-IP>
🐳 Docker로 서비스 이미지 빌드 & 푸시
1. Docker 설치 (EC2 내부)
sudo apt update
sudo apt install docker.io -y
sudo usermod -aG docker ubuntu
설치 후 exit → 다시 접속해야 docker 권한 적용됨
2. Docker Hub 로그인
docker login
⚖️ 이미지 빌드 & 푸시
백엔드 빌드 & 푸시
# 루트에 Dockerfile 있어야 함
cd 개발 폴더명
./gradlew build -x test
docker build -t <계정명>/share-back:latest .
docker push <계정명>/share-back:latest
3. 프론트 빌드 & 푸시
cd 폴더명
npm run build
docker build -t <계정명>/share-front:latest .
docker push <계정명>/share-front:latest
☁️ EC2에서 Docker 이미지 실행
백엔드 (8081)
docker pull <계정명>/share-back:latest
docker run -d --name share-back -p 8081:8081 <계정명>/share-back:latest
프론트 실행 (nginx 내장)
docker pull <계정명>/share-front:latest
docker run -d --name share-front -p 80:80 <계정명>/share-front:latest
🧩 문제 해결: CORS 403 오류
🔥 문제
- 프론트에서 EC2의 백엔드 API 호출 시 403 Forbidden 발생
🧠 원인
- Spring Boot에서 별도의 CORS 설정이 없으면 브라우저 요청 차단
✅ 해결 코드
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("*");
}
}
배포용 환경에서는 allowedOrigins("*") 대신 도메인 또는 IP 제한 필요
🧪 테스트 및 결과 확인
- 백엔드 API 확인
http://<EC2-IP>:8081/api/rewards/summary?userId=u-123 - 프론트 웹 확인
http://<EC2-IP>
🎯 배운 점
- 배포는 "서버에 띄우는 것" 이상으로, 네트워크, 보안, 설정, 디버깅 등 실무 감각이 필요한 작업이다.
- 직접 퍼블릭 클라우드에 Docker 컨테이너를 띄우며, 운영 환경과 개발 환경의 차이를 몸으로 체감할 수 있었다.
- “왜 이 기술을 선택했는가?” “무엇이 문제였고 어떻게 해결했는가?” 를 고민하는 과정에서 개발자로서 한층 성장했다.
📌 아키텍처 구성도
[🧍 사용자]
│
▼
[🌐 브라우저]
│
▼
[🧊 EC2: 프론트 (80포트, Vite + Nginx)]
│
▼
[🔥 EC2: 백엔드 API (8081포트, Spring Boot)]
│
▼
[🧵 Kafka: 공유/보상 이벤트 전송 및 처리]