기본 설정 확인
Apache 상태 및 설정 검증
# Apache 서비스 상태 확인 sudo systemctl status apache2 # 설정 파일 문법 검사 sudo apache2ctl configtest # 활성화된 가상호스트 목록 확인 sudo apache2ctl -S # Apache 버전 확인 apache2 -v # 로드된 모듈 확인 apache2ctl -M
필수 모듈 활성화
# 프록시 및 SSL 관련 모듈 활성화 sudo a2enmod proxy sudo a2enmod proxy_http sudo a2enmod ssl sudo a2enmod rewrite sudo a2enmod headers # 변경사항 적용 sudo systemctl restart apache2
가상호스트 생성
1. 설정 파일 생성
# 새 가상호스트 설정 파일 생성 sudo vim /etc/apache2/sites-available/testdomain.conf
2. 기본 HTTP 가상호스트
<VirtualHost *:80>
ServerName testdomain.com
ServerAlias www.testdomain.com
ServerAdmin admin@testdomain.com
DocumentRoot /var/www/testdomain
<Directory /var/www/testdomain>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/testdomain_error.log
CustomLog ${APACHE_LOG_DIR}/testdomain_access.log combined
</VirtualHost>
3. HTTP → HTTPS 리다이렉트
<VirtualHost *:80>
ServerName testdomain.com
ServerAlias www.testdomain.com
# 모든 HTTP 요청을 HTTPS로 리다이렉트
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [R=301,L]
ErrorLog ${APACHE_LOG_DIR}/testdomain_http_error.log
CustomLog ${APACHE_LOG_DIR}/testdomain_http_access.log combined
</VirtualHost>
4. HTTPS 가상호스트 (정적 파일)
<VirtualHost *:443>
ServerName testdomain.com
ServerAlias www.testdomain.com
ServerAdmin admin@testdomain.com
DocumentRoot /var/www/testdomain
<Directory /var/www/testdomain>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
# SSL 설정
SSLEngine on
Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateFile /etc/letsencrypt/live/testdomain.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/testdomain.com/privkey.pem
# 보안 헤더
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
Header always set X-Content-Type-Options nosniff
Header always set X-Frame-Options SAMEORIGIN
Header always set X-XSS-Protection "1; mode=block"
ErrorLog ${APACHE_LOG_DIR}/testdomain_https_error.log
CustomLog ${APACHE_LOG_DIR}/testdomain_https_access.log combined
</VirtualHost>
다양한 설정 예제
리버스 프록시
<VirtualHost *:443>
ServerName api.testdomain.com
# SSL 설정
SSLEngine on
SSLProxyEngine on
Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateFile /etc/letsencrypt/live/api.testdomain.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/api.testdomain.com/privkey.pem
# 프록시 설정
ProxyPreserveHost On
ProxyPass / http://localhost:3000/
ProxyPassReverse / http://localhost:3000/
# 프록시 헤더 설정
RequestHeader set X-Forwarded-Proto "https"
RequestHeader set X-Forwarded-Port "443"
ProxyAddHeaders On
# 타임아웃 설정
ProxyTimeout 300
# 요청 크기 제한 해제
LimitRequestBody 0
LimitRequestLine 65536
LimitRequestFieldSize 65536
ErrorLog ${APACHE_LOG_DIR}/api_error.log
CustomLog ${APACHE_LOG_DIR}/api_access.log combined
</VirtualHost>
WebSocket 프록시
<VirtualHost *:443>
ServerName ws.testdomain.com
SSLEngine on
SSLProxyEngine on
Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateFile /etc/letsencrypt/live/ws.testdomain.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/ws.testdomain.com/privkey.pem
# WebSocket 지원을 위한 프록시 설정
ProxyPreserveHost On
RewriteEngine On
RewriteCond %{HTTP:Upgrade} =websocket [NC]
RewriteRule /(.*) ws://localhost:8080/$1 [P,L]
RewriteCond %{HTTP:Upgrade} !=websocket [NC]
RewriteRule /(.*) http://localhost:8080/$1 [P,L]
ProxyPassReverse / http://localhost:8080/
ErrorLog ${APACHE_LOG_DIR}/ws_error.log
CustomLog ${APACHE_LOG_DIR}/ws_access.log combined
</VirtualHost>
여러 백엔드로 로드 밸런싱
sudo a2enmod proxy_balancer sudo a2enmod lbmethod_byrequests
<Proxy balancer://mycluster>
BalancerMember http://localhost:3001
BalancerMember http://localhost:3002
BalancerMember http://localhost:3003
ProxySet lbmethod=byrequests
</Proxy>
<VirtualHost *:443>
ServerName testdomain.com
SSLEngine on
Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateFile /etc/letsencrypt/live/testdomain.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/testdomain.com/privkey.pem
ProxyPreserveHost On
ProxyPass / balancer://mycluster/
ProxyPassReverse / balancer://mycluster/
ErrorLog ${APACHE_LOG_DIR}/testdomain_error.log
CustomLog ${APACHE_LOG_DIR}/testdomain_access.log combined
</VirtualHost>
경로별 다른 백엔드 라우팅
<VirtualHost *:443>
ServerName testdomain.com
SSLEngine on
Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateFile /etc/letsencrypt/live/testdomain.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/testdomain.com/privkey.pem
# API 요청은 백엔드 서버로
ProxyPass /api http://localhost:8000/api
ProxyPassReverse /api http://localhost:8000/api
# 정적 파일은 직접 제공
DocumentRoot /var/www/testdomain
<Directory /var/www/testdomain>
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/testdomain_error.log
CustomLog ${APACHE_LOG_DIR}/testdomain_access.log combined
</VirtualHost>
특정 IP만 접근 허용
<VirtualHost *:443>
ServerName admin.testdomain.com
SSLEngine on
Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateFile /etc/letsencrypt/live/admin.testdomain.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/admin.testdomain.com/privkey.pem
DocumentRoot /var/www/admin
<Directory /var/www/admin>
# 특정 IP만 허용
Require ip 192.168.1.0/24
Require ip 10.0.0.5
</Directory>
ErrorLog ${APACHE_LOG_DIR}/admin_error.log
CustomLog ${APACHE_LOG_DIR}/admin_access.log combined
</VirtualHost>
SSL/HTTPS 설정
Certbot으로 SSL 인증서 발급
# 자동 설정 (권장) sudo certbot --apache -d testdomain.com -d www.testdomain.com # 인증서만 발급 (수동 설정) sudo certbot certonly --standalone -d testdomain.com -d www.testdomain.com # 와일드카드 인증서 발급 sudo certbot certonly --manual --preferred-challenges dns -d testdomain.com -d *.testdomain.com # 인증서 갱신 테스트 sudo certbot renew --dry-run # 인증서 강제 갱신 sudo certbot renew --force-renewal # 인증서 자동 갱신 크론잡 설정 sudo crontab -e # 매일 새벽 2시에 갱신 확인 0 2 * * * certbot renew --quiet
SSL 설정 최적화
# /etc/letsencrypt/options-ssl-apache.conf 참고 # 또는 직접 설정 SSLEngine on SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1 SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384 SSLHonorCipherOrder off SSLSessionTickets off # OCSP Stapling 활성화 SSLUseStapling on SSLStaplingCache "shmcb:logs/stapling-cache(150000)"
가상호스트 관리
활성화/비활성화
# 가상호스트 활성화 sudo a2ensite testdomain.conf # 가상호스트 비활성화 sudo a2dissite testdomain.conf # 기본 사이트 비활성화 sudo a2dissite 000-default.conf # 설정 적용 (다운타임 없음) sudo systemctl reload apache2 # 설정 재시작 (다운타임 발생) sudo systemctl restart apache2
모듈 관리
# 모듈 활성화 sudo a2enmod 모듈명 # 모듈 비활성화 sudo a2dismod 모듈명 # 자주 사용하는 모듈들 sudo a2enmod rewrite # URL 재작성 sudo a2enmod headers # HTTP 헤더 조작 sudo a2enmod proxy # 프록시 기능 sudo a2enmod proxy_http # HTTP 프록시 sudo a2enmod proxy_wstunnel # WebSocket 프록시 sudo a2enmod ssl # SSL/TLS sudo a2enmod deflate # 압축 sudo a2enmod expires # 캐시 제어
문제 해결
로그 확인
# 실시간 에러 로그 모니터링 sudo tail -f /var/log/apache2/error.log # 실시간 액세스 로그 모니터링 sudo tail -f /var/log/apache2/access.log # 특정 가상호스트 로그 sudo tail -f /var/log/apache2/testdomain_error.log # 마지막 100줄 확인 sudo tail -100 /var/log/apache2/error.log # 특정 키워드로 검색 sudo grep "testdomain" /var/log/apache2/*.log # 에러만 필터링 sudo grep "error" /var/log/apache2/error.log # 최근 에러 (systemd) sudo journalctl -u apache2 -n 50
연결 테스트
# HTTP 응답 헤더 확인
curl -I http://testdomain.com/
# HTTPS 응답 헤더 확인
curl -I https://testdomain.com/
# 상세 디버깅 정보
curl -v https://testdomain.com/
# POST 요청 테스트
curl -X POST https://testdomain.com/api/endpoint \
-H "Content-Type: application/json" \
-d '{"key":"value"}'
# SSL 인증서 정보 확인
openssl s_client -connect testdomain.com:443 -servername testdomain.com < /dev/null
# 백엔드 서비스 테스트
curl -v http://localhost:3000/
포트 및 프로세스 확인
# 특정 포트 사용 확인 sudo netstat -tlnp | grep :80 sudo netstat -tlnp | grep :443 sudo netstat -tlnp | grep :3000 # 또는 ss 명령어 사용 (더 빠름) sudo ss -tlnp | grep :80 # Apache 프로세스 확인 ps aux | grep apache2 # 열린 파일 확인 sudo lsof -i :80 sudo lsof -i :443
일반적인 문제 해결
포트 충돌 문제 체크
Apache + Nginx 동시 사용 시 자주 발생
특히 Certbot –apache 사용 시 충돌할 수 있음.
sudo ss -tlnp | grep :80 sudo ss -tlnp | grep :443 // 만약 Nginx가 잡고 있다면 sudo systemctl stop nginx sudo systemctl disable nginx
403 Forbidden 오류
# Directory 권한 확인
<Directory /var/www/testdomain>
Require all granted
# 또는
Options +Indexes
</Directory>
# 파일 시스템 권한 확인
sudo chmod -R 755 /var/www/testdomain
sudo chown -R www-data:www-data /var/www/testdomain
500 Internal Server Error
# 설정 문법 오류 확인 sudo apache2ctl configtest # .htaccess 문제 확인 sudo tail -50 /var/log/apache2/error.log # SELinux 확인 (CentOS/RHEL) sudo setenforce 0 # 임시 비활성화
SSL 인증서 오류
# 인증서 파일 존재 확인 ls -la /etc/letsencrypt/live/testdomain.com/ # 인증서 유효기간 확인 sudo certbot certificates # 인증서 갱신 sudo certbot renew # SSL 인증서 권한 변경 주의 # SSLCertificateFile: file '/etc/letsencrypt/live/.../fullchain.pem' does not exist or is empty // 원인은 보통 인증서 폴더 권한 문제 sudo chmod 755 /etc/letsencrypt/live sudo chmod 644 /etc/letsencrypt/live/DOMAIN/fullchain.pem sudo chmod 600 /etc/letsencrypt/live/DOMAIN/privkey.pem
프록시 오류 (502 Bad Gateway)
# 백엔드 서비스 작동 확인 curl http://localhost:3000/ # SELinux 설정 (CentOS/RHEL) sudo setsebool -P httpd_can_network_connect 1 # 프록시 타임아웃 늘리기 ProxyTimeout 600
Proxy 헤더 관련 ForwardedHeaders 추가
ASP.NET Core, Node.js, Django 모두 HTTPS 프록시 환경에서 필수
RequestHeader set X-Forwarded-For %{REMOTE_ADDR}s
RequestHeader set X-Forwarded-Proto https
RequestHeader set X-Forwarded-Host %{HTTP_HOST}s
# (예시) ASP.NET Core
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
보안 강화
보안 헤더 설정
<VirtualHost *:443>
ServerName testdomain.com
# ... SSL 설정 ...
# HSTS (HTTP Strict Transport Security)
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
# XSS 방지
Header always set X-XSS-Protection "1; mode=block"
# MIME 타입 스니핑 방지
Header always set X-Content-Type-Options "nosniff"
# 클릭재킹 방지
Header always set X-Frame-Options "SAMEORIGIN"
# Referrer 정책
Header always set Referrer-Policy "strict-origin-when-cross-origin"
# CSP (Content Security Policy)
Header always set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline';"
# 서버 정보 숨기기
ServerTokens Prod
ServerSignature Off
</VirtualHost>
접근 제어
# IP 기반 접근 제어
<Directory /var/www/admin>
# 특정 IP만 허용
Require ip 192.168.1.0/24
Require ip 10.0.0.5
# 또는 특정 IP 차단
Require all granted
Require not ip 192.168.1.100
</Directory>
# HTTP Basic 인증
<Directory /var/www/protected>
AuthType Basic
AuthName "Restricted Area"
AuthUserFile /etc/apache2/.htpasswd
Require valid-user
</Directory>
.htpasswd 파일 생성
# htpasswd 파일 생성 (첫 사용자) sudo htpasswd -c /etc/apache2/.htpasswd username # 추가 사용자 등록 (-c 옵션 제거) sudo htpasswd /etc/apache2/.htpasswd username2
Rate Limiting (mod_ratelimit)
<Location /api>
SetOutputFilter RATE_LIMIT
SetEnv rate-limit 400
SetEnv rate-initial-burst 100
</Location>
성능 최적화
캐싱 설정
<VirtualHost *:443>
ServerName testdomain.com
# ... 기본 설정 ...
# 정적 파일 캐싱
<IfModule mod_expires.c>
ExpiresActive On
# 이미지
ExpiresByType image/jpg "access plus 1 year"
ExpiresByType image/jpeg "access plus 1 year"
ExpiresByType image/gif "access plus 1 year"
ExpiresByType image/png "access plus 1 year"
ExpiresByType image/webp "access plus 1 year"
ExpiresByType image/svg+xml "access plus 1 year"
# CSS/JS
ExpiresByType text/css "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
# 폰트
ExpiresByType font/woff2 "access plus 1 year"
ExpiresByType font/woff "access plus 1 year"
# HTML
ExpiresByType text/html "access plus 1 hour"
</IfModule>
# Cache-Control 헤더
<FilesMatch "\.(jpg|jpeg|png|gif|webp|svg|css|js|woff|woff2)$">
Header set Cache-Control "max-age=31536000, public"
</FilesMatch>
</VirtualHost>
Gzip & Brotli 압축
<IfModule mod_deflate.c>
# 압축 활성화
AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css
AddOutputFilterByType DEFLATE application/javascript application/json
AddOutputFilterByType DEFLATE application/xml application/xhtml+xml
AddOutputFilterByType DEFLATE image/svg+xml
# 이미지는 압축 제외 (이미 압축됨)
SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png|webp)$ no-gzip
</IfModule>
sudo apt install libapache2-mod-brotli
sudo a2enmod brotli
<IfModule mod_brotli.c>
BrotliCompressionQuality 5
AddOutputFilterByType BROTLI_COMPRESS text/html text/plain text/css application/javascript application/json image/svg+xml
</IfModule>
KeepAlive 설정
# /etc/apache2/apache2.conf # KeepAlive 활성화 KeepAlive On # 최대 요청 수 MaxKeepAliveRequests 100 # 타임아웃 (초) KeepAliveTimeout 5
MPM 설정 최적화
# /etc/apache2/mods-available/mpm_event.conf
<IfModule mpm_event_module>
StartServers 2
MinSpareThreads 25
MaxSpareThreads 75
ThreadLimit 64
ThreadsPerChild 25
MaxRequestWorkers 150
MaxConnectionsPerChild 0
</IfModule>
디렉토리 구조
Apache 설정 파일 구조
/etc/apache2/ ├── apache2.conf # 메인 설정 파일 ├── ports.conf # 포트 설정 ├── conf-available/ # 사용 가능한 설정 ├── conf-enabled/ # 활성화된 설정 ├── mods-available/ # 사용 가능한 모듈 ├── mods-enabled/ # 활성화된 모듈 (심볼릭 링크) ├── sites-available/ # 사용 가능한 가상호스트 │ ├── 000-default.conf │ ├── testdomain.conf │ └── api.testdomain.conf ├── sites-enabled/ # 활성화된 가상호스트 (심볼릭 링크) │ ├── 000-default.conf -> ../sites-available/000-default.conf │ └── testdomain.conf -> ../sites-available/testdomain.conf └── envvars # 환경 변수
웹 컨텐츠 디렉토리
/var/www/ ├── html/ # 기본 DocumentRoot ├── testdomain/ # 가상호스트 디렉토리 │ ├── public/ │ ├── index.html │ └── .htaccess └── logs/ # 로그 (선택사항)
유용한 명령어 모음
빠른 참조
# 설정 테스트 sudo apache2ctl configtest # 가상호스트 목록 sudo apache2ctl -S # 설정 리로드 (무중단) sudo systemctl reload apache2 # 재시작 sudo systemctl restart apache2 # 상태 확인 sudo systemctl status apache2 # 로그 실시간 모니터링 sudo tail -f /var/log/apache2/error.log # 특정 도메인 설정 확인 sudo apache2ctl -D DUMP_VHOSTS | grep testdomain # 활성화된 모듈 목록 apache2ctl -M # 설정 파일 문법 체크 sudo apachectl -t
자주 사용하는 작업
# 새 가상호스트 생성부터 활성화까지 sudo vim /etc/apache2/sites-available/newsite.conf sudo a2ensite newsite.conf sudo apache2ctl configtest sudo systemctl reload apache2 # SSL 인증서 발급 및 자동 설정 sudo certbot --apache -d newsite.com # 로그 분석 sudo tail -1000 /var/log/apache2/access.log | grep "POST" | wc -l # 디스크 사용량 확인 sudo du -sh /var/log/apache2/* # 오래된 로그 정리 sudo find /var/log/apache2/ -name "*.log.*" -mtime +30 -delete
문제 상황별 체크리스트
사이트가 접속되지 않을 때
- [ ] Apache 서비스 작동 확인:
sudo systemctl status apache2 - [ ] 포트 리스닝 확인:
sudo netstat -tlnp | grep :80 - [ ] 방화벽 확인:
sudo ufw status - [ ] DNS 설정 확인:
nslookup testdomain.com - [ ] 가상호스트 활성화 확인:
sudo apache2ctl -S - [ ] 설정 문법 확인:
sudo apache2ctl configtest
502 Bad Gateway 발생 시
- [ ] 백엔드 서비스 작동 확인:
curl http://localhost:3000/ - [ ] 프록시 설정 확인: ProxyPass, ProxyPassReverse
- [ ] SELinux 설정 확인 (CentOS/RHEL)
- [ ] 타임아웃 설정 확인: ProxyTimeout
- [ ] 에러 로그 확인:
sudo tail -50 /var/log/apache2/error.log
SSL 인증서 오류 시
- [ ] 인증서 파일 존재 확인
- [ ] 인증서 유효기간 확인:
sudo certbot certificates - [ ] 인증서 경로 확인
- [ ] 포트 443 리스닝 확인
- [ ] SSL 모듈 활성화 확인:
apache2ctl -M | grep ssl


