WordPress 503 Servicio no disponible: qué comprobar cuando el sitio está caído

¿Te fue útil?

503 es el sonido que hace un sitio web cuando no puede cumplir sus promesas. Tus usuarios ven una página en blanco, el equipo de marketing ve ingresos perdidos y tú ves un ticket que dice “sitio caído” con exactamente cero detalles útiles.

Esta guía es cómo cortar el ruido. No folklore de “limpia tu caché”. Comprobaciones reales, comandos que puedes ejecutar y decisiones que puedes tomar mientras el reloj de la incidencia corre.

Qué significa realmente un 503 (y qué no significa)

Un 503 “Service Unavailable” no es un único error. Es una clase de fallos donde un componente en la ruta de la petición no puede servirla ahora mismo. La frase clave es “ahora mismo”: el sistema está lo bastante vivo para responder, pero lo bastante malsano para rechazar, agotar el tiempo o descargar carga.

En el ecosistema WordPress, el 503 suele surgir de uno de estos puntos de estrangulamiento:

  • Proxy/CDN frontal (Cloudflare, Fastly, ALB/ELB, Nginx): el origen está caído o demasiado lento, fallan checks de salud, errores en upstream.
  • Servidor web (Nginx/Apache): no puede alcanzar el upstream, demasiados archivos abiertos, límites de workers, saturación de colas.
  • Runtime de la aplicación (PHP-FPM): el gestor de procesos al límite, solicitudes lentas, workers bloqueados, kills por OOM.
  • Base de datos (MySQL/MariaDB): conexiones máximas alcanzadas, disco lleno, consultas de larga duración, replicación retrasada si se separan lecturas.
  • Almacenamiento (disco local, NFS, EBS): picos de latencia, I/O wait, agotamiento de inodos, problemas de permisos tras despliegues.
  • Dependencias externas (SMTP, API de pagos, búsqueda): tema/plugin de WordPress bloqueándose en llamadas remotas.

Dos falsedades importantes:

  • 503 no es “WordPress está roto”. WordPress puede estar bien; la plataforma alrededor puede ser la que esté fallando estrepitosamente.
  • 503 no es “CPU alta”. Una CPU alta puede provocarlo, pero también lo pueden causar discos lentos, un resolvedor DNS bloqueado o un plugin que hace algo que no debe.

Una cita que vale la pena tener sobre tu monitor durante incidentes: paraphrased idea de John Allspaw: el sistema te está contando una historia; busca la narrativa, no un chivo expiatorio.

Broma #1: Un 503 es la manera que tiene tu servidor de decir “estoy ocupado” sin comprometerse con un plazo—básicamente soporte técnico, pero con cabeceras HTTP.

Guion de diagnóstico rápido (primero/segundo/tercero)

Cuando el sitio está caído, no necesitas un análisis profundo al principio. Necesitas un embudo que te lleve al cuello de botella en minutos. Esta es la secuencia que funciona en incidentes reales.

Primero: confirma dónde se genera el 503 (edge vs origen)

  1. Comprueba desde fuera: ¿recibes 503 desde el CDN/load balancer o desde tu origen?
  2. Comprueba desde dentro: haz curl al origen directamente (o al VIP del servicio) desde una máquina en la misma red.
  3. Decisión: Si el edge devuelve 503 pero el origen está bien, céntrate en checks de salud, reglas WAF, conectividad del origen, TLS o timeouts upstream. Si el origen devuelve 503 también, profundiza más.

Segundo: decide si estás limitado por capacidad o roto

  1. Mira carga, memoria y disco en el origen: ¿el servidor está thrashing, intercambiando, con I/O wait o sin espacio?
  2. Decisión: Si estás limitado por recursos, mitiga primero (escalar, reiniciar con cuidado, descargar carga) y luego investiga la causa raíz después de que el servicio vuelva.

Tercero: sigue la ruta de la petición, salto a salto

  1. Logs del servidor web: ¿las peticiones llegan a Nginx/Apache y qué errores upstream aparecen?
  2. Estado de PHP-FPM: ¿están saturadas las pools, hay workers atascados, aparecen slow logs?
  3. Salud de la base de datos: conexiones, consultas lentas, locks, disco y presión en el buffer pool.
  4. Decisión: Una vez que encuentres el primer componente que falla (no el último que se queja), has encontrado la perilla de control de la incidencia.

Regla de velocidad: si no puedes explicar el 503 tras 10 minutos, probablemente estás mirando la capa equivocada. Mueve un salto arriba o abajo en la cadena.

