# Opublikuj lokalny serwer przez tunel za pomocą PROXYSERVER() i PROXYCLIENT()

> Pozwól serwerowi Total.js z publicznym adresem przekazywać żądania do programu, który działa tylko na prywatnej maszynie, przez tunel WebSocket otwierany przez stronę prywatną.

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

`PROXY()` przekazuje żądanie do serwera, do którego proxy może dotrzeć. Tunel jest na odwrotny przypadek: program jest na laptopie lub za zaporą, więc nikt nie może się z nim połączyć, ale on może połączyć się na zewnątrz. `PROXYSERVER()` i `PROXYCLIENT()` robią to jednym WebSocketem otwieranym przez stronę prywatną:

- `PROXYSERVER([endpoint], [socketendpoint], [logger])` działa na serwerze publicznym. Każde żądanie poniżej `endpoint` (domyślnie `/`) jest wysyłane przez tunel; `socketendpoint` (domyślnie `/`) to adres WebSocketu, z którym łączy się klient. Używaj **różnych** adresów, gdy ta sama aplikacja obsługuje coś jeszcze: proxy na `/` przejmuje każde żądanie, także do Twoich własnych tras (działa przed nimi). `logger` to funkcja (domyślnie: wypisuje z datą); przekaż `null`, jeśli ma go nie być.
- `PROXYCLIENT(serverurl, port, [logger])` działa po stronie prywatnej (w tym przykładzie adres serwera jest budowany z `CONF.$port`, portu aplikacji). `serverurl` to adres WebSocketu serwera (`ws://` lub `wss://`; `http` jest zamieniane na `ws`), a `port` to `3000` lub `ip:3000`, lokalny program otrzymujący żądania. Zwraca klienta WebSocket.
- **Jeden klient naraz:** gdy łączy się drugi klient, serwer zamyka go z kodem `4001`. Bez klienta odpowiedzią serwera jest `Not yet available.`.
- Lokalny program otrzymuje **pełną ścieżkę oryginalnego żądania**, razem z `endpoint` (`/tunnel/hello`), nagłówkami odwiedzającego i nagłówkiem `x-proxy: Total.js`, z `host` ustawionym na adres lokalny.
- Trasa WebSocket nie ma własnego uwierzytelniania: nie publikuj jej bez czegoś przed nią, co decyduje, kto może się połączyć (adres jako sekret, własny `check`, zapora).

Tutaj jedna aplikacja jest obiema stronami: mały lokalny program na porcie 9511 (wystarczy dowolny program), serwer na `/tunnel/` i klient łączący się z tą samą aplikacją.

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