nginx gzip – How to Change Compression Level Based on User Agent

gzipnginx

I've profiled my site and realized that turning the gzip_comp_level up past 1 for desktop reduces total throughput. But, on mobile, where network speed is the bottleneck and not the server TTFB, setting gzip_comp_level to 4 or higher makes sense.

I wanted to change the gzip_comp_level based on user agent, but it doesn't seem like this is possible in NGINX.

Here's my nginx.conf

http {
server {
    ...

    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_buffers 16 8k;
    gzip_min_length 1024;
    gzip_types image/png image/svg+xml text/plain text/css image/jpeg application/font-woff application/json application/x-javascript application/javascript text/xml application/xml application/rss+xml text/javascript application/vnd.ms-fontobject application/x-font-ttf font/opentype;

    ...

    location / {
        include /etc/nginx/mime.types;
        expires max;

        sendfile on;
        tcp_nodelay on;
        tcp_nopush on;

        add_header Pragma public;
        add_header Cache-Control "public";
        add_header Vary "Accept-Encoding";

        if ($http_user_agent ~* '(iPhone|iPod|Opera Mini|Android.*Mobile|NetFront|PSP|BlackBerry|Windows Phone)') {
            set $ua_type "mobile";
        }

        if ($ua_type = "mobile") {
            gzip_comp_level 4;
        }
        if ($ua_type != "mobile") {
            gzip_comp_level 1;
        }

        location ~* \.(js|jpg|jpeg|png|css|svg|ttf|woff|woff2)$ {
            access_log off;
            log_not_found off;
        }
    }
}
}

NGINX gives nginx: [emerg] "gzip_comp_level" directive is not allowed here in /etc/nginx/nginx.conf:44

Is there anyway around this?

Best Answer

This should work

Using map we give a value for $ismobile based on the agent (Add more agents as required to the list in my config below).

We then check that value and return an error code.

We then get nginx to handle the error and redirect to a location which contains the correct gzip_comp_level and the rest of the configuration.

I've only included the relevant parts below.

http {

    map $http_user_agent $ismobile {
    "default"   0;
    "~*iphone"    1;
    .....

    }

    server {

        error_page 412 = @mobile;
        error_page 413 = @notmobile;
        recursive_error_pages on;

        if ($ismobile = "1"){
                return 412;
                }

        if ($ismobile = "0"){
            return 413;
            }

        location @mobile {
            gzip_comp_level 4;
            <add rest of config with an include or line by line>
        }

        location @notmobile {
            gzip_comp_level 1;
            <add rest of config with an include or line by line>
        }
    }
}