Headers
Cloudflare Pages에서 _headers 파일을 사용하여 HTTP 응답 헤더를 설정하는 방법을 설명합니다.
_headers 파일 생성
파일 위치
_headers 파일(확장자 없음)을 프로젝트의 정적 에셋 디렉토리에 생성합니다:
| 프레임워크 | 위치 |
|---|---|
| Astro | public/_headers |
| Next.js | public/_headers |
| Vue/Nuxt | public/_headers 또는 static/_headers |
| 정적 사이트 | 빌드 출력 디렉토리 |
참고:
_headers파일 자체는 에셋으로 제공되지 않고, Cloudflare Pages가 파싱하여 응답 헤더를 수정합니다.
구문
기본 형식
[URL 패턴] [헤더이름]: [헤더값]예시
# 모든 페이지에 보안 헤더 적용/* X-Frame-Options: DENY X-Content-Type-Options: nosniff
# 정적 에셋 캐싱/static/* Cache-Control: public, max-age=31536000, immutable구문 규칙
- 주석은
#으로 시작 - 각 줄은 최대 2,000자
- 최대 100개의 규칙 정의 가능
- 헤더 이름 앞에 공백(들여쓰기) 필요
URL 패턴 매칭
지원되는 패턴
| 패턴 | 설명 | 예시 |
|---|---|---|
| 정확한 경로 | 특정 URL만 매칭 | /about |
와일드카드 (*) | 모든 문자 매칭 | /api/*, /* |
플레이스홀더 (:name) | 명명된 세그먼트 | /users/:id |
패턴 예시
# 모든 페이지/*
# 특정 디렉토리/images/*/api/*
# 특정 파일 확장자/*.js/*.css
# 중첩 경로/blog/*/docs/*/images/*우선순위
리다이렉트가 헤더보다 먼저 적용됩니다. 요청이 리다이렉트와 헤더 규칙 모두에 매칭되면, 리다이렉트가 우선합니다.
헤더 조작
헤더 추가
/* X-Custom-Header: my-value Another-Header: another-value헤더 제거
헤더 이름 앞에 ! (느낌표 + 공백)를 붙여 헤더를 제거합니다:
/* ! Server ! X-Powered-By중복 헤더 값
동일한 헤더가 여러 규칙에서 적용되면, 값이 쉼표로 결합됩니다:
/* Cache-Control: public
/static/* Cache-Control: max-age=31536000/static/app.js 요청 시 결과:
Cache-Control: public, max-age=31536000일반적인 헤더 설정
CORS (Cross-Origin Resource Sharing)
# 모든 출처 허용/* Access-Control-Allow-Origin: *
# 특정 출처만 허용/api/* Access-Control-Allow-Origin: https://example.com Access-Control-Allow-Methods: GET, POST, OPTIONS Access-Control-Allow-Headers: Content-Type, Authorization캐싱
# HTML - 캐시 안함 Cache-Control: no-cache, no-store, must-revalidate
# 정적 에셋 - 1년 캐시 (해시된 파일명)/assets/* Cache-Control: public, max-age=31536000, immutable
# 이미지 - 1주일 캐시/images/* Cache-Control: public, max-age=604800
# API - 캐시 안함/api/* Cache-Control: no-store보안 헤더
/* # 클릭재킹 방지 X-Frame-Options: DENY
# MIME 타입 스니핑 방지 X-Content-Type-Options: nosniff
# Referrer 정보 제어 Referrer-Policy: strict-origin-when-cross-origin
# HTTPS 강제 Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
# XSS 보호 (레거시 브라우저용) X-XSS-Protection: 1; mode=blockContent Security Policy (CSP)
/* Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.example.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' https://fonts.gstatic.com; connect-src 'self' https://api.example.comPermissions Policy
/* Permissions-Policy: accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()검색 엔진 제어
# 스테이징 환경 인덱싱 방지/* X-Robots-Tag: noindex, nofollow
# 특정 경로만 인덱싱 방지/admin/* X-Robots-Tag: noindex/preview/* X-Robots-Tag: noindex실전 예시
완전한 _headers 파일
# 모든 페이지에 보안 헤더 적용/* X-Frame-Options: DENY X-Content-Type-Options: nosniff Referrer-Policy: strict-origin-when-cross-origin Permissions-Policy: accelerometer=(), camera=(), geolocation=()
# HTML 페이지/*.html/ Cache-Control: no-cache
# 정적 에셋 (해시된 파일명)/_astro/* Cache-Control: public, max-age=31536000, immutable
# 이미지/images/* Cache-Control: public, max-age=604800
# 폰트/fonts/* Cache-Control: public, max-age=31536000 Access-Control-Allow-Origin: *
# API 엔드포인트/api/* Cache-Control: no-store Access-Control-Allow-Origin: * Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS Access-Control-Allow-Headers: Content-Type, AuthorizationAstro 프로젝트용
public/_headers:
# 보안 헤더/* X-Frame-Options: SAMEORIGIN X-Content-Type-Options: nosniff Referrer-Policy: strict-origin-when-cross-origin
# Astro 빌드 에셋 (해시 포함)/_astro/* Cache-Control: public, max-age=31536000, immutable
# 이미지 최적화/_image Cache-Control: public, max-age=604800제한 사항
Pages Functions와의 호환성
_headers 파일의 커스텀 헤더는 Pages Functions 응답에 적용되지 않습니다.
SSR이나 Functions 기반 응답에 헤더를 추가하려면, 함수 코드에서 직접 헤더를 설정해야 합니다:
export async function onRequest(context) { const data = { message: "Hello" };
return new Response(JSON.stringify(data), { headers: { "Content-Type": "application/json", "Cache-Control": "no-store", "Access-Control-Allow-Origin": "*", }, });}기타 제한
- 각 줄 최대 2,000자
- 최대 100개 규칙
- HTTPS URL만 지원
- 일부 Cloudflare 예약 헤더는 수정 불가
디버깅
헤더 확인 방법
# curl로 헤더 확인curl -I https://your-site.pages.dev/
# 특정 경로 헤더 확인curl -I https://your-site.pages.dev/api/data브라우저 개발자 도구의 Network 탭에서도 응답 헤더를 확인할 수 있습니다.
일반적인 문제
-
헤더가 적용되지 않음
_headers파일 위치 확인 (빌드 출력에 포함되어야 함)- 구문 오류 확인 (들여쓰기, 콜론 뒤 공백)
-
Functions 응답에 헤더 없음
_headers는 정적 에셋에만 적용됨- Functions에서 직접 헤더 설정 필요
-
캐시가 예상대로 동작하지 않음
- Cloudflare 캐시 정책과의 상호작용 확인
Cache-Control값 검토