Para dejar SSH solo dentro de WireGuard, levanta la interfaz wg0 con wg-quick, asigna a cada cliente una IP con AllowedIPs y limita el puerto 22 a esa red: con ListenAddress en sshd_config o con una regla de ufw que solo acepte TCP 22 entrando por wg0. Desde fuera, el servidor solo expone el puerto UDP de WireGuard.

Cómo cambia la exposición de un servidor SSH detrás de WireGuard

OpenSSH escucha por defecto en el puerto TCP 22 y, si no se indica otra cosa, en todas las interfaces, incluida la pública. Con WireGuard delante, el único puerto abierto a Internet es el UDP del túnel, y WireGuard no responde a paquetes que no estén firmados con una clave conocida, así que un escaneo no ve nada.

El esquema de este artículo usa la red 10.8.0.0/24: el servidor es 10.8.0.1 y el móvil o el portátil, 10.8.0.2. SSH solo acepta conexiones en 10.8.0.1 o solo desde la interfaz wg0. Hay dos formas de conseguirlo y se pueden combinar: atar sshd a la IP del túnel con ListenAddress o filtrar con ufw por interfaz.

Configurar WireGuard con wg-quick y AllowedIPs para SSH

wg-quick lee /etc/wireguard/wg0.conf, crea la interfaz, asigna la dirección y añade rutas para cada rango declarado en AllowedIPs. Primero se generan las claves con permisos restrictivos:

umask 077
wg genkey | tee servidor.key | wg pubkey > servidor.pub

Configuración del servidor:

# /etc/wireguard/wg0.conf (servidor)
[Interface]
Address = 10.8.0.1/24
ListenPort = 51820
PrivateKey = <clave privada del servidor>

[Peer]
# móvil
PublicKey = <clave pública del móvil>
AllowedIPs = 10.8.0.2/32

Configuración del cliente, con túnel dividido: solo el tráfico hacia 10.8.0.1 entra en la VPN y el resto sale por la conexión normal.

[Interface]
Address = 10.8.0.2/32
PrivateKey = <clave privada del móvil>

[Peer]
PublicKey = <clave pública del servidor>
Endpoint = servidor.example.com:51820
AllowedIPs = 10.8.0.1/32
PersistentKeepalive = 25

En el servidor, AllowedIPs funciona como lista de control: solo se aceptan paquetes de ese peer con origen 10.8.0.2. En el cliente decide qué destinos se enrutan por el túnel; 0.0.0.0/0 enviaría todo el tráfico. Para arrancar y dejarlo persistente:

sudo wg-quick up wg0
sudo systemctl enable --now wg-quick@wg0
sudo wg show

Los detalles del protocolo y del intercambio de claves están en el inicio rápido oficial de WireGuard.

Limitar SSH a wg0 con ListenAddress en sshd_config

La directiva ListenAddress hace que sshd solo abra el socket en la dirección indicada; el puerto 22 deja de existir en la IP pública, tanto en IPv4 como en IPv6.

# /etc/ssh/sshd_config
ListenAddress 10.8.0.1
PasswordAuthentication no

sudo sshd -t
sudo systemctl restart ssh   # sshd en otras distribuciones

El problema típico es el orden de arranque: si sshd inicia antes que wg0, la dirección no existe y falla con «Cannot assign requested address». Se resuelve con un override de systemd (sudo systemctl edit ssh) que añada [email protected] y [email protected] en [Unit]. En distribuciones que arrancan sshd mediante ssh.socket, la dirección de escucha la fija la unidad del socket, no sshd_config. La referencia completa está en el manual de sshd_config.

Limitar SSH a wg0 con ufw: reglas exactas por interfaz

Con ufw, sshd sigue escuchando en todas partes, pero el cortafuegos solo deja pasar TCP 22 si entra por wg0. No depende del orden de arranque y también cubre Mosh, que usa UDP en los puertos 60000-61000.

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 51820/udp
sudo ufw allow in on wg0 to any port 22 proto tcp
sudo ufw allow in on wg0 to any port 60000:61000 proto udp
sudo ufw delete allow OpenSSH
sudo ufw enable
sudo ufw status verbose

