# Publier un serveur local par un tunnel avec PROXYSERVER() et PROXYCLIENT()

> Laissez un serveur Total.js à adresse publique transmettre des requêtes à un programme qui ne tourne que sur une machine privée, grâce à un tunnel WebSocket que le côté privé ouvre.

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

`PROXY()` transmet une requête à un serveur que le proxy peut atteindre. Un tunnel sert au cas inverse : le programme est sur un portable ou derrière un pare-feu, personne ne peut donc s'y connecter, mais lui peut se connecter vers l'extérieur. `PROXYSERVER()` et `PROXYCLIENT()` le réalisent avec un seul WebSocket que le côté privé ouvre :

- `PROXYSERVER([endpoint], [socketendpoint], [logger])` s'exécute sur le serveur public. Chaque requête sous `endpoint` (par défaut `/`) passe par le tunnel ; `socketendpoint` (par défaut `/`) est l'adresse WebSocket où le client se connecte. Utilisez des adresses **différentes** quand la même application sert autre chose : un proxy sur `/` prend toutes les requêtes, y compris celles de vos propres routes (il s'exécute avant elles). `logger` est une fonction (par défaut : écrit avec la date) ; passez `null` pour aucun.
- `PROXYCLIENT(serverurl, port, [logger])` s'exécute du côté privé (dans cet exemple l'adresse du serveur est construite avec `CONF.$port`, le port de l'application). `serverurl` est l'adresse WebSocket du serveur (`ws://` ou `wss://` ; `http` est changé en `ws`) et `port` est `3000` ou `ip:3000`, le programme local qui reçoit les requêtes. Il renvoie le client WebSocket.
- **Un client à la fois :** quand un second client se connecte, le serveur le ferme avec le code `4001`. Sans client, la réponse du serveur est `Not yet available.`.
- Le programme local reçoit le **chemin complet de la requête d'origine**, y compris l'`endpoint` (`/tunnel/hello`), les en-têtes du visiteur et un en-tête `x-proxy: Total.js`, avec `host` défini à l'adresse locale.
- La route WebSocket n'a pas d'authentification propre : ne la publiez pas sans quelque chose devant elle qui décide qui peut se connecter (l'adresse est le secret, un `check` à vous, un pare-feu).

Ici une application est les deux côtés : un petit programme local sur le port 9511 (n'importe quel programme conviendrait), le serveur sur `/tunnel/` et le client qui se connecte à la même application.

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