# Publica un servidor local a través de un túnel con PROXYSERVER() y PROXYCLIENT()

> Deja que un servidor Total.js con dirección pública reenvíe peticiones a un programa que solo funciona en una máquina privada, con un túnel WebSocket que abre el lado privado.

Framework: total5
Product: Total.js 5 (total5@0.0.19)
Language: es
Content-SHA256: 4edee9576ec0d853164b5f7a88cc402e5b9763bb738d251cb6b85dade573667f
Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c
Sources: total5-installed@total5@0.0.19
Review: not-recorded

`PROXY()` reenvía una petición a un servidor al que el proxy puede llegar. Un túnel es para el caso contrario: el programa está en un portátil o detrás de un cortafuegos, así que nadie puede conectarse a él, pero él sí puede conectarse hacia fuera. `PROXYSERVER()` y `PROXYCLIENT()` lo consiguen con un solo WebSocket que abre el lado privado:

- `PROXYSERVER([endpoint], [socketendpoint], [logger])` se ejecuta en el servidor público. Cada petición por debajo de `endpoint` (por defecto `/`) se envía por el túnel; `socketendpoint` (por defecto `/`) es la dirección WebSocket donde se conecta el cliente. Usa direcciones **distintas** cuando la misma aplicación sirve otras cosas: un proxy en `/` se lleva todas las peticiones, también las de tus propias rutas (se ejecuta antes que ellas). `logger` es una función (por defecto: imprime con la fecha); pasa `null` para ninguno.
- `PROXYCLIENT(serverurl, port, [logger])` se ejecuta en el lado privado (en este ejemplo la dirección del servidor se construye con `CONF.$port`, el puerto de la aplicación). `serverurl` es la dirección del WebSocket del servidor (`ws://` o `wss://`; `http` se cambia por `ws`) y `port` es `3000` o `ip:3000`, el programa local que recibe las peticiones. Devuelve el cliente WebSocket.
- **Un cliente a la vez:** cuando se conecta un segundo cliente, el servidor lo cierra con el código `4001`. Sin cliente la respuesta del servidor es `Not yet available.`.
- El programa local recibe la **ruta completa de la petición original**, incluido el `endpoint` (`/tunnel/hello`), las cabeceras del visitante y una cabecera `x-proxy: Total.js`, con `host` fijado a la dirección local.
- La ruta WebSocket no tiene autenticación propia: no la publiques sin algo delante que decida quién puede conectarse (la dirección es el secreto, un `check` propio, un cortafuegos).

Aquí una aplicación es los dos lados: un pequeño programa local en el puerto 9511 (cualquier programa serviría), el servidor en `/tunnel/` y el cliente que se conecta a la misma aplicación.

```js definitions/local.js
// The program that is "private": an ordinary HTTP server that only listens on the loopback address
require('http').createServer(function(req, res) {
	res.writeHead(200, { 'content-type': 'application/json' });
	res.end(JSON.stringify({ path: req.url, via: req.headers['x-proxy'] || null, host: req.headers.host }));
}).listen(9511, '127.0.0.1');
```

```js controllers/tunnel.js
exports.install = function() {
	ROUTE('GET /status/', status);
	ROUTE('POST /connect/', connect);
};

// The public side: /tunnel/* goes through the tunnel, the WebSocket of the client is /tunnel-socket/. No logger.
PROXYSERVER('/tunnel/', '/tunnel-socket/', null);

let client = null;

function connect($) {
	client = PROXYCLIENT('ws://127.0.0.1:' + CONF.$port + '/tunnel-socket/', '9511', null);
	$.json({ connecting: true });
}

function status($) {
	$.json({ connected: !!client });
}
```
