Guía Definitiva: Configura tu Servidor VPN con WireGuard en Linux Paso a Paso
Tengo un servidor Hetzner con IP pública que hace de nodo central, y desde él se conectan mi laptop de trabajo, un homelab en casa que cambia de IP cada 24 horas por CGNAT, y dos o tres colegas sysadmins que entran a una base de datos PostgreSQL para hacer queries de monitoreo. La combinación “WireGuard + servidor central + múltiples clientes remotos” es la topología más común que vas a encontrar en cualquier setup de VPN para sysadmins, y es la más práctica cuando quieres reemplazar OpenVPN o IPsec sin arrastrar décadas de configuración frágil. Esta guía documenta exactamente esa configuración: un servidor Linux con WireGuard pública escuchando en UDP, y N clientes que se autentican con criptografía de curva elíptica. Incluye los seis problemas que más cuestan tiempo la primera vez (handshake que no completa, AllowedIPs mal escritas, IP forwarding que no se aplica, DNS que se pierde al conectar, claves con permisos 644, y systemd tunnel), al daño sistemático con wg show, wg syncconf y ip route cuando ya las quemaste.
Si tu caso es estrictamente P2P entre dos nodos Linux con IP pública estable, esta guía tiene la mitad de lo que necesitas en mi nota sobre WireGuard punto a punto. Si tienes 5+ nodos servidores detrás de un hub central, te conviene leer la guía de hub-and-spoke. Esta nota asume el caso más común: un servidor público + N clientes que entran como road warriors.
TL;DR — Lo que vas a tener al final
- Tiempo de setup: 45-60 minutos para el servidor + 5 minutos por cliente nuevo una vez que tienes el script de generación.
- Requisitos: Linux con kernel 5.6+, root, IP pública fija (o dominio dinámico con ddclient), UDP 51820 reachable.
- Resultado: Servidor VPN con N clientes, tráfico cifrado Curve25519/ChaCha20, throughput ~950 Mbps en hardware moderno, latencia <5ms intra-túnel.
- Troubleshooting típico: Handshake que no completa (UDP filtrado), AllowedIPs superpuesta, ip_forward=0, claves legibles. Diagnosticables con
wg show+journalctl -u wg-quick@wg0.
Por qué WireGuard como servidor VPN
WireGuard es un protocolo VPN moderno escrito por Jason Donenfeld (zx2c4), integrado en el kernel de Linux desde la versión 5.6 (marzo 2020). El paquete wireguard-tools provee las herramientas de userspace (wg, wg-quick), y desde 2026 vas a encontrarlo ya compilado en cualquier distro de las últimas tres LTS. La versión estable actual del paquete wireguard-tools es 1.0.20260223 (febrero 2026), con revisiones de seguridad y bugfixes que salen cada 3-6 meses.
Las razones operativas por las que WireGuard reemplazó a OpenVPN en mi setup:
- Menos código, menos superficie de ataque. WireGuard son ~4,000 líneas auditables, contra ~600,000 de OpenVPN. Menos bugs latentes, menos CVEs por año.
- Curva elíptica real. Usa Curve25519 para intercambio de claves y ChaCha20-Poly1305 para cifrado. OpenVPN sigue dependiendo en muchos casos de RSA-2048 y AES-256-CBC, algoritmos válidos pero con peor rendimiento en CPU sin AES-NI.
- Roaming transparente. Cuando un cliente cambia de WiFi a 4G, WireGuard detecta el nuevo endpoint y sigue el túnel sin renegociar handshake. OpenVPN tira la conexión y vuelve a negociar, lo que se siente como corte.
- Configuración declarativa. Todo el estado del túnel está en
/etc/wireguard/wg0.conf. No hay estado en memoria que perder, no hay archivos de sesión que sincronizar entre nodos.wg syncconfrecarga cambios en caliente sin tirar la interfaz. - Rendimiento medible. En mi benchmark entre dos VMs Hetzner (CX31, 4 vCPU), WireGuard mueve ~940 Mbps con
iperf3, OpenVPN en modo AES-GCM se queda en ~320 Mbps con la misma CPU. La diferencia es ruido de CPU por paquete.
La única contra real es que WireGuard requiere UDP. Algunos firewalls corporativos estrictos bloquean todo UDP fuera de 53/443, en cuyo caso WireGuard no atraviesa. Para ese caso, Tailscale con DERP relays (HTTPS sobre 443) funciona mejor, pero a costa de depender de un servicio externo. Si tienes control del firewall upstream, UDP es preferible.
Decisiones de diseño antes de empezar
Antes de tocar ningún archivo de configuración, definí cinco cosas. Cambiar cualquiera después significa reconfigurar todos los clientes existentes, y eso duele cuando ya tienes 8 peers activos.
- Rango de IPs del túnel. El default sensato es
10.0.0.0/24con el servidor en10.0.0.1. Cada cliente toma una IP de /32. Si vas a federar con una LAN existente, usa un rango que no choque (ej:10.10.0.0/24). - Puerto UDP de escucha.
51820es el default documentado. Si tu proveedor de VPS bloquea puertos altos por política, usa uno alto aleatorio (41920,53321) y documentalo. WireGuard solo escucha en UN puerto por interfaz, no hay multiplexing. - DNS que el cliente va a usar dentro del túnel. La opción más limpia es que el servidor VPN resuelva DNS recursivo (Pi-hole, AdGuard Home, unbound) y los clientes apunten a
10.0.0.1como DNS. Alternativa: Quad9 (9.9.9.9) o Cloudflare (1.1.1.1) directamente. NO uses el DNS del ISP, se filtra por doh. - Endpoint público del servidor. IP fija o dominio con DNS dinámico. Si tu IP cambia, WireGuard igual sigue funcionando (los clientes encuentran el servidor por endpoint en su config), pero necesitas actualizar el campo
Endpointen cada cliente cuando cambia. Con ddclient + duckdns es automático. - Política de tráfico: full tunnel o split tunnel. Full tunnel: todo el tráfico del cliente pasa por la VPN (configuras
AllowedIPs = 0.0.0.0/0en el peer). Split tunnel: solo el tráfico hacia tu red privada va por VPN (AllowedIPs = 10.0.0.0/24, 192.168.1.0/24). Full tunnel es más simple para road warriors, split tunnel preserva latencia a internet. Yo uso split por defecto.
Con esas cinco decisiones tomadas, escribir la config es directo.
Instalar WireGuard en el servidor
WireGuard se divide en dos partes: el módulo del kernel (built-in desde 5.6) y las herramientas de userspace. En cualquier distro moderna solo necesitas el paquete wireguard-tools (que provee wg y wg-quick). Verifica primero que el módulo está cargado antes de instalar nada, porque instalar wireguard-dkms sobre un kernel que ya lo trae es desperdicio de MB y rebuild en cada update.
Debian 12+ y Ubuntu 22.04+
sudo apt update
sudo apt install -y wireguard wireguard-tools qrencode
# Verificar versión instalada
wg --version
# wireguard-tools v1.0.20260223 - esperado a oct 2026
uname -r
# 6.1.x o superior = módulo integrado, no necesita DKMS
qrencode lo necesitas después para generar el QR que escaneás desde el móvil. Si la versión de wg --version muestra algo más viejo que 1.0.20230223, agrega el PPA wireguard/wireguard o los backports de Debian. En Debian 12 bookworm-backports el paquete siempre está al día.
RHEL 9+, Rocky Linux 9+, AlmaLinux 9+
sudo dnf install -y epel-release elrepo-release
sudo dnf install -y kmod-wireguard wireguard-tools qrencode
sudo modprobe wireguard
lsmod | grep wireguard
En RHEL family el módulo viene en kmod-wireguard porque Red Hat no upstream-ea el módulo al kernel hasta que la RHEL minor lo integre (RHEL 9.4+ ya lo trae built-in). Si modprobe falla, falta el paquete kernel-devel-$(uname -r); instala ese y reintentá.
Fedora 41+ y Arch
# Fedora
sudo dnf install -y wireguard-tools qrencode
# Arch
sudo pacman -S wireguard-tools qrencode
En Fedora y Arch el módulo viene integrado al kernel stock, no necesitas nada extra. Después de instalar, Verifica que todo está:
# Debe listar el módulo (incluso si está built-in)
modinfo wireguard 2>&1 | grep -E '^(filename|version)'
# wg debe existir y responder
which wg wg-quick
Generar claves del servidor y de cada cliente
WireGuard usa criptografía asimétrica Curve25519. Cada peer (servidor y cada cliente) tiene un par clave privada/pública: la privada es la identidad criptográfica y nunca sale del equipo, la pública se comparte para que el otro peer te pueda mandar mensajes cifrados. El umask 077 previo es crítico: hace que cualquier archivo creado en esa sesión tenga permisos 600. Sin esto, las claves quedan legibles por todo el sistema.
umask 077
mkdir -p /etc/wireguard
cd /etc/wireguard
# Par de claves del SERVIDOR
wg genkey | tee server_private.key | wg pubkey > server_public.key
chmod 600 server_private.key server_public.key
ls -la server_private.key
# -rw------- 1 root root ... server_private.key
Para cada cliente, generas un par en el servidor (la clave privada del cliente va en el archivo .conf que después le pasás al cliente, y la pública va en la sección [Peer] del servidor). El patrón wg genkey | tee private | wg pubkey > public aprovecha la pipe: tee graba la privada y la pasa por stdin a wg pubkey, que deriva la pública de la privada sin tocar el disco intermedio.
# Generar claves para el cliente 'laptop'
wg genkey | tee /etc/wireguard/clients/laptop_private.key | wg pubkey > /etc/wireguard/clients/laptop_public.key
chmod 600 /etc/wireguard/clients/laptop_private.key
# La privada del cliente va al .conf del cliente; la pública queda en el servidor
Para cinco clientes tienes cinco pares de claves. Cuando agregás un sexto cliente, generas un sexto par y agregás su pública a la sección [Peer] del servidor. La privada del cliente NUNCA debe quedar en el servidor más allá del momento en que la exportás al archivo .conf que se lo entregás.
Configurar el servidor (wg0.conf)
El archivo /etc/wireguard/wg0.conf tiene una sección [Interface] (la identidad del propio servidor) y N secciones [Peer] (uno por cliente). El orden de los campos no importa, los nombres son case-sensitive. Acá va un servidor para 3 clientes:
# /etc/wireguard/wg0.conf
[Interface]
# Clave privada del SERVIDOR (la generaste arriba)
PrivateKey = <CONTENIDO_DE_server_private.key>
# IP del servidor dentro del túnel
Address = 10.0.0.1/24
# Puerto UDP de escucha
ListenPort = 51820
# NAT para que los clientes salgan a internet por este servidor
# Reemplaza 'eth0' por tu interfaz real: ip route | grep default
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -D FORWARD -o wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
# DNS que se va a inyectar a los clientes (si el server corre Pi-hole, etc)
# DNS = 10.0.0.1, 1.1.1.1
# Cliente 1: laptop
[Peer]
PublicKey = <laptop_public.key>
PresharedKey = <claves_preshared_generadas_abajo>
AllowedIPs = 10.0.0.2/32
# Cliente 2: homelab
[Peer]
PublicKey = <homelab_public.key>
PresharedKey = <claves_preshared_generadas_abajo>
AllowedIPs = 10.0.0.3/32
# Cliente 3: celular
[Peer]
PublicKey = <celular_public.key>
PresharedKey = <claves_preshared_generadas_abajo>
AllowedIPs = 10.0.0.4/32
# PersistentKeepalive para mantener la conexión viva detrás de NAT
# (los móviles están detrás de CGNAT y necesitan mandar paquetes periódicos)
PersistentKeepalive = 25
El PresharedKey es una clave simétrica adicional que se mezcla con la clave pública en cada handshake. Aporta post-quantum resistance ligero (clásico + cuántico opcional) y previene un ataque de MitM activo donde un atacante tiene la clave privada de Curve25519 pero no la preshared. Generala con wg genpsk y distribuyala por canal seguro (1Password, bitwarden). Si no quieres usarla, deja el campo comentado y WireGuard igual funciona con seguridad post-quantum opcional pero menos robusta.
wg genpsk | tee /etc/wireguard/clients/laptop_preshared.key
chmod 600 /etc/wireguard/clients/laptop_preshared.key
# Pega ese valor en PresharedKey del peer correspondiente
AllowedIPs en el peer del servidor es la lista de IPs que ese cliente puede rutear. Si vas a hacer split-tunnel y solo quieres que el cliente acceda a tu red VPN (10.0.0.0/24) y a tu LAN (192.168.1.0/24), esa es la lista. Si vas a hacer full-tunnel, ponés 0.0.0.0/0, ::/0 y el servidor hace NAT de todo el tráfico del cliente. PersistentKeepalive = 25 es importante para clientes detrás de NAT (móviles, IoT): manda un paquete keep-alive cada 25 segundos para que el NAT upstream no expire la traducción.
Habilitar IP forwarding y reglas de firewall
Sin net.ipv4.ip_forward=1, el kernel descarta cualquier paquete que no sea para sí mismo. Para que el servidor VPN pueda reenviar tráfico entre wg0 (la interfaz WireGuard) y eth0 (la interfaz pública), el forwarding tiene que estar activo. Esto se configura con sysctl, no con iptables (son capas distintas).
echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.d/99-wireguard.conf
# IPv6 si vas a enrutar IPv6
echo "net.ipv6.conf.all.forwarding=1" | sudo tee -a /etc/sysctl.d/99-wireguard.conf
sudo sysctl -p /etc/sysctl.d/99-wireguard.conf
# Verificar
cat /proc/sys/net/ipv4/ip_forward
# 1 = correcto
Las reglas de NAT ya están en PostUp/PostDown de wg0.conf, así que wg-quick las aplica automáticamente cuando levanta la interfaz. Verifica que tu interfaz pública es eth0 con ip -o -4 route show to default | awk '{print $5}': en Hetzner/DigitalOcean/OVH es eth0, en Raspberry Pi con USB ethernet puede ser eth1, en Proxmox VE es vmbr0 o ens18. Cambiá el PostUp/PostDown con la interfaz correcta antes de levantar, sino los clientes pueden handshake-ar pero no salen a internet.
Si prefieres nftables sobre iptables (recomendado en distros modernas, Fedora 39+, Debian 12+), la regla equivalente es:
sudo nft add table inet filter
sudo nft add chain inet filter forward '{ type filter hook forward priority 0; policy accept; }'
sudo nft add table inet nat
sudo nft add chain inet nat postrouting '{ type nat hook postrouting priority srcnat; }'
sudo nft add rule inet nat postrouting oifname "eth0" masquerade
Si tu server tiene UFW o firewalld por delante, abre el puerto UDP antes de levantar la interfaz:
# UFW (Debian/Ubuntu)
sudo ufw allow 51820/udp
sudo ufw reload
# firewalld (RHEL/Fedora)
sudo firewall-cmd --permanent --add-port=51820/udp
sudo firewall-cmd --reload
# nftables standalone
sudo nft add rule inet filter input udp dport 51820 accept
Si tu servidor está detrás de un cloud firewall (AWS Security Group, GCP firewall, Hetzner firewall panel), tienes que abrir el puerto UDP también ahí. Son firewalls separados, no se heredan.
Arrancar WireGuard y verificar con wg show
El patrón canónico es usar [email protected], un template unit de systemd: el @ indica que el nombre de la interfaz (wg0) se pasa como parámetro. systemd instancia el unit como [email protected], lee /etc/wireguard/wg0.conf, levanta la interfaz, configura IPs, rutas, y aplica los PostUp/PostDown.
# Levantar y habilitar auto-arranque en boot
sudo systemctl enable --now wg-quick@wg0
# Verificar estado
sudo systemctl status wg-quick@wg0
sudo wg show
La salida de wg show tiene que verse así cuando funciona:
interface: wg0
public key: <server_public.key>
private key: (hidden)
listening port: 51820
peer: <laptop_public.key>
preshared key: (hidden)
allowed ips: 10.0.0.2/32
peer: <homelab_public.key>
...
Si los peers aparecen pero latest handshake nunca aparece, el handshake no se completó. Las tres causas más comunes:
- El firewall upstream bloquea UDP 51820 (Verifica con
nc -uvz <server-ip> 51820desde el cliente). - El
Endpointen el cliente apunta a una IP o dominio incorrecto. - Las claves pública/privada están mezcladas (peer’s PublicKey en el server no corresponde a la privada del cliente).
Cuando el handshake se completa y el cliente quiere tráfico, ves latest handshake: 12 seconds ago y transfer: 1.4 KiB received, 892 B sent. El latest handshake se renueva cada 2 minutos mientras hay tráfico; si pasan más de 2 minutos sin renovarse, la sesión está muerta.
Generar archivos .conf y QR para los clientes
Para cada cliente necesitas un archivo .conf con la clave privada del cliente, la pública del servidor, el endpoint del servidor, y el AllowedIPs del lado del cliente. Para los móviles, el patrón más cómodo es generar un QR que escaneás desde la app de WireGuard (disponible para iOS y Android).
# Generar el .conf para el cliente 'laptop'
cat > /etc/wireguard/clients/laptop.conf <<EOF
[Interface]
PrivateKey = <CONTENIDO_DE_laptop_private.key>
Address = 10.0.0.2/24
DNS = 10.0.0.1, 1.1.1.1
[Peer]
PublicKey = <CONTENIDO_DE_server_public.key>
PresharedKey = <CONTENIDO_DE_laptop_preshared.key>
Endpoint = vpn.tudominio.com:51820
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25
EOF
chmod 600 /etc/wireguard/clients/laptop.conf
# Generar el QR para el celular
qrencode -t ansiutf8 < /etc/wireguard/clients/celular.conf
El AllowedIPs del lado del cliente es la inversa del servidor: lista qué tráfico del cliente va a entrar al túnel. 0.0.0.0/0, ::/0 es full-tunnel (todo el tráfico del cliente pasa por la VPN). Si quieres split-tunnel y solo el tráfico hacia tu red privada va por VPN, cambia a AllowedIPs = 10.0.0.0/24, 192.168.1.0/24.
Para entregar el archivo al cliente de forma segura: NO lo mandes por correo plano (la clave privada queda en logs de mail server, backups de Gmail, etc). usa un canal cifrado: 1Password shared vault, Magic Wormhole, age-crypted file transfer, o copiar el contenido por Signal. El QR es lo más práctico para el celular: lo generas en una terminal TTY local (qrencode -t ansiutf8 < celular.conf), lo escaneás con la app, y el archivo nunca toca la red.
Hardening del servidor
Una vez que el túnel funciona, hay cinco cosas que endurecen el servidor sin esfuerzo:
1. Permisos estrictos en todo /etc/wireguard/
sudo chown -R root:root /etc/wireguard
sudo chmod 700 /etc/wireguard
sudo chmod 600 /etc/wireguard/*.key /etc/wireguard/clients/*.key 2>/dev/null
sudo chmod 600 /etc/wireguard/wg0.conf
find /etc/wireguard -type d -exec chmod 700 {} ;
2. Limitar quién puede leer la config vía systemd. wg-quick usa un helper setuid que necesita leer la private key del server. Si tu distro tiene cap_net_admin en el binary, ya está. Verifica:
getcap /usr/bin/wg
# /usr/bin/wg cap_net_admin,cap_net_bind_service+ep
ls -la /usr/bin/wg-quick
3. Fail2ban sobre SSH (no sobre WireGuard directamente, pero asociado). WireGuard no tiene superficie de ataque autenticable (las claves son el único auth), pero si el server SSH está abierto al público, fail2ban sobre SSH es obligatorio. Hay bans por intento de login cada 2-3 segundos desde IPs aleatorias:
sudo apt install fail2ban
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd
4. Logrotate para wg show outputs automatizados. Si tienes un script que exporta métricas cada minuto vía wg show wg0 latest-handshakes, asegurate que el log donde las guarda rota diario con logrotate, sino te come el disco en una semana.
5. Monitoreo de handshakes con un cron simple. Los handshakes deberían renovarse cada 2 minutos mientras hay tráfico activo. Si un peer deja de renovar handshake por más de 5 minutos, algo se rompió (cliente apagado, NAT upstream expiró, UDP filtrado por un cambio de firewall). Un script simple te avisa:
#!/bin/bash
# /usr/local/bin/wg-monitor.sh
# Mandar alerta si un peer no renovó handshake en los últimos 3 minutos
THRESHOLD=180
NOW=$(date +%s)
wg show wg0 latest-handshakes | while read pubkey ts; do
if [ -z "$ts" ] || [ "$ts" = "0" ]; then
echo "ALERTA: peer $pubkey nunca hizo handshake"
continue
fi
AGE=$((NOW - ts))
if [ "$AGE" -gt "$THRESHOLD" ]; then
echo "ALERTA: peer $pubkey sin handshake hace ${AGE}s"
fi
done
Rotación de claves y monitoreo a largo plazo
WireGuard no tiene un mecanismo automático de rotación de claves. Las claves privada/pública son válidas mientras tú quieras: no expiran, no hay handshake de rekey automático. La rotación es operación manual, y la buena práctica es rotar las claves cada 6-12 meses, o inmediatamente si tienes sospecha de compromiso.
El procedimiento es directo: generas un par nuevo para el cliente, agregás el nuevo peer en el server con wg set wg0 peer <nueva_pubkey> preshared-key <file:///path/preshared> allowed-ips 10.0.0.2/32, distribuís el nuevo .conf al cliente, verificas que la nueva conexión funciona, y recién entonces removés el peer viejo con wg set wg0 peer <vieja_pubkey> remove. El patrón add-then-remove evita downtime: durante la transición el cliente puede tener ambas configs y entrar por cualquiera.
Para monitorear la salud del túnel a largo plazo, los tres comandos que más uso son:
# Estado actual de peers (handshake + última conexión + transfer acumulado)
sudo wg show
# Transfer por peer en formato JSON (para ingestar en Prometheus, etc)
sudo wg show wg0 transfer
# Solo los peers que tienen handshake activo ahora
sudo wg show wg0 latest-handshakes
El transfer acumulado es útil para detectar peers con consumo anómalo (un cliente comprometido puede empezar a usar el túnel como proxy). Si tu server tiene 5 laptops pero un peer transfiere 50 GB/día, mira el cliente.
Troubleshooting sistemático
Los seis problemas que más cuestan tiempo, en orden de frecuencia con los que aparecen en mi setup:
1. “Handshake does not complete” en el cliente. UDP 51820 está filtrado upstream, o el endpoint es incorrecto. nc -uvz <server-ip> 51820 desde el cliente: si retorna open, UDP llega; si retorna timeout, hay firewall bloqueando. Solución: cambiar el puerto, abrir en el firewall del cloud provider, o usar Tailscale si el firewall corporativo bloquea todo UDP fuera de 443.
2. Cliente se conecta pero no llega a internet. cat /proc/sys/net/ipv4/ip_forward en el server retorna 0, o la regla de NAT en PostUp apunta a una interfaz equivocada. Solución: sysctl -w net.ipv4.ip_forward=1 y Verifica con ip route | grep default que la interfaz pública es la correcta.
3. DNS se pierde al conectar al túnel. El cliente tiene DNS = 10.0.0.1 pero el server no resuelve DNS (no corre Pi-hole, unbound, dnsmasq). Solución: cambiar el DNS en el cliente a 1.1.1.1, 9.9.9.9 (DNS over HTTPS primero si tu server lo soporta), o instalar un resolver local en el server.
4. AllowedIPs superpuesta. Dos peers tienen AllowedIPs = 10.0.0.5/32, o un peer tiene 0.0.0.0/0 en el server cuando solo debería tener 10.0.0.X/32. WireGuard acepta la config pero los paquetes se enrutan al peer equivocado. Solución: cada peer en el server con AllowedIPs ÚNICA de su IP /32 dentro del rango VPN.
5. Claves con permisos 644. wg-quick rechaza arrancar si la private key del server es legible por otros usuarios. Solución: chmod 600 /etc/wireguard/server_private.key y verificar que ls -la muestra -rw-------.
6. systemd tira la interfaz al reiniciar. El unit [email protected] no quedó habilitado. systemctl enable wg-quick@wg0 y Verifica con systemctl is-enabled wg-quick@wg0 que retorna enabled. Si retorna static o disabled, no arranca en boot.
Para diagnóstico más profundo, journalctl -u wg-quick@wg0 -f muestra los logs en vivo cuando levantás la interfaz, y tcpdump -i wg0 -n te muestra los paquetes cifrados (no puedes leer el contenido, pero sí ver que hay tráfico y cuánto). Si ves paquetes en wg0 pero el cliente reporta 0 bytes received, la MTU está mal: WireGuard por default usa 1420 bytes, pero algunas ISPs tienen MTU de 1400 o inferior, y el reensamblado falla silenciosamente. Baja a MTU = 1280 en el [Interface] del server y prueba.
Preguntas frecuentes
¿WireGuard necesita IPv6 para funcionar?
No. WireGuard funciona perfecto con solo IPv4 en el túnel, aunque las herramientas (wg, wg-quick) soportan tanto IPv4 como IPv6. Si quieres enrutar tráfico IPv6 a través de la VPN, agrega direcciones fc00::1/64 en [Interface] Address y habilita net.ipv6.conf.all.forwarding=1. Sin IPv6 en el túnel, todo el tráfico IPv6 del cliente sale por su interfaz física normal, no por la VPN.
¿Puedo tener varios rangos de IP en el mismo servidor WireGuard?
Sí, pero no en la misma interfaz. Cada interfaz wg0, wg1, wg2 tiene su propio rango. El caso de uso típico: wg0 para road warriors en 10.0.0.0/24, wg1 para site-to-site en 10.1.0.0/24. Para levantar wg1 con la misma config: copia wg0.conf a wg1.conf, cambia el rango y los peers, y systemctl enable --now wg-quick@wg1. Las dos interfaces coexisten sin conflicto.
¿Cómo migro desde OpenVPN sin downtime?
Opera ambos en paralelo durante 2-4 semanas. Clientes OpenVPN siguen conectándose como siempre. Los clientes nuevos van a WireGuard. Cuando todos los críticos estén en WireGuard, apagas OpenVPN. Para no romper la config de los clientes viejos que quedan migrando, exporta sus claves WireGuard con un script que reutilice el common name del certificado OpenVPN como nombre del peer en wg0.conf.
¿Qué pasa si el servidor se reinicia mientras tengo clientes conectados?
Los clientes detectan la caída en ~30 segundos (timeout del último handshake) y siguen intentando reconectar cada 25 segundos con PersistentKeepalive. Cuando el server vuelve, el handshake automático se completa y el túnel sigue. No hay estado que perder del lado del cliente, la reconexión es stateless. Para reducir el tiempo de reconexión, baja PersistentKeepalive a 15 (más tráfico keep-alive, pero reconexión más rápida).
¿WireGuard es seguro para producción o solo para homelab?
WireGuard está en producción en Cloudflare (WARP), Tailscale, Mozilla VPN, IVPN, Proton VPN, y la mayoría de proveedores de VPS que ofrecen VPN gestionada. La criptografía (Curve25519, ChaCha20-Poly1305, BLAKE2s) es estándar moderna, y el código es lo suficientemente corto para que múltiples auditorías independientes lo hayan revisado. Para producción, agrega preshared keys por peer (resistencia post-quantum adicional), rota claves cada 6-12 meses, y monitorea handshakes con el script de la sección de hardening.
Lee también
- Configuración de WireGuard VPN Punto a Punto en Linux: Guía Definitiva
- WireGuard Hub-and-Spoke en Linux: cómo unir 3 o más nodos detrás de un servidor central (Guía 2026)
- WireGuard vs OpenVPN: comparativa 2026 y cuál elegir
- Configura PiVPN para Acceso Remoto: Guía Definitiva para Sysadmins Linux 2026
- Cómo configurar un firewall en Linux con nftables (reemplazo de iptables)
