El Reglamento General de Protección de Datos (RGPD, o GDPR en inglés) obliga a quien trata datos personales a aplicar "medidas técnicas y organizativas apropiadas" para protegerlos (artículo 32). Como administrador del servidor, esa parte técnica te toca a ti: saber dónde están los datos, limitar quién accede, registrar los accesos, cifrar, borrar lo que ya no hace falta y poder restaurar tras un incidente. En esta guía aplicarás esas medidas en un servidor Ubuntu 24.04 con herramientas estándar y verificables.

Requisitos previos

  • Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath.
  • Un usuario no root con privilegios sudo y acceso SSH mediante clave pública.
  • Nginx instalado, si quieres seguir el paso 2 (con Apache el principio es el mismo).
  • Un destino externo para las copias de seguridad (otro servidor accesible por SFTP o un almacenamiento compatible con S3) para el paso 7.

Qué pide el RGPD a nivel técnico

El artículo 32 no enumera herramientas; pide un nivel de seguridad adecuado al riesgo e incluye expresamente estos objetivos. La tabla muestra cómo se traducen en un servidor y en qué paso de esta guía se aplican:

Objetivo del RGPDMedida en el servidorPaso
Minimización de datos (art. 5.1.c)Inventario y logs sin datos innecesarios1 y 2
ConfidencialidadAcceso SSH por clave, permisos por grupo3
Cifrado y seudonimizaciónTLS en tránsito, LUKS en reposo, IP anonimizada2 y 4
Capacidad de demostrar el cumplimientoRegistro de accesos con auditd5
Limitación del plazo de conservación (art. 5.1.e)Retención automática de logs y exportaciones6
Disponibilidad y resilienciaCopias cifradas y probadas7
Notificación de brechas en 72 horas (art. 33)Parches, detección y registro de incidentes8

Paso 1: Inventariar dónde hay datos personales

No puedes proteger lo que no sabes que existe. Empieza por los servicios que escuchan en la red, porque cada uno recibe o almacena datos:

sudo ss -tulpn
Netid State  Local Address:Port  Peer Address:Port Process
tcp   LISTEN 0.0.0.0:22          0.0.0.0:*         users:(("sshd",pid=812,fd=3))
tcp   LISTEN 0.0.0.0:443         0.0.0.0:*         users:(("nginx",pid=1020,fd=6))
tcp   LISTEN 127.0.0.1:3306      0.0.0.0:*         users:(("mysqld",pid=945,fd=21))

Para cada servicio, localiza dónde guarda los datos. Los lugares habituales en un servidor web son:

  • Base de datos: tablas de usuarios, pedidos, formularios. En MySQL, los datos están en /var/lib/mysql.
  • Archivos subidos por usuarios: por ejemplo /var/www/your_domain/uploads.
  • Logs: /var/log/nginx/, el journal de systemd y los logs de la aplicación. Contienen IP, y a menudo correos o identificadores en las URL.
  • Copias de seguridad y exportaciones: volcados de base de datos, archivos CSV generados para soporte.

Revisa si los logs de acceso contienen direcciones de correo en las URL, un fallo frecuente en formularios que usan GET:

sudo grep -Eoh '[A-Za-z0-9._%+-]+(@|%40)[A-Za-z0-9.-]+\.[A-Za-z]{2,}' /var/log/nginx/access.log | sort -u | head

Si aparecen resultados, corrige la aplicación para que envíe esos datos por POST. Anota cada ubicación en una tabla (qué datos, ruta, quién accede, cuánto tiempo se conservan): es la base técnica del registro de actividades de tratamiento que exige el artículo 30.

Paso 2: Minimizar los datos personales en los logs

Las direcciones IP son datos personales según la jurisprudencia europea. Si no necesitas la IP completa en los logs de acceso, trúncala: eliminar el último octeto en IPv4 (y conservar solo los dos primeros grupos en IPv6) es suficiente para estadísticas y depuración.

Anonimizar la IP en Nginx

Crea un archivo en conf.d, que Nginx carga dentro del bloque http:

sudo nano /etc/nginx/conf.d/anonimizar-ip.conf
map $remote_addr $remote_addr_anon {
    ~(?P<ip>\d+\.\d+\.\d+)\.    $ip.0;
    ~(?P<ip>[^:]+:[^:]+):       $ip::;
    default                     0.0.0.0;
}

log_format anonimizado '$remote_addr_anon - $remote_user [$time_local] '
                       '"$request" $status $body_bytes_sent '
                       '"$http_referer" "$http_user_agent"';

Después usa ese formato en cada bloque server de tus sitios. Edita el archivo del sitio:

sudo nano /etc/nginx/sites-available/your_domain

Añade dentro del bloque server la línea access_log:

server {
    server_name your_domain;
    access_log /var/log/nginx/access.log anonimizado;
    # ... resto de la configuración del sitio
}

Valida y recarga:

