0x29 - nginx: Adding expiration headers
Today I was confronted with the tas of setting a proper expiration header to asset files. As a reminder: this is the aim:
- when requesting an existing file with an additional timestamp parameter (i.e. "?123") add an expiration header.
- when requesting an existing file without an additional timestamp parameter don't add an expiration header.
- when requesting a non-existing file pass on the request to the passenger application.
After surfing the web for ages I found no working solution. In any case, the following did the trick. Read below for an explanation and how I checked this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# Server settings. server_name and path should match.
server {
listen 80;
server_name server.dev;
root /Users/me/sites/server/public;
index index.html index.htm;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
sendfile on;
location / {
if (-f $request_filename) {
set $file X;
}
if ($args ~* ^[0-9]+$) {
set $file "${file}C";
}
# existing and can be kept by the client?
if ($file = "XC") {
expires 365d;
}
# Doesn't exist? Go to rails app
passenger_enabled on;
rails_env production;
}
}
This takes the following into account:
- The location value doesn't include the request query parameter
- This solution adds expiration headers to all requests where a file exists, not only to the "classical" asset requests.
- For some reason that I don't understand I had to put the "passenger_enabled" and "rails_env" inside the location block. Otherwise the rails application would never pick up any request with a file extension.
After I was done I found an apparently working configuration with a different (and I must say more elegant) approach in the comment section over at Craig's. It is sad you find the good stuff only after banging your head for hours :)
And this is how I tested it:
-
Get the robots.txt file, it must not contain an "Expires" header:
1 2 3 4
~/site> curl -I http://server.dev/robots.txt HTTP/1.1 200 OK Server: nginx/0.7.61 ...
-
Get the robots.txt file, with a time stamp; it must contain an "Expires" header:
1 2 3 4 5 6 7
~/site> curl -I http://server.dev/robots.txt?1234 HTTP/1.1 200 OK Server: nginx/0.7.61 Date: Fri, 13 Nov 2009 00:01:23 GMT Last-Modified: Sat, 08 Aug 2009 20:28:57 GMT Expires: Sat, 13 Nov 2010 00:01:23 GMT ...
-
Get a dynamically created javascript file; it must not contain an "Expires" header, but must refer to Phusion Passenger in the "Server" header, and this regardless of whether or not a timestamp is set:
1 2 3 4 5 6 7
~/sites/whispler> curl -I http://server.dev/xx.js?1234 ... Server: nginx/0.7.61 + Phusion Passenger 2.2.5 (mod_rails/mod_rack) ~/sites/whispler> curl -I http://server.dev/xx.js ... Server: nginx/0.7.61 + Phusion Passenger 2.2.5 (mod_rails/mod_rack)