๐Ÿ’พ Archived View for bbs.geminispace.org โ€บ s โ€บ Gemini โ€บ 3233 captured on 2023-09-28 at 17:41:39. Gemini links have been rewritten to link to archived content

View Raw

More Information

โฌ…๏ธ Previous capture (2023-09-08)

โžก๏ธ Next capture (2023-11-04)

๐Ÿšง View Differences

-=-=-=-=-=-=-

Reverse proxy for gemini vhosts

I'm looking into writing a reverse proxy server which supports Gemini. ideally I'd like it to work like an HTTP reverse proxy like nginx or caddy, where it directs requests to different backend servers depending on the hostname.

The problem is... is this even really possible, given that client certs are a thing? How can the proxy serve the connection long enough to figure out a hostname, and still proxy it to the backend server with the original TLS session intact. The proxy can't fake that it has the client's cert key, after all.

Posted in: s/Gemini

๐Ÿ‘ป mediocregopher

2023-07-18 ยท 2 months ago

22 Comments โ†“

๐Ÿš€ skyjake

The real client certificate of the requestor would only be available at the proxy. However, the proxy could generate a new, privately stored certificate of its own that represents each unique requestor, and make its reverse requests using those. So basically man-in-the-middling the connections. This should be generally fine if the generated certificates use the same subject/issuer fields, and these are your locally-run proxied services that only talk to the outside world via the proxy.

However, if the proxied service displays client certificate fingerprints, like many do, the user might be worried that they don't match the clientside fingerprints.

When it comes to the TLS sessions, the time it takes to do the reverse requests shouldn't be an issue. Clients will generally tolerate a delay of multiple seconds.

๐Ÿค– alexlehm

I have considered that a bit since I have a go-based gemini server and wanted to access another server running in java on another port, but i don't think this is feasible when actually accepting the connection on the proxy. a nginx style forwarding before the full tls protocol is done might be possible to forward different vhosts to different backends. this will not work for path-based rules (similar to mod_rewrite) unless the backend connection uses a different protocol and passes the client cert has as a header or environment var, that would be more something like fcgi, not actual gemini

๐Ÿ‘ป mediocregopher

MITM all connections would _technically_ work, but I think at that point I would just not support it. That would essentially tie the backend to the proxy permanently, if the backend does anything with client certs, which wouldn't work for my case.

But luckily, after a bit of research, it seems it's possible to do it transparently. Since the TLS Client Hello message is sent plaintext at the start of the message, the server should be able to read just that, parse it, then forward it and the rest of the connection to the correct backend.

โ€” https://jean.ribes.ovh/gemini-reverse-proxy-using-traefik/#navbar-end

If traefik can do it, I can do it.

๐Ÿค– alexlehm

I should say that a HTTPS reverse proxy would have the same problem if a client cert is used

๐Ÿš€ skyjake

Forwarding the connection does sound like a much better solution. It is beyond my level of expertise to evaluate whether it's a good idea, though... A reverse proxy that forwards TLS connections without modifying them seems like something that is pretty much protocol-agnostic?

๐Ÿ‘ป mediocregopher

An HTTPS reverse proxy _would_ have the same problem if client certs were used, but fortunately (for http proxies) http client certs aren't really a thing.

And @skyjake yeah, it's a pretty protocol agnostic solution, which I guess is why traefik supports it despite almost certainly not deliberately supporting gemini. But it also precludes modifying HTTP headers on requests and such (like adding X-Forwarded-For), which I guess is why it's not more common in http proxies.

โ˜•๏ธ mozz

Peaking the TLS SNI is the best way to go. The disadvantage is that if the client doesn't send the SNI, or if the SNI doesn't match the actual URL inside the gemini request, you're kind of screwed.

Also check out the PROXY protocol, which allows you to attach client information like the true IP address in the absence of having access to HTTP headers. I added support for this to jetforce although I'm not using it currently.

https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt

๐Ÿ™ norayr

hello, i am trying to understand, if we have such a solution now?

based on what i read (and hopefully understand) i would prefer a server that forwards requests to different ports depending on domain name. but without doing mitm, i guess it can just forward everything back and forth?

2023-07-21 ยท 2 months ago

๐Ÿ™ norayr

i as referred to this thread

โ€” here

๐Ÿค– alexlehm

@norayr the problem is that the proxy has to determine the hostname in the unencrypted part of the TLS protocol, which apparently works, but it unusual (the solution provided by relayd seems to work)

๐Ÿ Addison

โ€” => Here's an NGINX config that uses SNI to do what you're asking. Cheers

๐Ÿ™ norayr

relayd? hmmm... did anyone already configure some capsules like that? can i find some example configurations somewhere?

๐Ÿ™ norayr

omg let me see!

๐Ÿ‘ป mediocregopher

@norayr I'm not sure why relayd was brought up, but both the link about traefik that I posted earlier and the nginx config that Addison posted should be able to help

2023-07-22 ยท 2 months ago

๐Ÿค– alexlehm

@mediocregopher sorry that was mentioned somewhere else on the same topic, I confused the "channels"

๐Ÿ‘ป mediocregopher

To follow up: I wasn't able to do transparent TLS proxying in rust+tokio due to the tokio_rustls crate not supporting it, ended up implementing it myself

โ€” https://github.com/rustls/tokio-rustls/issues/6

2023-07-24 ยท 2 months ago

๐Ÿ™ norayr

thank you for sharing. i looked at your code and issue comments and tried to understand it all. it looks like you have made a significant effort with a relatively new to you language, thank you for that too.

let's see how it continues. we need a reverse tls proxy tool.

i perhaps would use such a tool with more enjoyment if i knew it is written in go, since i percieve it as more simple and modernistic language (from what we have in the mainstream) just like i perceive gemini to be simple and modernistic. but rust is fine.

2023-07-26 ยท 2 months ago

๐Ÿ‘ป mediocregopher

As someone who primarily writes go, I totally agree with you :) but the project I'm working on is in rust, to help me expand my skillset a bit. I think the same strategy I've employed here could be done in go even easier, using a TeeReader

2023-07-27 ยท 2 months ago

๐Ÿ™ norayr

oh so nice to hear it. well, let's see if they accept your changes, and if not then i am glad there is a go project you can contribute to.

๐Ÿ™ norayr

i am following the issue and i see you created another branch. waiting to get the solution, hopefully it'll compile for me, and configure several virtual hosts for gemini on my server.

then i would move everything possible to gemini, and proxy with kineto.

๐Ÿ‘ป mediocregopher

Some final closure on this thread, thanks for all the input everyone!

โ€” mediocregopher.com/posts/domani.gmi

2023-08-09 ยท 7 weeks ago

๐Ÿ™ norayr

so what happened in issue #6 of tokio-rustls? how did it end? did they accept your changes?

what is the solution if i want to do the same, i. e. host several of my gemini domains on one machine?

2023-08-10 ยท 7 weeks ago