🌐

실전 국제 SEO와 hreflang

올바른 hreflang으로 각 시장에서 순위에 오르는 다국어·다지역 사이트를 출시하라.

📖 14 분 읽기 🕑 업데이트 2026-06-22

콘텐츠가 더 이상 단일 청중만을 위한 것이 아니게 되는 순간 국제 SEO에 손을 대게 된다. 이 문제를 강제하는 계기는 두 가지다. 첫째는 언어다. 사이트를 독일어, 일본어, 스페인어로 번역하면, 각 번역본이 그 언어를 읽는 사람들에게 노출되도록 만들어야 한다. 둘째는 지역이다. 언어는 같지만 시장이 다른 경우인데, 미국 스토어와 영국 스토어가 둘 다 영어이면서도 가격, 배송, 철자, 법적 문구가 다른 식이다. 흔히 두 가지에 동시에 부딪힌다. 미국용 영어, 영국용 영어, 독일용 독일어, 오스트리아용 독일어처럼 말이다.

검색 엔진은 당신의 /de/produkt 페이지가 /en/product의 독일어 대응판이라는 사실을 자동으로 알지 못한다. 추측에 맡기면 잘못 판단하고, 그 대가는 구체적이다.

  • 잘못된 지역 노출. 미국 달러 가격 페이지가 영국 검색자에게 노출되고, 그들은 결제 단계에서 잘못된 통화를 만나 이탈한다.
  • 자기 잠식(self-cannibalization). 거의 동일한 두 영어 페이지가 같은 쿼리를 두고 경쟁한다. Google은 거의 무작위로 하나를 고르고, 신호가 분산되어 어느 쪽도 단일 페이지만큼 잘 순위에 오르지 못한다.
  • 중복 콘텐츠 희석. 번역되지 않은 보일러플레이트와 로케일 간 공유 템플릿은 얇고 반복적인 콘텐츠처럼 보여 클러스터 전체의 평가를 끌어내린다.

hreflang은 이를 해결하는 메커니즘이다. “이 URL은 이 페이지의 X-언어, Y-지역 버전이며, 여기 모든 형제 페이지가 있다”라고 검색 엔진에 알려주는 일련의 주석이다. 제대로 하면 각 검색자를 그들을 위해 만들어진 페이지로 라우팅한다. 잘못하면 — 그리고 아주 쉽게 잘못할 수 있다 — 조용히 아무 일도 하지 않거나, 더 나쁘게는 크롤러를 엉뚱한 페이지로 보낸다. 이 가이드는 실무자 버전이다. 먼저 구조, 그다음 구현, 마지막으로 몇 시간을 잡아먹는 실패 패턴 순이다.

URL 구조 — hreflang이 올라앉는 토대

어떤 주석을 달기 전에, 로케일을 URL에 어떻게 매핑할지 정해야 한다. 이 결정은 되돌리기 어렵고(사이트의 모든 URL을 바꾼다), 따라서 신중히 따져야 한다. 실현 가능한 패턴은 세 가지다.

방식예시SEO 권위(authority)Google에 주는 지리 신호비용 및 설정유지보수
ccTLD (국가 코드 최상위 도메인)example.de, example.co.uk분산 — 각 도메인이 권위를 처음부터 쌓음가장 강함 — .de는 명백한 독일 신호높음 — 다수 도메인 구매·방어, 별도 호스팅·인증서높음 — 도메인마다 별도 SEO 자산
서브디렉터리example.com/de/, example.com/en-gb/통합 — 모든 로케일이 한 도메인의 권위를 공유보통 — hreflang + 콘텐츠로 설정낮음 — 도메인 하나, 인증서 하나, 배포 하나낮음 — 단일 코드베이스, 단일 자산
서브도메인de.example.com, uk.example.com대체로 분산 — Google은 서브도메인을 준-별개로 취급보통중간 — 서브도메인마다 DNS + 인증서중간

