Cómo muestro «en mantenimiento» cuando mi servidor está apagado
ContenidoContents
Todo mi sitio se sirve desde un Mac mini en casa, detrás de un túnel de Cloudflare. Funciona muy bien hasta que tengo que reiniciarlo: una actualización del sistema, mantenimiento, un susto. Y ahí aparece un problema con cara de acertijo.
Quiero que, durante esos minutos, quien entre vea un “vuelvo enseguida, estoy en mantenimiento” en lugar de un error feo. Pero hay una pega: la máquina que serviría esa página es exactamente la que está apagada. Es el problema del huevo y la gallina.
Por qué mi propia página de error no sirve
Tengo páginas de error bonitas (403, 404, 503…) en el servidor. El detalle es que las sirve Apache, que vive en el Mac mini. Si reinicio el Mac, Apache no existe en ese momento, así que no puede entregar ni siquiera su página de “estoy caído”. El túnel se viene abajo y Cloudflare, que no encuentra a nadie al otro lado, muestra su propio error genérico (el famoso Error 1033).
Tengo activado Always Online, que ayuda: Cloudflare guarda una copia de algunas páginas y la sirve si el origen cae. Pero eso muestra contenido archivado, no un mensaje de “estoy haciendo mantenimiento”. No es lo mismo.
La conclusión es incómoda pero lógica: la página que avisa de que mi servidor no está disponible no puede vivir en mi servidor. Tiene que vivir en otro sitio que siga en pie cuando el Mac no esté.
La idea: moverla al borde
Ese “otro sitio que sigue en pie” es la red de Cloudflare. Lo que necesito es un trocito de código que se ejecute en el edge, delante de mi servidor, y que decida: si el Mac responde, te dejo pasar; si no responde, te enseño yo la página de mantenimiento.
Eso es exactamente un Cloudflare Worker.
Lo primero que miré fue la opción “oficial”: las Custom Error Pages de Cloudflare, que permiten personalizar la pantalla de origen caído. Pero no están en el plan gratuito —son de pago—, y pasar a Pro solo por esto no me compensaba. Los Workers, en cambio, sí entran en el plan Free (100.000 peticiones al día; para un sitio personal sobra de largo). Así que, Worker.
Cómo funciona
El Worker se pone delante del tráfico y tiene una lógica mínima:
1export default {
2 async fetch(request, env) {
3 // 1) Interruptor manual
4 if ((env.MAINTENANCE || '').toLowerCase() === 'on') {
5 return maintenancePage();
6 }
7 // 2) Detección automática
8 try {
9 const resp = await fetch(request); // intenta mi Mac
10 if (resp.status >= 521 && resp.status <= 530) // Cloudflare: origen caído
11 return maintenancePage();
12 return resp; // todo bien: deja pasar
13 } catch (e) {
14 return maintenancePage();
15 }
16 },
17};
Son dos disparadores independientes:
- Automático: en cada visita, el Worker intenta hablar con mi Mac. Si está apagado, el túnel cae y Cloudflare devuelve un error de la familia 52x. El Worker lo detecta y sirve la página de mantenimiento sin que yo toque nada. Esto cubre el caso importante: un reinicio, o incluso un cuelgue inesperado a las tres de la mañana.
- Manual: una variable
MAINTENANCE. Si la pongo enon, muestra la página aunque el Mac siga vivo. Es para el mantenimiento planificado: la activo antes de empezar, sigo trabajando contra el servidor porlocalhost(que no pasa por Cloudflare) y la quito al terminar.
La página responde con un HTTP 503 y una cabecera Retry-After. Es el código correcto: los buscadores entienden que es algo temporal, reintentan y no te penalizan. Y va con Cache-Control: no-store, así que en cuanto desactivo el mantenimiento desaparece al instante.
Dos detalles que me costaron
Ruta, no dominio. Al asignar el Worker, Cloudflare ofrece “dominio personalizado” o “patrón de ruta”. Si eliges dominio personalizado, el Worker sustituye a tu sitio para siempre y se rompe el truco de “intentar el origen primero”. Lo que quieres es patrón de ruta (tudominio.com/*): el Worker se interpone, pero el dominio sigue resolviendo a tu servidor, así que puede intentarlo y solo actuar si no responde.
Dónde NO ponerlo. El Worker se interpone en todo el tráfico de las rutas que le asignes. Lo puse en la web y en mi otro sitio, pero deliberadamente lo dejé fuera del Moodle. Interponer una capa extra en un servicio con sesiones, subidas de archivos y conexiones en tiempo real es añadir un punto de fallo donde más duele. Para lo crítico, cuanto menos haya en medio, mejor.
Lo bonito del asunto
La página de mantenimiento es completamente autónoma: todo el HTML y el CSS van embebidos en el Worker, sin cargar ni una fuente ni una imagen externa. Tiene que ser así, porque cualquier recurso que intentara pedir a mi servidor… no estaría, que es justo el motivo por el que se está mostrando.
Y esa es la idea que me llevo. En un montaje casero, dar por hecho que tu servidor estará ahí para disculparse por no estar ahí es un error de lógica. La disculpa hay que dejarla guardada fuera, en alguien que siga despierto cuando tú apagues la luz.