# Copias de seguridad, restauración y actualización

Este tutorial realiza una copia de seguridad de la configuración del puesto, las credenciales de acceso, las concesiones de dispositivos, los puntos de control de monitoreo y las notificaciones en cola. Los mensajes de correo electrónico originales permanecen con su proveedor de correo electrónico; esta copia de seguridad restaura la instancia Mailwake.

## 1. Qué conservar

Una copia de seguridad recuperable contiene:

- El directorio `/data` completo: `mailwake.db`, `secret.key` y archivos SQLite relacionados. Mantenga la base de datos y la clave juntas.
- Redactar configuración: puertos, volúmenes y configuración del entorno.
- La imagen en ejecución: restaure la misma versión del programa que la base de datos.

El siguiente script se dirige a la instalación estándar de Compose. Guarda la configuración y la imagen, detiene brevemente el puesto, copia todos los datos y luego reinicia el puesto. El monitoreo se detiene durante ese intervalo. Después del reinicio, el puesto se reanuda desde los puntos de control guardados y recupera los mensajes que aún están en la carpeta y que se recibieron en las últimas 24 horas.

Si su instalación utiliza una configuración de proxy inverso u otros archivos montados en el host, copie esos archivos también en la copia de seguridad. Ajuste sus rutas al restaurar en otra máquina.

## 2. Crea tu primera copia de seguridad

Descargue [script de respaldo](/downloads/backup.sh), guárdelo como `backup.sh` y colóquelo en el directorio de instalación de su servidor, por ejemplo `~/mailwake/backup.sh`.

Ver el script de respaldo

```sh
#!/bin/sh
# Copyright (C) 2026 Mailwake contributors
# SPDX-License-Identifier: AGPL-3.0-only
# License: https://www.gnu.org/licenses/agpl-3.0.html
# Back up a running Compose installation; execute as a user with Docker access.
set -eu

if [ "$#" -ne 2 ]; then
  echo "Usage: backup.sh /absolute/compose-directory /absolute/backup-directory" >&2
  exit 2
fi
case "$1:$2" in
  /*:/*) ;;
  *) echo "Use absolute directory paths." >&2; exit 2 ;;
esac
cd "$1"
umask 077
lock=".mailwake-backup.lock"
if ! mkdir "$lock" 2>/dev/null; then
  echo "Could not create $PWD/$lock. Check directory permissions and active backups." >&2
  exit 1
fi
restart=0
cleanup() {
  result=$?
  trap - EXIT
  if [ "$restart" -eq 1 ]; then
    docker compose start core >&2 || result=1
  fi
  rmdir "$lock" || result=1
  exit "$result"
}
trap cleanup EXIT
trap 'exit 130' INT
trap 'exit 143' TERM
container=$(docker compose ps -q core)
if [ -z "$container" ]; then
  echo "Start the Core service before running this backup." >&2
  exit 1
fi
mkdir -p "$2"
backup="$2/mailwake-$(date +%Y%m%d-%H%M%S)"
test ! -e "$backup"
staging="$backup.incomplete"
mkdir "$staging"
mkdir "$staging/data"
docker compose config > "$staging/compose.yaml"
docker inspect --format '{{.Image}}' "$container" > "$staging/image-id.txt"
docker image save --output "$staging/image.tar" "$(cat "$staging/image-id.txt")"
restart=1
docker compose stop core >&2
docker compose cp core:/data/. "$staging/data/" >&2
docker compose start core >&2
restart=0
mv "$staging" "$backup"
printf 'Backup saved: %s\n' "$backup"

```

Ejecute en la terminal de su servidor:

```
sh "$HOME/mailwake/backup.sh" "$HOME/mailwake" "$HOME/mailwake-backups"
```

**Verifique el resultado**: la terminal imprime `Backup saved:` con la nueva ruta del directorio y `docker compose ps` muestra el puesto ejecutándose nuevamente. Si la copia falla, el script intenta reiniciar el puesto y devuelve un error. Los directorios que terminan en `.incomplete` son copias de seguridad sin terminar; guárdelos para solucionar problemas.

