faramir con dos sitios web. gandalf, NO es origen de datos. Solo se migran ciertas tareas cron puntuales (ver Fase 7). (a eliminar ambos al final)Internet → gimli (nginx, SSL) → proxy_pass → faramir.proxy_pass hacia faramir: Internet → gimli (nginx, SSL) → local (PHP-FPM / archivos).proxy_pass por root/fastcgi_pass local en el vhost de gimli, una vez verificado que todo funciona. El rollback consiste en revertir esa línea.–all-databasespruebaewelinapmu.my.to (WordPress)arocha.my.to (Dokuwiki)check_sites, report_fail2ban, apto update, check_reboot y notify provienen de un repositorio común y ya existen en todas las máquinas (gandalf incluida) — no requieren verificación ni instalación# En gimli df -h /var/www df -h /tmp df -h /home # Espacio requerido: mínimo 3GB libres (datos + backups)
# En gimli sudo mkdir -p /var/www/dokuwiki sudo mkdir -p /var/www/pruebaewelinapmu sudo chown -R www-data:www-data /var/www/dokuwiki /var/www/pruebaewelinapmu sudo mkdir -p /tmp/migracion_backup
# En faramir mkdir -p ~/backup_migracion cd ~/backup_migracion
# 1. Identificar y volcar SOLO las bases de datos relevantes (WordPress + Dokuwiki si usa BD) sudo mysql -e "SHOW DATABASES;" grep -i "DB_NAME" /var/www/pruebaewelinapmu/wp-config.php sudo mysqldump --single-transaction --routines --triggers wordpress_db > wordpress_db.sql gzip wordpress_db.sql
# 2. Backup de Dokuwiki sudo tar -czf dokuwiki_backup.tar.gz -C /var/www dokuwiki
# 3. Backup de WordPress (completo) sudo tar -czf wordpress_backup.tar.gz -C /var/www pruebaewelinapmu
# 4. Backup de configuración Nginx (solo referencia, no se copiará entera a gimli) sudo tar -czf nginx_config_backup.tar.gz -C /etc nginx
# 5. Backup de crontabs crontab -l > crontab_usuario.txt sudo crontab -l > crontab_root.txt
# 6. Backup de listas de paquetes dpkg -l | grep '^ii' | awk '{print $2}' > paquetes_instalados.txt dpkg --get-selections > paquetes_selecciones.txt apt-mark showmanual > paquetes_manuales.txt
# 7. Verificar backups ls -lh tar -tzf dokuwiki_backup.tar.gz | head -20 tar -tzf wordpress_backup.tar.gz | head -20 zcat wordpress_db.sql.gz | head -50
# 8. Copiar backups a gimli scp *.tar.gz *.txt ubuntu@gimli:/tmp/migracion_backup/
# En gimli cd /tmp/migracion_backup ls -lh md5sum *.tar.gz *.txt # Guardar checksums para verificar integridad
No hay repositorios adicionales que sincronizar. Gimli parte sin base de datos (no tiene MariaDB instalado) y sin varios paquetes que sí están en faramir — hay que instalarlos todos antes de empezar el resto de la migración.
# En gimli cd /tmp/migracion_backup sudo apt update sudo apt install -y $(cat paquetes_instalados.txt) 2>&1 | tee instalacion_paquetes.log grep "Unable to locate package" instalacion_paquetes.log grep "dependency problems" instalacion_paquetes.log sudo systemctl restart php8.4-fpm mariadb
# En gimli sudo systemctl status nginx sudo systemctl status php8.4-fpm sudo systemctl status mariadb sudo systemctl status fail2ban
proxy_pass http://arocha.my.to; (y lo mismo para pruebaewelinapmu) no apunta a una IP directa: se resuelve vía /etc/hosts de gimli, donde arocha.my.to, luis-arocha.duckdns.org y pruebaewelinapmu.my.to están mapeados a 10.0.0.10 (faramir)./etc/hosts de gimli es compartido por todo el grupo (contiene también gandalf y boromir con sus propios dominios) — nunca tocar líneas ajenas a faramir.arocha en gimli YA tiene bloque SSL completo (certbot, redirección HTTP→HTTPS). El vhost de pruebaewelinapmu en gimli solo tiene listen 80, sin SSL, sin bloque de redirección, sin acme-challenge. Esto significa que probablemente no existe certificado emitido para pruebaewelinapmu todavía y hay que solicitarlo como parte de esta fase (no se puede asumir que ya existe, a diferencia de arocha).arocha además responde también en luis-arocha.duckdns.org — mantener ese alias.# En gimli sudo cp /etc/nginx/sites-available/pruebaewelinapmu /etc/nginx/sites-available/pruebaewelinapmu.bak.$(date +%Y%m%d) sudo cp /etc/nginx/sites-available/arocha /etc/nginx/sites-available/arocha.bak.$(date +%Y%m%d)
Combina la base de gimli (SSL, 10-restrict-methods.inc, protección anti-scraping de /doku.php) con la lógica real de Dokuwiki de faramir (rewrites, bloqueo de /conf/ y /data/, fastcgi local).
# En gimli sudo tee /etc/nginx/sites-available/arocha.new > /dev/null <<'EOF' #==============================================================================# # arocha.my.to (Dokuwiki) # #==============================================================================# server { include /etc/nginx/conf.d/10-restrict-methods.inc; listen [::]:443 ssl ipv6only=on; # managed by Certbot listen 443 ssl; # managed by Certbot server_name arocha.my.to luis-arocha.duckdns.org; root /var/www/dokuwiki; index index.php doku.php; client_max_body_size 4M; client_body_buffer_size 128K; location /robots.txt { alias /var/www/dokuwiki/robots.txt; } location /.well-known/acme-challenge { root /var/tmp/acme-challenges; try_files $uri =404; } location ^~ /conf/ { return 403; } location ^~ /data/ { return 403; } location ~ /\.ht { deny all; } location / { try_files $uri $uri/ @dokuwiki; } location @dokuwiki { rewrite ^/_media/(.*) /lib/exe/fetch.php?media=$1 last; rewrite ^/_detail/(.*) /lib/exe/detail.php?media=$1 last; rewrite ^/_export/([^/]+)/(.*) /doku.php?do=export_$1&id=$2 last; rewrite ^/(.*) /doku.php?id=$1 last; } # doku.php con la protección anti-scraping que antes filtraba el proxy_pass # (Referer + $is_deep_query + limit_req), ahora aplicada al fastcgi local. # location = /doku.php tiene prioridad sobre el bloque genérico ~ \.php$ location = /doku.php { limit_except GET HEAD POST OPTIONS { deny all; } expires -1; set $suspect ""; if ($is_deep_query) { set $suspect "D"; } if ($http_referer !~* "^https?://(arocha\.my\.to|luis-arocha\.duckdns\.org)/") { set $suspect "${suspect}R"; } if ($suspect = "DR") { return 403; } limit_req zone=deep_query_limit burst=10 nodelay; try_files $uri =404; fastcgi_pass unix:/run/php/php8.4-fpm.sock; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } location ~ \.php$ { try_files $uri =404; fastcgi_pass unix:/run/php/php8.4-fpm.sock; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } ssl_certificate /etc/letsencrypt/live/arocha.my.to/fullchain.pem; # managed by Certbot ssl_certificate_key /etc/letsencrypt/live/arocha.my.to/privkey.pem; # managed by Certbot include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot } server { if ($host = arocha.my.to) { return 301 https://$host$request_uri; } # managed by Certbot if ($host = luis-arocha.duckdns.org) { return 301 https://$host$request_uri; } # managed by Certbot listen 80; listen [::]:80; server_name arocha.my.to luis-arocha.duckdns.org; return 404; # managed by Certbot } EOF
⚠️ Requiere certificado nuevo (ver 2.4) antes de poder activar el bloque SSL tal cual está escrito abajo.
# En gimli sudo tee /etc/nginx/sites-available/pruebaewelinapmu.new > /dev/null <<'EOF' #==============================================================================# # pruebaewelinapmu.my.to (WordPress) # #==============================================================================# server { listen 80; listen [::]:80; include /etc/nginx/conf.d/10-restrict-methods.inc; server_name pruebaewelinapmu.my.to; root /var/www/pruebaewelinapmu; index index.php index.html; access_log /var/log/nginx/pruebaewelinapmu.access.log; error_log /var/log/nginx/pruebaewelinapmu.error.log; client_max_body_size 10M; location /robots.txt { alias /var/www/pruebaewelinapmu/robots.txt; } location /.well-known/acme-challenge { root /var/tmp/acme-challenges; try_files $uri =404; } location / { try_files $uri $uri/ /index.php?$args; } location ~ \.php$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:/run/php/php8.4-fpm.sock; # Este server block solo se alcanza por HTTPS (443), así que HTTPS # siempre es "on" aquí. El truco de faramir con X-Forwarded-Proto # ya no hace falta al servir localmente con SSL terminado en el # mismo nginx. fastcgi_param HTTPS on; } location ~ /\.ht { deny all; } location ~* /(?:xmlrpc\.php|wp-config\.php|readme\.html|license\.txt) { deny all; } } EOF
⚠️ Certbot con el plugin –nginx edita el vhost que esté activo en sites-enabled.
# En gimli - confirmar primero que efectivamente no existe: sudo certbot certificates | grep -A5 pruebaewelinapmu # Emitir por webroot (no toca el vhost activo en producción) sudo certbot -d pruebaewelinapmu.my.to # Verificar sudo certbot certificates | grep -A5 pruebaewelinapmu
# En gimli sudo nginx -t
Como los .new todavía no están en sites-enabled, para probarlos hay que apuntar php-fpm directamente o activar un puerto alternativo temporal. La forma más simple: comprobar a nivel de archivo y de PHP-FPM antes de que existan datos (esto se completa de verdad en la Fase 6, una vez migrados los ficheros y la BD):
# En gimli - comprobaciones básicas ahora; las pruebas HTTP completas se # hacen en la Fase 6 cuando los .new ya estén activados en un vhost de prueba php -v ls -la /etc/nginx/sites-available/*.new
⚠️ Nota de secuencia: los .new sustituyen por completo la lógica de proxy_pass. No se activan (no se copian sobre el fichero real ni se tocan symlinks de sites-enabled) hasta la Fase 7, una vez migrados y verificados los datos (Fases 3-6). Esto evita romper el sitio en producción antes de tiempo.
# En gimli sudo systemctl start mariadb sudo systemctl enable mariadb
# En gimli cd /tmp/migracion_backup sudo gunzip wordpress_db.sql.gz # Crear la BD si no existe (nombre real obtenido en 0.4) sudo mysql -e "CREATE DATABASE IF NOT EXISTS wordpress_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" sudo mysql wordpress_db < wordpress_db.sql sudo mysql -e "SHOW DATABASES;"
# En gimli - obtener credenciales exactas de faramir ssh ubuntu@faramir "grep -E 'DB_NAME|DB_USER|DB_PASSWORD|DB_HOST' /var/www/pruebaewelinapmu/wp-config.php" # Crear usuario en gimli SOLO si no existe ya (gimli aloja otras BD/usuarios) sudo mysql -e "CREATE USER IF NOT EXISTS 'wordpress_user'@'localhost' IDENTIFIED BY 'contraseña_segura';" sudo mysql -e "GRANT ALL PRIVILEGES ON wordpress_db.* TO 'wordpress_user'@'localhost';" sudo mysql -e "FLUSH PRIVILEGES;"
# En gimli cd /tmp/migracion_backup sudo tar -xzf dokuwiki_backup.tar.gz -C /var/www/ ls -la /var/www/dokuwiki
# En gimli - copia completa tal cual estaba en faramir cd /tmp/migracion_backup sudo rm -rf /var/www/pruebaewelinapmu sudo tar -xzf wordpress_backup.tar.gz -C /var/www/ ls -la /var/www/pruebaewelinapmu
# En gimli - el wp-config.php ya viene incluido en la copia completa. # Solo hay que revisar/actualizar credenciales de BD si difieren: sudo vim /var/www/pruebaewelinapmu/wp-config.php # Confirmar DB_HOST, DB_NAME, DB_USER, DB_PASSWORD
# En gimli sudo chown -R www-data:www-data /var/www/pruebaewelinapmu /var/www/dokuwiki sudo find /var/www/pruebaewelinapmu -type d -exec chmod 755 {} \; sudo find /var/www/pruebaewelinapmu -type f -exec chmod 644 {} \; sudo chmod 600 /var/www/pruebaewelinapmu/wp-config.php
# En gimli - cada sitio sirve su propio robots.txt (ya no comparten el de /var/www/html) ls -la /var/www/dokuwiki/robots.txt /var/www/pruebaewelinapmu/robots.txt 2>&1 # Si falta alguno, crear uno básico: [ -f /var/www/dokuwiki/robots.txt ] || echo -e "User-agent: *\nDisallow:" | sudo tee /var/www/dokuwiki/robots.txt [ -f /var/www/pruebaewelinapmu/robots.txt ] || echo -e "User-agent: *\nDisallow:" | sudo tee /var/www/pruebaewelinapmu/robots.txt sudo chown www-data:www-data /var/www/dokuwiki/robots.txt /var/www/pruebaewelinapmu/robots.txt
Sin WP-CLI instalado, se hace vía SQL directo. El prefijo de tablas (normalmente wp_, pero puede ser otro) está en $table_prefix dentro de wp-config.php.
# En gimli - comprobar prefijo de tablas grep table_prefix /var/www/pruebaewelinapmu/wp-config.php # Verificar URLs almacenadas (ajustar wp_ si el prefijo es distinto) sudo mysql wordpress_db -e "SELECT option_name, option_value FROM wp_options WHERE option_name IN ('siteurl','home');" # Si hace falta corregir (solo la URL exacta, no cambia rutas dentro de contenido): # sudo mysql wordpress_db -e "UPDATE wp_options SET option_value='https://pruebaewelinapmu.my.to' WHERE option_name IN ('siteurl','home');"
⚠️ Un simple UPDATE en wp_options no reescribe URLs que puedan estar serializadas dentro de otros campos (widgets, algunos ajustes de plugins). Si tras la migración se detectan URLs rotas en contenido serializado, ese caso puntual sí justificaría instalar WP-CLI temporalmente para usar wp search-replace (que gestiona la serialización correctamente) — evaluarlo solo si aparece el problema, no de forma preventiva.
Solo hace falta añadir check_sites y check_sites Diario (confirmado por Luis) más los ajustes de permisos propios de Dokuwiki. El resto de tareas que aparecían en el crontab original de gandalf/faramir (report_fail2ban, apto update, check_reboot, notify, copias/backup) ya existen en gimli — vienen de un repositorio común a todas las máquinas y no requieren ninguna acción.
# En gimli crontab -e # ========== DE GANDALF (a migrar) ========== 12 * * * * check_sites 15 09 * * * check_sites Diario # ========== NUEVAS, DE FARAMIR (permisos Dokuwiki) ========== 01 00 * * * sudo find /var/www/dokuwiki -type d -exec chmod 775 {} \; 02 00 * * * sudo find /var/www/dokuwiki -type f -exec chmod 664 {} \; 08 01 * * * sudo chown www-data:www-data -R /var/www/dokuwiki
# En gimli sudo crontab -e # ========== NUEVAS, DE FARAMIR (permisos WordPress) ========== */15 * * * * find /var/www/pruebaewelinapmu -type d -exec chmod g+rwx {} \; */15 * * * * find /var/www/pruebaewelinapmu -type f -exec chmod g+rw {} \;
# En gimli crontab -l sudo crontab -l
Este es el único momento en que los vhosts .new entran en juego antes del corte real. Se activan ya con la lógica final (local, sin proxy_pass), pero solo si Fases 3-5 (BD, archivos, permisos) ya están completas — si no, esta prueba fallará por falta de datos, no por la configuración de nginx.
# En gimli sudo cp /etc/nginx/sites-available/arocha.new /etc/nginx/sites-available/arocha sudo cp /etc/nginx/sites-available/pruebaewelinapmu.new /etc/nginx/sites-available/pruebaewelinapmu sudo nginx -t sudo systemctl reload nginx
⚠️ A partir de aquí, ambos dominios ya sirven en local (dejan de usar proxy_pass a faramir). Si algo falla en las pruebas siguientes, usar el rollback de 7.3 inmediatamente — no es necesario esperar a completar toda la Fase 6 para revertir.
# En gimli sudo systemctl status nginx php8.4-fpm mariadb fail2ban sudo netstat -tlnp | grep -E ':(80|443|3306)'
# En gimli sudo -u www-data ls -la /var/www/dokuwiki/data/ curl -I https://arocha.my.to curl -I https://luis-arocha.duckdns.org # Navegar manualmente y verificar: # - Página de inicio, edición de página, archivos multimedia # - Que la protección de /doku.php (Referer, limit_req) no bloquee uso normal
Sin WP-CLI, la verificación es a nivel de archivos, PHP-FPM y navegación real, en vez de comandos wp.
# En gimli curl -I https://pruebaewelinapmu.my.to curl -I https://pruebaewelinapmu.my.to/wp-admin # Confirmar que los plugins y temas migrados están presentes como archivos ls /var/www/pruebaewelinapmu/wp-content/plugins/ ls /var/www/pruebaewelinapmu/wp-content/themes/ # Verificar manualmente en el navegador: frontend, admin (login), PDFs, # imágenes, y que los plugins críticos funcionan correctamente
# En gimli sudo tail -f /var/log/nginx/error.log sudo tail -f /var/log/php8.4-fpm.log sudo tail -f /var/log/mysql/error.log sudo grep -i error /var/log/nginx/error.log | tail -20 sudo grep -i error /var/log/php8.4-fpm.log | tail -20
# En gimli - copias/backup y demás scripts comunes no requieren prueba # (ya funcionan igual que en el resto de máquinas del grupo) check_sites
Con la Fase 6.0, gimli ya sirve ambos dominios en local — el corte “real” ya ha ocurrido en el momento en que las pruebas de la Fase 6 se completan con éxito. Esta fase es solo para asegurar que no queda ningún dato desactualizado de última hora y dejar constancia formal del corte.
# En gimli - solo si ha pasado tiempo entre el backup (Fase 0) y este punto # y podría haber contenido nuevo en faramir (páginas de wiki editadas, # posts publicados, etc. mientras faramir seguía siendo el backend activo) rsync -avz --delete ubuntu@faramir:/var/www/dokuwiki/ /var/www/dokuwiki/ rsync -avz --delete --exclude='wp-config.php' \ ubuntu@faramir:/var/www/pruebaewelinapmu/ /var/www/pruebaewelinapmu/ ssh ubuntu@faramir "sudo mysqldump --single-transaction wordpress_db" > /tmp/wordpress_final.sql sudo mysql wordpress_db < /tmp/wordpress_final.sql sudo systemctl reload nginx
⚠️ Si se ejecuta este paso, hay que repetir las pruebas clave de la Fase 6 (frontend, admin, multimedia) tras la resincronización.
# En gimli - basta con restaurar el vhost con proxy_pass a faramir sudo cp /etc/nginx/sites-available/pruebaewelinapmu.bak.$(date +%Y%m%d) /etc/nginx/sites-available/pruebaewelinapmu sudo cp /etc/nginx/sites-available/arocha.bak.$(date +%Y%m%d) /etc/nginx/sites-available/arocha sudo nginx -t sudo systemctl reload nginx # Faramir no ha sido tocado en ningún momento, por lo que el tráfico # vuelve a funcionar de inmediato en cuanto se recarga nginx
Modificar el script backup_data.
# En gimli - monitoreo, faramir se mantiene encendido e intacto como red de seguridad watch -n 30 'curl -s -o /dev/null -w "%{http_code}" https://pruebaewelinapmu.my.to && echo " - WordPress OK"' watch -n 30 'curl -s -o /dev/null -w "%{http_code}" https://arocha.my.to && echo " - Dokuwiki OK"'
# En gimli - eliminar las referencias a gandalf y faramir (ya no se necesitan: # gandalf porque los scripts se obtienen del repositorio común, no por IP; # faramir porque gimli ya sirve ambos sitios en local). NO tocar boromir. sudo vim /etc/hosts # Eliminar las líneas: # 10.0.0.201 gandalf # 10.0.0.10 pruebaewelinapmu.my.to # 10.0.0.10 faramir # 10.0.0.10 arocha.my.to # 10.0.0.10 luis-arocha.duckdns.org cat /etc/hosts
⚠️ Revisar el resultado a mano antes de guardar — no usar sed automático aquí, mejor edición manual para no arriesgar el resto del fichero (compartido con boromir y otros sitios del grupo).
Tras confirmar que gimli funciona correctamente sin incidencias durante el periodo de observación, eliminar faramir y gandalf por completo (instancia y volumen de disco) desde la consola de Oracle Cloud.
Verificar que la instancia y el volumen han desaparecido.
⚠️ Este paso es irreversible: no hay backup posterior de faramir ni desmantelamiento gradual — se destruye la máquina y su disco directamente. Confirmar que el periodo de observación (8.1) ha sido satisfactorio antes de ejecutar.