Nginx stopped serving gzip?

I upgraded my servers to 23.05 and I noticed that nginx is no longer compressing the assets it’s serving. The configuration didn’t change.

I don’t know if it’s 23.05 or earlier, but I noticed because pagespeed started complaining about missing text compression.

Anyone else noticing this?

It does work with pre-compressed files and that’s arguably a better way of going about it, so now I implemented that, but still, it’s surprising that gzip on doesn’t work any more for .js files.

Here’s my config:

{
  services.nginx = {
    package = pkgs.nginxMainline;

    # Puts nginx config in /etc and keeps connections open
    enableReload = true;

    additionalModules = [ pkgs.nginxModules.vts pkgs.nginxModules.brotli ];

    recommendedGzipSettings = true;
    recommendedOptimisation = true;
    recommendedProxySettings = true;
    recommendedTlsSettings = true;
  };
}
1 Like

cc @Sandro, as one of the last people to touch that part of the module + someone I know uses at least some form of compression :slight_smile:

1 Like

Is the file(s?) beneath 256 bytes? nixpkgs/nixos/modules/services/web-servers/nginx/default.nix at 9a1570b7e996d995fd770a795e9ef97f29475210 · NixOS/nixpkgs · GitHub

1 Like

No, quite a lot more :sweat_smile:
So you’re seeing gzip working on non-precompressed files?

Could you share the resulting nginx.conf file?

