Dominios personalizados, enrutado por rutas, subdominios de juego y Domain Connect
Un servicio siempre es accesible en una dirección gratuita de la plataforma. Esta guía explica cómo hacer que responda en un nombre propio. Cuáles de estas opciones tiene tu servicio depende de su producto, así que consulta antes sus capacidades: custom_domain y external_access aparecen cuando las admite. Los ejemplos usan el ayudante de Usar la API de Zaroz.
Los dominios que necesitan certificado usan TLS automático, así que el nombre debe apuntar ya a Zaroz en el DNS antes de que se pueda emitir. Un dominio pending es normal mientras esperas al DNS; no es un error.
Dominios personalizados
Demuestra que el dominio es tuyo
Salvo que el nombre sea una sola etiqueta bajo un dominio padre que Zaroz mismo registró para ti, la organización debe demostrar antes que controla el dominio con un registro DNS TXT: consulta Verificar un dominio. Los nombres dentro de la zona DNS de Zaroz se rechazan para siempre, y un nombre que ya tiene otra organización se rechaza con la misma respuesta que uno que no has demostrado, de modo que esta API no sirve para averiguar quién tiene qué.
Comprobar, asociar, esperar, desasociar
Pregunta primero si un nombre se podría asociar; no cambia nada.
import { call } from "./zaroz";const avail = await call("GET", `/service-instances/${SERVICE}/custom-domains/availability?hostname=www.example.com`);if (avail.body.status !== "available") throw new Error(avail.body.status);await call("POST", `/service-instances/${SERVICE}/custom-domains`, { hostname: "www.example.com" });// pending hasta que el DNS apunte aquí y se emita el certificadofor (let i = 0; i < 60; i++) { const { body } = await call("GET", `/service-instances/${SERVICE}/custom-domains`); const mine = body.domains.find((d: any) => d.hostname === "www.example.com"); console.log(mine.status); if (mine.status !== "pending") break; await new Promise((r) => setTimeout(r, 30_000));}
Python
Code
import timefrom zaroz import call_, avail = call("GET", f"/service-instances/{SERVICE}/custom-domains/availability?hostname=www.example.com")assert avail["status"] == "available", avail["status"]call("POST", f"/service-instances/{SERVICE}/custom-domains", {"hostname": "www.example.com"})for _ in range(60): # pending hasta que el DNS apunte aquí y se emita el certificado _, body = call("GET", f"/service-instances/{SERVICE}/custom-domains") mine = next(d for d in body["domains"] if d["hostname"] == "www.example.com") print(mine["status"]) if mine["status"] != "pending": break time.sleep(30)
Crea un CNAME (www.example.com hacia el host de la plataforma que el listado devuelve como platform_host) en tu proveedor de DNS. Un dominio desnudo (example.com) no puede tener CNAME: usa el registro ALIAS, ANAME o de aplanado de CNAME de tu proveedor hacia el mismo destino.
status pasa de pending a active (ruta y certificado en marcha) o failed (normalmente el certificado: no se puede emitir hasta que el DNS apunte aquí; corrige el registro y se reintenta).
Asociar es idempotente: un nombre ya asociado a este servicio se vuelve a aplicar y se devuelve. Un servicio admite un número limitado de dominios (limit en el listado), y uno que no publica HTTP no puede tener ninguno.
Desasociar elimina la ruta, el certificado y tu reclamación del nombre, así que puedes volver a asociarlo más tarde. El host gratuito de la plataforma no se puede desasociar.
const E = `/projects/${PROJECT}/service-instances/${SERVICE}/endpoints/${ENDPOINT}`;const d = await call("POST", `${E}/domains`, { domain: "www.example.com" });console.log(d.body.dns); // crea exactamente este registro en tu proveedor de DNS
Python
Code
E = f"/projects/{PROJECT}/service-instances/{SERVICE}/endpoints/{ENDPOINT}"_, d = call("POST", f"{E}/domains", {"domain": "www.example.com"})print(d["dns"]) # crea exactamente este registro en tu proveedor de DNS
La respuesta te dice el registro DNS exacto que crear (dns). Un rechazo nombra su motivo antes de los dos puntos en details: invalid_domain (400), o platform_domain, domain_taken, domain_not_verified, domain_limit, not_ready (422). Un código failure explica un dominio failed.
Enrutado por rutas
Cuando un dominio está en un endpoint HTTPS puedes enviar algunas rutas a otro sitio, de modo que app.com llegue a un servicio y app.com/api a otro. El destino debe ser un endpoint HTTPS abierto de un servicio del mismo proyecto. Gana la ruta coincidente más larga; el endpoint al que está asociado el dominio responde todo lo demás. La llamada reemplaza todo el conjunto, y una lista vacía elimina todas las rutas.
curl
Code
curl -sS -X PUT "$ZAROZ_API$E/$ENDPOINT/domains/$ROUTE/paths" -H "$AUTH" -H "Content-Type: application/json" -d '{ "paths": [ {"path": "/api", "strip_prefix": true, "target_service_instance_id": "<uuid del servicio de la API>", "target_endpoint_id": "<uuid de su endpoint https>"} ]}'# ¿cómo enruta ahora este dominio y adónde iría /api/users?curl -sS "$ZAROZ_API$E/$ENDPOINT/domains/$ROUTE/routing?path=/api/users" -H "$AUTH"
Con strip_prefix: true el destino recibe /users; con false recibe /api/users. Cada regla tiene un status: serving, starting (su destino aún no está activo), shadowed (otra regla con la misma ruta gana siempre, así que esta nunca sirve) o broken (su destino no puede responder). Rechazos: invalid_path y target_not_found (400; un destino inexistente, cerrado o de otro proyecto responden igual), y path_limit, duplicate_path, target_not_http (422).
Subdominios de juego
Un servidor de juegos puede tomar un nombre gratuito bajo una zona de la plataforma (<nombre>.<zona>), que apunta a su dirección pública, con un registro SRV para los juegos que leen el puerto de ahí. Un servicio tiene uno.
status es pending (creando los registros), active, failed (se reintenta solo) o deleting. PATCH .../game-subdomains/{id} con un nombre nuevo lo reemplaza (la respuesta trae un id nuevo) y DELETE lo libera. Un nombre sigue ocupado un tiempo después de que su titular anterior lo liberó. Rechazos: zone_unavailable, invalid_subdomain, subdomain_taken, already_has_subdomain (422).
Si tu proveedor de DNS admite Domain Connect, Zaroz puede enviarte allí para que apruebes los registros exactos en lugar de copiarlos tú. Nunca escribe tu DNS por sí mismo. Solo lo ofrecen los productos que declaran una plantilla (servidores de juegos con un registro SRV), y un despliegue puede no ejecutarlo en absoluto: comprueba domain_connect en qué ofrece el despliegue.
curl
Code
curl -sS "$ZAROZ_API/service-instances/$SERVICE/domain-connect" -H "$AUTH"# {"supported": true, "links": []}curl -sS -X POST "$ZAROZ_API/service-instances/$SERVICE/domain-connect/discover" -H "$AUTH" \ -H "Content-Type: application/json" -d '{"domain": "example.com", "host": "play"}'# {"id": "...", "status": "pending", "apply_url": "https://dns-provider.example/...", "hostname": "play.example.com"}# envía el navegador del cliente a apply_url y después:curl -sS -X POST "$ZAROZ_API/service-instances/$SERVICE/domain-connect/$LINK/verify" -H "$AUTH"curl -sS -X DELETE "$ZAROZ_API/service-instances/$SERVICE/domain-connect/$LINK" -H "$AUTH"
TypeScript
Code
const state = await call("GET", `/service-instances/${SERVICE}/domain-connect`);if (state.body.supported) { const link = await call("POST", `/service-instances/${SERVICE}/domain-connect/discover`, { domain: "example.com", host: "play", // "" apunta el dominio raíz al servidor }); console.log("Abre", link.body.apply_url); // cuando el cliente apruebe en su proveedor de DNS: const v = await call("POST", `/service-instances/${SERVICE}/domain-connect/${link.body.id}/verify`); console.log(v.body.status); // active | pending | failed}
Python
Code
_, state = call("GET", f"/service-instances/{SERVICE}/domain-connect")if state["supported"]: _, link = call("POST", f"/service-instances/{SERVICE}/domain-connect/discover", {"domain": "example.com", "host": "play"}) # "" apunta el dominio raíz al servidor print("Abre", link["apply_url"]) # cuando el cliente apruebe en su proveedor de DNS: _, v = call("POST", f"/service-instances/{SERVICE}/domain-connect/{link['id']}/verify") print(v["status"]) # active | pending | failed
verify comprueba el DNS en vivo: active cuando el registro SRV está publicado y apunta al host y puerto esperados, failed cuando se encuentra un registro distinto, pending mientras no se haya propagado nada. Liberar un enlace no toca tu proveedor de DNS; quita allí los registros tú mismo. Un servicio admite como máximo 20 enlaces, y un proveedor sin flujo síncrono no se puede usar (crea los registros a mano).
Puertos en bruto con un dominio HTTP
Un servicio con acceso externo también puede publicar un dominio delante de un puerto TCP, con certificado gestionado, mediante POST /service-instances/{id}/external-access/{allocation_id}/http (cuerpo {"domain": "..."}). Sigue las mismas reglas que un dominio personalizado (DELETE en la misma ruta lo elimina). Abrir, cerrar y la cuota de los propios puertos están en Puertos públicos y endpoints.