프론트엔드(Next.js)와 백엔드(Spring Boot)를 분리하고, 백엔드를 외부에 노출하지 않는 구성
rewrites가 /api/* 요청을 백엔드로 프록시[일반 트래픽]
브라우저 → Route53 (example.com)
→ CloudFront
→ alb-front (internet-facing)
→ EC2: Next.js(:3000)
│
│ rewrites /api/* (VPC 내부, HTTP)
▼
alb-internal (internal) 🔒
│
▼
EC2: Nginx(:8080) → Spring Boot(:8081/:8082)
[회사 Swagger 접근]
회사 IP → Route53 (api.example.com)
→ alb-public (internet-facing, 회사 IP만 허용) 🏢
→ EC2: Nginx(:8080) → Spring Boot(:8081/:8082)
EC2가 위치한 AZ를 포함하여 프라이빗 서브넷을 생성한다.
생성한 서브넷:
- private-subnet-01: ap-northeast-2a, 10.0.10.0/24
- private-subnet-02: ap-northeast-2c, 10.0.11.0/24
- private-subnet-03: ap-northeast-2d, 10.0.12.0/24
주의사항:
- MapPublicIpOnLaunch: False (프라이빗)
- EC2 인스턴스가 위치한 AZ를 반드시 포함해야 함
- AZ를 잘못 선택하면 타겟이 "unused" 상태가 됨
설정:
- 이름: alb-internal
- Scheme: internal ← (생성 후 변경 불가)
- VPC: 기존 VPC 선택
- 서브넷: 1단계에서 만든 프라이빗 서브넷 선택 (EC2 AZ 포함 필수)
- 보안 그룹: 새로 생성 (아래 참조)
리스너:
- HTTP:80 → forward → 타겟 그룹
- HTTPS:443 → forward → 타겟 그룹 (선택사항, 내부 통신이면 HTTP만으로 충분)
internal ALB용:
- 이름: tg-internal
- 프로토콜: HTTP, 포트: 8080
- 헬스체크 경로: /api/v1/heartBeat
- 타겟 등록: EC2 인스턴스 (포트 8080)
회사 전용 ALB용 (타겟 그룹은 ALB 간 공유 불가):
- 이름: tg-public
- 프로토콜: HTTP, 포트: 8080
- 헬스체크 경로: /api/v1/heartBeat
- 타겟 등록: 동일 EC2 인스턴스 (포트 8080)
sg-alb-internal)인바운드:
- TCP 80 ← 소스: EC2 보안 그룹 (sg-xxxxxxxxx)
- TCP 443 ← 소스: EC2 보안 그룹 (sg-xxxxxxxxx)
아웃바운드:
- 전체 허용 (0.0.0.0/0)
인바운드 추가:
- TCP 8080 ← 소스: Internal ALB 보안 그룹 (sg-xxxxxxxxx)
인바운드:
- TCP 443 ← 소스: 회사 IP/32 (예: xxx.xxx.xxx.xxx/32)
아웃바운드:
- 전체 허용
example.com (A 레코드, Alias):
→ CloudFront 배포 DNS
*.example.com (A 레코드, Alias):
→ CloudFront 배포 DNS
api.example.com (A 레코드, Alias):
→ alb-public (internet-facing, 회사 전용)
# EC2 배포용 .env
BASE_URL=http://internal-alb-internal-xxxxxxxxxx.ap-northeast-2.elb.amazonaws.com
.env 변경 후 반드시 재빌드 필요:
pnpm build (또는 npm run build)
pm2 restart web
HTTPS(443) 리스너:
- 기본 액션: forward → tg-public
HTTP(80) 리스너:
- 기본 액션: forward → tg-public (또는 HTTPS 리다이렉트)
# EC2에 SSH 접속 후
ssh my-dev-server
# Internal ALB를 통한 API 호출
curl -s -o /dev/null -w '%{http_code}' \
http://internal-alb-internal-xxxxxxxxxx.ap-northeast-2.elb.amazonaws.com/api/v1/heartBeat
# 기대 결과: 200
# AWS CLI로 확인
aws elbv2 describe-target-health \
--target-group-arn <타겟그룹ARN> \
--profile my-profile \
--region ap-northeast-2
# 기대 결과: "State": "healthy"
브라우저에서: https://api.example.com/swagger-ui/index.html
- 회사 IP에서: 접근 가능
- 외부 IP에서: 보안 그룹에서 차단 (타임아웃)
원인: EC2가 위치한 AZ의 서브넷이 ALB에 연결되지 않음
확인: EC2의 AZ와 ALB의 AZ 목록 비교
해결: 해당 AZ에 프라이빗 서브넷 생성 후 ALB에 추가
원인 1: EC2 보안 그룹이 ALB 보안 그룹으로부터의 트래픽을 차단
확인: EC2 SG에 ALB SG → 8080 포트 인바운드 규칙 존재 여부
해결: EC2 SG에 인바운드 규칙 추가 (TCP 8080, 소스: ALB SG)
원인 2: 보안 그룹 포트가 0으로 설정됨
확인: SG 인바운드 규칙의 FromPort/ToPort 확인
해결: 올바른 포트 번호로 수정 (80, 443, 8080 등)
원인: 해당 타겟 그룹이 이미 다른 ALB에서 사용 중
해결: 새 타겟 그룹을 동일한 설정으로 생성하여 사용