AWS에서 WEB-WAS 연동하기

목차

AWS WEB-WAS 연동은 온프레미스에서 다루던 NginX(WEB)와 Tomcat(WAS) 구조를 EC2·ALB·NLB·VPC 위에 3-Tier로 옮기는 작업이다. 이 글은 퍼블릭 구간(ALB→WEB)과 프라이빗 구간(NLB→WAS)을 VPC 서브넷으로 분리하고, 보안 그룹을 계층별로 체인 구성한 뒤, 배스천 호스트를 거쳐 프라이빗 인스턴스에 접속해 NginX 리버스 프록시까지 연결하는 전 과정을 아키텍처 개요 → EC2·보안 그룹 → 웹·WAS 설치 → 리버스 프록시 연동 → 동작 확인 순서로 정리한다.

아키텍처 개요

구성하려는 AWS WEB-WAS 연동 구조는 다음과 같다. 외부 요청은 ALB(Application Load Balancer)가 받아 퍼블릭 경로의 WEB(NginX) 인스턴스로 전달한다. WEB은 다시 NLB(Network Load Balancer)를 거쳐 프라이빗 서브넷에 있는 WAS(Tomcat)로 요청을 넘긴다. 이렇게 하면 WAS는 외부에 직접 노출되지 않고, 트래픽 흐름은 한 방향으로만 흐른다.

  • 요청 흐름 : 사용자 → ALB → WEB(NginX) → NLB → WAS(Tomcat)
  • 퍼블릭 구간 : ALB, WEB 인스턴스
  • 프라이빗 구간 : NLB, WAS 인스턴스 (공인 IP 없음)
  • 관리 접속 : 배스천(점프 서버) → WEB·WAS

사용한 리소스와 미들웨어 버전은 다음과 같다.

  • WEB : NginX 1.25
  • WAS : Tomcat 10.1.17
  • VM 인스턴스 : EC2 (RHEL8, t2.micro)
  • 로드 밸런서 : ALB, NLB
  • 네트워크 : VPC (디폴트 VPC, 리전 ap-northeast-2 서울)

NginX와 Tomcat을 직접 연동하는 기본기는 NginX-Tomcat 연동 & 멀티 인스턴스 로드밸런싱 글에서 먼저 확인하면 이번 AWS 구성을 이해하기 쉽다.

VPC 서브넷 설계

기존 디폴트 VPC를 그대로 쓰되, 역할별로 서브넷을 나눠 IP 범위를 분리했다. WEB·WAS 서브넷은 공인 IP를 부여하지 않고, 외부에서 관리 접속을 받는 배스천 서브넷에만 탄력적 IP(Elastic IP)를 붙인다.

서브넷IPv4 CIDR공인 IP용도
my-web-sub-01172.31.0.16/28XWEB 인스턴스
my-web-sub-02172.31.0.32/28XWEB 가용영역 분산
my-was-sub-01172.31.0.48/28XWAS 인스턴스
my-was-sub-02172.31.0.64/28XWAS 가용영역 분산
my-bastion172.31.0.0/28탄력적 IP배스천(점프 서버)

ALB와 NLB는 가용영역(AZ)을 2개 이상 묶어야 정상 동작하므로 WEB·WAS 서브넷을 각각 두 개씩 다른 AZ에 배치했다. 같은 AZ에만 서브넷이 있으면 로드 밸런서 생성 단계에서 매핑할 대상이 부족해진다.

보안 그룹 체인 구성

AWS WEB-WAS 연동의 보안 핵심은 각 계층이 바로 앞 단계에서 오는 트래픽만 허용하도록 보안 그룹을 체인처럼 묶는 것이다. 인바운드 소스를 IP 대역이 아니라 앞단 보안 그룹 자체로 지정하면, 인스턴스 IP가 바뀌어도 규칙을 고칠 필요가 없고 외부에서 WAS로 바로 들어오는 경로가 원천 차단된다.

보안 그룹인바운드 허용소스설명
my-alb-sg-01TCP 800.0.0.0/0 (anywhere)ALB — 외부 HTTP 수신
web-sg-01TCP 80my-alb-sg-01WEB — ALB에서 오는 80만
my-nlb-sg-01TCP 8080web-sg-01NLB — WEB에서 오는 8080만
was-sg-01TCP 8080my-nlb-sg-01WAS — NLB에서 오는 8080만
Bastion-sgTCP 22 (SSH)관리자 IP (가능하면 anywhere 지양)배스천 — 관리 접속용

WEB·WAS 인스턴스의 보안 그룹에는 배스천을 통한 관리 접속을 위해 TCP 22 from Bastion-sg 규칙도 추가한다. 즉 WEB·WAS는 SSH를 배스천 보안 그룹에서만 받는다.

EC2 인스턴스 생성

WEB, WAS, 배스천 세 종류의 인스턴스를 생성한다. EC2 생성 마법사에서 설정하는 핵심 항목은 다음과 같다.

