| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 | 31 |
- SEQUENCE
- SpringLegacy
- 냄새라도
- AOP
- string
- JDBC
- MVC요청플로우
- index
- 공통기술
- 이벤트핸들러this
- DDD
- 전전긍긍
- model
- 단위테스트
- JPA
- TDD
- 문제선택근거
- Ajax
- Transaction
- 디스크i/o
- 커뮤니티서버
- 클린아키텍처
- MVC
- 이벤트핸들러등록
- springsecurity
- OOP
- 공통규약
- 설정세팅
- 사면초가
- 로그백
- Today
- Total
개발이군고구마
Apache HTTPD 본문
Apache HTTPD, 정확히 무엇인가
"세계에서 가장 많이 쓰이는 웹 서버"라는 표현은 추상적. EC2 환경에서 실제로 어떤 역할을 하는지를 중심으로 이해하는 것이 핵심.
EC2의 80·443 포트를 열고, 외부에서 들어오는 모든 HTTP/HTTPS 요청을 가장 먼저 받아서 "어디로 보낼지"를 결정하는 프로세스.
EC2 내부에서 실제로 동작하는 프로세스
# EC2에 SSH 접속 후 프로세스 확인
$ ps aux | grep httpd
root 1234 httpd ← 마스터 프로세스 (설정 로드, 워커 관리)
apache 1235 httpd ← 워커 프로세스 (실제 요청 처리)
apache 1236 httpd
apache 1237 httpd
포트 점유
80·443 포트를 열고 외부 요청 수신
라우팅 결정
URL 경로에 따라 ALB, S3, 로컬 파일로 분기
SSL/TLS 처리
HTTPS 인증서 관리 및 암복호화
로깅
모든 요청·응답 기록 및 에러 추적
httpd.conf — 경비원의 근무 지침서
Apache는 스스로 판단하지 않음. httpd.conf에 적힌 내용 그대로만 행동. 지침서가 없으면 아무것도 못하고, 지침서가 잘못되면 엉뚱한 곳으로 요청을 보내거나 503 에러 반환.
httpd.conf = 경비원 근무 지침서 (전체 규정집)
conf.d/*.conf = 서비스별 세부 업무 지침서 (실제 작업 파일)
RHEL / CentOS 계열 디렉토리 구조
/etc/httpd/ ├── conf/ │ └── httpd.conf ← 총괄 설정 (ServerRoot, Listen, User 등) │ ├── conf.d/ ← ★ 실제 작업 영역 │ ├── myapp.conf ← 서비스 VirtualHost, ProxyPass 설정 │ ├── ssl.conf ← HTTPS 인증서 설정 │ └── welcome.conf ← 기본 웰컴 페이지 (보통 비활성화) │ ├── conf.modules.d/ │ ├── 00-base.conf ← 기본 모듈 목록 │ └── 00-proxy.conf ← ProxyPass 사용 시 필요한 모듈 │ └── logs/ ├── access_log ← 모든 요청 기록 └── error_log ← 에러 발생 기록
Debian / Ubuntu 계열 디렉토리 구조
/etc/apache2/ ├── apache2.conf ← 총괄 설정 │ ├── sites-available/ ← 정의만 해두는 곳 (비활성) │ ├── 000-default.conf │ └── myapp.conf │ ├── sites-enabled/ ← 심볼릭 링크로 활성화된 설정 │ └── myapp.conf → ../sites-available/myapp.conf │ ├── mods-available/ ← 사용 가능한 모듈 목록 └── mods-enabled/ ← a2enmod 명령으로 활성화된 모듈
패키지 이름이
httpd(RHEL) vs apache2(Ubuntu)로 다를 뿐, 동작 원리와 설정 문법은 완전히 동일.
| 항목 | RHEL / CentOS (httpd) | Ubuntu / Debian (apache2) |
|---|---|---|
| 패키지 설치 | yum install httpd | apt install apache2 |
| 서비스 시작 | systemctl start httpd | systemctl start apache2 |
| 메인 설정 | /etc/httpd/conf/httpd.conf | /etc/apache2/apache2.conf |
| 추가 설정 | conf.d/*.conf | sites-enabled/*.conf |
| 모듈 활성화 | 설정파일에 직접 LoadModule 작성 | a2enmod proxy 명령 사용 |
| 소프트웨어 | 동일 — Apache HTTP Server 2.4 | |
Apache → ALB : ProxyPass 설정
ProxyPass는 Apache가 받은 요청을 내부 또는 외부의 다른 서버로 투명하게 전달하는 디렉티브. 클라이언트는 ALB의 존재를 알지 못하고 Apache 하나와만 통신하는 것처럼 인식.
모듈 활성화 (설정 전 필수)
# RHEL/CentOS — /etc/httpd/conf.modules.d/00-proxy.conf 확인
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule headers_module modules/mod_headers.so
# Ubuntu/Debian — 명령어로 활성화
$ a2enmod proxy proxy_http headers
VirtualHost + ProxyPass 설정
/etc/httpd/conf.d/myapp.conf
<VirtualHost *:80>
ServerName www.example.com
# ① 원본 Host 헤더를 백엔드에 그대로 전달
ProxyPreserveHost On
# ② /api/* 요청을 ALB로 전달
ProxyPass /api http://my-alb-1234.ap-northeast-2.elb.amazonaws.com/api
ProxyPassReverse /api http://my-alb-1234.ap-northeast-2.elb.amazonaws.com/api
# ③ 클라이언트 실제 IP를 백엔드에 전달
RequestHeader set X-Forwarded-For "%{REMOTE_ADDR}s"
RequestHeader set X-Forwarded-Proto "http"
# ④ 나머지 경로는 로컬 파일 서빙
DocumentRoot /var/www/html
ErrorLog /var/log/httpd/error.log
CustomLog /var/log/httpd/access.log combined
</VirtualHost>
| 디렉티브 | 역할 |
|---|---|
| ProxyPass | 요청을 지정한 백엔드 URL로 포워딩 |
| ProxyPassReverse | 백엔드의 리다이렉트 응답 Location 헤더를 Apache 주소로 재작성 |
| ProxyPreserveHost On | 원본 도메인(Host 헤더) 유지. ALB 연결 시 권장 |
| X-Forwarded-For | 백엔드가 클라이언트 실제 IP를 알 수 있도록 헤더 추가 |
Apache → S3 : ProxyPass vs RewriteRule
S3로 연결하는 방법은 두 가지. 목적에 따라 선택이 달라짐.
방법 A — ProxyPass
- S3 URL 클라이언트에 미노출
- 비공개(Private) S3 버킷 사용 가능
- Apache가 모든 트래픽을 중계
- 대용량 파일 시 Apache 부하 증가
- ProxyPreserveHost Off 설정 필수
방법 B — RewriteRule (302)
- S3 URL이 브라우저에 노출됨
- S3 버킷이 퍼블릭이어야 함
- Apache는 302만 응답, 부하 최소
- 대용량 파일, CDN 연계에 최적
- CloudFront 앞단 구성과 궁합 최적
방법 A — ProxyPass로 S3 연결
/etc/httpd/conf.d/myapp.conf
<VirtualHost *:80>
ServerName www.example.com
# S3 연결 시 반드시 Off — On이면 S3가 Host 헤더를 인식 못해 403 발생
ProxyPreserveHost Off
# /uploads/* → S3 비공개 버킷으로 프록시
ProxyPass /uploads https://my-bucket.s3.ap-northeast-2.amazonaws.com/uploads
ProxyPassReverse /uploads https://my-bucket.s3.ap-northeast-2.amazonaws.com/uploads
</VirtualHost>
ProxyPreserveHost Off 를 반드시 설정. On 상태로 요청 시 S3가 Host 헤더(www.example.com)를 인식하지 못해 403 AccessDenied 오류 발생.
방법 B — RewriteRule로 S3 리다이렉트
/etc/httpd/conf.d/myapp.conf
LoadModule rewrite_module modules/mod_rewrite.so
<VirtualHost *:80>
ServerName www.example.com
RewriteEngine On
# /static/* → CloudFront(S3 앞단)로 302 리다이렉트
RewriteRule ^/static/(.*)$ \
https://d1234abcd.cloudfront.net/static/$1 [R=302,L]
# /uploads/* → S3 퍼블릭 버킷으로 리다이렉트
RewriteRule ^/uploads/(.*)$ \
https://my-bucket.s3.ap-northeast-2.amazonaws.com/uploads/$1 [R=302,L]
</VirtualHost>
| 비교 항목 | ProxyPass | RewriteRule (302) |
|---|---|---|
| S3 URL 노출 | ❌ 숨김 | ✅ 노출 |
| Apache 부하 | 높음 (트래픽 중계) | 낮음 (302만 응답) |
| S3 퍼블릭 설정 | 불필요 | 퍼블릭 필수 |
| 대용량 파일 | 비추천 | 추천 |
| CDN 연계 | 가능 | 최적 |
| 적합한 케이스 | 비공개 파일, URL 은닉 | 이미지·동영상, CDN 활용 |
ALB + S3 통합 최종 설정 예시
/api는 ALB, /uploads는 S3 프록시, /static은 S3 리다이렉트, 나머지는 로컬 파일 서빙 — 실제 프로덕션에서 사용하는 전체 VirtualHost 구성.
/etc/httpd/conf.d/myapp.conf
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule headers_module modules/mod_headers.so
LoadModule ssl_module modules/mod_ssl.so
<VirtualHost *:443>
ServerName www.example.com
# SSL 설정
SSLEngine on
SSLCertificateFile /etc/ssl/certs/example.crt
SSLCertificateKeyFile /etc/ssl/private/example.key
RewriteEngine On
# ── ① /static/* → CloudFront 302 리다이렉트 ────────────────
RewriteRule ^/static/(.*)$ \
https://d1234abcd.cloudfront.net/static/$1 [R=302,L]
# ── ② /uploads/* → S3 비공개 버킷 ProxyPass ────────────────
ProxyPreserveHost Off # S3 연결 시 Off 필수
ProxyPass /uploads https://my-private.s3.ap-northeast-2.amazonaws.com/uploads
ProxyPassReverse /uploads https://my-private.s3.ap-northeast-2.amazonaws.com/uploads
# ── ③ /api/* → ALB ProxyPass ────────────────────────────────
ProxyPreserveHost On # ALB 연결 시 On 권장
ProxyPass /api http://my-alb-xxxx.ap-northeast-2.elb.amazonaws.com/api
ProxyPassReverse /api http://my-alb-xxxx.ap-northeast-2.elb.amazonaws.com/api
RequestHeader set X-Forwarded-Proto "https"
RequestHeader set X-Forwarded-For "%{REMOTE_ADDR}s"
# ── ④ 나머지 → 로컬 파일 ────────────────────────────────────
DocumentRoot /var/www/html
<Directory /var/www/html>
Options -Indexes
AllowOverride None
Require all granted
</Directory>
ErrorLog /var/log/httpd/error.log
CustomLog /var/log/httpd/access.log combined
</VirtualHost>
# HTTP → HTTPS 리다이렉트
<VirtualHost *:80>
ServerName www.example.com
RewriteEngine On
RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [R=301,L]
</VirtualHost>
설정 적용 및 검증
# 설정 문법 검사 (적용 전 반드시 실행)
$ httpd -t
Syntax OK
# 무중단 설정 반영 (권장)
$ systemctl reload httpd
# 완전 재시작
$ systemctl restart httpd
# 실시간 에러 로그 확인
$ tail -f /var/log/httpd/error.log
ASG 환경에서 httpd 설정 자동화
Auto Scaling Group(ASG)은 트래픽 변화에 따라 EC2를 자동으로 종료하고 새로 생성. 수동으로 conf 파일을 배포하면 새 인스턴스에는 설정이 없는 상태로 올라오므로, 설정 파일을 코드로 관리하고 인스턴스 생성 시 자동으로 주입하는 구조가 필수.
Git 리포지토리에 conf 파일 관리 → CI/CD가 S3에 업로드 → ASG가 EC2 생성 시 UserData 스크립트 실행 → S3에서 conf 다운로드 → httpd 자동 시작
Git 리포지토리 — conf 파일 구조
서비스 유형(api, mobile, pc)별로 conf를 분리해서 관리. 각 Launch Template이 필요한 파일만 선택적으로 S3에서 가져옴.
httpd-configs/ ← Git 리포지토리 루트 ├── common/ │ ├── httpd.conf ← 전체 공통 설정 (포트, 모듈, 로그) │ └── ssl.conf ← HTTPS 공통 설정 │ ├── api/ │ └── api.conf ← API 서버용 VirtualHost (ProxyPass → ALB-API) │ ├── mobile/ │ └── mobile.conf ← 모바일 웹용 VirtualHost (ProxyPass → ALB-Mobile) │ ├── pc/ │ └── pc.conf ← PC 웹용 VirtualHost (ProxyPass → ALB-PC) │ └── scripts/ └── upload-to-s3.sh ← CI/CD에서 호출하는 S3 업로드 스크립트
CI/CD → S3 업로드 스크립트
scripts/upload-to-s3.sh
#!/bin/bash
# GitHub Actions / CodePipeline 등에서 호출
# conf 파일 전체를 S3에 동기화
BUCKET="my-httpd-configs"
REGION="ap-northeast-2"
# 변경된 파일만 동기화 (--delete: S3에서 삭제된 파일도 반영)
aws s3 sync ./ s3://$BUCKET/httpd/ \
--region $REGION \
--exclude "*.sh" \
--exclude ".git/*" \
--delete
echo "✅ conf 파일 S3 동기화 완료"
Launch Template — UserData 스크립트
ASG의 Launch Template에 UserData를 등록해두면, EC2가 생성될 때마다 자동으로 실행됨.
APP_TYPE 환경변수 또는 태그를 통해 어느 conf를 내려받을지 결정.
Launch Template UserData — api 서버 예시
#!/bin/bash
# EC2 생성 시 자동 실행되는 UserData 스크립트
# 역할: S3에서 해당 서버 유형의 conf를 받아 httpd 설치 후 시작
## ① 변수 정의
APP_TYPE="api" # api / mobile / pc — Launch Template마다 다르게 설정
BUCKET="my-httpd-configs"
REGION="ap-northeast-2"
CONF_DIR="/etc/httpd/conf.d"
## ② 패키지 업데이트 및 httpd 설치
yum update -y
yum install -y httpd mod_ssl
## ③ S3에서 공통 설정 다운로드
aws s3 cp s3://$BUCKET/httpd/common/httpd.conf /etc/httpd/conf/httpd.conf \
--region $REGION
aws s3 cp s3://$BUCKET/httpd/common/ssl.conf $CONF_DIR/ssl.conf \
--region $REGION
## ④ S3에서 서버 유형별 conf 다운로드
# APP_TYPE=api → api/api.conf 만 적용
# APP_TYPE=mobile → mobile/mobile.conf 만 적용
# APP_TYPE=pc → pc/pc.conf 만 적용
aws s3 cp s3://$BUCKET/httpd/$APP_TYPE/$APP_TYPE.conf \
$CONF_DIR/$APP_TYPE.conf \
--region $REGION
## ⑤ 설정 문법 검사
httpd -t
if [ $? -ne 0 ]; then
echo "❌ httpd 설정 오류 — 시작 중단" | logger
exit 1
fi
## ⑥ httpd 시작 및 자동시작 등록
systemctl enable httpd
systemctl start httpd
echo "✅ $APP_TYPE 서버 httpd 시작 완료" | logger
EC2가 S3에서 conf를 다운로드하려면, Launch Template에 연결된 IAM Instance Profile에
s3:GetObject 권한이 있어야 함. 별도의 Access Key 없이 IAM Role로만 처리하는 것이 보안 모범 사례.
서비스별 conf 파일 예시
api/api.conf — API 서버 전용
<VirtualHost *:443>
ServerName api.example.com
SSLEngine on
SSLCertificateFile /etc/ssl/certs/example.crt
SSLCertificateKeyFile /etc/ssl/private/example.key
# API 트래픽 전체를 ALB-API로 프록시
ProxyPreserveHost On
ProxyPass / http://api-alb-xxxx.ap-northeast-2.elb.amazonaws.com/
ProxyPassReverse / http://api-alb-xxxx.ap-northeast-2.elb.amazonaws.com/
RequestHeader set X-Forwarded-Proto "https"
ErrorLog /var/log/httpd/api-error.log
CustomLog /var/log/httpd/api-access.log combined
</VirtualHost>
mobile/mobile.conf — 모바일 웹 전용
<VirtualHost *:443>
ServerName m.example.com
SSLEngine on
SSLCertificateFile /etc/ssl/certs/example.crt
SSLCertificateKeyFile /etc/ssl/private/example.key
RewriteEngine On
# 정적 자산 → CloudFront
RewriteRule ^/static/(.*)$ \
https://mobile-cdn.cloudfront.net/static/$1 [R=302,L]
# 모바일 앱 API → ALB-Mobile
ProxyPreserveHost On
ProxyPass /api http://mobile-alb-xxxx.ap-northeast-2.elb.amazonaws.com/api
ProxyPassReverse /api http://mobile-alb-xxxx.ap-northeast-2.elb.amazonaws.com/api
DocumentRoot /var/www/html/mobile
ErrorLog /var/log/httpd/mobile-error.log
CustomLog /var/log/httpd/mobile-access.log combined
</VirtualHost>
ASG Launch Template — 서비스별 분리 구조
• conf 파일이 Git으로 버전 관리되므로 변경 이력 추적 및 롤백 가능
• ASG가 EC2를 몇 대 생성하든 항상 동일한 설정으로 올라옴 (불변 인프라)
• 서비스 유형별로 conf가 분리되어 있어 api만, 또는 mobile만 별도 배포 가능
• EC2 내부에 conf를 직접 수정하면 다음 Scale-in/out 시 사라지므로, 서버에서 직접 수정하는 습관은 금지
UserData 스크립트는 EC2 최초 부팅 시에만 실행됨. 이미 실행 중인 인스턴스에 conf를 변경하려면 S3 업데이트 후 인스턴스 교체(Refresh)가 필요. ASG의 "Instance Refresh" 기능을 사용하면 무중단으로 순차 교체 가능.
핵심 개념 요약
| 용어 | 실제 의미 |
|---|---|
| httpd (Apache) | EC2에서 80/443 포트를 열고 요청을 수신하는 프로세스 |
| httpd.conf | Apache가 어떻게 동작할지 정의된 설정 파일 (근무 지침서) |
| conf.d/*.conf | 서비스별 세부 설정 파일. 실제 작업 대상 |
| VirtualHost | 도메인별로 다른 설정을 적용하는 단위 |
| ProxyPass | 요청을 ALB·S3 등 다른 서버로 투명하게 전달 |
| ProxyPassReverse | 백엔드 리다이렉트 URL을 Apache 주소로 재작성 |
| RewriteRule | URL 패턴 매칭 후 리다이렉트 또는 변환 |
| mod_proxy | ProxyPass 기능을 사용하기 위한 Apache 모듈 |
| ASG (Auto Scaling Group) | 트래픽에 따라 EC2를 자동 생성·종료하는 AWS 서비스 |
| Launch Template | ASG가 EC2를 생성할 때 참조하는 인스턴스 설정 템플릿 |
| UserData | EC2 최초 부팅 시 자동 실행되는 초기화 스크립트 |
| Instance Refresh | ASG가 기존 인스턴스를 새 설정으로 순차적으로 무중단 교체하는 기능 |
ALB로 전달 시 →
ProxyPreserveHost On — 원본 도메인 유지S3로 전달 시 →
ProxyPreserveHost Off — S3가 Host 헤더를 자체 처리
S3 URL 숨기기 / 비공개 버킷 필요 → ProxyPass
대용량 파일 / CDN 연계 / Apache 부하 최소화 → RewriteRule (302)
'Cloud Deploy' 카테고리의 다른 글
| Jenkins 구조와 원리 정리 (0) | 2026.07.01 |
|---|---|
| 배포 흐름으로 이해하는 AWS 인프라 구조 (0) | 2026.04.04 |
| Git revert, revert의 이해 (1) | 2026.04.03 |
| NLB와 ALB의 차이 (Reverse Proxy 와 D-NAT) (0) | 2026.03.25 |
| Git의 원리: 객체, 브랜치, HEAD, 병합, 원격 저장소 (0) | 2026.03.21 |