Support for Wordpress HTTP 3 QUIC

I read this thread Will there be support for http3? - #12 by sahsanu, and I offer my config under WordPress. I have 3 sites, everything is fine and without errors. The check shows both in the console and online that http3 is supported. Perhaps someone will add something else. Thank you for your attention



server {
    listen      %ip%:%web_ssl_port% ssl http2;
    listen      %ip%:%web_ssl_port% quic reuseport;
    listen      [::]:%web_ssl_port% ssl http2;
    listen      [::]:%web_ssl_port% quic reuseport;

    server_name %domain_idn% %alias_idn%;
    root        %sdocroot%;
    index       index.php index.html index.htm;
    access_log  /var/log/nginx/domains/%domain%.log combined;
    access_log  /var/log/nginx/domains/%domain%.bytes bytes;
    error_log   /var/log/nginx/domains/%domain%.error.log error;

    ssl_certificate     %ssl_pem%;
    ssl_certificate_key %ssl_key%;
    ssl_stapling        on;
    ssl_stapling_verify on;

    # TLS 1.3 0-RTT anti-replay
    if ($anti_replay = 307) { return 307 https://$host$request_uri; }
    if ($anti_replay = 425) { return 425; }

    include %home%/%user%/conf/web/%domain%/nginx.hsts.conf*;

    # HTTP/3 specific settings
    ssl_protocols TLSv1.3;
    ssl_prefer_server_ciphers off;

    add_header Alt-Svc 'h3-23=":%web_ssl_port%"; ma=86400'; # Advertise that HTTP/3 is available
    add_header QUIC-Status $quic;

    location = /favicon.ico {
        log_not_found off;
        access_log off;
    }

    location = /robots.txt {
        try_files $uri $uri/ /index.php?$args;
        log_not_found off;
        access_log off;
    }

    location ~ /\.(?!well-known\/) {
        deny all;
        return 404;
    }

    location = /xmlrpc.php {
        deny all;
        access_log off;
        log_not_found off;
        return 403;
    }

    location / {
        try_files $uri $uri/ /index.php?$args;
        limit_req zone=hand burst=5 nodelay;

        location ~* ^.+\.(ogg|ogv|svg|svgz|swf|eot|otf|woff|woff2|mov|mp3|mp4|webm|flv|ttf|rss|atom|jpg|jpeg|gif|png|webp|ico|bmp|mid|midi|wav|rtf|css|js|pdf|jar)$ {
            expires 365d;
            fastcgi_hide_header "Set-Cookie";
        }

        location ~* /(?:uploads|files)/.*.php$ {
            deny all;
            return 404;
        }

        location ~ [^/]\.php(/|$) {
            try_files $uri =404;
            include /etc/nginx/fastcgi_params;

            fastcgi_index index.php;
            fastcgi_param HTTP_EARLY_DATA $rfc_early_data if_not_empty;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

            fastcgi_pass %backend_lsnr%;

            include %home%/%user%/conf/web/%domain%/nginx.fastcgi_cache.conf*;

            if ($request_uri ~* "/wp-admin/|/wp-json/|wp-.*.php|xmlrpc.php|index.php|/store.*|/cart.*|/my-account.*|/checkout.*") {
                set $no_cache 1;
            }

            if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in|woocommerce_items_in_cart|woocommerce_cart_hash|PHPSESSID") {
                set $no_cache 1;
            }
        }
    }

    location /error/ {
        alias %home%/%user%/web/%domain%/document_errors/;
    }

    location /vstats/ {
        alias %home%/%user%/web/%domain%/stats/;
        include %home%/%user%/web/%domain%/stats/auth.conf*;
    }

    proxy_hide_header Upgrade;

    include /etc/nginx/conf.d/phpmyadmin.inc*;
    include /etc/nginx/conf.d/phppgadmin.inc*;
    include %home%/%user%/conf/web/%domain%/nginx.ssl.conf_*;
}

The 3 sites are on the same server using the same ip?

Yes that’s right, is used CF

I mean the same ip in your server. I’m asking because this is what happens when you use reuseport in two different sites sharing the same listen ip:

