404가 실제로 뜻하는 것

404는 서버와의 대화는 성공했는데, 그 주소에 아무것도 없다는 응답입니다. DNS 조회도, 연결도, TLS도 됐고, 서버가 “이 경로에는 줄 게 없다”고 답한 것입니다.

이것만으로도 많은 것이 배제됩니다. DNS 문제는 브라우저에 ERR_NAME_NOT_RESOLVED로, 죽은 서버는 ERR_CONNECTION_REFUSED나 시간 초과로 나오고, 둘 다 HTTP 상태 코드가 아예 없습니다. 404는 항상 HTTP로 말하는 무언가가 만든 것입니다.

상태 코드는 없는 상태가 영구적인지도 말해 주지 않습니다. 그걸 위한 코드가 410 Gone이고, 삭제한 페이지를 다룰 때 중요합니다(아래 참고).

방문자라면

먼저 URL에 오타가 없는지 보세요. 대문자도 포함입니다. 대부분의 서버에서 /About과 /about은 다른 경로입니다. 경로 끝부분을 지우거나 한 단계 위 섹션 페이지로 가 보세요. 삭제된 페이지라면 Wayback Machine 같은 아카이브에 사본이 남아 있을 수 있습니다. 그 밖에는 사이트 쪽에서 고칠 일이고, 어느 링크를 눌러 왔는지 운영자에게 알려 주면 도움이 됩니다.

1단계: 누가 404를 냈는지 찾기

“404”는 여러 층에서 만들어지고, 층마다 해결책이 다릅니다. 응답 본문을 보면 대개 티가 납니다.

curl -sI https://www.example.com/missing
curl -s https://www.example.com/missing | head -20
보이는 것응답한 주체
“404 Not Found” 아래에 “nginx”nginx가 파일을 찾지 못했고 처리할 location도 없음
“Not Found. The requested URL was not found on this server.”Apache
Cannot GET /path그 메서드·경로에 라우트가 없는 Express(Node) 앱
“Whitelabel Error Page”그 경로를 처리할 핸들러가 없는 Spring Boot 앱
평문 404 page not foundGo 서버의 기본 핸들러. 맞는 라우터가 없을 때의 Traefik 포함
{"message":"no Route matched with those values"}Kong API 게이트웨이: 그 호스트·경로의 라우트가 없음
ID가 붙은 404: NOT_FOUNDVercel
<Code>NoSuchKey</Code>가 든 XMLAmazon S3(또는 S3 호환 스토리지)
“There isn’t a GitHub Pages site here.”모르는 커스텀 도메인을 받은 GitHub Pages
내 사이트 디자인의 404 화면내 애플리케이션의 라우터

게이트웨이, ingress, 프록시가 내는 “no route” 메시지는 꼭 알아봐야 합니다. 요청이 내 코드에 닿기 전에 멈췄다는 뜻이므로, 앱을 아무리 디버깅해도 소용없습니다. 그 호스트·경로에 대한 게이트웨이의 라우트 정의를 보세요.

HTTP 점검은 내 네트워크 밖에서 본 리다이렉트 경로 전체와 최종 상태를 보여 줍니다. 무엇보다 먼저 이걸 보세요. 생각보다 많은 404가 엉뚱한 곳으로 보내는 리다이렉트의 끝에서 납니다.

홈페이지까지 사이트 전체가 404

/조차 404라면 요청이 엉뚱한 곳에 도착하고 있거나, 맞는 곳에 도착했는데 내용이 없는 것입니다.

다른 가상 호스트가 응답함. 웹 서버는 Host 헤더로 사이트를 고릅니다. 내 호스트명이 어떤 server_name(nginx)이나 ServerName·ServerAlias(Apache)에도 없으면 기본 사이트가 응답하고, 거기에는 대개 내 경로가 없습니다. 비교해 보세요.

curl -sI -H 'Host: www.example.com' http://203.0.113.10/
curl -sI -H 'Host: example.com' http://203.0.113.10/
nginx -T | grep -n server_name

한 이름은 되고 다른 이름은 404라면, 빠진 이름을 올바른 server 블록에 추가하세요. www와 루트 도메인은 서로 다른 이름이라 둘 다 적어야 합니다.

DNS가 다른 곳을 가리킴. 서버를 옮긴 뒤 레코드가 이제 이 사이트를 서비스하지 않는 예전 호스트를 계속 가리키는 경우입니다. DNS 조회로 이름이 어디로 해석되는지 보고 배포한 곳과 비교하세요.

