# Publish a local server through a tunnel with PROXYSERVER() and PROXYCLIENT()

> Let a Total.js server with a public address forward requests to a program that only runs on a private machine, with a WebSocket tunnel that the private side opens.

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

`PROXY()` forwards a request to a server that the proxy can reach. A tunnel is for the opposite case: the program is on a laptop or behind a firewall, so nobody can connect to it, but it can connect out. `PROXYSERVER()` and `PROXYCLIENT()` make that with one WebSocket that the private side opens:

- `PROXYSERVER([endpoint], [socketendpoint], [logger])` runs on the public server. Every request below `endpoint` (default `/`) is sent through the tunnel; `socketendpoint` (default `/`) is the WebSocket address where the client connects. Use **different** addresses when the same application serves anything else: a proxy on `/` takes every request, also the ones of your own routes (it runs before them). `logger` is a function (default: prints with the date); pass `null` for none.
- `PROXYCLIENT(serverurl, port, [logger])` runs on the private side (in this example the address of the server is built with `CONF.$port`, the port of the application). `serverurl` is the address of the WebSocket of the server (`ws://` or `wss://`; `http` is changed to `ws`) and `port` is `3000` or `ip:3000`, the local program that receives the requests. It returns the WebSocket client.
- **One client at a time:** when a second client connects, the server closes it with the code `4001`. Without a client the answer of the server is `Not yet available.`.
- The local program receives the **whole path of the original request**, including the `endpoint` (`/tunnel/hello`), the headers of the visitor and an `x-proxy: Total.js` header, with `host` set to the local address.
- The WebSocket route has no authentication of its own: do not publish it without something in front of it that decides who can connect (the address is the secret, a `check` of your own, a firewall).

Here one application is both sides: a small local program on port 9511 (any program would do), the server on `/tunnel/` and the client that connects to the same 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 });
}
```
