Go to file
_ b659d6b74f add "news" URL to server list page 2021-04-27 14:10:11 -05:00
assets update: add a few other assets from the logo 2020-12-18 18:10:00 +00:00
bare_minimum_crypto update: add bug 2021-02-18 19:08:31 +00:00
crates add "news" URL to server list page 2021-04-27 14:10:11 -05:00
docs 🚧 wip: can't remember what I was working on 2021-01-19 23:25:24 +00:00
handlebars add "news" URL to server list page 2021-04-27 14:10:11 -05:00
issues Update auth-route-YNQAQKJS.md 2021-03-22 09:58:23 -05:00
src ♻️ refactor: rename `RelayState` to `Relay` and privatize `load_templates` 2021-04-18 08:28:07 -05:00
tools/ptth_tail ⬆️ deps: upgrade everything to Tokio 1.2.0 2021-03-06 21:46:35 +00:00
.dockerignore 🐳 build: set up app package for ptth_relay Docker images 2021-02-20 18:34:57 +00:00
.gitattributes update: fix Linguist excludes 2021-01-20 20:31:36 -06:00
.gitconfig add "news" URL to server list page 2021-04-27 14:10:11 -05:00
.gitignore 🐳 build: set up app package for ptth_relay Docker images 2021-02-20 18:34:57 +00:00
.gitmodules update: better base64 lib 2021-01-17 10:16:57 -06:00
.rgignore Update todo 2020-11-06 18:49:57 +00:00
COPYING Add license and README 2020-10-27 13:59:03 +00:00
Cargo.lock 📝 docs: update README before publishing to crates.io 2021-04-18 12:56:36 -05:00
Cargo.toml 🚨 refactor: appease clippy 2021-04-03 15:23:03 +00:00
Dockerfile ⬆️ deps: upgrade everything to Tokio 1.2.0 2021-03-06 21:46:35 +00:00
README.md 📦 build: preparing to publish on crates.io 2021-01-20 21:22:37 -06:00
app_package_Dockerfile 🐳 build: set up app package for ptth_relay Docker images 2021-02-20 18:34:57 +00:00
build_and_minimize.bash 📦 build (ptth_relay): update ID of bottom layer that we minimize out 2020-12-12 05:23:23 +00:00
build_app_package.bash 🐛 bug: fix missing Git version 2021-02-20 21:34:19 +00:00
build_ptth_server.bash 📦 build: don't print rsync verbose stuff during build 2021-02-01 00:06:22 +00:00
readme_draft.md drafting readme 2021-03-21 19:10:24 +00:00
run_app_package.bash 🐳 build: set up app package for ptth_relay Docker images 2021-02-20 18:34:57 +00:00
run_docker_image.bash 💄 update: add dev mode and server Git version to server list 2020-12-13 03:00:45 +00:00
rust-toolchain ⬆️ deps: Update to Rust 1.50.0 2021-02-20 19:12:38 +00:00
todo.md 🐛 remove todo for symlink bug 2021-04-26 16:14:26 -05:00


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.


An extroverted HTTP server that makes outgoing connections through firewalls.


Client -> Firewall -> Server


Client -> Firewall -> Relay <- Firewall <- Server

The server can run behind a firewall, because it is actually a special HTTP client. The relay acts as a facade, so the client is still a normal HTTP client like Firefox, curl, or wget.



  • 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 = ""
file_server_root = "./data"


name = "my_server"
tripcode = "czpCob1t1T7IU9zIlYyoNRomyeN7pqKSg1R0EUPz6Pw="

name = "some_other_server"
tripcode = "su2wWbTyf5xih4yiCTfAzqDlASatV+0dI+UVKFBIsEI="


  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

If you only have pre-built binaries:

  • ./ptth_relay
  • ./ptth_server
  • firefox

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;


(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

  O ---------> O
               | H2
  O <--------- O
  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.


Client    Relay    Server

            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. 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.

How should I report bugs or request features?

For now, either email me (if you know me personally) or make a pull request to add an item to todo.md.


PTTH is licensed under the GNU AGPLv3

Copyright 2020 "Trish"