Hechos y contexto interesantes (rápido pero útil)

  • HTTP 503 tiene una intención “honesta”: está diseñado para ser temporal y puede incluir un encabezado Retry-After para clientes bien comportados.
  • 503 se usa comúnmente para modo mantenimiento porque le dice a los buscadores “no indexéis esto como un fallo permanente”, a diferencia de un 404.
  • Muchos proxies emiten 503 por problemas upstream incluso cuando el origen habría devuelto 504 o 500—tu código de error puede ser una traducción, no una verdad absoluta.
  • Nginx devuelve 502/504 para muchos fallos upstream, pero ciertas configuraciones o balanceadores intermedios pueden mostrarlos como 503 en su lugar.
  • WordPress raramente emite un 503 en crudo; típicamente es la capa web, PHP-FPM o la ruta fatal de un plugin la que provoca que el servidor no pase checks de salud.
  • PHP-FPM ha sido la palanca de escalado por defecto para WordPress en muchas pilas desde principios de los 2010s porque desacopla los workers PHP del modelo de procesos del servidor web.
  • “Thundering herd” no es teórico: una expiración de caché al mismo segundo en muchos nodos puede causar una estampida sincronizada, empujando PHP-FPM al territorio 503.
  • Algunas plataformas gestionadas de WordPress devuelven 503 intencionalmente para proteger infra compartida bajo carga, prefiriendo disponibilidad parcial a un colapso total.

Preguntas de triaje que reducen el radio del impacto

Haz estas preguntas antes de empezar a reiniciar cosas como si fueran una máquina tragaperras.

  • ¿Son todas las páginas o solo algunas? Si solo falla el admin o el checkout, piensa en sesiones, locks de base de datos o APIs externas.
  • ¿Son todas las regiones o una sola? Si solo falla una región, sospecha de enrutamiento, DNS o un problema zonal de almacenamiento.
  • ¿Cambió algo? Despliegues, actualizaciones de plugins, ediciones de tema, subidas de versión PHP, cambios de regla WAF, rotación de certificados.
  • ¿Es por carga? Pico de tráfico, ola de bots o un cron que se ejecuta a la hora en punto y convierte la base de datos en puré.
  • ¿Es intermitente? Los 503 intermitentes huelen a saturación: límites de workers, pools de conexiones o I/O lento.

El objetivo es escoger una hipótesis que puedas refutar rápidamente. La respuesta a incidentes es básicamente ciencia, pero con más café y menos becas.

Tareas prácticas: comandos, salidas, decisiones (12+)

A continuación hay tareas prácticas que puedes ejecutar en un origen Linux típico de WordPress (Nginx + PHP-FPM + MySQL/MariaDB). Ajusta los nombres de servicio para tu distro. Cada tarea incluye: comando, salida de ejemplo, qué significa y qué haces después.

Tarea 1: Verificar el síntoma desde el exterior (código de estado + cabeceras)

cr0x@server:~$ curl -sS -o /dev/null -D - https://example.com | sed -n '1,20p'
HTTP/2 503
date: Thu, 26 Dec 2025 10:12:41 GMT
content-type: text/html; charset=UTF-8
server: cloudflare
cf-ray: 88c0a1b8f9c01234-AMS

Significado: La respuesta se genera en el edge (server: cloudflare). Aún no sabes si el origen está caído o si el edge no puede alcanzarlo.

Decisión: Prueba el origen directamente (Tarea 2). Si el origen está sano, investiga conectividad CDN/origen, firewall, TLS o checks de salud.

Tarea 2: Curl al origen directamente (omitir CDN)

cr0x@server:~$ curl -sS -o /dev/null -D - -H 'Host: example.com' http://127.0.0.1/ | sed -n '1,15p'
HTTP/1.1 503 Service Temporarily Unavailable
Server: nginx
Date: Thu, 26 Dec 2025 10:13:02 GMT
Content-Type: text/html
Content-Length: 190
Connection: keep-alive

Significado: El propio origen está devolviendo 503 (nginx). Ahora estás en la pila del origen: Nginx, PHP-FPM, app, base de datos, almacenamiento.

Decisión: Salta a los logs del servidor web y a la salud del upstream (Tareas 6–8).

Tarea 3: Comprobar presión básica del host (load, memoria, swap)

cr0x@server:~$ uptime
 10:13:12 up 23 days,  4:01,  2 users,  load average: 18.42, 17.90, 16.55

Significado: El load average es muy alto. Eso puede ser saturación de CPU, I/O wait o explosión de la cola de procesos por demasiados procesos ejecutables.

Decisión: Confirma si la carga es CPU o I/O (Tarea 4) antes de aumentar ciegamente los workers de PHP (lo que puede empeorar la situación).

Tarea 4: Identificar CPU vs I/O wait (vmstat)

cr0x@server:~$ vmstat 1 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
16  4      0  32120  11244 622144    0    0   120  3400 2200 6100 15  8 20 57  0
18  3      0  29804  10980 615332    0    0    90  4100 2400 6500 12  7 18 63  0
20  5      0  28512  10820 612110    0    0   110  5200 2500 6900 10  6 14 70  0
15  2      0  31040  11100 620400    0    0    95  3800 2100 6000 14  7 22 57  0
17  4      0  29520  10920 614880    0    0   105  4600 2450 6700 11  6 16 67  0

Significado: El wa alto (I/O wait) indica que las CPUs están mayormente esperando al disco/almacenamiento de red. La columna “b” (bloqueados) también está elevada.

Decisión: Investiga latencia de disco y presión del sistema de archivos (Tareas 5 y 14). No “arregles” esto añadiendo hijos de PHP-FPM; solo crearás más procesos bloqueados.

Tarea 5: Comprobar espacio en disco y agotamiento de inodos