# nginx -t
nginx: [emerg] duplicate listen options for 203.0.113.1:443 in /etc/nginx/conf.d/domains/example.net.ssl.conf:7
nginx: configuration file /etc/nginx/nginx.conf test failed

Also, I don’t know what is the nginx version you are using but since version 1.25.1 the use of http2 in listen directive is deprecated, it must be added as http2 on; directive and Hestia adds it to a conf file.

# grep -r http2 /etc/nginx/*
/etc/nginx/conf.d/http2-directive.conf:http2 on;

I try this conf with

server {
	listen      %ip%:%web_ssl_port% ssl;
	listen      %ip%:%web_ssl_port% quic;
	server_name %domain_idn% %alias_idn%;
	root        %sdocroot%;
	index       index.php index.html index.htm;

	access_log  /var/log/nginx/domains/%domain%.log combined;
	access_log  /var/log/nginx/domains/%domain%.bytes bytes;
	error_log   /var/log/nginx/domains/%domain%.error.log error;

	ssl_certificate     %ssl_pem%;
	ssl_certificate_key %ssl_key%;
	ssl_stapling        on;
	ssl_stapling_verify on;
	http3 on;
    quic_retry on;
    quic_gso on;
    add_header Alt-Svc 'h3=":$server_port"; ma=86400';
	add_header X-protocol $server_protocol always;


I think something is missing from the Hestia conf

P.S.
sudo add-apt-repository ppa:5-sergey/nginx-quic
sudo apt update
sudo cp -r /etc/nginx /etc/nginx_bak
sudo apt purge nginx -y
nano /etc/apt/sources.list.d/nginx.list
#deb [arch=arm64 signed-by=/usr/share/keyrings/nginx-keyring.gpg] Index of /packages/mainline/ubuntu/ jammy nginx
ecc…

You’re right, I missed it, corrected http 2, I don’t see any errors, but you say that reuseport is installed on only one site? I definitely have it on all). Perhaps something has changed? Of course I don’t trust AI very much but,
https://handmadeflowers.angellive.ru/
https://opensource.angellive.ru/
https://quantumtransition.angellive.ru/

limit_req_zone $binary_remote_addr zone=quant:1m rate=1r/s;

