diff --git a/scripts/servidor/publicar-webs.sh b/scripts/servidor/publicar-webs.sh index 5ddc7ada..e5bca0d5 100755 --- a/scripts/servidor/publicar-webs.sh +++ b/scripts/servidor/publicar-webs.sh @@ -11,8 +11,9 @@ # # tawasuyu.net, www → /work/sergio/tawasuyu (monorepo, con rewrites a web/tawasuyu-web) # gioser.net → /work/sergio/gioser-web/ -# takana.gioser.net → /work/sergio/gioser-web/takana } las genera scripts/hermanas.py -# hifas.gioser.net → /work/sergio/gioser-web/hifas } +# takana-os.net, www → /work/sergio/takana/web/takana-os.net (⚠ el ÁRBOL DE TRABAJO) +# takana.gioser.net → 301 a takana-os.net (desde el 2026-09-21) +# hifas.gioser.net → /work/sergio/gioser-web/hifas (la genera scripts/hermanas.py) # gioser.net/{humanoid,muestras,vivo,ende,reencuentro} → /work/www/gioser-web/… (MEDIOS, no están en git) # # El `.git` de los clones no se filtra: el vhost tiene `@oculto path /.* */.*` → 404, y se comprueba @@ -22,7 +23,13 @@ # Idempotente. Se corre EN LA CAJA. set -eu +# ⚠ `takana-os.net` NO ENTRA EN EL `pull` DE ARRIBA, Y ES A PROPÓSITO (2026-09-21). Su raíz no es +# un clon de publicación: es `/work/sergio/takana`, el árbol que los agentes editan. Un `pull` ahí +# mueve HEAD bajo los pies de quien esté trabajando (CLAUDE.md §2 ter, donde eso ya costó un commit +# entero). Para ese sitio, publicar es guardar el fichero — no hay nada que tirar, sólo que +# comprobar. Por eso figura abajo, en los controles, y no acá. MONO=${MONO:-/work/sergio/tawasuyu} +TAKANA=${TAKANA:-/work/sergio/takana} WEB=${WEB:-/work/sergio/gioser-web} tirar() { # $1 = clon @@ -58,10 +65,14 @@ sed "s|^DESTINO = Path(\"/home/sergio/gioser-web\")|DESTINO = Path(\"$WEB\")|" \ "$WEB/scripts/hermanas.py" > /tmp/hermanas-caja.py python3 /tmp/hermanas-caja.py >/dev/null rm -f /tmp/hermanas-caja.py +# `hermanas.py` sigue escribiendo las DOS, pero desde el 2026-09-21 la de takana ya no se sirve: +# `takana.gioser.net` redirige al dominio propio y la página buena vive en el repo takana. Se deja +# generar porque el guion es de ese otro repo y partirlo acá es tocarlo de paso; lo que sí cambió +# es el control, que abajo espera un 301 y no un fichero. for p in takana hifas; do [ -s "$WEB/$p/index.html" ] || { echo " ✗ $p quedó sin index.html" >&2; exit 1; } done -echo " ✓ takana $(wc -c < "$WEB/takana/index.html") B · hifas $(wc -c < "$WEB/hifas/index.html") B" +echo " ✓ hifas $(wc -c < "$WEB/hifas/index.html") B · takana $(wc -c < "$WEB/takana/index.html") B (ya no servida)" echo "==> control: lo que se SIRVE tiene que ser lo que está en disco" falla=0 @@ -71,10 +82,32 @@ comprobar() { # $1 = url $2 = fichero en disco if [ "$viv" = "$dis" ]; then printf " ✓ %-30s %s\n" "$1" "$viv" else printf " ✗ %-30s vivo=%s disco=%s\n" "$1" "$viv" "$dis"; falla=$((falla+1)); fi } +# Un nombre que REDIRIGE no se comprueba por contenido: se comprueba por destino. Y un nombre que +# todavía no resuelve no es un fallo del sitio —es un registro DNS que falta—, así que avisa en vez +# de ponerse rojo: mezclar las dos cosas es cómo un control deja de leerse. +# +# ⚠ Quién resuelve se lo pregunto a CURL, por su código de salida 6 («couldn't resolve host»), y no +# a `getent`: **en esta caja `getent` NO EXISTE** —musl/busybox no lo traen— así que la primera +# versión de esta función daba `not found` (127) para TODO y declaraba «no resuelve todavía» hasta +# de los nombres que estaban andando. Un control que nunca mira nada se ve igual que uno en verde. +redirige() { # $1 = url $2 = destino esperado + rc=0 + d=$(curl -s -o /dev/null -w "%{redirect_url}" --max-time 15 "$1") || rc=$? + if [ "$rc" -eq 6 ]; then + printf " ~ %-30s el nombre no resuelve todavía (¿falta el registro A?)\n" "$1"; return 0 + fi + if [ "$rc" -ne 0 ]; then + printf " ✗ %-30s curl salió %s (¿certificado, o no escucha?)\n" "$1" "$rc"; falla=$((falla+1)); return 0 + fi + if [ "$d" = "$2" ]; then printf " ✓ %-30s → %s\n" "$1" "$d" + else printf " ✗ %-30s → %s (esperaba %s)\n" "$1" "${d:-nada}" "$2"; falla=$((falla+1)); fi +} comprobar https://tawasuyu.net/ "$MONO/web/tawasuyu-web/index.html" -comprobar https://takana.gioser.net/ "$WEB/takana/index.html" +comprobar https://takana-os.net/ "$TAKANA/web/takana-os.net/index.html" comprobar https://hifas.gioser.net/ "$WEB/hifas/index.html" comprobar https://gioser.net/ "$WEB/index.html" +redirige https://takana.gioser.net/ https://takana-os.net/ +redirige https://git.takana-os.net/ https://git.gioser.net/ # Los medios no salen de git, pero tienen que seguir en pie. for u in https://gioser.net/humanoid/ https://gioser.net/muestras/; do @@ -82,10 +115,14 @@ for u in https://gioser.net/humanoid/ https://gioser.net/muestras/; do [ "$c" = "200" ] && printf " ✓ %-30s %s\n" "$u" "$c" || { printf " ✗ %-30s %s\n" "$u" "$c"; falla=$((falla+1)); } done -# Y que servir DESDE UN CLON no exponga el repo. -g=$(curl -s -o /dev/null -w "%{http_code}" --max-time 15 https://tawasuyu.net/.git/config) -[ "$g" = "404" ] && echo " ✓ /.git/config → 404 (la regla @oculto cubre el clon)" \ - || { echo " ✗ /.git/config → $g — EL REPO ESTÁ EXPUESTO"; falla=$((falla+1)); } +# Y que servir DESDE UN ÁRBOL DE GIT no exponga el repo. Son dos ahora, y el de takana además +# sirve un subdirectorio del árbol vivo, así que el día que alguien suba el root un nivel quedaría +# el repo entero publicado — y eso no falla de forma visible. +for u in https://tawasuyu.net/.git/config https://takana-os.net/.git/config; do + g=$(curl -s -o /dev/null -w "%{http_code}" --max-time 15 "$u") + [ "$g" = "404" ] && printf " ✓ %-30s 404 (la regla @oculto tapa el árbol)\n" "$u" \ + || { printf " ✗ %-30s %s — EL REPO ESTÁ EXPUESTO\n" "$u" "$g"; falla=$((falla+1)); } +done [ "$falla" -eq 0 ] || { echo "==> $falla control(es) en rojo" >&2; exit 1; } echo "==> sitios publicados y verificados" diff --git a/web/takana-os.net/README.md b/web/takana-os.net/README.md index 073134e6..145ea0fd 100644 --- a/web/takana-os.net/README.md +++ b/web/takana-os.net/README.md @@ -23,8 +23,15 @@ medidas: ninguna baja de 4,5:1. `repo.gioser.net`. Comprobado: `takana install age --repo https://repo.gioser.net --trust ./trust` responde `release: trusted (by release)`. -⚠ `takana repo list --repo ` **no habla HTTP** — sólo directorios locales — y ante una URL dice -«repo vacío» con salida 0 en vez de decir que no sabe. El que sí baja por red es `install --repo`. +Y **desde el 2026-09-21 se puede mirar el repo sin construir nada**, que antes no se podía: +`repo list` y `repo verify` aceptan la misma lista de orígenes que `install`. Hasta ese día sólo +miraban directorios locales y ante una URL respondían «repo vacío» **con salida 0** — 173 paquetes +leídos como ninguno. + +```sh +takana repo list --repo https://takana-os.net/repo # 173 paquete(s) +takana repo verify --repo https://takana-os.net/repo --trust ./trust # release: trusted +``` ## Cómo se sirve @@ -35,7 +42,7 @@ HEAD bajo los pies de otro agente (CLAUDE.md §2 ter). Este README **no se sirve**: son notas de operación, y el matcher del vhost las 404ea. -El bloque, por si hay que rehacer la caja (`caddy validate` → `arjectl restart caddy`, **nunca** +Los bloques, por si hay que rehacer la caja (`caddy validate` → `arjectl restart caddy`, **nunca** `caddy reload`: el Caddyfile lleva `admin off`, SDD 28 §6.14): ```caddyfile @@ -56,18 +63,44 @@ takana-os.net, www.takana-os.net { file_server } } + +git.takana-os.net { + import acceso + redir https://git.gioser.net{uri} permanent +} + +takana.gioser.net { + import acceso + redir https://takana-os.net{uri} permanent +} ``` -## DNS +`scripts/servidor/publicar-webs.sh` comprueba los cuatro: los dos que sirven ficheros por sha +contra el disco, y los dos que redirigen por destino. -El dominio se registró el 2026-09-21 y **el vhost está puesto antes que los registros**: hasta que -`takana-os.net` resuelva a la caja, Caddy no puede pedir el certificado y el nombre no responde. -Hacen falta dos `A` a `2.29.29.217` (la IP de la caja), igual que la de `repo`: +## Los nombres + +| nombre | qué hace | estado | +|---|---|---| +| `takana-os.net`, `www` | el sitio | ✅ con certificado de Let's Encrypt (2026-09-21) | +| `takana-os.net/repo/` | el repo de paquetes, el mismo `/srv/repo` | ✅ | +| `takana.gioser.net` | **301 → `takana-os.net`** | ✅ | +| `git.takana-os.net` | **301 → `git.gioser.net`** | ⏳ vhost puesto, **falta el registro A** | + +`git.takana-os.net` sólo redirige, y es deliberado: gitea tiene UN `ROOT_URL` con el que arma cada +enlace y cada URL de clon que muestra, así que colgarlo de un segundo nombre daría un sitio que se +contradice —entrás por uno y te ofrece clonar del otro— y moverlo de verdad rompe los clones y el +CI que ya apuntan al viejo. + +Los registros van a `2.29.29.217`, la IP de la caja: ``` -takana-os.net. A 2.29.29.217 -www.takana-os.net. A 2.29.29.217 +takana-os.net. A 2.29.29.217 ✅ puesto +www.takana-os.net. A 2.29.29.217 ✅ puesto +git.takana-os.net. A 2.29.29.217 ⏳ falta ``` -Con eso puesto, el certificado sale solo en la primera petición — y **tarda unos segundos más que -el primer `curl`**: si da error, reintentar antes de ir a mirar logs (SDD 28 §6.14). +El certificado sale solo en la primera petición tras el DNS — y **tarda unos segundos más que el +primer `curl`**: si da error, reintentar antes de ir a mirar logs (SDD 28 §6.14). Si el nombre ya +resolvía cuando Caddy arrancó pero el certificado no llegó, **reiniciar caddy fuerza el reintento** +sin esperar el backoff: fue lo que hizo falta acá. diff --git a/web/takana-os.net/index.html b/web/takana-os.net/index.html index 0d1a189d..49b46b15 100644 --- a/web/takana-os.net/index.html +++ b/web/takana-os.net/index.html @@ -312,7 +312,9 @@ footer.pie{border-top:1px solid var(--linea);background:var(--papel);padding:2.6 https://takana-os.net/repo/ -
$ takana install age --repo https://takana-os.net/repo --trust ./trust
+
$ takana repo list   --repo https://takana-os.net/repo
+$ takana repo verify --repo https://takana-os.net/repo --trust ./trust
+$ takana install age --repo https://takana-os.net/repo --trust ./trust

Hoy publica la clausura del perfil servidor. El mismo repo se sirve también en repo.gioser.net; --repo acepta varios orígenes separados por coma y los prueba en orden.