.htaccess 생성기를 사용하면 mod_rewrite 문법을 외우거나 괄호 위치 오류로 500 에러를 낼 걱정 없이 유효한 Apache .htaccess 설정을 생성할 수 있습니다. .htaccess(“hypertext access”의 약자)는 디렉터리별 설정 파일로, Apache가 모든 요청마다 읽습니다. 메인 서버 설정을 건드리지 않고 리다이렉트·헤더·인증·압축을 제어할 수 있습니다.

.htaccess의 용도와 사용 시점

.htaccessAllowOverride가 활성화된 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 생성기 사용해보기 →

필요한 규칙을 선택하고 도메인과 경로를 입력하면 올바른 순서·문법 오류 없음·각 블록 설명 주석이 있는 프로덕션 준비 완료된 .htaccess 파일이 생성됩니다.