Aplica estas reglas desde una sesión ya abierta por el túnel y prueba una segunda conexión a 10.8.0.1 antes de cerrar la primera. La combinación más robusta es ufw por interfaz más ListenAddress: si una de las dos capas falla, la otra sigue cerrando el puerto.

SSH por WireGuard desde iOS y Android frente a escritorio

En el móvil, el túnel lo levanta la app oficial de WireGuard como perfil VPN del sistema, y el cliente SSH se conecta a 10.8.0.1 como a cualquier host. La app puede generar el par de claves en el dispositivo o importar un .conf mediante QR con qrencode -t ansiutf8 < cliente.conf.

Qué se mideiOS / AndroidEscritorio
Cliente del túnelApp oficial de WireGuard, perfil VPN del sistemawg-quick o app oficial
Importar configuraciónCódigo QR o archivo .confCopiar el .conf a /etc/wireguard
Cambio de wifi a datosMosh mantiene la sesión SSH vivaPoco frecuente; SSH plano suele bastar
Esc, Ctrl, Tab y flechasRequieren un teclado propio de la terminalTeclado físico
Clave privada SSHAlmacén seguro del sistema~/.ssh con permisos 700 y claves 600

En termi1, terminal SSH para móvil, la clave Ed25519 se genera en el propio teléfono y no sale del dispositivo; Mosh conserva la sesión al pasar de wifi a datos y tmux mantiene lo que dejaste corriendo. Si la conexión a 10.8.0.1 está etiquetada como producción, Production Guard retiene los comandos que borran o detienen algo antes de llegar al prompt. Si prefieres no gestionar claves de WireGuard a mano, una malla como red privada sin abrir puertos o Tailscale cumple el mismo papel.

4 errores al encerrar SSH dentro de WireGuard

  1. Cerrar el 22 público sin acceso de emergencia. Si el túnel cae, solo quedará la consola del proveedor; compruébala antes.
  2. Solapar AllowedIPs entre peers. Dos peers con el mismo rango hacen que el tráfico vaya al último declarado.
  3. Olvidar los puertos UDP de Mosh. Mosh arranca por SSH, pero sin 60000-61000 abiertos en wg0 la sesión no se establece.
  4. No validar sshd_config. Ejecuta sshd -t antes de reiniciar; un error de sintaxis deja el servicio parado.

Preguntas frecuentes

¿Basta con WireGuard sin cambiar la configuración de SSH?

WireGuard sin cambios en SSH no protege el puerto 22: sshd sigue escuchando en la IP pública y cualquiera puede intentar conectarse. Hace falta ListenAddress con la IP del túnel o una regla de ufw que solo acepte TCP 22 entrando por wg0.

¿Qué pongo en AllowedIPs del cliente para usar solo SSH?

AllowedIPs del cliente debe contener solo la IP del servidor en el túnel, por ejemplo 10.8.0.1/32. Así wg-quick enruta únicamente ese tráfico por la VPN y la navegación sale por la conexión normal. Usar 0.0.0.0/0 enviaría todo el tráfico por el túnel.

¿Funciona Mosh a través de WireGuard?

Mosh funciona a través de WireGuard si el servidor acepta UDP 60000-61000 en wg0. Mosh abre primero una conexión SSH para lanzar mosh-server y después usa UDP. No hace port forwarding ni X11 forwarding, así que esas funciones requieren SSH clásico.

¿Qué pasa si WireGuard cae y SSH solo escucha en wg0?

Si WireGuard cae con SSH limitado a wg0, no habrá acceso SSH desde Internet hasta que el túnel vuelva. Por eso conviene tener la consola web del proveedor, habilitar wg-quick@wg0 en el arranque y ordenar sshd después del túnel con systemd.