cr0x@server:~$ df -hT /
Filesystem     Type  Size  Used Avail Use% Mounted on
/dev/nvme0n1p2  ext4   40G   39G  520M  99% /

Significado: Estás básicamente sin espacio en disco. Muchos servicios fallan de formas extrañas cuando no pueden escribir logs, archivos temporales o sockets.

Decisión: Libera espacio inmediatamente (rotar logs, borrar grandes temporales, mover backups), luego vuelve a probar. Si es agotamiento de inodos, comprueba la Tarea 5b:

cr0x@server:~$ df -i /
Filesystem      Inodes  IUsed   IFree IUse% Mounted on
/dev/nvme0n1p2  2621440 2619900   1540  100% /

Significado: Agotamiento de inodos: demasiados archivos pequeños (directorios de caché, sesiones, variantes de imágenes). WordPress más un plugin de caché agresivo puede provocarlo.

Decisión: Purga los directorios de caché y almacenamiento de sesiones; considera mover la caché a tmpfs o almacenamiento de objetos a largo plazo.

Tarea 6: Revisar el log de errores de Nginx en busca de pistas upstream

cr0x@server:~$ sudo tail -n 30 /var/log/nginx/error.log
2025/12/26 10:12:58 [error] 22114#22114: *98123 connect() to unix:/run/php/php8.2-fpm.sock failed (11: Resource temporarily unavailable) while connecting to upstream, client: 203.0.113.10, server: example.com, request: "GET / HTTP/1.1", upstream: "fastcgi://unix:/run/php/php8.2-fpm.sock:", host: "example.com"
2025/12/26 10:13:01 [error] 22114#22114: *98145 upstream timed out (110: Connection timed out) while reading response header from upstream, client: 198.51.100.42, server: example.com, request: "GET /wp-admin/ HTTP/1.1", upstream: "fastcgi://unix:/run/php/php8.2-fpm.sock:", host: "example.com"

Significado: Nginx no puede conectar con el socket de PHP-FPM a veces y en otras ocasiones agota el tiempo. Esto suele ser saturación de PHP-FPM, workers atascados o problemas de backlog del socket.

Decisión: Inspecciona la salud del servicio PHP-FPM y el estado de las pools (Tareas 7–9). Si PHP-FPM está caído, reinícialo; si está arriba pero saturado, encuentra la ruta lenta.

Tarea 7: Verificar si PHP-FPM está en ejecución y estable

cr0x@server:~$ systemctl status php8.2-fpm --no-pager
● php8.2-fpm.service - The PHP 8.2 FastCGI Process Manager
     Loaded: loaded (/lib/systemd/system/php8.2-fpm.service; enabled; preset: enabled)
     Active: active (running) since Thu 2025-12-26 09:02:11 UTC; 1h 11min ago
       Docs: man:php-fpm8.2(8)
   Main PID: 1032 (php-fpm8.2)
     Status: "Processes active: 64, idle: 0, Requests: 92314, slow: 387, Traffic: 0.0req/sec"
      Tasks: 65 (limit: 18922)
     Memory: 2.4G
        CPU: 1h 03min

Significado: “idle: 0” con muchos procesos activos sugiere saturación completa. Si tu pool tiene max children 64, has alcanzado el techo.

Decisión: No aumentes max children hasta que la máquina colapse. Primero determina por qué los workers son lentos (Tarea 9) y si la base de datos o el almacenamiento son el verdadero cuello de botella (Tareas 11–14).

Tarea 8: Comprobar el socket de PHP-FPM y el backlog de escucha

cr0x@server:~$ sudo ss -xlpn | grep php
u_str LISTEN 0      128    /run/php/php8.2-fpm.sock  22139            * 0 users:(("php-fpm8.2",pid=1032,fd=8))

Significado: El backlog del socket es 128. Si ves muchas conexiones pendientes o errores como “Resource temporarily unavailable”, el backlog y la disponibilidad de procesos importan.

Decisión: Si el backlog es demasiado pequeño para tus ráfagas, ajusta listen.backlog y el kernel somaxconn después. Ahora, encuentra por qué los workers no se liberan.

Tarea 9: Habilitar/inspeccionar el slow log de PHP-FPM (encuentra la ruta de código lenta)

cr0x@server:~$ sudo tail -n 30 /var/log/php8.2-fpm/slow.log
[26-Dec-2025 10:12:55]  [pool www] pid 11844
script_filename = /var/www/example.com/public/index.php
[0x00007f6b2c2f81f0] mysqli_query() /var/www/example.com/public/wp-includes/wp-db.php:2050
[0x00007f6b2c2f7f20] query() /var/www/example.com/public/wp-includes/wp-db.php:1941
[0x00007f6b2c2f7c50] get_results() /var/www/example.com/public/wp-includes/wp-db.php:2970
[0x00007f6b2c2f6a10] get_posts() /var/www/example.com/public/wp-includes/post.php:2543
[0x00007f6b2c2f51a0] WP_Query->get_posts() /var/www/example.com/public/wp-includes/class-wp-query.php:3604

Significado: Los workers están atascados en consultas MySQL. El 503 es un síntoma a nivel de aplicación de un problema de base de datos (o latencia de almacenamiento que hace lenta la base de datos).

