AI 검색최적화 robots.txt, 이렇게 수정했습니다 — 그리고 댓글 하나로 다시 뒤집혔습니다

제주에서 스쿠버다이빙 체험과 자격증 교육을 운영하는 지인의 홈페이지를 제가 직접 구축했습니다. Astro로 만들었고 한국어·영어·일본어·중국어 4개 언어를 운영합니다.

목표는 처음부터 명확했습니다. 광고비를 쓰는 대신 AI가 먼저 추천하는 홈페이지를 만드는 것. 요즘 손님들은 네이버보다 ChatGPT에 먼저 물어봅니다. "제주 스쿠버다이빙 어디가 좋아?"라는 질문에 지인의 상호가 나오게 하는 게 설계 목표였습니다.

그런데 아무리 좋은 콘텐츠를 써도 크롤러가 못 들어오면 전부 무효입니다.

그 허가증이 robots.txt입니다. 이미 한 번 작성해서 올려둔 상태였지만 이게 최적인지 확신이 없어서, Claude에 검증을 맡겼습니다.

그리고 이 글을 처음 올린 뒤, 댓글 하나 때문에 확정했던 파일을 40줄에서 3줄로 다시 줄였습니다. 그 과정까지 전부 담았습니다.

WHY — 왜 robots.txt부터인가

순서상 0순위다. 스키마 마크업이든 FAQ 구조든 콘텐츠든, 크롤이 막혀 있으면 전부 0점이 됩니다.

비용이 0원이다. 30분이면 끝나고 개발 리소스도 안 듭니다. 가성비로 따지면 GEO 항목 중 압도적 1위입니다.

실수했을 때 피해가 크다. 슬래시 하나 잘못 넣으면 사이트 전체가 검색에서 사라질 수 있는 파일입니다.

WHO — 누구를 위한 설정인가

첫 번째 깨달음이 여기서 나왔습니다. "AI 크롤러"는 하나가 아니라 목적이 전혀 다른 세 가족입니다.

구분

하는 일

대표 봇

막으면

AI 검색(리트리벌)

AI 답변용 인덱스 구축

OAI-SearchBot, Claude-SearchBot, PerplexityBot

인용에서 완전 제외

실시간 요청

사용자가 묻는 순간 페이지를 직접 가져옴

ChatGPT-User, Claude-User, Perplexity-User

실시간 조회·요약 불가

학습(training)

모델 훈련 데이터 수집

GPTBot, ClaudeBot, CCBot

학습 데이터에서 제외

이름이 함정입니다. GPTBot(학습)과 OAI-SearchBot(검색)은 완전히 다른 봇이고, ClaudeBotClaude-SearchBot도 마찬가지입니다. 이름만 보고 뭉뚱그려 막으면 학습만 거부하려다 인용까지 같이 끊깁니다.

WHAT — 무엇을 허용하기로 했나

전부 허용으로 결정했습니다. 근거는 업종 특성이었습니다.

  • 다이빙샵 홈페이지의 코스·요금·시즌 정보는 지켜야 할 자산이 아니라 알려야 할 정보입니다

  • 학습봇 허용은 장기 브랜드 각인입니다. 모델이 "제주 스쿠버다이빙" 하면 상호를 떠올리게 되려면 학습 데이터에 들어가야 합니다

  • 로컬 비즈니스는 잃을 게 없습니다. 인용 1건이 예약 1건이 되는 구조입니다

미디어나 유료 교육 사업이었다면 반대로 판단했을 겁니다. "학습은 거부, AI 검색 인용은 유지"라는 절충안도 실제로 가능합니다.

WHEN — 언제 했고 지금 상태는

7월 10일 구글 서치콘솔 등록, 8월 5일에 "지금 세팅이 최적인가"를 점검한 게 이번 작업이었습니다.

WHERE — 어디에 두는가

Astro는 public/robots.txt에 정적 파일로 둡니다. 빌드하면 그대로 루트로 복사됩니다.

HOW — 어떻게 검증했나

라운드 1 — Claude(웹)에서 현재 파일 분석 요청

기존 robots.txt 전문을 그대로 붙여넣고 물었습니다.

아래 robots.txt를 분석해줘. 더 개선해야 하는 거 없어?

