# Publique um servidor local através de um túnel com PROXYSERVER() e PROXYCLIENT()

> Deixe um servidor Total.js com endereço público reencaminhar pedidos para um programa que só corre numa máquina privada, com um túnel WebSocket que o lado privado abre.

Framework: total5
Product: Total.js 5 (total5@0.0.19)
Language: pt
Content-SHA256: 693534fca3fc911024bc4bbd2c0502c290c50de52c46e5dc6b087484cd8dbcdb
Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c
Sources: total5-installed@total5@0.0.19
Review: not-recorded

`PROXY()` reencaminha um pedido para um servidor a que o proxy consegue chegar. Um túnel é para o caso contrário: o programa está num portátil ou atrás de uma firewall, pelo que ninguém se consegue ligar a ele, mas ele consegue ligar-se para fora. `PROXYSERVER()` e `PROXYCLIENT()` conseguem-no com um único WebSocket que o lado privado abre:

- `PROXYSERVER([endpoint], [socketendpoint], [logger])` corre no servidor público. Cada pedido abaixo de `endpoint` (por omissão `/`) é enviado pelo túnel; `socketendpoint` (por omissão `/`) é o endereço WebSocket onde o cliente se liga. Use endereços **diferentes** quando a mesma aplicação serve mais alguma coisa: um proxy em `/` fica com todos os pedidos, também os das suas próprias rotas (corre antes delas). `logger` é uma função (por omissão: imprime com a data); passe `null` para nenhum.
- `PROXYCLIENT(serverurl, port, [logger])` corre no lado privado (neste exemplo o endereço do servidor é construído com `CONF.$port`, a porta da aplicação). `serverurl` é o endereço WebSocket do servidor (`ws://` ou `wss://`; `http` é mudado para `ws`) e `port` é `3000` ou `ip:3000`, o programa local que recebe os pedidos. Devolve o cliente WebSocket.
- **Um cliente de cada vez:** quando se liga um segundo cliente, o servidor fecha-o com o código `4001`. Sem cliente a resposta do servidor é `Not yet available.`.
- O programa local recebe o **caminho completo do pedido original**, incluindo o `endpoint` (`/tunnel/hello`), os cabeçalhos do visitante e um cabeçalho `x-proxy: Total.js`, com `host` definido para o endereço local.
- A rota WebSocket não tem autenticação própria: não a publique sem algo à frente que decida quem se pode ligar (o endereço como segredo, um `check` seu, uma firewall).

Aqui uma aplicação é os dois lados: um pequeno programa local na porta 9511 (qualquer programa serviria), o servidor em `/tunnel/` e o cliente que se liga à mesma aplicação.

```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 });
}
```
