검색엔진에 당신의 사이트 구조를 제대로 알려주지 못해 페이지가 색인되지 않는 경험을 했을까? 많은 개발자들이 콘텐츠만 잘 만들면 자동으로 검색 결과에 나타날 거라고 생각한다. 하지만 구글이나 네이버는 당신의 사이트 지도를 받아야 모든 페이지를 효율적으로 크롤링할 수 있다. XML 사이트맵은 검색엔진에게 당신의 웹사이트에 어떤 페이지들이 있는지, 언제 마지막으로 수정되었는지, 얼마나 자주 업데이트되는지를 명확하게 전달하는 수단이다. 이번 글에서는 XML 사이트맵을 직접 만드는 방법부터 검색엔진에 제출하는 과정, 그리고 robots.txt와 함께 크롤링 최적화를 완성하는 방법까지 정확하게 정리하겠다.

 

XML 사이트맵이란 무엇인가

XML 사이트맵은 당신의 웹사이트에 있는 모든 페이지(또는 중요한 페이지들)를 나열하는 파일이다. 파일명은 보통 sitemap.xml이고, 웹사이트 루트 디렉토리(예: https://example.com/sitemap.xml)에 배치된다. 구글, 네이버, 빙과 같은 검색엔진은 이 파일을 읽고 당신의 사이트 구조를 파악한 후, 효율적으로 페이지를 크롤링한다. 특히 새로 추가된 페이지나 수정된 페이지를 빠르게 발견할 수 있게 도와준다. 사이트맵이 없어도 검색엔진은 내부 링크를 따라 페이지를 찾을 수 있지만, 고아 페이지(고립된 페이지)나 업데이트 빈도가 낮은 페이지는 놓칠 가능성이 높다.

 

XML 사이트맵 포맷 이해하기

XML 사이트맵은 다음과 같은 구조를 가진다. 각 페이지는 <url> 태그로 감싸지고, 페이지 주소(<loc>), 마지막 수정 날짜(<lastmod>), 업데이트 빈도(<changefreq>), 중요도(<priority>)를 담는다. priority는 상대적 중요도를 0.0~1.0 사이의 값으로 표현한다. 홈페이지는 보통 1.0, 블로그 글은 0.7~0.8, 오래된 보관함은 0.3~0.5 정도로 설정한다.

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>https://example.com/</loc>
    <lastmod>2025-01-15</lastmod>
    <changefreq>weekly</changefreq>
    <priority>1.0</priority>
  </url>
  <url>
    <loc>https://example.com/blog/article-1</loc>
    <lastmod>2025-01-14</lastmod>
    <changefreq>monthly</changefreq>
    <priority>0.8</priority>
  </url>
</urlset>

 

PHP로 동적 사이트맵 생성하기

정적 사이트라면 수동으로 sitemap.xml을 만들 수 있지만, 블로그처럼 콘텐츠가 자주 추가되는 사이트라면 자동으로 생성해야 한다. PHP로 데이터베이스의 모든 페이지를 가져와 XML 형식으로 출력하는 코드를 작성해보자.

기본 사이트맵 생성 함수

먼저 PDO를 사용해 데이터베이스에서 페이지 정보를 가져오고, 이를 XML로 변환하는 함수를 만든다.

<?php
// sitemap.php - 동적 사이트맵 생성

try {
    $pdo = new PDO('mysql:host=localhost;dbname=mysite', 'user', 'password');
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
    http_response_code(500);
    exit('Database connection failed');
}

header('Content-Type: application/xml; charset=UTF-8');
echo '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
echo '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' . "\n";

// 홈페이지 추가
echo '  <url>' . "\n";
echo '    <loc>https://example.com/</loc>' . "\n";
echo '    <lastmod>' . date('Y-m-d') . '</lastmod>' . "\n";
echo '    <changefreq>weekly</changefreq>' . "\n";
echo '    <priority>1.0</priority>' . "\n";
echo '  </url>' . "\n";

// 블로그 글 가져오기
$stmt = $pdo->query('SELECT id, slug, updated_at FROM posts WHERE status = "published" ORDER BY id DESC');

while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
    $url = 'https://example.com/blog/' . htmlspecialchars($row['slug']);
    $lastmod = date('Y-m-d', strtotime($row['updated_at']));
    
    echo '  <url>' . "\n";
    echo '    <loc>' . $url . '</loc>' . "\n";
    echo '    <lastmod>' . $lastmod . '</lastmod>' . "\n";
    echo '    <changefreq>monthly</changefreq>' . "\n";
    echo '    <priority>0.8</priority>' . "\n";
    echo '  </url>' . "\n";
}

