feat: New blog post

This commit is contained in:
PapaTutuWawa 2023-07-15 23:48:36 +02:00
parent 949563452b
commit 98cfbaf97c
3 changed files with 216 additions and 1 deletions

View File

@ -0,0 +1,125 @@
<!-- title: Running Prosody on Port 443 Behind traefik 2: Electric ALPN -->
<!-- description: In this blog post, I tell you how I changed my setup for proxying my XMPP server using traefik -->
<!-- render: yes -->
Hello everyone. Long time, no read.
In 2020, I published a post titled "[Running Prosody on Port 443 Behind traefik](https://blog.polynom.me/Running-Prosody-traefik.html)", where I described how I run my XMPP server
behind the "application proxy" [*traefik*](https://github.com/traefik/traefik).
I did this because I wanted to run my XMPP server *prosody* on port 443, so that the clients connected
to my server can bypass firewalls that only allow web traffic. While that approach worked,
over the last three years I changed my setup dramatically.
While migrating my old server from *Debian* to *NixOS*, I decided that I wanted a website
hosted at the same domain I host my XMPP server at. This, however, was not possible with
*traefik* back then because it only allowed the `HostSNI` rule, which differentiates TLS
connections using the sent *Server Name Indication*. This is a problem, because a connection
to `polynom.me` the website and `polynom.me` the XMPP server both result in the same SNI being
sent by a connecting client.
Some time later, I stumbled upon [*sslh*](https://github.com/yrutschle/sslh), which is a
tool similar to *traefik* in that it allows hosting multiple services on the same port, all
differentiated by the SNI **and** the ALPN set by the connecting client. ALPN, or *Application-Layer Protocol Negotiation*, is an extension
to TLS which allows a connecting client to advertise the protocol(s) it would like to use
inside the encrypted session [(source)](https://en.wikipedia.org/wiki/Application-Layer_Protocol_Negotiation). As such, I put
*sslh* in front of my *traefik* and told it to route XMPP traffic (identified with an ALPN
of `xmpp-client`) to my prosody server and everything else to my *traefik* server. While this
worked well, there were two issues:
1. I was not running *sslh* in its ["transparent mode"](https://github.com/yrutschle/sslh/blob/master/doc/config.md#transparent-proxy-support), which uses some fancy iptable rules to allow the services behind it to see a connecting client's real IP address instead of just `127.0.0.1`. However, this requires more setup to work. This is an issue for services which enforce rate limits, like *NextCloud* and *Akkoma*. If one of theses services gets hit by many requests, all the services see are requests from `127.0.0.1` and may thus rate limit (or ban) `127.0.0.1`, meaning that all - even legitimate - requests are rate limited. Additionally, I was not sure if I could just use this to route an incoming IPv6 request to `127.0.0.1`, which is an IPv4 address.
2. One day, as I was updating my server, I noticed that all my web services were responding very slowly. After some looking around, it turned out that *sslh* took about 5 seconds to route IPv6 requests, but not IPv4 requests. As I did not change anything (besides update the server), to this day I am not sure what happened.
Due to these two issues, I decided to revisit the idea I described in my old post.
## The Prosody Setup
On the prosody-side of things, I did not change a lot compared to the old post. I did, however,
migrate from the `legacy_ssl_*` options to the newer `c2s_direct_tls_*` options, which
[replace the former](https://hg.prosody.im/trunk/file/tip/doc/doap.xml#l758).
Thus, my prosody configuration regarding direct TLS connections now looks like this:
```lua
c2s_direct_tls_ports = { 5223 }
c2s_direct_tls_ssl = {
[5223] = {
key = "/etc/prosody/certs/polynom.me.key";
certificate = "/etc/prosody/certs/polynom.me.crt";
};
}
```
## The *Traefik* Setup
On *traefik*-side of things, only one thing really changed: Instead of just having a rule using
`HostSNI`, I now also require that the connection with the XMPP server advertises an ALPN
of `xmpp-client`, which is specified in the
[appropriate XMPP spec](https://xmpp.org/extensions/xep-0368.html). From my deployment
experience, all clients I tested (*Conversations*, *Blabber*, *Gajim*, *Dino*, *Monal*, [Moxxy](https://moxxy.org))
correctly set the ALPN when connecting via a direct TLS connection.
So my *traefik* configuration now looks something like this (Not really, because I let NixOS
generate the actual config, but it is very similar):
```yaml
tcp:
routers:
xmpps:
entrypoints:
- "https"
rule: "HostSNI(`polynom.me`) && ALPN(`xmpp-client`)"
service: prosody
tls:
passthrough: true
# [...]
services:
prosody:
loadBalancer:
servers:
- address: "127.0.0.1:5223"
http:
routers:
web-secure:
entrypoints:
- "https"
rule: "Host(`polynom.me`)"
service: webserver
tls:
```
The entrypoint `https` is just set to listen on `:443`. This way, I can route IPv4 and IPv6
requests. Also note the `passthrough: true` in the XMPP router's `tls` settings. If this is
not set to `true`, then *traefik* would terminate the connection's TLS session before passing
the data to the XMPP server.
However, this config has one really big issue: In order
to have the website hosted at `polynom.me` be served using TLS, I have to set the
router's `tls` attribute. The *traefik*
documentation says that "*If both HTTP routers and TCP routers listen to the
same entry points, the TCP routers will apply before the HTTP routers. If no matching route
is found for the TCP routers, then the HTTP routers will take over.*"
[(source)](https://doc.traefik.io/traefik/routing/routers/#general_1).
This, however, does not seem to be the case if a HTTP router (in my example with ```Host(`polynom.me`)```) and a TCP router (in my example with ```HostSNI(`polynom.me`)```) respond to the same
SNI **and** the HTTP router has its `tls` attribute set. In that case, the HTTP router appears
to be checked first and will complain, if the sent ALPN is not one of the
[HTTP ALPNs](https://developer.mozilla.org/en-US/docs/Glossary/ALPN), for example when
connecting using XMPP. As such we can connect to the HTTP server but not to the
XMPP server.
It appears to be an issue that [I am not alone with](https://github.com/traefik/traefik/issues/9922), but also
one that is not fixed. So I tried digging around in *traefik*'s code and tried a couple of
things. So for my setup to work, I have to apply [this patch](https://github.com/PapaTutuWawa/traefik/commit/36f0e3c805ca4e645f3313f667a6b3ff5e2fe4a9) to *traefik*. With that, the issue *appears*
to be gone, and I can access both my website and my XMPP server on the same domain and on the
same port. Do note that this patch is not upstreamed and may break things. For me, it
works. But I haven't run extensive tests or *traefik*'s integration and unit tests.
## Conclusion
This approach solves problem 2 fully and problem 1 partially. *Traefik* is able to route
the connections correctly with no delay, compared to *sslh*. It also provides my web services
with the connecting clients' IP addresses using HTTP headers. It does not, however, provide
my XMPP server with a connecting client's IP address. This could be solved with some clever
trickery, like telling *traefik* to use the [*PROXY* protocol](https://doc.traefik.io/traefik/routing/services/#proxy-protocol) when connecting to prosody,
and enabling the [`net_proxy`](https://modules.prosody.im/mod_net_proxy.html) module. However,
I have not yet tried such a setup, though I am very curious and may try that out.

View File

@ -0,0 +1,90 @@
-----BEGIN PGP MESSAGE-----
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
P208uOWxmfX/Bg==
=/2ew
-----END PGP MESSAGE-----

View File

@ -5,7 +5,7 @@
}:
stdenv.mkDerivation {
pname = "blog";
version = "20211128";
version = "20231507";
src = ../.;