I have an image file at https://www.example.com/img/bart-had-a-groove.gif

And this is the only cache block in my site config, there is no caching settings in global nginx.conf.

location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ {
  expires 1M;
  access_log off;
  add_header Cache-Control "public, no-transform, max-age=2628000";

Now, you can see my header is set to Cache-Control "public, no-transform, max-age=2628000";, but if you CURL the image e.g. curl -X GET -I https://www.example.com/img/bart-had-a-groove.gif you get:

HTTP/1.1 200 OK
Content-Type: image/gif
Connection: keep-alive
Server: nginx/1.13.9
Content-Length: 771510
Last-Modified: Fri, 17 Feb 2017 17:26:23 GMT
ETag: "58a7323f-bc5b6"
Pragma: public
Cache-Control: public
Accept-Ranges: bytes
Date: Mon, 19 Mar 2018 21:49:33 GMT
Expires: Wed, 18 Apr 2018 21:49:33 GMT

You can see that Cache-Control: public does not match the config. It's missing the no-transform, max-age=2628000 part.

I run systemctl stop nginx && systemctl start nginx && systemctl reload nginx after every change.

Update The rest of server block:

server {
  listen 80;
  listen 443;
  server_name example.com;
  return 301 https://www.$server_name$request_uri;

server {
  listen 80;
  listen 443 ssl http2;
  root /var/www/example.com/htdocs/;

  index index.html index.htm;

  server_name www.example.com;

  location / {
    autoindex on;
    try_files $uri $uri/ =404;    

  location ~ \.php$ {
    fastcgi_split_path_info ^(.+?\.php)(|/.*)$;
    # Security note: If you're running a version of PHP older than the
    # latest 5.3, you should have "cgi.fix_pathinfo = 0;" in php.ini.
    # See http://serverfault.com/q/627903/94922 for details.
    include fastcgi_params;
    # Block httpoxy attacks. See https://httpoxy.org/.
    fastcgi_param HTTP_PROXY "";
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_param PATH_INFO $fastcgi_path_info;
    fastcgi_param QUERY_STRING $query_string;
    fastcgi_intercept_errors on;
    # PHP 5 socket location.
    #fastcgi_pass unix:/var/run/php5-fpm.sock;
    # PHP 7 socket location.
    fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;

location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ {
  #expires 1M;
  access_log off;
  add_header Cache-Control "public, no-transform, max-age=2628000";

  pagespeed on;
  # Needs to exist and be writable by nginx.  Use tmpfs for best performance.
  pagespeed FileCachePath /var/ngx_pagespeed_cache;
  # Ensure requests for pagespeed optimized resources go to the pagespeed handler
  # and no extraneous headers get set.
  location ~ "\.pagespeed\.([a-z]\.)?[a-z]{2}\.[^.]{10}\.[^.]+" {
    add_header "" "";
  location ~ "^/pagespeed_static/" { }
  location ~ "^/ngx_pagespeed_beacon$" { }

You are using two correlating configuration directives, regarding the "Cache-Control" header (see below). I recommend to use only add_header as you appreciate the "no-transform" directive of the "Cache-Control" header.

expires 1M;

--> Will set header "Cache-Control" and "Expires".

See documentation:

Enables or disables adding or modifying the “Expires” and “Cache-Control” response header ...

add_header Cache-Control "public, no-transform, max-age=2628000";

--> Will manually set the "Cache-Control" header.

  • I tried that, it's not applying to the image. The header never change. – user3108268 Mar 20 '18 at 11:09
  • Turns out it has something to do with pagespeed. But not sure what, toggling it off and on after making changes to my header, it applies. You can see the rest of my config in original post. – user3108268 Mar 20 '18 at 11:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.