Decisión: Cambia el foco a la salud de la base de datos y al comportamiento de las consultas (Tareas 11–13). Reiniciar PHP-FPM no arreglará una base de datos que está ahogándose; solo restablece la cola brevemente.

Tarea 10: Verificar que el cron de WordPress no esté causando estampidas

cr0x@server:~$ sudo tail -n 50 /var/log/syslog | grep -E 'wp-cron|cron' | tail -n 10
Dec 26 10:00:01 server CRON[21780]: (www-data) CMD (/usr/bin/php /var/www/example.com/public/wp-cron.php)
Dec 26 10:00:02 server CRON[21795]: (www-data) CMD (/usr/bin/php /var/www/example.com/public/wp-cron.php)
Dec 26 10:00:03 server CRON[21810]: (www-data) CMD (/usr/bin/php /var/www/example.com/public/wp-cron.php)

Significado: Varias invocaciones de cron consecutivas pueden acumularse, especialmente si un trabajo es lento o se solapan. El cron de WordPress es famoso por ser “útil” en el peor momento.

Decisión: Deshabilita temporalmente el disparo de WP cron vía peticiones web y pásalo a un cron del sistema único más tarde. Durante la incidencia, para la estampida y vuelve a comprobar la carga.

Tarea 11: Comprobar maxi conexiones de la base de datos y presión de hilos

cr0x@server:~$ mysql -e "SHOW GLOBAL STATUS LIKE 'Threads_connected'; SHOW GLOBAL VARIABLES LIKE 'max_connections';"
+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| Threads_connected | 298   |
+-------------------+-------+
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| max_connections | 300   |
+-----------------+-------+

Significado: Estás en el techo de conexiones. Nuevas peticiones se encolan o fallan; componentes upstream pueden producir 503 dependiendo de cómo manejen timeouts.

Decisión: Identifica quién mantiene las conexiones (Tarea 12) y por qué. La mitigación a corto plazo puede ser reiniciar clientes descontrolados o aumentar max connections si la memoria lo permite, pero arreglar el comportamiento de las consultas es el trabajo real.

Tarea 12: Encontrar consultas largas y locks

cr0x@server:~$ mysql -e "SHOW FULL PROCESSLIST;" | head -n 20
Id	User	Host	db	Command	Time	State	Info
421	wpuser	10.0.2.15:51244	wpdb	Query	87	Sending data	SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts WHERE 1=1 AND wp_posts.post_type = 'post' ORDER BY wp_posts.post_date DESC LIMIT 0, 10
422	wpuser	10.0.2.15:51262	wpdb	Query	90	Locked	UPDATE wp_options SET option_value = '...' WHERE option_name = 'rewrite_rules'
430	wpuser	10.0.2.15:51410	wpdb	Sleep	220		NULL

Significado: Tienes consultas atascadas (“Locked”) y selects de larga duración. Actualizaciones en la tabla de opciones (como rewrite_rules) pueden bloquear y bloquear peticiones a nivel global.

Decisión: Si una consulta concreta está bloqueando el mundo, puede que necesites matarla quirúrgicamente y desactivar el plugin/tema/acción que la provoca. Matar consultas al azar es cómo se crean incidentes secundarios.

Tarea 13: Comprobar señales del slow query log de MySQL (si está activado)

cr0x@server:~$ sudo tail -n 20 /var/log/mysql/slow.log
# Time: 2025-12-26T10:12:41.123456Z
# User@Host: wpuser[wpuser] @ 10.0.2.15 []
# Query_time: 5.882  Lock_time: 1.204 Rows_sent: 10  Rows_examined: 890221
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts WHERE 1=1 AND wp_posts.post_type = 'post' ORDER BY wp_posts.post_date DESC LIMIT 0,10;

Significado: Rows examined es enorme para un conjunto de resultados pequeño. Eso es un problema de índices, una consulta sin límite o un plugin que hace “búsqueda” de forma ineficiente.

Decisión: Aplica arreglos de índices y refactoriza consultas después de la recuperación. Durante la incidencia, reduce la carga (cachea, limita bots, deshabilita la funcionalidad) y mantén la base de datos respirando.

Tarea 14: Comprobar latencia de almacenamiento y I/O wait a nivel de dispositivo (iostat)