대부분의 사이트에 대한 권장: 서브디렉터리. 각 시장이 0에서 기어오르도록 강요하는 대신, 모든 로케일이 메인 도메인이 이미 쌓은 권위를 물려받게 한다. 운영 비용도 가장 싸다 — 저장소 하나, 배포 파이프라인 하나, TLS 인증서 하나, 모니터링할 자산 하나. 그리고 정적 사이트 생성기가 자연스럽게 만들어내는 형태가 바로 이것이다.

ccTLD는 지리 신호가 비용을 감수할 가치가 있는 경우를 위해 아껴두라. 각 국가에서 독립적으로 권위를 쌓을 자원을 갖춘 대형 브랜드이거나, 현지 신뢰가 막대하게 중요하거나(금융, 의료, 정부 인접 분야), 규제 기관이 사실상 현지 도메인을 요구하는 경우다. 서브도메인은 중간 선택지로, 보통 SEO보다는 인프라 이유(지역별 별도 스택)로 선택된다 — Google은 잘 처리한다고 밝혔지만, 실제로는 서브디렉터리만큼 권위 통합이 깔끔하지 않다.

💡 팁: 로케일 세그먼트는 경로의 맨 앞에 둔다 — /blog/de/post가 아니라 /de/blog/post. 최상위 접두사는 모호함이 없고, 라우팅이 쉽고, 라우팅 트리의 한 분기에서 로케일 로직(통화, 언어 헤더)을 적용할 수 있게 해준다.

🧑‍💻 개발자 관점: 무엇을 선택하든, 코드에서 로케일을 단일 진실 공급원(single source of truth)으로 만들어라 — locale -> { hreflang, currency, path prefix }를 매핑하는 설정 객체 하나. 다른 모든 시스템(사이트맵, hreflang 태그, 언어 전환기, 분석)은 그 한 곳에서 읽어야 한다. fr-CA를 추가하는 날, 파일 일곱 개가 아니라 하나만 편집하고 싶을 것이다.

hreflang 구현 — 세 가지 전달 방법

hreflang은 동일한 데이터를 세 채널 중 하나로 전달하는 것이다. 페이지마다 하나의 주된 방법을 고른다. 같은 URL에서 방법을 섞으면 모순을 부른다. 아래의 모든 것을 압도하는 절대 규칙: 주석은 양방향(반환 태그)이어야 한다. 페이지 A가 B를 독일어 대체본으로 나열하면, B도 A를 영어 대체본으로 나열해야 한다. 단 하나의 링크라도 반환이 빠지면, Google은 그 페이지의 전체 클러스터를 무시한다. 악수라고 생각하라 — 양손이 모두 뻗어야 거래가 성립한다.

가장 흔한 방법. 각 페이지의 <head>자기 자신을 포함하여(self-referential) 모든 로케일 대체본과 x-default를 나열한다.

<!-- In the <head> of https://example.com/en/product -->
<link rel="alternate" hreflang="en" href="https://example.com/en/product" />
<link rel="alternate" hreflang="en-GB" href="https://example.com/en-gb/product" />
<link rel="alternate" hreflang="de" href="https://example.com/de/produkt" />
<link rel="alternate" hreflang="zh-CN" href="https://example.com/zh-cn/product" />
<link rel="alternate" hreflang="x-default" href="https://example.com/en/product" />

이 집합에 속한 모든 대체 페이지는 동일한 블록을 지녀야 한다(항목 중 하나로 자기 URL을 자기 참조하면서). 그 동일함이 양방향 악수다.

방법 2 — XML 사이트맵

대형 사이트에 최적이다. 주석을 수천 개 페이지 헤드 대신 한 파일에서 유지하며, 단일 사이트맵 항목이 전체 클러스터를 한 번에 선언한다.

<url>
  <loc>https://example.com/en/product</loc>
  <xhtml:link rel="alternate" hreflang="en" href="https://example.com/en/product"/>
  <xhtml:link rel="alternate" hreflang="en-GB" href="https://example.com/en-gb/product"/>
  <xhtml:link rel="alternate" hreflang="de" href="https://example.com/de/produkt"/>
  <xhtml:link rel="alternate" hreflang="x-default" href="https://example.com/en/product"/>
</url>

