TCP and UDP Proxies
r3v3rs3 proxies more than HTTP. This guide publishes a PostgreSQL server over TCP and a DNS server over UDP, and then puts mutual TLS in front of the database so that only a client with a certificate connects.
A TCP or UDP proxy forwards bytes. It reads no request, so it has no virtual hosts, no routes, no path and no header rules.
Follow Getting Started first.
Step 1: Publish PostgreSQL over TCP
- Click Ports in the menu, then Add.
- Write
postgresin the name field, select the interface and the port5432, and select the protocol TCP. - Click Create and check the state Listening.
- Click Proxies, then Add, and select the protocol TCP / TCP over TLS.
- Select the
postgresport. - Under Upstream Server, write the address of the database in Host, for example
10.0.0.5, and5432in Port. - Click Create.
$ psql "postgresql://postgres:<password>@proxy.example.com:5432/postgres" -c 'select version();'
PostgreSQL 17.11 on aarch64-unknown-linux-musl, ...
r3v3rs3 stores the address as a multiaddr: /ip4/<address>/tcp/<port>, /ip6/<address>/tcp/<port> or /dns/<name>/tcp/<port>. With /dns, r3v3rs3 resolves the name for each connection.
A TCP port serves one TCP proxy at a time. A second TCP proxy on the same port is an error.
Step 2: Publish a DNS Server over UDP
- Add a port with the protocol UDP, for example on the port
53. - Add a proxy with the protocol UDP and select the port. Under Upstream Server, write
10.0.0.53in Host and53in Port.
$ dig +short @proxy.example.com example.com A
172.66.147.243
A UDP proxy opens one session for each client address, with its own socket to the upstream server. The session closes when no packet passes in either direction for Session Idle Timeout (Seconds), 60 seconds by default. You can also configure Maximum Datagram Size (Bytes) (default 65527 bytes). A port keeps at most 10,000 sessions and drops the packets of new clients when it is full.
Step 3: Add Mutual TLS
A TCP over TLS port terminates TLS and sends plain bytes to the upstream server. With client authentication, only a client with a certificate of your CA connects.
Create the certificates
- Click Certificates, then the Server Certs tab, then Self-sign.
- Write the host name of the proxy in the subject names, for example
db.example.com, and create it. r3v3rs3 also creates a CA certificate in the Root Certs tab. - Open the Client Certs tab, click Self-sign, select the certificate type Client Certificate and the CA of the step before, then create it.
- Download the client certificate with Download. The archive holds
chain.pemandkey.pem. Give both to the client. - Download the CA certificate in the Root Certs tab and save it as
ca.pem. The client checks the server certificate with it.
Bind the port
- Add a port with the protocol TCP over TLS, for example on the port
5433. The port5432of Step 1 already carries a TCP proxy. - Write the host name in Server Names. r3v3rs3 selects the server certificate from the SNI of the client.
- Select Required in Client Authentication.
- Select the CA certificate in Client CA Certificates. The system root certificates are not used.
- Create the proxy on this port, with the same upstream server as Step 1.
Test the port with openssl s_client:
$ openssl s_client -connect db.example.com:5433 -servername db.example.com \
-CAfile ca.pem -cert chain.pem -key key.pem
A client without -cert and -key gets no connection. The TLS library of the client names the alert.
Optional accepts a client without a certificate, and checks the certificate of a client that sends one. Off asks for none.
When the client authentication config becomes invalid, for example after somebody removes the root certificate, the port closes every connection and the port list shows TLS Error.
Step 4: Encrypt the Upstream Connection
Steps 1 and 3 send plain bytes to the database. To use TLS there too:
- Open the proxy and turn on Connect with TLS for the upstream server. Its address then ends with
/tls. - When the database asks for a client certificate, select one in Client Certificate. r3v3rs3 sends it to every TLS upstream server that asks for one.
[my-database]
protocol = "tcp"
client_cert = "a1b2c3d"
upstream_servers = [{ addr = "/dns/db.internal/tcp/5433/tls" }]
A client certificate that a proxy uses cannot be deleted. When it becomes invalid, a TCP proxy closes the connection instead of connecting without it.
Step 5: Add More Upstream Servers
A TCP proxy with several upstream servers balances the connections. A UDP proxy sends the packets of one session to one server.
- Load Balancing selects the algorithm, for example round robin or client IP hash.
- The health check removes a server that does not answer, and brings it back when it answers again. Max Fails and Check Interval (Seconds) set it.
- Circuit Breaker stops new connections to a server that keeps failing. When every server has an open circuit, the client connection closes.
Load Balancing and Health Checks describes the fields.
The Client Address
A TCP proxy hides the client address from the upstream server, because the connection comes from r3v3rs3.
- Turn on Send PROXY Protocol so that each upstream connection starts with the client address. Turn it on only when every upstream server reads that header, for example PostgreSQL behind a pooler that supports it.
- In the other direction, Receive PROXY Protocol on the port reads the address from a load balancer in front of r3v3rs3. A UDP port cannot do this.
What a TCP or UDP Proxy Does Not Have
- No virtual hosts and no routes. One port carries one TCP proxy, so the port number selects the service.
- No cache, no compression and no header rules. These need HTTP.
- No authentication and no access list. Use mutual TLS, an IP filter of your firewall, or the authentication of the service itself.
Next Steps
- Ports: every port type, the server names and the PROXY protocol.
- UDP Sessions: the session model and its limits.
- Upstream Client Certificates: mutual TLS towards the upstream server.