항목설정 값
AMIRed Hat Enterprise Linux 8 (RHEL8)
인스턴스 유형t2.micro (프리 티어)
키 페어forPJ (.pem 다운로드 — 분실 시 재발급 불가)
네트워크/서브닛WEB→web-sub, WAS→was-sub, 배스천→bastion
퍼블릭 IP 자동 할당배스천만 활성화, WEB·WAS는 비활성화
보안 그룹위 표의 web-sg-01 / was-sg-01 / Bastion-sg

키 페어를 생성하면 본인 로컬 컴퓨터에 개인키인 .pem 파일이 한 번만 다운로드된다. 여기서는 키 페어 이름을 forPJ로 했다. 이 파일은 분실하면 같은 키로 재발급되지 않으니 안전한 디렉터리에 보관한다.

웹 서버(NginX)와 WAS(Tomcat) 설치

my-web-01에는 NginX 1.25를, my-was-01에는 Tomcat 10.1.17을 설치한다. RHEL8 기준 설치·기동 명령은 다음과 같다. 미들웨어 설치 세부 과정은 아래 두 링크를 참고했다.

WAS 인스턴스 — Tomcat 기동 확인

WAS 인스턴스에서 Tomcat을 실행하고, 8080 포트가 리슨 상태인지 확인한다.

# Tomcat 기동
$CATALINA_HOME/bin/startup.sh

# 8080 리슨 확인
ss -lntp | grep 8080

# 로컬에서 응답 확인
curl -I http://localhost:8080

WEB 인스턴스 — NginX 기동 확인

WEB 인스턴스에서 NginX를 실행하고 80 포트 응답을 확인한다.

# NginX 기동
/usr/local/nginx/sbin/nginx

# 설정 문법 검사 + 리로드(이후 수정 시)
/usr/local/nginx/sbin/nginx -t
/usr/local/nginx/sbin/nginx -s reload

# 80 리슨 확인
ss -lntp | grep :80

로드 밸런서(ALB · NLB)와 대상 그룹

퍼블릭 진입점인 ALB와, WEB→WAS 내부 전달용 NLB를 각각 생성하고 대상 그룹에 인스턴스를 등록한다.

로드 밸런서리스너대상 그룹대상헬스체크
my-alb-01 (ALB)HTTP 80my-web-group-01WEB 인스턴스:80HTTP / 200
my-nlb-01 (NLB)TCP 8080my-was-tg-01WAS 인스턴스:8080TCP 8080

대상 그룹을 만들면 등록한 인스턴스에 주기적으로 헬스체크가 돈다. ALB는 HTTP 응답 코드(기본 200)로, NLB는 해당 포트의 TCP 연결 성립 여부로 정상을 판단한다. 따라서 헬스체크가 통과하려면 그 시점에 WEB은 NginX(80)가, WAS는 Tomcat(8080)이 실제로 떠 있어야 한다.

WEB·WAS 대상 그룹이 모두 healthy로 뜨면 로드 밸런서 ↔ 인스턴스 연결은 정상이다. 반대로 unhealthy라면 ① 인스턴스에서 서비스가 떠 있는지 ② 보안 그룹이 헬스체크 포트를 허용하는지를 먼저 점검한다.

참고로 대상을 등록 해제하면 NLB는 기본 300초의 등록 해제 지연(deregistration delay) 동안 진행 중인 연결을 마무리한 뒤 대상을 제외한다. 인스턴스를 교체할 때 이 시간을 감안한다.

배스천 호스트로 WEB · WAS 접속

프라이빗 서브넷의 WEB·WAS 인스턴스에는 공인 IP가 없으므로, 외부에서 직접 SSH로 들어갈 수 없다. 대신 탄력적 IP가 붙은 배스천(점프 서버)에 먼저 접속한 뒤, 배스천에서 다시 프라이빗 인스턴스로 SSH 접속한다. 아래는 Windows 11의 PowerShell·터미널 기준이다.

먼저 로컬에서 배스천에 접속한다. -i 뒤에 다운로드한 키 파일 경로를 지정한다.

ssh -i C:/path/to/forPJ.pem ec2-user@<배스천 탄력적 IP>

배스천에 접속했으면, 프라이빗 인스턴스로 다시 들어가기 위해 같은 키 파일을 배스천으로 옮긴다. 키 파일 권한이 너무 개방적이면 SSH가 키 사용을 거부하므로 chmod 400으로 소유자 읽기 전용으로 조인다.

# 배스천에 키 파일 생성(로컬 .pem 내용을 붙여넣기) 또는 scp로 전송
vi forPJ.pem

# 키 권한을 소유자 읽기 전용으로
chmod 400 forPJ.pem

# 배스천 → 프라이빗 인스턴스 접속
ssh -i forPJ.pem ec2-user@<프라이빗 EC2 사설 IP>
배스천을 거쳐 WEB 인스턴스에 SSH 접속한 화면

WEB 인스턴스에 접속한 CLI 화면. WAS 인스턴스에 접속하려면 IP 주소만 바꿔 주면 된다.

