From c91c14e2684f6bc9b24f4be7244e547206ede846 Mon Sep 17 00:00:00 2001 From: rafa Date: Mon, 15 Jun 2026 15:57:39 -0400 Subject: [PATCH] Actualizar docs de prod a wp-nuevo (134.0.10.170) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Credenciales: wp-nuevo + SSH actual + DB cambiante; .org desmontado - Infraestructura: sección Producción a wp-nuevo + Cloudflare + herramientas - Limitaciones: jail cPanel actual (scp no, ssh cat, proc_open, Cloudflare, GD) - Sincronización: método tar + ssh cat + wp eval-file; ejemplo avatares #62 --- Credenciales-y-accesos.md | 84 +++++++++-------- Infraestructura.md | 16 ++-- Limitaciones-servidor-prod.md | 82 +++++++---------- Sincronizacion-local-prod.md | 166 ++++++++++++---------------------- 4 files changed, 146 insertions(+), 202 deletions(-) diff --git a/Credenciales-y-accesos.md b/Credenciales-y-accesos.md index 16983ec..dd5d35a 100644 --- a/Credenciales-y-accesos.md +++ b/Credenciales-y-accesos.md @@ -1,62 +1,72 @@ # Credenciales y accesos > **Wiki privada.** Estas credenciales solo son visibles para usuarios autenticados en Gitea local. +> **Actualizado: 2026-06-15.** El antiguo hosting `feadulta.org` (WP staging Dreamhost) fue **desmontado el 2026-05-24** — sus credenciales (SSH `feadultada`, HTTP Basic Auth `feadul316`, DB `278025353...`) ya **NO aplican**. -## HTTP Basic Auth (protege la web hasta el cutover) +## Producción actual: WordPress nuevo (wp-nuevo) -Se quita en el cutover. Mientras está activo, cualquier petición a `feadulta.org` pide usuario/password antes de cargar WordPress. +El WP de la migración vive ahora en el **mismo servidor que el Joomla de producción**, bajo `/web/wp-nuevo/`. | | | |---|---| -| Usuario | `feadul316` | -| Contraseña | `X5nWjWrnPg7F` | +| Subdominio | `wp-nuevo.feadulta.com` (detrás de **Cloudflare**) | +| WP root | `/web/wp-nuevo/` | +| ⚠️ NO tocar | `/web/` = Joomla vivo (feadulta.com). `/web/anterior/` = web V1 FrontPage (2006-2012) | -## WordPress Admin +### SSH (mismo acceso para wp-nuevo y Joomla) + +| | | +|---|---| +| Host | `134.0.10.170` | +| Usuario | `feadulta` | +| Contraseña | `C6c2A!mAl3Wj.BQF` (cambiada 2026-06-14; host key ED25519) | +| HOME | `/entrada` | + +```bash +sshpass -p 'C6c2A!mAl3Wj.BQF' ssh -o StrictHostKeyChecking=accept-new feadulta@134.0.10.170 '' +# si "host key changed": ssh-keygen -f ~/.ssh/known_hosts -R 134.0.10.170 y reconectar +``` + +### Base de datos de wp-nuevo + +El **nombre de la BD cambia** (se regenera con cada dump) → leerlo de `/web/wp-nuevo/wp-config.php` (`DB_NAME`). + +| | | +|---|---| +| Host | `127.0.0.1` (solo desde el server) | +| Usuario | `myfeadulta` | +| Contraseña | `7c7J*VqU.v1WhsHu` | +| Prefijo | `wp_` · Charset columnas **utf8mb4** | + +```bash +# SIEMPRE --default-character-set=utf8mb4 (la conexión por defecto es latin1 y corrompe acentos) +DB=$(grep DB_NAME /web/wp-nuevo/wp-config.php | sed -E "s/.*'DB_NAME', *'([^']+)'.*/\1/") +mysql --default-character-set=utf8mb4 -h127.0.0.1 -umyfeadulta -p'7c7J*VqU.v1WhsHu' "$DB" -e "SQL" +``` + +### WordPress Admin | Entorno | URL | Usuario | Contraseña | |---|---|---|---| | Local (Tailscale) | https://farmer.taild3aaf6.ts.net/fea/wp-admin | `eqpyk` | `NuevaFeAdulta2024!` | -| Producción | http://feadulta.org/wp-admin/ | `eqpyk` | `NuevaFeAdulta2026!` | +| Prod (wp-nuevo) | https://wp-nuevo.feadulta.com/wp-admin | `eqpyk` | `NuevaFeAdulta2024!` | -## SSH producción +## Joomla producción (feadulta.com, VIVO — solo lectura salvo migración) + +Mismo servidor/SSH que arriba. **No cambiar** credenciales de cPanel ni de los admin Joomla (765 josek = hermana de Rafa, 763 icalvotorre, 57 calvo). | | | |---|---| -| Host | `feadulta.org` | -| Usuario | `feadultada` | -| Contraseña | `mzdY69rn0B2N-UIX` | -| WP root | `/web/` | - -## Base de datos producción - -Solo accesible desde el server (no expuesta al exterior). - -| | | -|---|---| -| Host | `127.0.0.1` | -| DB | `278025353wordpress20260112013937` | -| Usuario | `myfeadultaa5` | -| Contraseña | `KjyGU29h` | - -Comando habitual: -```bash -mysql -h127.0.0.1 -umyfeadultaa5 -pKjyGU29h 278025353wordpress20260112013937 -``` +| DB | `fejoomla3` · user `fejoomla3` · pass `5FF-}5^[>7^pK4W9` · host `127.0.0.1` | +| Prefijo | `ew4r_` (K2 en `ew4r_k2_items`, cartas/contenido en `ew4r_content`) | ## Base de datos local (Docker) | | | |---|---| -| Host | `172.18.0.2` | -| DB | `wordpress_db` | -| Usuario | `wordpress_user` | -| Contraseña | `wordpress_pass` | +| Host | `172.18.0.2` (container `wordpress-mysql`) | +| DB | `wordpress_db` · user `wordpress_user` · pass `wordpress_pass` | ## Brevo (boletín) -- Cuenta SendinBlue/Brevo ID `c3555982` -- URL del formulario embebido: ver [Alta-boletin-Brevo](Alta-boletin-Brevo) - -## Joomla (legacy, solo lectura) - -Container local `joomla-web` (puerto 8080) sigue disponible para consulta histórica de la BD K2 original. Credenciales del container en `/home/rafa/joomla-migration/docker-compose.yml`. +- Cuenta Brevo ID `c3555982` · formulario embebido: ver [Alta-boletin-Brevo](Alta-boletin-Brevo) diff --git a/Infraestructura.md b/Infraestructura.md index 0fd934f..5db00d5 100644 --- a/Infraestructura.md +++ b/Infraestructura.md @@ -52,18 +52,18 @@ docker exec -it wordpress-web bash # Entrar al WP docker exec wordpress-mysql mysql -uwordpress_user -pwordpress_pass wordpress_db ``` -## Producción +## Producción (actualizado 2026-06-15) -Hosting Dreamhost compartido. Limitaciones importantes — ver [Limitaciones del servidor de producción](Limitaciones-servidor-prod). +> El antiguo `feadulta.org` (Dreamhost) fue **desmontado el 2026-05-24**. El WP de producción vive ahora en `wp-nuevo`, en el **mismo servidor que el Joomla**. Limitaciones importantes — ver [Limitaciones del servidor de producción](Limitaciones-servidor-prod). | | | |---|---| -| Host | `feadulta.org` | -| Usuario SSH | `feadultada` | -| Document root | `/web/` | -| PHP | 8.x, con `proc_open` desactivado | -| wp-cli | Instalado en `/web/`, invocar con `wp --path=/web/ ` | -| DB | MySQL local al server (127.0.0.1) | +| Subdominio | `wp-nuevo.feadulta.com` (detrás de **Cloudflare** → bloquea curl/headless con 403) | +| Host SSH | `134.0.10.170` · usuario `feadulta` (ver [Credenciales](Credenciales-y-accesos)) | +| WP root | `/web/wp-nuevo/` · ⚠️ `/web/` = Joomla vivo, NO tocar | +| PHP | 8.3 · **`proc_open` desactivado** · GD + Imagick disponibles | +| Herramientas | `wp` (wp-cli 2.12), `php`, `composer`, `git`, `svn`, `tar`, `mysql` · NO hay `scp`/`sftp`/`mysqldump`/`stat`/`python3`/`curl`/`which` | +| DB | MySQL `127.0.0.1`, **nombre cambiante** (leer de wp-config), user `myfeadulta` | ## Git diff --git a/Limitaciones-servidor-prod.md b/Limitaciones-servidor-prod.md index 8deb81a..91556f0 100644 --- a/Limitaciones-servidor-prod.md +++ b/Limitaciones-servidor-prod.md @@ -1,72 +1,58 @@ -# Limitaciones del servidor de producción +# Limitaciones del servidor de producción (wp-nuevo) -Hosting compartido (Dreamhost). Más restrictivo de lo habitual. **Leer antes** de plantear cualquier operación contra prod. +> **Actualizado 2026-06-15.** Esta página describe el servidor **actual** (`134.0.10.170`, el mismo del Joomla, donde vive `/web/wp-nuevo/`). El antiguo Dreamhost `.org` se desmontó el 2026-05-24. -## Lo que NO hay instalado / disponible +Shell muy restringido (jail cPanel). **Leer antes** de plantear cualquier operación contra prod. + +## Lo que SÍ hay (habilitado por Rafa) + +`php` 8.3 · `wp` (wp-cli 2.12) · `composer` · `git` · `svn` · `tar` · `mysql` · `bash`, `ls`, `echo`, `cat` · GD + Imagick. + +## Lo que NO hay | | Implicación | |---|---| -| ❌ `sshpass` | No se puede automatizar `ssh` con password desde el server. Las conexiones se hacen desde el local con `paramiko`. | -| ❌ `sftp` | No se pueden subir ficheros por SFTP. Hay que usar **PHP + base64 + paramiko** (ver [Sincronización local → producción](Sincronizacion-local-prod)). | -| ❌ `python3` | Nada de scripts Python en el server. Los scripts viven en local y se conectan por SSH ejecutando PHP. | -| ❌ `base64` (cmdline) | No hay binario `base64` en `PATH`. Hay que usar PHP (`base64_decode`) para decodificar payloads. | +| ❌ `scp` / `sftp` | "Connection closed" (jail). Subir ficheros con `ssh '... cat > /ruta'` < fichero_local (binario-safe). | +| ❌ `mysqldump` | No hay backup/dump por línea de comando. Backup = selectivo con `wp post get` / `wp eval` a fichero. | +| ❌ `stat`, `which`, `uname`, `hostname` | Verificar tamaños con `wc -c`, no con `stat`. | +| ❌ `python3`, `curl`, `wget` | Nada de scripts Python ni verificación HTTP desde el server. | -## PHP en prod +## PHP: `proc_open` desactivado -- Versión PHP: 8.x (compartido) -- **`proc_open` está desactivado** → cualquier librería que lo necesite falla: - - `wp-cli db query` → ❌ FALLA. Usar `mysql` directo. - - Cualquier wrapper que use `Symfony\Process` → riesgo de falla. +Cualquier comando wp-cli que invoque un binario externo **FALLA**: -## wp-cli - -✅ Está instalado en `/web/`. Se invoca con: +- ❌ `wp db export` / `wp db import` (usan mysqldump) · `wp search-replace` puede fallar. +- ✅ Funcionan (acceden por PHP): `wp post get/update/list`, `wp option`, `wp eval`, **`wp eval-file`**, `wp cache flush`, `wp user meta get/update`. ```bash -wp --path=/web/ +cd /web/wp-nuevo && wp --skip-plugins --skip-themes ``` -Funciona para la mayoría de operaciones (`post update`, `post create`, `term get`, `option get`, etc.). Solo falla lo que requiere `proc_open` (en la práctica: `wp db query`). +> Usa `--skip-plugins --skip-themes` para evitar warnings/errores de plugins al correr wp-cli. + +## Cloudflare + +`wp-nuevo.feadulta.com` está **detrás de Cloudflare** → bloquea `curl`/Playwright/headless con **403 "Attention Required"**. +**No se puede verificar con curl ni navegador headless.** Verificar **server-side** (`wp eval`, `wp post get`) o pedir a Rafa que mire en su navegador. ## MySQL -``` -Host: 127.0.0.1 (NO está expuesto al exterior — solo accesible desde el server) -DB: 278025353wordpress20260112013937 -User: myfeadultaa5 -Pass: KjyGU29h -``` - -Comando directo (siempre vía SSH): - ```bash -mysql -h127.0.0.1 -umyfeadultaa5 -pKjyGU29h 278025353wordpress20260112013937 -e "SELECT ..." +# nombre de BD cambiante -> leerlo de wp-config; SIEMPRE utf8mb4 +DB=$(grep DB_NAME /web/wp-nuevo/wp-config.php | sed -E "s/.*'DB_NAME', *'([^']+)'.*/\1/") +mysql --default-character-set=utf8mb4 -h127.0.0.1 -umyfeadulta -p'7c7J*VqU.v1WhsHu' "$DB" -e "SELECT ..." ``` ## Acceso SSH -``` -ssh feadultada@feadulta.org # password: mzdY69rn0B2N-UIX +```bash +sshpass -p 'C6c2A!mAl3Wj.BQF' ssh -o StrictHostKeyChecking=accept-new feadulta@134.0.10.170 '' ``` -Tarda un poco en establecer la conexión (no usa key auth en este momento — sería bueno cambiarlo). +`sshpass` SÍ funciona desde el local (ya no se usa paramiko). HOME en el server = `/entrada`. -## Estrategia de operación +## Gotchas -Por las limitaciones anteriores: - -1. **Todo el código y los scripts viven en local.** El server solo ejecuta comandos sueltos. -2. **Para subir ficheros:** `paramiko` desde local + `php -r "file_put_contents(...)"` en server, payload codificado en base64. -3. **Para tocar BD:** `mysqldump` local + `mysql -e` en prod, transferidos por el mismo método de payload. -4. **Para automatizar:** scripts Python en local, NO en prod. - -## Otros gotchas - -- El **caché de Astra** puede mantener CSS viejo. Hay que limpiar manualmente desde wp-admin después de cambiar shortcodes/CSS. -- **UpdraftPlus** corre en prod. Si haces un restore puede sobreescribir mu-plugins recientes — ten cuidado tras un restore con verificar `fea-homepage.php` y `carta-semana-plugin.php`. Ya pasó al menos una vez con EFFA (2026-03-14). -- **HTTP Basic Auth** se desactiva en el cutover. Si haces tests automáticos contra prod ahora, hay que pasar las credenciales (`feadul316:X5nWjWrnPg7F`) o el server contesta 401. - -## Pendientes / mejoras - -- [ ] Cambiar a SSH key auth en lugar de password (sigue pendiente). -- [ ] Documentar en este repo el comando para limpiar caché (Astra + cualquier object cache). +- ⚠️ **`/web/` es el Joomla VIVO — no tocar.** Solo `/web/wp-nuevo/`. `/web/anterior/` = web V1 FrontPage. +- Tras cambios, limpiar caché: `wp --skip-plugins --skip-themes cache flush`. +- Charset: la conexión `mysql` por defecto es latin1 → sin `--default-character-set=utf8mb4` se corrompen acentos. diff --git a/Sincronizacion-local-prod.md b/Sincronizacion-local-prod.md index faba0d6..2be796d 100644 --- a/Sincronizacion-local-prod.md +++ b/Sincronizacion-local-prod.md @@ -1,134 +1,82 @@ -# Sincronización local → producción +# Sincronización local → producción (wp-nuevo) -Regla general: cualquier cambio en local debe replicarse en producción **del mismo modo**, porque los IDs y las versiones de código viven en paralelo. +> **Actualizado 2026-06-15.** Prod = `/web/wp-nuevo/` en `134.0.10.170` (mismo server que el Joomla). El método con `paramiko` + base64 del `.org` viejo **ya no se usa**: ahora `sshpass` y `tar` están disponibles. -Antes de tocar nada, lee [Limitaciones del servidor de producción](Limitaciones-servidor-prod) — sin esas restricciones, lo que sigue no tiene sentido. +Antes de tocar nada, lee [Limitaciones del servidor de producción](Limitaciones-servidor-prod). -## Tipos de cambio y método +Regla general: los **IDs y el código viven en paralelo** entre local y prod (misma migración). Replica los cambios del mismo modo y mantén los IDs sincronizados. -| Cambio | Cómo replicar a producción | -|---|---| -| **mu-plugins** (`fea-homepage.php`, `carta-semana-plugin.php`) | PHP + base64 + `paramiko` (ver más abajo) | -| **Posts / páginas nuevas** | `wp --path=/web/ post create` vía SSH (paramiko) | -| **Metas de BD masivas** | `mysqldump` local + `mysql` directo en prod | -| **Cambios puntuales en BD** | `mysql -h127.0.0.1 -u... -p... DB -e "SQL"` vía SSH | -| **Files (imágenes, JS, CSS)** | Igual que mu-plugins: PHP + base64 + paramiko | - -## Método canónico: PHP + base64 + paramiko - -Funciona porque NO requiere `sftp`, `sshpass` ni `base64` en el server — solo PHP y SSH. - -```python -import paramiko, base64 - -client = paramiko.SSHClient() -client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) -client.connect('feadulta.org', - username='feadultada', - password='mzdY69rn0B2N-UIX') - -with open('/local/path/file.php', 'rb') as f: - content = f.read() - -# Importante: vaciar el destino antes de empezar (file_put_contents con FILE_APPEND) -client.exec_command("php -r \"file_put_contents('/ruta/destino', '');\"") - -chunk_size = 50_000 # 50 KB -for i in range(0, len(content), chunk_size): - chunk = content[i:i + chunk_size] - b64 = base64.b64encode(chunk).decode() - cmd = f"php -r \"file_put_contents('/ruta/destino', base64_decode('{b64}'), FILE_APPEND);\"" - client.exec_command(cmd) -``` - -> El chunk de 50KB evita que el shell rechace la línea por longitud. PHP `base64_decode` lo reconstruye binariamente en destino. - -## Importar SQL en prod - -Después de generar `/tmp/algo.sql` (en local o subido a prod por el método anterior): +## Acceso ```bash -mysql -h127.0.0.1 -umyfeadultaa5 -pKjyGU29h \ - 278025353wordpress20260112013937 < /tmp/algo.sql +export SSHPASS='C6c2A!mAl3Wj.BQF' +SSH="sshpass -e ssh -o StrictHostKeyChecking=accept-new feadulta@134.0.10.170" +WP="cd /web/wp-nuevo && wp --skip-plugins --skip-themes" ``` -Vía paramiko: +## Subir ficheros (scp/sftp NO funcionan) -```python -client.exec_command( - "mysql -h127.0.0.1 -umyfeadultaa5 -pKjyGU29h " - "278025353wordpress20260112013937 < /tmp/algo.sql" -) +Fichero único (binario-safe): +```bash +$SSH 'cat > /web/wp-nuevo/wp-content/.../destino.png' < /local/fichero.png +$SSH 'wc -c /web/wp-nuevo/wp-content/.../destino.png' # verificar tamaño (no hay stat) ``` -## Export de metas/posts desde local +Muchos ficheros → empaquetar y extraer con `tar` (sí existe en prod): +```bash +tar czf /tmp/bundle.tgz -C /local/dir subcarpeta/ # ojo a las rutas relativas del tar +$SSH 'cat > /web/wp-nuevo/wp-content/uploads/bundle.tgz' < /tmp/bundle.tgz +$SSH 'cd /web/wp-nuevo/wp-content/uploads && tar xzf bundle.tgz && rm bundle.tgz' +``` + +## mu-plugins (`fea-homepage.php`, `carta-semana-plugin.php`) ```bash -docker exec wordpress-mysql mysqldump \ - -uwordpress_user -pwordpress_pass wordpress_db wp_postmeta \ - --where="meta_key IN ('_cita_evangelio','_carta_id')" \ - --no-create-info --complete-insert --skip-extended-insert \ - > /tmp/metas.sql +# backup primero (no hay mysqldump/stat; cp sí) +$SSH 'cp /web/wp-nuevo/wp-content/mu-plugins/fea-homepage.php /entrada/fea-homepage.php.bak-$(date +%Y%m%d-%H%M)' +# subir +$SSH 'cat > /web/wp-nuevo/wp-content/mu-plugins/fea-homepage.php' < wordpress/wp-content/mu-plugins/fea-homepage.php +``` -# Quitar el meta_id para evitar conflictos de PK en prod -sed -i 's/INSERT INTO `wp_postmeta` (`meta_id`, /INSERT INTO `wp_postmeta` (/g; s/(NULL, /(/g' /tmp/metas.sql +> ⚠️ **No copiar `post_content` local→prod**: mete URLs de `farmer.taild3aaf6.ts.net`. Transformar siempre sobre el contenido descargado de prod (`wp post get ID --field=content`), preservando sus URLs `wp-nuevo.feadulta.com`. + +## Posts / metas / opciones + +Vía `wp eval-file` (sube el .php con `cat >` y ejecútalo). `proc_open` off → **no** `wp db query/import`; usar `wp eval`, `wp post update ID /ruta/fichero`, o `mysql` directo. + +```bash +$SSH 'cat > /web/wp-nuevo/script.php' < script.php +$SSH 'cd /web/wp-nuevo && APPLY=1 wp --skip-plugins --skip-themes eval-file script.php' +``` + +## Verificar (Cloudflare bloquea curl/headless) + +Server-side únicamente, o pedir a Rafa que mire en el navegador: +```bash +$SSH 'cd /web/wp-nuevo && wp --skip-plugins --skip-themes post get ID --field=content' +$SSH 'cd /web/wp-nuevo && wp --skip-plugins --skip-themes eval "echo wp_get_attachment_url(ID);"' +$SSH 'cd /web/wp-nuevo && wp --skip-plugins --skip-themes cache flush' ``` ## Sincronizar IDs entre local y prod -Cuando local y prod crean el mismo post con IDs distintos (porque WP autoincrementa por separado), arreglar con UPDATEs directos en prod **usando offset temporal** para evitar conflictos de PK. +Los IDs de objetos suelen **coincidir** local↔prod (menú 1, archive 26561, cabecera 42366, pie 42370, template single 42359). Si difieren, mover con offset temporal +99000 para evitar conflictos de PK: ```sql --- 1) Mover a IDs temporales (offset +99000) -UPDATE wp_posts SET ID = ID + 99000 - WHERE ID IN (43905, 43906, 43907, 43908); -UPDATE wp_postmeta SET post_id = post_id + 99000 - WHERE post_id IN (43905, 43906, 43907, 43908); -UPDATE wp_term_relationships SET object_id = object_id + 99000 - WHERE object_id IN (43905, 43906, 43907, 43908); - --- 2) Mover a los IDs finales (los de local) -UPDATE wp_posts SET ID = 43906 WHERE ID = 143904; -UPDATE wp_postmeta SET post_id = 43906 WHERE post_id = 143904; -UPDATE wp_term_relationships SET object_id = 43906 WHERE object_id = 143904; --- (... repetir para cada post a sincronizar) +UPDATE wp_posts SET ID = ID + 99000 WHERE ID IN (...); +UPDATE wp_postmeta SET post_id = post_id + 99000 WHERE post_id IN (...); +UPDATE wp_term_relationships SET object_id = object_id + 99000 WHERE object_id IN (...); +-- luego mover a los IDs finales ``` -### Lección clave +## Ejemplo real: despliegue de avatares (issue #62, 2026-06-15) -> **No uses IDs hardcodeados distintos por entorno** ni queries dinámicas tipo `get_page_by_path()` para resolver IDs de posts conocidos. Sincroniza los IDs entre local y prod desde el momento en que crees el post, y hardcodea con seguridad. +Patrón completo de referencia (genera PNGs en local → tar → `ssh cat` → `tar xzf` → `wp eval-file` que crea attachments y reapunta `foto_perfil`, con backup en `_foto_perfil_pre62`): -Esta lección viene del trabajo con [Evangelios y comentarios](Evangelios-y-comentarios). +1. Generar ficheros en local (`/tmp/...` → `uploads/avatares/autores/`). +2. `tar czf` con rutas relativas correctas + manifest `uids.json` + script importer. +3. `ssh 'cat > .../bundle.tgz'` < bundle · `tar xzf`. +4. `APPLY=1 wp eval-file import_prod_62.php` (dry-run sin `APPLY`). +5. Verificar server-side con `wp eval` (contar reapuntados); limpiar caché. -## wp-cli en producción - -```bash -wp --path=/web/ -``` - -`proc_open` está desactivado → `wp db query` y similares **NO funcionan**. Usar `mysql` directo. - -## Flujo típico cuando cambias un shortcode - -1. Editas `fea-homepage.php` en `/home/rafa/joomla-migration/wordpress/wp-content/mu-plugins/`. -2. Verificas en local (https://farmer.taild3aaf6.ts.net/fea/). -3. Subes a prod con paramiko + base64. -4. Vacías cualquier caché en prod (Astra / object cache si aplica). -5. Commit + push al repo Gitea. - -## Backup antes de tocar prod - -Antes de un UPDATE masivo o de tocar un fichero PHP en prod: - -```bash -# Backup del mu-plugin -ssh feadultada@feadulta.org "cp /web/wp-content/mu-plugins/fea-homepage.php \ - /web/wp-content/mu-plugins/fea-homepage.php.bak.$(date +%Y%m%d-%H%M)" - -# Backup parcial de BD -ssh feadultada@feadulta.org "mysqldump -h127.0.0.1 -umyfeadultaa5 -pKjyGU29h \ - 278025353wordpress20260112013937 wp_postmeta \ - --where=\"meta_key='_carta_id'\" > /tmp/backup_carta_id.sql" -``` - -UpdraftPlus también está corriendo en prod, pero el backup manual es más rápido para cambios puntuales. +Scripts en `wordpress/wp-content/uploads/avatares/` (local). Ver `master-feadulta.md` para detalle.