sudo nginx -t
sudo systemctl reload nginx

Haz una petición y comprueba la última línea del log:

curl -s -o /dev/null https://your_domain
sudo tail -n 1 /var/log/nginx/access.log
203.0.113.0 - - [25/Sep/2026:10:12:44 +0000] "GET / HTTP/2.0" 200 612 "-" "curl/8.5.0"

La IP aparece truncada. Si usas fail2ban u otra herramienta que bloquea por IP leyendo este log, necesitará la IP completa: en ese caso mantén un log separado con retención muy corta solo para ella.

Limitar la retención del journal

El journal de systemd guarda por defecto hasta llenar un porcentaje del disco, sin límite de tiempo. Fija un plazo con un archivo adicional:

sudo mkdir -p /etc/systemd/journald.conf.d
sudo nano /etc/systemd/journald.conf.d/retencion.conf
[Journal]
MaxRetentionSec=90d

Reinicia el servicio y comprueba el espacio que ocupa:

sudo systemctl restart systemd-journald
journalctl --disk-usage

Revisa también la directiva rotate de /etc/logrotate.d/nginx: indica cuántos archivos rotados se conservan. El plazo adecuado lo decide tu política de retención; lo importante es que exista uno y que el servidor lo aplique solo.

Paso 3: Restringir el acceso al servidor y a los datos

SSH solo con clave y sin root

Crea un archivo de configuración adicional. En Ubuntu 24.04 se cargan los archivos de /etc/ssh/sshd_config.d/ por orden alfabético y gana el primer valor, así que usa un prefijo bajo para que prevalezca sobre otros archivos como 50-cloud-init.conf:

sudo nano /etc/ssh/sshd_config.d/01-seguridad.conf
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no

Valida, recarga y comprueba la configuración efectiva:

sudo sshd -t
sudo systemctl reload ssh
sudo sshd -T | grep -E '^(permitrootlogin|passwordauthentication)'
permitrootlogin no
passwordauthentication no

Un grupo para quien trata los datos

Da acceso a los directorios con datos personales solo a las personas que lo necesitan, mediante un grupo. Crea el grupo y el directorio:

sudo groupadd datos-personales
sudo install -d -m 2770 -o root -g datos-personales /srv/datos-personales
sudo usermod -aG datos-personales your_user

El bit setgid (el 2 de 2770) hace que los archivos nuevos hereden el grupo. Comprueba los permisos:

ls -ld /srv/datos-personales
drwxrws--- 2 root datos-personales 4096 Sep 25 10:20 /srv/datos-personales

El usuario tendrá acceso a partir de su siguiente inicio de sesión. Revisa periódicamente quién pertenece al grupo y quién tiene sudo:

getent group datos-personales sudo

Paso 4: Cifrar los datos en tránsito y en reposo

El RGPD cita el cifrado expresamente como medida adecuada. Comprueba primero el estado actual:

  • En tránsito: todo el tráfico con datos personales debe ir por TLS. Comprueba que tu sitio redirige a HTTPS con curl -sI http://your_domain | grep -i location y que solo acepta TLS 1.2 y 1.3. Si tu base de datos acepta conexiones remotas, esas conexiones también deben cifrarse.
  • En reposo: comprueba si el directorio de datos está en un volumen cifrado:
lsblk -o NAME,TYPE,FSTYPE,MOUNTPOINTS

Un volumen cifrado aparece como crypto_LUKS con un dispositivo de tipo crypt debajo. Si los datos personales están en un disco sin cifrar, muévelos a un volumen LUKS. Tienes el procedimiento completo en las guías de cifrado de datos en tránsito y en reposo de esta misma sección.

El cifrado en reposo también resuelve el borrado seguro en discos SSD y NVMe, donde herramientas como shred no garantizan nada porque el controlador del disco reubica los bloques: destruir las claves de un volumen LUKS deja ilegibles todos sus datos.

Paso 5: Registrar los accesos con auditd

Para demostrar quién accedió a los datos y cuándo, usa el sistema de auditoría del kernel. Instálalo:

sudo apt install auditd

Crea un archivo de reglas:

sudo nano /etc/audit/rules.d/rgpd.rules
# Lecturas y modificaciones de datos personales
-w /srv/datos-personales -p rwa -k datos_personales

# Cambios en cuentas y privilegios
-w /etc/passwd -p wa -k identidades
-w /etc/group -p wa -k identidades
-w /etc/sudoers -p wa -k sudoers
-w /etc/sudoers.d -p wa -k sudoers

# Cambios en la configuración de SSH
-w /etc/ssh/sshd_config -p wa -k ssh_config
-w /etc/ssh/sshd_config.d -p wa -k ssh_config

-p rwa registra lecturas, escrituras y cambios de atributos. En directorios con mucho tráfico (por ejemplo, el de subidas de una web) registrar las lecturas genera mucho volumen; en ese caso usa -p wa.