# jejuscubadiving.com — AI 검색 가시성 확보 정책
# 리트리벌·검색 봇: 전면 허용 (AI 답변 인용 = 예약 유입 경로)

User-agent: OAI-SearchBot
Allow: /

User-agent: ChatGPT-User
Allow: /

User-agent: Claude-SearchBot
Allow: /

... (봇별로 개별 그룹 10개) ...

User-agent: *
Allow: /

Sitemap: https://jejuscubadiving.com/sitemap-index.xml

가장 뼈아팠던 지적은 이거였습니다.

"robots.txt는 그룹을 상속하지 않습니다."

크롤러는 자기 이름이 적힌 그룹 하나만 읽고 나머지는 전부 무시합니다. 지금은 User-agent: *가 전체 허용이라 문제가 안 보이지만, 나중에 특정 경로를 막겠다고 * 그룹에 Disallow를 추가하면 개별 그룹이 있는 AI 봇 10종은 그 규칙을 전혀 적용받지 않습니다.

이 지적은 나중에 아주 중요한 복선이 됩니다. 일단 넘어가겠습니다.

또 하나. 국내 크롤러가 통째로 빠져 있었습니다. 네이버는 Yeti, 다음은 Daumoa입니다. 제주 로컬 비즈니스인데 이걸 명시하지 않은 건 명백한 누락이었습니다.

라운드 2 — 프레임워크를 밝히자 답이 뒤집혔습니다

라운드 1의 개선안에는 /wp-admin/, admin-ajax.php, /?s= 같은 경로가 잔뜩 들어 있었습니다. 전부 WordPress 전제였습니다. 그래서 정정했습니다.

이 사이트는 Astro 프레임워크로 제작되었어.
https://jejuscubadiving.com/sitemap-index.xml 은 맞아

답이 상당 부분 뒤집혔습니다.

  • 제외할 게 거의 없다. Astro는 정적 빌드라 /wp-admin/ 같은 경로가 존재하지 않습니다

  • /_astro/는 절대 막으면 안 된다. 번들된 CSS/JS가 여기 있어서 차단하면 렌더링 평가에서 손해를 봅니다

  • sitemap-index.xml은 정확하다. @astrojs/sitemap의 기본 출력물이 이 이름입니다

  • Astro는 오히려 GEO에 유리하다. AI 크롤러 대부분은 JavaScript를 실행하지 않는데, Astro는 빌드 시점에 완성된 HTML을 내보내므로 크롤러가 본문 전체를 그대로 받습니다

교훈: 환경 정보를 먼저 주지 않으면 AI는 가장 흔한 케이스(WordPress)를 가정합니다. 이건 AI 잘못이 아니라 제 정보 제공 부족이었습니다.

라운드 3 — 코드베이스로 교차검증

채팅으로 받은 진단을 그대로 실행하지 않고, 코드베이스 전체에 접근할 수 있는 Claude Code에 그 진단을 통째로 넣어 검증시켰습니다.

결과적으로 몇 가지 지적이 걸러졌습니다. 채팅 쪽은 제가 붙여넣은 파일만 보고 판단할 수밖에 없는데, 실제 코드에는 이미 해결된 부분이 있었던 겁니다. 파일 조각만 보고 내린 진단과, 렌더링된 결과물과 소스를 다 본 진단은 다릅니다.

robots.txt 관련 지적은 이 검증을 통과했습니다. 그래서 확정했습니다.

1차 확정본 (40줄)

# jejuscubadiving.com · AI 검색 가시성 확보 정책
# Astro 정적 빌드 / 최종 수정: 2026-08-06
# 정책: 로컬 비즈니스 = 인용 1건이 예약 1건. 검색·실시간·학습 전면 허용.
#
# 주의 1: /_astro/ 는 CSS·JS 번들 경로이므로 절대 차단하지 말 것.
#
# 주의 2: 크롤러는 "가장 구체적으로 일치하는 그룹 하나"만 적용하고 나머지는 무시한다.
#   아래에 이름이 적힌 봇은 User-agent: * 그룹을 절대 읽지 않는다.
#   따라서 나중에 무언가를 차단해야 하면 * 에만 넣어서는 안 되고,
#   차단이 필요한 모든 그룹에 같은 Disallow 를 반복해서 넣어야 한다.
#
# 주의 3: noindex 페이지(/404/, /*/thanks/, /authors/)를 여기서 Disallow 하지 말 것.
#   크롤을 막으면 구글이 noindex 메타를 읽지 못해 URL만 검색결과에 남는다.

