I've searched everywhere for a working answer to this issue, but none of the answers seem to work. I'm also sorry for the super long post but I just need to ask for help on this. I've tried to be as detailed as possible.

I have an nginx webserver with ngx_pagespeed installed on CentOS 7 I built from source and for the life of me, I can't get cache-control or expire headers to work. I have searched and tried every suggested "solution" on here, StackOverflow, the nginx wiki, and have seen probably 50 different pages of different ways people have gotten theirs "working".

Now I know that ngx_pagespeed has their own caching, but my site doesn't seem to be benefiting from that. So I'm trying to set my own cache-control and expire headers for media (jpg, gif, etc). But, for the past 2 days, all I get is:

Output from curl -I

HTTP/2 200
server: nginx
content-type: text/html; charset=UTF-8
vary: Accept-Encoding
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
strict-transport-security: max-age=31536000
x-content-type-options: nosniff
date: Tue, 26 Jun 2018 02:02:46 GMT
x-page-speed: Powered By ngx_pagespeed
cache-control: max-age=0, no-cache

I'm so frustrated over this. No matter what I try, I can't get anything other than

cache-control: max-age=0, no-cache from the curl.

Below are my config files. My site's config is in /etc/nginx/sites-available/conf and nginx's config file is in /etc/nginx/nginx.conf.


user  centos;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;