server {
    listen      %ip%:%web_ssl_port% ssl;
    listen      %ip%:%web_ssl_port% quic reuseport;
    listen      [::]:%web_ssl_port% ssl;
    listen      [::]:%web_ssl_port% quic reuseport;

    server_name %domain_idn% %alias_idn%;
    root        %sdocroot%;
    index       index.php index.html index.htm;
    access_log  /var/log/nginx/domains/%domain%.log combined;
    access_log  /var/log/nginx/domains/%domain%.bytes bytes;
    error_log   /var/log/nginx/domains/%domain%.error.log error;

    ssl_certificate     %ssl_pem%;
    ssl_certificate_key %ssl_key%;
    ssl_stapling        on;
    ssl_stapling_verify on;

    # TLS 1.3 0-RTT anti-replay
    if ($anti_replay = 307) { return 307 https://$host$request_uri; }
    if ($anti_replay = 425) { return 425; }

    include %home%/%user%/conf/web/%domain%/nginx.hsts.conf*;

    # HTTP/3 specific settings
    ssl_protocols TLSv1.3;
    ssl_prefer_server_ciphers off;

    add_header Alt-Svc 'h3-23=":%web_ssl_port%"; ma=86400'; # Advertise that HTTP/3 is available
    add_header QUIC-Status $quic;

    location = /favicon.ico {
        log_not_found off;
        access_log off;
    }

    location = /robots.txt {
        try_files $uri $uri/ /index.php?$args;
        log_not_found off;
        access_log off;
    }

    location ~ /\.(?!well-known\/) {
        deny all;
        return 404;
    }

    location = /xmlrpc.php {
        deny all;
        access_log off;
        log_not_found off;
        return 403;
    }

    location / {
        try_files $uri $uri/ /index.php?$args;
        limit_req zone=hand burst=5 nodelay;

        location ~* ^.+\.(ogg|ogv|svg|svgz|swf|eot|otf|woff|woff2|mov|mp3|mp4|webm|flv|ttf|rss|atom|jpg|jpeg|gif|png|webp|ico|bmp|mid|midi|wav|rtf|css|js|pdf|jar)$ {
            expires 365d;
            fastcgi_hide_header "Set-Cookie";
        }

        location ~* /(?:uploads|files)/.*.php$ {
            deny all;
            return 404;
        }

        location ~ [^/]\.php(/|$) {
            try_files $uri =404;
            limit_req zone=quant burst=20 nodelay;
            include /etc/nginx/fastcgi_params;

            fastcgi_index index.php;
            fastcgi_param HTTP_EARLY_DATA $rfc_early_data if_not_empty;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

            fastcgi_pass %backend_lsnr%;

            include %home%/%user%/conf/web/%domain%/nginx.fastcgi_cache.conf*;

            if ($request_uri ~* "/wp-admin/|/wp-json/|wp-.*.php|xmlrpc.php|index.php|/store.*|/cart.*|/my-account.*|/checkout.*") {
                set $no_cache 1;
            }

            if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in|woocommerce_items_in_cart|woocommerce_cart_hash|PHPSESSID") {
                set $no_cache 1;
            }
        }
    }

    location /error/ {
        alias %home%/%user%/web/%domain%/document_errors/;
    }

    location /vstats/ {
        alias %home%/%user%/web/%domain%/stats/;
        include %home%/%user%/web/%domain%/stats/auth.conf*;
    }

    proxy_hide_header Upgrade;

    include /etc/nginx/conf.d/phpmyadmin.inc*;
    include /etc/nginx/conf.d/phppgadmin.inc*;
    include %home%/%user%/conf/web/%domain%/nginx.ssl.conf_*;
}

nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
root@rgkpwsgxjj:~# nginx -v
nginx version: nginx/1.27.0
systemctl status nginx
● nginx.service - nginx - high performance web server
     Loaded: loaded (/lib/systemd/system/nginx.service; enabled; preset: enabled)
     Active: active (running) since Tue 2024-07-30 23:18:26 MSK; 4s ago
       Docs: https://nginx.org/en/docs/
    Process: 39940 ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf (code=exited, status=0/SUCCESS)
   Main PID: 39942 (nginx)
      Tasks: 4 (limit: 1139)
     Memory: 5.6M
        CPU: 29ms
     CGroup: /system.slice/nginx.service
             ├─39942 "nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf"
             ├─39943 "nginx: worker process"
             ├─39944 "nginx: cache manager process"
             └─39945 "nginx: cache loader process"

июл 30 23:18:26 rgkpwsgxjj systemd[1]: Starting nginx.service - nginx - high performance web server...
июл 30 23:18:26 rgkpwsgxjj systemd[1]: nginx.service: Can't open PID file /run/nginx.pid (yet?) after start: No such file or directory
июл 30 23:18:26 rgkpwsgxjj systemd[1]: Started nginx.service - nginx - high performance web server.





What else should be added to the config, for example for security or functionality?

If we check Nginx doc Module ngx_http_core_module

The listen directive can have several additional parameters specific to socket-related system calls. These parameters can be specified in any listen directive, but only once for a given address:port pair.

So, socket parameters like reuseport can only be used for an address:port, if you use it in several server blocks, you should get the error I posted previously so I don’t know what’s going on here :wink: I also use Nginx 1.27.0.

Are you sure you are not using different internal/private ips and nated the public ip?

No), I deliberately posted all the screenshots, configs and so on, just in case I miss something, I wanted to shoot another video, but I restrained myself. Perhaps you will have some kind of thought, what information confirms this, and I will send it to you). That is, once again I have the same IP VDS server for the panel, this is natural, and accordingly for the sites. Perhaps if you download the config for yourself, you will not have an error, for example, on 2 test sites

As I read somewhere, this does not apply to 2 different virtual hosts, but maybe I don’t understand something, but I’m fine)