// 정적 페이지 추가
$staticPages = [
    ['url' => 'https://example.com/about', 'priority' => '0.7'],
    ['url' => 'https://example.com/contact', 'priority' => '0.7'],
    ['url' => 'https://example.com/services', 'priority' => '0.8'],
];

foreach ($staticPages as $page) {
    echo '  <url>' . "\n";
    echo '    <loc>' . $page['url'] . '</loc>' . "\n";
    echo '    <changefreq>monthly</changefreq>' . "\n";
    echo '    <priority>' . $page['priority'] . '</priority>' . "\n";
    echo '  </url>' . "\n";
}

echo '</urlset>';
?>

위 코드를 https://example.com/sitemap.php 또는 https://example.com/sitemap.xml로 접근할 수 있도록 설정하면, 데이터베이스의 모든 게시물과 정적 페이지가 자동으로 XML 형식으로 출력된다. 중요한 점은 Content-Type 헤더를 application/xml로 설정해야 검색엔진이 올바르게 인식한다는 것이다.

사이트맵 캐싱으로 성능 최적화

데이터베이스 쿼리를 매번 실행하는 것은 비효율적이다. 사이트맵을 1시간에 한 번씩만 생성하고 캐시 파일에 저장하는 방식으로 개선하자.

<?php
// sitemap.php - 캐싱 기능 추가

$cacheFile = __DIR__ . '/cache/sitemap.xml';
$cacheExpire = 3600; // 1시간

// 캐시 파일이 존재하고 유효하면 그대로 전송
if (file_exists($cacheFile) && time() - filemtime($cacheFile) < $cacheExpire) {
    header('Content-Type: application/xml; charset=UTF-8');
    readfile($cacheFile);
    exit;
}

try {
    $pdo = new PDO('mysql:host=localhost;dbname=mysite', 'user', 'password');
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
    http_response_code(500);
    exit('Database connection failed');
}

$xml = '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
$xml .= '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' . "\n";

// 홈페이지
$xml .= '  <url><loc>https://example.com/</loc><lastmod>' . date('Y-m-d') . '</lastmod><changefreq>weekly</changefreq><priority>1.0</priority></url>' . "\n";

// 게시물
$stmt = $pdo->query('SELECT id, slug, updated_at FROM posts WHERE status = "published" ORDER BY id DESC');
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
    $url = 'https://example.com/blog/' . htmlspecialchars($row['slug']);
    $lastmod = date('Y-m-d', strtotime($row['updated_at']));
    $xml .= '  <url><loc>' . $url . '</loc><lastmod>' . $lastmod . '</lastmod><changefreq>monthly</changefreq><priority>0.8</priority></url>' . "\n";
}

$xml .= '</urlset>';

// 캐시 디렉토리가 없으면 생성
if (!is_dir(__DIR__ . '/cache')) {
    mkdir(__DIR__ . '/cache', 0755, true);
}

// XML을 캐시 파일에 저장
file_put_contents($cacheFile, $xml);

header('Content-Type: application/xml; charset=UTF-8');
echo $xml;
?>

이렇게 하면 첫 번째 요청만 데이터베이스를 조회하고, 이후 1시간 동안은 캐시 파일을 사용해 서버 부하를 줄일 수 있다.

 

robots.txt와 사이트맵 함께 구성하기

robots.txt는 검색엔진 크롤러에게 웹사이트의 어느 부분을 크롤링해도 되고, 어느 부분은 크롤링하면 안 되는지를 알려주는 파일이다. XML 사이트맵과 함께 사용하면 크롤링 효율을 극대화할 수 있다.

기본 robots.txt 설정

웹사이트 루트에 robots.txt 파일을 만들고, 사이트맵의 위치를 명시한다.

User-agent: *
Disallow: /admin/
Disallow: /private/
Disallow: /temp/
Disallow: /assets/css/
Disallow: /assets/js/

Allow: /search/

Sitemap: https://example.com/sitemap.xml
Sitemap: https://example.com/sitemap-news.xml

이 설정은 모든 검색엔진 크롤러(/admin/, /private/, /temp/ 디렉토리 접근 차단)가 관리 페이지에 접근하지 못하도록 하면서, 당신의 XML 사이트맵 위치를 명확하게 알려준다. 여러 개의 사이트맵(예: 뉴스 사이트맵, 이미지 사이트맵)을 여러 줄로 나열할 수 있다.

특정 크롤러만 차단하기

특정 검색엔진의 크롤러만 차단하거나, 크롤링 속도를 제한할 수도 있다.

# 모든 크롤러 기본 규칙
User-agent: *
Disallow: /admin/
Allow: /shop/
Sitemap: https://example.com/sitemap.xml

