--- title: "Replicación de MySQL entre centros de datos en Ubuntu 24.04" description: "Replica MySQL con GTID y TLS entre dos centros de datos, sincroniza archivos con rsync, vigila el retraso y promueve la réplica si cae el servidor principal." category: "Migración y Recuperación ante Desastres" language: es source: https://cubepath.com/es/docs/migración-y-recuperación-ante-desastres/estrategias-de-replicacion-entre-centros-de-datos updated: 2026-09-25 --- # Replicación de MySQL entre centros de datos en Ubuntu 24.04 Replicar los datos a un segundo centro de datos permite recuperar un servicio en minutos cuando cae el principal, con una pérdida de datos de segundos en lugar de las horas que separan dos copias de seguridad. En esta guía montarás una réplica de MySQL 8.0 con GTID y conexión cifrada entre dos servidores Ubuntu 24.04 situados en ubicaciones distintas, sincronizarás los archivos de la aplicación con rsync y verás cómo promover la réplica si el principal deja de estar disponible. ## Elegir la estrategia de replicación Antes de configurar nada conviene saber qué ofrece cada opción habitual: | Estrategia | Tipo | Pérdida de datos si cae el principal | Adecuada entre centros de datos | |---|---|---|---| | Replicación asíncrona de MySQL | Lógica, asíncrona | Segundos (lo que no se haya replicado) | Sí, tolera latencia alta | | Streaming replication de PostgreSQL | Física, asíncrona o síncrona | Segundos o cero si es síncrona | Sí; la síncrona añade la latencia del enlace a cada commit | | Galera / Group Replication | Síncrona, multimaestro | Cero | Solo con latencias bajas y al menos tres nodos | | DRBD | Bloque | Cero en modo síncrono | Poco recomendable con latencias de WAN | | rsync periódico | Archivos | Lo cambiado desde la última ejecución | Sí, para archivos que cambian poco | Para la mayoría de aplicaciones web la combinación más sensata entre centros de datos es replicación asíncrona de la base de datos y rsync para los archivos, que es lo que se configura aquí. La replicación síncrona entre ubicaciones lejanas penaliza cada escritura con el tiempo de ida y vuelta del enlace. ## Requisitos previos - Dos servidores con Ubuntu 24.04 LTS en centros de datos distintos, por ejemplo dos VPS de CubePath en ubicaciones diferentes: - **Principal** (`primary_ip`), con MySQL y los datos actuales. - **Réplica** (`replica_ip`), recién instalado. - Un usuario no root con privilegios `sudo` en ambos. - MySQL 8.0 del repositorio de Ubuntu (`sudo apt install mysql-server`) en los dos servidores. Deben tener la misma versión. - Conectividad entre ambos en el puerto 3306. Lo ideal es un túnel privado (WireGuard o la red privada del proveedor); si usas IP públicas, restringe el acceso con el cortafuegos como se indica en el paso 1. En la guía, la base de datos de la aplicación se llama `your_database`. ## Paso 1: Configurar el servidor principal La replicación basada en GTID identifica cada transacción con un ID global, así que la réplica sabe siempre por dónde va sin tener que indicar archivos y posiciones del registro binario. Eso simplifica mucho la conmutación por error. En el **principal**, crea un archivo de configuración propio. Los archivos de `/etc/mysql/mysql.conf.d/` se leen en orden alfabético, así que este se aplica después de `mysqld.cnf` y sus valores prevalecen: ```bash sudo nano /etc/mysql/mysql.conf.d/replication.cnf ``` ```ini [mysqld] server-id = 1 bind-address = primary_ip log_bin = /var/log/mysql/mysql-bin.log binlog_expire_logs_seconds = 604800 gtid_mode = ON enforce_gtid_consistency = ON ``` `bind-address` hace que MySQL escuche en la IP que usará la réplica (por defecto Ubuntu solo escucha en `127.0.0.1`). `binlog_expire_logs_seconds` conserva los registros binarios 7 días: si la réplica pasa más tiempo desconectada tendrás que volver a inicializarla. Reinicia MySQL y comprueba que GTID está activo: ```bash sudo systemctl restart mysql sudo mysql -e "SELECT @@server_id, @@gtid_mode, @@log_bin;" ``` ```output +-------------+-------------+-----------+ | @@server_id | @@gtid_mode | @@log_bin | +-------------+-------------+-----------+ | 1 | ON | 1 | +-------------+-------------+-----------+ ``` Permite el acceso al puerto 3306 solo desde la réplica: ```bash sudo ufw allow from replica_ip to any port 3306 proto tcp ``` ## Paso 2: Crear el usuario de replicación Crea un usuario que solo pueda conectarse desde la IP de la réplica, que exija TLS y que tenga únicamente el privilegio de replicación. Sustituye `your_strong_password` por una contraseña larga y aleatoria: ```bash sudo mysql ``` ```sql CREATE USER 'repl'@'replica_ip' IDENTIFIED BY 'your_strong_password' REQUIRE SSL; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'replica_ip'; EXIT; ``` MySQL 8.0 genera certificados TLS propios al instalarse, así que la conexión irá cifrada sin configuración adicional. Esos certificados son autofirmados: cifran el tráfico pero no autentican al servidor, otra razón para limitar el acceso por IP o usar un túnel privado. ## Paso 3: Configurar el servidor réplica En la **réplica**, crea el mismo archivo con un `server-id` distinto: ```bash sudo nano /etc/mysql/mysql.conf.d/replication.cnf ``` ```ini [mysqld] server-id = 2 log_bin = /var/log/mysql/mysql-bin.log binlog_expire_logs_seconds = 604800 gtid_mode = ON enforce_gtid_consistency = ON relay_log = /var/log/mysql/mysql-relay-bin ``` La réplica también mantiene su registro binario: cuando la promuevas a principal, podrás colgar de ella una nueva réplica sin más cambios. Reinicia MySQL: ```bash sudo systemctl restart mysql ``` ## Paso 4: Cargar los datos iniciales en la réplica La réplica necesita partir de una copia exacta de los datos, junto con el conjunto de GTID que ya contiene, para empezar a replicar justo desde ese punto. En el **principal**, genera un volcado coherente. `--set-gtid-purged=ON` añade al volcado la lista de transacciones ya incluidas: ```bash sudo mysqldump --single-transaction --routines --triggers --events \ --set-gtid-purged=ON --databases your_database > ~/initial.sql ``` mysqldump mostrará un aviso sobre volcados parciales con GTID. Es esperado: indica que el volcado marca como aplicadas todas las transacciones del servidor, no solo las de `your_database`, que es justo lo que queremos al inicializar una réplica. Copia el volcado a la réplica: ```bash rsync -avz --progress ~/initial.sql your_user@replica_ip:~/ ``` En la **réplica**, vacía el historial de GTID (solo es necesario en una réplica nueva, nunca en un servidor con datos propios) e importa el volcado: ```bash sudo mysql -e "RESET MASTER;" sudo mysql < ~/initial.sql ``` Comprueba que la réplica conoce ahora los GTID del principal: ```bash sudo mysql -e "SELECT @@GLOBAL.gtid_purged\G" ``` ```output *************************** 1. row *************************** @@GLOBAL.gtid_purged: 5c8f2e1a-7b3d-11ef-9a41-525400a1b2c3:1-1843 ``` ## Paso 5: Iniciar la replicación En la **réplica**, indica de dónde replicar. `SOURCE_AUTO_POSITION = 1` usa los GTID para calcular desde dónde continuar y `SOURCE_SSL = 1` obliga a cifrar la conexión: ```bash sudo mysql ``` ```sql CHANGE REPLICATION SOURCE TO SOURCE_HOST = 'primary_ip', SOURCE_USER = 'repl', SOURCE_PASSWORD = 'your_strong_password', SOURCE_AUTO_POSITION = 1, SOURCE_SSL = 1; START REPLICA; SET PERSIST read_only = ON; SET PERSIST super_read_only = ON; EXIT; ``` `super_read_only` impide que nadie, ni siquiera root, escriba por error en la réplica. Los hilos de replicación sí pueden escribir. `SET PERSIST` guarda estos valores para que sobrevivan a un reinicio. Comprueba el estado de la replicación: ```bash sudo mysql -e "SHOW REPLICA STATUS\G" | grep -E "Replica_IO_Running|Replica_SQL_Running:|Seconds_Behind_Source|Last_.*Error:" ``` ```output Replica_IO_Running: Yes Replica_SQL_Running: Yes Seconds_Behind_Source: 0 Last_IO_Error: Last_SQL_Error: ``` Los dos hilos deben estar en `Yes`. Para confirmarlo con datos reales, crea una tabla de prueba en el **principal**: ```bash sudo mysql -e "CREATE TABLE your_database.repl_test (id INT PRIMARY KEY); INSERT INTO your_database.repl_test VALUES (1);" ``` Y consúltala en la **réplica**: ```bash sudo mysql -e "SELECT * FROM your_database.repl_test;" ``` ```output +----+ | id | +----+ | 1 | +----+ ``` Borra la tabla en el principal con `DROP TABLE your_database.repl_test;`; el borrado también se replicará. ## Paso 6: Sincronizar los archivos de la aplicación La base de datos no lo es todo: archivos subidos por usuarios, configuración y certificados también deben estar en el segundo centro de datos. rsync solo transfiere los cambios, así que puede ejecutarse cada pocos minutos. En la **réplica**, da a tu usuario permiso de escritura sobre el directorio de destino: ```bash sudo install -d -o your_user -g www-data -m 755 /var/www ``` En el **principal**, genera una clave SSH para root sin frase de paso y muestra la parte pública: ```bash sudo ssh-keygen -t ed25519 -f /root/.ssh/app-sync -N "" -C "app-sync" sudo cat /root/.ssh/app-sync.pub ``` Añade esa línea al archivo `~/.ssh/authorized_keys` de `your_user` en la réplica. Después, desde el principal, conéctate una vez como root para aceptar la huella del servidor: ```bash sudo ssh -i /root/.ssh/app-sync your_user@replica_ip true ``` En la réplica los archivos quedarán a nombre de `your_user`, legibles por el servidor web. Si tu aplicación necesita otro propietario, ajústalo con `chown` al promover la réplica. Ahora crea un servicio de systemd en el principal: ```bash sudo nano /etc/systemd/system/app-sync.service ``` ```ini [Unit] Description=Sincronizar archivos de la aplicación con la réplica Wants=network-online.target After=network-online.target [Service] Type=oneshot ExecStart=/usr/bin/rsync -az --delete --bwlimit=20000 -e "ssh -i /root/.ssh/app-sync" /var/www/ your_user@replica_ip:/var/www/ ``` `--bwlimit=20000` limita la transferencia a unos 20 MB/s para no saturar el enlace entre centros de datos. `--delete` borra en la réplica lo que se borre en el principal: revisa bien las rutas antes de activarlo, porque un error en el origen se propaga al destino. Por eso la replicación no sustituye a las copias de seguridad. Crea un temporizador que lo ejecute cada 5 minutos: ```bash sudo nano /etc/systemd/system/app-sync.timer ``` ```ini [Unit] Description=Sincronización periódica de archivos con la réplica [Timer] OnBootSec=2min OnUnitActiveSec=5min [Install] WantedBy=timers.target ``` systemd no lanza una nueva ejecución de un servicio `oneshot` mientras la anterior sigue activa, así que no hace falta un bloqueo adicional. Actívalo y comprueba el resultado: ```bash sudo systemctl daemon-reload sudo systemctl enable --now app-sync.timer sudo journalctl -u app-sync.service -n 5 ``` ## Paso 7: Vigilar el retraso de la réplica Una réplica que se ha parado sin que nadie lo sepa no protege de nada. Los dos indicadores a vigilar son que ambos hilos estén en `Yes` y que `Seconds_Behind_Source` sea bajo. Crea en la réplica un usuario de solo lectura para tu sistema de monitorización: ```sql CREATE USER 'monitor'@'localhost' IDENTIFIED BY 'your_monitor_password'; GRANT REPLICATION CLIENT ON *.* TO 'monitor'@'localhost'; ``` Como `super_read_only` está activo en la réplica, crea este usuario en el **principal**: se replicará solo. Con él, herramientas como el exportador `mysqld_exporter` de Prometheus o el agente de Zabbix pueden leer `SHOW REPLICA STATUS` y alertar, por ejemplo, si el retraso supera 60 segundos durante más de 5 minutos o si algún hilo deja de estar en `Yes`. ## Paso 8: Promover la réplica si cae el principal Cuando el principal no está disponible y has decidido conmutar, el procedimiento es corto. Antes de nada, asegúrate de que el principal antiguo no puede volver a recibir escrituras (apágalo o bloquea el puerto 3306): dos servidores aceptando escrituras a la vez generan datos divergentes muy difíciles de reconciliar. En la **réplica**, comprueba hasta dónde llegó la replicación, detenla y elimina su configuración: ```bash sudo mysql ``` ```sql SHOW REPLICA STATUS\G STOP REPLICA; RESET REPLICA ALL; SET PERSIST super_read_only = OFF; SET PERSIST read_only = OFF; EXIT; ``` Después: 1. Cambia `bind-address` en `/etc/mysql/mysql.conf.d/replication.cnf` a la IP por la que se conectará la aplicación y reinicia MySQL. 2. Crea el usuario de la aplicación para la nueva IP de origen si es distinta y abre el puerto 3306 en UFW para los servidores de aplicación. 3. Apunta la aplicación al nuevo servidor, cambiando la cadena de conexión o el registro DNS que usa. 4. Detén el temporizador `app-sync.timer` en el antiguo principal cuando vuelva, para que no sobrescriba archivos nuevos. Cuando el antiguo principal se recupere, no lo reincorpores tal cual: puede tener transacciones que nunca llegaron a la réplica. Lo seguro es reinstalarlo como nueva réplica del servidor promovido, repitiendo los pasos 3 a 5 en sentido inverso. ## Solución de problemas - **`Authentication plugin 'caching_sha2_password' reported error: Authentication requires secure connection`**: la réplica se conecta sin TLS. Asegúrate de haber usado `SOURCE_SSL = 1` en `CHANGE REPLICATION SOURCE TO`. - **`Replica_IO_Running: Connecting`**: la réplica no llega al principal. Comprueba `bind-address`, la regla de UFW y que puedes conectar con `nc -zv primary_ip 3306` desde la réplica. - **Error 1236, `Cannot replicate because the source purged required binary logs`**: la réplica estuvo desconectada más tiempo del que se conservan los registros binarios. Vuelve a inicializarla desde el paso 4. - **`Seconds_Behind_Source` crece sin parar**: la réplica no da abasto aplicando cambios. Revisa el disco y la CPU de la réplica y busca consultas masivas en el principal (por ejemplo `UPDATE` sin `WHERE` sobre tablas grandes). ## Conclusión Tienes una réplica de MySQL cifrada en otro centro de datos, los archivos de la aplicación sincronizados cada 5 minutos y un procedimiento claro para promover la réplica. Esta configuración reduce el RPO a segundos, pero no protege frente a errores lógicos como un borrado accidental, que se replica al instante: mantén también copias de seguridad con retención. Como siguientes pasos, ensaya la promoción en un entorno de pruebas, automatiza el cambio de tráfico con conmutación por error de DNS y documenta el procedimiento en tu plan de recuperación ante desastres.