← Blog

Alexis · 2026-09-29

VPN site-to-site con WireGuard: homelab a VPS

El homelab funciona con direcciones RFC1918 privadas detrás de un router doméstico. El VPS está en internet público con una IP estática. Conseguir que se comuniquen entre sí — de forma fiable, segura y sin exponer nada innecesariamente — es exactamente para lo que sirve una VPN site-to-site.

Uso WireGuard para esto. Es rápido, tiene una superficie de ataque mínima (aproximadamente 4.000 líneas de código frente a las ~100.000 de OpenVPN), y la configuración es lo suficientemente simple como para entenderla completamente. Sin autoridad certificadora, sin PKI compleja, solo pares de claves y rangos de IPs permitidas.

Qué consigue el túnel

Con el túnel en funcionamiento:

Arquitectura

flowchart TD
    classDef internet fill:#f9f9f9,stroke:#333,stroke-width:2px;
    classDef vps fill:#e1f5fe,stroke:#01579b,stroke-width:2px;
    classDef homelab fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px;
    classDef tunnel fill:#fff3e0,stroke:#ef6c00,stroke-width:2px;

    Internet([Internet])

    subgraph VPS [VPS — IP Pública]
        VPS_WG["WireGuard\n10.10.0.1/24"]
        VPS_NGINX["NGINX"]
        VPS_App["App Rust\nPuerto 9080"]
    end

    subgraph Homelab [Homelab — LAN Privada]
        HL_WG["WireGuard\n10.10.0.2/24"]
        Forgejo["Forgejo\n192.168.10.x"]
        Runner["Runner Forgejo"]
        Staging["Contenedor Staging"]
    end

    Internet -->|HTTPS| VPS_NGINX
    VPS_NGINX --> VPS_App
    VPS_WG <-->|UDP cifrado 51820| HL_WG
    Runner -->|despliegue vía túnel| VPS_App
    Runner --> Staging

    class Internet internet;
    class VPS_WG,VPS_NGINX,VPS_App vps;
    class HL_WG,Forgejo,Runner,Staging homelab;

Configuración del VPS

En el VPS, WireGuard escucha en el puerto UDP 51820. El VPS tiene una IP pública estática, por lo que es el endpoint estable al que se conecta el homelab:

# /etc/wireguard/wg0.conf — VPS
[Interface]
Address = 10.10.0.1/24
ListenPort = 51820
PrivateKey = <clave-privada-vps>

# Peer homelab
[Peer]
PublicKey = <clave-publica-homelab>
AllowedIPs = 10.10.0.2/32, 192.168.10.0/24

AllowedIPs en el lado del VPS incluye la dirección WireGuard del homelab (10.10.0.2) y la subred LAN del homelab (192.168.10.0/24). Esto indica al kernel del VPS que enrute los paquetes destinados a la LAN del homelab a través del túnel.

Habilitar el reenvío de IP en el VPS para que el tráfico pueda enrutarse:

echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf && sysctl -p

Configuración del homelab

El peer del homelab tiene una IP pública dinámica (conexión residencial), por lo que inicia la conexión al VPS y la mantiene con un keepalive:

# /etc/wireguard/wg0.conf — Homelab (pfSense o Linux)
[Interface]
Address = 10.10.0.2/24
PrivateKey = <clave-privada-homelab>

# Peer VPS
[Peer]
PublicKey = <clave-publica-vps>
Endpoint = <ip-publica-vps>:51820
AllowedIPs = 10.10.0.1/32
PersistentKeepalive = 25

PersistentKeepalive = 25 envía un paquete de handshake cada 25 segundos. Esto mantiene el túnel activo a través de NAT y routers domésticos que de otro modo descartarían las conexiones UDP inactivas.

Generación de claves

Genera pares de claves en cada lado — nunca transfieras claves privadas por la red:

# En cada máquina
wg genkey | tee privatekey | wg pubkey > publickey

Intercambia solo las claves públicas. Cada lado conserva su clave privada localmente.

Verificar el túnel

# En cualquier lado
wg show

# Comprobar conectividad
ping 10.10.0.1   # desde homelab → endpoint del túnel VPS
ping 192.168.10.5  # desde VPS → host del homelab

Un handshake exitoso muestra latest handshake en la salida de wg show. Si está ausente, verifica que el puerto UDP 51820 esté abierto en el firewall del VPS y que las claves públicas coincidan con lo configurado en cada peer.

Usar el túnel para CI/CD

El runner de Forgejo en el homelab despliega en el VPS a través del túnel. El script de despliegue se conecta via SSH a 10.10.0.1 (la dirección WireGuard del VPS) en lugar de la IP pública — el tráfico permanece dentro del túnel cifrado, y el puerto SSH del VPS no necesita ser públicamente accesible.

ssh -i /home/runner/.ssh/deploy_key [email protected] \
  "podman pull registry.home.internal/app:latest && \
   podman restart app"

Stack

WireGuard · pfSense · Linux · Podman · Forgejo CI