🎨 Sysprovider Code
Sysprovider LogoWiki
🇪🇸Hosting español para ecommerce

Implementación de VPN site-to-site con WireGuard y encriptación ChaCha20

Actualizado el 14 de abril de 2026

Introducción

En el ecosistema actual de infraestructura cloud y datacenters distribuidos, la necesidad de interconectar redes de forma segura, eficiente y con baja latencia es crítica. Las VPNs site-to-site tradicionales basadas en IPsec o OpenVPN, aunque maduras, a menudo adolecen de complejidad de configuración, overhead de rendimiento no despreciable o dependencias de kernel pesadas. Aquí es donde WireGuard irrumpe como un cambio de paradigma.

WireGuard no es solo un protocolo más; es una redefinición de lo que una VPN moderna debe ser: un cifrado de última generación (ChaCha20, Poly1305, Curve25519), un código base minimalista (~4000 líneas) que facilita la auditoría de seguridad, y una integración directa en el kernel de Linux desde la versión 5.6. Este artículo técnico profundiza en la implementación de un túnel site-to-site entre dos servidores Ubuntu 22.04 LTS, detallando cada paso, la justificación criptográfica y las optimizaciones de rendimiento.

Arquitectura y Justificación Criptográfica

Antes de escribir una línea de configuración, es imperativo entender por qué WireGuard elige su stack criptográfico.

El Tridente Criptográfico: ChaCha20, Poly1305 y Curve25519

A diferencia de IPsec, que a menudo negocia algoritmos (con la consiguiente complejidad y posibles vectores de ataque), WireGuard es opinático y fijo. Esto elimina la necesidad de un proceso de handshake complejo para acordar cifrados.

ComponenteAlgoritmoPropósitoPor qué es superior
Cifrado SimétricoChaCha20Cifrado del payload del paquete3x más rápido que AES en CPUs sin aceleración por hardware (AES-NI). Resistente a ataques de temporización y de canal lateral.
AutenticaciónPoly1305MAC (Message Authentication Code)Garantiza integridad y autenticidad. Diseñado para ser rápido en software, complementa perfectamente a ChaCha20.
Intercambio de ClavesCurve25519 (X25519)Derivación de claves compartidasCurva elíptica de alta seguridad (128 bits de seguridad) con implementaciones resistentes a implementaciones defectuosas.
Derivación de ClavesBLAKE2sKDF (Key Derivation Function) para sesionesMás rápido que SHA-3 y SHA-2, diseñado para hashing de alto rendimiento.
Sello de TiempoTacit (no es un algoritmo)Prevención de ataques de replayCada paquete lleva un sello de tiempo de 64 bits. El receptor rechaza paquetes con sellos anteriores al último válido.

Nota clave: La combinación ChaCha20-Poly1305 es un AEAD (Authenticated Encryption with Associated Data). Esto significa que el cifrado y la autenticación se realizan en un solo paso, eliminando vulnerabilidades de padding oracle que afectan a modos como CBC.

Modelo de Confianza: Clave Pública como Identidad

En WireGuard, no hay certificados X.509 ni CA. La identidad de un peer es su clave pública Curve25519. Esto simplifica drásticamente el modelo de confianza: si tienes la clave pública correcta, confías en el peer. La configuración site-to-site es inherentemente una relación de confianza bilateral.

Escenario de Implementación

Vamos a interconectar dos sedes:

  • Sede A (Servidor Central):
    • Interfaz Pública: eth0 con IP 203.0.113.1 (IP pública).
    • Red Interna: 10.10.10.0/24.
    • WireGuard IP del túnel: 10.10.20.1/24.
  • Sede B (Sucursal):
    • Interfaz Pública: eth0 con IP 198.51.100.1 (IP pública, posiblemente dinámica, usaremos un endpoint fijo para el ejemplo).
    • Red Interna: 10.10.30.0/24.
    • WireGuard IP del túnel: 10.10.20.2/24.

El objetivo es que cualquier host en 10.10.10.0/24 pueda comunicarse con cualquier host en 10.10.30.0/24 a través del túnel cifrado.

Paso 1: Instalación y Generación de Claves

WireGuard viene integrado en kernels modernos, pero necesitamos las herramientas de userspace.

En Ambos Servidores

# Actualizar repositorios e instalar wireguard-tools
sudo apt update
sudo apt install -y wireguard-tools

# Verificar que el módulo del kernel está disponible
sudo modprobe wireguard
lsmod | grep wireguard
# Debería mostrar: wireguard           ...  0

Generación del Par de Claves