It applies to ip:port if two server blocks have the same ip and port, the reuseport can only be used in one of them.

Could you please show the output of this command?

grep -R reuseport /etc/nginx/conf.d/domains/*angellive.ru

grep -R reuseport /etc/nginx/conf.d/domains/*angellive.ru
grep: /etc/nginx/conf.d/domains/*angellive.ru: No such file or directory

Sorry, I forgot last wildcard.

grep -R reuseport /etc/nginx/conf.d/domains/*angellive.ru*

Nothing empty output

root@rgkpwsgxjj:~# grep -R reuseport /etc/nginx/conf.d/domains/*angellive.ru*
root@rgkpwsgxjj:~# 

Then you are not using reuseport in any of your configuration files…

grep -R 'listen.*quic' /etc/nginx/conf.d/domains/*angellive.ru*
root@rgkpwsgxjj:~# grep -R 'listen.*quic' /etc/nginx/conf.d/domains/*angellive.ru*
root@rgkpwsgxjj:~# 

At the same time, all sites gave HTTP 2, and began to give HTTP 3 in the control panel, it is also checked online HTTP/3 Check - handmadeflowers.angellive.ru
HTTP/3 Check - quantumtransition.angellive.ru
HTTP/3 Check - opensource.angellive.ru

You get http3 because you are using Cloudflare as proxy and the http3 is provided by Cloudflare.

But you are not even using quic in your nginx conf.

Show the listen directives please:

grep -Ri 'listen' /etc/nginx/conf.d/domains/*angellive.ru*
/etc/nginx/conf.d/domains/angellive.ru.conf:    listen      203.0.113.160:80;
/etc/nginx/conf.d/domains/angellive.ru.ssl.conf:        listen      203.0.113.160:443 ssl;
/etc/nginx/conf.d/domains/handmadeflowers.angellive.ru.conf:    listen      203.0.113.160:80;
/etc/nginx/conf.d/domains/handmadeflowers.angellive.ru.ssl.conf:        listen      203.0.113.160:443 ssl;
/etc/nginx/conf.d/domains/hestia.angellive.ru.conf:     listen      203.0.113.160:80;
/etc/nginx/conf.d/domains/hestia.angellive.ru.ssl.conf: listen      203.0.113.160:443 ssl;
/etc/nginx/conf.d/domains/opensource.angellive.ru.conf: listen      203.0.113.160:80;
/etc/nginx/conf.d/domains/opensource.angellive.ru.ssl.conf:     listen      203.0.113.160:443 ssl;
/etc/nginx/conf.d/domains/quantumtransition.angellive.ru.conf:  listen      203.0.113.160:80;
/etc/nginx/conf.d/domains/quantumtransition.angellive.ru.ssl.conf:      listen      203.0.113.160:443 ssl;

But before I upgraded the configuration it was HTTP 2, this is the IP of my VDS

I’ve edited your post to replace the real ip by 203.0.113.160.

Well, you didn’t apply your wordpress template to your sites and that is the reason you see no errors regarding duplicated listen directives using reuseport.

Now I’ve just changed the template to WordPress, and again I see http3, apparently you’re right, CF does it itself. To apply the template, I use

v-rebuild-users

And also go to the panel, and change the template from WordPress to site + vorpress
And it has always been used before)
Well, how can I do it right now, leave it on one site

server {
    listen      %ip%:%web_ssl_port% ssl;
    listen      %ip%:%web_ssl_port% quic reuseport;
    listen      [::]:%web_ssl_port% ssl ;
    listen      [::]:%web_ssl_port% quic reuseport;

And do others?

server {
    listen      %ip%:%web_ssl_port% ssl;
    listen      %ip%:%web_ssl_port% quic;
    listen      [::]:%web_ssl_port% ssl;
    listen      [::]:%web_ssl_port% quic;

You can create two templates, one using reuseport and assign it to only one web site and the other one without reuseport to the other web sites.

But if you rebuilt all your users, that has no sense, the nginx conf should be updated.

ls -l /usr/local/hestia/data/templates/web/nginx/php-fpm/wordpress*