ksergio.com

github-logo

  • Shell
  • MySQL
Publicado hace 2 semanas

Copias de seguridad de tu servidor

Copias de seguridad de tu servidor
  1. Como hago una copia de seguridad
  2. Script de bash
  3. Automatizacion con cron
    1. Como se hace
    2. Una consideracion importante
  4. Conceptos
    1. bash
    2. ssh y scp
    3. mysqldump
    4. cron
    5. Consideraciones de seguridad
  5. Variaciones
    1. Guardar estado de la base de datos
    2. Borrar copias antiguas automaticamente

¿Como hago una copia de seguridad?

El tutorial está escrito para Linux pero es fácilmente adaptable para Windows simplemente cambiando el script de bash por un script de comandos de windows .bat, y en ve de usar cron sustituyelo por el programador de tareas o Task Scheduler.

Ok, si necesitas la respuesta rápida simplemente sigue estos pasos a continuación. Más adelante explico paso a paso que es cada comando y como funciona para poder adaptarlo a tu gusto.

Este script sincroniza la base de datos del servidor con tu base de datos en tu máquina local, pero puedes generar archivos de backup y guardarlos por separado. Más adelante explico esto en detalle.

Script de bash

Primero tenemos que crear nuestro script de bash. Puede usar cualquier editor para simplemente pegar el siguiente contenido:

#!/bin/bash

# --- Cargar credenciales básicas ---

DIR_SCRIPT="$(cd "$(dirname "$0")" && pwd)"

# IP servidor
HOST="1.1.1.1"

# Credenciales para SSH y SCP
SSH_USER="usuario_ssh"
SSH_PASSWORD="tu_password_ssh"

# Que directorio quieres copiar
DIR_DESTINO="$DIR_SCRIPT/ruta_directorio_local"
DIR_ORIGEN="/ruta_absoluta_en_el_servidor"

# Credenciales MySQL o MariaDB
MYSQL_REMOTE_USER="usuario_conexion_mysql_servidor"
MYSQL_REMOTE_PASSWORD="password_mysql_servidor"
MYSQL_LOCAL_USER="usuario_conexion_mysql_local"
MYSQL_LOCAL_PASSWORD="password_mysql_local"

# Nombre de la base de datos a copiar
DB_ORIGEN="base_de_datos_servidor"
DB_DESTINO="base_de_datos_local"

# --- Sincronizar ficheros ---

if [ ! -d "$DIR_DESTINO" ]
then
    echo "El directorio de destino no existe"
    exit 1
fi

if ! ssh "$SSH_USER@$HOST" "[ -d '$DIR_ORIGEN' ]"
then
    echo "El directorio de origen remoto no existe"
    exit 1
fi

# Descomentar si deseamos borrar el contenido previo
# rm -rf "${DIR_DESTINO:?}/"*

echo "Copiando ficheros del servidor..."
sshpass -p "$SSH_PASSWORD" scp -r "$SSH_USER@$HOST:$DIR_ORIGEN/"* "$DIR_DESTINO/"
echo "Ficheros copiados con éxito"

# --- Sincronizar base de datos ---
DUMP_FILE="$DIR_SCRIPT/temp_dump.sql"


export MYSQL_PWD="$MYSQL_REMOTE_PASSWORD"
echo "Creando fichero de respaldo de la base de datos..."
mysqldump -h "$HOST" -u "$MYSQL_REMOTE_USER" "$DB_ORIGEN" > "$DUMP_FILE"
echo "Creado fichero de respaldo con éxito"
unset MYSQL_PWD


export MYSQL_PWD="$MYSQL_LOCAL_PASSWORD"
echo "Sincronizando la base de datos local..."
mysql -h 127.0.0.1 -P 3306 -u "$MYSQL_LOCAL_USER" "$DB_DESTINO" < "$DUMP_FILE"
echo "Sincronizado con éxito"
unset MYSQL_PWD

rm -f "$DUMP_FILE"

echo "¡Archivos y base de datos sincronizados con éxito!"

Modifica las variables de las credenciales, direcciones de carpetas que quieras pegar y la dirección IP de tu servidor.

