From a3611a3245f448d5ac5c7fc87c5d931bad78f81e Mon Sep 17 00:00:00 2001 From: "Opix (agente)" Date: Wed, 12 Aug 2026 11:13:21 -0400 Subject: [PATCH] =?UTF-8?q?Wiki:=20producci=C3=B3n=20Hetzner,=20trampas=20?= =?UTF-8?q?del=20entorno=20y=20mapa=20del=20conocimiento=20heredado?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tres páginas nuevas escritas por Opix, verificadas contra el servidor el 2026-08-12 en solo lectura: - Produccion-Hetzner-acceso: clave SSH correcta (id_ed25519, no feadulta_ed25519), contenedor de Coolify, y el hecho de que no hay WP-CLI (se usa php -r con wp-load.php). - Trampas-del-entorno: las cuatro limitaciones del jail de CDMON que ya no aplican, más las que siguen vigentes, marcando qué está verificado. - Conocimiento-heredado: mapa de las skills de Hermes, la memoria de Claude Code y los scripts, con su estado de vigencia. Home actualizado con aviso de vigencia y enlaces al Gitea vivo (apuntaba a localhost:3000). Ninguna credencial en el contenido. --- Conocimiento-heredado.md | 99 +++++++++++++++++++++++++++++++ Home.md | 35 +++++++---- Produccion-Hetzner-acceso.md | 105 +++++++++++++++++++++++++++++++++ Trampas-del-entorno.md | 110 +++++++++++++++++++++++++++++++++++ 4 files changed, 339 insertions(+), 10 deletions(-) create mode 100644 Conocimiento-heredado.md create mode 100644 Produccion-Hetzner-acceso.md create mode 100644 Trampas-del-entorno.md diff --git a/Conocimiento-heredado.md b/Conocimiento-heredado.md new file mode 100644 index 0000000..e5ae480 --- /dev/null +++ b/Conocimiento-heredado.md @@ -0,0 +1,99 @@ +# Conocimiento heredado — dónde está todo + +> Levantado por Opix el **2026-08-12**. Mapa de lo que Hermes sabía hacer como +> webmaster de feadulta, con el estado de vigencia de cada fuente. + +**Ninguna de estas fuentes es autoritativa por sí sola.** Varias describen el +servidor cPanel/CDMON, retirado en el cutover del 2026-08-03. Verifica contra la +máquina antes de operar. Ver [[Produccion-Hetzner-acceso]] y [[Trampas-del-entorno]]. + +## 1. Skills de Hermes — `~/.hermes/skills/` (WSL) + +Lo más denso y lo más cercano a runbook. ~2.200 líneas. + +### `feadulta/feadulta-webmaster/` — la principal (192 líneas + 10 referencias) +Principio operativo: **diagnóstico + preparación + dry-run**; no tocar producción sin +instrucción explícita. Cubre: +- Endpoints REST acotados para operaciones editoriales (avatar de autor). +- Hotfix de contenido con TTS accidental: despublicación reversible del audio. +- Cron diario de feedback `fea_feedback` y su diagnóstico. +- Triage y contención de incidentes de seguridad (backdoors en mu-plugins). +- Retirada segura de bases de datos. +- Releases de contenido con carta ya publicada: serialización con lock, snapshot del + cluster Polylang completo, doble verificador draft/publish, rollback. + +Referencias: `translation-hotfixes`, `wordpress-compromise-first-response`, +`local-docx-carta-preview`, `feedback-beta`, `mysql-three-connection-release-gate`, +`rest-editorial-endpoints`, `guarded-release-handoff`, +`release-serialization-and-verification`, `access-log-forensics`, +`guarded-production-content-releases`, `production-mu-plugin-deploy`, +`feedback-cron-dedup`, `wordpress-author-avatar-api`. + +### `feadulta/webmaster/` — skill anterior (71 líneas + 3 referencias) +Más concreta y más obsoleta. `references/gotchas.md` y `references/procedures.md` +siguen siendo buenos resúmenes; `references/environment.md` describe el prod +**anterior**. Su contenido vigente está volcado en [[Trampas-del-entorno]]. + +### `feadulta/feadulta-carta-derivados/` (477 líneas + 7 referencias) +Traducción + TTS + rotación de la carta semanal. **La skill tiene desviaciones +respecto al código** (argparse de `tts_produce.py`, flags `--allow-default-voice` y +`--remap-conflicts` que no existen). Usar la versión contrastada, no la skill. + +### `feadulta/feadulta-editorial-workflows/` (100 líneas + 4 referencias) +Coordinación semanal con Inma/Mixbot, DOCX omitidos, evangelio diario A/B/C. + +### `feadulta-analytics/` (117 líneas + 1 referencia) +GA4: informes y renovación de OAuth. Scripts en `~/.hermes/scripts/feadulta_ga4_*.py`. + +### Fuera de feadulta pero aplicables +`devops/self-hosted-service-exposure/`, `devops/caddy-routing-recipes/`, +`devops/self-hosted-saas-operations/`. + +## 2. Wiki del servidor — `rafa/server` + +4 páginas. `Backups` es **la mejor escrita y la más actual** de las dos wikis: +diseño pull en dos capas, `~/backup-hetzner/pull-hetzner.sh`, verificación real de +restauración del 2026-08-01, y trampas de NTFS/rsync/Coolify. + +## 3. Memoria de Claude Code (WSL) + +`~/.claude/projects/-mnt-c-Users-Chia/memory/` — 88 ficheros, índice en `MEMORY.md`. + +| Fichero | Contenido | +|---|---| +| `master-feadulta.md` (20 KB) | Arquitectura WP, term_ids, Polylang, carta, EFFA, avatares, scripts delta | +| `master-infra.md` (17 KB) | Hardware, Tailscale, Docker, LLMs locales, Hetzner, APIs | +| `master-gitea.md` (8,7 KB) | Setup, quirks de la wiki, convenciones, comandos API | +| `feadulta-migracion-cdmon-hetzner-202607.md` (39 KB) | **El cutover del 2026-08-03** — fuente real del estado actual de prod | + +Y ~35 ficheros `feadulta-*.md` de incidentes y proyectos concretos. + +## 4. Scripts y perfiles + +- `~/.hermes/scripts/` — `fea_feedback_last24h.py`, `fea_tts_backlog_report.py`, + `feadulta_ga4_daily.py`, `feadulta_ga4_weekly.py`, `cron_scan.py`. +- `~/.hermes/profiles/feadulta/.env` — credenciales de producción. +- `~/.env` (permisos 600) — tokens de Gitea. +- `~/backup-hetzner/` — pull de backups + alerta Telegram + systemd. +- `~/.hermes/SOUL.md` — personalidad general de Hermes ("Luigi"). Sin contenido + operativo de feadulta; no hace falta migrarlo. + +## 5. Política de secretos + +**Ninguna credencial en esta wiki.** Solo punteros a los `.env` y a `~/.ssh/`. +Decisión de Rafa, 2026-08-12. + +⚠️ La página [[Credenciales-y-accesos]] (junio 2026) **contiene contraseñas en +claro** y contradice esta política. Pendiente de decidir su limpieza — ten en cuenta +que borrarlas del texto no las quita del historial git de la wiki. + +## 6. Estado de la migración de este conocimiento + +| Bloque | Estado | +|---|---| +| Acceso a producción | ✅ [[Produccion-Hetzner-acceso]] | +| Trampas del entorno | ✅ [[Trampas-del-entorno]] | +| Ciclo de la carta (traducción + TTS) | ✅ contrastado con el código, fuera de la wiki | +| Áreas funcionales (portada, Polylang, autores, EFFA, buscador) | ⏳ en la wiki desde junio, sin re-verificar contra el código | +| Seguridad e incidentes | ⏳ sigue solo en la skill de Hermes | +| Despliegue de mu-plugins, backups y rollback | ⏳ pendiente de consolidar | diff --git a/Home.md b/Home.md index 5f12148..357dc49 100644 --- a/Home.md +++ b/Home.md @@ -1,22 +1,37 @@ > **Este es el repo activo** — migrado desde el Gitea local de Tailscale el 2026-06-28. > Servidor: **gitea.feadulta.com** (Hetzner FSN1) -# feadulta.org — Wiki del proyecto +# feadulta.com — Wiki del proyecto -Portal cristiano español de renovación de la fe. Documentación operativa del proyecto de migración Joomla → WordPress y de su operación. +Portal cristiano español de renovación de la fe. Documentación operativa del proyecto +de migración Joomla → WordPress y de su operación. -**Estado:** migración completa, web protegida con HTTP Basic, cutover DNS previsto ~junio 2026. +**Estado:** migración completa. Cutover Joomla→WordPress cerrado el 2026-07-07/08 y +cutover de servidor CDMON→Hetzner cerrado el 2026-08-03. + +> ⚠️ **Aviso de vigencia.** Las páginas de operación y arquitectura se escribieron en +> junio de 2026, antes del cambio de servidor. Donde describan cPanel/CDMON +> (`134.0.10.170`, `/web/wp-nuevo`, `wp-nuevo.feadulta.com`) o el Gitea en +> `localhost:3000`, están **obsoletas**. Empieza por +> [[Produccion-Hetzner-acceso]] y [[Trampas-del-entorno]]. +> +> **Ninguna credencial debe vivir en esta wiki** (decisión de Rafa, 2026-08-12). --- ## Índice -### Operación -- [Credenciales y accesos](Credenciales-y-accesos) -- [Infraestructura](Infraestructura) -- [Limitaciones del servidor de producción](Limitaciones-servidor-prod) +### Operación — empieza por aquí +- [Producción Hetzner: acceso y ejecución](Produccion-Hetzner-acceso) ✅ *verificado 2026-08-12* +- [Trampas del entorno](Trampas-del-entorno) ✅ *verificado 2026-08-12* +- [Conocimiento heredado: dónde está todo](Conocimiento-heredado) - [Sincronización local → producción](Sincronizacion-local-prod) +### Operación — anterior al cutover de servidor ⚠️ +- [Infraestructura](Infraestructura) — la sección de producción describe CDMON +- [Limitaciones del servidor de producción](Limitaciones-servidor-prod) — **ya no aplican** +- [Credenciales y accesos](Credenciales-y-accesos) — ⚠️ contiene contraseñas, pendiente de limpiar + ### Arquitectura WordPress - [Arquitectura WordPress](Arquitectura-WordPress) - [Portada y shortcodes](Portada-y-shortcodes) @@ -45,7 +60,7 @@ Portal cristiano español de renovación de la fe. Documentación operativa del ## Repo -- **Código:** http://localhost:3000/rafa/feadulta · https://farmer.taild3aaf6.ts.net/git/rafa/feadulta +- **Código:** https://gitea.feadulta.com/rafa/feadulta +- **Issues:** https://gitea.feadulta.com/rafa/feadulta/issues - **Directorio local:** `/home/rafa/joomla-migration/` -- **Issues:** http://localhost:3000/rafa/feadulta/issues -- **Milestones:** `v1: Pre-cutover` · `v2: Post-launch` +- **Wiki del servidor:** https://gitea.feadulta.com/rafa/server/wiki diff --git a/Produccion-Hetzner-acceso.md b/Produccion-Hetzner-acceso.md new file mode 100644 index 0000000..fd388ae --- /dev/null +++ b/Produccion-Hetzner-acceso.md @@ -0,0 +1,105 @@ +# Producción (Hetzner + Coolify) — acceso y ejecución + +> Verificado contra el servidor el **2026-08-12** en solo lectura. — Opix +> +> Esta página **sustituye** a lo que dicen [[Infraestructura]] y +> [[Limitaciones-servidor-prod]] sobre producción: ambas describen el servidor +> anterior (cPanel/CDMON, `134.0.10.170`, `/web/wp-nuevo`), retirado en el cutover +> a Hetzner del **2026-08-03**. + +## SSH + +```bash +ssh -i ~/.ssh/id_ed25519 rafa@188.40.120.157 +# también por Tailscale: +ssh rafa@srv1.taild3aaf6.ts.net +``` + +⚠️ **La clave es `~/.ssh/id_ed25519`** (comentario `claude-code@feadulta`). +La otra clave del directorio, `~/.ssh/feadulta_ed25519` +(`claude-code@wsl-feadulta-deploy`, mayo 2026), **da `Permission denied`**: es de la +etapa CDMON. Es un error fácil de cometer porque el nombre parece el correcto. + +`FEA_PROD_SSH_PASS` en el perfil de Hermes está **vacío a propósito**: la +autenticación es por clave. Los scripts `sync_*_to_prod.py` caen a `ssh` normal +(sin `sshpass`) cuando esa variable está vacía. No es un valor que falte por rellenar. + +## El contenedor de WordPress + +| | | +|---|---| +| Contenedor | `wordpress-r2ssjifwj0r0ghyoqd528uaa` | +| Imagen | `wordpress:latest` — WordPress **7.0.3** | +| PHP | 8.3.31 (CLI) en `/usr/local/bin/php` | +| Docroot | `/var/www/html` (volumen persistente `r2ssjifwj0r0ghyoqd528uaa_wordpress-files`) | +| BD | contenedor `mysql-r2ssjifwj0r0ghyoqd528uaa` (MySQL 8) | +| Servicio Coolify | `feadulta-wp`, uuid `r2ssjifwj0r0ghyoqd528uaa` | + +En el mismo host conviven **tres WordPress** (feadulta, summaraise, aqtalent), el +relay de Buzz, el CRM Relaticle, Beszel y el mirror estático de Joomla. Comprueba +siempre el nombre completo del contenedor antes de un `docker exec`. + +## ⚠️ No hay WP-CLI en el contenedor + +`command -v wp` → nada. La imagen oficial `wordpress:latest` no lo incluye; no es un +fallo de configuración ni algo que se haya perdido. + +**La vía correcta es `php -r` cargando `wp-load.php`** — es lo que describe +`FEA_PROD_WPLOAD` del perfil de Hermes. + +```bash +ssh -i ~/.ssh/id_ed25519 rafa@188.40.120.157 \ + "docker exec wordpress-r2ssjifwj0r0ghyoqd528uaa php -r \ + 'require \"/var/www/html/wp-load.php\"; echo home_url(),\"|\",get_bloginfo(\"version\"),\"|\",wp_count_posts()->publish;'" +``` + +Salida real del 2026-08-12: + +``` +https://www.feadulta.com|7.0.3|29435 +``` + +### Scripts largos + +```bash +scp -i ~/.ssh/id_ed25519 script.php rafa@188.40.120.157:/tmp/script.php +ssh -i ~/.ssh/id_ed25519 rafa@188.40.120.157 \ + 'docker cp /tmp/script.php wordpress-r2ssjifwj0r0ghyoqd528uaa:/tmp/script.php && \ + docker exec wordpress-r2ssjifwj0r0ghyoqd528uaa php /tmp/script.php' +``` + +⚠️ Para copiar **directorios**, usa `docker cp origen/. :/destino/` con el `/.` +final. Sin él, si el destino ya existe, Docker crea `destino/origen` anidado — y +WordPress no carga mu-plugins desde subdirectorios, así que el despliegue queda +silenciosamente inactivo. Ver [[Trampas-del-entorno]]. + +## Verificación: Cloudflare sigue delante + +`curl -sI https://www.feadulta.com` devuelve **403** con `cf-mitigated: challenge`, +incluso desde el propio servidor. No se puede certificar nada con curl, Playwright, +headless ni `wp_remote_get`. La verificación de producción es **server-side** +(`docker exec … php -r`) o navegación humana real. + +Desde dentro del servidor, `curl -H 'Host: www.feadulta.com' http://127.0.0.1/` +sí llega al origen (302), saltándose Cloudflare. + +## Credenciales + +**No están en esta wiki y no deben estarlo.** Viven en: + +- `~/.hermes/profiles/feadulta/.env` (WSL) — host SSH, contenedor, wp-load. +- `~/.env` (WSL, permisos 600) — tokens de Gitea. +- `~/.ssh/id_ed25519` — clave de acceso al servidor. + +## Local, para contraste + +```bash +docker exec wordpress-web php -r 'require "/var/www/html/wp-load.php"; echo home_url();' +docker cp /tmp/x.php wordpress-web:/tmp/x.php && \ + docker exec wordpress-web wp eval-file /tmp/x.php --allow-root --path=/var/www/html +``` + +El local **sí** tiene wp-cli pero **no** cliente `mysql`: `wp db query` falla, hay que +usar `wp eval-file`. QA visual siempre contra `https://farmer.taild3aaf6.ts.net/fea/`, +que es el `siteurl` real — `localhost:8081` sirve desde la raíz y las `@font-face` +caen por CORS. diff --git a/Trampas-del-entorno.md b/Trampas-del-entorno.md new file mode 100644 index 0000000..5d4c547 --- /dev/null +++ b/Trampas-del-entorno.md @@ -0,0 +1,110 @@ +# Trampas del entorno + +> Consolidado por Opix el **2026-08-12** desde las skills de Hermes, filtrado contra +> el estado real del servidor tras el cutover a Hetzner del 2026-08-03. +> +> Lo marcado **[verificado]** se comprobó contra la máquina ese día. El resto es +> documentación heredada **sin re-verificar**: trátalo como pista, no como hecho. + +## Ya NO aplican — eran del jail de CDMON [verificado] + +Estas cuatro condicionaban buena parte de los procedimientos antiguos y **hoy son +falsas**. Si las lees en [[Limitaciones-servidor-prod]] o en las skills de Hermes, +están obsoletas. + +| Trampa vieja | Realidad en Hetzner | +|---|---| +| `proc_open()` deshabilitado | `disable_functions` vacío, funciona | +| No hay `mysqldump` ni `stat` | `stat` en el contenedor WP; `mysqldump 8.4.10` en el de MySQL | +| `php` y `grep` rotos (GLIBC) | PHP 8.3.31 y `grep` correctos | +| `scp`/`sftp` no funcionan | `scp` y `docker cp` normales | + +Importa más de lo que parece: varios procedimientos daban rodeos (subir ficheros con +`ssh 'cat > ruta'`, backups selectivos post a post, usar `wp` para todo porque `php` +estaba roto) que hoy son innecesarios. Copiarlos tal cual hereda los rodeos. + +Lo que **sí** falta hoy dentro del contenedor de WordPress: `wp`, `mysql`, +`mysqldump`, `git`, `python3`. Sí hay: `php`, `curl`, `grep`, `stat`, `tar`. + +## Siguen vigentes + +### Cloudflare bloquea curl y headless [verificado] +403 con `cf-mitigated: challenge`, también desde el propio servidor. Verificación +de prod siempre server-side. Ver [[Produccion-Hetzner-acceso]]. + +### `docker cp` anida directorios en silencio [verificado] +Si el destino ya existe como directorio, `docker cp origen :/ruta/destino` crea +`destino/origen`. Pasó desplegando mu-plugins el 2026-08-12: acabaron en +`wp-content/mu-plugins/mu-plugins/` y el lint posterior los dio por desaparecidos, +con la conclusión equivocada de que el volumen no persistía. + +Dos consecuencias: +1. **WordPress no carga mu-plugins desde subdirectorios** — solo los `.php` del + primer nivel. Un despliegue anidado no falla: queda inactivo sin avisar. +2. Antes de concluir "no persiste", mira el mount real: + ```bash + docker inspect --format '{{range .Mounts}}{{.Type}} {{.Destination}} <- {{.Source}}{{println}}{{end}}' + docker inspect --format 'Created={{.Created}} StartedAt={{.State.StartedAt}} RestartCount={{.RestartCount}}' + ``` + En feadulta, `/var/www/html` es el volumen `r2ssjifwj0r0ghyoqd528uaa_wordpress-files` + y el contenedor no se recrea desde el 2026-08-03 (`RestartCount=0`). + +Usa `docker cp origen/. :/destino/` para volcar contenido sin anidar. + +### hub-proxy nunca devuelve 404 +El nginx del hub responde la portada del Hub con **200 + text/html (20.597 bytes)** +para cualquier ruta desconocida. Comprueba `content_type` y tamaño, no solo el código. + +### Charset: el CLI de MySQL conecta en latin1 +Columnas en utf8mb4. Siempre `mysql --default-character-set=utf8mb4`, o corrompe acentos. + +### La categoría de la carta está partida en tres +6 `cartasemana` → 22 `carta-semana-pasada` → 21 `cartas-de-otras-semanas`. +Buscar siempre en las tres. Ver [[Carta-de-la-semana]]. + +### Heredadas, sin re-verificar +- **wp-cli y categorías**: `wp post term set category 28` asigna el término *de + nombre* "28", no el term_id. Usar el slug. +- **WP_Tax_Query + Polylang**: `get_posts(['lang'=>$x,'category__in'=>[$c]])` genera + `AND 0=1`. No pasar `lang` explícito. `get_term_by('slug',…)` en idioma ≠ ES + devuelve `false`: usar `$wpdb->get_var()`. +- **Títulos en MAYÚSCULAS** en la BD (legacy Joomla); `fea_title()` los normaliza en + el front. Es intencional. +- **Single posts usan template FSE** (Twenty Twenty-Five, post 42359), no Astra. +- **Páginas desde CLI**: HTML plano con shortcodes, nunca bloques Gutenberg. +- **URLs entre entornos**: local cuelga de `/fea`, prod de la raíz. No copiar + `post_content` sin reescribir. +- **IDs**: los de posts ES coinciden local↔prod; los de attachments y user_meta **no**. + +## Trampas de herramienta (agentes en WSL) + +### `wsl -d Ubuntu -- bash -lc '…'` rompe bucles y rutas +Las variables se pierden, los `for … in *.md` se comen los argumentos y las rutas +`/tmp/x.sh` se traducen a rutas de Windows. Escribe el `.sh` por UNC +(`\\wsl.localhost\Ubuntu\tmp\…`) y lánzalo con `bash -lc 'cd /tmp; bash x.sh'`. + +### `wp eval-file` y las globales +Dentro de una función, `global $X` **no** ve las variables del script: pásalas con `use`. + +### Regex en PHP sobre texto español: siempre `/u` +`m[áa]s` o `eucarist[ií]as` **sin** el modificador `u` no casan: las vocales +acentuadas ocupan 2 bytes y la clase de caracteres parte el UTF-8. Costó un +diagnóstico entero equivocado el 2026-08-12. + +### La API de wiki de Gitea +Devuelve `content_base64`, no `content`, y da **404 con títulos acentuados** aunque +el `sub_url` sea el que ella misma publica. Clona `.wiki.git` en su lugar. +(La wiki vive en el branch `main`; documentación antigua dice `master`.) + +## Trampas de método + +- **Contar en la BD antes de proponer un comando que muta.** No extrapolar el alcance + de un fix desde una página renderizada. +- **Seguir el camino completo del dato** antes de gritar "fuga a producción". +- **"El dato no existe" solo vale tras seguir los enlaces**, no solo los metas. +- **Antes de agrupar por un meta de origen, comprobar que no haya varios**: conviven + `_fgj2wp_old_k2_id` (K2, 18.121) y `_fgj2wp_old_id` (Joomla core, 9.022). +- **Verificar las dos mitades de una rotación**: que la carta nueva entre *y* que la + anterior salga. +- **Un issue no es un diario.** Si te retractas, se reescribe entero; el rastro va al + canal, no al ticket.