루트 요소의 네임스페이스를 잊지 말 것: xmlns:xhtml="http://www.w3.org/1999/xhtml". 그리고 양방향 규칙은 여전히 적용된다 — 클러스터의 모든 <url> 항목은 한 동료로의 링크만이 아니라 전체 xhtml:link 자식 집합을 필요로 한다.

편집할 <head>가 없는 PDF 같은 비-HTML 파일을 위한 유일한 선택지다. 응답 헤더로 전달한다.

Link: <https://example.com/en/manual.pdf>; rel="alternate"; hreflang="en",
      <https://example.com/de/handbuch.pdf>; rel="alternate"; hreflang="de"

방법 고르기

방법적합한 곳주의할 점
HTML <link>소/중형 사이트, 완전한 템플릿 제어페이지 무게; 로케일 변경 시 모든 페이지 편집
XML 사이트맵대형 사이트, 프로그램 방식 생성사이트맵이 라이브 URL과 완벽히 동기 유지되어야 함
HTTP 헤더PDF 및 기타 비-HTML 자산서버/엣지 설정 필요; 잊기 쉬움

코드를 정확히 쓰기

값은 language 또는 language-REGION이다.

  • 언어만en, de, zh, fr. 어디에 있든 그 언어 사용자를 타깃으로 한다.
  • 언어 + 지역en-GB, en-US, zh-CN, pt-BR. 그 국가의 그 언어 사용자를 타깃으로 한다.

언어 코드는 ISO 639-1(두 글자)이다. 지역 코드는 ISO 3166-1 alpha-2(두 글자, 대륙이나 언어가 아닌 국가)이다. 고전적인 함정: 영국의 국가 코드는 UK가 아니라 GB다. 그리고 x-default는 폴백 버킷이다 — 당신이 명시적으로 다루지 않은 언어/지역을 가진 누구에게나 보여주는 페이지다(다음에 자세히). 대소문자는 강제되지 않지만, 관례적 형태는 소문자 언어, 대문자 지역이다: zh-CN, en-GB.

흔한 실수 — 몇 시간을 잡아먹는 실패 패턴

hreflang은 조용히 실패한다. 오류 페이지가 없다. 태그는 그냥 무시되고 당신의 로케일은 순위에서 표류한다. 다음은 반복되는 원인들이다.

  1. 반환 태그 누락. 페이지 A가 B를 가리키지만 B가 A를 되가리키지 않는다. 가장 흔한 단일 실패이며, 깨진 링크만이 아니라 전체 클러스터를 무효화한다. 항상 모든 페이지에 완전하고 대칭적인 집합을 렌더링하라.

  2. 잘못되거나 유효하지 않은 코드. en-GB 대신 en-UK. 지역 코드를 지어내기(en-EUEU라는 국가는 없다). 지역이 와야 할 곳에 언어를 쓰기. 유효하지 않은 항목 하나가 집합 전체를 무효로 만들 수 있다. ISO 목록에 대조해 검증하라.

  3. 상대 URL. hreflang은 프로토콜과 호스트를 포함한 절대 URL을 요구한다/de/produkt가 아니라 https://example.com/de/produkt. 상대 URL은 무시된다.

  4. canonical과 hreflang의 충돌. 이것이 미묘한 킬러다. 각 로케일 페이지의 canonical은 자기 참조여야 한다 — /de/produkt/de/produkt로 정규화된다. 모든 로케일이 대신 영어 버전으로 정규화하면, “이것들은 중복이니 영어만 색인하라”고 Google에 말하는 셈이고, 이는 “이것들은 서로 구별되는 로케일 대응판”이라는 hreflang과 정면으로 모순된다. canonical이 이기고, 당신의 번역본은 색인에서 사라진다. 규칙: 모든 페이지에 자기 참조 canonical + hreflang 집합.

  5. x-default 누락. 엄격히 필수는 아니지만, 그것이 없으면 Google은 매칭되지 않는 사용자를 위해 선언된 폴백이 없다. 항상 x-default를 포함하라 — 보통 언어 선택 페이지나 가장 일반적인/기본 언어 버전을 가리킨다.

  6. 리디렉션되거나 비-200 URL에 주석 달기. 집합의 모든 URL은 200 OK를 반환하고 색인 가능해야 한다. 301 리디렉션되거나 404가 나는 URL을 hreflang으로 가리키면 클러스터의 그 노드가 깨진다.

  7. 전달 방법을 일관성 없이 섞기. 사이트맵은 이렇게 말하고 HTML 헤드는 저렇게 말한다. 단일 진실 공급원을 하나 골라라.