Cuando ejecutes el script si alguno de estos datos está mal puede que te aparezca un error descriptivo. Lo primero de todo, ¡Comprueba que todas estás variables estén correctas!

# IP servidor
HOST="1.1.1.1"

# Credenciales para SSH y SCP
SSH_USER="usuario_ssh"
SSH_PASSWORD="tu_password_ssh"

# Que directorio quieres copiar
DIR_DESTINO="$DIR_SCRIPT/ruta_directorio_local"
DIR_ORIGEN="/ruta_absoluta_en_el_servidor"

# Credenciales MySQL o MariaDB
MYSQL_REMOTE_USER="usuario_conexion_mysql_servidor"
MYSQL_REMOTE_PASSWORD="password_mysql_servidor"
MYSQL_LOCAL_USER="usuario_conexion_mysql_local"
MYSQL_LOCAL_PASSWORD="password_mysql_local"

# Nombre de la base de datos a copiar
DB_ORIGEN="base_de_datos_servidor"
DB_DESTINO="base_de_datos_local"

A continuación, por defecto, normalmente tendrás que darle permisos de ejecución a tu script recien creado de la siguiente forma. Si no haces este paso, simplemente no se va a ejecutar y no te dará la opción siquiera.

chmod +x nombre_script.sh

Una vez hechos todos estos pasos podrás ejecutarlo, tanto desde la interfaz gráfica como con la terminal situandote en el directorio donde está el script y haciendo:

./nombre_script.sh

Ya puedes hacer copias a mano simplemente ejecutando tu script. ¿Pero como hago que se ejecute de forma periódica?

Automatización con cron

¿Como se hace?

Simplemente con estos pasos debería funcionar sin más complicaciónes. Ahora además podemos hacer que este script se ejecute automáticamente cada X periodo de tiempo con cron.

Solo necesitamos poner lo siguiente en nuestra terminal.

crontab -e

Esto nos abrirá un editor de textos para editar el fichero de cron. Por defecto te lo abrirá con un editor de consola como vim o nano. Con esto tendrás que pelearte a parte, pero no debe suponer demasiado reto si lo único que necesitas es escribir una linea.

Agrega la siguiente linea al fichero que hará que el script se ejecute cada 12h. Una vez a las 00:00h y otra a las 12:00h.

0 */12 * * * /la_ruta_de_tu_directorio/tu_script.sh

Lo que hacemos aquí es especificar el formato de cada cuanto se tiene que ejecutar este fichero y donde se encuentra en tu máquina. ¡Debes poner la ruta absoluta del script!.

Si quieres personalizar el periodo puedes inspirarte en esta página donde salen ejemplos comunes y una herramienta interactiva para visualizar tu patrón: https://crontab.guru/examples.html

¡Una consideración importante!

Si te fijas siempre usamos rutas absolutas. Nunca he usado una ruta relativa en mi script. Esto es VITAL, ya que cuando cron ejecuta el script lo hará desde el directorio que sea... No debemos suponer que cron ejecuta el script desde el directorio donde está. Por eso es necesario siempre darle rutas absolutas.

Por eso en los scripts verás que a la hora de construir el path de los ficheros o directorios usados siempre hago algo como;

# Primera forma
DIR_SCRIPT="$(cd "$(dirname "$0")" && pwd)"

# Segunda forma
parentPath="$(dirname "$(realpath "$0")")"

Usarémos estas variables para construir las rutas hacia nuestros recursos.

Conceptos

Bash

Es el intérprete de comandos más común en sistemas Linux/Unix. Permite ejecutar comandos del sistema, automatizar tareas con scripts, trabajar con variables, condicionales, bucles, etc.

SSH y SCP

SSH (Secure Shell): Protocolo seguro para conectarse a servidores de forma remota usando cifrado. Sustituyó a Telnet.

SCP (Secure Copy): Permite transferir archivos de forma segura entre equipos usando SSH como transporte. Ejemplo:

mysqldump

Herramienta oficial de MySQL/MariaDB para generar respaldos de bases de datos en formato SQL. Suele instalarse si hemos instalado el cliente o servidor de MySQL en nuestra máquina

