Instalación y configuración de Wireguard

Vamos a instalar un servidor Wireguard en nuestro VPS.

# Instalamos wireguard y generador de qr para escanear desde app movil
sudo apt install wireguard qrencode -y

# Cambiamos a nuestro directorio de wireguard
sudo su
cd /etc/wireguard/
umask 077

# Generamos claves de servidor
wg genkey | tee /etc/wireguard/server.key | wg pubkey > /etc/wireguard/server.pub

Creamos nuestro fichero wg0.conf:

nano wg0.conf

[Interface]
# IP que tendrá el VPS dentro de la VPN
Address = 10.8.0.1/24
# Puerto de escucha (OJO - abrir el puerto en ufw y panel de nuestro vps si es necesario)
ListenPort = 51820
# Clave privada del servidor
PrivateKey = # GENERADA EN EL APARTADO ANTERIOR - FICHERO server.key

# Reglas para permitir que el tráfico fluya y salga a internet
#PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o ens6 -j MASQUERADE
#PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o ens6 -j MASQUERADE

# Reglas combinadas: Acceso a Internet (ens6) + Acceso a Tailscale (tailscale0)
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o ens6 -j MASQUERADE; iptables -A FORWARD -i %i -o tailscale0 -j ACCEPT; iptables -A FORWARD -i tailscale0 -o %i -m state --state RELATED,ESTABLISHED -j ACCEPT; iptables -t nat -A POSTROUTING -o tailscale0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o ens6 -j MASQUERADE; iptables -D FORWARD -i %i -o tailscale0 -j ACCEPT; iptables -D FORWARD -i tailscale0 -o %i -m state --state RELATED,ESTABLISHED -j ACCEPT; iptables -t nat -D POSTROUTING -o tailscale0 -j MASQUERADE


# CLIENTES

# s24
[Peer]
PublicKey = # CLAVE PUBLICA DE NUESTRO CLIENTE S24
AllowedIPs = 10.8.0.2/32

# envy
[Peer]
PublicKey = # CLAVE PUBLICA DE NUESTRO CLIENTE ENVY
AllowedIPs = 10.8.0.3/32

Generamos las claves de nuestro primer cliente:

wg genkey | tee /etc/wireguard/s24.key | wg pubkey > /etc/wireguard/s24.pub

Fichero de configuracion del cliente:

nano s24.conf

[Interface]
# Clave privada del cliente s24
PrivateKey = # CLAVE PRIVADA DE s24 GENERADA EN EL PASO ANTERIOR FICHERO s24.key
Address = 10.8.0.2/24
#### OJO CON ESTO ######
# DNS = 1.1.1.1 # NETCUP es muy exigente con su firewall externo y no permite las consultas DNS. Un problema parecido he tenido en la configuración de AdguardHome
# Para hacer funcionar esta configuración de wireguard en mi vps de NetCUP tengo que comentar la línea de DNS, cuando estaba en piensasolutions no me hacía falta comentar la línea.

[Peer]
# Public key del servidor
PublicKey = # CLAVE PUBLICA DEL SERVIDOR FICHERO server.pub
Endpoint = IP_PUBLICA_VPS:51820
AllowedIPs = 0.0.0.0/0

Generamos el codigo qr para escanear con el movil:

qrencode -t ansiutf8 < s24.conf

vps-5.png

Y listo. Con esto ya está configurado nuestro servidor y nuestro.

Arrancamos el servicio y lo habilitamos:

systemctl start wg-quick@wg0
systemctl enable wg-quick@wg0

#Vemos el estado del servidor
wg show

vps-4.png

Cuando actualicemos algún peer reiniciamos el servidor wireguard:

systemctl restart wg-quick@wg0

IMPORTANTE: Fichero wg0.conf no se puede borrar. Los ficheros .conf de los clientes no es necesarios conservarlos.Simplemente los creamos para generar luego el qr o para importarlos desde nuestro gestor de red de Gnome. RECORDAR actualizar nuestro fichero wg0.conf con cada cliente que añadimos.