# ===== AI 검색·리트리벌 =====
User-agent: OAI-SearchBot
User-agent: ChatGPT-User
User-agent: Claude-SearchBot
User-agent: Claude-User
User-agent: PerplexityBot
User-agent: Perplexity-User
User-agent: DuckAssistBot
Allow: /

# ===== AI 학습 =====
User-agent: GPTBot
User-agent: ClaudeBot
User-agent: CCBot
User-agent: Google-Extended
User-agent: Applebot-Extended
User-agent: meta-externalagent
Allow: /

# ===== 일반 검색엔진 (국내 포털 포함) =====
User-agent: Googlebot
User-agent: Bingbot
User-agent: Applebot
User-agent: Yeti
User-agent: Daumoa
Allow: /

# ===== 기본: 전체 허용 =====
User-agent: *
Disallow:

Sitemap: https://jejuscubadiving.com/sitemap-index.xml

여기까지가 처음 이 글을 올렸을 때의 결론이었습니다.

라운드 4 — 댓글 하나가 전제를 흔들었습니다

글을 올리고 체크님이 댓글을 남겨주셨습니다.

"저는 robots.txt에 개별 에이전트에 대한 룰을 따로 적용하지는 않고, 전체허용(User-agent: *, Allow: /)과 명시적인 disallow를 중심으로 간단히 만드는 편인데, 에이전트들을 따로 나열하는 게 좋을지에 대한 의견도 궁금합니다."

읽는 순간 답이 막혔습니다. "왜 나열해야 하는가"에 제대로 답할 수가 없었습니다.

그래서 이 댓글을 그대로 Claude에 물어봤습니다.

robots.txt 사례게시글 댓글에 이런 질문이 있어. 어떻게 답변해줘야 할까?

[체크님 댓글 전문]

돌아온 첫 문장이 이랬습니다.

"댓글 쓰신 분 방식이 기술적으로는 더 낫습니다."

지적 ① — 기능적 이득이 0이다

전부 허용이 목적이라면 User-agent: * 하나로 이미 끝입니다. 개별로 열 번 적어도 열리는 문은 똑같습니다. 위의 세 그룹을 통째로 지워도 크롤러가 보는 결과는 100% 동일합니다.

지적 ② — 오히려 위험을 만들었다

제가 쓴 주석 2번을 다시 보세요.

"나중에 무언가를 차단해야 하면 * 에만 넣어서는 안 되고, 차단이 필요한 모든 그룹에 같은 Disallow 를 반복해서 넣어야 한다."

이 경고문이 필요한 상황 자체를 제가 만들었습니다. 개별 그룹이 없으면 이 함정도 없습니다. 위험을 만들어놓고 그 위험을 설명하는 주석을 정성껏 붙인 셈입니다.

체크님 방식은 애초에 이 함정에 안 걸립니다.

지적 ③ — 개별 나열이 필요한 경우는 하나뿐이다

봇마다 정책이 다를 때. 이게 유일한 진짜 이유입니다.

# 학습 거부
User-agent: GPTBot
Disallow: /

# 검색·인용은 허용
User-agent: OAI-SearchBot
Allow: /

이런 차등 정책은 * 하나로 표현이 안 됩니다. 하지만 저는 전 그룹 정책이 동일했습니다. 나눌 이유가 없었습니다.

지적 ④ — 제가 원했던 건 주석 한 줄이면 됐다

제가 나열한 진짜 이유는 "AI 봇 정책을 검토했다"는 기록을 남기고 싶어서였습니다. 클라이언트 사이트라 나중에 다른 사람이 열었을 때 "방치된 설정"이 아니라 "검토된 정책"으로 읽히길 바랐습니다.

그런데 그건 주석 한 줄이면 됩니다. 봇 이름 25개를 나열할 필요가 없었습니다.

라운드 5 — 그럼 봇 공격은?

여기서 제가 반문했습니다. "User-agent: * 하나면 이상한 봇이나 크롤러 공격에 취약하지 않나?"

답이 명확했습니다.

