EasyPages es un panel autoalojado para Cloudflare Pages: tus proyectos, sus despliegues, el ZIP que estás a punto de publicar y los dominios que apuntan a ellos, en una sola pantalla. Se distribuye como un único contenedor Docker para tu homelab o red privada, y siempre trabaja contra tu cuenta de Cloudflare con tu token de API.

El problema

Publicar un sitio estático es un problema resuelto hasta la última milla. A partir de ahí toca abrir el dashboard de Cloudflare, encontrar el proyecto entre todo lo demás de una cuenta pensada para operar infraestructura, subir el build, esperar a ver si el despliegue levantó, ir a otra pestaña para el dominio personalizado y a otra más para el comando de build.

EasyPages reúne ese bucle en un panel que ejecutas tú. Una lista de proyectos de Pages, un botón para desplegar, una zona donde soltar el ZIP y los dominios justo al lado del proyecto al que pertenecen.

Qué hace

  • Lista de proyectos. Todos los proyectos de Cloudflare Pages con su estado y su origen, en una sola vista.
  • Crear proyectos Direct Upload. Levanta un proyecto nuevo desde el panel, sin abrir el dashboard de Cloudflare.
  • Despliegues. Dispara un despliegue y consulta el historial reciente con rama, commit y fecha.
  • Subida de ZIP. Suelta un .zip y publícalo directamente en el proyecto Direct Upload seleccionado.
  • Dominios personalizados. Añade y elimina dominios, con confirmación antes de borrar uno.
  • Configuración de build. Edita el comando de build y el directorio de salida actuales desde la pestaña de ajustes.
  • Español e inglés en toda la interfaz, con cambio instantáneo desde la cabecera.

La instalación es una variable

CF_API_TOKEN es la única variable obligatoria. El identificador de cuenta se deduce del propio token, igual que hacen el SDK oficial de Cloudflare y Wrangler, así que no tienes que buscarlo: solo defines CF_ACCOUNT_ID en el único caso que la deducción no puede resolver, un token que llega a varias cuentas, y los logs del servidor lo dicen y listan los identificadores entre los que elegir.

Esa resolución es perezosa, no en el arranque: un host que reinicia sin internet arranca igualmente y reporta un error claro en lugar de negarse a levantar.

Tampoco hay usuario ni contraseña en el .env. La cuenta de operador se crea en el navegador la primera vez que abres el panel, y ninguna variable de entorno puede crearla, sustituirla ni esquivarla — AUTH_USER y AUTH_PASS se eliminaron en la versión que introdujo el asistente. ¿Perdiste la contraseña? Detienes la aplicación, borras credentials.json y vuelve el asistente; el secreto de sesión queda intacto.

Seguridad y alcance

EasyPages es un panel de un solo operador: una cuenta, sin roles y sin multi-tenancy. Quien entre puede crear, desplegar y borrar proyectos y dominios con tu token de Cloudflare, así que trata el acceso al panel como equivalente al acceso a ese token.

  • La contraseña se guarda como hash scrypt (los parámetros van dentro del hash, así que pueden subirse más adelante sin invalidar nada). La sesión es una cookie firmada, HttpOnly y SameSite=Lax de 24 horas que lleva un nombre de usuario y una versión de token — ningún secreto.
  • Cada cambio de credenciales incrementa esa versión de token, lo que invalida todas las cookies emitidas antes. Así funciona "cerrar sesión en el resto de dispositivos" sin almacenar sesiones en el servidor.
  • El CSRF es un token opaco por sesión, obligatorio en todo método no seguro, y los intentos fallidos de login se limitan en dos cubos: la IP reportada y el peer del socket. El segundo no es opcional — X-Forwarded-For lo envía el cliente, así que sin él rotar un valor falso daría cuota nueva en cada petición.
  • El token de Cloudflare nunca se escribe en disco, nunca se envía al navegador y nunca aparece en una respuesta de error.
  • Entre el primer arranque y el final del asistente, cualquiera que llegue al puerto puede reclamar la instancia — el mismo compromiso de confianza en el primer uso que hacen Portainer o Home Assistant. Complétalo enseguida y no publiques el puerto antes de hacerlo.
  • Detrás de un proxy inverso con TLS, define SESSION_COOKIE_SECURE=true. Si el proceso queda expuesto directamente, define TRUST_PROXY=false para que el limitador use el socket real y no una cabecera que controla el cliente.

Stack

React 18 con Vite y Tailwind en el frontend; Node 24 con Express en el backend; un único contenedor Docker. Sin base de datos: Cloudflare es la fuente de verdad de todo el dominio, y el único estado local son la credencial y la clave de firma de sesión, ambas con permisos 0600 en el volumen de datos. Licencia Apache-2.0, imagen ghcr.io/kn990x/easypages.

El CI ejecuta lint, el build y las dos suites de tests (node:test en el backend, Vitest en el frontend), además de una construcción de la imagen y un smoke test de arranque en frío con una sola variable de entorno y un volumen limpio: estado, asistente, sesión, asset fantasma, permisos del fichero de credenciales y healthcheck del contenedor.

easypages.app vive en un repositorio aparte: un sitio estático y bilingüe hecho con Astro sobre Cloudflare Workers, con una sola isla de Preact — una réplica interactiva del dashboard funcionando con datos de ejemplo — y cero peticiones a terceros.

Empezar

mkdir easypages && cd easypages
curl -fsSL -o docker-compose.yml https://raw.githubusercontent.com/KN990x/EasyPages/main/docker-compose.yml
curl -fsSL -o .env.example https://raw.githubusercontent.com/KN990x/EasyPages/main/.env.example
cp .env.example .env

# Rellena CF_API_TOKEN
docker compose up -d --pull always

Abre http://tu-servidor:8002 y elige usuario y contraseña en el asistente. El Compose incluye una imagen fijada en GHCR, ./easypages-data:/data y un healthcheck en /api/health; el contenedor corre como uid 1000, así que si creaste la carpeta como root ejecuta chown -R 1000:1000 ./easypages-data.

El token de API necesita exactamente un permiso: Account → Cloudflare Pages → Edit. Nada más — el identificador de cuenta se lee del propio token.

La documentación completa — permisos del token, variables opcionales, proxies inversos y el entorno de desarrollo — está en easypages.app y en el repositorio KN990x/EasyPages.