504 Gateway Timeout: 원인과 해결 방법 완벽 가이드

504 Gateway Timeout이란?
504 Gateway Timeout은 게이트웨이 또는 프록시 역할을 하는 서버가 업스트림 서버로부터 제시간에 응답을 받지 못했음을 나타내는 HTTP 상태 코드입니다. 프록시가 업스트림의 응답을 기다렸지만, 너무 오래 걸려서 프록시가 대기를 포기하고 브라우저에 504를 반환한 것입니다.
공식 정의는 RFC 9110(HTTP Semantics) 섹션 15.6.5에 명시되어 있습니다. "504(Gateway Timeout) 상태 코드는 서버가 게이트웨이 또는 프록시로 동작하는 동안, 요청을 완료하기 위해 접근해야 하는 업스트림 서버로부터 제시간에 응답을 받지 못했음을 나타낸다."
핵심 단어는 게이트웨이입니다. 504에는 항상 최소 두 개의 서버가 관련됩니다. 여러분이 접속한 서버(프록시/게이트웨이)와 그 뒤에 있는 응답하지 못한 서버(업스트림/오리진)입니다. 일반적인 프록시에는 Nginx 리버스 프록시, Cloudflare, AWS Application Load Balancer(ALB), CloudFront 등이 있습니다.
504 오류의 표시 형태
504 오류 메시지는 브라우저, 웹 서버, CDN에 따라 다르게 표시됩니다. 가장 흔히 볼 수 있는 메시지는 다음과 같습니다.
504 Gateway Timeout
504 Gateway Time-out (Nginx 기본값 — 하이픈 포함)
HTTP Error 504 — Gateway Timeout
이 페이지가 작동하지 않음 — [도메인]에서 응답하는 데 시간이 너무 오래 걸렸습니다 (Chrome / Edge)
Gateway Timeout (Firefox)
Error 504
504 Gateway Time-out — The server didn't respond in time (Apache mod_proxy 사용 시)
Error 524: A timeout occurred (Cloudflare 전용 — 엄밀히 504는 아니지만 근본 원인은 동일)
ERROR — The request could not be satisfied — 504 ERROR (AWS CloudFront)
메시지의 문구와 관계없이, 근본적인 원인은 항상 동일합니다. 프록시 서버가 업스트림 서버의 응답을 기다렸지만, 업스트림 서버가 설정된 타임아웃 시간 내에 응답하지 않은 것입니다.
504 Gateway Timeout이 발생하는 과정
504 오류를 이해하려면 브라우저와 오리진 서버 사이의 타임아웃 체인을 이해해야 합니다. 일반적인 웹 요청은 여러 레이어를 거치며, 각 레이어에는 자체적인 타임아웃 설정이 있습니다.
일반적인 요청 흐름: 브라우저 → CDN(Cloudflare) → 로드 밸런서 → Nginx → PHP-FPM → 데이터베이스. 데이터베이스 쿼리가 90초 걸리는데 Nginx의 proxy_read_timeout이 60초로 설정되어 있다면, Nginx는 대기를 중단하고 로드 밸런서에 504를 반환하며, 이것이 다시 브라우저로 전달됩니다.
504를 반환하는 서버는 항상 중간 서버(프록시 또는 게이트웨이)이며, 오리진 서버 자체가 아닙니다. 오리진 서버는 단순히 제시간에 응답하지 못한 것이며, 아직 요청을 처리 중이거나 완전히 크래시되었을 수 있습니다.
| 레이어 | 기본 타임아웃 | 타임아웃 시 동작 |
|---|---|---|
| Cloudflare (Free/Pro) | 100초 | Error 524 반환 (자체 코드) |
| AWS CloudFront | 30초 | 504 ERROR 반환 |
| AWS ALB | 60초 | awselb 헤더와 함께 504 반환 |
| GCP Load Balancer | 30초 | 504 반환 |
| Nginx (proxy_read_timeout) | 60초 | 504 Gateway Time-out 반환 |
| Apache (ProxyTimeout) | 60초 | 504 Gateway Timeout 반환 |
| PHP max_execution_time | 30초 | 스크립트 종료, Nginx가 응답을 받지 못해 504 반환 |
504 Gateway Timeout의 주요 원인
근본 원인을 파악하는 것이 가장 빠른 해결 방법입니다. 서버가 504를 반환하는 가장 흔한 이유를 발생 빈도 순으로 정리했습니다.
느린 오리진 서버 — 복잡한 데이터베이스 쿼리 실행, 보고서 생성, 느린 서드파티 API 호출을 수행하는 PHP 스크립트가 프록시의 타임아웃을 초과할 수 있습니다. 이것이 504 오류의 가장 흔한 원인입니다.
서버 과부하 — CPU 100%, 메모리 부족(OOM kill), 모든 PHP-FPM 워커가 바쁜 상태. 오리진 서버가 살아 있지만 제시간에 응답할 수 없을 정도로 과부하 상태입니다.
데이터베이스 병목 — 느린 SQL 쿼리, 인덱스 누락, 테이블 잠금, 커넥션 풀 고갈. 애플리케이션이 데이터베이스를 기다리며 멈추고, 프록시가 타임아웃됩니다.
잘못된 타임아웃 설정 — 백엔드가 정당하게 더 많은 시간이 필요한 경우(예: 보고서 생성기나 파일 업로드 처리기)에 Nginx
proxy_read_timeout이 너무 낮게 설정된 경우.프록시와 오리진 간 네트워크 문제 — 데이터 센터 간 패킷 손실, 높은 지연 시간, 라우팅 문제. 멀티 리전 또는 하이브리드 클라우드 환경에서 흔합니다.
방화벽 또는 보안 그룹의 트래픽 차단 — AWS 보안 그룹이 임시 포트 트래픽을 허용하지 않거나, iptables 규칙이 내부 연결을 차단하거나, WAF가 정당한 업스트림 요청을 차단하는 경우.
프록시에서의 DNS 해석 실패 — 프록시가 업스트림 호스트명을 해석할 수 없는 경우. Nginx에서는
proxy_pass에 변수를 사용하면서resolver지시어를 설정하지 않은 경우에 발생합니다.CDN 타임아웃 — Cloudflare는 Free/Pro/Business 플랜에서 100초의 엄격한 제한이 있습니다. 오리진이 100초 이상 걸리면 Nginx 설정과 관계없이 Cloudflare가 Error 524를 반환합니다.
DDoS 공격 — 대량의 요청이 서버 리소스를 소모하여 프록시의 타임아웃 시간 내에 정상 트래픽에 응답하기 어렵게 만듭니다.
방문자를 위한 504 오류 해결 방법
다른 사람의 웹사이트에서 504 오류가 표시된다면, 문제는 해당 서버 쪽에 있으며 여러분의 기기 문제가 아닙니다. 하지만 몇 가지 시도해 볼 수 있는 방법이 있습니다.
기다렸다가 새로고침 — 대부분의 504 오류는 일시적입니다. 30~60초 기다린 후
Ctrl+Shift+R(Windows/Linux) 또는Cmd+Shift+R(Mac)로 강제 새로고침하세요.모든 사용자에게 사이트가 다운되었는지 확인 — DNS Robot의 HTTP 헤더 도구를 사용하여 외부에서 서버의 응답 코드를 확인하세요. 모든 사용자에게 504가 반환되면 서버 측 문제입니다.
시크릿 모드 또는 다른 브라우저로 시도 — 브라우저 확장 프로그램, 캐시된 오류 페이지, 로컬 설정 문제를 배제할 수 있습니다.
다른 네트워크로 시도 — Wi-Fi에서 모바일 데이터로 전환하거나 VPN을 비활성화하세요. ISP와 서버 간 라우팅 문제가 504를 유발할 수 있습니다.
DNS 캐시 초기화 — 오래된 DNS 레코드가 요청을 잘못된 서버로 라우팅할 수 있습니다. Windows:
ipconfig /flushdns. Mac:sudo dscacheutil -flushcache && sudo killall -HUP mDNSResponder.사이트의 상태 페이지나 소셜 미디어 확인 — 알려진 장애나 유지보수 정보가 게시되어 있을 수 있습니다.
해결 방법 1: 타임아웃 설정 늘리기 (Nginx & Apache)
504 오류의 가장 일반적인 해결 방법은 리버스 프록시의 타임아웃 값을 늘리는 것입니다. 백엔드가 기본값인 60초 이상이 정당하게 필요한 경우, 프록시에 더 오래 기다리도록 설정해야 합니다.
# Nginx — reverse proxy to a backend (Node.js, Python, etc.)
location / {
proxy_pass http://backend;
proxy_connect_timeout 300;
proxy_send_timeout 300;
proxy_read_timeout 300;
send_timeout 300;
}
# Nginx — FastCGI (PHP-FPM)
location ~ \.php$ {
fastcgi_pass unix:/var/run/php-fpm.sock;
fastcgi_read_timeout 300;
fastcgi_send_timeout 300;
fastcgi_connect_timeout 300;
include fastcgi_params;
}Apache에서 mod_proxy를 사용하는 경우, VirtualHost에 ProxyTimeout 300을 추가하거나 백엔드별로 ProxyPass / http://backend:8080/ timeout=300을 사용하세요.
중요: 이러한 타임아웃은 전체 전송 시간이 아닌 두 연속 읽기/쓰기 작업 사이의 시간을 측정합니다. proxy_read_timeout 300은 "300초 동안 데이터가 도착하지 않으면"이라는 의미이며, "전체 응답이 300초 이내에 완료되어야 한다"는 의미가 아닙니다. 타임아웃 값을 변경한 후에는 설정을 리로드하세요: sudo nginx -t && sudo systemctl reload nginx.
해결 방법 2: 느린 스크립트와 데이터베이스 쿼리 최적화
백엔드가 지속적으로 타임아웃을 초과한다면, 타임아웃 값을 늘리는 것은 문제를 감추는 것에 불과합니다. 진정한 해결책은 백엔드 응답 속도를 높이는 것입니다.
느린 쿼리 찾기 — MySQL 슬로우 쿼리 로그를 활성화하고(
slow_query_log = 1,long_query_time = 1), 의심되는 쿼리에EXPLAIN ANALYZE를 사용하세요. 누락된 인덱스를 추가하고,SELECT *를 피하고, 큰 결과 세트를 페이지네이션하세요.캐싱 추가 — Redis 또는 Memcached를 사용하여 비용이 큰 쿼리 결과를 캐싱하세요. 매번 페이지 로드마다 5초 걸리는 쿼리는 캐싱해야 합니다.
무거운 작업을 백그라운드 작업으로 이동 — 보고서 생성, 이메일 발송, 이미지 처리, 데이터 가져오기는 작업 큐(Celery, Sidekiq, Bull)에서 실행하고, HTTP 요청 사이클 내에서 수행하지 마세요.
API 호출 최적화 — 백엔드가 느린 서드파티 API를 호출하는 경우, 해당 호출에 타임아웃을 추가하고 하나의 느린 API가 모든 요청을 차단하지 않도록 서킷 브레이커를 구현하세요.
N+1 쿼리 줄이기 — ORM이 생성하는 쿼리는 수백 개의 개별 데이터베이스 호출을 만들 수 있습니다. 즉시 로딩(Eager loading) 또는 배치 쿼리를 사용하여 라운드 트립을 줄이세요.
해결 방법 3: 서버 리소스 확인 (CPU, RAM, 디스크)
오리진 서버가 과부하 상태이면 요청을 충분히 빠르게 처리할 수 없고, 프록시가 대기하다 타임아웃됩니다. 무엇이 리소스를 소모하고 있는지 확인하세요.
# Check CPU and memory usage
top -bn1 | head -20
# Check disk space (full disk = silent failures)
df -h
# Check memory details
free -m
# Find processes using the most CPU
ps aux --sort=-%cpu | head -10
# Find processes using the most memory
ps aux --sort=-%mem | head -10
# Check active network connections
ss -sCPU 또는 RAM이 90% 이상이라면 애플리케이션을 최적화하거나, 폭주하는 프로세스를 종료하거나, 서버를 업그레이드해야 합니다. 디스크 공간이 가득 찼다면 오래된 로그 파일, 백업, 임시 파일을 정리하세요. 디스크가 가득 차면 데이터베이스가 조용히 크래시되어 연쇄적인 504 오류를 유발할 수 있습니다.
해결 방법 4: 오류 로그 확인
오류 로그는 프록시가 504를 반환한 정확한 이유를 알려줍니다. 원인을 추측하기 전에 항상 로그를 먼저 확인하세요.
# Nginx error log (look for "upstream timed out")
tail -50 /var/log/nginx/error.log
# Apache error log
tail -50 /var/log/apache2/error.log # Debian/Ubuntu
tail -50 /var/log/httpd/error_log # CentOS/RHEL
# PHP-FPM log
tail -50 /var/log/php8.2-fpm.log
# System log (OOM kills, crashes)
tail -50 /var/log/syslog504를 유발하는 일반적인 로그 메시지:
"upstream timed out (110: Connection timed out)" (Nginx) — 업스트림 서버가 proxy_read_timeout 내에 응답하지 않았습니다. 타임아웃을 늘리거나 느린 업스트림을 수정하세요.
"server reached pm.max_children" (PHP-FPM) — 모든 PHP 워커 프로세스가 사용 중입니다. PHP-FPM 풀 설정에서 pm.max_children을 늘리세요.
"connect() failed (111: Connection refused)" (Nginx) — 업스트림 서버가 실행 중이 아니거나 예상 포트에서 수신 대기하지 않습니다. 백엔드를 재시작하세요.
"Too many connections" (MySQL) — 데이터베이스 연결 제한이 소진되었습니다. MySQL 설정에서 max_connections를 늘리거나 커넥션 풀링을 최적화하세요.
해결 방법 5: PHP-FPM 설정 조정
PHP 기반 애플리케이션(WordPress, Laravel, Magento)에서는 PHP-FPM이 흔한 병목 지점입니다. 타임아웃 체인은 일관성이 있어야 합니다: Nginx 타임아웃 ≥ PHP-FPM 타임아웃 ≥ PHP max_execution_time.
| 설정 | 파일 | 기본값 | 권장값 |
|---|---|---|---|
| max_execution_time | php.ini | 30초 | 120~300초 |
| request_terminate_timeout | PHP-FPM 풀 설정 | 0 (max_execution_time 사용) | max_execution_time과 동일하게 |
| pm.max_children | PHP-FPM 풀 설정 | 5 | RAM 기준: (총 RAM - 1GB) / 40MB |
| pm.max_requests | PHP-FPM 풀 설정 | 0 (무제한) | 500~1000 (메모리 누수 방지) |
| fastcgi_read_timeout | nginx.conf | 60초 | ≥ max_execution_time |
PHP-FPM 설정을 변경한 후에는 서비스를 재시작하세요: sudo systemctl restart php8.2-fpm. Nginx의 fastcgi_read_timeout은 항상 PHP의 max_execution_time보다 크거나 같게 설정해야 합니다. 그렇지 않으면 PHP가 완료되기 전에 Nginx가 포기하여 504가 발생합니다.
해결 방법 6: CDN 및 프록시 설정 확인
사이트가 Cloudflare나 AWS CloudFront 같은 CDN 뒤에 있다면, CDN에는 서버 설정을 재정의할 수 있는 자체 타임아웃 설정이 있습니다.
| CDN / 프록시 | 기본 타임아웃 | 최대 설정 가능 | 참고 |
|---|---|---|---|
| Cloudflare Free | 100초 | 100초 (고정) | 504가 아닌 Error 524 반환 |
| Cloudflare Pro | 100초 | 100초 (고정) | Free와 동일 — 변경 불가 |
| Cloudflare Business | 100초 | 100초 (고정) | 동일한 제한 적용 |
| Cloudflare Enterprise | 100초 | 6,000초 | Cache Rules를 통해 설정 가능 |
| AWS CloudFront | 30초 | 180초 | 배포 오리진 설정에서 설정 |
| AWS ALB | 60초 | 설정 가능 | 유휴 타임아웃으로 설정 |
| GCP Load Balancer | 30초 | 사실상 제한 없음 | 백엔드 서비스 타임아웃으로 설정 |
Cloudflare 사용자: Free, Pro, Business 플랜을 사용하고 오리진이 100초 이상 걸리면 항상 Error 524가 반환됩니다. 선택지는 백엔드를 100초 이내에 응답하도록 최적화하거나, 장시간 작업을 백그라운드 작업으로 이동하거나, Enterprise로 업그레이드하는 것입니다.
AWS CloudFront 사용자: 배포의 오리진 설정에서 오리진 응답 타임아웃을 늘리세요. 기본 30초는 동적 콘텐츠에는 너무 짧은 경우가 많습니다.
DNS Robot의 HTTP 헤더 도구를 사용하여 응답 헤더를 확인하고 어느 레이어가 504를 반환하는지 식별하세요. server: cloudflare, server: awselb/2.0, server: nginx 같은 헤더로 프록시를 특정할 수 있습니다.
해결 방법 7: WordPress 전용 솔루션
WordPress 사이트는 무거운 플러그인, 데이터베이스 비대화, 공유 호스팅 제한으로 인해 504 오류가 특히 발생하기 쉽습니다. WordPress에 특화된 해결 방법을 소개합니다.
느린 플러그인 찾기 — 모든 플러그인을 비활성화한 후 하나씩 다시 활성화하세요. wp-admin에 접근할 수 없으면 SSH를 통해
plugins폴더 이름을 변경하세요:mv wp-content/plugins wp-content/plugins_disabled. Query Monitor 플러그인을 사용하여 느린 데이터베이스 쿼리를 식별하세요.PHP 메모리 늘리기 —
wp-config.php에define('WP_MEMORY_LIMIT', '512M');을 추가하세요. 많은 플러그인이 기본 128MB 이상을 필요로 합니다.캐싱 플러그인 설치 — WP Super Cache, W3 Total Cache 또는 WP Rocket은 매 요청마다 PHP를 실행하는 대신 정적 HTML을 제공하여 서버 측 처리를 줄입니다.
오브젝트 캐싱 사용 — Redis 또는 Memcached와 WordPress 오브젝트 캐시 플러그인을 설치하세요. 데이터베이스 쿼리 결과를 메모리에 캐싱하여 MySQL 부하를 줄입니다.
데이터베이스 정리 — 오래된 게시물 수정본, 트랜지언트, 스팸 댓글, 고아 메타데이터를 삭제하세요. WP-Optimize 또는 WP-Sweep을 사용하세요.
wp-config.php에define('WP_POST_REVISIONS', 5);를 추가하여 향후 수정본 수를 제한하세요.wp-cron 비활성화 — WordPress의 가상 cron은 모든 페이지 로드 시 실행되어 작업이 쌓일 수 있습니다.
wp-config.php에define('DISABLE_WP_CRON', true);를 추가하고 실제 서버 cron 작업을 설정하세요:*/5 * * * * curl -s https://yoursite.com/wp-cron.php > /dev/null 2>&1.
504 vs 502 vs 503 vs 408: 차이점은?
이러한 HTTP 오류 코드는 종종 혼동됩니다. 각각의 정확한 의미를 알아보겠습니다.
| 코드 | 이름 | 발생 원인 | 프록시 필요? |
|---|---|---|---|
| 408 | Request Timeout | 클라이언트가 서버에 요청을 보내는 데 너무 오래 걸림 | 아니오 — 서버가 클라이언트를 타임아웃 |
| 502 | Bad Gateway | 프록시가 업스트림으로부터 잘못된 응답을 수신 | 예 |
| 503 | Service Unavailable | 서버가 과부하 또는 유지보수 중으로 요청 처리 불가 | 아니오 — 모든 서버가 반환 가능 |
| 504 | Gateway Timeout | 프록시가 타임아웃 내에 업스트림으로부터 응답을 받지 못함 | 예 |
| 524 | A Timeout Occurred | Cloudflare가 오리진에 연결했지만 100초 내에 HTTP 응답을 받지 못함 | Cloudflare 전용 (비표준) |
핵심 차이점: 502는 프록시가 잘못된 응답을 받은 것이고, 504는 프록시가 응답을 전혀 받지 못한 것입니다. 503은 프록시가 필요하지 않으며, 과부하 시 어떤 서버든 반환할 수 있습니다. 408은 클라이언트 측 타임아웃(4xx 클래스)으로, 서버가 클라이언트의 요청 전송을 기다리다 포기한 경우입니다.
502와 504가 동시에 발생하면, 업스트림 서버가 크래시되고 있을 가능성이 높습니다. 502는 프록시가 죽어가는 프로세스로부터 부분적이거나 손상된 응답을 받을 때 발생하고, 504는 프로세스가 완전히 무응답 상태일 때 발생합니다.
504 오류가 SEO에 미치는 영향
간단히 말하면: 짧은 504는 SEO에 영향이 없습니다. 장기간의 504는 색인 삭제를 유발할 수 있습니다.
수 분~수 시간: 영향 없음. Google은 일시적인 서버 오류를 이해하며 즉시 패널티를 부과하지 않습니다. 장애 중에 Googlebot이 크롤링하지 않았다면 알아차리지도 못합니다.
수 시간~수 일: Google은 부하를 가중시키지 않기 위해 5xx 오류를 반환하는 사이트의 크롤 빈도를 줄입니다. Google Search Console의 페이지 인덱싱 보고서에서 '서버 오류(5xx)'로 표시될 수 있습니다.
수 일~수 주: 지속적인 504 오류는 영향받는 페이지의 색인 삭제로 이어질 수 있습니다. 순위가 크게 하락합니다. Google의 John Mueller에 따르면, 서버가 하루 동안 다운되면 복구 후 1~3주 동안 상황이 '불안정'할 수 있습니다.
복구: 서버가 안정되면 Google은 자동으로 페이지를 다시 크롤링하고 재색인합니다. Google Search Console의 URL 검사 도구를 사용하여 중요한 페이지의 재색인을 요청하세요. 복구 시간은 사이트 규모와 오류 지속 기간에 따라 달라집니다.
504 Gateway Timeout을 예방하는 방법
예방이 사후 대응보다 항상 낫습니다. 타임아웃 제한 내에서 서버를 안정적으로 운영하기 위한 모범 사례를 소개합니다.
모니터링 설정 — 가동 시간 모니터링(UptimeRobot, Pingdom 또는 DNS Robot의 Ping 도구)을 사용하여 사용자가 보고하기 전에 504 오류를 감지하세요.
타임아웃 체인 일치시키기 — CDN 타임아웃 ≥ 프록시 타임아웃 ≥ 애플리케이션 타임아웃이 되도록 하세요. 불일치한 값은 예측할 수 없는 504 오류를 유발합니다.
헬스 체크 구현 — 로드 밸런서와 프록시는 업스트림 서버를 헬스 체크하고, 응답하지 않는 인스턴스에서 트래픽을 우회시켜야 합니다.
캐싱을 적극 활용 — 정적 자산, API 응답, 데이터베이스 쿼리를 캐싱하세요. 캐시된 응답은 504를 유발할 만큼 느려지지 않습니다.
오토스케일링 적용 — 수평 확장(인스턴스 추가)을 사용하여 트래픽 급증이 단일 서버를 압도하지 않도록 하세요.
무거운 작업 오프로드 — 파일 처리, 보고서 생성, 이메일 발송, 대량 가져오기는 백그라운드 작업 큐로 이동하세요. HTTP 요청 내에서 비용이 큰 작업을 수행하지 마세요.
느린 쿼리 모니터링 — MySQL/PostgreSQL에서 슬로우 쿼리 로깅을 활성화하세요. 1초를 초과하는 쿼리에 대해 알림을 설정하세요.
의존성 건전성 유지 — 백엔드가 의존하는 서드파티 API를 모니터링하세요. 하나의 느린 API가 모든 사용자에게 504 오류를 연쇄적으로 유발하지 않도록 타임아웃과 서킷 브레이커를 추가하세요.
서버 응답 코드 확인하기
DNS Robot의 HTTP 헤더 도구를 사용하여 서버의 HTTP 상태 코드, 응답 헤더, 타이밍을 확인하고 504 오류를 디버깅하세요.
Try HTTP Headers CheckerFrequently Asked Questions
504 Gateway Timeout은 프록시 또는 게이트웨이 서버(Nginx, Cloudflare, 로드 밸런서 등)가 업스트림/오리진 서버의 응답을 기다렸지만, 업스트림 서버가 너무 오래 걸려 프록시가 대기를 포기하고 브라우저에 504 오류를 반환한 것을 의미합니다.