Adding the Expires header to improve caching static content in nginx
Nginx makes it very easy to define headers to improve the caching of static resources such as images, style sheets and JavaScript files. To accomplish this task, we only need a few things to configure.
MIME types configuration
First we have to ensure that the configuration of the MIME types are correct. MIME is short for Multipurpose Internet Mail Extensions and defines what a specific file contains. For example, a file with the file extension .png is most likely a PNG file. Or in MIME language, a image/png. The first part is the category (an image), the second one the specific type (PNG). An HTML file is text and is mapped as text/html.
The definitions of the MIME types are usually stores in a file mime.types. The main configuration file of nginx, which is typically /etc/nginx/nginx.conf, usually already includes it by default.
http {
include /etc/nginx/mime.types;
}
Check your configuration if this is the case. Also check if it has a set of defined MIME types.
Define a map
The second step is to set a map and use the sent_http_content_type variable. This contains the value that the server will return to the client, based on the definition it found in the MIME types.
map $sent_http_content_type $example_com_expire_time {
application/javascript 1d;
application/json 1d;
application/pdf 90d;
font/woff 90d;
font/woff2 90d;
~image/ 7d;
image/jpeg 30d;
image/png 30d;
image/svg+xml 30d;
image/webp 30d;
image/x-icon 30d;
text/css 1d;
text/html 1h;
text/xml 4h; # atom.xml
default 4h;
}
Tip: if you have multiple virtual hosts configured, include the name of your virtual host in the variable that ends with expire_time. This way configuration settings won’t conflict with each other, resulting in unexpected caching values.
In the map above we defined several common MIME types. The default line tells what the default value is, when the MIME type does not match any of the defined ones. In this case we set the value to four hours, but by setting is to ‘off’, you can disable caching for unspecified types.
Configure your virtual host
With the map in place, it is time to enable the setting. This is usually done in your server definition, the place where the virtual host is configured. This way all returned files will receive the related header.
http {
server {
server_name example.com;
### Caching
expires $example_com_expire_time;
location / {
# ... configuration
}
}
}
Restart nginx and test
After saving the changes, perform a configuration test first.
nginx -t
Now we can use a tool like curl to test if our headers are set correctly.
curl --head https://example.com
If all is well, you most likely will see the following two headers:
- Expires
- Cache-Control
The Expires will show you the actual date and time, where the Cache-Control defines the time in seconds (with max-age).
Bonus tip: automated testing
To easily test if all your file types are correct, consider using a configuration file that can be used together with curl. Then insert multiple types of requests on your website, such as the home page, the path to the logo, your sitemap, your robots.txt, etc. This way you can easily repeat the test and see if multiple MIME types are properly detected and get the right caching instructions. See the cheat sheet for all tips regarding using curl.
» Mastering the tool: curl cheat sheet
curl cheat sheetConclusion
Setting headers to allow clients to cache static content is fairly easy to do. Define the right map, insert the header, and finally test if everything is working as expected.
Did you already secure your nginx configuration? Have a look at the nginx security hardening guide.