events {
    worker_connections  1024;

http {
    include       mime.types;
    include /etc/nginx/sites-enabled/*;
    default_type  application/octet-stream;

    #log_format  main  '$remote_addr - $remote_user [$time_local]                 
    "$request" '
    #'$status $body_bytes_sent "$http_referer" '
    #'"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

     server {
        listen       80;
        server_name  localhost;

I don't think the rest of nginx.conf is relevant. It's all commented out anyway by default. This file could be all kinds of wrong. I tried adding things here that I found that "fixed" it for other people.


# don't send the nginx version number in error pages and Server header
server_tokens off;

server {
    listen 80;
    server_name my_site;
    return 301 https://www.my_site.org;

    root /home/centos/site_folder/public;

    location / {
    add_header Cache-Control "public";
    expires 1d;
    proxy_pass http://site_ip:8080;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    proxy_cache_bypass $http_upgrade;

    #proxy_buffering on;
    #proxy_ignore_headers "Set-Cookie";
    #proxy_hide_header "Set-Cookie";

    proxy_buffering on;
    #proxy_ignore_headers Expires;
    #proxy_ignore_headers X-Accel-Expires;
    #proxy_ignore_headers Cache-Control;
    #proxy_ignore_headers Set-Cookie;

    #proxy_hide_header X-Accel-Expires;
    #proxy_hide_header Expires;
    #proxy_hide_header Cache-Control;
    #proxy_hide_header Pragma;


    location ~*  \.(jpg|jpeg|png|gif|ico|css|js)$ {
    expires 15d;

    location ~* \.(jpg|jpeg|gif|png)$ {
    expires 365d;

    location ~* \.(pdf|css|html|js|swf)$ {
    expires 30d;


server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
ssl_certificate /my/certs/are/here.crt;
ssl_certificate_key /my/certs/are/here.key;

# intermediate configuration
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;

# enable session resumption to improve https performance
    ssl_session_cache shared:SSL:50m;
    ssl_session_timeout 1d;
    ssl_session_tickets off;

    ssl_stapling on;
    ssl_stapling_verify on;

    gzip on;
    gzip_disable "MSIE [1-6]\.(?!.*SV1)";
    gzip_proxied any;
    gzip_types text/plain text/css application/json         
    application/javascript application/x-javascript text/xml 
    application/xml application/xml+rss text/javascript image/x- 
    icon image/bmp image/svg+xml;
    gzip_vary on;
    gzip_comp_level 5;
    gzip_min_length 256;
    gzip_buffers 16 8k;

    include /etc/nginx/snippets/security-headers.conf;

    server_name my_site.org;
    access_log /var/log/nginx/nginx.vhost.access.log;
    error_log /var/log/nginx/nginx.vhost.error.log;
    location / {
    #root /home/centos/my_site.org/public;
    try_files $uri $uri/ /index.html?$args;
    index index.html;


    location ~*\.(js|css|png|jpg|jpeg|gif|ico)$ {
    expires 30d;
    add_header Cache-Control "public, no-transform";

    location /page1 {
    default_type "text/html";
    alias /home/centos/my_site.org/public/page1.html;

    location /page2 {
    default_type "text/html";
    alias /home/centos/my_site.org/public/page2.html;

    location ~* \. 
    (jpeg|jpg|JPG|gif|png|ico|cur|gz|svg|svgz|webp)$ {
    #root /home/centos/my_site.org/public;
    #include /etc/nginx/snippets/security-headers.conf;
    try_files $uri $uri/ /$1/$2 =404;
    #access_log off;
    #log_not_found off;

    #location ~* \.(mp3|mpeg|mpg|mp4|ogg|ogv|webm|webp|htc)$ {        
    #root /home/centos/my_site.org/public;
    #include /etc/nginx/snippets/security-headers.conf;
    #try_files $uri $uri/ /$1/$2 =404;
    #proxy_cache_valid any 30d;
    #access_log off;
    #add_header Cache-Control "public";

    #location ~* \.(|css|js)$ {
    #expires 7d;
    #root /home/centos/my_site.org/public;
    #include /etc/nginx/snippets/security-headers.conf;
    #try_files $uri $uri/ /$1/$2 =404;
    #access_log off;
    #add_header Cache-Control "public";

    # Pagespeed main settings

    pagespeed on;
    pagespeed FileCachePath /var/ngx_pagespeed_cache;   
    pagespeed FileCacheSizeKb            102400;
    pagespeed FileCacheCleanIntervalMs   3600000;
    pagespeed FileCacheInodeLimit        500000;
    pagespeed Domain https://www.my_site.org;
    pagespeed XHeaderValue "Powered By ngx_pagespeed";
    pagespeed HonorCsp on;
    pagespeed LowercaseHtmlNames on;
    #pagespeed EnableFilters extend_cache;
    #pagespeed ModifyCachingHeaders off;

    # Image related
    pagespeed EnableFilters rewrite_images;
    pagespeed EnableFilters convert_gif_to_png;
    pagespeed EnableFilters convert_jpeg_to_progressive;
    pagespeed EnableFilters strip_image_color_profile;
    pagespeed EnableFilters strip_image_meta_data;
    pagespeed EnableFilters jpeg_subsampling;
    pagespeed EnableFilters lazyload_images;
    pagespeed EnableFilters responsive_images,resize_images;
    pagespeed EnableFilters resize_mobile_images;
    pagespeed EnableFilters recompress_images;

    # code related
    pagespeed EnableFilters collapse_whitespace;

    # JS related
    pagespeed EnableFilters rewrite_javascript;
    pagespeed EnableFilters combine_javascript;

    # CSS related
    pagespeed EnableFilters rewrite_css;
    pagespeed EnableFilters prioritize_critical_css;
    pagespeed EnableFilters combine_css;
    pagespeed EnableFilters outline_css;
    pagespeed EnableFilters flatten_css_imports;

    # Ensure requests for pagespeed optimized resources go to the         
    # handler and no extraneous headers get set.

    location ~ "\.pagespeed\.([a-z]\.)?[a-z]{2}\.[^.]{10}\.[^.]+" 
    { add_header "" ""; }

    #location ~* \.(jpg|jpeg|gif|png|js|css)$ {
    #add_header Cache-Control "public, max-age=600";

    location ~ "^/ngx_pagespeed_static/" { }
    location ~ "^/ngx_pagespeed_beacon" { }


These configs work and pass nginx -t but the caching just won't work. I have left all of my commented out code so you can see what I've done/tried. Any help here would be greatly appreciated. If I've missed any needed details, let me know. Thank you!

  • Your curl output shows content-type text/html. However, you are referring to media files in your question. What URL are you requesting with curl in your example? Jun 26, 2018 at 6:56
  • @Tero Kilkanen The URL I'm requesting is my site: https://www.gr80.org. I've tried specifying media files in the location directive but it doesn't ever seem to honor that.
    – Grady
    Jun 26, 2018 at 11:35
  • Please show curl output for HTTP headers for a media file in your question. Jun 26, 2018 at 16:39
  • How would I do that when my media is being hosted on Amazon S3 and not on my webserver?
    – Grady
    Jun 26, 2018 at 16:53
  • 1
    @Tero Kilkanen - This did it! I set the cache-control and expires header in the S3 bucket settings. Thank you so much for pointing me in the right direction. I feel like an idiot for not putting this together sooner. I've read over a ton of your answers on here. I'm glad you were the one to help me. You're a legend around here.
    – Grady
    Jun 26, 2018 at 17:32

1 Answer 1


With some direction from Tero Kilkanen, I was able to set the cache-control and expires header from the S3 bucket that the media is being hosted on and not from my nginx webserver.

Thank you!

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.