Ampliar la capacidad de RAM de nuestro VPS con swap

Nuestro VPS está muy escaso de RAM. Vamos a darle algo de margen aprovechando nuestro nvme y creando una swap de 1GB de tamaño.

Creación de nuestro fichero swap:


sudo fallocate -l 1G /swapfile
ls -la /

sudo chmod 600 /swapfile

sudo mkswap /swapfile

sudo swapon /swapfile

echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
cat /etc/fstab

free -h

sudo sysctl vm.swappiness=20
htop

vps-3.png

Backups remotos con Borgmatic

En este mismo blog, tengo una entrada con la configuración de borgmatic en mi NAS secundario de backups.
Vamos a hacer una mejora en la programación de los backups.
Debian 13 ya no usa cron para las tareas. Ahora usa systemd.

Instalación de borgmatic

# Instalación
sudo apt install borgmatic

# Generamos fichero de configuración
sudo generate-borgmatic-config

Editamos nuestro fichero de borgmatic:

sudo nano /etc/borgmatic/config.yaml

# Añadimos lo siguiente:
source_directories:
  - /home/usuario

repositories:
  # USAMOS NUESTRA IP DE TAILSCALE
  - path: ssh://borg@100.105.100.10:2222/./piensa
    label: piensa

exclude_caches: true
exclude_patterns:
  - '*.pyc'
  - /home/*/.cache


compression: auto,zstd
encryption_passphrase: PASS_SUPER_SECRETA
archive_name_format: "{hostname}-{now}"

# Usamos root porque hay directorios que solo tienen permisos de root (pe. en crowdsec)
ssh_command: ssh -i /root/.ssh/piensa
retries: 5
retry_wait: 5

keep_daily: 3
keep_weekly: 4
keep_monthly: 12

checks:
  - name: repository
    frequency: 4 weeks
  - name: archives
    frequency: 8 weeks

check_last: 3

apprise:
  states:
    - start
    - finish
    - fail

  services:
    - url: mailtos://smtp.gmail.com:587?user=SUPERUSUARIO@gmail.com&pass=SUPERSECRETA_PASS&from=SUPERUSUARIO@gmail.com&to=DESTINATARIO@gmail.com
      label: mail
    - url: tgram://BOT_TOKEN:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/-ID_GRUPO_TELEGRAM/
      label: telegram

  start:
    title: ⚙️ Starrted Backup Piensa
    body: Starting backup process

  finish:
    title: ✅ SUCCESS Backup Piensa
    body: Backup Piensa success

  fail:
    title: ❌ FAILED Backup Piensa
    body: Backups Piensa failed

Con esto ya está configurado el backup de nuestros datos.

Ahora tenemos que verificar que la configuración sea correcta, iniciamos el repositorio de borg en el servidor remoto y hacemos el primer backup:

# Verificamos configuración
sudo env "PATH=$PATH" borgmatic config validate
# Iniciamos el repositorio
sudo env "PATH=$PATH" borgmatic init --encryption repokey-blake2
# Primer backup
sudo borgmatic create --list --stats

Vamos a programar los backups. En la web de borgmatic nos explica como hacerlo con tareas de systemd.


wget https://projects.torsion.org/borgmatic-collective/borgmatic/raw/branch/main/sample/systemd/borgmatic.service
wget https://projects.torsion.org/borgmatic-collective/borgmatic/raw/branch/main/sample/systemd/borgmatic.timer
sudo mv borgmatic.service borgmatic.timer /etc/systemd/system/
# Connfiguración de horario:
cd /etc/systemd/system
sudo nano borgmatic.timer

# Añadimos lo siguiente:
[Unit]
Description=Run borgmatic backup every day at 23:25:00

[Timer]
#OnCalendar=daily
OnCalendar=*-*-* 23:25:00
Persistent=true
RandomizedDelaySec=10m

[Install]
WantedBy=timers.target

Retocamos un par de cosas en nuestro fichero borgmatic.service

# Connfiguración de horario:
cd /etc/systemd/system
sudo nano borgmatic.service

[Unit]
Description=borgmatic backup
Wants=network-online.target
After=network-online.target
# Prevent borgmatic from running unless the machine is plugged into power. Remove this line if you
# want to allow borgmatic to run anytime.
#ConditionACPower=true
Documentation=https://torsion.org/borgmatic/

[Service]
Type=oneshot
RuntimeDirectory=borgmatic
StateDirectory=borgmatic

# Comentamos para que borgmatic no vaya al fichero borgmatic.pw a buscar las contraseñas
# Load single encrypted credential.
# LoadCredentialEncrypted=borgmatic.pw

LockPersonality=true
MemoryDenyWriteExecute=no
NoNewPrivileges=yes
PrivateDevices=yes
PrivateTmp=yes
ProtectClock=yes
ProtectControlGroups=yes
ProtectHostname=yes
ProtectKernelLogs=yes
ProtectKernelModules=yes
ProtectKernelTunables=yes
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_NETLINK
RestrictNamespaces=yes
RestrictRealtime=yes
RestrictSUIDSGID=yes
SystemCallArchitectures=native
SystemCallFilter=@system-service @mount
SystemCallErrorNumber=EPERM
ProtectSystem=full

CapabilityBoundingSet=CAP_DAC_READ_SEARCH CAP_NET_RAW

# Lower CPU and I/O priority.
Nice=19
CPUSchedulingPolicy=batch
IOSchedulingClass=best-effort
IOSchedulingPriority=7
IOWeight=100

Restart=no
LogRateLimitIntervalSec=0

# Delay start to prevent backups running during boot. Note that systemd-inhibit requires dbus and
# dbus-user-session to be installed.
ExecStartPre=sleep 1m

# En esta linea es importante indicar la ruta de nuestro borgmatic
# which borgmatic
ExecStart=systemd-inhibit --who="borgmatic" --what="sleep:shutdown" --why="Prevent interrupting scheduled backup" /usr/bin/borgmatic --verbosity -2 --syslog-verbosity 1

Por último, solo queda habilitar el nuevo servicio:

sudo systemctl enable --now borgmatic.timer

Verificamos la proxima ejecución:

systemctl list-timers borgmatic.timer

NEXT                        LEFT LAST                        PASSED UNIT            ACTIVATES        
Fri 2026-03-06 23:30:33 UTC   7h Fri 2026-03-06 07:18:33 UTC 8h ago borgmatic.timer borgmatic.service

1 timers listed.
Pass --all to see loaded but inactive timers, too.

Con esto debería estar correctamente configurados los backus a nuestro servidor borg a través del cliente borgmatic.

Para verificar nuestros backups:

sudo borgmatic list                   
piensa: Listing archives
my-vps-2026-02-23T12:23:46           Mon, 2026-02-23 12:23:46 [f6508163e6c277ea7cbaf33db275ba2052d430d4538e4ca12161a9fec5ee5a06]
my-vps-2026-02-28T08:10:03           Sat, 2026-02-28 08:10:04 [c0fe77d566cc1db569e05c5ff9d7fc5d845e93b667373de24d86445891645945]
my-vps-2026-03-01T08:10:04           Sun, 2026-03-01 08:10:05 [87a15d7677e28c62fe143e28117652dc8ca9f08b230083a01047147eb0cea948]
my-vps-2026-03-02T23:25:04           Mon, 2026-03-02 23:25:05 [e4209a633f6a2f67cba38e3f4d6c481e6212cbcf76d0d2f79d22cc2c52d754e6]
my-vps-2026-03-03T00:51:39           Tue, 2026-03-03 00:51:40 [f1c31249f7c8ded0e7d289a593c78e146606934cd5a913fec9959e7268e88cea]

Restaurar el backup

Esta la parte más importante de los backups. He realizado varias pruebas y todo ha funcionado correctamente. Para restaurar el backup primero hacemos un listado de los que tenemos y después montamos el backup en la ubicación deseada para restaurar los ficheros:

Primero listamos los ficheros creados con borgmatic:

sudo borgmatic list

Una vez sabemos el fichero que nos interesa podemos ver el contenido:

sudo borgmatic list --archive server-2020-04-01

Extracción completa de ficheros:

sudo borgmatic extract --archive my_server-2025-07-30T04:24:04 --destination /mnt/new-directory

Extracción de una parte solamente:

sudo borgmatic extract --archive my_server-2020-04-01 --path mnt/catpics --destination /mnt/new-directory

Actualizaciones de seguridad automaticas

Instalamos paquetes necesarios:

sudo apt update && sudo apt upgrade
sudo apt install unattended-upgrades apt-listchanges -y

Configuración:

sudo nano /etc/apt/apt.conf.d/50unattended-upgrades

# Nos aseguramos que las lineas siguientes están descomentadas:

Unattended-Upgrade::Origins-Pattern {
        // Codename based matching:
        // This will follow the migration of a release through different
        // archives (e.g. from testing to stable and later oldstable).
        // Software will be the latest available for the named release,
        // but the Debian release itself will not be automatically upgraded.
//      "origin=Debian,codename=${distro_codename}-updates";
//      "origin=Debian,codename=${distro_codename}-proposed-updates";
        "origin=Debian,codename=${distro_codename},label=Debian";
        "origin=Debian,codename=${distro_codename},label=Debian-Security";
        "origin=Debian,codename=${distro_codename}-security,label=Debian-Security";
//      "o=Debian Backports,n=${distro_codename}-backports,l=Debian Backports";

# Limpieza de dependencias no usadas
// Do automatic removal of unused packages after the upgrade
// (equivalent to apt-get autoremove)
Unattended-Upgrade::Remove-Unused-Dependencies "true";


# Podríamos configurar reinicio automático, pero prefiero hacerlo después tras una notificación:
# Descomentaríamos esto:
// Unattended-Upgrade::Automatic-Reboot "true";

// Automatically reboot even if there are users currently logged in
// when Unattended-Upgrade::Automatic-Reboot is set to true
//Unattended-Upgrade::Automatic-Reboot-WithUsers "true";

// If automatic reboot is enabled and needed, reboot at the specific
// time instead of immediately
//  Default: "now"

# Aquí configuraríamos la hora del reinicio:
// Unattended-Upgrade::Automatic-Reboot-Time "02:00";

Configuramos el lanzador:

sudo nano /etc/apt/apt.conf.d/20auto-upgrades

# Añadimos lo siguiente:
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Download-Upgradeable-Packages "1";
APT::Periodic::AutocleanInterval "7";
APT::Periodic::Unattended-Upgrade "1";

Verificamos el correcto funcionamiento:

sudo unattended-upgrade --dry-run --debug
sudo cat /var/log/unattended-upgrades/unattended-upgrades.log

systemctl status unattended-upgrades

Notificaciones de actualizaciones

Notificaciones con las actualizaciones automáticas. Creamos los scripts de notificación.

Como unattended-upgrades envía correos electrónicos de forma nativa, pero no notificaciones Webhook/Push directamente, usaremos un script de “Post-Invoke”.

sudo nano /usr/local/bin/notify-updates.sh

# Añadimos lo siguiente:
#!/bin/bash

# Configuración
APPRISE_URL="tgram://11111111111111:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/-5002897396/"
HOSTNAME=$(hostname)
REBOOT_FILE="/var/run/reboot-required"
REBOOT_PKGS="/var/run/reboot-required.pkgs"

# 1. Obtener paquetes (usamos una variable limpia)
LAST_UPGRADES=$(grep "Packages that were upgraded:" /var/log/unattended-upgrades/unattended-upgrades.log | tail -n 1 | cut -d: -f2)
[ -z "$LAST_UPGRADES" ] && LAST_UPGRADES="Ninguno (solo ajustes de seguridad)"

# 2. Lógica de reinicio
if [ -f "$REBOOT_FILE" ]; then
    ICON="⚠️"
    SUBJECT="REINICIO REQUERIDO - Piensa: $HOSTNAME"
    MSG_REBOOT="ATENCIÓN: Se requiere reiniciar el sistema."
else
    ICON="✅"
    SUBJECT="Actualización Exitosa - Piensa: $HOSTNAME"
    MSG_REBOOT="No es necesario reiniciar."
fi

# 3. Construir el cuerpo CON SALTOS DE LÍNEA REALES
# Importante: Las líneas vacías entre el texto mantienen el formato en Telegram
FINAL_BODY="$ICON Actualizaciones completadas en Piensa: $HOSTNAME.

Paquetes: $LAST_UPGRADES

$MSG_REBOOT"

# 4. Enviar (Apprise detectará los saltos de línea del shell)
apprise --title "$SUBJECT" --body "$FINAL_BODY" "$APPRISE_URL"

Como vemos en nuestro script el sistema nos avisa si es necesario reiniciar. En Debian, cuando apt instala un nuevo kernel, crea dos archivos temporales. El script simplemente mira si están ahí:

/var/run/reboot-required	#Su presencia indica que el sistema debe reiniciarse.
/var/run/reboot-required.pkgs	#Contiene la lista de paquetes que forzaron el reinicio (ej. linux-image-6.1...).

Hacemos el script ejecutable:

sudo chmod +x /usr/local/bin/notify-updates.sh

Creamos un nuevo archivo de configuración en APT para que ejecute el script justo después de que unattended-upgrades termine su tarea:

sudo nano /etc/apt/apt.conf.d/99apprise-notifications

# Añadimos lo siguiente:
Unattended-Upgrade::Post-Invoke { "/usr/local/bin/notify-updates.sh"; };

Pruebas:

sudo touch /var/run/reboot-required
/usr/local/bin/notify-updates.sh
sudo rm /var/run/reboot-required

En este punto nuestro sistema hace lo siguiente: 1.- Actualización diaria: unattended-upgrades hace el trabajo sucio.

2.- Post-Update: Recibimos un mensaje con los paquetes instalados y un aviso si hace falta reiniciar.
Ahora ya es decisión nuestra realizar el reinicio del sistema

Notificaciones de Servidor Online y espacio de almacenamiento

Ya que nos hemos puesto con las notificaciones, vamos a configurar las notificaciones para que una vez reiniciemos el sistema no informe que está operativo y otra para informar de poco espacio de almacenamiento. Mi VPS es muy modesto y esta última me vendrá muy bien en caso de problemas con el llenado del disco.

Creamos nuestro script:

sudo nano /usr/local/bin/notify-boot.sh

# Contenido:

#!/bin/bash
# Configuración
APPRISE_URL="tgram://2222222222:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/-5002897396/"
HOSTNAME=$(hostname)
UPTIME=$(uptime -p)

# Mensaje de sistema iniciado
SUBJECT="🚀 Servidor Online - Piensa: $HOSTNAME"
BODY="El sistema se ha iniciado correctamente.
Estado: $UPTIME
Fecha: $(date '+%Y-%m-%d %H:%M:%S')"

# Enviar notificación
/usr/bin/apprise --title "$SUBJECT" --body "$BODY" "$APPRISE_URL"

Permisos de ejecución:

sudo chmod +x notify-boot.sh
sudo nano /etc/systemd/system/notify-boot.service

# Contenido:
[Unit]
Description=Notificación de inicio por Apprise
After=network-online.target
Wants=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/notify-boot.sh
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

Cargamos el nuevo servicio y lo habilitamos:

sudo systemctl daemon-reload
sudo systemctl enable notify-boot.service

Prueba:

sudo systemctl start notify-boot.service

Vamos con la notificación de disco muy lleno:

sudo nano /usr/local/bin/check-disk.sh

# Contenido:

#!/bin/bash
# Configuración
APPRISE_URL="tgram://2222222222:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/-5002897396/"
THRESHOLD=10  # Porcentaje mínimo de espacio libre antes de avisar
HOSTNAME=$(hostname)

# Obtener el uso actual de la partición raíz (/)
CURRENT_FREE=$(df / --output=pcent | tail -1 | tr -dc '0-9')
FREE_SPACE_PERCENT=$((100 - CURRENT_FREE))

if [ "$FREE_SPACE_PERCENT" -le "$THRESHOLD" ]; then
    ICON="🚨"
    SUBJECT="ALERTA DE DISCO - $HOSTNAME"
    BODY="¡Poco espacio en disco detectado!

Espacio libre: $FREE_SPACE_PERCENT%
Uso actual: $CURRENT_FREE%

Se recomienda limpiar logs o paquetes antiguos antes de la próxima actualización."

    # Enviar notificación
    /usr/bin/apprise --title "$SUBJECT" --body "$BODY" "$APPRISE_URL"
fi

Permisos de ejecución:

sudo chmod +x check-disk.sh

Programación diaria con systemd timers:

sudo nano /etc/systemd/system/check-disk.service

# Contenido:
[Unit]
Description=Chequeo de espacio en disco para alertas Apprise
After=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/check-disk.sh

[Install]
WantedBy=multi-user.target

Creamos la Unidad de timer. Este archivo le dice a systemd cuando ejecutarlo:

sudo nano /etc/systemd/system/check-disk.timer

# Contenido:
[Unit]
Description=Ejecutar chequeo de disco diariamente

[Timer]
# Se ejecuta todos los días a las 08:30 AM
OnCalendar=*-*-* 08:30:00
# Añade un margen aleatorio de 5 min para no saturar si tienes muchos VPS
RandomizedDelaySec=300
Persistent=true # Si el VPS estaba apagado a las 08:30, el script se ejecutará inmediatamente en cuanto se encienda

[Install]
WantedBy=timers.target

Activamos el nuevo timer:

sudo systemctl daemon-reload
sudo systemctl enable --now check-disk.timer

Listado de timers activos en el sistema:

sudo systemctl list-timers

Logs de la última vez que se ejecutó el checkeo del disco:

sudo journalctl -u check-disk.service

Prueba para que nos avise por Telegram:

sudo nano /usr/local/bin/check-disk.sh
# Editamos nuestro script y modificamos la siguiente linea:
# Si nuestro disco está mas de un 10% lleno que nos avise:
THRESHOLD=90  # Porcentaje mínimo de espacio libre antes de avisar

# Y lanzamos nuestro script.
/usr/local/bin/check-disk.sh

Nos debería llegar una notificación a Telegram con el aviso.

Ejecución manual del checkeo del disco:

sudo systemctl start check-disk.service

Con todo esto, nuestro VPS nos notificará de los siguientes eventos:

Actualizaciones: Te avisa qué instaló.
Mantenimiento: Te avisa si el kernel cambió y toca reiniciar.
Supervivencia: Te avisa si el VPS arrancó tras un corte o reboot.
Prevención: Te avisa si se está quedando sin espacio en disco.


Fuentes y enlaces de interés que ayudaran a complementar esta guía:

Debo decir que en esta guía he tirado mucho de IA.
https://blog.lasnotasdenoah.com/posts/vps-proxy/
Instalación de traefik sin etiquetas
Crowdsec WAF - Appsec
Web oficial de borgmatic