232 lines
7.4 KiB
Markdown
232 lines
7.4 KiB
Markdown
![The PTTH logo, a green box sitting on a black conveyor belt. The box has an arrow pointing left, and the text "PTTH", in white. The conveyor belt has an arrow pointing right, in white.](assets/logo-128-pixel.png)
|
|
|
|
# PTTH
|
|
|
|
An HTTP server that can run behind a firewall by connecting out to a relay.
|
|
|
|
```
|
|
Outside the tunnel
|
|
+--------+ +------------+ +-------------+
|
|
| Client | >>> | PTTH relay | <<< | PTTH server |
|
|
+--------+ +------------+ +-------------+
|
|
|
|
Inside the tunnel
|
|
+--------+ -------------- +-------------+
|
|
| Client | >>> >>> >>> | Server |
|
|
+--------+ -------------- +-------------+
|
|
```
|
|
|
|
The server can run behind a firewall, because it is actually a special HTTP
|
|
client.
|
|
|
|
## Configuration
|
|
|
|
ptth_server:
|
|
|
|
- Copy ptth_server or ptth_server.exe onto the server
|
|
- Create ptth_server.toml in the server's working dir
|
|
- Add a human-readable name and a secret API key generated by diceware
|
|
- Run `ptth_server --print-tripcode` and copy the output into ptth_relay.toml
|
|
|
|
ptth_relay first-time config:
|
|
|
|
- Copy ptth_relay onto the server (A Dockerfile is provided with no guarantees)
|
|
- Create ptth_relay.toml in the relay's working dir
|
|
|
|
Example server config: (Won't run because the key is too weak)
|
|
|
|
```
|
|
name = "my_server"
|
|
api_key = "secretpassword"
|
|
relay_url = "http://127.0.0.1:4000"
|
|
file_server_root = "./data"
|
|
```
|
|
|
|
ptth_relay.toml:
|
|
|
|
```
|
|
[[servers]]
|
|
name = "my_server"
|
|
tripcode = "czpCob1t1T7IU9zIlYyoNRomyeN7pqKSg1R0EUPz6Pw="
|
|
|
|
[[servers]
|
|
name = "some_other_server"
|
|
tripcode = "su2wWbTyf5xih4yiCTfAzqDlASatV+0dI+UVKFBIsEI="
|
|
```
|
|
|
|
## Use
|
|
|
|
1. Start the relay
|
|
2. Start a server
|
|
3. Use a client to access a server through the relay
|
|
|
|
From the source code directory:
|
|
|
|
- `cargo run --bin ptth_relay`
|
|
- `cargo run --bin ptth_server`
|
|
- `firefox http://127.0.0.1:4000/servers/my_server/files/`
|
|
|
|
If you only have pre-built binaries:
|
|
|
|
- `./ptth_relay`
|
|
- `./ptth_server`
|
|
- `firefox http://127.0.0.1:4000/servers/my_server/files/`
|
|
|
|
To run the relay behind Nginx, these directives improve time-to-first-byte
|
|
when streaming:
|
|
|
|
```
|
|
client_max_body_size 0;
|
|
proxy_http_version 1.1;
|
|
proxy_request_buffering off;
|
|
proxy_buffering off;
|
|
```
|
|
|
|
## Glossary
|
|
|
|
(sorted alphabetically)
|
|
|
|
- **Backend API** - The HTTP API that ptth_server uses to establish the tunnel.
|
|
Noted in the code with the cookie "7ZSFUKGV".
|
|
- **Client** - Any client that connects to ptth_relay in order to reach a
|
|
destination server. Admins must terminate TLS between
|
|
ptth_relay and all clients.
|
|
- **Frontend** - The human-friendly, browser-friendly HTTP+HTML interface
|
|
that ptth_relay serves directly or relays from ptth_server.
|
|
This interface has no auth by default. Admins must provide their own auth
|
|
in front of ptth_relay. OAuth2 is recommended.
|
|
- **ptth_file_server** - A standalone file server. It uses the same code
|
|
as ptth_server, so production environments don't need it.
|
|
- **ptth_relay** or **Relay server** - The ptth_relay app. This must run on a server
|
|
that can accept incoming HTTP connections.
|
|
- **ptth_server** or **Destination server** - The ptth_server app. This should run behind
|
|
a firewall. It will connect out to the relay and accept incoming connections
|
|
through the PTTH tunnel.
|
|
- **Scraper API** - An optional HTTP API for scraper clients to access ptth_relay and
|
|
the destination servers using machine-friendly auth.
|
|
- **Tripcode** - The base64 hash of a server's private API key. When adding
|
|
a new server, the tripcode must be copied to ptth_relay.toml on the relay
|
|
server.
|
|
- **Tunnel** - The reverse HTTP tunnel between ptth_relay and ptth_server.
|
|
ptth_server connects out to ptth_relay, then ptth_relay forwards incoming
|
|
connections to ptth_server through the tunnel.
|
|
|
|
## Comparison with normal HTTP
|
|
|
|
Normal HTTP:
|
|
|
|
```
|
|
Client Server
|
|
|
|
H1
|
|
O ---------> O
|
|
| H2
|
|
O <--------- O
|
|
H3
|
|
```
|
|
|
|
1. The client connects to the server and sends a request
|
|
2. The server accepts the connection and processes the request
|
|
3. The server responds with a response
|
|
|
|
We'll call these steps "H1", "H2", and "H3" in the next section.
|
|
|
|
PTTH:
|
|
|
|
```
|
|
Client Relay Server
|
|
|
|
P1
|
|
O <----- O
|
|
P2/H1 |
|
|
O ------> O
|
|
| P3
|
|
O -----> O
|
|
| P4/H2
|
|
O <----- O
|
|
| P5
|
|
O <------ O
|
|
P6/H3 | P7
|
|
O -----> O
|
|
```
|
|
|
|
We'll call these steps "P1" through "P7".
|
|
|
|
1. The server makes a "listen" request to the relay,
|
|
punching out through the server's firewall.
|
|
The server and relay are now in a long-polling state with each other,
|
|
waiting for a client to make a request.
|
|
2. A client makes a request to the relay. (P2 == H1)
|
|
3. The relay packages the request and sends it as a response to the server,
|
|
completing the server's request in P1.
|
|
The client and relay are now in a long-polling state, waiting for the server
|
|
to respond.
|
|
4. The server processes the request. (P4 == H2)
|
|
5. The server packages its response in another request to the relay.
|
|
6. The relay unwraps the request and forwards it to the client. (P6 == H3)
|
|
7. When the full response body has been streamed through the relay and to the
|
|
client, the relay will respond to the server.
|
|
|
|
Every step of the normal HTTP process is inverted for the server:
|
|
|
|
- It must stay connected to the relay even when nothing is happening
|
|
- A request arrives packaged in a response
|
|
- A response is sent out packaged as a request
|
|
|
|
There are twice as many steps, and the per-connection and per-request overhead
|
|
is probably high. But once the connections are established, the only
|
|
overhead is that of using a relay, which is similar to many other file transfer
|
|
or remote desktop software.
|
|
|
|
## Comparison with similar software
|
|
|
|
PTTH is very similar to [PageKite](https://github.com/pagekite/PyPagekite).
|
|
PTTH's relay is equivalent to PageKite's front-end server, and PTTH's server
|
|
is equivalent to (I think) PageKite's backend.
|
|
|
|
WireGuard can also pierce firewalls, but it requires root permissions,
|
|
and the client must be a WireGuard node. PTTH allows any normal HTTP client
|
|
such as curl, Firefox, etc.
|
|
|
|
## Module overview
|
|
|
|
```
|
|
+------------+ +-------------+ +------------------+
|
|
| ptth_relay | | ptth_server | | ptth_file_server |
|
|
+------------+ +-------------+ +------------------+
|
|
| | | |
|
|
\ / \ /
|
|
V V V V
|
|
+------------+ +-------------+
|
|
| http_serde | | file_server |
|
|
+------------+ +-------------+
|
|
```
|
|
|
|
The top-level binaries are ptth_relay, ptth_server, and ptth_file_server.
|
|
|
|
ptth_relay should run on a well-known public server, behind an HTTPS proxy
|
|
such as Caddy, Nginx, or Apache.
|
|
|
|
ptth_file_server is a standalone HTTP file server, similar to Python2's
|
|
`-m SimpleHTTPServer` command, or Python3's `-m http.server`.
|
|
|
|
ptth_server and ptth_file_server use the `file_server` module. ptth_server
|
|
will connect out to a ptth_relay instance and serve files through the reverse
|
|
HTTP tunnel.
|
|
|
|
The `http_serde` module is shared by ptth_relay and ptth_server so that they
|
|
can communicate with each other easily.
|
|
|
|
## Why are GitHub issues disabled?
|
|
|
|
Because they are not part of Git.
|
|
|
|
For now, either email me (if you know me personally) or make a pull request to add an item to [todo.md](todo.md).
|
|
|
|
## License
|
|
|
|
PTTH is licensed under the
|
|
[GNU AGPLv3](https://www.gnu.org/licenses/agpl-3.0.html)
|
|
|
|
Copyright 2020 "Trish"
|