.htaccess 생성기를 사용하면 mod_rewrite 문법을 외우거나 괄호 위치 오류로 500 에러를 낼 걱정 없이 유효한 Apache .htaccess 설정을 생성할 수 있습니다. .htaccess(“hypertext access”의 약자)는 디렉터리별 설정 파일로, Apache가 모든 요청마다 읽습니다. 메인 서버 설정을 건드리지 않고 리다이렉트·헤더·인증·압축을 제어할 수 있습니다.
.htaccess의 용도와 사용 시점
.htaccess는 AllowOverride가 활성화된 Apache 서버에서만 동작합니다. Nginx·LiteSpeed·CDN 전용 구성에서는 사용할 수 없습니다. Nginx에는 디렉터리별 설정 파일에 해당하는 것이 없으며, 규칙은 server {} 블록에 작성합니다.
.htaccess가 적합한 경우:
httpd.conf를 편집할 수 없는 공유 호스팅- WordPress·Joomla·Drupal(모두 퍼머링크에
.htaccess사용) - 서버 재시작 없이 빠르게 규칙을 적용하고 싶은 경우
메인 서버 설정이나 Nginx를 선택해야 하는 경우:
- 트래픽이 많은 사이트(
.htaccess는 모든 요청마다 재읽기로 지연 발생) - 컨테이너나 서버리스 환경
- 모든 가상 호스트에 전역으로 적용해야 하는 규칙
필수 .htaccess 규칙
HTTPS 강제(HTTP에서 HTTPS 리다이렉트)
가장 많이 사용되는 .htaccess 규칙입니다. 모든 HTTP 트래픽을 HTTPS로 리다이렉트합니다. Google 순위 신호이기도 합니다.
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
SSL을 종료하는 로드 밸런서 뒤에 있는 경우 전달된 헤더를 사용하세요:
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
www·non-www 통일
하나를 정규 형식으로 정하고 나머지를 리다이렉트합니다:
# non-WWW를 정규 형식으로
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*)$ https://%1/$1 [R=301,L]
# WWW를 정규 형식으로
RewriteEngine On
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^(.*)$ https://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
301 영구 리다이렉트
특정 페이지를 새 URL로 이동합니다:
Redirect 301 /old-page https://yourdomain.com/new-page
정규 표현식을 사용한 패턴 기반 리다이렉트:
RewriteEngine On
RewriteRule ^blog/(.+)$ /articles/$1 [R=301,L]
커스텀 404 오류 페이지
ErrorDocument 404 /404.html
ErrorDocument 500 /500.html
ErrorDocument 403 /403.html
CORS 헤더
특정 도메인 또는 모든 오리진의 크로스 오리진 요청을 허용합니다:
# 특정 오리진 허용
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "https://app.yourdomain.com"
Header set Access-Control-Allow-Methods "GET, POST, OPTIONS"
Header set Access-Control-Allow-Headers "Content-Type, Authorization"
</IfModule>
# 모든 오리진 허용(공개 API나 폰트 서빙)
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "*"
</IfModule>
Basic 인증(비밀번호 보호)
디렉터리를 사용자명과 비밀번호로 보호합니다:
AuthType Basic
AuthName "Restricted Area"
AuthUserFile /path/to/.htpasswd
Require valid-user
.htpasswd 파일 생성:
htpasswd -c /path/to/.htpasswd username
# 비밀번호 입력 프롬프트가 나타납니다
전체 디렉터리 대신 특정 파일만 보호:
<Files "admin.php">
AuthType Basic
AuthName "Admin"
AuthUserFile /path/to/.htpasswd
Require valid-user
</Files>
Gzip 압축
텍스트 기반 응답을 압축하여 전송 크기를 줄입니다. HTML·CSS·JavaScript에서 보통 60~80% 절감 효과가 있습니다:
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/html text/plain text/css
AddOutputFilterByType DEFLATE application/javascript application/json
AddOutputFilterByType DEFLATE application/xml image/svg+xml
AddOutputFilterByType DEFLATE font/woff2 font/woff
</IfModule>
브라우저 캐시 헤더
정적 에셋의 캐시 기간을 브라우저에 알립니다:
<IfModule mod_expires.c>
ExpiresActive On
# 이미지
ExpiresByType image/jpeg "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 month"
ExpiresByType image/x-icon "access plus 1 year"
# CSS와 JavaScript
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 0 seconds"
</IfModule>
Vite·webpack·Next.js처럼 파일명에 콘텐츠 해시를 사용한다면 immutable로 최대 캐시 효율을 얻을 수 있습니다:
<FilesMatch "\.[0-9a-f]{8,}\.(js|css|woff2)$">
Header set Cache-Control "public, max-age=31536000, immutable"
</FilesMatch>
핫링킹 방지
다른 사이트가 이미지를 임베드하여 대역폭을 소비하는 것을 방지합니다:
RewriteEngine On
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^https?://(www\.)?yourdomain\.com/ [NC]
RewriteRule \.(jpg|jpeg|png|gif|webp|svg)$ - [F,L]
보안 헤더
<IfModule mod_headers.c>
# 클릭재킹 방지
Header always set X-Frame-Options "SAMEORIGIN"
# MIME 타입 스니핑 방지
Header always set X-Content-Type-Options "nosniff"
# 오래된 브라우저의 XSS 필터 활성화
Header always set X-XSS-Protection "1; mode=block"
# 리퍼러 정책
Header always set Referrer-Policy "strict-origin-when-cross-origin"
# 서버 시그니처 제거
Header always unset X-Powered-By
Header always unset Server
</IfModule>
.htaccess 규칙 테스트
curl — 리다이렉트 확인
# 리다이렉트를 따라 최종 URL 표시
curl -L -I https://yourdomain.com/old-page
# 모든 리다이렉트 홉 표시
curl -v https://yourdomain.com/old-page 2>&1 | grep -E "< HTTP|Location:"
CORS 헤더 테스트
curl -H "Origin: https://other.com" \
-H "Access-Control-Request-Method: GET" \
-I https://yourdomain.com/api/resource
Gzip 테스트
curl -H "Accept-Encoding: gzip" -I https://yourdomain.com/
# 확인 항목: Content-Encoding: gzip
캐시 헤더 확인
curl -I https://yourdomain.com/static/app.js
# 확인 항목: Cache-Control과 Expires 헤더
자주 하는 실수
1. RewriteEngine On 누락 — RewriteRule을 사용하는 모든 블록의 첫 줄에 이 줄이 필요합니다. 빠뜨리면 500 에러가 발생합니다.
2. 규칙 순서 중요 — Apache는 규칙을 위에서 아래로 처리하고 [L]이 있는 첫 번째 매치에서 멈춥니다. 광범위한 규칙보다 더 구체적인 규칙을 먼저 배치하세요.
3. 무한 리다이렉트 루프 — HTTPS 리다이렉트가 이미 HTTPS인 경우에도 실행되면 루프가 발생합니다. 항상 %{HTTPS} off 또는 %{HTTP:X-Forwarded-Proto} !https를 확인하세요.
4. .htpasswd 경로 — 상대 URL이 아닌 절대 서버 경로를 사용하세요. 상대 경로는 대부분의 설정에서 작동하지 않습니다.
5. mod_rewrite가 활성화되지 않음 — Ubuntu/Debian에서는 sudo a2enmod rewrite && sudo systemctl restart apache2를 실행하세요.
추측 없이 .htaccess 구성하기
위의 규칙은 실제 사용 사례의 90%를 커버하지만, 리다이렉트·인증·캐시 규칙을 올바르게 조합하려면 신중한 순서 지정과 문법이 필요합니다.
필요한 규칙을 선택하고 도메인과 경로를 입력하면 올바른 순서·문법 오류 없음·각 블록 설명 주석이 있는 프로덕션 준비 완료된 .htaccess 파일이 생성됩니다.