# Publiceer een lokale server via een tunnel met PROXYSERVER() en PROXYCLIENT()

> Laat een Total.js-server met een openbaar adres verzoeken doorsturen naar een programma dat alleen op een privémachine draait, met een WebSocket-tunnel die de privékant opent.

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

`PROXY()` stuurt een verzoek door naar een server die de proxy kan bereiken. Een tunnel is voor het omgekeerde geval: het programma staat op een laptop of achter een firewall, zodat niemand ermee kan verbinden, maar het zelf wel naar buiten kan verbinden. `PROXYSERVER()` en `PROXYCLIENT()` doen dat met één WebSocket die de privékant opent:

- `PROXYSERVER([endpoint], [socketendpoint], [logger])` draait op de openbare server. Elk verzoek onder `endpoint` (standaard `/`) wordt door de tunnel gestuurd; `socketendpoint` (standaard `/`) is het WebSocket-adres waar de client verbindt. Gebruik **verschillende** adressen als dezelfde applicatie nog iets anders serveert: een proxy op `/` neemt elk verzoek, ook die van je eigen routes (hij draait ervoor). `logger` is een functie (standaard: print met de datum); geef `null` mee voor geen.
- `PROXYCLIENT(serverurl, port, [logger])` draait op de privékant (in dit voorbeeld wordt het adres van de server gebouwd met `CONF.$port`, de poort van de applicatie). `serverurl` is het WebSocket-adres van de server (`ws://` of `wss://`; `http` wordt `ws`) en `port` is `3000` of `ip:3000`, het lokale programma dat de verzoeken ontvangt. Het geeft de WebSocket-client terug.
- **Eén client tegelijk:** wanneer een tweede client verbindt, sluit de server hem met de code `4001`. Zonder client is het antwoord van de server `Not yet available.`.
- Het lokale programma ontvangt het **volledige pad van het oorspronkelijke verzoek**, inclusief het `endpoint` (`/tunnel/hello`), de headers van de bezoeker en een header `x-proxy: Total.js`, met `host` ingesteld op het lokale adres.
- De WebSocket-route heeft geen eigen authenticatie: publiceer hem niet zonder iets ervoor dat beslist wie mag verbinden (het adres als geheim, een eigen `check`, een firewall).

Hier is één applicatie beide kanten: een klein lokaal programma op poort 9511 (elk programma zou volstaan), de server op `/tunnel/` en de client die verbindt met dezelfde applicatie.

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