# 구글만 특정 처리
User-agent: Googlebot
Disallow: /temp/
Crawl-delay: 2

# 특정 크롤러 차단
User-agent: AhrefsBot
User-agent: SemrushBot
Disallow: /

# 다른 모든 크롤러
User-agent: *
Crawl-delay: 5

Crawl-delay는 크롤러가 페이지를 크롤링할 때 요청 간 대기 시간(초 단위)을 지정한다. AhrefsBot이나 SemrushBot 같은 공격적인 크롤러는 차단하고, 검색엔진의 크롤러는 허용하는 방식이다.

 

Google Search Console과 Naver Search Advisor에 등록하기

사이트맵을 만들었다면 검색엔진에 등록해야 한다. 검색엔진이 당신의 사이트맵을 자동으로 발견할 수도 있지만, 명시적으로 등록하는 것이 더 빠르다.

Google Search Console 등록

Google Search Console(https://search.google.com/search-console)에 접속해 당신의 사이트를 인증한 후, 좌측 메뉴의 '색인'에서 '사이트맵'을 선택한다. 사이트맵 URL(예: https://example.com/sitemap.xml)을 입력하고 '제출'을 클릭하면 완료다. 며칠 후 Search Console에서 색인 상태 보고서를 확인할 수 있다.

Naver Search Advisor 등록

Naver Search Advisor(https://webmaster.naver.com)에 로그인해 사이트를 등록한 후, '관리'에서 '요청'을 선택한다. '사이트맵 제출'을 클릭하고 사이트맵 URL을 입력한 후 '제출'을 클릭한다. Naver는 구글보다 느린 속도로 크롤링하지만, 한국의 주요 검색엔진이므로 반드시 등록해야 한다.

 

흔한 실수와 주의사항

✗ 잘못된 것: 사이트맵에 모든 URL을 포함시키기 (50,000개 초과)
✓ 올바른 것: 사이트맵은 최대 50,000개의 URL을 포함할 수 있으므로, 페이지가 더 많다면 여러 개의 사이트맵을 만들고 sitemap_index.xml에서 참조해야 한다.

<?xml version="1.0" encoding="UTF-8"?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <sitemap>
    <loc>https://example.com/sitemap-1.xml</loc>
  </sitemap>
  <sitemap>
    <loc>https://example.com/sitemap-2.xml</loc>
  </sitemap>
</sitemapindex>

✗ 잘못된 것: robots.txt에서 사이트맵을 Disallow하기
✓ 올바른 것: robots.txt 파일 자체는 Disallow되면 안 되며, /sitemap.xml도 검색엔진이 자유롭게 접근할 수 있어야 한다.

✗ 잘못된 것: 존재하지 않는 URL을 사이트맵에 포함시키기
✓ 올바른 것: 정기적으로 사이트맵에 있는 URL을 확인하고, 삭제된 페이지는 사이트맵에서도 제거해야 한다. 그렇지 않으면 검색엔진이 404 에러를 계속 만나게 되어 색인 효율이 떨어진다.

✗ 잘못된 것: lastmod 날짜를 임의로 설정하기
✓ 올바른 것: lastmod는 실제 페이지 수정 날짜를 정확하게 입력해야 한다. 검색엔진은 이 정보를 바탕으로 크롤링 우선순위를 결정한다.

 

사이트맵 검증 및 모니터링

사이트맵을 제출한 후에도 주기적으로 검증해야 한다. Google Search Console에서 '색인' > '사이트맵' 메뉴로 가면 제출된 사이트맵의 상태를 확인할 수 있다. 색인된 페이지 수, 오류 페이지, 경고 등이 표시된다. 만약 색인 오류가 발생했다면, 해당 URL에 접근할 수 있는지, HTTP 상태 코드가 올바른지 확인해야 한다.

또한 온라인 사이트맵 검증 도구(예: https://www.xml-sitemaps.com/validate-xml-sitemap.html)를 이용해 XML 형식이 올바른지 확인할 수 있다.

 

마무리

XML 사이트맵은 단순한 파일이지만, 검색엔진이 당신의 사이트를 빠르고 완전하게 이해하도록 돕는 핵심 도구다. robots.txt와 함께 제대로 설정하면 크롤링 예산을 효율적으로 사용할 수 있고, 새 페이지가 더 빨리 색인된다. 이 글에서 제시한 PHP 코드를 참고해 동적으로 사이트맵을 생성하고, Google Search Console과 Naver Search Advisor에 제출하면, 당신의 웹사이트가 검색 결과에 더 자주, 더 높게 나타날 것이다. 매월 한 번씩 사이트맵 상태를 모니터링하는 작은 습관이 모여 검색 순위 개선으로 이어진다는 점을 잊지 말자.