--- title: "Cómo hacer backups en Amazon S3 con aws s3 sync en Ubuntu" description: "Configura backups diarios de tu servidor Ubuntu 24.04 en Amazon S3 con aws s3 sync, un usuario IAM de mínimo privilegio, versionado, retención y timer systemd." category: "Integración Cloud" language: es source: https://cubepath.com/es/docs/integración-cloud/sincronizacion-de-aws-s3-para-backup-y-almacenamiento updated: 2026-09-25 --- # Cómo hacer backups en Amazon S3 con aws s3 sync en Ubuntu Amazon S3 es un almacenamiento de objetos duradero y barato, adecuado para guardar copias de seguridad fuera del servidor. Con `aws s3 sync` solo se suben los archivos que han cambiado, y si activas el versionado del bucket S3 conserva también las versiones anteriores. En este tutorial prepararás un bucket privado con versionado y retención de 30 días, un usuario IAM que solo puede escribir en ese bucket y un script de backup en Ubuntu 24.04 que se ejecuta cada noche con un timer de systemd. ## Requisitos previos Para seguir esta guía necesitas: - Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath, con un usuario no root con privilegios `sudo`. - Una cuenta de AWS y, en tu equipo local o en AWS CloudShell, la AWS CLI v2 configurada con un usuario con permisos de administración de S3 e IAM. Esos permisos solo se usan en los pasos 1 y 2; el servidor nunca los tendrá. - Opcional: MySQL o MariaDB en el servidor si quieres incluir un volcado de bases de datos. En los ejemplos, sustituye `your_bucket` por un nombre de bucket único a nivel global (por ejemplo `backups-miempresa-web01`) y `eu-west-1` por la región que prefieras. ## Paso 1: Crear el bucket con versionado Ejecuta estos comandos en el equipo con credenciales de administrador, no en el servidor. Crea el bucket: ```bash aws s3 mb s3://your_bucket --region eu-west-1 ``` ```output make_bucket: your_bucket ``` Los buckets nuevos tienen bloqueado el acceso público y cifrado en reposo con SSE-S3 por defecto. Activa el versionado para que cada sobrescritura o borrado deje una copia de la versión anterior: ```bash aws s3api put-bucket-versioning --bucket your_bucket --versioning-configuration Status=Enabled ``` Comprueba las tres propiedades: ```bash aws s3api get-bucket-versioning --bucket your_bucket aws s3api get-public-access-block --bucket your_bucket aws s3api get-bucket-encryption --bucket your_bucket ``` La primera debe devolver `"Status": "Enabled"`, la segunda `BlockPublicAcls`, `IgnorePublicAcls`, `BlockPublicPolicy` y `RestrictPublicBuckets` a `true`, y la tercera `"SSEAlgorithm": "AES256"`. ## Paso 2: Definir la retención con una regla de ciclo de vida Con el versionado activo, las versiones antiguas se acumulan para siempre. Una regla de ciclo de vida las elimina a los 30 días, limpia las marcas de borrado huérfanas y aborta subidas multiparte incompletas. Crea el archivo `lifecycle.json`: ```bash nano lifecycle.json ``` ```json { "Rules": [ { "ID": "retencion-30-dias", "Status": "Enabled", "Filter": {}, "NoncurrentVersionExpiration": { "NoncurrentDays": 30 }, "Expiration": { "ExpiredObjectDeleteMarker": true }, "AbortIncompleteMultipartUpload": { "DaysAfterInitiation": 7 } } ] } ``` Aplica la regla y compruébala: ```bash aws s3api put-bucket-lifecycle-configuration --bucket your_bucket --lifecycle-configuration file://lifecycle.json aws s3api get-bucket-lifecycle-configuration --bucket your_bucket ``` La salida debe mostrar la regla `retencion-30-dias` con `"Status": "Enabled"`. Ajusta `NoncurrentDays` a la retención que necesites. ## Paso 3: Crear un usuario IAM de mínimo privilegio El servidor necesita credenciales propias que solo sirvan para este bucket. Crea el documento de política `backup-policy.json`, sustituyendo `your_bucket`: ```bash nano backup-policy.json ``` ```json { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": ["s3:ListBucket", "s3:GetBucketLocation"], "Resource": "arn:aws:s3:::your_bucket" }, { "Effect": "Allow", "Action": ["s3:PutObject", "s3:GetObject", "s3:DeleteObject"], "Resource": "arn:aws:s3:::your_bucket/*" } ] } ``` La política no incluye `s3:DeleteObjectVersion` ni permisos sobre el versionado o el ciclo de vida. Si alguien roba estas claves y borra los objetos, S3 solo crea marcas de borrado y las versiones anteriores siguen disponibles durante el periodo de retención. Crea el usuario, adjúntale la política como política en línea y genera sus claves de acceso: ```bash aws iam create-user --user-name backup-web01 aws iam put-user-policy --user-name backup-web01 --policy-name s3-backup --policy-document file://backup-policy.json aws iam create-access-key --user-name backup-web01 ``` ```output { "AccessKey": { "UserName": "backup-web01", "AccessKeyId": "AKIA...", "Status": "Active", "SecretAccessKey": "wJalr...", ... } } ``` Copia `AccessKeyId` y `SecretAccessKey`: la clave secreta no se vuelve a mostrar. ## Paso 4: Instalar la AWS CLI v2 en el servidor A partir de aquí todo se hace en el servidor. Ubuntu 24.04 no incluye la AWS CLI v2 en sus repositorios, así que usa el instalador oficial de AWS: ```bash sudo apt update sudo apt install unzip curl curl -fsSL "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o awscliv2.zip unzip -q awscliv2.zip sudo ./aws/install ``` En un servidor ARM (aarch64) descarga `awscli-exe-linux-aarch64.zip` en su lugar. Comprueba la versión: ```bash aws --version ``` ```output aws-cli/2.x.x Python/3.x.x Linux/6.8.0-xx-generic exe/x86_64.ubuntu.24 ``` El backup se ejecutará como root, así que guarda las credenciales en el perfil `backup` de root: ```bash sudo -H aws configure --profile backup ``` Introduce las claves del paso 3, la región del bucket y `json` como formato de salida. Las credenciales quedan en `/root/.aws/credentials`, legible solo por root. Comprueba que funcionan: ```bash sudo -H aws s3 ls s3://your_bucket --profile backup ``` Un bucket vacío no devuelve nada y el comando termina sin error. Si ves `AccessDenied`, revisa el nombre del bucket en la política. ## Paso 5: Escribir el script de backup El script sincroniza `/var/www` y `/etc`, y sube un volcado comprimido de todas las bases de datos si MySQL o MariaDB están instalados. Como el volcado siempre tiene el mismo nombre, el versionado del bucket guarda automáticamente los de los últimos 30 días. ```bash sudo nano /usr/local/bin/backup-s3.sh ``` ```bash #!/usr/bin/env bash set -euo pipefail BUCKET="your_bucket" export AWS_PROFILE="backup" DUMP_DIR="/var/backups/mysql" echo "Inicio del backup: $(date --iso-8601=seconds)" # Volcado de bases de datos (solo si hay MySQL/MariaDB) if command -v mysqldump > /dev/null; then install -d -m 700 "$DUMP_DIR" mysqldump --all-databases --single-transaction --routines --events \ | gzip > "$DUMP_DIR/all-databases.sql.gz" aws s3 cp "$DUMP_DIR/all-databases.sql.gz" "s3://$BUCKET/mysql/all-databases.sql.gz" --only-show-errors fi # Archivos web aws s3 sync /var/www/ "s3://$BUCKET/www/" --delete --only-show-errors \ --exclude "*.log" --exclude "*/cache/*" # Configuración del sistema aws s3 sync /etc/ "s3://$BUCKET/etc/" --delete --only-show-errors echo "Backup completado: $(date --iso-8601=seconds)" ``` `--delete` mantiene el destino idéntico al origen; gracias al versionado, un archivo borrado por error en el servidor sigue recuperable durante 30 días. El volcado usa la autenticación por socket de root que Ubuntu configura por defecto en MySQL y MariaDB, así que no hace falta poner contraseñas en el script. > Nota: `/etc` contiene archivos sensibles como `/etc/shadow` o claves privadas. El bucket es privado y está cifrado, pero trata estas copias con el mismo cuidado que el propio servidor. Hazlo ejecutable y lánzalo una vez a mano: ```bash sudo chmod 750 /usr/local/bin/backup-s3.sh sudo -H /usr/local/bin/backup-s3.sh ``` ```output Inicio del backup: 2026-09-25T10:14:02+00:00 Backup completado: 2026-09-25T10:15:37+00:00 ``` Comprueba lo que se ha subido: ```bash sudo -H aws s3 ls s3://your_bucket/ --recursive --summarize --profile backup | tail -n 2 ``` ```output Total Objects: 1843 Total Size: 412337914 ``` La segunda ejecución será mucho más rápida porque `sync` solo sube los archivos nuevos o modificados. ## Paso 6: Programar el backup con un timer de systemd Un timer de systemd registra cada ejecución en el journal y recupera las ejecuciones perdidas si el servidor estaba apagado. Crea el servicio: ```bash sudo nano /etc/systemd/system/backup-s3.service ``` ```ini [Unit] Description=Backup del servidor a Amazon S3 Wants=network-online.target After=network-online.target [Service] Type=oneshot Environment=HOME=/root ExecStart=/usr/local/bin/backup-s3.sh ``` `HOME=/root` es necesario para que la AWS CLI encuentre `/root/.aws`. Crea el timer: ```bash sudo nano /etc/systemd/system/backup-s3.timer ``` ```ini [Unit] Description=Backup diario a Amazon S3 [Timer] OnCalendar=*-*-* 03:00:00 RandomizedDelaySec=15min Persistent=true [Install] WantedBy=timers.target ``` Recarga systemd, activa el timer y lanza el servicio una vez para validarlo: ```bash sudo systemctl daemon-reload sudo systemctl enable --now backup-s3.timer sudo systemctl start backup-s3.service systemctl list-timers backup-s3.timer ``` ```output NEXT LEFT LAST PASSED UNIT ACTIVATES Sat 2026-09-26 03:07:41 UTC 16h left Fri 2026-09-25 10:20:05 UTC 1min ago backup-s3.timer backup-s3.service ``` Revisa el resultado de la ejecución: ```bash sudo journalctl -u backup-s3.service -n 20 --no-pager ``` Debes ver las líneas `Inicio del backup` y `Backup completado`, y `Finished backup-s3.service`. ## Paso 7: Restaurar desde S3 Un backup que no se ha probado a restaurar no es un backup. Descarga la copia de la web a un directorio temporal y compárala: ```bash sudo -H aws s3 sync s3://your_bucket/www/ /tmp/restore-www/ --profile backup sudo diff -rq /var/www/ /tmp/restore-www/ | head ``` Si solo aparecen los archivos excluidos (logs y caché), la copia es correcta. Para recuperar un volcado de un día anterior, lista sus versiones y descarga la que necesites por su `VersionId`: ```bash sudo -H aws s3api list-object-versions --bucket your_bucket --prefix mysql/all-databases.sql.gz \ --query 'Versions[].[VersionId,LastModified]' --output table --profile backup sudo -H aws s3api get-object --bucket your_bucket --key mysql/all-databases.sql.gz \ --version-id VERSION_ID /tmp/all-databases.sql.gz --profile backup ``` Restaura el volcado con `zcat /tmp/all-databases.sql.gz | sudo mysql`, idealmente primero en un servidor de pruebas. ## Solución de problemas **`An error occurred (AccessDenied)`**: comprueba qué identidad está usando la CLI con `sudo -H aws sts get-caller-identity --profile backup`. Debe aparecer `user/backup-web01`. Si es correcta, revisa que el ARN de la política coincide exactamente con el nombre del bucket. **El timer se ejecuta pero falla con `Unable to locate credentials`**: falta `Environment=HOME=/root` en el servicio, o las credenciales se guardaron en el `HOME` de tu usuario. Repite `sudo -H aws configure --profile backup`. **`mysqldump: Access denied for user 'root'@'localhost'`**: tu instalación usa contraseña para root. Crea `/root/.my.cnf` con una sección `[mysqldump]` que incluya `user` y `password`, con permisos `600`. **El bucket crece más de lo esperado**: consulta el tamaño con `aws s3 ls --recursive --summarize` y revisa que la regla de ciclo de vida está activa. Las versiones antiguas se borran de forma asíncrona, uno o dos días después de cumplir los 30 días. ## Conclusión Tu servidor sube cada noche sus archivos web, su configuración y sus bases de datos a un bucket S3 privado, con versiones de los últimos 30 días y credenciales que no pueden destruir ese historial. Como siguientes pasos puedes cifrar los volcados en el cliente con `gpg` antes de subirlos, mover las versiones antiguas a S3 Glacier Instant Retrieval con otra regla de ciclo de vida para abaratar costes, o activar S3 Object Lock en un bucket nuevo si necesitas copias inmutables.