cr0x@server:~$ iostat -xz 1 3
Linux 6.1.0 (server) 	12/26/2025 	_x86_64_	(8 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
          12.31    0.00    6.22   58.44    0.00   23.03

Device            r/s     rkB/s   rrqm/s  %rrqm r_await rareq-sz     w/s     wkB/s   wrqm/s  %wrqm w_await wareq-sz  aqu-sz  %util
nvme0n1         42.00   1800.00     0.00   0.00   12.40    42.86  210.00  86000.00   120.00  36.36   95.20   409.52   20.10  99.80

Significado: Write await es muy alto y el dispositivo está ~100% utilizado. Cuando el almacenamiento está saturado, los workers PHP se paran, la base de datos se atasca y Nginx empieza a devolver timeouts/503 upstream.

Decisión: Identifica qué está escribiendo (logs, backups, vaciados de BD). Pausa I/O no esencial (backups, cron jobs, indexación) y considera mover uploads/caché a volúmenes separados más tarde.

Tarea 15: Comprobar si el kernel está matando procesos (OOM)

cr0x@server:~$ sudo dmesg -T | tail -n 20
[Thu Dec 26 10:11:33 2025] Out of memory: Killed process 11844 (php-fpm8.2) total-vm:2145120kB, anon-rss:612000kB, file-rss:0kB, shmem-rss:0kB, UID:33 pgtables:1920kB oom_score_adj:0

Significado: Workers de PHP-FPM están siendo OOM-killed. Eso puede manifestarse como 503 intermitentes a medida que la capacidad cae y se recupera.

Decisión: Mitiga reduciendo max children de PHP-FPM, arreglando fugas de memoria (plugins), incrementando memoria con cautela y añadiendo swap solo con intención.

Tarea 16: Comprobar conexiones activas del servidor web y tasa de peticiones

cr0x@server:~$ sudo ss -s
Total: 2345 (kernel 0)
TCP:   1988 (estab 612, closed 1201, orphaned 0, timewait 1103)

Transport Total     IP        IPv6
RAW	  0         0         0
UDP	  14        12        2
TCP	  787       735       52
INET	  801       747       54
FRAG	  0         0         0

Significado: Mucho timewait y alto total de conexiones pueden indicar ráfagas, bots, mala configuración de keepalive o comportamiento del balanceador de carga.

Decisión: Si el tráfico es de tipo ataque, limita la tasa en el edge o en Nginx. Si es tráfico normal, asegúrate de que los límites de workers y descriptores de archivo no sean demasiado bajos.

Tarea 17: Confirmar límites de descriptores de archivo (causa clásica oculta de 503)

cr0x@server:~$ sudo cat /proc/$(pidof nginx | awk '{print $1}')/limits | grep -i "open files"
Max open files            1024                 1024                 files

Significado: 1024 archivos abiertos para Nginx es poco para un sitio con tráfico (conexiones, logs, archivos temporales). Al alcanzarlo obtienes errores upstream extraños y accepts fallidos.

Decisión: Aumenta límites vía overrides de systemd y la configuración de Nginx. Durante un incidente, reducir conexiones (rate-limit/bots) puede comprar tiempo.

Tarea 18: Probar rápidamente ejecución PHP sin todo WordPress

cr0x@server:~$ printf '%s\n' '/dev/null
cr0x@server:~$ curl -sS http://127.0.0.1/health.php
ok

Significado: PHP-FPM puede ejecutar un script trivial. Si las páginas de WordPress dan 503 pero esto funciona, el runtime está vivo; el problema probablemente sea el código de WordPress (plugin/tema), la base de datos o el almacenamiento.

Decisión: Si PHP trivial funciona, comprueba la conectividad a la base de datos y deshabilita plugins/temas recientes de forma controlada (ver sección de listas de verificación).

Modos comunes de fallo en pilas WordPress

1) Saturación de la pool de PHP-FPM (más común, menos entendida)

Cuando PHP-FPM se queda sin workers inactivos, las peticiones se encolan en el socket. Nginx espera. Eventualmente se rinde y obtienes 503/504/502 según la configuración y componentes upstream. El usuario ve “Service Unavailable”, tú ves un pantano de workers haciendo algo lento.

Qué lo causa:

  • Consultas de base de datos lentas (índices faltantes, locks de tablas, autoload de options inflado).
  • Almacenamiento lento (uploads en filesystem de red, disco saturado).
  • Llamadas a APIs externas dentro del render de la página (pagos/envíos, píxeles de marketing, fuentes remotas, checks de licencia).
  • Demasiados workers para la RAM disponible provocando OOM y thrash.

Estrategia de arreglo: Primero estabiliza: limita concurrencia, reinicia con gracia si es necesario, limpia caches con cuidado. Luego encuentra la ruta lenta mediante slow logs, processlist de BD y trazas de peticiones.

2) Timeouts upstream del servidor web mal ajustados

Si tus timeouts upstream son demasiado agresivos, peticiones legítimamente lentas se cortan y parecen 503 a los clientes. Si los timeouts son demasiado permisivos, construyes colas enormes y amplificas los fallos.

Regla de opinión: los timeouts deberían reflejar la realidad, no la esperanza. Si las páginas normales tardan 8 segundos, no “arreglas” eso poniendo timeouts de 120 segundos. Arreglas la página.

3) Techo de conexiones de la base de datos o tormentas de locks

WordPress puede generar un número sorprendente de consultas concurrentes bajo carga, especialmente con plugins pesados. Cuando la BD alcanza max connections, nuevas peticiones PHP bloquean o fallan. Eso se propaga como “upstream timed out”, “could not connect” o un 503 de balanceadores que marcan checks de salud como fallidos.

Las tormentas de locks suelen venir de:

  • Plugins que actualizan wp_options con frecuencia.
  • Regeneración de reglas de rewrite por tráfico.
  • Plugins de caché que escriben bajo carga.

4) Latencia de almacenamiento y desastres de inodos