Carga las reglas y comprueba que están activas:

sudo augenrules --load
sudo auditctl -l
-w /srv/datos-personales -p rwa -k datos_personales
-w /etc/passwd -p wa -k identidades
...

Genera un acceso de prueba y búscalo:

echo prueba | sudo tee /srv/datos-personales/prueba.txt > /dev/null
sudo ausearch -k datos_personales -i --start today | grep -m1 'type=SYSCALL'
type=SYSCALL msg=audit(25/09/26 10:31:07.214:1187) : arch=x86_64 syscall=openat success=yes exit=3 ... auid=your_user uid=root ... comm=tee exe=/usr/bin/tee key=datos_personales

El campo auid identifica al usuario que inició sesión aunque haya usado sudo. Para un resumen por clave:

sudo aureport -k --summary -i

Los logs de auditoría se guardan en /var/log/audit/ y rotan según max_log_file y num_logs en /etc/audit/auditd.conf. Como un atacante con root podría borrarlos, envíalos también a un servidor de logs central.

Paso 6: Aplicar la retención automáticamente

Los datos que ya no se necesitan deben borrarse. En lugar de un script casero, usa systemd-tmpfiles, que Ubuntu ejecuta a diario mediante systemd-tmpfiles-clean.timer. Por ejemplo, para que las exportaciones generadas para solicitudes de acceso de los interesados se borren a los 30 días:

sudo nano /etc/tmpfiles.d/rgpd-exportaciones.conf
d /srv/datos-personales/exportaciones 2770 root datos-personales 30d

Crea el directorio y comprueba que la regla es válida:

sudo systemd-tmpfiles --create /etc/tmpfiles.d/rgpd-exportaciones.conf
sudo systemd-tmpfiles --clean /etc/tmpfiles.d/rgpd-exportaciones.conf
systemctl list-timers systemd-tmpfiles-clean.timer

A partir de ahora, los archivos de ese directorio sin acceso ni modificación en 30 días se eliminan solos. Para los datos de la base de datos (cuentas inactivas, pedidos antiguos), la retención debe implementarla la aplicación con una tarea programada que borre o anonimice registros según la política definida.

Paso 7: Hacer copias cifradas y comprobar que se restauran

El RGPD exige poder restaurar el acceso a los datos tras un incidente, y las copias contienen los mismos datos personales que el servidor. restic cifra las copias antes de enviarlas y aplica la retención. Instálalo:

sudo apt install restic

Inicializa un repositorio en un servidor remoto por SFTP. Te pedirá una contraseña: guárdala fuera del servidor, porque sin ella las copias son irrecuperables:

sudo restic -r sftp:[email protected]:/srv/restic/your_server init

Haz una copia del directorio de datos y aplica una política de retención:

sudo restic -r sftp:[email protected]:/srv/restic/your_server backup /srv/datos-personales
sudo restic -r sftp:[email protected]:/srv/restic/your_server forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune

Comprueba que puedes restaurar, que es lo que realmente importa:

sudo restic -r sftp:[email protected]:/srv/restic/your_server restore latest --target /tmp/prueba-restauracion
sudo ls -l /tmp/prueba-restauracion/srv/datos-personales
sudo rm -rf /tmp/prueba-restauracion

La retención de las copias forma parte de tu política: un dato borrado a petición de su titular sigue en las copias hasta que caducan. Documenta ese plazo. Para las copias de bases de datos, haz primero un volcado coherente (por ejemplo con mysqldump --single-transaction) y copia el volcado.

Paso 8: Prepararse para detectar y notificar una brecha

Ante una brecha de datos personales, el responsable debe notificarla a la autoridad de control (en España, la AEPD) en un plazo de 72 horas desde que tenga constancia. Técnicamente eso exige mantener el sistema parcheado y poder reconstruir qué pasó.

Comprueba que las actualizaciones de seguridad automáticas están activas:

systemctl status unattended-upgrades --no-pager

Si no lo están, actívalas:

sudo apt install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades

Revisa los intentos de acceso SSH fallidos y los inicios de sesión correctos:

sudo journalctl -u ssh --since "24 hours ago" | grep -E 'Failed|Accepted' | tail -n 20

Con esto, más los registros de auditd del paso 5 y la IP de origen en los logs de SSH, podrás responder a las preguntas clave ante un incidente: qué sistema se vio afectado, qué datos contenía, quién accedió y desde cuándo.

Conclusión

Has aplicado en el servidor las medidas técnicas que el RGPD exige de forma explícita: sabes dónde están los datos personales, los logs contienen menos datos, el acceso está restringido y registrado, los datos caducan automáticamente y las copias están cifradas y probadas. Como siguientes pasos, centraliza los logs de auditoría fuera del servidor, cifra con LUKS los volúmenes que aún no lo estén y revisa estas medidas al menos una vez al año o cuando cambie la aplicación, dejando constancia de cada revisión.