Nginx x-accel stripping Content-Encoding header

gzipnginx

I have my Nginx server setup allow requests to be served with the X-Accel-Redirect header. This works fine for images, but I'm trying to get it to work for Javascript files that are already gzip'ed on the disk and it appears Nginx is stripping off the Content-Encoding header. This makes the browser not unzip the content when it receives it, which obviously makes it not work.

How can I serve pre-gzipped content through X-Accel-Redirect ?

The headers seen are:

With Accel = doesn't work

Accept-Ranges:bytes
Cache-Control:max-age=1209600, s-maxage=120960
Connection:keep-alive
Content-Length:122871
Content-Type:application/javascript
Date:Mon, 24 Jun 2013 13:44:36 GMT
Expires:Mon, 08 Jul 2013 13:44:36 GMT
Last-Modified:Mon, 24 Jun 2013 13:38:20 GMT
Server:nginx/1.2.8

No accel = works

Cache-Control:max-age=1209600, s-maxage=120960
Connection:keep-alive
Content-Encoding:gzip
Content-Length:122871
Content-Type:application/javascript
Date:Mon, 24 Jun 2013 13:45:08 GMT
Expires:Mon, 08 Jul 2013 13:45:08 GMT
HTTP1/0 200 Ok:
Pragma:cache
Server:nginx/1.2.8
X-Powered-By:PHP/5.4.9

In case it's relevant the code that is serving the content is:

public static function  proxyFile($fileNameToServe, $mimeType, $alreadyGzip = false){
        $seconds_to_cache = 3600 * 24 * 7 * 2; 

        $filesize = filesize($fileNameToServe);
        header('Content-Length: '.$filesize);

        if ($alreadyGzip) {
            header('Content-Encoding: gzip');
        }

        if(defined('X-ACCEL-REDIRECT') == true && constant('X-ACCEL-REDIRECT') == true){
            $filenameToProxy = str_replace(PATH_TO_ROOT."var/cache", '/protected_files', $fileNameToServe );
            sendProxyHeaders($mimeType, $seconds_to_cache);
            header("X-Accel-Redirect: ".$filenameToProxy);
            exit(0);
        }
        else{
            sendProxyHeaders($mimeType, $seconds_to_cache);
            $fileHandle = fopen($fileNameToServe, 'r');

            if($fileHandle == false){
                throw new \Exception("Failed to open file [$fileNameToServe] for serving.");
            }

            while (!feof($fileHandle)) {
                $contents = fread($fileHandle, 8192);
                echo $contents;
            }

            fclose($fileHandle);
        }

        exit(0);
    }

I've tried setting proxy_pass_header Content-Encoding; but apparently it has no effect.

Best Answer

It appears there are two solutions:

  1. Tell Nginx to pass the Content-Encoding header by add_header Content-Encoding $upstream_http_content_encoding;, and turn gzip off for the x-accel-redirect location, to prevent the content being gzipped twice.

    location ^~ /protected_files { gzip off; internal; alias /home/intahwebz/var/cache; add_header Content-Encoding $upstream_http_content_encoding; }

  2. Enable the gzip_static module.

Before serving a file from disk to a gzip-enabled client, this module will look for a precompressed file in the same location that ends in ".gz". The purpose is to avoid compressing the same file each time it is requested.