« Back to Web

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 sheet

Conclusion

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.

Relevant commands in this article

Like to learn more about the commands that were used in this article? Have a look, for some there is also a cheat sheet available.

Feedback

Small picture of Michael Boelen

This article has been written by our Linux security expert Michael Boelen. With focus on creating high-quality articles and relevant examples, he wants to improve the field of Linux security. No more web full of copy-pasted blog posts.

Discovered outdated information or have a question? Share your thoughts. Thanks for your contribution!

Mastodon icon