When a web server serves content to a user, the content is usually cached in the user’s browser. If there is a proxy between the user and the web server, the content is often cached there as well. It is not uncommon for the server administrator to want to control how long the content is cached.
If the content is cached for too long, the user could be presented with outdated information. So you might want to shorten the max-age value. Likewise, if the content is not cached or for too short of a time, the user might experience slower load times since the browser will have to fetch every file from the web server. Even if it has been retrieved before.
This is where the Cache-Control header comes in. Specifically the max-age directive within the header.
The max-age directive instructs the caching software how long after the content is generated, it should be cached. The value is specified in seconds.
So to control the max-age value, we will have to manipulate the HTTP response headers Apache sends when responding to the user’s request. I will try to show you the simplest way to do this below.
Load mod_headers module
In order to set the max-age directive, we will have to inject the cache-control header directly into the response headers. The simplest way to do this is to use mod_headers. Mod_headers is an apache module that allows us to manipulate the HTTP headers apache sends in response to a request.
This module is usually not loaded by default, so we will have to make sure it is loaded before we continue.
Let’s quickly enable it using the a2enmod utility:
sudo a2enmod headers
The output of this command should look like this:
Enabling module headers. To activate the new configuration, you need to run: systemctl restart apache2
Next, we will restart Apache so it will reload all modules. Assuming your Linux distribution uses Systemd, the command should be:
sudo systemctl restart apache2
The mod_headers module should be loaded now. But we can make sure by querying apache using the a2query utility:
a2query -m headers
If everything went as planned, apache should reply that the module is enabled:
headers (enabled by site administrator)
Set the cache-control header
We are now ready to inject some headers. First of all, find the place you will set the header in your configuration. Most likely this will be in the virtualhost configuration for your site. Something like /etc/apache2/sites-enabled/000-default.conf.
In the first example, we will set the Cache-control header for the whole HTML root directory. We want the content to be cached for up to 24 hours, so we will set the equivalent time in seconds, 86400 (60*60*24=86400).
<Directory /var/www/html> Header set Cache-Control "max-age=86400" </Directory>
In some cases, you might want to check if mod_headers is available. Because if you try to set the headers and the mod_headers module is not loaded, starting apache will fail.
In that case, just wrap the Header command in an IfModule directive as below:
<Directory /var/www/html> <IfModule headers> Header set Cache-Control "max-age=86400" </IfModule> </Directory>
Set max-age for some file extensions
In many cases, it can be beneficial to set longer max-age for some file extensions. Like in this example, where we set the max-age value for some popular image formats to one week:
<FilesMatch ".(ico|png|jpg|jpeg|webp)$"> Header set Cache-Control "max-age=604800" </FilesMatch>
Common max-age settings
Max-age is expressed in seconds. If you have been in this business for a while, you probably remember some of the most common values. Like 86400 for 24 hours and 3600 for one hour. But I usually have to calculate the value for some time values I don’t use often. So to spare you some time, I have created a table with some common values.
Set max-age to zero
There are two ways to disable caching for a response. Either set the max-age to 0 (zero) or use the no-cache directive. That means the following two lines will have about the same effect:
Header set Cache-Control: no-cache Header set Cache-Control "max-age=0"
Public vs. Private
One thing to take into account when setting the Cache-Control header is if the content can be cached for multiple users. In some scenarios, the cache is shared among multiple users. Think proxy servers or CDN.
It is possible that the content is generated specifically for each user with the same filename, like a page where the user is logged in. In this scenario, you do not want to risk the user being shown content that was generated for some other user using the same cache. So you may want to make sure that the file is only cached for this particular user.
To request that the content is only cached for this particular user, you should add the private directive. This would, in most cases, mean that the information is only cached in the user’s own browser.
Header set Cache-Control "max-age=86400, private"
Likewise, if the content is shared among all users, you should definitely set the public directive. This may speed up loading times for some users.
Header set Cache-Control "max-age=86400, public"