To be able to use the Expires header, mod_expires must be enabled in your Apache configuration. You can confirm this on CentOS using the following command:
httpd -M | grep -i expires
This module controls the Expires HTTP header settings and the Cache-Control HTTP header max-age directives. This should be installed by default on most servers.
If the current date is Mar 2, 2019, the following shows that the Expires headers for a .png resource is set for 4 months:
$ curl -LI https://domain.tld/wp-content/uploads/2018/12/img-023-144x144.png HTTP/1.1 200 OK Date: Sun, 03 Mar 2019 04:38:32 GMT Server: Apache Last-Modified: Tue, 25 Dec 2018 11:42:14 GMT Accept-Ranges: bytes Content-Length: 10603 Cache-Control: max-age=10368000, public Expires: Mon, 01 Jul 2019 04:38:32 GMT Vary: Accept-Encoding Content-Type: image/png
Here is the .htaccess rule confirming this:
[root@host public_html]# grep png .htaccess | grep -i expires ExpiresByType image/png "access plus 4 months" [root@host public_html]#
This shows that Expires is working.
Occasionally, you may test your landing page on some 3rd-party tools and they will inform you that Expires are not working. What they should say is that Expires are not set and working for *all* resources used on the landing page.
If you instead curl a single resource from your site that you have explicitly set expiration rules for, then you can see the output like that shown above. The landing page is often returned as text/html Content-Type, but it usually doesn't give the same headers that are given when testing a single resource.
You can go further and change the setting to make sure the change is detected when testing. Initially, html was set 0 for this one resource:
[root@host public_html]# grep -i expires .htaccess | grep -i html ExpiresByType text/html "access plus 0 seconds" [root@host public_html]#
If you change the expires time for html to something else, it should then be detected. I've tested this using the readme.html file by setting it to 10 days:
Before changing from 0, it shows the current date:
$ curl -I https://domain.com/readme.html HTTP/1.1 200 OK Date: Sun, 03 Mar 2019 04:37:07 GMT Server: Apache Accept-Ranges: bytes Content-Length: 7425 Cache-Control: max-age=0, public Expires: Sun, 03 Mar 2019 04:37:07 GMT Vary: Accept-Encoding,User-Agent X-Powered-By: WP Rocket/3.2.6 Content-Type: text/html; charset=UTF-8
After changing to 10 days, it shows 10 days from now:
$ curl -I https://domain.com/readme.html HTTP/1.1 200 OK Date: Sun, 03 Mar 2019 04:53:59 GMT Server: Apache Accept-Ranges: bytes Content-Length: 7425 Cache-Control: max-age=864000, public Expires: Wed, 13 Mar 2019 04:53:59 GMT Vary: Accept-Encoding,User-Agent X-Powered-By: WP Rocket/3.2.6 Content-Type: text/html; charset=UTF-8
If you want your landing page to show these headers as well, you may have to consult your developer for help in identifying what resources exist on the landing page but do not have expirations set in the .htaccess.