웹사이트를 운영하면서 구글 검색 결과를 확인해본 적이 있을까? 그런데 같은 페이지인데도 URL이 두 가지 형태로 표시되거나, 웹에서 사용하는 URL과 검색 결과에 나오는 URL이 다른 경험을 했다면 이 글이 정확히 당신의 문제를 풀어줄 것이다. 대부분의 개발자와 사이트 운영자는 URL 정규화와 표준 URL 설정의 중요성을 간과하고, 결과적으로 검색 색인 중복, 페이지 권위성 분산, SEO 순위 하락이라는 악순환에 빠진다. 이번에는 URL이 정확히 어떻게 마크업되는지, 왜 중복이 발생하는지, 그리고 canonical 태그와 301 리다이렉트로 완벽하게 통제하는 방법까지 실무 레벨에서 정리해보겠다.

 

1단계. URL 정규화가 왜 필요한가

같은 콘텐츠에 접근하는 URL이 여러 개라면 검색엔진은 어떤 URL을 대표로 색인할지 판단해야 한다. 예를 들어 다음 네 가지 URL이 모두 같은 페이지를 보여준다면 어떻게 될까.

https://example.com/blog/article
https://example.com/blog/article/
https://www.example.com/blog/article
https://example.com/blog/article?utm_source=google

구글 크롤러는 이들을 모두 별개의 페이지로 인식하고 각각을 색인한다. 결국 같은 콘텐츠가 여러 URL에 흩어지면서 검색 순위에 필요한 백링크 수, 페이지 조회수, 사용자 신호 등이 분산된다. 이것이 URL 정규화가 필수적인 이유다. 대표 URL을 명시하고 나머지는 그곳으로 유도해야 한다.

 

2단계. URL 정규화 방법 3가지
방법 1. Canonical 태그 (권장)

canonical 태그는 HTML 헤드 섹션에 추가하는 가장 간단한 방법이다. 페이지에서 어떤 URL이 대표 버전인지 검색엔진에 명시적으로 알린다.

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>My Article</title>
  <link rel="canonical" href="https://example.com/blog/article">
</head>
<body>
  <h1>Article Title</h1>
</body>
</html>

✓ 올바른 방법. canonical 링크는 항상 절대 주소(전체 도메인 포함)를 사용하고, 같은 페이지 내에 정확히 하나만 있어야 한다. 추적 매개변수(utm_source, fbclid 등)가 있는 경우는 그것을 제거한 깔끔한 URL을 지정한다.

방법 2. 301 리다이렉트

서버 수준에서 영구적으로 한 URL을 다른 URL로 이동시킨다. 가장 강력한 방법이고, 검색엔진은 301 응답을 받으면 해당 URL의 SEO 점수를 새 URL로 완전히 이전한다.

<?php
// .htaccess (Apache)
// RewriteEngine On
// RewriteCond %{HTTP_HOST} !^www\. [NC]
// RewriteRule ^(.*)$ https://www.example.com/$1 [L,R=301]

// PHP 코드
if ($_SERVER['HTTP_HOST'] !== 'www.example.com') {
    header('HTTP/1.1 301 Moved Permanently');
    header('Location: https://www.example.com' . $_SERVER['REQUEST_URI']);
    exit;
}

// 또는 Nginx
// if ($host != 'www.example.com') {
//     rewrite ^(.*)$ https://www.example.com$1 permanent;
// }

✓ www 있고 없고의 일관성을 유지하는 데 특히 효과적이다. Search Console에서도 선호하는 도메인을 설정할 수 있으니 함께 사용하면 더 좋다.

방법 3. robots.txt와 X-Robots-Tag 헤더

URL을 완전히 다른 페이지가 아니라, 특정 매개변수를 무시하도록 지시할 수 있다. 특히 세션 ID나 추적 매개변수가 있을 때 유용하다.

User-agent: *
Disallow: /
Allow: /blog/
Allow: /about/

# 매개변수 처리 (Google Search Console)
Clean-param: utm_source&utm_medium&fbclid

✓ 이 방식은 Google Search Console에서 매개변수 처리를 통해서만 적용된다. robots.txt의 Clean-param은 구글 크롤러에게만 적용되므로, 모든 검색엔진을 대상으로는 canonical 태그가 낫다.

 

3단계. 실전 예제: 전자상거래 사이트 상품 페이지