El directorio de bloqueo evita la superposición de copias de seguridad manuales y programadas. Si el host falla o el proceso se cierra a la fuerza, primero confirme que no se esté ejecutando ninguna copia de seguridad, luego elimine `.mailwake-backup.lock` del directorio de instalación y vuelva a ejecutar el script.

Cada copia de seguridad tiene este diseño:

```
mailwake-20261008-030000/
  compose.yaml
  image-id.txt
  image.tar
  data/
    mailwake.db
    secret.key
    ...
```

Guardar la imagen requiere espacio adicional en el disco y ocurre antes de que se detenga el puesto. El directorio utiliza permisos privados y contiene tanto las credenciales cifradas como su clave. Confirme que existen `data/mailwake.db`, `data/secret.key` y `image.tar`, luego realice el ejercicio de restauración a continuación al menos una vez.

## 3. Restaurar en un nuevo volumen

Detenga la instancia original y mantenga su volumen original. Ambas instancias comparten identidades de buzón y dispositivo, por lo que se debe ejecutar solo una a la vez.

```
cd ~/mailwake
docker compose stop core
```

Configure `backup` en su ruta de respaldo real. Prepare un nuevo directorio de instalación, su imagen y configuración:

```
backup="$HOME/mailwake-backups/mailwake-20261008-030000"
mkdir -p ~/mailwake-restored
cd ~/mailwake-restored
cp "$backup/compose.yaml" ./compose.yaml
docker load --input "$backup/image.tar"
restore_volume="mailwake-restored-$(date +%Y%m%d-%H%M%S)"
cat > compose.override.yaml <<EOF
name: mailwake-restored
services:
  core:
    image: $(cat "$backup/image-id.txt")
volumes:
  core-data:
    name: $restore_volume
networks:
  default:
    name: $restore_volume-network
EOF
```

Redactar carga automáticamente `compose.override.yaml`. Selecciona un volumen de datos nuevo y la imagen respaldada exacta. Cree el contenedor, copie los datos, establezca la propiedad para el usuario del contenedor y comience:

```
(
  set -eu
  docker compose create --pull never core
  docker compose run --rm --no-deps -T --user 0:0 --entrypoint sh core \
    -c 'entries=$(ls -A /data) && test -z "$entries"'
  docker compose cp "$backup/data/." core:/data/
  docker compose run --rm --no-deps -T --user 0:0 --cap-add CHOWN --entrypoint chown core \
    -R 10001:10001 /data
  docker compose up -d --pull never
  docker compose logs --tail=50 core
)
```

Continúe solo después de que cada comando tenga éxito. Si la verificación del volumen vacío falla, elija un `restore_volume` nuevo, reescriba la anulación y vuelva a crear el contenedor. Un destino poblado podría mezclar archivos antiguos con datos restaurados; este procedimiento utiliza un volumen vacío.

**Comprueba el resultado**: inicia sesión con tu contraseña de administrador original. Los buzones de correo y las selecciones de carpetas permanecen presentes, la supervisión se reanuda y las concesiones de dispositivos provienen de la copia de seguridad. Si ve una nueva pantalla de configuración, detenga la instancia restaurada y verifique la ruta de copia y el montaje del volumen. Para errores de descifrado, confirme que la base de datos y `secret.key` provienen de la misma copia de seguridad.

## 4. Verificar la instancia restaurada

1. Verifique el recuento de buzones de correo, las carpetas seleccionadas y verifique los métodos con la instalación original.
2. Envía una notificación de prueba de canal y confirma que llega a tu teléfono.
3. Envíe un nuevo correo electrónico desde otro buzón a una carpeta supervisada y verifique su registro de entrega.
4. Reinicie la instancia restaurada, inicie sesión nuevamente y confirme que su configuración y monitoreo persisten.

Una vez verificado, apunte el proxy inverso a la instancia restaurada y adminístrela desde `~/mailwake-restored`. Actualice el trabajo de copia de seguridad para usar ese directorio. Deje la instancia original detenida y conserve su volumen y la copia de seguridad hasta que se confirme la recuperación.

