503이 뜻하는 것

502와 504는 프록시가 응답을 받으려고 시도했다가 실패한 상황을 말합니다. 503은 종류가 다릅니다. 무언가가 지금은 이 요청을 처리하지 않기로 결정한 것입니다. RFC 9110은 503을 서버가 “일시적인 과부하나 예정된 점검 때문에 현재 요청을 처리할 수 없으며, 얼마 뒤에는 해소될 가능성이 높은” 상태로 정의합니다.

실제 운영 환경에서 그 결정은 몇 군데 중 한 곳에서 나옵니다.

  • 점검 모드: 사람이나 배포 스크립트가 켠 것.
  • rate limit이나 과부하 보호: 나(또는 내 IP)가 너무 많이 보내서 거부하는 것.
  • 쓸 수 있는 백엔드 없음: 로드밸런서나 ingress는 정상인데 요청을 보낼 정상 대상이 없는 것.
  • 멈춘 프로세스 관리자나 앱 풀: 중지됐거나 재시작 중인 것.

결정이기 때문에 503은 대개 빠르게 돌아옵니다. 60초 동안 멈춰 있다가 실패하는 요청은 503이 아니라 타임아웃입니다. 예외가 되는 제품군은 아래에서 다룹니다.

응답에 Retry-After 헤더가 붙을 수 있습니다. 초 단위 숫자나 날짜입니다. 필수는 아니지만, 있다면 서버가 얼마나 기다리라고 알려 주는 것입니다.

방문자라면

모두에게 오류가 난다면 사이트가 점검 중이거나 과부하입니다. 기다렸다가 다시 시도하세요. 내 쪽에서 고칠 것은 없습니다.

나에게만 난다면 rate limit일 가능성이 큽니다. 한도는 IP 주소 단위로 세기 때문에, 사람이 몰리는 VPN 출구, 여럿이 쓰는 사무실 회선, 많은 가입자를 주소 하나 뒤에 두는 이동통신망에서는 내가 만들지 않은 한도에 걸릴 수 있습니다. 1분 기다리거나, VPN을 끄거나, 와이파이에서 모바일 데이터로 바꿔 보세요. 새로고침을 반복하면 rate limit은 더 나빠집니다. 새로고침 하나하나가 다 세어지기 때문입니다.

누가 보냈는지 찾기

여기서는 상태 코드만으로 알 수 있는 게 생각보다 적습니다. 소프트웨어마다 503에 담는 뜻이 다르기 때문입니다. 헤더와 본문을 보세요.

curl -sv -o /dev/null https://example.com/ 2>&1 | grep -iE '^< (HTTP|server|retry-after|via|x-cache|x-served-by|cf-ray)'

흔한 모양과 그 뜻은 이렇습니다.

보이는 것보낸 쪽보통의 의미
nginx 페이지 “503 Service Temporarily Unavailable”nginxlimit_req/limit_conn이 거부했거나, 점검용 return 503
“Briefly unavailable for scheduled maintenance. Check back in a minute.”WordPress업데이트가 진행 중이거나, 중간에 끊겼음
Server: awselb/2.0AWS ALB대상 그룹에 등록된 대상이 없거나, 규칙이 고정 503을 돌려줌
“No server is available to handle this request.”HAProxybackend의 모든 서버가 다운이거나 점검 상태
“Error 503 Backend fetch failed”와 “Guru Meditation”Varnish백엔드가 실패했거나 타임아웃
“first byte timeout”이나 “backend read error”가 적힌 “Error 503”Fastly원 서버 타임아웃이나 장애
“The server is temporarily unable to service your request due to maintenance downtime or capacity problems”Apache흔히 mod_proxy가 백엔드에 연결하지 못한 것
Server: Microsoft-HTTPAPI/2.0과 “HTTP Error 503. The service is unavailable.”Windows IIS (HTTP.sys)애플리케이션 풀이 중지됨

Varnish, Fastly, Apache 줄을 눈여겨보세요. 이 제품들은 백엔드가 죽었거나 너무 느린 상황을 503으로 보고합니다. nginx라면 502나 504라고 했을 상황입니다. 그래서 Varnish 기반 캐시에서 온 503은 사실상 ‘내 백엔드가 실패했다’는 뜻이고, 502나 504처럼 백엔드부터 진단해야 합니다.

