NGINX - Cannot set Cache-control for redirected .js files (with alias + rewrite)

5,660

add_header is part of a third party module called "headers more", you either need to build nginx from source or make sure your repository has already done it for you.

To build nginx from source read this tutorial I wrote - it's pretty quick and easy.

The way to check if the module is working is to run

nginx -V

Add see if this is in the output

--add-module=../headers-more-nginx-module-0.29

Another way is to add a simple add_header to the main location block. add_header's a good debugging tool as well.

For reference, here's how I do the Nginx build. Note at the tutorial above there's a more optimized version of the configure command, but this one is more compatible and probably safer

cd /home/ec2-user
mkdir nginx-build
cd nginx-build
service nginx stop
yum groupinstall "Development Tools"
yum install pcre-devel zlib-devel openssl-devel
wget http://nginx.org/download/nginx-1.9.11.tar.gz
wget http://labs.frickle.com/files/ngx_cache_purge-2.3.tar.gz
wget https://github.com/openresty/headers-more-nginx-module/archive/v0.29.tar.gz
tar -xzf nginx-1.9.11.tar.gz
tar -xzf ngx_cache_purge-2.3.tar.gz
tar -xzf v0.29.tar.gz # headers-more
# Note that I have no idea what the next line does but it was in the official guide
PS_NGX_EXTRA_FLAGS="--with-cc=/opt/rh/devtoolset-2/root/usr/bin/gcc"
# Safe option, slower, lots of modules included
./configure --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-http_ssl_module --with-http_realip_module --with-http_addition_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_stub_status_module --with-http_auth_request_module --with-threads --with-stream --with-stream_ssl_module --with-http_slice_module --with-mail --with-mail_ssl_module --with-file-aio --with-ipv6 --with-http_v2_module --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic' --add-module=/tmp/ngx_cache_purge-2.3 --add-module=/tmp/headers-more-nginx-module-0.29 --with-http_realip_module --add-modeule=../ngx_pagespeed-release-1.9.32.10-beta
make && make install
make clean  (NB: optional)
service nginx start

Then try this kind of block for your static resource caching. Note there is no try_files in there.

location ~*  \.(jpg|jpeg|png|gif|css|js|ico)$ {
  log_not_found off; access_log off;
  add_header Cache-Control "public, max-age=691200, s-maxage=691200";
  more_clear_headers "Pragma"; more_clear_headers "Expires";
}
Share:
5,660

Related videos on Youtube

CEDA
Author by

CEDA

Updated on September 18, 2022

Comments

  • CEDA
    CEDA over 1 year

    I have successfully setup an nginx server which uses both alias + rewrite as in the below configuration. Everything works except that javascript files are not enforced browser caching.

    • Server url: http://localhost/
    • Server root: /space1/www
    • An alias named 'builder', with its root directory: /space1/builder
    • There's a web app called 'luoicongtrinh' in: /space1/builder/apps/luoicongtrinh/admin
    • Path of static resources of this app are rewritten, like: http://localhost/builder/apps/luoicongtrinh/admin/js/main.js will be served from the location: /space1/builder/apps/luoicongtrinh/public/js/main.js
    • I would like to setup Cache-control for this file but still unsuccessful

    Current working configuration (with no cache-control)

    server {
        listen       80;
    
        server_name  localhost;
        root /space1/www;
        index  index.html index.htm index.php;
    
        access_log /var/log/nginx/access.log debug;
    
        location / {
            server_tokens off;
            client_max_body_size 20m;
            client_body_buffer_size 128k;
        }
    
        location ~ /\. {
            access_log off;
            log_not_found off;
            deny all;
        }
    
        # builder
        location /builder {
            alias /space1/builder;
    
            # luoicongtrinh
            rewrite ^/builder/apps/luoicongtrinh/(css|images|js|fonts|lib|uploads)/(.+)$ /builder/apps/luoicongtrinh/public/$1/$2 last;
            rewrite ^/builder/apps/luoicongtrinh/admin/(css|images|js|fonts|lib|uploads)/(.+)$ /builder/apps/luoicongtrinh/public/$1/$2 last;
            rewrite ^/builder/apps/luoicongtrinh/admin/?(.*)$ /builder/apps/luoicongtrinh/admin/index.php?p=$1&$args last;
    
            fastcgi_split_path_info ^/builder/(.+\.php)(.*)$;
            include /etc/nginx/php_fastcgi;
        }
    
        # Default PHP support
        include /etc/nginx/php_fastcgi;
    }
    

    I try to add the following block to enforce browser caching for static files (for example: http://localhost/builder/apps/luoicongtrinh/admin/js/main.js) but this does not work.

    location ~* \.(?:ico|css|js|gif|jpe?g|png)$ {
        expires 30d;
        add_header Pragma public;
        add_header Cache-Control "public";
        try_files $uri =404;
    }
    

    I have also try various configurations but still unsuccessful.

    Please guide me how to set this up correctly. Many thanks!!!

    UPDATE: I have tried using "if" block and this works.

    # builder
    location /builder {
        alias /space1/builder;
    
        # cache control for static resources
        if ($uri ~* "/(css|images|js|fonts|lib|uploads)/") {
            expires 30d;
            add_header Pragma public;
            add_header Cache-Control "public";
        }
    
        # luoicongtrinh
        rewrite ^/builder/apps/luoicongtrinh/(css|images|js|fonts|lib|uploads)/(.+)$ /builder/apps/luoicongtrinh/public/$1/$2 last;
        rewrite ^/builder/apps/luoicongtrinh/admin/(css|images|js|fonts|lib|uploads)/(.+)$ /builder/apps/luoicongtrinh/public/$1/$2 last;
        rewrite ^/builder/apps/luoicongtrinh/admin/?(.*)$ /builder/apps/luoicongtrinh/admin/index.php?p=$1&$args last;
    
        fastcgi_split_path_info ^/builder/(.+\.php)(.*)$;
        include /etc/nginx/php_fastcgi;
    }
    

    I've read that using "if" is "evil". Do you know how to formulate the above "if" block another way?

  • CEDA
    CEDA about 8 years
    Thanks Tim. I have tried your suggestion but still no luck. I still got the 404 error.
  • Tim
    Tim about 8 years
    Try the block I posted above. try_files isn't necessary - what are you trying to achieve with that? Remove your pragma and expires, they're for HTTP1.0 and really old browsers, from memory, they're really not necessary.
  • CEDA
    CEDA about 8 years
    Thanks. I have tried with an "if" block and it now works. See above UPDATE section
  • Tim
    Tim about 8 years
    If is Evil. nginx.com/resources/wiki/start/topics/depth/ifisevil Your solution is slower than it should be, prone to breaking, and uses more resources. Just get your regular expression right. This should be trivial. Post the link to your actual website if you want me to verify behavior.
  • CEDA
    CEDA about 8 years
    Thanks Tim. This is for our internal server so its public link is not available. I know it's recommended to avoid if block, but I haven't found any workaround yet.
  • Tim
    Tim about 8 years
    The location block I posted should do the job perfect. It shouldn't go within your builder location, it's a location in its own right. If you need this to only apply to the builder location (which would be a bit odd) then you just need to alter the regular expression in my location block.
  • CEDA
    CEDA about 8 years
    I have tried your block but then there's 404 error. I know your block should work in case of direct resource paths, but in my case, the resource paths need to be rewritten (as I described in the question). For example: .../ADMIN/js/main.js should go to .../PUBLIC/js/main.js. Your posted block does not handle the redirection so we will get 404 error.
  • Tim
    Tim about 8 years
    Doing detailed stuff can be a bit tricky. Suggest you continue to play around, but good that you have an IF option working just in case you can't go further.