WordPress no es solo PHP y MySQL. Son archivos multimedia, cachés, sesiones y restos de plugins. Cuando el almacenamiento es lento, todo se vuelve lento. Cuando los inodos se agotan, todo se rompe de maneras creativas.

5) El edge devuelve 503 porque los checks de salud fallan

Tu origen puede servir páginas reales pero fallar el endpoint de health check por redirecciones, autenticación o llamadas a dependencias. El load balancer entonces marca el target como no saludable y sirve 503 aunque la app esté mayormente viva.

6) Colapso de plugin/tema tras una actualización

Un solo plugin puede añadir consultas N+1, llamadas remotas o trabajo CPU pesado en cada petición. Bajo tráfico real, eso es una denegación de servicio en cámara lenta que te has pagado tú mismo.

Broma #2: El plugin prometía “impulsar el rendimiento”. Lo hizo—hasta que impulsó tu tasa de errores.

Tres micro-historias del mundo corporativo (porque sigue pasando)

Micro-historia 1: La incidencia causada por una suposición equivocada

Tenían un sitio WordPress delante de un CDN y un load balancer gestionado. Durante un lanzamiento de producto, aparecieron 503. El equipo asumió “el origen está caído” y empezó a reiniciar PHP-FPM y escalar instancias. Ayudaba unos dos minutos cada vez. Los 503 volvían como una invitación recurrente de calendario.

La suposición equivocada fue sutil: trataron el 503 como un error de aplicación. Pero el load balancer era quien lo devolvía, y lo hacía porque fallaban los checks de salud. El endpoint de salud era /, que empezó a redirigir a una ruta geo-específica tras un cambio de marketing. El load balancer no seguía redirecciones. Targets no saludables, 503 instantáneo.

Empeoró porque los reinicios cambiaban el timing y hacían que los checks de salud pasaran intermitentemente. Eso creó la ilusión de arreglos parciales, que llevó a más reinicios, lo que empeoró la estabilidad visible. Todos tenían gráficas. Nadie tenía la gráfica correcta.

La solución fue aburrida: un endpoint dedicado /healthz que devuelve un 200 simple, servido por Nginx sin tocar PHP. Los checks se estabilizaron inmediatamente. Después, el equipo pudo ver el problema real: el tráfico era alto, pero la pila realmente aguantaba bien una vez que se le permitió recibir peticiones.

Micro-historia 2: La optimización que salió mal

Otra empresa intentó “acelerar WordPress” subiendo mucho el pm.max_children de PHP-FPM y bajando los timeouts de Nginx para mantenerlo ágil. El sitio se sintió rápido en staging. En producción llegó el tráfico y la máquina se convirtió en un radiador con un problema de disco.

El aumento de workers multiplicó consultas concurrentes a la base de datos. La BD empezó a volcar páginas sucias constantemente. La utilización del disco se fue al máximo. El I/O wait se disparó. Los workers PHP se apilaron esperando a la BD y los timeouts de Nginx empezaron a cortarlos. El usuario vio 503; el equipo vio “pero aumentamos capacidad”.

Habían optimizado para throughput en papel, ignorando el cuello de botella compartido: I/O de la base de datos en disco. Más concurrencia no significó más finalizaciones. Significó más espera.

La recuperación fue reducir la concurrencia de forma intencional: bajar niños de PHP-FPM para coincidir con la capacidad de la BD, extender timeouts upstream lo justo para evitar reintentos masivos y limitar endpoints caros. Tras apagar el fuego, añadieron caché apropiado y arreglaron las peores consultas. La “optimización” fue una lección sobre cuellos de botella.

Micro-historia 3: La práctica aburrida pero correcta que salvó el día

Una empresa de medios corría WordPress a tráfico alto y estable. Su arma secreta no era una malla de servicios sofisticada. Era disciplina: un endpoint de health check que no tocaba PHP, rotación regular de logs, alertas de capacidad sobre disco e inodos y un runbook de incidentes estándar que todo el mundo realmente usaba.

Una tarde, las tasas de 503 subieron. On-call siguió el runbook: confirmar edge vs origen, comprobar disco, PHP-FPM y conexiones a BD. El uso de disco estaba bien, pero los inodos casi agotados. Un plugin de caché había empezado a generar enormes cantidades de archivos pequeños tras un cambio de configuración. PHP no podía escribir sesiones con fiabilidad y el sitio empezó a lanzar errores y timeouts.

Como tenían alertas de inodos, lo detectaron antes del fallo total. Purgaron el directorio de caché, aplicaron un límite a la generación de archivos de caché y más tarde migraron el almacenamiento de caché a Redis. Los usuarios percibieron un bache, no un titular.

No fue glamuroso. Fue correcto. La corrección rutinaria es como ganas los apagones sin acabar en las redes sociales.

Errores comunes: síntoma → causa raíz → solución

Esta sección evita el patrón de “lo reiniciamos seis veces y ahora está peor”.

503 solo en el CDN, el origen parece bien

  • Síntoma: Cabeceras del edge muestran CDN/load balancer; curl al origen devuelve 200.
  • Causa raíz: Path de health check fallando, IP del origen bloqueada, mismatch TLS, regla WAF o el origen rate-limiteando al edge.
  • Solución: Usa un /healthz dedicado que devuelva 200 sin auth/redirecciones; confirma que el firewall permite IPs del edge; verifica certificado y SNI; consulta logs del edge.