⚠️ 주의: hreflang은 클러스터링과 라우팅 힌트이지 순위 부스트가 아니다. 약한 페이지를 끌어올리지 못한다. 올바르게 했을 때, 이미 순위에 오른 올바른 페이지가 각 검색자에게 보이도록 보장할 뿐이다. “트래픽이 두 배가 됐다”가 아니라 “사용자가 이제 올바른 로케일에 도착한다”를 기대하라.

언어 vs 지역 타깃팅 — 자기 자신과 경쟁하지 마라

가장 어려운 전략적 판단은 얼마나 세분화할지다. 로케일 페이지가 많다고 더 좋은 게 아니다. 유지보수를 늘리고 자기 경쟁의 위험을 키운다.

언어만으로 타깃(en, de, fr)할 때는 콘텐츠가 국가와 무관하게 그 언어의 모든 사용자에게 진정으로 동일한 경우다 — 같은 제품, 같은 가격, 같은 문구. 독일, 오스트리아, 스위스를 한 독일어 페이지로 서빙하는 것이 더 단순하고 신호를 단일 URL에 집중시킨다.

언어 + 지역으로 타깃(en-US, en-GB)할 때같은 언어시장마다 다른 콘텐츠를 필요로 하는 경우다. 가격이나 통화가 다르거나, 배송이나 재고가 다르거나, 지역별 법적 문구가 있거나, 분리할 가치가 있는 철자/관용구 차이(color/colour, fall/autumn)가 있을 때다.

위험 구역은 같은 언어, 여러 지역, 거의 동일한 콘텐츠다 — 가격 문자열만 다른 en-USen-GB 페이지. Google에는 이것들이 같은 쿼리를 두고 경쟁하는 중복처럼 보이며, 이것이 고전적인 자기 잠식 함정이다. 빠져나가는 두 가지 방법:

  • 분리를 정당화할 만큼 차별화하라 — 구별되는 가격, 현지 예시, 시장별 섹션 — 그리고 올바른 hreflang을 연결해 Google이 당신 대신 고르는 대신 지역으로 라우팅하게 하라.
  • 또는 언어만으로 통합하라(enx-default) — 시장이 정말로 다르지 않다면. 강한 페이지 하나가 약한 쌍둥이 둘을 이긴다.

💡 팁: 유용한 테스트 — 미국과 영국 방문자가 같은 페이지로 똑같이 잘 서빙된다면, 별도의 지역 페이지가 필요 없다. 경험이 진정으로 갈릴 때만 분리하라.

도구와 검증

hreflang은 규모에서 눈으로 검증하기엔 너무 오류가 잦다. 워크플로에 녹여 넣어라.

  • Google Search Console. International Targeting / Page indexing 리포트는 Google 자신의 파싱에서 직접 hreflang 오류(“no return tags”, “unknown language code”)를 드러낸다. 이것이 그라운드 트루스다 — Google이 자기가 보는 것을 알려주는 것. 모든 로케일 출시 후에 확인하라.
  • hreflang 검증기. 전용 체커(Merkle의 hreflang 태그 테스트 도구, TechnicalSEO.com, Aleyda Solis의 생성기)는 URL을 받아 상호성, 코드 유효성, 절대 URL을 검증한다. 생성기로 올바른 첫 집합을 만들고, 그다음 검증기로 라이브 페이지를 확인하라.
  • 크롤러. Screaming Frog, Sitebliss, 또는 Ahrefs의 사이트 감사는 사이트 전체를 크롤링해 누락된 반환 태그, 비-200 대체본, canonical/hreflang 충돌을 수천 개 URL에 걸쳐 한 번에 표시한다 — 대형 사이트를 감사하는 유일한 실용적 방법이다.
  • 헤더와 빠른 헤드 확인용 curl. HTTP-헤더 hreflang이나 페이지 헤드를 일회성으로 검증할 때:
# Inspect HTTP Link-header hreflang (e.g. on a PDF)
curl -sI https://example.com/en/manual.pdf | grep -i '^link:'

# Pull every hreflang link from a rendered page
curl -s https://example.com/en/product | grep -o 'hreflang="[^"]*"'

🧑‍💻 개발자 관점: CI 검사를 추가하라. 빌드된 출력을 크롤링하고, 모든 페이지의 hreflang 집합을 파싱하고, 배포 전에 상호성, 절대 URL, 자기 참조 canonical을 단언하라. 파이프라인의 30줄짜리 스크립트가 반환 태그 누락 버그를 3주 후 Search Console이 아니라 PR 시점에 잡아낸다.

🧑‍💻 이 사이트를 작업 예시로

이 사이트 자체가 이중 언어(영어와 중국어)이므로, 이 규칙들에 따라 살아간다. Astro의 i18n 지원으로 구축되었다. 각 가이드는 /en//zh/ 경로 접두사(서브디렉터리 — 위의 권장 사항) 아래 둘 다 존재하며, 각 로케일을 그 hreflang 값과 경로 접두사로 매핑하는 단일 로케일 설정으로 구동된다. 그 설정이 개발자 관점 팁에서 말한 단일 진실 공급원이다 — 언어 전환기, 라우팅, hreflang 태그가 모두 그곳에서 읽는다.

hreflang 주석은 모든 페이지 헤드에 손으로 작성되는 대신 Astro의 사이트맵 통합으로 자동 생성된다. 사이트가 빌드될 때, 통합은 로케일 설정을 순회하며 번역된 각 페이지에 대해 완전한 양방향 xhtml:link 클러스터(x-default 포함)를 내보내고 사이트맵 하나를 쓴다. 새 로케일 추가는 수백 개 파일을 훑는 일이 아니라 설정 편집이다 — 그리고 생성기가 매번 대칭 집합을 내보내므로 상호성이 구조적으로 보장된다.

이것이 프레임워크의 **레이어 7(고급 및 확장)**이 작동하는 모습이다 — 국제 SEO는 기본기가 탄탄해진 후에 덧입히는 고급 관심사다. 하지만 그것은 저 아래 **레이어 2(빌드 레이어)**에서 구현된다. i18n 라우팅과 사이트맵 생성은 나중에 볼트로 덧붙인 게 아니라 사이트의 토대에 배선되어 있다. 정적 출력과 사이트맵이 어떻게 생성되는지 그 메커니즘이 궁금하다면, Edge SEO와 빌드 레이어 가이드가 이를 자동으로 만드는 배포 및 생성 파이프라인을 다룬다.

핵심 요약

  • ✅ 기본값은 서브디렉터리(/de/, /en-gb/)로 — 권위를 통합하고, 비용이 가장 적고, 정적 생성기가 자연스럽게 만들어내는 형태다. ccTLD는 강한 지리-신뢰 요구가 있을 때를 위해 아껴두라.
  • ✅ 모든 hreflang 집합을 양방향이며 자기 참조로 만들고, 절대 URL과 **x-default**를 포함하라 — 반환 태그 하나가 깨지면 전체 클러스터가 무효가 된다.
  • ✅ 각 로케일에서 canonical을 자기 참조로 유지하라. 절대로 번역본을 기본 언어로 정규화하지 마라, 그러면 색인에서 빠진다.
  • ISO 코드를 정확히 사용하라 — 언어는 ISO 639-1, 지역은 ISO 3166-1(en-UK가 아니라 en-GB).
  • ✅ 콘텐츠가 진정으로 다를 때만 지역으로 분리하라. 그렇지 않으면 자기 잠식을 피하기 위해 언어로 타깃하라.
  • 지속적으로 검증하라 — Search Console + 크롤러 + CI 상호성 검사. hreflang은 조용히 실패하기 때문이다.