Aunque existen aplicaciones 'todo en uno' como Nextcloud, Radicale es más específico para crear un servidor de código abierto muy liviano y sin necesidad de una base de datos, permitiendo gestionar, respaldar y sincronizar de forma libre los Contactos (.vcf) con CardDAV y Calendarios (.ics) con CalDAV (listas de tareas, notas o diarios) entre dispositivos.
Esta guía está diseñada para ser simple y accesible, con la idea principal de que el usuario tome el control de sus propios datos de Contactos y Calendarios (diarios, tareas).
Si bien la instalación de Radicale, Let's Encrypt y Nginx con Reverse Proxy (o la opción con Docker) es rápida, tenga en cuenta que, como es habitual en cualquier proyecto, los preparativos suelen ser un poco más extensos.
Si ya tiene preparado el servidor Linux y tiene un Dominio puede saltar al paso 5.
Para estas notas, se puede utilizar cualquier VPS basado en Linux Debian y adquirir un dominio con el registrador de tu preferencia, ya que las configuraciones son muy similares. En los ejemplos de estas notas se utilizan los servicios "Siempre Gratis" de Oracle Cloud OCI para crear el servidor Linux y los servicios de Gandi.net para registrar un dominio.
1. Requisitos
Requisitos:
- Una IP pública estática
- Un servidor Linux
- Un dominio
Para asegurar un flujo de datos seguro y sin interrupciones, esta guía utiliza un dominio registrado en gandi.net (por su interfaz simple y política de "No Bullshit"). Normalmente y en cualquier registrador, los dominios tienen precios accesibles y se puede optar por dominios .com, .org, .cc, .net, etc., o dominios específicos de un país, y pueden ser de utilidad para múltiples proyectos.
Para obtener una IP pública estática y un servidor Linux, es posible utilizar los servicios de oracle.com/cloud/ a través de la opción "Try OCI for free".
Nota: Para registrar una cuenta gratuita en Oracle Cloud, es necesario proporcionar información de una persona real, incluyendo una tarjeta que valide al usuario, y una vez creada, se tiene acceso hasta 4 servidores Linux de forma gratuita , Oracle no hará ningún cobro a menos que se solicite explícitamente cambiar a una cuenta de pago.
Usuarios y Passwords utilizados:
Esta es una lista de usuarios y passwords que se crean durante la instalación:
- User y Password para los servicios VPS Linux (Oracle Cloud OCI en los ejemplos).
- User y Password para el registrador de dominios (gandi.net en los ejemplos).
- User y Password para Radicale (usuario1 en los ejemplos).
- Password para la Clave SSH (para ingresar al servidor Linux con el usuario pruebauser).
- User y Password para el nuevo usuario de Linux (pruebauser en los ejemplos).
- Usuario específico para ejecutar Radicale de forma más segura (usuario_restringido en los ejemplos).
Nota: Para facilitar la administración, se recomienda utilizar un gestor de passwords como KeepassXC.
2. Crear la Clave SSH
Crear la llave SSH en Linux desde la terminal:
#1. Crear la llave SSH con el nombre "server" (Usar cualquier nombre o el nombre por defecto).
ssh-keygen -o -t rsa -b 4096 -f ~/.ssh/server
#2. Solicitará agregar una contraseña cualquiera (normalmente una nueva) y luego confirmarla.
#3. Se crea en la carpeta ~/.ssh la Clave privada (server) y la Clave pública (server.pub).
#4. Consultar la llave SSH.
cat ~/.ssh/server.pub
Nota: El principio de la criptografía asimétrica es que el cliente posee una clave privada y el servidor una clave pública, solo quienes posean la clave privada pueden descifrar la clave SSH para acceder al servidor. Este par de archivos puede ser copiado o movido a cualquier ruta o dispositivo.
En Windows se pueden utilizar herramientas como PuTTY, WSL o incluso una máquina virtual con Linux. Sin embargo, se recomienda instalar Git SCM y utilizar su herramienta Git Bash:
https://git-scm.com/downloads/win (64-bit Git for Windows Setup)
La guía utiliza nano como editor de texto. Durante la instalación de Git SCM, hay una sección para elegir entre Vim y otros, se puede elegir nano.
Crear la llave SSH en Git Bash:
#1. Crear la llave SSH con el nombre "server" (Usar cualquier nombre o el nombre por defecto).
ssh-keygen -o -t rsa -b 4096 -f ~/.ssh/server
#2. Solicitará agregar una contraseña cualquiera (normalmente una nueva) y luego confirmarla.
#3. Consultar la llave SSH para copiar y utilizar en Oracle Cloud.
cat ~/.ssh/server.pub
#En Windows los archivos Clave privada (server) y la Clave pública (server.pub)
se crearon en C:/Users/USUARIO/.ssh/
Nota: El principio de la criptografía asimétrica es que el cliente posee una clave privada y el servidor una clave pública, solo quienes posean la clave privada pueden descifrar la clave SSH para acceder al servidor. Este par de archivos puede ser copiado o movido a cualquier ruta o dispositivo.
3. Crear el Servidor Linux
Crear una instancia OCI:
Una vez creada la cuenta en Oracle Cloud se inicia sesion.
- Ir al menú de opciones.
- Seleccionar "Instancias".
- Seleccionar la raíz.
- Crear instancia.
- Agregar un nombre (el nombre del host).
- Cambiar la imagen de Linux.
- Seleccionar Ubuntu.
- Seleccionar la versión.
- Seleccionar imagen.
- Verificar si la red está creada, si no es así, crearla.
- Seleccionar "Pegar claves públicas".
- Agregar la clave SSH creada y copiada anteriormente.
- Crear.
- Controles de la instancia OCI (la máquina virtual Linux). Con el botón "Terminar" se puede eliminar la instancia.
- Obtenemos la IP pública estática.
- Obtenemos el usuario de la instancia llamado "ubuntu" (es el usuario del servidor Linux, más adelante se cambia por seguridad).
Abrir puertos en las configuraciones de red de Oracle Cloud:
- Buscar " Default Security List ".
- Hacer clic en la Subred encontrada.
- Agregar reglas de entrada.
- CIDR de origen: 0.0.0.0/0
- Protocolo IP: TCP.
- Rango de puertos de destino: 80,443.
- Agregar reglas de entrada.
4. Agregar la IP a los DNS del Registrador de Dominios
En el ejemplo con gandi.net, después de adquirir un dominio ingresar a la pantalla principal.
- Ir a Dominio.
- Hacer clic en el dominio.
- Ir a Zonas DNS.
- Add record.
- Seleccionar tipo A.
- Normalmente se utiliza un TTL de 3600 (1 hora).
- Agregar cualquier nombre de subdominio, en el ejemplo se utiliza "radicale".
- Agregar la IP pública obtenida de Oracle Cloud.
- Crear.
5. Ingresar y Preparar el Servidor
Ingresar al servidor desde el cliente con la terminal:
#1. Colocar el comando especificando la clave pública con el usuario y la IP pública.
ssh -i ~/.ssh/server ubuntu@168.138.92.191
#2. Escribir "yes".
#3. Agregar la contraseña de la clave SSH.
#4. Ahora se ha ingresado al servidor Linux.
Crear un usuario nuevo y eliminar el usuario por defecto "ubuntu" creado por Oracle Cloud OCI:
#1. Crear usuario, en el ejemplo se llama "pruebauser".
sudo adduser pruebauser
#2. Agregar una nueva contraseña para el usuario nuevo y repetir.
#3. Se puede dejar en blanco o agregar información.
#4. Se agrega el usuario al grupo de sudo.
sudo usermod -aG sudo pruebauser
#4. Copiar la carpeta con la Clave Pública SSH al nuevo usuario para permitir su ingreso.
sudo cp -r /home/ubuntu/.ssh /home/pruebauser/
#4. Se le agregan los permisos del usuario nuevo a la carpeta copiada.
sudo chown -R pruebauser:pruebauser /home/pruebauser/.ssh
#5. "exit" dos veces para salir completamente e iniciar sesión con el nuevo usuario.
#6. Iniciar con el nuevo usuario, se utiliza el password para la Clave SSH.
ssh -i ~/.ssh/server pruebauser@168.138.92.191
#Eliminar el usuario "ubuntu".
#Usar sudo con el password del nuevo usuario.
sudo userdel -f ubuntu
sudo rm -r /home/ubuntu
Cambiar la zona horaria:
#Buscar el nombre correcto de la zona horaria (Ctrl+c para salir).
sudo timedatectl list-timezones
#Cambiar la zona horaria.
sudo timedatectl set-timezone America/Costa_Rica
Actualizar e instalar herramientas básicas:
#Actualizar Linux.
sudo apt update && apt upgrade -y
#Instalar nano, rsyslog y el framework para el Firewall (normalmente ya instalado).
sudo apt install nano rsyslog netfilter-persistent iptables-persistent -y
Abrir puerto 80 (http) y 443 (https) en el servidor Linux:
#Abrir puertosnen el servidor Linux: sudo iptables -I INPUT 6 -m state --state NEW -p tcp --match multiport --dports 80,443 -j ACCEPT #Hacer la regla persistente: sudo netfilter-persistent save
6. Instalar y Configurar Radicale, Let's Encrypt y Nginx con Reverse Proxy
Instalar herramientas:
sudo apt install radicale apache2-utils certbot python3-certbot-nginx nginx -y
Habilitar Radicale:
#Habilitar.
sudo systemctl enable radicale
#Iniciar.
sudo systemctl start radicale
#Verificar (ctrl+c para salir).
sudo systemctl status radicale
Configurar Radicale:
#Respaldar el archivo config.
sudo mv /etc/radicale/config /etc/radicale/config.backup
#Crear y abrir con nano el archivo config.
sudo nano /etc/radicale/config
#Copiar y pegar el siguiente contenido en el archivo abierto con nano:
[server]
hosts = 127.0.0.1:5232
max_connections = 20
max_content_length = 100000000
timeout = 30
[auth]
type = htpasswd
htpasswd_filename = /etc/radicale/users
htpasswd_encryption = bcrypt
delay = 5
[rights]
type = from_file
file = /etc/radicale/rights
[storage]
filesystem_folder = /var/lib/radicale/collections
max_sync_token_age = 2592000
[logging]
level = warning
mask_passwords = True
# Ctrl+s guardar.
# Ctrl+x salir de nano.
#Respaldar el archivo rights.
sudo mv /etc/radicale/rights /etc/radicale/rights.backup
#Definir los permisos de acceso a las colecciones.
sudo nano /etc/radicale/rights
#Copiar y pegar el siguiente contenido en el archivo abierto con nano:
#Agregar un usuario admin para Radicale, en el ejemplo se llama "usuario1"
[root]
user: .+
collection:
permissions: R
[principal]
user: .+
collection: {user}
permissions: RW
[calendars]
user: .+
collection: {user}/[^/]+
permissions: rw
[admin]
user: ^usuario1$
collection: .*
permissions: rw
[user-rights]
user: ^.+$
collection: {user}/.*
permissions: rw
Agregar usuarios:
# Crear el archivo cifrado con un usuario, en el ejemplo usuario1.
# Agregar contraseña y repetir.
sudo htpasswd -Bc /etc/radicale/users usuario1
# Si se desea agregar otros usuarios, quitar la bandera "-c".
sudo htpasswd -B /etc/radicale/users nuevo_usuario
Configuración segura de Radicale con usuario restringido:
#Configura un usuario específico para ejecutar Radicale de forma más segura.
sudo adduser --system --group --disabled-login usuario_restringido
#Edita/crear el archivo del servicio.
sudo nano /etc/systemd/system/radicale.service
[Unit]
Description=A simple CalDAV (calendar) and CardDAV (contact) server
After=network.target
[Service]
User=usuario_restringido
Group=usuario_restringido
ExecStart=/usr/bin/radicale --config /etc/radicale/config
Restart=on-failure
[Install]
WantedBy=multi-user.target
#Cambia la propiedad de los directorios.
sudo chown -R usuario_restringido:usuario_restringido /etc/radicale /var/lib/radicale /var/log/radicale
#Permisos de los directorios restrictivos.
sudo chmod -R 750 /etc/radicale /var/lib/radicale /var/log/radicale
#Reiniciar el demonio.
sudo systemctl daemon-reload
#Habilitar.
sudo systemctl enable radicale
#Iniciar.
sudo systemctl restart radicale
#Verificar (ctrl+c para salir).
sudo systemctl status radicale
Crear Certificados para el Dominio con Let's Encrypt:
#Antes de generar los certificados, verificar que hay acceso al dominio.
host radicale.varlogsys.com
#El comando anterior debería devolver la IP Pública.
#1. Generar certificados para el dominio.
sudo certbot --nginx -d radicale.varlogsys.com
#2. Agregar un email cualquiera.
#3. Aceptar con "y".
#4. Aceptar con "y".
#Las renovaciones de certificados de Let's Encrypt ya están automatizadas.
Configuración de Nginx y Reverse Proxy:
#Archivo de configuración de Nginx para el dominio radicale.varlogsys.com. Abrir con nano.
sudo nano /etc/nginx/sites-available/radicale.varlogsys.com
server {
listen 443 ssl http2;
server_name radicale.varlogsys.com;
ssl_certificate /etc/letsencrypt/live/radicale.varlogsys.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/radicale.varlogsys.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384";
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_dhparam /etc/nginx/dhparam.pem;
# Configuración de seguridad adicional
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
# Logs específicos para Radicale
access_log /var/log/nginx/radicale_access.log;
error_log /var/log/nginx/radicale_error.log;
location / {
proxy_pass http://127.0.0.1:5232;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
# Redirigir tráfico HTTP a HTTPS
server {
listen 80;
server_name radicale.varlogsys.com;
return 301 https://$server_name$request_uri;
}
#Generar un grupo Diffie-Hellman para mejorar la seguridad SSL. (Puede durar minutos)
sudo openssl dhparam -out /etc/nginx/dhparam.pem 2048
#Enlazar la nueva configuración y recargar Nginx.
sudo ln -s /etc/nginx/sites-available/radicale.varlogsys.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo unlink /etc/nginx/sites-enabled/default
sudo systemctl restart nginx
sudo systemctl restart radicale
#El servidor Radicale ahora funciona, ingresar al sitio, en el ejemplo radicale.varlogsys.com
Ver logs:
sudo journalctl -u radicale.service
sudo journalctl -u nginx.service
sudo tail /var/log/nginx/error.log
sudo tail /var/log/nginx/access.log
Respaldar todos los contactos y calendarios:
#Crear el archivo de respaldo llamado radicale_backup.tar.gz
sudo tar -cvzf /home/pruebauser/radicale_backup.tar.gz /var/lib/radicale/collections /etc/radicale/users
sudo chown pruebauser:pruebauser /home/pruebauser/radicale_backup.tar.gz
#Ejecutar lo siguiente en la PC cliente si se desea descargar el respaldo desde el servidor al cliente:
scp -i ~/.ssh/server pruebauser@168.138.92.191:/home/pruebauser/radicale_backup.tar.gz ~/
Restaurar/subir todos los contactos y calendarios:
#Ejecutar lo siguiente en la PC cliente si se desea subir el archivo desde cliente al servidor:
scp -i ~/.ssh/server ~/radicale_backup.tar.gz pruebauser@168.138.92.191:~/
#Este comando descomprimirá los archivos del respaldo directamente en sus ubicaciones originales
sudo tar -xvzf radicale_backup.tar.gz -C /
#Ajustar los permisos
sudo chown -R usuario_restringido:usuario_restringido /etc/radicale /var/lib/radicale
sudo chmod -R 750 /etc/radicale /var/lib/radicale
sudo chmod 640 /etc/radicale/users
Configurar los servicios con Docker:
#Instalar docker, certbot, htpasswd y crear los contenedores Radicale y Nginx.
sudo apt install docker.io docker-compose certbot apache2-utils -y
mkdir -p ~/radicale/data ~/radicale/config ~/radicale/auth
nano ~/radicale/docker-compose.yml
#Copiar y pegar el siguiente contenido en el archivo abierto con nano:
version: '3'
services:
radicale:
image: tomsquest/docker-radicale:latest
container_name: radicale
ports:
- "127.0.0.1:5232:5232"
volumes:
- ./data:/data
- ./config:/config
- ./auth:/auth
environment:
- UID=1000
- GID=1000
restart: unless-stopped
networks:
- radicale_network
nginx:
image: nginx:alpine
container_name: radicale_nginx
ports:
- "80:80"
- "443:443"
volumes:
- ./config/nginx.conf:/etc/nginx/nginx.conf:ro
- /etc/letsencrypt:/etc/letsencrypt:ro
- /var/log/nginx:/var/log/nginx
#- ./auth:/auth
depends_on:
- radicale
networks:
- radicale_network
restart: unless-stopped
networks:
radicale_network:
driver: bridge
nano ~/radicale/config/config
#Copiar y pegar el siguiente contenido en el archivo abierto con nano:
[server]
hosts = 0.0.0.0:5232
[auth]
type = htpasswd
htpasswd_filename = /auth/htpasswd
htpasswd_encryption = bcrypt
[rights]
type = owner_only
[storage]
type = multifilesystem
filesystem_folder = /data
nano ~/radicale/config/nginx.conf
#Copiar y pegar el siguiente contenido en el archivo abierto con nano:
events {}
http {
server {
listen 80;
server_name radicale.varlogsys.com;
# Redirección HTTP a HTTPS
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name radicale.varlogsys.com;
ssl_certificate /etc/letsencrypt/live/radicale.varlogsys.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/radicale.varlogsys.com/privkey.pem;
# Cabeceras de seguridad
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header X-Frame-Options "DENY" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline';" always;
access_log /var/log/nginx/radicale_access.log;
error_log /var/log/nginx/radicale-error.log;
location / {
proxy_pass http://radicale:5232/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# Autenticación básica desde nginx (Tiene que ver con - ./auth:/auth del docker-compose.yml)
# auth_basic "Restricted Content";
# auth_basic_user_file /auth/htpasswd;
}
}
#Crea el usuario1:
htpasswd -Bc ~/radicale/auth/htpasswd usuario1
#Añadir un usuario nuevo:
htpasswd -B ~/radicale/auth/htpasswd newuser
#Antes de generar los certificados, verificar que hay acceso al dominio.
host radicale.varlogsys.com
#El comando anterior debería devolver la IP Pública.
#Generar certificados para el dominio:
sudo certbot certonly --standalone -d radicale.varlogsys.com
#Iniciar/crear los contenedores Docker:
sudo docker-compose -f ~/radicale/docker-compose.yml up -d
#Muestra los contenedores Docker:
sudo docker ps
#Detener/borrar los contenedores:
sudo docker-compose -f ~/radicale/docker-compose.yml down
#Iniciar/crear los contenedores:
sudo docker-compose -f ~/radicale/docker-compose.yml up -d
#Muestra los registros (logs) de los contenedores :
sudo docker logs radicale_nginx && sudo docker logs radicale
Respaldar todos los contactos y calendarios de la instalación con Docker:
#Crear el archivo de respaldo llamado radicale_docker_backup.tar.gz
tar -cvzf ~/radicale_docker_backup.tar.gz ~/radicale/data ~/radicale/auth
#Ejecutar lo siguiente en la PC cliente si se desea descargar el respaldo desde el servidor al cliente:
scp -i ~/.ssh/server pruebauser@168.138.92.191:/home/pruebauser/radicale_docker_backup.tar.gz ~/
Restaurar/subir todos los contactos y calendarios:
#Ejecutar lo siguiente en la PC cliente si se desea subir el archivo desde cliente al servidor:
scp -i ~/.ssh/server ~/radicale_docker_backup.tar.gz pruebauser@168.138.92.191:/home/pruebauser/
#Descomprimir los archivos del respaldo en los volúmenes montados (con los contenedores detenidos):
tar -xvzf ~/radicale_docker_backup.tar.gz -C ~/
#Permisos de los volúmenes:
chown -R pruebauser ~/radicale/data ~/radicale/auth
#Iniciar los contenedores de Docker
sudo docker-compose -f ~/radicale/docker-compose.yml up -d
Configurar el Servidor Radicale en Producción y Agregar a los Clientes
Ingresar al subdominio creado ( radicale.varlogsys.com ):
Nota: En la instalación con Docker, la interfaz es ligeramente distinta.
- Iniciar sesión con los usuarios creados, en el ejemplo "usuario1".
- Si se han exportado contactos desde otras fuentes, se pueden subir archivos .vcf o .ics.
- Es posible crear una "Lista de Contactos" o un "Calendario", que puede incluir o no tareas o diarios.
- En las Collections se proporcionará el enlace para agregar a los servicios, en el ejemplo es:
https://radicale.varlogsys.com/usuario1/3451bb85-88f5-15d0-8e45-d2076a01ab16/
Nota: Si se hace clic en el enlace, descargará el calendario completo, útil para respaldar o mudarse.
Configurar en Android
Ejemplo de configuración de calendario en Android:
- Instalar DAVx5 desde F-Droid o Google Play.
- En este caso, DAVx5 reconocerá todo con solo la raíz del sitio web (radicale.varlogsys.com).
- Una vez agregada la cuenta, se puede administrar la sincronización y demás.
- Se puede verificar que concuerda con lo seleccionado en Radicale: Calendario, Tareas y Diario.
- En la imagen de la app de calendario Etar, en las opciones, se puede ver el "CalendarioPruebas".
- En la última imagen de la app de calendario Etar, se crea un "Evento desde Android".
Ahora se pueden crear eventos y demás, sincronizados en los calendarios de Android.
Configurar en Otros Cliente de Calendarios y Contactos
Ejemplo de configuración de calendario en el cliente Thunderbird de escritorio:
- Seleccionar calendario o contactos
- Agregar un nuevo calendario.
- Seleccionar On the Network.
- Agregar el usuario
- Agregar el enlace del calendario
- Agregar el password
- Dejar el formato CalDAV
- Vemos el calendario creado en Radicale llamado ""CalendarioPrueba""
- El calendario fue agregado.
- Se puede ver el evento creado en Android.
- El evento completo, se puede editar.
Protección y Seguridad General del Servidor
En un servicio personal se pueden evitar los intentos de ingreso por SSH, de hecho, se puede visualizar estos intentos de ingreso.
Cambiar opciones de SSH:
# Ver intentos fallidos de inicio de sesión.
sudo lastb
# Ingresar a las configuraciones de SSH
sudo nano /etc/ssh/sshd_config
# - Descomentar y cambiar la línea #MaxSessions 10 por las deseadas, por ejemplo MaxSessions 2
# - Desactivar el inicio por ssh del usuario root PermitRootLogin no
# - Tiempo en segundos que se cierra la sesión: ClientAliveInterval 900
# - Agregar la siguiente linea para permitir solo nuestro usuario AllowUsers pruebause
# - Descomentar y cambiar la línea #port 22 por algún otro puerto, por ejemplo port 22090
# Recordar abrir el puerto 22090:
iptables -I INPUT 6 -m state --state NEW -p tcp --match multiport --dports 22090 -j ACCEPT
netfilter-persistent save
# Recordar abrir el puerto en las reglas del servicio VPS (Oracle Cloud en los ejemplos).
sudo systemctl restart sshd
# Ahora se inicia sesión con ssh -p 22090 pruebauser@168.138.92.191
Deshabilitar el ingreso con contraseña root:
# Deshabilita el ingreso con contraseña root
passwd -d root
passwd -l root
Esta configuración habilita actualizaciones automáticas de seguridad y mantenimiento esenciales de la versión de Linux (en el ejemplo Ubuntu). Sin embargo, no cubre algunas actualizaciones, por eso es importante verificar el sistema cada cierto tiempo.
#Instalar las actualizaciones automáticas
sudo apt install unattended-upgrades -y
sudo mv /etc/apt/apt.conf.d/50unattended-upgrades /etc/apt/apt.conf.d/50unattended-upgrades.bak
sudo nano /etc/apt/apt.conf.d/50unattended-upgrades
#Copiar y pegar el siguiente contenido en el archivo abierto con nano:
// Automatically upgrade packages from these origins and components
Unattended-Upgrade::Origins-Pattern {
"origin=Ubuntu,codename=${distro_codename},label=Ubuntu";
"origin=Ubuntu,codename=${distro_codename},label=Ubuntu-Security";
"origin=UbuntuESMApps,codename=${distro_codename},label=UbuntuESMApps";
"origin=UbuntuESM,codename=${distro_codename},label=UbuntuESM";
};
// List of blacklisted packages that should not be automatically upgraded
Unattended-Upgrade::Package-Blacklist {
};
// Automatically reboot *without* confirmation if needed
Unattended-Upgrade::Automatic-Reboot "true";
// Automatically reboot even if users are logged in
Unattended-Upgrade::Automatic-Reboot-WithUsers "true";
// Time to reboot the system when unattended upgrades are done
Unattended-Upgrade::Automatic-Reboot-Time "02:00";
// Enable notifications of upgrades
Unattended-Upgrade::Mail "root";
Unattended-Upgrade::MailOnlyOnError "true";
// Remove unused dependencies
Unattended-Upgrade::Remove-Unused-Dependencies "true";
// Do not automatically upgrade to newer kernel versions if the system requires a reboot
Unattended-Upgrade::MinimalSteps "true";
sudo mv /etc/apt/apt.conf.d/20auto-upgrades /etc/apt/apt.conf.d/20auto-upgrades.bak
sudo nano /etc/apt/apt.conf.d/20auto-upgrades
#Copiar y pegar el siguiente contenido en el archivo abierto con nano:
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
APT::Periodic::Download-Upgradeable-Packages "1";
APT::Periodic::AutocleanInterval "7";
APT::Periodic::Unattended-Upgrade "1";
#Seleccionar Yes
sudo dpkg-reconfigure --priority=low unattended-upgrades
Fail2ban monitorea los logs del sistema en busca de intentos fallidos de acceso, como en SSH o servidores web, y bloquea automáticamente las IPs que exceden un número definido de intentos, protegiendo el servidor contra ataques de fuerza bruta.
#Instalar Fail2ban
sudo apt install fail2ban -y
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
sudo systemctl status fail2ban
#Esta configuración permite 3 intentos de ingreso; si falla, se "banea" la IP por 3600 segundos (1 hora)
#Se tiene una configuración por defecto para todas las Jails, pero se pueden configurar independiente.
#La IP 203.0.113.45 ha sido agregada como IP ignorada (whitelisted), por lo que no será bloqueada.
#Ver en la PC cliente la IP Pública actual. En el ejemplo 203.0.113.45:
curl ifconfig.io
#Ver en la PC servidor la IP Local Privada.
#En el ejemplo inet 10.0.0.116/24:
ip a
#Copiar y pegar el siguiente contenido en el archivo abierto con nano:
sudo nano /etc/fail2ban/jail.local
[DEFAULT]
bantime = 3600
findtime = 1200
maxretry = 3
backend = polling
banaction = iptables-allports
action = %(action_)s
ignoreip = 127.0.0.1/8 ::1 10.0.0.116/24 172.17.0.1/16 172.18.0.1/16 203.0.113.45
[sshd]
enabled = true
port = ssh
logpath = /var/log/auth.log
backend = systemd
[nginx-http-auth]
enabled = true
port = http,https
logpath = /var/log/nginx/error.log
[nginx-badbots]
enabled = true
port = http,https
logpath = /var/log/nginx/access.log
bantime = 86400
[nginx-botsearch]
enabled = true
port = http,https
logpath = /var/log/nginx/access.log
[radicale-auth]
enabled = true
port = http,https
filter = radicale-auth
logpath = /var/log/nginx/radicale_access.log
#Esta configuración permite proteger Radicale de intentos de autenticación fallidos.
sudo nano /etc/fail2ban/filter.d/radicale-auth.conf
[Definition]
failregex = ^<HOST> - \S+ .* "(GET|PROPFIND|HEAD|POST) .* HTTP/.*" 401
ignoreregex = ^<HOST> - - .* "(GET|PROPFIND|HEAD|POST) .* HTTP/.*" 401
#Detecta bots maliciosos que intentan acceder a rutas vulnerables o inexistentes.
sudo nano /etc/fail2ban/filter.d/nginx-badbots.conf
[Definition]
failregex = ^<HOST> -.*"(GET|POST).*HTTP.*(wp-login.php|xmlrpc.php|admin|admin.php|login.php|wp-admin|wp-content|wp-includes).*$
^<HOST> -.*"(GET|POST).*HTTP.*(\.git/HEAD|\.svn/entries|\.env|phpinfo|config.php|\.bak|\.old).*$
ignoreregex =
#Reiniciar Fail2ban.
sudo systemctl restart fail2ban
#Ver estado de Fail2ban.
sudo systemctl status fail2ban
#Ver todas las jails activas.
sudo fail2ban-client status
#Ver el estado de una jail específica.
sudo fail2ban-client status sshd
sudo fail2ban-client status nginx-http-auth
#Banear manualmente una IP. En el ejemplo se banea la IP en la Jail sshd.
sudo fail2ban-client set sshd banip 203.0.113.45
#Desbanear una IP manualmente.
sudo fail2ban-client set sshd unbanip 203.0.113.45
#Ver el historial de baneos.
sudo cat /var/log/fail2ban.log | grep Ban
#Ver el movimiento en los logs de Fail2ban.
sudo tail -f /var/log/fail2ban.log
Nota del flujo de trabajo de Fail2ban:
En la configuración de Nginx se crean "Logs específicos para Radicale" con los permisos adecuados para que Fail2ban los utilice (/etc/nginx/sites-available/radicale.varlogsys.com).
En la configuración de las Jail (/etc/fail2ban/jail.local) se agrega el log personalizado (/var/log/nginx/radicale_access.log) en la sección [radicale-auth].
También se crea un archivo/filtro (/etc/fail2ban/filter.d/radicale-auth.conf) para que Fail2ban entienda qué debe encontrar en las líneas de radicale_access.log, para esto se utiliza una expresión regular que identifica cuál línea tiene un usuario y el error 401, que es un intento de ingreso erróneo. Ejemplo de línea en radicale_access.log:
134.142.110.40 - usuario1 [22/Oct/2024:15:23:10 +0000] "PROPFIND / HTTP/2.0" 401 ...
Fail2ban identifica el problema e inicia el contador y segun las configuraciones banea la IP. El movimiento se puede visualizar con sudo tail -f /var/log/fail2ban.log:
[14678]: INFO [radicale-auth] Found 134.142.110.40
[14678]: INFO [radicale-auth] Found 134.142.110.40
[14678]: NOTICE [radicale-auth] Ban 134.142.110.40
Fail2ban monitorea los logs del sistema en busca de intentos fallidos de acceso, como en SSH o servidores web, y bloquea automáticamente las IPs que exceden un número definido de intentos, protegiendo el servidor contra ataques de fuerza bruta.
#Instalar Fail2ban
sudo apt install fail2ban -y
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
sudo systemctl status fail2ban
#Esta configuración permite 3 intentos de ingreso; si falla, se "banea" la IP por 3600 segundos (1 hora)
#Se tiene una configuración por defecto para todas las Jails, pero se pueden configurar independiente.
#La IP 203.0.113.45 ha sido agregada como IP ignorada (whitelisted), por lo que no será bloqueada.
#Ver en la PC cliente la IP Pública actual. En el ejemplo 203.0.113.45:
curl ifconfig.io
#Ver en la PC servidor la IP Local Privada y de Docker.
#En el ejemplo inet 10.0.0.116/24 172.17.0.1/16 172.18.0.1/16:
ip a
#Copiar y pegar el siguiente contenido en el archivo abierto con nano:
sudo nano /etc/fail2ban/jail.local
[DEFAULT]
bantime = 3600
findtime = 1200
maxretry = 3
backend = polling
banaction = iptables-docker-custom
action = %(action_)s
ignoreip = 127.0.0.1/8 ::1 10.0.0.116/24 172.17.0.1/16 172.18.0.1/16 203.0.113.45
[sshd]
enabled = true
port = ssh
logpath = /var/log/auth.log
backend = systemd
banaction = iptables-allports
[nginx-http-auth]
enabled = true
port = http,https
logpath = /var/log/nginx/error.log
[nginx-badbots]
enabled = true
port = http,https
logpath = /var/log/nginx/access.log
bantime = 86400
[nginx-botsearch]
enabled = true
port = http,https
logpath = /var/log/nginx/access.log
[radicale-auth]
enabled = true
port = http,https
filter = radicale-auth
logpath = /var/log/nginx/radicale_access.log
sudo nano /etc/fail2ban/action.d/iptables-docker-custom.conf
[Definition]
actionstart = iptables -N f2b-
iptables -A f2b- -j RETURN
iptables -I DOCKER-USER -p tcp -m multiport --dports http,https -j f2b-
actionstop = iptables -D DOCKER-USER -p tcp -m multiport --dports http,https -j f2b-
iptables -F f2b-
iptables -X f2b-
actionban = iptables -I f2b- -s -j REJECT
actionunban = iptables -D f2b- -s -j REJECT
#Esta configuración permite proteger Radicale de intentos de autenticación fallidos.
sudo nano /etc/fail2ban/filter.d/radicale-auth.conf
[Definition]
failregex = ^<HOST> - \S+ .* "(GET|PROPFIND|HEAD|POST) .* HTTP/.*" 401
ignoreregex = ^<HOST> - - .* "(GET|PROPFIND|HEAD|POST) .* HTTP/.*" 401
#Detecta bots maliciosos que intentan acceder a rutas vulnerables o inexistentes.
sudo nano /etc/fail2ban/filter.d/nginx-badbots.conf
[Definition]
failregex = ^<HOST> -.*"(GET|POST).*HTTP.*(wp-login.php|xmlrpc.php|admin|admin.php|login.php|wp-admin|wp-content|wp-includes).*$
^<HOST> -.*"(GET|POST).*HTTP.*(\.git/HEAD|\.svn/entries|\.env|phpinfo|config.php|\.bak|\.old).*$
ignoreregex =
#Reiniciar Fail2ban.
sudo systemctl restart fail2ban
#Ver estado de Fail2ban.
sudo systemctl status fail2ban
#Ver todas las jails activas.
sudo fail2ban-client status
#Ver el estado de una jail específica.
sudo fail2ban-client status sshd
sudo fail2ban-client status nginx-http-auth
#Banear manualmente una IP. En el ejemplo se banea la IP en la Jail sshd.
sudo fail2ban-client set sshd banip 203.0.113.45
#Desbanear una IP manualmente.
sudo fail2ban-client set sshd unbanip 203.0.113.45
#Ver el historial de baneos.
sudo cat /var/log/fail2ban.log | grep Ban
#Ver el movimiento en los logs de Fail2ban.
sudo tail -f /var/log/fail2ban.log
Nota del flujo de trabajo de Fail2ban:
En la configuración de Nginx se crean "Logs específicos para Radicale" con los permisos adecuados para que Fail2ban los utilice (/etc/nginx/sites-available/radicale.varlogsys.com).
En la configuración de las Jail (/etc/fail2ban/jail.local) se agrega el log personalizado (/var/log/nginx/radicale_access.log) en la sección [radicale-auth].
También se crea un archivo/filtro (/etc/fail2ban/filter.d/radicale-auth.conf) para que Fail2ban entienda qué debe encontrar en las líneas de radicale_access.log, para esto se utiliza una expresión regular que identifica cuál línea tiene un usuario y el error 401, que es un intento de ingreso erróneo. Ejemplo de línea en radicale_access.log:
134.142.110.40 - usuario1 [22/Oct/2024:15:23:10 +0000] "PROPFIND / HTTP/2.0" 401 ...
Fail2ban identifica el problema e inicia el contador y segun las configuraciones banea la IP. El movimiento se puede visualizar con sudo tail -f /var/log/fail2ban.log:
[14678]: INFO [radicale-auth] Found 134.142.110.40
[14678]: INFO [radicale-auth] Found 134.142.110.40
[14678]: NOTICE [radicale-auth] Ban 134.142.110.40
Sobre el consumo del servidor
Es importante mencionar que un servidor con Radicale, Let's Encrypt y Nginx con Reverse Proxy tiene un consumo muy bajo de recursos, incluso podría funcionar en un sistema con 512 MB de RAM o menos (dependiendo de la cantidad de usuarios, colecciones y otros factores). Sin embargo, la ejecución de aplicaciones como ClamAV cambia la dinámica de consumo de recursos.
Siendo objetivos, es importante mencionar que utilizar la memoria Swap para suplir la falta de memoria RAM es una mala práctica.
La memoria Swap utiliza parte del almacenamiento del disco y, en términos generales, la emplea como si fuera RAM.
El problema de esta práctica es que la memoria Swap es significativamente más lenta y, además, provoca un desgaste en la unidad de almacenamiento.
Sin embargo, en ocasiones tenemos aplicaciones que solo se ejecutan esporádicamente y requieren picos de memoria RAM como sucede con ClamAV, que durante sus escaneos puede llegar a tener picos de consumo de RAM. Dado que esto no ocurre de manera constante, podemos recurrir a la memoria Swap como apoyo.
Por otro lado, si estamos usando servicios en la nube y no nuestro propio hardware, algunos picos de consumo de RAM a la semana no son tan preocupantes.
#Agregar 4GB de Swap: sudo fallocate -l 4G /swapfile && sudo chmod 600 /swapfile && sudo mkswap /swapfile && sudo swapon /swapfile sudo cp /etc/fstab /etc/fstab.bak echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab && sudo sysctl vm.swappiness=10 && echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.conf #Verificar la memoria: free -mh
Nota: Si el servidor tiene menos de 1 GB, se recomienda no continuar o agregar memoria Swap. La instalación de rkhunter, chkrootkit y ClamAV es opcional en un servidor donde solo está Radicale.
Instalación de rkhunter y chkrootkit
rkhunter y chkrootkit detectan rootkits y malware en Linux, escaneando archivos y buscando comportamientos sospechosos o signos de infecciones conocidas.
#Instalar sudo apt install rkhunter chkrootkit -y Si pregunta sobre configurar Postfix: "No configuration" #Habilitar escaneos automáticos con cron.(Seleccionar 1. nano.) sudo crontab -e #Agregar al final del texto lo siguiente para escanear una vez a la semana:0 5 * * 1 /usr/bin/rkhunter --check --report-warnings-only | tee /var/log/rkhunter.log 0 6 * * 1 /usr/sbin/chkrootkit | tee /var/log/chkrootkit.log# Actualizar la base de datos de propiedades. sudo rkhunter --propupd #Realizar un escaneo manual con rkhunter. sudo rkhunter --check #Solo ver los mensajes de advertencia. sudo rkhunter --check --report-warnings-only #Realizar un escaneo manual con chkrootkit. sudo chkrootkit | sudo tee /var/log/chkrootkit.log #Ver los resultados de los escaneos. sudo cat /var/log/rkhunter.log sudo cat /var/log/chkrootkit.log
Instalación de ClamAV
ClamAV es un antivirus de código abierto para Linux, diseñado para detectar malware y virus.
Es posible que, después de la instalación se inicie un escaneo, lo que puede provocar lentitud o que la conexión se congele, lo mejor es esperar que termine, especialmente si la máquina es modesta.
#Instalar ClamAV.
sudo apt install clamav clamav-daemon clamav-freshclam -y
#Habilitar las actualizaciones.
sudo systemctl enable clamav-freshclam
sudo systemctl start clamav-freshclam
sudo systemctl status clamav-freshclam
#Habilitar escaneos automáticos con cron.(Seleccionar 1. nano.)
sudo crontab -e
#Agregar al final del texto lo siguiente para escanear a las 4am:
0 4 * * * /usr/bin/clamscan -r / --log=/var/log/clamav/clamav.log
#Ver los resultados de los escaneos.
sudo cat /var/log/clamav/scan.log
#Verificar el estado de la base de datos.
sudo cat /var/log/clamav/freshclam.log