Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add HTTP/3 support #1531

Open
wants to merge 20 commits into
base: master
Choose a base branch
from
Open

Add HTTP/3 support #1531

wants to merge 20 commits into from

Conversation

strarsis
Copy link
Contributor

@strarsis strarsis commented Jul 29, 2024

This PR adds the necessary configuration for proper HTTP/3 support (by nginx) (with HTTP/1/HTTPS/2 co-existence).

  • Some additional SSL/QUIC/HTTP/3 tweaks, which are used in nginx documentation, forum threads (1; 2) are added to the configuration when HTTP/3 support is turned on.
  • The OS ansible-managed ferm firewall is also configured to allow inbound UDP/433 for QUIC (HTTP/3).
    The approach is also used in the previous PR for HTTPS (Conditionally add HTTPS inbound allow firewall rule #1530).
  • Repeating configuration is included as external files for readability and maintainability.
  • nginx requires one (and only one listen quic directive to have the reuseport option (only one listen quic directive can have the reuseport option). As the listen quic directive requires a certificate, the first WordPress site ("vhost") that has HTTPS enabled, has the reuseport option added to its listen quic directive.

Additional notes (some may be useful in the documentation):

  • HTTP/3 is based on QUIC which itself is based on UDP (combining TCP characteristics and TLS encryption).
  • HTTP/3 is already well supported by all current browsers.
  • Besides the OS firewall (that is configured by Trellis) there is often a hardware/cloud firewall in front of the server,
    of course it also needs to be configured for allowing inbound UDP/443 traffic for QUIC (HTTP/3) (example for Hetzner Cloud Firewall).
  • HTTP/3 requires an additional HTTP header to be sent for advertising the availability of QUIC/HTTP/3,
    without this HTTP header, HTTP/3 will not work, despite everything else being perfectly configured and running.
  • Port number 443 is actually not mandatory for HTTP/3 (to some degree, also depending on browser), but it is recommended to use the same port number 443 as for HTTPS (TCP), nginx then listens on 443/UDP in parallel to 443/TCP for HTTP/1/HTTPS/2.
  • In my experience, testing HTTP/3 requests...
    • worked best with the Chrome Developer Tools (Network tab, toggle Protocol column on).
    • curl/wget HTTP/3 support is not a given in current stable Ubuntu. I used a curl Docker image with HTTP/3 support.
    • Some online HTTP/3 testing tools do not always work and incorrectly report HTTP/3 as not being supported, despite all other clients and tools being able to use HTTP/3.

Useful resources

@strarsis
Copy link
Contributor Author

@swalkinshaw: Using nginx includes makes the configuration much readable now.

@strarsis
Copy link
Contributor Author

strarsis commented Aug 4, 2024

The SSL early data option allows for RTT-0 requests (zero round-trip time), however, it comes with security implications (possibility of replay attacks), the application layer (so the PHP WordPress app here) gets a HTTP Header Early-Data passed from the reverse proxy (nginx), and for risky operations (as authentication/login) the app has to terminate requests with HTTP 425 Too Early.
I was not able to find any occurrence of this logic in WordPress code or plugins or discussions about this, hence I commented out this optimization until it is deemed safe for WordPress applications.

@swalkinshaw
Copy link
Member

Mind rebasing @strarsis ? Looks good otherwise and all the notes/documentation is appreciated.

@strarsis
Copy link
Contributor Author

@swalkinshaw: Sure! I also have to test the HTTP/3 specific configuration a bit further.

@strarsis strarsis changed the title Add HTTP/3 support Add HTTP/3 support Aug 24, 2024
@strarsis
Copy link
Contributor Author

strarsis commented Aug 27, 2024

@swalkinshaw: Well, I "rebased" it somehow. If necessary, I create a new branch/PR.

So it turned out that a global listen for QUIC with reuseport is necessary for working QUIC responses.
For a QUIC listen is also a SSL certificate required, it does not matter which one.
So for providing such a SSL certificate, one of the sites have to be specified as the "default site".

@swalkinshaw
Copy link
Member

😓 wow they really don't make this easy. I'll try and think of another solution for the default site/SSL cert 🤔

@strarsis
Copy link
Contributor Author

strarsis commented Aug 28, 2024

another solution for the default site/SSL cert

That listen quic is only needed for reuseport (apparently required by the nginx worker processes for correctly responding to QUIC requests). With listen quic nginx requires a SSL cert and key, but that listen and SSL would not be used otherwise.

Working, confirmed alternatives:

  • Add reuseport to one (and only one) existing site listen quic directive. This appears to be the simplest way to do it. The site index could be used to render reuseport only for the first site.
  • Use a snakeoil cert (as the already installed one /etc/ssl/certs/ssl-cert-snakeoil.pem; /etc/ssl/private/ssl-cert-snakeoil.key) for the global quic listen directive with reuseport to satisfy the cert condition for a quic listen.

@strarsis
Copy link
Contributor Author

strarsis commented Aug 30, 2024

Edit: jinja namespaces probably do not scope beyond the iteration of ansible template loops, so a different approach is used.

Now simply the first site that uses HTTPS will have the reuseports option added to its quic listen directive.
For this a helper variable is added that contains all sites that use SSL (not the boolean one),
and then just the item key is compared to determine whether the current config in jinja is the one for the first HTTPS using site.

@strarsis
Copy link
Contributor Author

strarsis commented Aug 31, 2024

@swalkinshaw: Edit: After some real-world testing I noticed that some WordPress sites had redirect issues (on frontend) (ERR_TOO_MANY_REDIRECTS). I am not sure whether this has been caused by http/3. Still testing and observing the behavior with http/3 enabled. Possible related issue. This appears to be caused by the redirects, when HTTP/3 is advertised/used there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants