# Túneles SSH

Túnel SSH persistente entre dos VPS con autossh: un servicio del receptor queda en localhost del iniciador sin exponerse.

Fuente: https://ardumaker.com/docs/tuneles-ssh/

- Categoría: Servidores e infraestructura
- Estado: Disponible
- Requisitos: Dos VPS (de la misma empresa para el flujo automático); Ser miembro de la empresa con acceso a ambos VPS; Sistemas con systemd y un OpenSSH compatible (se consulta con `ver_funciones_vps`, función «Túneles SSH entre VPS»)
- Herramientas MCP (Solo leen): `ver_estado_receptor_tunel_vps`, `listar_claves_receptor_tunel_vps`, `ver_estado_iniciador_tunel_vps`, `listar_tuneles_vps`, `ver_tunel_vps`
- Herramientas MCP (Escriben o modifican): `configurar_receptor_tunel_vps`, `agregar_clave_receptor_tunel_vps`, `configurar_iniciador_tunel_vps`, `crear_tunel_vps`, `controlar_tunel_vps`
- Herramientas MCP (Destructivas): `configurar_tunel_entre_vps`, `eliminar_receptor_tunel_vps`, `eliminar_clave_receptor_tunel_vps`, `eliminar_iniciador_tunel_vps`, `eliminar_tunel_vps`

## ¿Qué permite hacer?

- Usar desde un VPS un servicio que escucha en otro (una base, una API interna) como si estuviera en `localhost`, sin publicarlo en internet.
- Armar todo en una sola llamada (`configurar_tunel_entre_vps`), o paso a paso.
- Autorizar o revocar las claves que pueden entrar al receptor.
- Arrancar, detener o reiniciar cada túnel, y ver su estado en vivo.

## ¿Cuándo conviene usarlo?

- Una app en un VPS necesita la base de datos que vive en otro.
- Separar una API interna de su frontend sin abrir puertos públicos del servicio.

## ¿Cómo funciona en ArduMaker?

Es un reenvío **local** (`ssh -L`) que corre en el **iniciador**: lo que escucha en `puerto_remoto` del receptor queda disponible en `localhost:puerto_local` dentro del iniciador. No funciona al revés y no expone nada a internet.

### Los pasos

1. **Receptor** (`configurar_receptor_tunel_vps`): crea un usuario dedicado al túnel, configura `sshd` para aceptar ese usuario en el puerto 2222 (sin terminal, sin X11, sin agente, solo reenvío TCP) y publica el 2222 con una redirección. Corre en segundo plano.
2. **Iniciador** (`configurar_iniciador_tunel_vps`): instala `autossh` y genera un par de claves ed25519. También en segundo plano.
3. **Clave**: la clave pública del iniciador se autoriza en el receptor (`agregar_clave_receptor_tunel_vps`).
4. **Túnel** (`crear_tunel_vps`): crea en el iniciador un servicio systemd `ardutunnel_<nombre>` que corre `autossh -L <local>:<destino>:<puerto>` contra el receptor, lo habilita y lo arranca.

`configurar_tunel_entre_vps` hace los cuatro pasos y además arranca el túnel. Espera a que cada rol termine de instalarse (hasta unos minutos); si uno no termina a tiempo, se detiene con `tunel_rol_instalando` y se puede retomar con `desde`. Un rol ya instalado no se reinstala, una clave ya autorizada se reusa y un túnel con ese nombre y puerto local ya creado se devuelve tal cual.

## ¿Qué cambia realmente?

### En el receptor

- Un usuario de túnel con sus claves autorizadas en un bloque propio de `authorized_keys`.
- Un archivo de configuración de `sshd` gestionado por ArduMaker que agrega el puerto 2222 con su bloque `Match LocalPort` (el 22 sigue declarado). No hay que editarlo a mano: se reescribe entero cada vez que cambia un rol.
- Una redirección pública hacia el 2222 del VPS.

### En el iniciador

- El paquete `autossh` y un par de claves ed25519 del usuario de túnel.
- Un servicio `ardutunnel_<nombre>.service` por túnel, con `Restart=always`, habilitado al inicio.
- Un `known_hosts` propio de los túneles: la primera clave del receptor queda fijada y, si después cambia, el túnel no conecta.

## Puertos y conexión

| Dato | Valor |
| --- | --- |
| Puerto del receptor en el VPS | 2222 |
| Puerto público | El `host_port` de la redirección al 2222 (`public_port`) |
| Host | El `dnsip` del receptor |
| Cadena de conexión | `<usuario>@<dnsip> -p <public_port>` |