document root가 틀렸거나 빌드 결과물이 비어 있음. root는 /var/www/site인데 빌드는 /var/www/site/dist에 됐거나, 프레임워크는 dist/에 쓰는데 정적 호스팅은 build/를 배포하도록 설정된 경우입니다. nginx에서는 디렉터리가 없으면 404이고, 디렉터리는 있는데 index 파일이 없고 autoindex off면 403이 납니다. 원인을 가리는 데 쓸모 있는 차이입니다.

플랫폼이 내 커스텀 도메인을 모름. GitHub Pages, S3 웹사이트 엔드포인트, Netlify 등은 도메인이 자기를 가리키지만 설정에서 사이트에 연결되지 않았으면 자체 404를 냅니다.

일부 경로만 404

SPA에서 새로고침하면 404

가장 흔한 경우입니다. React, Vue, Angular 앱 안에서 클릭해 다니면 되는데, /dashboard/settings에서 새로고침하거나 링크로 바로 열면 404가 납니다. 라우트는 JavaScript 안에만 있고, 서버는 dashboard/settings라는 파일을 찾다가 없으니 404를 냅니다.

모르는 경로는 index.html로 넘기라고 서버에 알려 주세요.

location / {
    try_files $uri $uri/ /index.html;
}

Apache는 FallbackResource /index.html, Netlify는 _redirects에 /* /index.html 200 한 줄입니다. 다른 정적 호스팅에도 같은 역할의 rewrite 설정이 있습니다.

대가도 있습니다. 이제 모르는 URL이 전부 앱 껍데기와 함께 200을 돌려줍니다. 이게 soft 404이니(아래 참고) 앱의 not found 화면에서 따로 처리해야 합니다.

대소문자

Linux 파일 시스템은 대소문자를 구분하고, Windows와 macOS(기본 설정)는 구분하지 않습니다. /images/Logo.png 링크는 내 노트북에서는 되지만 파일 이름이 logo.png인 서버에서는 404입니다.

git에도 함정이 있습니다. 대소문자를 구분하지 않는 파일 시스템에서는 Logo.png를 logo.png로 바꿔도 변경으로 잡히지 않을 수 있습니다. git mv -f Logo.png logo.png로 바꿔야 저장소에 실제로 반영됩니다.

trailing slash와 base path

/docs와 /docs/는 다른 URL입니다. 정적 호스팅은 보통 /docs/를 docs/index.html로 서비스하고, /docs가 되는지는 호스팅과 프레임워크의 trailing slash 설정에 따라 다릅니다. 한 형태를 정하고, 링크를 그 형태로 만들고, 다른 형태는 리다이렉트하세요.

리버스 프록시에는 더 미묘한 버전이 있습니다. nginx에서 proxy_pass에 URI 부분이 있느냐에 따라 백엔드가 받는 경로가 달라집니다.

location /api/ {
    proxy_pass http://backend:3000/;   # /api/users -> /users
}
location /api/ {
    proxy_pass http://backend:3000;    # /api/users -> /api/users
}

백엔드 라우트가 /users인데 두 번째 형태를 썼다면(또는 그 반대라면) API 호출이 전부 404입니다. 하위 경로에 배포한 앱도 같습니다. 앱은 /app/에서 서비스되는데 자원을 /assets/...로 참조하면, 페이지는 뜨지만 스크립트와 이미지가 전부 404입니다. 프레임워크의 base path를 설정하세요.

동작하지 않는 rewrite 규칙

WordPress의 고유주소(퍼머링크), Laravel 라우트, 대부분의 PHP 프레임워크는 .htaccess의 rewrite에 의존합니다. 이게 조용히 동작하지 않는 경우가 두 가지 있습니다.

  • 그 디렉터리에 AllowOverride None이 걸려 있어 Apache가 .htaccess를 아예 무시함. 홈은 되고 다른 페이지는 전부 404입니다.
  • mod_rewrite가 로드되지 않았는데 규칙이 <IfModule mod_rewrite.c>로 감싸여 있어, 오류 대신 그냥 건너뜀.

증상은 같습니다. /는 되고 /about은 안 됩니다. apachectl -M | grep rewrite와 사이트 <Directory> 블록의 AllowOverride를 확인하세요. nginx에는 .htaccess가 아예 없으므로 rewrite가 서버 설정에 있어야 합니다(PHP 프레임워크는 보통 try_files $uri $uri/ /index.php?$query_string;).

한글·공백이 든 파일 이름

한글이나 공백이 든 파일은 퍼센트 인코딩된 형태로 요청되고, 서버는 그걸 디코딩해 디스크의 정확한 바이트와 맞춰야 합니다. macOS에서 만든 파일은 유니코드 분해형(NFD)으로 저장될 수 있는데, 링크는 거의 항상 조합형(NFC)으로 적힙니다. 눈으로는 똑같지만 일치하지 않아 404가 납니다. 서버에서 파일 이름을 다시 바꾸거나, 처음부터 ASCII 파일 이름을 쓰면 피할 수 있습니다.

삭제한 페이지: 301, 404, 410

페이지를 지우거나 옮길 때는 의도를 갖고 고르세요.

  • 내용이 옮겨 갔거나 분명한 대체 페이지가 있음: 새 URL로 301. 방문자와 링크가 따라가고, 검색엔진도 시간이 지나며 옛 URL의 평가를 새 URL로 옮깁니다. 301과 302 비교를 참고하세요.
  • 내용이 완전히 사라짐: 404나 410을 돌려주세요. Google은 둘을 거의 같게 처리한다고 밝혀 왔습니다. 410은 일부러 지웠다는 뜻을 분명히 하므로 URL이 조금 더 빨리 빠질 수 있습니다.
  • 전부 홈으로 리다이렉트하지 마세요. 특정 글을 찾던 방문자는 답이 없는 페이지를 받고, Google도 관계없는 페이지로의 리다이렉트를 어차피 soft 404로 처리할 수 있습니다.

있으면 안 되는 URL의 404는 사이트의 다른 페이지 검색 순위에 해가 되지 않습니다. 고칠 가치가 있는 건 사람이나 다른 사이트가 아직 링크하고 있는 URL의 404입니다. Search Console의 페이지 색인 보고서에 나오고, 접근 로그에서도 볼 수 있습니다.

awk '$9 == 404 {print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

(기본 combined 로그 형식 기준입니다. 9번째 필드가 상태 코드, 7번째가 경로입니다.)

soft 404: 반대 방향의 문제

soft 404는 “찾을 수 없음”이라고 말하면서 상태 코드는 200을 돌려주는 페이지입니다. 검색엔진은 이 불일치를 알아채고 soft 404로 표시해 색인에서 뺄 수 있고, 모니터링은 아무 문제도 보지 못합니다.

흔한 출처는 이렇습니다.

  • 모든 경로에 200을 돌려주고 not found 문구는 JavaScript로 그리는 SPA fallback.
  • 리다이렉트로 설정된 사용자 오류 페이지. Apache의 ErrorDocument 404 /404.html은 404 상태를 유지하지만, ErrorDocument 404 https://example.com/404.html(전체 URL)은 Apache가 대신 리다이렉트하게 만들어 최종 응답이 200이 됩니다.
  • 오류처럼 보이는 빈 검색 결과나 빈 카테고리 페이지.

서버 렌더링 사이트라면 사용자 오류 페이지가 404 상태로 나가는지 확인하세요. nginx의 error_page 404 /404.html;은 기본적으로 그렇게 합니다. SPA라면 서버가 어떤 라우트가 있는지 알고 나머지에 404를 돌려주게 하거나, not found 화면에 <meta name="robots" content="noindex">를 넣으세요. 확인은 브라우저가 아니라 curl -sI로 하세요. 화면은 어느 쪽이든 똑같아 보입니다.

고친 다음에

실패했던 URL과 그 이웃들, 즉 www와 루트 도메인 버전, trailing slash가 있는 것과 없는 것에 HTTP 점검을 돌리세요. 있는 페이지는 최종 상태가 200이어야 하고, 엉터리 경로는 여전히 404여야 합니다. 그래야 고치는 과정에서 soft 404를 만들지 않았다는 것이 확인됩니다.

관련 가이드

  • 403 Forbidden: 경로는 있는데(또는 있을 수도 있는데) 접근이 거부된 경우입니다.
  • 리다이렉트 루프 진단: 리다이렉트가 404로 끝나지 않고 끝없이 이어지는 경우입니다.

내 도메인에서 바로 확인

무료, 가입 불필요. 이 가이드가 다루는 항목을 바로 검사하고 조치 방법을 알려드립니다.