Skip to content

$http_host can be empty when using http3 #226

@realrellek

Description

@realrellek

Describe the bug
When using http3, the $http_host variable may be empty. It is used by the config file tho to determine where in the file system the cache file could be. So this fails, thus yielding a cache miss, and going through the php system.

If that happens, it'll result in a cache url like
/var/customers/webs/wum/domain.tld/wp-content/cache/wp-rocket/////index-https.html
which doesn't exist, thus the miss.

Versions
What version of Nginx are you using ? 1.28.0
What version of Rocket-Nginx are you using ? 3.1.1
What version of WP Rocket are you using ? 3.20.1.2
Are you using Nginx as a reverse proxy (with Apache for instance) ? nope

To Reproduce
Steps to reproduce the behaviour:
I'm not actually sure because even on my server, the $http_host variable is set sometimes, and sometimes not. But it has to do with http3 as per google.

Did you activate the debug in Rocket-Nginx ? Please do and include any headers.

x-rocket-nginx-file: /var/customers/webs/wum/domain.tld/wp-content/cache/wp-rocket/////index-https.html
x-rocket-nginx-reason: File not cached
x-rocket-nginx-serving-static: MISS

/etc/nginx/sites-enabled/35_froxlor_ssl_vhost_domain.tld.conf:

# 35_froxlor_ssl_vhost_domain.tld.conf
# Created 16.11.2025 18:54
# Do NOT manually edit this file, all changes will be deleted after the next domain change at the panel.

server {
        listen [dead:beef:c0fe:babe::2]:443 ssl;
        http2 on;
        listen [dead:beef:c0fe:babe::2]:443 quic;
        listen 69.69.69.69:443 ssl;
        listen 69.69.69.69:443 quic;
        add_header Alt-Svc 'h3=":443"; ma=86400';
        http3 on;
        http3_hq on;
        quic_gso on;
        quic_retry on;
        server_name domain.tld www.domain.tld domain.othertld www.domain.othertld;
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;
        ssl_dhparam /etc/ssl/webserver/dhparams.pem;
        ssl_prefer_server_ciphers off;
        ssl_session_tickets on;
        ssl_session_cache shared:SSL:10m;
        ssl_certificate /etc/ssl/froxlor-custom/domain.tld.crt;
        ssl_certificate_key /etc/ssl/froxlor-custom/domain.tld.key;
        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
        include /etc/apache2/conf-enabled/acme.conf;
        access_log /var/customers/logs/wum-domain.tld-access.log combined;
        error_log /var/customers/logs/wum-domain.tld-error.log warn;
        root /var/customers/webs/wum/domain.tld/;
        location / {
                index index.php index.html index.htm;
                try_files $uri $uri/ /index.php?$args;
        }

        location ^~ /goaccess {
                alias /var/customers/webs/wum/goaccess/domain.tld/;
                auth_basic "Restricted Area";
                auth_basic_user_file /etc/nginx/froxlor-htpasswd/1-c123456789.htpasswd;
        }

        location ~ ^(.+?\.php)(/.*)?$ {
                include /etc/nginx/fastcgi_params;
                fastcgi_split_path_info ^(.+?\.php)(/.*)$;
                fastcgi_param SCRIPT_FILENAME $request_filename;
                fastcgi_param PATH_INFO $2;
                fastcgi_param HTTPS on;
                fastcgi_pass unix:/var/lib/apache2/fastcgi/1-wum-domain.tld-php-fpm.socket;
                fastcgi_index index.php;
        }

        location ~ /\. {
                deny all;
        }

        charset utf-8;
        etag off;
        gzip on;
        gzip_vary on;
        gzip_types
        application/atom+xml
        application/javascript
        application/json
        application/rss+xml
        application/vnd.ms-fontobject
        application/x-font-ttf
        application/xhtml+xml
        application/xml
        font/opentype
        image/svg+xml
        image/x-icon
        text/css
        text/plain
        text/x-component
        text/xml;
        add_header X-Robots-Tag "noarchive";
        if ($host != "www.domain.tld") {
                return 301 https://www.domain.tld$request_uri;
        }

        if ($args ~* "wptouch_switch=") {
                return 301 $uri; # $uri hat keinen Query String
        }

        rewrite ^/kategorie/(.+)/www\.domain\.othertld/(.+)$ https://www.domain.tld/$2 permanent;
        rewrite (.+)/amp/?$ $1 permanent;
        location = /sitemap-news.xml {
                return 301 https://www.domain.tld/post_google_news.xml;
        }

        location = /sitemap.xml {
                return 301 https://www.domain.tld/sitemapindex.xml;
        }

        include /etc/nginx/snippets/wum-domain-redirects.conf;
        location ~ /\.user\.ini$ {
                deny all;
        }

        include /etc/nginx/rocket-nginx/conf.d/default.conf;
        client_max_body_size 512M;
        client_body_buffer_size 2M;
        location ~* ^(/.+)\.(jpg|jpeg|jpe|png|gif)$ {
                add_header Vary Accept;
                set $canavif 1;
                if ($http_accept !~* "avif") { set $canavif 0;
                }

                if (!-f $request_filename.avif) { set $canavif 0; }
                if ($canavif = 1) {
                        rewrite ^(.*)$ $1.avif break;
                }

                set $canwebp 1;
                if ($http_accept !~* "webp") { set $canwebp 0; }
                if (!-f $request_filename.webp) { set $canwebp 0; }
                if ($canwebp = 1) {
                        rewrite ^(.*)$ $1.webp break;
                }

        }

        location = /fpm-status {
                allow 127.0.0.1;
                allow ::1;
                allow 69.69.69.69; # Deine Monitoring-IP, nehme ich an
                deny all;
                set $fpm_socket "unix:/var/lib/apache2/fastcgi/1-wum-domain.tld-php-fpm.socket";
                if ($fpm_socket = "unix:") {
                        return 404;
                }

                include fastcgi_params;
                fastcgi_param SCRIPT_FILENAME "";
                fastcgi_param SCRIPT_NAME /fpm-status;
                fastcgi_pass $fpm_socket;
        }

}

Expected behavior
It should use a populated variable

Additional context
I also had to add this:

fastcgi_param  HTTP_HOST       $host;
fastcgi_param  HTTP_HOST      $http_host if_not_empty;

into /etc/nginx/fastcgi_params because otherwise PHP scripts are going crazy. It is a somewhat documented thing, tho nginx doesn't seem to feel responsible to "fix" this.

I'd propose that the config file doesn't rely on $http_host but sets its own variable, and checks if $http_host has something useful, and if not, it uses $host.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions