2

I have the following nginx config:

server {
    listen 8080;

    root /site_root/web;
    index index.html;

    server_name www.mysite.com;

    location / {
        try_files $uri @rewriteapp;
    }

    location @rewriteapp {
        rewrite ^(.*)$ /app.php/$1 last;
    }

    # add headers to static files
    location ~* \.(?:ico|css|js|gif|jpe?g|png|svg|woff|ttf|eot)$ {
        expires 365d;
        add_header Pragma public;
        add_header Cache-Control "public";
    }

    location ~ \.php {
        fastcgi_split_path_info ^(.+\.php)(/.*)$;
        include fastcgi_params;
        fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param HTTPS $https;
        fastcgi_pass unix:/var/run/php-fpm-www.sock;
    }
}

Issue This is a standard php application with front controller and some static assets (js/css etc) sitting as files on the filesystem (for arguments sake the location of these files is '/site_root/web/assets').

The intention of the above config is to add 'max-age' headers to these static files to allow browsers to cache them. This works for all files which exist on the filesystem. However I have some assets which are dynamically generated and need to pass through php ('/site_root/web/assets/dynamic/file.uk.js', '/site_root/web/assets/dynamic/file.us.js', '/site_root/web/assets/variable/variable.uk.js').

The issue is that the inclusion of the location directive 'add headers to static files' is causing those dynamic files to 404. How can I either (in order of how desirable each solution is):

  • Change the location directive to exclude files which don't exist on the server (using try_files/internal?)

  • Change the location directive to exclude paths which match (a whitelist e.g 'dynamic|variable')

  • Why mot just name them file.uk.js.php? – Alexey Ten Jun 4 '15 at 7:28
5

Nginx only uses one location block

This comes down to the fact that nginx will only use one location block. Anything in other location blocks is ignored. In the question any request which matches the "static files" location block, whether the file exists or not, will be processed by that location block only. Whenever there's some ambiguity, I find a useful technique for debugging:

location /something-else {
    add_header "section" "something else location"; 
    # ^ if this location block is used, that header is in the output
    ...
}

In the headers for a response, the header added from the block which matched will be included:

$ curl -I "http://nginx.h5bp.dev/something"
...
section: something location # <- like so

Solutions

There are many solutions, and you might find this reference material useful to read. One thing to bear in mind is that nginx is intended to be used with prefix routing - that makes life easy for nginx, and you.

Prefix routing

So, if you can do this:

location ~ ^/(css|images|js)/ {
    expires 365d;
    add_header Pragma public;
    add_header Cache-Control "public";
}

location ~ \.php {
    ...
}

That would be the optimal solution. An extension to that using nested location blocks can also be used, if it's necessary:

location ~ ^/(css|images|js)/ {
    location ~* \.(?:whatever|ext)$ {
        expires 365d;
        add_header Pragma public;
        add_header Cache-Control "public";
    }
}

location ~ \.php {
    ...
}

Put try files in all location blocks

In the question, there is one location block - so this is an obvious alternative, as mentioned by Micheal:

location ~* \.(?:ico|css|js|gif|jpe?g|png|svg|woff|ttf|eot)$ {
    try_files $uri @rewriteapp; # <- added
    expires 365d;
    add_header Pragma public;
    add_header Cache-Control "public";
}

location ~ \.php {
    ...
}

If you have multiple location blocks though, this gets pretty tedious (though, also probably indicates not using nginx as designed)

404 Front controller

The will-always-work setup, irrespective of what your location blocks look like is to use a 404 front controller. In your case this would mean:

server {
    listen 8080;

    root /site_root/web;
    index index.html;

    server_name www.mysite.com;

    try_files $uri $uri/ @rewriteapp;
    error_page 404 = @rewriteapp

    location @rewriteapp {
        rewrite ^ /app.php/$request_uri last;
    }

    # add headers to static files
    location ~* \.(?:ico|css|js|gif|jpe?g|png|svg|woff|ttf|eot)$ {
        expires 365d;
        add_header Pragma public;
        add_header Cache-Control "public";
    }

    location ~ \.php {
        fastcgi_split_path_info ^(.+\.php)(/.*)$;
        include fastcgi_params;
        fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param HTTPS $https;
        fastcgi_pass unix:/var/run/php-fpm-www.sock;
    }
}

Or similar. Pick the solution that works for you and is the simplest.

| improve this answer | |
  • Thanks so much for this thorough answer - I'll review it today and let you know how I get on. – calumbrodie Jun 5 '15 at 6:41
  • Went for the 404 front controller, works perfectly. H5BP docs were useful as well. Thanks again – calumbrodie Jun 6 '15 at 12:50
1

Why don't you just pass them on to your application?

location ~* \.(?:ico|css|js|gif|jpe?g|png|svg|woff|ttf|eot)$ {
    try_files $uri @rewriteapp;
    #...everything else
| improve this answer | |
  • That will only work putting try files in each location block. A try files directive in server scope is only used if no location block matches the request. – AD7six Jun 3 '15 at 19:03
  • It's meant to go in the relevant location block. – Michael Hampton Jun 3 '15 at 19:16
  • @MichaelHampton I'm not really sure what you mean. I tried moving my 'asset' block above the first 'try files' block and I ended up with a 503 when trying to load my dynamic js file – calumbrodie Jun 3 '15 at 20:44
  • order of directives wont cause a 503 (and generally doesn't matter) - probably means you made a typo. This answer doesn't suggest reordering location blocks. – AD7six Jun 4 '15 at 9:11

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.