Picos de 503 durante ráfagas de tráfico, luego se recupera

  • Síntoma: 503 intermitentes, errores de timeout upstream en Nginx.
  • Causa raíz: max children de PHP-FPM alcanzado; límite de conexiones BD alcanzado; estampida de caché.
  • Solución: Añade caching que prevenga estampidas, ajusta PHP-FPM para coincidir con CPU/RAM y capacidad de BD, limita rutas botosas y asegúrate de que OPcache esté bien configurado.

503 tras actualizar plugin/tema

  • Síntoma: La caída empieza justo después de la actualización; el admin puede ser inaccesible; los slow logs muestran rutas PHP específicas.
  • Causa raíz: Plugin provoca errores fatales, consumo masivo de memoria o escrituras DB intensas; incompatibilidad con versión PHP.
  • Solución: Desactiva el plugin renombrando su directorio o usando WP-CLI; revierte; fija versiones; introduce staging y despliegues canary.

503s que correlacionan con “Disco 100%” o alto iowait

  • Síntoma: Alto iowait, stalls en MySQL, workers PHP bloqueados.
  • Causa raíz: Job de backup, avalancha de logs, vaciado masivo de BD, almacenamiento en red lento, agotamiento de inodos.
  • Solución: Para/limita I/O ruidoso; mueve escritores pesados fuera del volumen raíz; ajusta comportamiento de flush de la BD; separa uploads/cache; monitoriza latencia, no solo rendimiento.

Reiniciar PHP-FPM “lo arregla” brevemente

  • Síntoma: Mejora inmediata, luego recaída rápida.
  • Causa raíz: Reinicio resetea la cola; el cuello de botella subyacente permanece (BD, almacenamiento, API externa); o hay fuga de memoria que se reconstruye rápido.
  • Solución: Usa la ventana de recuperación para recopilar evidencia: slow logs, processlist, top offenders y limitar la tasa. Luego aborda la causa raíz.

Sólo wp-admin devuelve 503

  • Síntoma: La página principal a veces funciona, el admin falla constantemente.
  • Causa raíz: Las páginas con mayor privilegio activan lógica de plugins más pesada, peticiones no cacheadas o escrituras de sesión; también puede indicar lentitud del proveedor de autenticación.
  • Solución: Desactiva plugins que enganchan en admin; revisa almacenamiento de sesiones; prueba un endpoint PHP mínimo; investiga llamadas externas de auth.

Listas de verificación / plan paso a paso

Checklist A: Triaje de 10 minutos para restaurar el servicio

  1. Localiza el origen del 503: edge vs origen (curl cabeceras; origen directo).
  2. Comprueba salud del host: load, memoria, swap, espacio en disco, inodos.
  3. Mira logs Nginx/Apache: errores de conexión a upstream, timeouts, “too many open files”.
  4. Revisa estado de PHP-FPM: en ejecución, max children alcanzado, actividad en slow log.
  5. Comprueba saturación de BD: threads connected, max connections, processlist locks.
  6. Mitigar:
    • Limitar rutas abusivas/bots en el edge o Nginx.
    • Purgar o precalentar caches críticos si es seguro.
    • Parar jobs background pesados (backups, imports, cron storms).
    • Recargar/reiniciar servicios con gracia solo si entiendes qué estás reseteando.
  7. Verificar recuperación: curl desde origen y desde fuera, comprobar 2–3 páginas clave, vigilar la caída de la tasa de errores.

Checklist B: Desactivar plugin de forma segura cuando wp-admin está caído

Si sospechas seriamente de un plugin y no puedes acceder al admin, hazlo desde el sistema de archivos. Es brusco pero eficaz.

  1. Identifica plugin(s) actualizados recientemente (desde logs de despliegue o mtimes de archivos).
  2. Desactiva renombrando el directorio (WordPress lo ignorará).
  3. Re-prueba el endpoint de salud y la homepage.
  4. Si se recupera, mantén el plugin desactivado y planifica una reactivación controlada con perfilado.
cr0x@server:~$ cd /var/www/example.com/public/wp-content/plugins
cr0x@server:~$ sudo mv suspicious-plugin suspicious-plugin.disabled
cr0x@server:~$ curl -sS -o /dev/null -w "%{http_code}\n" -H 'Host: example.com' http://127.0.0.1/
200

Significado: Si el estado devuelve 200 tras desactivar, has aislado la causa al plugin o algo que éste disparó.

Decisión: Manténlo desactivado; notifica a las partes interesadas; captura logs y una copia de la versión del plugin para análisis posterior.

Checklist C: Reinicio elegante de servicios sin empeorar

Los reinicios son herramientas, no plegarias. Úsalos cuando el componente esté realmente bloqueado, no como sustituto del diagnóstico.

cr0x@server:~$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
cr0x@server:~$ sudo systemctl reload nginx
cr0x@server:~$ sudo systemctl restart php8.2-fpm

