Blog 

Estás viendo un solo post, ver todos

Aplicaciones en Cloudflare que responden en todos los subdominios

Publicado el 4 de Abril de 2026 en  

La plataforma de aplicaciones de Cloudflare tiene una limitación bien conocida: no se puede usar patrones con comodines en la ruta (por ejemplo, *.misitio.com). Si uno necesita alojar una aplicación en varios subdominios, tiene que agregar cada uno como una ruta distinta. Esto tiene dos desventajas. La primera: qué paja. La segunda: todos los subdominios existentes son visibles en los registros DNS.

Todo el mundo resuelve esto con redirects, pero yo no quería redirigir al usuario a otra URL, sino servir contenido en cualquier subdominio.

Al principio pensé que la solución era simple: si internamente dirigía todas las peticiones a un mismo lugar, podía alojar la aplicación ahí y responder según la url que figurara en la request. Pero historia larga hecha corta, no se puede: el router de Cloudflare rebota cualquier petición que no haya llegado al subdominio específico donde corre la aplicación.

Estuve un par de tardes peleando con este problema hasta que encontré la solución. Un worker sí puede usar patrones con comodines en la ruta, y además tiene la capacidad de reescribir la petición y devolvérsela al router de Cloudflare para que siga procesándola.

Con Wrangler instalado, usé la siguiente configuración en wrangler.jsonc:

{
  "name": "misitio-worker",
  "main": "index.js",
  "compatibility_date": "2026-01-14",
  "route": {
    "pattern": "*.misitio.com/*",
    "zone_name": "misitio.com"
  }
}

Esta configuración monta un worker que responde en todos los subdominios. El código de index.js es:

function stripSubdomain(hostname) {
    const parts = hostname.split('.');
    if (parts.length <= 2) return hostname;
    return parts.slice(-2).join('.');
}

export default {
    fetch: async (req) => {
        const originalUrl = new URL(req.url);
        const modifiedUrl = new URL(req.url);
        const rootDomain = stripSubdomain(originalUrl.hostname);

        modifiedUrl.hostname = rootDomain;

        const newReq = new Request(modifiedUrl, req);
        newReq.headers.set('X-Original-Hostname', originalUrl.hostname);

        return fetch(newReq, { cf: { resolveOverride: rootDomain } });
    }
};

Esto intercepta la request, la modifica apuntándola a la ruta raíz, y graba la ruta original en la cabecera X-Original-Hostname para poder usarla más adelante.

Una vez que este worker está deployado en un dominio, solamente falta configurar el DNS. Hay que indicarle al navegador que el dominio acepta peticiones a cualquier subdominio. Hay varias formas de hacer esto, pero en Cloudflare la más simple es con un registro AAAA. En Name ponemos * y en Content ponemos 100::.

Hecho esto, cuando llega una petición a algo.misitio.com, el worker le sobreescribe la ruta a misitio.com, y ahí alguna aplicación que tengamos montada (un túnel, por ejemplo) la procesa, aprovechando X-Original-Hostname.

Por ejemplo, mi túnel Zero Trust apunta a un proxy Traefik que captura ciertas peticiones así:

- "traefik.http.routers.misitio.rule=HeaderRegexp(`X-Original-Hostname`, `^misubdominio\\..+$`)"

Usando esta lógica se puede modificar completamente el flujo interno de peticiones. La única desventaja es el límite de cien mil ejecuciones de worker gratuitas por día, pero para el uso que le estoy dando, me sobra.