Cada servidor necesita su propio par de claves. La clave privada nunca debe salir del servidor.

# 1. Crear directorio de configuración (protegido)
sudo mkdir -p /etc/wireguard
cd /etc/wireguard
sudo umask 077  # Asegura que los archivos creados solo sean legibles por root

# 2. Generar clave privada
wg genkey | sudo tee privatekey | wg pubkey | sudo tee publickey

# 3. Verificar
cat privatekey
cat publickey

¿Por qué umask 077? La clave privada es el talón de Aquiles de la seguridad. Si es legible por otros usuarios, cualquier proceso comprometido podría leerla y suplantar al servidor. umask 077 asegura que los archivos se creen con permisos 600 (solo lectura/escritura para root).

Resultado esperado:

  • Sede A: privatekey_A y publickey_A.
  • Sede B: privatekey_B y publickey_B.

Paso 2: Configuración del Túnel en la Sede A (Central)

Creamos el archivo de configuración de la interfaz. WireGuard usa un formato INI simple.

sudo nano /etc/wireguard/wg0.conf

Contenido para Sede A:

[Interface]
# Dirección IP del túnel para este servidor

Address = 10.10.20.1/24
# Clave privada generada en el paso anterior

PrivateKey = <privatekey_A>
# Puerto de escucha UDP (por defecto 51820, puede cambiarse)

ListenPort = 51820
# Tabla de enrutamiento. 'auto' (por defecto) añade rutas automáticamente.
# 'off' desactiva la gestión automática de rutas.

Table = auto
# Reglas de firewall para iptables/nftables (opcional pero recomendado)
# Asegura que el tráfico que sale del túnel se enmascare (MASQUERADE) para llegar a la red local.

PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

[Peer]
# Clave pública de la Sede B

PublicKey = <publickey_B>
# Red(es) que se deben enrutar a través de este peer (la red local de la Sede B)

AllowedIPs = 10.10.30.0/24
# Dirección IP pública y puerto de la Sede B

Endpoint = 198.51.100.1:51820
# Mantener la conexión activa si hay NAT (útil si el peer tiene IP dinámica)
# En este caso, lo configuramos para mantener el estado del firewall/NAT.

PersistentKeepalive = 25

Análisis de Directivas Clave:

  • Address: No es una IP virtual. WireGuard añade esta IP a la interfaz wg0. Es la dirección de origen para los paquetes que salen del túnel.
  • Table = auto: WireGuard gestiona automáticamente la tabla de enrutamiento. Cuando ve AllowedIPs = 10.10.30.0/24, añade una ruta estática en la tabla principal: 10.10.30.0/24 via dev wg0. Esto es fundamental para que el tráfico destinado a la Sede B se dirija al túnel.
  • PostUp / PostDown: Scripts que se ejecutan al activar/desactivar la interfaz.
    • iptables -A FORWARD -i wg0 -j ACCEPT: Permite que el tráfico que entra por wg0 sea reenviado.
    • iptables -A FORWARD -o wg0 -j ACCEPT: Permite que el tráfico que sale hacia wg0 sea reenviado.
    • iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE: Crítico para site-to-site. Sin esto, los paquetes que salen del túnel hacia la red local (10.10.10.0/24) tendrían como origen la IP del túnel (10.10.20.1), no la IP del host original. MASQUERADE cambia el origen por la IP de eth0 (203.0.113.1), permitiendo que los hosts de la red local respondan correctamente.
  • AllowedIPs: Es la lista de control de acceso (ACL) del tráfico. WireGuard solo acepta paquetes entrantes cuyo origen IP esté dentro de este rango. También es la lista de rutas que se añaden a la tabla de enrutamiento.
  • PersistentKeepalive: Envía un paquete vacío cada 25 segundos. Esencial si la Sede B está detrás de un NAT que cierra sesiones UDP inactivas.

Paso 3: Configuración del Túnel en la Sede B (Sucursal)

Configuración simétrica pero con roles invertidos.

sudo nano /etc/wireguard/wg0.conf

Contenido para Sede B:

[Interface]

Address = 10.10.20.2/24

PrivateKey = <privatekey_B>

ListenPort = 51820

Table = auto

# Reglas de firewall para la Sede B
# Nota: El MASQUERADE se hace sobre la interfaz de salida local (eth0)

PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

[Peer]

PublicKey = <publickey_A>
# Red de la Sede A

AllowedIPs = 10.10.10.0/24
# Endpoint de la Sede A

Endpoint = 203.0.113.1:51820

PersistentKeepalive = 25

Diferencia clave: En AllowedIPs, la Sede B solo enruta la red de la Sede A (10.10.10.0/24). Si quisiéramos que todo el tráfico de la Sede B saliera a Internet a través de la Sede A (VPN full-tunnel), añadiríamos 0.0.0.0/0. Para un site-to-site, solo las redes privadas.

Paso 4: Habilitar el Reenvío de IP (IP Forwarding)

Sin esto, el kernel de Linux descartará cualquier paquete que no esté destinado a una IP local. Es el corazón del enrutamiento.

En Ambos Servidores

# Habilitar forwarding de forma permanente
sudo nano /etc/sysctl.conf
# Descomentar o añadir la línea:
net.ipv4.ip_forward=1

# Aplicar el cambio sin reiniciar
sudo sysctl -p

# Verificar
sysctl net.ipv4.ip_forward
# Debe devolver: net.ipv4.ip_forward = 1

Advertencia de seguridad: Habilitar IP Forwarding convierte al servidor en un router. Combinado con las reglas de iptables anteriores, cualquier tráfico que entre por eth0 y tenga como destino otra red (si existiera) sería reenviado. Las reglas FORWARD en PostUp limitan esto solo a la interfaz wg0, pero es una buena práctica tener un firewall restrictivo en INPUT.

Paso 5: Activación y Verificación del Túnel

En Ambos Servidores

# Activar la interfaz wg0
sudo wg-quick up wg0

# Verificar el estado de la interfaz
sudo wg show

# Verificar las rutas añadidas
ip route show

# Verificar las reglas de iptables (deberías ver las cadenas FORWARD con ACCEPT para wg0)
sudo iptables -L FORWARD -v -n

Salida esperada de sudo wg show:

interface: wg0
  public key: <publickey_A>
  private key: (hidden)
  listening port: 51820

peer: <publickey_B>
  endpoint: 198.51.100.1:51820
  allowed ips: 10.10.30.0/24
  latest handshake: 1 minute, 30 seconds ago
  transfer: 1.2 KiB received, 2.1 KiB sent

Si ves latest handshake: ... ago, el túnel está establecido. Si ves (none), el handshake no se ha completado. Revisa:

  1. Firewalls (UFW, iptables, Security Groups en cloud) que permitan tráfico UDP en el puerto 51820.
  2. Que AllowedIPs esté correctamente configurado.
  3. Que las claves públicas coincidan.

Hacer la Configuración Persistente

Para que el túnel se active automáticamente al arrancar el sistema:

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

Paso 6: Pruebas de Conectividad y Rendimiento

Prueba Básica de Ping

Desde un host en la Sede A (10.10.10.100):

ping -c 4 10.10.30.100

Si el ping falla, el problema suele estar en el enrutamiento de retorno. La Sede B debe tener una ruta para 10.10.10.0/24 hacia 10.10.20.1 (que ya la tiene por AllowedIPs). Asegúrate de que los firewalls locales de los hosts destino permitan ICMP.

Prueba de Ancho de Banda con iperf3

# En la Sede B (servidor iperf)
iperf3 -s

# En la Sede A (cliente iperf)
iperf3 -c 10.10.20.2 -t 30 -P 4

WireGuard con ChaCha20-Poly1305 debería mostrar un rendimiento cercano al de la velocidad de línea de la interfaz física, especialmente en CPUs modernas sin aceleración AES-NI. La sobrecarga es mínima (~60 bytes por paquete).

Optimización y Resolución de Problemas

Ajuste de MTU (Maximum Transmission Unit)

WireGuard añade overhead. Si la interfaz física tiene MTU 1500, la MTU del túnel debe ser menor para evitar fragmentación.

[Interface]

Address = 10.10.20.1/24

PrivateKey = ...

MTU = 1420

Razonamiento: WireGuard añade 80 bytes de overhead (cifrado + UDP + IP). 1500 - 80 = 1420. Ajustar la MTU previene la fragmentación a nivel de IP, que puede causar caídas de rendimiento en ciertos middleboxes.

Firewall y NAT

Asegúrate de que el tráfico UDP hacia el puerto 51820 esté permitido en ambos firewalls de red (cloud, router físico, etc.). Si usas ufw:

sudo ufw allow 51820/udp

Peer Detrás de NAT Dinámico

Si la Sede B tiene una IP pública dinámica,

¿Necesitas ayuda?Son dos de nuestros técnicos, Agustín y Mikel, y están disponibles para resolver cualquier problema.

Hablar con ellos ahora
Agustín y Mikel