```ini
ExecStart=/usr/bin/autossh -M 0 -N \
  -o "ServerAliveInterval=30" -o "ServerAliveCountMax=3" \
  -o "StrictHostKeyChecking=accept-new" -o "ExitOnForwardFailure=yes" \
  -L <puerto_local>:localhost:<puerto_remoto> \
  -i <clave_del_tunel> -p <public_port> <usuario>@<dnsip>
```

`ver_estado_receptor_tunel_vps` devuelve la cadena de conexión y un ejemplo de uso para conectar desde otra máquina con `ssh -N -L`.

## Esquema

**Un túnel entre dos VPS**

```text
App en el iniciador (localhost:<puerto_local>)
  ↓
autossh (servicio ardutunnel_<nombre>)
  ↓
Redirección del receptor (<dnsip>:<public_port> → 2222)
  ↓
sshd del receptor :2222 (solo el usuario de túnel, solo reenvío)
  ↓
Servicio del receptor (localhost:<puerto_remoto>)
```

## Resultado esperado

- `ver_tunel_vps` muestra el túnel con el estado en vivo de su servicio systemd.
- `listar_tuneles_vps` lista los túneles del iniciador; `ver_estado_iniciador_tunel_vps` trae su clave pública y la cantidad de túneles.
- Desde el iniciador, el servicio responde en `localhost:<puerto_local>`.

```bash
systemctl status ardutunnel_mi-base
nc -vz localhost 15432
```

## Errores y resolución

| Respuesta | Causa | Qué hacer |
| --- | --- | --- |
| 409 `tunel_rol_instalando` | Un rol todavía se está instalando | Volver a pedir; retoma desde ahí |
| `tunel_rol_fallido` | La instalación de un rol falló | Ver el estado del rol y reintentar |
| `tunel_mismo_vps` | Receptor e iniciador son el mismo VPS | Usar dos VPS distintos |
| 409 puerto local en uso | Otro túnel del iniciador ya usa ese `local_port` | Elegir otro puerto |
| 409 `Key already registered` | La clave ya está autorizada | Nada que hacer |
| El túnel no conecta | La clave del receptor cambió, o la clave del iniciador no está autorizada | Revisar `ver_logs_systemd_vps` del servicio `ardutunnel_<nombre>` |

> **PRECAUCION:** `eliminar_iniciador_tunel_vps` borra **todos** los túneles del VPS a la vez, y `eliminar_receptor_tunel_vps` quita el usuario de túnel y sus claves: los túneles que entraban dejan de funcionar. `controlar_tunel_vps` con `stop` corta lo que esté pasando por el túnel.

Si un paso del flujo falla, se deshace lo que se puede; los paquetes instalados quedan y se informan en `residuo` (reinstalar no cambia nada). El flujo acepta `idempotency_key` y `simular`.

## Relación con MCP

Sí, en los perfiles `/mcp` y `/mcp/vps`. Instalar un rol devuelve un `operacion_id`: `ver_operacion` dice cuándo está listo.

| Herramienta | Tipo |
| --- | --- |
| `configurar_tunel_entre_vps` | Escritura (flujo completo) |
| `ver_estado_receptor_tunel_vps`, `listar_claves_receptor_tunel_vps`, `ver_estado_iniciador_tunel_vps`, `listar_tuneles_vps`, `ver_tunel_vps` | Lectura |
| `configurar_receptor_tunel_vps`, `configurar_iniciador_tunel_vps`, `agregar_clave_receptor_tunel_vps`, `crear_tunel_vps` | Escritura |
| `controlar_tunel_vps` | Escritura (con `stop` corta el tráfico) |
| `eliminar_tunel_vps`, `eliminar_clave_receptor_tunel_vps`, `eliminar_receptor_tunel_vps`, `eliminar_iniciador_tunel_vps` | Destructiva |

Referencia en [/mcp/docs](https://ardumaker.com/mcp/docs) y ejemplos en [/mcp/tuneles](https://ardumaker.com/mcp/tuneles).

## Funciones relacionadas

- [Firewall y puertos](https://ardumaker.com/docs/firewall-y-puertos/)
- [Servicios systemd](https://ardumaker.com/docs/systemd/)
- [PostgreSQL](https://ardumaker.com/docs/postgresql/)
- [Servidores VPS](https://ardumaker.com/docs/vps/)