HTTP 점검은 우리 네트워크 밖에서 본 상태 코드와 Server, Retry-After를 포함한 헤더를 보여 줍니다.

흔한 원인과 해결

켜 둔 채 잊은 점검 모드

가장 민망하고 가장 흔한 원인입니다. 배포 스크립트가 점검 모드를 켜 놓고, 끄기 전에 실패한 경우입니다.

  • WordPress는 코어·플러그인·테마를 업데이트하는 동안 사이트 루트에 .maintenance 파일을 만듭니다. 업데이트가 중간에 끊기면(타임아웃, 브라우저 탭을 닫음) 파일이 남고, 사이트는 “Briefly unavailable” 메시지와 함께 계속 503을 냅니다. WordPress 루트의 .maintenance를 지운 뒤, 끊겼던 업데이트가 실제로 끝났는지 확인하세요.
  • Laravel은 php artisan down 뒤에 503을 돌려주고, php artisan up으로 되돌립니다.
  • 직접 만든 nginx 스위치는 흔히 플래그 파일을 확인합니다. sudo nginx -T | grep -n -B2 -A4 'return 503'으로 찾아보세요.

점검 페이지를 쓸 거라면 제대로 만드세요. 검색엔진이 점검 페이지를 사이트 본문으로 색인하지 않도록 200이 아니라 503을 돌려주고, Retry-After를 붙입니다.

error_page 503 @maintenance;

location @maintenance {
    root /var/www/maintenance;
    add_header Retry-After 600 always;
    rewrite ^ /index.html break;
}

location / {
    if (-f /etc/nginx/maintenance.flag) {
        return 503;
    }
    proxy_pass http://app;
}

always가 중요합니다. 없으면 nginx는 성공·리다이렉트 응답에만 헤더를 붙이고 503에는 붙이지 않습니다. 이렇게 해 두면 sudo touch /etc/nginx/maintenance.flag로 점검을 켜고 파일을 지우면 꺼지며, 리로드도 필요 없습니다.

검색엔진은 503을 일시적인 것으로 보고 나중에 다시 옵니다. 다만 그건 몇 시간 단위의 이야기이지 몇 주가 아닙니다. 며칠씩 503을 내면 페이지가 색인에서 빠지기 시작한다고 보는 게 맞습니다.

너무 빡빡하거나 엉뚱한 IP를 세는 rate limit

nginx의 limit_req와 limit_conn은 기본적으로 503으로 거부합니다. 오류 로그에서는 대략 이렇게 보입니다.

2026/10/07 11:20:05 [error] 2114#2114: *10422 limiting requests, excess: 20.240 by zone "per_ip", client: 203.0.113.50, server: example.com, request: "GET /api/search?q=x HTTP/1.1", host: "example.com"

고칠 것이 두 가지 있고, 둘 다 할 가치가 있습니다.

먼저 429 Too Many Requests를 돌려주게 바꾸세요. 그래야 클라이언트도, 모니터링도, 나 자신도 rate limit과 장애를 구별할 수 있습니다.

limit_req_status 429;
limit_conn_status 429;

그다음 한도가 올바른 주소를 세는지 확인하세요. nginx가 로드밸런서나 CDN 뒤에 있는데 zone 키가 $binary_remote_addr이라면, 모든 방문자가 로드밸런서의 몇 안 되는 IP를 나눠 쓰게 되고, 바쁜 1분 동안 모두가 한도에 걸립니다. realip 모듈을 설정해(set_real_ip_from에 프록시 대역, real_ip_header에 프록시가 넣는 헤더) $remote_addr가 방문자 주소가 되게 하세요. 그 헤더는 프록시 주소에서 온 것만 믿어야 합니다. 아무에게서나 믿으면 클라이언트가 자기 IP를 마음대로 고를 수 있습니다.

burst가 설정돼 있는지도 보세요. 없으면 limit_req는 초과분을 전혀 허용하지 않아서, 자원 스무 개를 불러오는 페이지를 연 브라우저가 스크립트용으로 만든 한도에 걸릴 수 있습니다.

정상 백엔드가 없음