Significado: Recarga Nginx primero (barata y de bajo riesgo) tras verificar la config. Reinicia PHP-FPM solo si los workers están atascados/OOMed y necesitas deshacer el atasco.

Decisión: Si reiniciar PHP-FPM restaura el servicio pero la recaída es rápida, deja de reiniciar y cambia a “recopilar evidencia de la ruta lenta”.

Checklist D: Estabilización post-recuperación (mismo día)

  1. Mantén límites de tasa hasta confirmar estabilidad bajo carga normal.
  2. Captura artefactos: consultas lentas principales, fragmentos de slow log de PHP-FPM, errores upstream de Nginx, muestras de processlist de BD.
  3. Escribe una breve línea temporal del incidente: qué cambió, cuándo empezó, qué mitigaciones funcionaron.
  4. Convierte el mayor punto doloroso en un control permanente (alerta, dashboard, test automatizado).

FAQ

1) ¿Un 503 de WordPress es siempre un problema del servidor?

No. A menudo es el servidor reaccionando a un comportamiento de la aplicación: un plugin que genera consultas costosas, un tema que llama a APIs externas o crons que se acumulan. El servidor es solo el mensajero.

2) ¿Por qué veo a veces 503 y otras 504?

Diferentes capas traducen fallos de forma distinta. Un load balancer puede llamar a un timeout upstream 503, mientras que Nginx puede emitir 504. Centra tu atención en dónde se origina el fallo, no en el código exacto.

3) ¿Debo aumentar pm.max_children de PHP-FPM para arreglar 503?

Sólo si has confirmado que tienes CPU/RAM de sobra y que la base de datos/almacenamiento pueden manejar más concurrencia. Si no, amplificas el cuello de botella y arriesgas OOM kills y peor latencia.

4) ¿Cómo sé si la base de datos es el cuello de botella?

Slow logs de PHP-FPM mostrando mysqli_query(), Threads_connected de MySQL cerca del máximo, consultas de larga duración en el processlist y alto I/O wait en el host de BD son señales fuertes.

5) ¿Puede un CDN causar 503 aunque mi origen esté bien?

Sí. Fallos en checks de salud, acceso al origen bloqueado, mismatch TLS/SNI o rate limiting pueden hacer que el edge devuelva 503. Siempre prueba el origen directamente con la cabecera Host correcta.

6) ¿Cuál es la forma más rápida de aislar un plugin malo?

Desactívalo sin usar wp-admin: renombra el directorio del plugin y vuelve a probar. Para un enfoque más quirúrgico, desactiva plugins uno a uno empezando por los más recientes.

7) ¿Por qué reiniciar lo “arregla” temporalmente?

Porque vacías colas y matas workers atascados, lo que restaura la capacidad brevemente. Si la dependencia lenta permanece, sólo estás reiniciando el cronómetro.

8) ¿Un 503 puede ser causado por permisos de archivos?

Indirectamente. Si WordPress no puede escribir en directorios de uploads/cache/session, las peticiones pueden colgar o fallar, llevando a fallos upstream. Revisa logs de Nginx/PHP por errores de permisos y verifica la salud del sistema de archivos.

9) ¿Qué endpoint de health check debería usar para balanceadores?

Un endpoint estático servido por el servidor web (no PHP), que devuelva 200 con trabajo mínimo. Si necesitas checks más profundos, crea un segundo endpoint para monitorización interna, no para el enrutamiento de tráfico.

10) ¿Cómo prevengo 503s a largo plazo?

Instrumenta los cuellos de botella (saturación PHP-FPM, conexiones BD, latencia de disco), controla la concurrencia, cachea lo correcto y trata las actualizaciones de plugins como despliegues—en etapas y reversibles.

Conclusión: siguientes pasos después de volver

Una vez que el sitio esté sirviendo de nuevo, no “cierres la incidencia” y te vayas. El sistema te acaba de enseñar dónde se rompe. Convierte esa lección en algo útil.

  1. Convierte la causa raíz en un guardarraíl: alertas sobre inodos/latencia de disco, saturación de PHP-FPM, margen de conexiones BD y corrección del health check.
  2. Arregla la ruta lenta: indexa las peores consultas, elimina o sustituye el comportamiento más pesado de plugins y deja de hacer llamadas remotas en el path crítico de renderizado.
  3. Ajusta la concurrencia: configura los children de PHP-FPM acorde a lo que la base de datos y el almacenamiento pueden sostener, no a lo que tranquiliza.
  4. Haz que las fallas cuesten menos: añade un verdadero /healthz, caching con protección contra estampidas y limitación de tasa para endpoints abusivos.
  5. Escribe el runbook que deseabas tener: los comandos exactos que ejecutaste, los logs que importaron y notas de “no volver a hacer esto”. En la próxima caída estarás cansado y menos ingenioso.

Si haces estas cinco cosas, el próximo 503 no será un misterio. Será un modo de fallo conocido con una respuesta corta, ligeramente molesta pero eficaz.

← Anterior
Proxmox ‘vzdump backup failed’: 10 causas reales y cómo comprobarlas en orden
Siguiente →
Fallos en la migración en caliente de Proxmox: qué verificar en red, flags de CPU y almacenamiento

Deja un comentario