pid /run/nginx/nginx.pid;
error_log stderr;
daemon off;
events {
}
http {
        # Load mime types.
        include /nix/store/dwq697bxfhp7hpcq2mkd9m9469cqm7nm-mailcap-2.1.53/etc/nginx/mime.types;
        # When recommendedOptimisation is disabled nginx fails to start because the mailmap mime.types database
        # contains 1026 entries and the default is only 1024. Setting to a higher number to remove the need to
        # overwrite it because nginx does not allow duplicated settings.
        types_hash_max_size 4096;
        include /nix/store/ny4469ws21i68jyagp7n8v4fdj6addx2-nginx-1.24.0/conf/fastcgi.conf;
        include /nix/store/ny4469ws21i68jyagp7n8v4fdj6addx2-nginx-1.24.0/conf/uwsgi_params;
        default_type application/octet-stream;
        upstream myserver {
                server localhost:3000 max_fails=0 fail_timeout=60 ;
        }
        # optimisation
        sendfile on;
        tcp_nopush on;
        tcp_nodelay on;
        keepalive_timeout 65;
        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;
        # Keep in sync with https://ssl-config.mozilla.org/#server=nginx&config=intermediate
        ssl_session_timeout 1d;
        ssl_session_cache shared:SSL:10m;
        # Breaks forward secrecy: https://github.com/mozilla/server-side-tls/issues/135
        ssl_session_tickets off;
        # We don't enable insecure ciphers by default, so this allows
        # clients to pick the most performant, per https://github.com/mozilla/server-side-tls/issues/260
        ssl_prefer_server_ciphers off;
        # OCSP stapling
        ssl_stapling on;
        ssl_stapling_verify on;
        gzip on;
        gzip_static on;
        gzip_vary on;
        gzip_comp_level 5;
        gzip_min_length 256;
        gzip_proxied expired no-cache no-store private auth;
        gzip_types application/atom+xml application/geo+json application/json application/ld+json application/manifest+json application/rdf+xml application/vnd.ms-fontobject application/wasm application/x-rss+xml application/x-web-app-manifest+json application/xhtml+xml application/xliff+xml application/xml font/collection font/otf font/ttf image/bmp image/svg+xml image/vnd.microsoft.icon text/cache-manifest text/calendar text/css text/csv text/javascript text/markdown text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/xml;
        proxy_redirect          off;
        proxy_connect_timeout   60s;
        proxy_send_timeout      60s;
        proxy_read_timeout      60s;
        proxy_http_version      1.1;
        # don't let clients close the keep-alive connection to upstream. See the nginx blog for details:
        # https://www.nginx.com/blog/avoiding-top-10-nginx-configuration-mistakes/#no-keepalives
        proxy_set_header        "Connection" "";
        include /nix/store/wfdk2qisjwl33193j8x24wra9w3sv3a9-nginx-recommended-proxy-headers.conf;
        # $connection_upgrade is used for websocket proxying
        map $http_upgrade $connection_upgrade {
                default upgrade;
                ''      close;
        }
        client_max_body_size 50m;
        server_tokens off;
        log_format default '$remote_addr $status $bytes_sent $request_time "$request" "$http_referer" "$http_user_agent"';
        access_log syslog:server=unix:/dev/log,nohostname default;
        # for netdata
        vhost_traffic_status_zone;
        server {
                listen 0.0.0.0:80 default_server ;
                listen [::0]:80 default_server ;
                server_name localhost ;
                root /var/empty;
                location /status {
                        vhost_traffic_status_display;
                        vhost_traffic_status_display_format html;
                        access_log off;
                        allow 127.0.0.1;
                        allow ::1;
                        deny all;
                }
        }
        server {
                listen 0.0.0.0:80 ;
                listen [::0]:80 ;
                server_name myserver;
                # Rule for legitimate ACME Challenge requests (like /.well-known/acme-challenge/xxxxxxxxx)
                # We use ^~ here, so that we don't check any regexes (which could
                # otherwise easily override this intended match accidentally).
                location ^~ /.well-known/acme-challenge/ {
                        root /var/lib/acme/acme-challenge;
                        auth_basic off;
                }
                location / {
                        return 301 https://$host$request_uri;
                }
        }
        server {
                listen 0.0.0.0:443 http2 ssl ;
                listen [::0]:443 http2 ssl ;
                server_name myserver;
                # Rule for legitimate ACME Challenge requests (like /.well-known/acme-challenge/xxxxxxxxx)
                # We use ^~ here, so that we don't check any regexes (which could
                # otherwise easily override this intended match accidentally).
                location ^~ /.well-known/acme-challenge/ {
                        root /var/lib/acme/acme-challenge;
                        auth_basic off;
                }
                ssl_certificate /var/lib/acme/myserver/fullchain.pem;
                ssl_certificate_key /var/lib/acme/myserver/key.pem;
                ssl_trusted_certificate /var/lib/acme/myserver/chain.pem;
                location ~ /\. {
                        return 404 deny;
                }
                location / {
                        index index.html;
                        try_files $uri @$service;
                        root /var/www;
                }
                location /_img/ {
                        try_files $uri @$service;
                        alias /$userHome/$dir/build/processed/;
                        expires max;
                }
                location /_vendor/ {
                        alias /$userHome/$dir/vendor/;
                        expires 7d;
                }
                location @server {
                        proxy_pass http://server;
                        include /nix/store/wfdk2qisjwl33193j8x24wra9w3sv3a9-nginx-recommended-proxy-headers.conf;
                }
                location ~ /_img/(?<match>[^/]+@[^@./]+)$ {
                        try_files /$match$imgExt @$service;
                        root /$userHome/$dir/build/processed;
                }
                location ~* ^/_/(.+)$ {
                        try_files /client-esmodules/$1 /client/$1 =404;
                        root /$userHome/$dir/build/;
                        expires max;
                }
                set $service server;
                set $userHome /home/server;
                set $dir www;
        }
        map $http_accept $imgExt {
                default   ".jpg";
                "~*avif"  ".avif";
                "~*webp"  ".webp";
        }
        map $http_accept $imgExt {
                default   ".jpg";
                "~*avif"  ".avif";
                "~*webp"  ".webp";
        }
}

My two cents

I wonder if gzip_proxied should receive extra no_etag no_last_modified :thinking: , maybe they are not listed on purpose.

It seems text/html is missing from gzip_types, but maybe the application/xhtml+xml matches…

What’s type content type returned when you query a .js file?

It’s application/javascript so it should have been covered right?

I can’t find application/javascript in the mime type list.

That’s what developer tools tell me for dynamic generated files.

We need to find some tool to programmatically fix them. Neither mailcap nor media-types is complete or usable by nginx without edits.

2 Likes

:man_facepalming:
I thought about this and somehow was under the impression that it was in there :sweat_smile:

Hmm, why? Isn’t it always desirable to compress results that weren’t compressed (with the correct mime type)?