404 페이지 만드는 기준 · 방문자를 어디로 보내나
404 페이지는 사과문을 붙이는 자리가 아니라 방문자를 다음 행동으로 보내는 자리다. 그리고 없어진 페이지를 전부 404로 두면 안 된다. 301로 보낼 것과 404로 둘 것을 가르는 기준, 그리고 soft 404가 만드는 문제까지 정리했다.
404는 요청한 URL에 해당하는 페이지가 서버에 없다는 뜻의 HTTP 상태 코드이고, 페이지가 정말로 사라졌다면 404를 반환하는 것이 맞는 처리다. 사이트에 404가 존재한다는 사실 자체는 검색 순위를 떨어뜨리는 문제가 아니다. 실제로 결정해야 할 것은 "404를 없앨까"가 아니라 "삭제한 그 페이지에 검색 유입이나 외부 링크가 있었나"다. 있었다면 내용이 가장 가까운 페이지로 301 리다이렉트하고, 없었다면 그냥 404로 두면 된다. 삭제한 페이지를 전부 홈으로 리다이렉트하는 처리는 두 경우 모두에서 틀린 답이다.
404는 오류가 아니라 답변이다
이름에 "오류"가 붙어 있어서 오해가 생긴다. 404는 서버가 고장 났다는 신호가 아니라, "그 주소에는 아무것도 없다"는 정확한 답변이다. 없는 페이지를 없다고 말하는 것은 서버가 할 수 있는 가장 정직한 응답이다.
검색엔진 입장에서도 같다. 크롤러가 404를 받으면 그 URL은 색인에서 빠지는 방향으로 정리된다. 언제 빠지는지, 다시 얼마나 자주 찾아오는지는 검색엔진이 정하는 일이라 예고된 일정이 없다. 다만 이것이 처벌이 아니라 정리라는 점은 분명하다. 사이트에서 지운 페이지가 검색 결과에 계속 남아 있는 쪽이 오히려 문제다.
그래서 "Search Console에 404가 30개 잡혔다"는 그 자체로는 아무 정보도 아니다. 그 30개가 어떤 URL인지 열어봐야 판단이 시작된다.
404가 많으면 순위가 떨어지나
개수만 놓고 걱정할 일은 아니다. 404가 몇 개인지를 순위 하락의 원인으로 볼 근거는 없고, 검색엔진이 그런 감점을 공지한 적도 없다. 오래 운영한 사이트라면 404는 자연스럽게 쌓인다. 남이 오타로 링크를 걸어도 404가 생기고, 스팸 봇이 없는 주소를 긁어도 404가 생긴다. 그건 내 사이트의 상태가 아니라 외부 세계의 상태다.
단, 404가 성과에 영향을 주는 경로가 하나 있다. 지금도 트래픽이 들어오던 페이지를 예고 없이 404로 만들었을 때다. 이때 잃는 것은 "404가 생겨서"가 아니라 "그 페이지가 받던 검색 유입과 링크가 갈 곳을 잃어서"다. 원인을 정확히 짚어야 처방이 맞는다.
이 구분이 중요한 이유는 처방이 정반대이기 때문이다. 전자는 아무것도 안 해도 되고, 후자는 리다이렉트가 필요하다. 404 목록을 통째로 "고쳐야 할 것"으로 보면 후자를 놓치고 전자에 시간을 쓴다.
삭제 여부를 가르는 질문 두 개
페이지를 지웠거나 지우려 할 때, 판단은 두 질문으로 끝난다.
첫째, 최근 몇 달 동안 그 URL로 검색 유입이 있었나. Search Console 실적 보고서에서 페이지별로 확인할 수 있다.
둘째, 다른 사이트에서 그 URL로 링크를 걸어둔 곳이 있나. Search Console 링크 보고서의 외부 링크 항목에서 확인한다.
둘 다 아니오면 404로 둔다. 하나라도 예면 대체 페이지를 찾아 301을 건다. 대체 페이지가 도저히 없으면 억지로 만들지 말고 404로 두는 편이 낫다. 관련 없는 페이지로 보낸 리다이렉트는 사용자를 혼란스럽게 하고, 검색엔진도 그것을 실질적인 404로 취급한다. 반대로 같은 내용이 두 주소에 남아 있는 경우라면 판단이 쉽다. 짧은 쪽을 긴 쪽으로 301하고 사이트맵에서도 빼면, 두 주소가 같은 검색어를 두고 경쟁하는 상태가 정리된다.
상황별 결정표
| 삭제한 페이지의 상태 | 권장 처리 | 이유 |
|---|---|---|
| 검색 유입도 외부 링크도 없음 | 404 그대로 둔다 | 조치할 가치가 없다. 크롤러가 알아서 정리한다 |
| 유입 있음, 내용이 거의 같은 페이지 있음 | 그 페이지로 301 | 유입과 링크를 이어받는다 |
| 유입 있음, 대체 페이지 없음 | 404 + 404 화면에서 관련 글 안내 | 무관한 곳으로 보내면 실질적 404로 처리된다 |
| 외부 링크만 있음 | 가장 가까운 페이지로 301 | 링크를 걸어준 쪽의 독자를 살린다 |
| URL 구조만 바뀜, 내용 동일 | 새 URL로 301 | 표준 이전 처리 |
| 상품 일시 품절 | 200 유지, 재입고 안내 표시 | 삭제가 아니라 상태 변경이다 |
| 캠페인 종료, 영구 삭제 확정 | 410 또는 404 | 되살릴 계획이 없음을 명확히 한다 |
| 잘못 배포된 테스트 URL, 색인 안 됨 | 404 | 아무 조치도 필요 없다 |
| 중복 페이지 정리 | 남길 페이지로 301 | 신호를 한 곳에 모은다 |
이 표에서 가장 자주 틀리는 줄은 세 번째다. 유입이 있으니 뭐라도 해야 할 것 같아서 카테고리나 홈으로 보내는데, 그게 다음 장의 문제다.
전부 홈으로 리다이렉트하면 왜 안 되나
지운 URL 200개를 일괄로 홈으로 넘기는 처리는 배포 한 줄로 끝나서 유혹적이다. 그런데 이건 검색엔진에도 사람에게도 도움이 안 된다.
검색엔진 쪽부터 보자. 원래 페이지와 내용이 전혀 다른 곳으로 보내는 리다이렉트는 실질적으로 "그 페이지는 없다"는 말과 같다. 그래서 리다이렉트로 처리했는데도 결과적으로 404와 동일하게 취급되는 일이 생긴다. 코드만 301이고 의미는 404인 셈이다.
사용자 쪽은 더 나쁘다. 특정 글을 찾아 들어온 사람이 아무 설명 없이 홈에 떨어진다. 자기가 실수한 건지, 사이트가 이상한 건지 알 수 없다. 찾던 글이 없어졌다는 사실조차 확인하지 못한 채 나가게 된다. 404 화면은 최소한 "이 주소는 없어졌다"는 정보를 준다.
예외는 있다. 도메인 전체를 옮기면서 URL 구조가 1:1로 대응되지 않고, 옛 사이트의 개별 페이지가 사실상 트래픽이 없었던 경우라면 홈으로 모으는 처리가 실용적일 수 있다. 하지만 그건 "전부 홈으로"가 정답이어서가 아니라, 개별 대응의 가치가 0에 가까워서다. 유입이 있던 URL은 그 경우에도 개별로 매핑해야 한다.
301과 302, 무엇을 언제 쓰나
301은 영구 이동, 302는 임시 이동이다. 판단 기준은 "옛 URL을 다시 쓸 계획이 있나" 하나다.
다시 쓸 계획이 없다면 301이다. 페이지를 합쳤거나, URL 규칙을 바꿨거나, 도메인을 옮겼다면 전부 301이다. 301은 검색엔진에 "색인의 주소를 새 URL로 봐 달라"고 보내는 신호다. 강한 신호이긴 하지만 지시는 아니어서, 어느 주소를 대표로 삼을지는 결국 검색엔진이 판단한다.
옛 URL이 살아 돌아올 거라면 302다. 점검 중 임시 안내, A/B 테스트, 지역별 임시 분기 같은 경우다. 302를 쓰면 검색엔진은 원래 URL을 계속 색인 대상으로 본다.
실무에서 흔한 실수는 반대로 쓰는 것이다. 프레임워크나 서버 기본값이 302인 경우가 있어서, 영구 이전인데 302로 나가는 사이트가 꽤 있다. 배포 후에 실제 응답 헤더를 한 번 찍어보면 바로 보인다.
curl -sI https://example.com/old-page | head -n 5
첫 줄의 상태 코드와 Location 헤더, 이 두 줄만 보면 된다. 브라우저에서 눌러보면 어차피 새 페이지가 열리기 때문에 301인지 302인지 구분되지 않는다.
상태 코드 레퍼런스
| 코드 | 의미 | 검색엔진의 처리 | 쓰는 때 |
|---|---|---|---|
| 200 | 정상 | 내용을 색인한다 | 페이지가 존재할 때 |
| 301 | 영구 이동 | 새 URL로 색인을 옮긴다 | 되돌릴 계획이 없는 이전 |
| 302 | 임시 이동 | 원래 URL을 계속 본다 | 점검, 테스트, 임시 분기 |
| 307 | 임시 이동, 메서드 유지 | 302와 유사 | 임시 이동에 POST 유지가 필요할 때 |
| 308 | 영구 이동, 메서드 유지 | 301과 유사 | 영구 이전에 POST 유지가 필요할 때 |
| 404 | 없음 | 색인에서 제거, 재방문 감소 | 페이지가 사라졌을 때 |
| 410 | 영구 삭제 | 404와 같되 의도가 더 명확 | 되살릴 계획이 확실히 없을 때 |
| 503 | 일시 사용 불가 | 나중에 다시 온다 | 계획된 점검 |
404와 410의 차이는 실무에서 크지 않다. 둘 다 "이 주소에 페이지가 없다"는 답이고, 색인에서 빠지는 방향도 같다. 410은 "일시적 장애가 아니라 내가 지웠다"는 신호가 더 분명한 정도로 보면 된다. 굳이 410을 지원하려고 서버 코드를 고칠 일은 아니다.
503은 성격이 다르다. 점검 때문에 사이트를 잠깐 내릴 때 404를 반환하면 크롤러는 페이지가 사라졌다고 판단한다. 이럴 땐 503을 반환해야 한다. 이 실수는 점검이 끝나고 한참 지나서야 색인 감소로 드러나기 때문에 원인을 찾기 어렵다.
soft 404: 200을 반환하는 "없는 페이지"
가장 골치 아픈 유형이다. 화면에는 "페이지를 찾을 수 없습니다"라고 쓰여 있는데, 서버는 200 OK를 반환하는 경우다.
왜 생기냐면, 프런트엔드에서 라우팅을 처리하는 구조에서는 서버가 일단 HTML 껍데기를 200으로 내려주고, 없는 경로라는 판단은 브라우저 안에서 일어나기 때문이다. 서버는 자기가 404 화면을 내보내고 있다는 사실을 모른다.
검색엔진은 내용을 보고 "이건 사실 없는 페이지네"라고 판단해 soft 404로 분류하곤 한다. 색인은 되지 않는데, 서버가 계속 200을 돌려주니 크롤러 입장에서는 그 URL을 다시 찾아올 이유가 남아 있다. 없는 페이지에 크롤이 반복되는 구조라 URL이 많은 사이트일수록 손해가 커진다.
확인 방법은 간단하다. 없는 주소를 하나 만들어서 헤더를 찍어본다.
curl -sI https://example.com/definitely-not-a-real-page | head -n 1
여기서 200이 나오면 soft 404다. 404가 나와야 정상이다. 브라우저 화면만 보고 판단하면 절대 잡히지 않는다.
이 함정은 404 화면에만 있는 게 아니다. 검색 결과 0건 페이지, 빈 카테고리 페이지, 만료된 채용 공고 페이지도 같은 형태로 걸린다. 내용이 사실상 비어 있으면서 200을 반환하는 모든 페이지가 후보다.
쓸모 있는 404 페이지에 들어가는 것
404 페이지는 사과문이 아니라 다음 행동을 안내하는 화면이다. 들어갈 것은 많지 않다.
| 요소 | 넣는 이유 | 흔한 실수 |
|---|---|---|
| "이 주소에는 페이지가 없다"는 명확한 한 줄 | 사용자가 자기 실수인지 판단할 수 있게 | 애매한 문구로 얼버무린다 |
| 사이트 내 검색창 | 찾던 것에 도달할 가장 짧은 경로 | 아예 없다 |
| 주요 섹션 링크 3~5개 | 목적지를 잃은 사용자의 대안 | 전체 메뉴를 통째로 나열한다 |
| 홈으로 가는 링크 | 최소한의 탈출구 | 이것 하나만 있다 |
| 평소와 같은 헤더와 푸터 | 사이트를 벗어난 게 아님을 알림 | 완전히 다른 레이아웃 |
| 서버 상태 코드 404 | 검색엔진이 상황을 이해함 | 200을 반환한다 |
넣지 말아야 할 것도 있다. 몇 초 뒤 자동으로 홈으로 튕기는 스크립트는 사용자가 주소를 확인할 기회를 뺏는다. 과한 농담 일러스트는 정보를 대신하지 못한다. 그리고 404 화면 자체를 검색 결과에 노출시킬 이유는 없으므로, 사이트맵에 넣거나 내부 링크로 홍보할 필요는 없다.
Search Console에서 404를 어떻게 찾나
색인 생성 보고서의 페이지 항목에서 색인되지 않은 이유별 목록을 볼 수 있다. 여기서 봐야 할 항목은 세 가지다.
첫째, "찾을 수 없음(404)". 실제 404를 반환하는 URL 목록이다. 여기서 내가 알아보는 URL과 처음 보는 URL을 나눈다. 처음 보는 것들은 대부분 외부 오타 링크나 봇이 만든 주소이고, 손댈 이유가 없다. 한 가지 함정이 있다. 이 목록의 판정은 마지막 크롤 시점의 상태다. 고친 지 한참 지난 URL이 여전히 404로 적혀 있을 수 있으므로, 목록을 보고 바로 손대기 전에 그 주소를 직접 열어 지금 무엇을 반환하는지 확인한다.
둘째, "소프트 404". 앞 장에서 말한, 200을 반환하는 없는 페이지다. 이 목록은 실제로 고쳐야 하는 목록이다.
셋째, "리디렉션 포함 페이지". 이 자체는 정상이지만, 여기에 있으면 안 될 URL이 섞여 있는지 확인한다.
작업 순서로 정리하면 이렇다.
| 순서 | 할 일 | 판단 |
|---|---|---|
| 1 | 404 목록을 내려받는다 | 내 URL과 외부에서 만들어진 URL을 나눈다 |
| 2 | 내 URL만 남겨 실적 보고서와 대조한다 | 최근 유입이 있었나 |
| 3 | 링크 보고서에서 외부 링크를 확인한다 | 걸린 링크가 있나 |
| 4 | 유입 또는 링크가 있는 것만 매핑한다 | 대체 페이지를 하나씩 지정 |
| 5 | 301을 걸고 응답 헤더로 검증한다 | 실제 코드와 Location 확인 |
| 6 | 나머지는 그대로 둔다 | 아무것도 하지 않는다 |
4단계에서 목록이 200개쯤 되면 전부 손으로 매핑하려다 지친다. 유입이 큰 것부터 위에서 끊어 처리하고 나머지는 404로 두는 편이 낫다. 롱테일 하나를 살리는 이익보다 잘못된 매핑이 만드는 혼란이 크다.
유입이 있었는지 판단할 때 쓰는 보고서는 블로그 방문자 줄었을 때 원인 찾는 순서에서 다룬 것과 같다. 실적 보고서에서 그 URL이 어떤 검색어로 얼마나 노출됐는지를 보면 301을 걸 값어치가 있는지가 갈린다.
여기서 답이 상황에 달린 부분이 하나 있다. 이 작업의 우선순위다. 사이트가 100페이지 규모이고 이번 달 유입이 세 자리라면 404 정리는 급한 일이 아니다. 반대로 사이트를 막 이전했거나 대량으로 글을 정리한 직후라면 다른 어떤 작업보다 먼저 해야 한다. 이 글의 순서를 그대로 밟기 전에 어느 쪽인지부터 정하는 게 맞다.
증상과 원인 대조표
| 증상 | 흔한 원인 | 확인 방법 |
|---|---|---|
| 404 목록에 모르는 URL이 잔뜩 있다 | 외부 오타 링크, 봇 스캔 | 링크 보고서에서 참조 페이지 확인 |
| 리다이렉트를 걸었는데 옛 URL이 계속 색인돼 있다 | 302로 나가고 있다 | 응답 헤더의 상태 코드 확인 |
| 없는 페이지인데 색인 시도가 계속된다 | soft 404 | 헤더가 200인지 확인 |
| 이전 후 검색 유입이 급감했다 | 매핑 누락 또는 홈 일괄 리다이렉트 | 옛 URL 목록과 리다이렉트 규칙 대조 |
| 리다이렉트가 유난히 느리다 | 리다이렉트 체인 | curl로 경유 횟수 확인 |
| 페이지를 지웠는데 검색 결과에서 안 사라진다 | robots.txt로 막아버렸다 | robots.txt 규칙 확인 |
| 점검 후 여러 페이지가 색인에서 빠졌다 | 점검 중 404를 반환했다 | 점검 시 503 반환 여부 |
아래 두 줄은 원인이 서로 반대 방향이라 특히 헷갈린다. 하나는 크롤러를 막아서 생기고, 하나는 크롤러에게 잘못된 답을 줘서 생긴다.
robots.txt로 막으면 404가 사라지나
사라지지 않는다. 오히려 반대 효과가 난다.
robots.txt는 크롤링을 막는 도구다. 크롤러가 그 URL에 접근하지 못하면, 그 URL이 404를 반환한다는 사실도 확인할 수 없다. 확인하지 못하니 색인에서 빼지도 못한다. 지운 페이지를 검색 결과에서 빨리 없애고 싶다면 막지 말고 크롤하게 둬야 한다.
지운 URL을 robots.txt로 차단하는 처리는 보고서의 404 숫자를 줄이려고 하는 경우가 많은데, 숫자는 줄어도 실제 상태는 나빠진다. 크롤링 제어와 색인 제어는 다른 문제다.
리다이렉트 체인은 왜 문제인가
A를 B로, B를 C로 보내면 A에서 C까지 두 번을 거친다. 사이트를 몇 년 운영하면 이런 체인이 저절로 쌓인다. 2015년 URL이 2019년 URL을 거쳐 지금 URL로 가는 식이다.
체인 자체가 치명적이진 않지만, 길어지면 사용자가 기다리고 크롤러도 중간에 포기할 수 있다. 그리고 중간 고리 하나가 사라지면 전체가 끊긴다.
정리 원칙은 하나다. 새 리다이렉트를 추가할 때 기존 규칙을 검색해서, 그 대상으로 향하던 옛 규칙도 최종 목적지로 갱신한다. 이걸 습관으로 만들면 체인이 자라지 않는다.
루프는 다르다. A가 B로, B가 A로 가면 브라우저가 오류를 낸다. 이건 해당 경로가 통째로 죽는 사고이므로, 규칙을 추가한 뒤에는 반드시 실제로 한 번 열어봐야 한다.
글을 지우기 전에 쓰는 5분
블로그를 운영하다 보면 오래된 글을 지우고 싶어진다. 지우기 전에 이 순서만 밟으면 대부분의 사고를 막을 수 있다.
먼저 Search Console 실적에서 그 URL의 최근 3개월 노출과 클릭을 본다. 클릭이 0이고 노출도 거의 없으면 그냥 지워도 된다.
노출이 있는데 클릭이 0이라면, 지우기 전에 제목과 첫 문단을 고쳐보는 쪽을 먼저 시도한다. 검색엔진이 이미 보여주고 있는 페이지를 없애는 건 마지막 수단이다.
클릭이 있다면 지우지 말고 갱신한다. 정말 없애야 한다면 내용이 겹치는 다른 글로 301을 건다.
그리고 지운 뒤에는 사이트 안에서 그 글로 걸려 있던 내부 링크를 찾아 고친다. 내부 링크가 404를 가리키는 상태는 외부 오타 링크와 달리 전적으로 내 책임이다.
정리하면 판단은 세 줄이다
첫째, 404는 정상적인 답변이고 개수는 문제가 아니다.
둘째, 유입이나 외부 링크가 있던 URL만 골라 가장 가까운 페이지로 301을 건다. 대체할 곳이 없으면 404로 둔다.
셋째, 없는 페이지가 200을 반환하고 있지 않은지 응답 헤더로 확인한다. 이 셋을 지키면 나머지는 대부분 손댈 필요가 없다.
자주 묻는 질문
404 페이지가 100개 넘게 잡혔는데 다 고쳐야 하나요
아닙니다. 개수는 판단 기준이 아닙니다. 목록을 열어 검색 유입이 있었거나 외부 링크가 걸린 URL만 골라내면 보통 그중 소수입니다. 나머지는 외부 오타 링크나 봇이 만든 주소이고, 그대로 두는 것이 정상적인 처리입니다.
지운 글을 카테고리 페이지로 보내도 되나요
내용이 실제로 대응될 때만 괜찮습니다. 특정 제품 글을 지우고 그 제품군 목록으로 보내는 것은 자연스럽습니다. 반면 전혀 다른 주제의 목록으로 보내면 검색엔진이 실질적인 404로 취급하고, 들어온 사람도 찾던 내용을 얻지 못합니다. 대응이 애매하면 404로 두고 404 화면에서 관련 글을 안내하는 편이 낫습니다.
301 리다이렉트는 얼마나 오래 유지해야 하나요
가능하면 계속 유지하는 것이 좋습니다. 검색엔진이 새 URL을 인식한 뒤에도 옛 주소가 적힌 외부 링크나 북마크는 계속 남아 있기 때문입니다. 규칙이 수백 개로 늘어 관리가 어려워지면, 오래되고 접근이 전혀 없는 규칙부터 서버 로그를 확인한 뒤 정리하십시오.
사이트 전체를 새 도메인으로 옮길 때도 같은 기준인가요
기본 원칙은 같지만 규모가 다릅니다. 옛 URL과 새 URL을 1:1로 대응시키는 매핑 표를 먼저 만들고, 유입이 있던 페이지부터 확인하십시오. 도메인 이전은 Search Console에 주소 변경을 알리는 절차도 함께 진행하는 것이 안전합니다.
404 화면을 만들 때 서버 설정도 따로 해야 하나요
예. 화면만 만들고 끝내면 서버가 200을 반환하는 soft 404가 되기 쉽습니다. 404 화면을 만든 뒤에는 없는 주소를 하나 열어 응답 헤더의 상태 코드가 실제로 404인지 확인하십시오. 브라우저 화면으로는 구분되지 않습니다.
참고 자료
- 리디렉션과 Google 검색 — 301과 302의 차이, 영구 이동과 임시 이동의 구분, 사이트 이전 시 리다이렉트 처리 방법
- robots.txt 소개 — 크롤링 제어가 색인에 미치는 영향, 크롤링 차단과 색인 제거가 서로 다른 문제라는 점