"* 때문에 취약해지는 게 아닙니다. robots.txt로는 애초에 아무것도 막을 수 없습니다."

robots.txt는 부탁이지 차단이 아닙니다. 서버가 검사하는 게 아니라 크롤러가 자발적으로 읽고 지켜주는 신사협정입니다.

Disallow: /

Allow: /

착한 봇 (구글·OpenAI·Anthropic)

안 옵니다

옵니다

나쁜 봇 (스크래퍼·취약점 스캐너)

그냥 옵니다

그냥 옵니다

나쁜 봇 입장에서는 두 경우가 완전히 동일합니다.

오히려 Disallow: /admin/ 같은 줄은 보안에 도움이 되기는커녕 공격자에게 관리자 경로를 알려주는 공개 문서가 됩니다. robots.txt는 누구나 열어볼 수 있으니까요.

진짜 방어선은 다른 층에 있습니다.

  • CDN/WAF — Cloudflare 봇 차단. 가장 실효성 높음

  • Rate limiting — IP·User-Agent별 요청 속도 제한

  • 인증 — 민감한 경로는 로그인 뒤로. 유일하게 확실한 방법

  • noindex 메타태그 — 색인만 막고 싶을 때

그리고 이 사이트는 Astro 정적 빌드라 애초에 공격 표면이 없습니다. 관리자 페이지도, DB도, 로그인도 없습니다. 빌드된 HTML만 서빙합니다. 걱정할 건 침입이 아니라 트래픽 비용이고, 그건 Cloudflare 무료 플랜으로 충분합니다.

최종 확정본 (3줄)

# jejuscubadiving.com · robots.txt
# 최종 검토: 2026-08-06 / Astro 정적 빌드 (public/robots.txt 가 단일 소스)
#
# 정책: 로컬 비즈니스 = 인용 1건이 예약 1건.
#       AI 검색·실시간 요청·학습 크롤러 전부 허용으로 검토 완료.
#       (GPTBot, ClaudeBot, OAI-SearchBot, PerplexityBot, Yeti, Daumoa 등
#        개별 확인. 전 그룹 정책이 동일하므로 * 하나로 통합 관리한다.)
#
# 주의 1: /_astro/ 는 CSS·JS 번들 경로다. 절대 차단하지 말 것.
#
# 주의 2: noindex 페이지(/404/, /*/thanks/, /authors/)를 Disallow 하지 말 것.
#         크롤을 막으면 구글이 noindex 메타를 못 읽어 URL만 검색결과에 남는다.
#         robots meta + sitemap 제외로 이미 처리돼 있다.
#
# 주의 3: 봇별로 정책을 다르게 가져갈 일이 생기면(예: 학습 거부 + 검색 허용)
#         그때 그룹을 분리한다. 단, 분리하면 개별 그룹은 * 를 읽지 않으므로
#         Disallow 를 모든 그룹에 반복해야 한다.

User-agent: *
Disallow:

Sitemap: https://jejuscubadiving.com/sitemap-index.xml

40줄 → 3줄. 검토 이력은 주석에 남고, 그룹 상속 함정은 사라지고, 크롤러가 보는 결과는 이전과 100% 동일합니다.

주석 세 개는 살렸습니다. /_astro/ 차단 금지는 Astro 고유 함정이고, noindex 경고는 실무에서 가장 흔한 실수이고, 세 번째는 나중에 그룹을 나눌 때를 위한 안전장치입니다. 나열은 버리고 지식은 남긴 셈입니다.

결과와 배운 점

배운 점 & 꿀팁

1. AI에게 물을 때 환경 정보를 먼저 주세요. "Astro입니다" 한 줄을 라운드 2에서야 말했더니 답이 절반쯤 뒤집혔습니다. 프레임워크, 호스팅, CMS, 언어 구성. 이 네 가지를 첫 질문에 넣으세요.

2. 파일 조각만 보여주면 진단도 조각납니다. 채팅에 파일 하나를 붙여넣으면 AI는 그 파일만 보고 판단합니다. 코드베이스 전체를 볼 수 있는 도구로 한 번 더 검증하세요.

3. 기존 구조를 개선할 때 "이 구조가 필요한가"를 먼저 물으세요. 이게 이번 최대 교훈입니다. 저도 Claude도 처음부터 "개별 나열 구조를 어떻게 개선할까"만 생각했습니다. 봇을 추가하고, 그룹을 통합하고, 주석을 다듬었습니다. 그런데 그 구조 자체가 필요 없었습니다. 물음이 잘못되면 답이 아무리 정교해도 소용없습니다.

4. robots.txt는 보안 수단이 아닙니다. 차단은 WAF와 인증의 몫입니다. Disallow는 착한 봇에게만 통하고, 나쁜 봇에게는 오히려 지도를 그려줍니다.

5. 국내 크롤러를 잊지 마세요. GEO 자료가 대부분 해외 기준이라 Yeti, Daumoa가 빠지기 쉽습니다. 전부 허용이면 *로 커버되지만, 정책을 나눌 때는 반드시 명시해야 합니다.

6. 실시간 요청 봇을 챙기세요. ChatGPT-User, Claude-User, Perplexity-User. 손님이 우리 링크를 AI에 직접 던지는 순간 = 구매 직전입니다.

7. 커뮤니티에 공개하는 것 자체가 검증 단계입니다. Claude 3라운드, Claude Code 교차검증까지 거쳐 "확정"이라고 올린 파일이 댓글 한 줄에 무너졌습니다. AI를 몇 번 돌려도 안 나오던 질문이 사람 한 명에게서 나왔습니다. 체크님께 감사드립니다.

시행착오

  • 첫 질문에 환경 정보를 안 넣어서 WordPress 기준 답변을 받고 라운드 하나를 날렸습니다

  • 불필요한 구조를 정성껏 최적화했습니다. 봇 25개를 분류하고 주석까지 달았는데, 그 구조 자체가 필요 없었습니다

  • 제가 만든 위험을 설명하는 주석을 붙였습니다. 주석 2번이 그것입니다. 경고문이 필요하다는 건 설계가 잘못됐다는 신호였는데 못 알아챘습니다

  • robots.txt로 봇 공격을 막을 수 있다고 막연히 생각했습니다. 그런 기능은 원래 없습니다

도움이 필요한 부분

  • AI 인용 여부 자체를 추적하는 방법이 고민입니다. 클릭이 없어도 답변에 언급되면 브랜드 효과가 있는데 GA로는 안 잡힙니다. 다른 분들은 어떻게 추적하시나요?

  • 학습봇 허용 여부를 어떻게 판단하셨는지 의견 듣고 싶습니다. 저는 노출 우선으로 전부 허용했는데 반대 관점도 궁금합니다

앞으로의 계획

  1. 코스 페이지 구조화 데이터 — 가격·소요시간·최소 연령·포함 내역. AI가 "제주 체험다이빙 얼마야?"에 답할 때 인용할 건더기가 여기서 나옵니다. robots.txt보다 이게 훨씬 중요합니다

  2. 코스 페이지 lastmod 추가 — 단, 빌드 날짜를 자동으로 찍으면 안 됩니다. 매 배포마다 오늘 날짜가 들어가면 구글이 이 사이트의 lastmod 전체를 불신합니다. 실제로 바뀔 때만 사람이 갱신하는 별도 필드로 분리

  3. hreflang 상호 참조 검증 — 각 언어 버전이 서로를 정확히 가리키는지

  4. 월 1회 인용 모니터링 — 한/영/일/중 질문 세트를 매달 동일하게 던져 상호 노출 여부 기록

robots.txt는 30분이면 끝나고 0원인데, 안 하면 그 뒤의 모든 작업이 0점이 되는 파일입니다. 그런데 정작 대부분의 사이트가 한 번도 안 열어봅니다.

그리고 이번에 배운 건, 잘 만드는 것보다 "이게 필요한가"를 먼저 묻는 게 중요하다는 겁니다. 저는 40줄을 정성껏 만들고 나서야 3줄이면 됐다는 걸 알았습니다.

혹시 아직 확인 안 해보셨다면, 지금 새 탭 열고 본인도메인.com/robots.txt 한 번만 확인해 보세요. 30초면 됩니다 🙌

퍼널해커 장원근

4
5개의 답글
밀어주고 끌어주는

온·오프라인 AI 스터디

AI로 어디까지 할 수 있는지
직접 확인하실 분만 신청하세요.