실제 상황을 생각해보자. 상품 페이지는 정렬, 필터, 페이지 번호 매개변수가 붙는다.

<?php
// product.php
$product_id = $_GET['id'] ?? null;
$sort = $_GET['sort'] ?? 'default';
$page = $_GET['page'] ?? 1;

// 정규화된 대표 URL 생성
$canonical_url = 'https://example.com/product?id=' . urlencode($product_id);

// 다른 모든 매개변수는 무시
?>
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title><?php echo htmlspecialchars($product['name']); ?></title>
  <!-- id만 포함된 깔끔한 URL을 대표로 -->
  <link rel="canonical" href="<?php echo $canonical_url; ?>">
</head>
<body>
  <h1><?php echo htmlspecialchars($product['name']); ?></h1>
  <!-- 상품 정보 -->
</body>
</html>

✗ 잘못된 방법. canonical 태그 없이 매개변수가 붙은 여러 URL을 모두 색인하게 하면, 검색 결과에 sort=popularity&page=2 같은 URL까지 노출된다.

<?php
// product.php (올바른 버전)
$product_id = (int)$_GET['id'];
$sort = $_GET['sort'] ?? 'default';
$page = (int)($_GET['page'] ?? 1);

// 제품 데이터 조회
$product = fetchProduct($product_id);

// 정렬·페이지는 무시하고 ID만으로 canonical 생성
$canonical = "https://example.com/product?id={$product_id}";
?>
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="description" content="<?php echo htmlspecialchars($product['desc']); ?>">
  <link rel="canonical" href="<?php echo $canonical; ?>">
  <title><?php echo htmlspecialchars($product['name']); ?></title>
</head>
<body>
  <h1><?php echo htmlspecialchars($product['name']); ?></h1>
  <!-- 상품 상세 -->
</body>
</html>

✓ 올바른 방법. canonical 태그에는 id만 포함되고, 페이지 내에서는 sort·page 매개변수로 동적으로 필터링해서 보여준다. 검색 결과에는 깔끔한 product?id=123 만 노출되지만, 사용자는 여전히 원하는 정렬·페이지를 볼 수 있다.

 

4단계. 주의사항과 흔한 실수
실수 문제점 올바른 방법
Canonical에 상대 주소 사용 검색엔진이 해석하지 못함 <link rel="canonical" href="https://example.com/page">
한 페이지에 여러 canonical 모두 무시됨 항상 정확히 하나만 사용
다른 사이트 URL로 canonical 권위성 분산, 검색엔진이 스팸 의심 같은 도메인 내 URL만 지정
301 리다이렉트 + Canonical 동시 사용 혼란스러운 신호 전달 리다이렉트로 충분하면 canonical 생략
www 일관성 없음 (mix.com + www.mix.com) 색인 중복, 순위 분산 301 리다이렉트로 하나로 통일 + Search Console 설정
HTTPS와 HTTP 혼용 보안 문제 + 색인 중복 모든 HTTP를 HTTPS로 301 리다이렉트

 

5단계. Search Console에서 확인하기

Google Search Console에 접속해서 '설정 > 기본 도메인'에서 선호 도메인을 명시할 수 있다. 이것만으로도 www/non-www 혼동을 줄일 수 있다. 그리고 '검사' 탭에서 특정 URL을 입력하면 검색엔진이 인식한 대표 URL(canonical)이 뭔지 확인할 수 있다.

검사 결과:
입력 URL: https://example.com/blog/article?utm_source=google
검색엔진이 인식한 URL: https://example.com/blog/article
Canonical: https://example.com/blog/article
상태: 색인됨

이렇게 나오면 정상이다. 만약 canonical이 다르게 표시되거나 대표 URL이 예상과 다르면, PHP 코드의 canonical 태그를 다시 확인해야 한다.

 

마무리

URL 정규화는 SEO의 기초다. 같은 콘텐츠가 여러 URL로 흩어지면 아무리 좋은 콘텐츠도 검색 순위에서 밀린다. Canonical 태그 하나, 또는 301 리다이렉트 하나가 모여서 결국 검색 순위와 트래픽 안정성을 결정한다. 이 글의 3단계 실전 예제를 참고해 당신의 사이트에 canonical 태그를 추가하고, Search Console에서 확인해보자. 중복 URL이 정리되는 순간 검색 순위가 서서히 올라갈 것이다.