Las notificaciones pendientes o fallidas vuelven a su estado de copia de seguridad y pueden entregarse nuevamente. Utilice el mismo procedimiento para revertir una actualización, restaurando los datos y la imagen antiguos juntos.

## 5. Programe copias de seguridad y guarde una copia externa

En un servidor Linux, primero complete una copia de seguridad manual y luego use `crontab -e` para agregar lo siguiente. Reemplace `/home/you` con sus rutas absolutas:

```
PATH=/usr/local/bin:/usr/bin:/bin
0 3 * * * /bin/sh /home/you/mailwake/backup.sh /home/you/mailwake /home/you/mailwake-backups >> /home/you/mailwake-backup.log 2>&1
```

Esto se ejecuta diariamente a las 03:00 en la zona horaria local del servidor. El usuario programado necesita acceso a Docker. En un NAS, utilice el mismo comando de Shell en su programador de tareas. Al día siguiente, busque un nuevo directorio y `Backup saved:` en el registro. Abordar las fallas; un programador no puede establecer que una copia de seguridad sea recuperable.

Una copia de seguridad en el mismo disco no cubre fallas del disco o de la máquina. Copie los directorios completos a otra máquina o a un almacenamiento de copia de seguridad protegido, por ejemplo a través de SSH:

```
scp -r "$HOME/mailwake-backups/mailwake-20261008-030000" \
  backup-user@backup-host:/srv/mailwake-backups/
```

Reemplace el origen, el usuario remoto, el host y el destino. Restrinja el acceso en el destino a los mantenedores de respaldo. Utilice almacenamiento cifrado o cifre el archivo antes de cargarlo cuando sea necesario el cifrado en reposo. Una posible política de retención es siete copias diarias y cuatro semanales. Antes de eliminar copias de seguridad anteriores, verifique la copia externa y un ejercicio de restauración reciente.

## Hacer una copia de seguridad de una instalación de Docker Run

La instalación de Docker Run utiliza un contenedor denominado `mailwake` y el volumen `mailwake-data`. Estos comandos se ejecutan en un subshell e intentan reiniciar el contenedor original si falla la copia:

```
(
  set -eu
  umask 077
  backup="$HOME/mailwake-backups/mailwake-$(date +%Y%m%d-%H%M%S)"
  mkdir -p "$backup/data"
  docker inspect --format '{{.Image}}' mailwake > "$backup/image-id.txt"
  docker image save --output "$backup/image.tar" "$(cat "$backup/image-id.txt")"
  trap 'docker start mailwake >/dev/null' EXIT
  docker stop mailwake
  docker cp mailwake:/data/. "$backup/data/"
  docker start mailwake
  trap - EXIT
  printf 'Backup saved: %s\n' "$backup"
)
```

Guarde su comando Docker Run junto con los datos. Para restaurar, detenga el contenedor original, cargue `image.tar`, cree un nuevo volumen y contenedor y copie los datos antes de comenzar:

```
(
  set -eu
  backup="$HOME/mailwake-backups/mailwake-20261008-030000"
  image=$(cat "$backup/image-id.txt")
  restore_volume="mailwake-restored-$(date +%Y%m%d-%H%M%S)"
  docker stop mailwake
  docker load --input "$backup/image.tar"
  docker volume create "$restore_volume"
  docker create --name mailwake-restored --restart unless-stopped \
    --stop-timeout 30 --read-only --security-opt no-new-privileges:true --cap-drop ALL \
    -p 127.0.0.1:8080:8080 -v "$restore_volume:/data" "$image"
  docker run --rm --user 0:0 --entrypoint sh -v "$restore_volume:/data" "$image" \
    -c 'entries=$(ls -A /data) && test -z "$entries"'
  docker cp "$backup/data/." mailwake-restored:/data/
  docker run --rm --user 0:0 --entrypoint chown -v "$restore_volume:/data" "$image" \
    -R 10001:10001 /data
  docker start mailwake-restored
)
```

Continúe solo después de que cada comando tenga éxito y siga la lista de verificación anterior. Mantenga el contenedor y el volumen originales y deje el contenedor original detenido mientras se ejecuta la instancia restaurada.