Los disintos flags usados sirven para pasarle el usuario y la contraseña. Con el flag -p se pedirá la contraseña de forma interactiva al ejecutarse.

En nuestro script hemos utilizado la variable de entorno MYSQL_PWD para no tener que pasarlo a mano al comando.

mysqldump -u usuario -p basedatos > respaldo.sql

El archivo respaldo.sql contiene instrucciones SQL (CREATE TABLE, INSERT, etc.) que permiten reconstruir la base de datos.

Para restaurar el contenido usamos el comando siguiente usand el alguno de estos ficheros de respaldo.

mysql -u usuario -p basedatos < respaldo.sql

Cron

Básicamente es un programa que corre en segundo plano en nuestro linux y ejecuta de forma periódica alguna tarea, script o programa.

El archivo crontab es el que le dice a cron que y cuando se ha de ejecutar.

Consideraciones de seguridad

Hemos visto anteriormente que podemos pasar la contraseña directamente a mysqldump con el flag -p, pero esto es una mala práctica ya que queda el registro del comando en la terminal. Otro usuario podría leer la contraseña pasada.

Por ello utilizamos la variable de entorno MYSQL_PWD y la seteamos a las credenciales. Si no se le pasa el flag -p el comando intentará usar la contraseña guardada en la variable MYSQL_PWD. Una vez usada la borramos con unset.

Otra opción es usar el flag --defaults-extra-file= segudo del path de un fichero de configuración. Le podemos dar el nombre que queramos y se vería de la siguiente forma;

[client]
	host=HOST
	port=PORT
	user=USER
	password=PASSWORD

Aqui guardamos las credenciales y podriamos invocar el volcado solo pasandole como primer parametro el nombre de la base de datos.

mysqldump --defaults-extra-file="./mysql.conf" "nombre_base_datos" > "respaldo.sql"

Por otro lado nuestro no podemos pasarle de la misma forma la contraseña a nuestro comando ssh. Este nos pedirá de forma interactiva la contraseña.

Una forma de automatizarlo es usando claves .ssh , que requiere de más configuraciones extras. Otra forma algo más rudimentaria sería la usada con sshpass - noninteractive ssh password provider.

De esta forma podemos pasarle de forma programatica la contraseña como se ve en esta linea, donde scp nos solicita la contraseña para hacer la copia de ficheros desde el servidor.

sshpass -p "$SSH_PASSWORD" scp -r "$SSH_USER@$HOST:$DIR_ORIGEN/"* "$DIR_DESTINO/"

Variaciones

Guardar estado de la base de datos

Nuestro script anterior sincroniza la base de datos local con la del servidor. Pero quizas queramos guardar varios archivos de respaldo para cada día por ejemplo. Bastaría con simplemente no borrar el fichero volcado con mysqldump.

Podemos generar un nombre para cada fecha en la que se ejecuta el script de la siguiente forma;

DB_NAME="mi_db"
parentPath="$(dirname "$(realpath "$0")")"
TIMESTAMP=$(date +"%Y%m%d%H%M%S")
FILENAME="backup_${TIMESTAMP}.sql"

y luego usar nuestro volcado usando el nombre generado;

mysqldump --defaults-extra-file="${parentPath}/mysql.conf" "$DB_NAME" > "${parentPath}/backups/${FILENAME}"

Quitamos la linea que borra el fichero de volcado y asi lo tenemos guardado.

# Comentamos la linea del 'rm'
# rm -f "${parentPath}/${FILENAME}"

Borrar copias antiguas automáticamente

Guardar estos ficheros de resplado no es gratis. Tienen un tamaño, que aunque no sea considerable, a la larga si guardamos muchos puede llenar nuestro disco. Para evitar esto podemos seguir una estrategia que haga lo siguiente.

Una vez ejecutado nuestra copia de seguridad, que busque en el directorio donde se guardan los ficheros de backups (aquellos acabados en backup_xxx.sql, por ejemplo) y borre los que tengan más de X días de antiguedad. Podemos lograrlo con algo como esto;

# Eliminar backups antiguos (más de 30 días)
find "${parentPath}/backups" -name "backup_*" -type f -mtime +30 -delete
echo "Archivos antiguos eliminados"