로드밸런서나 ingress는 멀쩡합니다. 트래픽을 보낼 대상이 뒤에 없을 뿐입니다.

  • AWS ALB는 대상 그룹에 등록된 대상이 없을 때 503을 돌려줍니다. 하지 않는 일도 알아 두세요. 대상이 등록돼 있는데 전부 health check에 실패하면 ALB는 ‘fail open’으로 그 대상들에게 어쨌든 트래픽을 보내므로, 503이 아니라 대상들의 오류(흔히 502)가 보입니다. 그래서 ALB의 503은 대개 빈 대상 그룹을 뜻합니다. 0으로 줄어든 Auto Scaling 그룹이나, 한꺼번에 전부 등록 해제한 배포가 흔한 경우입니다.
  • Kubernetes ingress-nginx는 Service에 준비된 endpoint가 없을 때 503을 냅니다. kubectl get endpoints <service>가 비어 있다면, readiness probe를 통과한 Pod가 없거나 Service selector가 Pod 라벨과 맞지 않는 것입니다. 의존 서비스(DB)를 확인하는 readiness probe는 그 서비스가 잠깐 흔들릴 때 모든 Pod를 한꺼번에 빼 버릴 수 있습니다. readiness는 Pod 자신의 상태만 보게 하세요.
  • HAProxy는 모든 서버가 다운으로 표시되면 “No server is available”을 보여 줍니다. stats 소켓의 show stat으로 어떤 health check가 실패했는지 볼 수 있습니다.

과부하와 느린 확장

트래픽이 용량보다 빨리 늘었고, 무언가가 넘치는 부분을 503으로 덜어 내고 있습니다. 동시 처리 한도, 가득 찬 큐, 스스로를 보호하는 앱 풀 같은 것입니다. autoscaling은 꾸준히 느는 트래픽에는 도움이 되지만 갑작스러운 급증에는 그렇지 못합니다. 새 인스턴스가 부팅하고 health check를 통과하기까지 몇 분이 걸리고, 그동안 기존 인스턴스들이 일을 거부하기 때문입니다.

단기 해결은 뻔합니다. 인스턴스를 늘리거나 최소 수를 올리는 것입니다. 장기적으로는 캐시할 수 있는 것을 엣지에서 캐시해 급증이 애플리케이션까지 오지 않게 하고, 비싼 경로가 급증을 정면으로 맞지 않게 하세요.

멈춘 프로세스

Windows에서는 애플리케이션 풀이 중지되면 IIS가 HTTP.sys의 503을 돌려줍니다. 앱이 짧은 시간에 여러 번 죽어서 Rapid-Fail Protection이 풀을 멈춘 경우가 흔합니다. Windows 이벤트 로그(System, Application)에 이유가 남으니, 죽는 원인을 고친 뒤 풀을 시작하세요. 리눅스에서 비슷한 상황은 대개 502로 나옵니다. nginx는 죽은 백엔드를 그렇게 보고하기 때문입니다. Apache를 거쳐 503이 보인다면 ProxyPass가 가리키는 백엔드가 떠 있는지 확인하세요. Apache mod_proxy는 대략 AH00957: http: attempt to connect to 127.0.0.1:8080 (127.0.0.1) failed 같은 줄을 남기고 503을 돌려줍니다.

고친 다음에

  • 서버 안에서만이 아니라 바깥에서 HTTP 점검으로 다시 확인하세요. rate limit이나 네트워크별 차단은 안에서 보면 멀쩡해 보입니다.
  • 점검 페이지의 Retry-After 헤더를 curl -sI로 확인하세요.
  • 503이 rate limit 때문이었다면 평범한 하루치 로그를 보세요. 매일 오후마다 실제 방문자를 거부하는 한도라면 한 번 풀어 줄 게 아니라 rate나 burst를 올려야 합니다.
  • 포트 점검은 공개 포트가 응답하는지 확인해 줍니다. 503이 전달되려면 포트가 열려 있어야 하므로, 포트가 닫혀 있다면 다른 문제를 보고 있는 것입니다.

비슷해 보이는 다른 오류

  • 502 Bad Gateway: 프록시가 뒤쪽 서버에서 깨진 응답을 받았습니다.
  • 504 Gateway Timeout: 프록시가 응답을 기다리다 타이머가 끝났습니다.
  • ERR_CONNECTION_REFUSED: 그 포트에서 아무것도 응답하지 않아 HTTP 상태 코드가 아예 없습니다.

내 도메인에서 바로 확인

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