키 파일을 배스천에 그대로 두는 방식 대신, 로컬 한 번의 명령으로 배스천을 경유하려면 SSH의 점프 호스트 옵션(-J)을 쓸 수도 있다. 키 파일이 프라이빗 인스턴스에 남지 않아 더 안전하다.

ssh -i C:/path/to/forPJ.pem -J ec2-user@<배스천 IP> ec2-user@<프라이빗 사설 IP>

WEB에서 NginX 리버스 프록시로 WAS 연동

이제 WEB(NginX)이 받은 요청을 NLB를 거쳐 WAS(Tomcat)로 넘기도록 리버스 프록시를 설정한다. WEB 인스턴스에서 nginx.conf를 열고 location 블록의 proxy_pass 대상을 NLB의 DNS 주소:8080으로 지정한다.

vi /usr/local/nginx/conf/nginx.conf

server 블록 안의 location /를 다음과 같이 수정한다. 정적 파일을 NginX가 직접 서빙하지 않고 모든 요청을 WAS로 넘길 것이므로 root/index 대신 proxy_pass를 둔다. 백엔드가 원래 클라이언트 정보를 알 수 있도록 proxy_set_header로 호스트와 IP 헤더를 함께 전달하는 것이 좋다.

location / {
    proxy_pass http://<NLB의 DNS 주소>:8080;

    proxy_set_header Host              $host;
    proxy_set_header X-Real-IP         $remote_addr;
    proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}

설정을 저장한 뒤 문법을 검사하고 NginX를 리로드한다. WAS 쪽 Tomcat도 떠 있어야 한다.

# 문법 검사
/usr/local/nginx/sbin/nginx -t

# 무중단 리로드
/usr/local/nginx/sbin/nginx -s reload

이렇게 하면 ALB로 들어온 요청이 WEB(NginX)에 도달하고, proxy_pass를 통해 NLB로, 다시 WAS(Tomcat)로 전달된다. NLB의 DNS 주소는 고정 IP가 아니라 도메인이므로 인스턴스가 바뀌어도 이 설정을 다시 손볼 필요가 없다.

최종 동작 확인

모든 구성이 끝났으면 웹 브라우저 주소창에 ALB의 DNS 주소를 입력한다. ALB → WEB(NginX) → NLB → WAS(Tomcat) 순으로 요청이 전달되어 아래처럼 Tomcat 기본 화면이 뜨면 AWS WEB-WAS 연동이 성공한 것이다.

AWS ALB DNS로 접속해 NginX·Tomcat 연동이 완료된 화면

커맨드 라인에서 확인하려면 ALB DNS로 직접 요청을 보내 응답 헤더를 본다.

curl -I http://<ALB의 DNS 주소>

자주 막히는 지점 (FAQ)

대상 그룹이 unhealthy로 뜬다

헬스체크 포트(WEB 80, WAS 8080)로 연결이 안 되는 경우다. 인스턴스에서 NginX·Tomcat이 실제로 떠 있는지(ss -lntp), 보안 그룹이 앞단(ALB·NLB)에서 오는 트래픽을 허용하는지 확인한다. 보안 그룹 소스를 IP가 아닌 앞단 보안 그룹으로 지정했는지도 점검 포인트다.

프라이빗 인스턴스에 SSH가 안 된다

WEB·WAS는 공인 IP가 없으므로 로컬에서 바로 접속할 수 없다. 반드시 배스천을 경유해야 하며, WEB·WAS 보안 그룹에 SSH from Bastion-sg 규칙이 있어야 한다. 키 권한 오류(Permissions are too open)가 나면 chmod 400으로 키 파일 권한을 조인다.

ALB 접속은 되는데 503/502가 뜬다

ALB는 살아 있지만 뒤쪽 연동이 끊긴 경우다. 503은 WEB 대상 그룹에 healthy 대상이 없을 때, 502는 WEB의 proxy_pass가 NLB/WAS로 도달하지 못할 때 자주 나타난다. NginX의 proxy_pass 주소가 NLB DNS:8080이 맞는지, NLB 대상 그룹이 healthy인지 순서대로 확인한다.

정리

AWS WEB-WAS 연동의 핵심은 네 가지다. ① VPC 서브넷으로 퍼블릭(ALB·WEB)과 프라이빗(NLB·WAS) 구간을 나누고, ② 보안 그룹을 앞단 보안 그룹 기준으로 체인 구성하며, ③ 프라이빗 인스턴스 접근은 배스천 호스트로만 열고, ④ ALB → WEB → NLB → WAS 흐름을 NginX proxy_pass로 연결하는 것이다. 온프레미스에서 같은 구조의 기본기를 다지려면 NginX-Tomcat 연동Tomcat-MariaDB 연동 글을 함께 보면 좋다.

💬 댓글 0

💬 댓글을 남기려면?
첫 댓글을 남겨보세요 ✨

이 콘텐츠가 도움이 됐나요?

누스쿨 커뮤니티에서 더 많은 커리어 전략을 나눠요