# Absolute rather than relative times in expires directives

**URL:** <https://www.ruby-forum.com/t/absolute-rather-than-relative-times-in-expires-directives/192527>\
**Category:** NGINX\
**Created:** [August 1, 2010, 11:25am UTC](https://www.ruby-forum.com/t/absolute-rather-than-relative-times-in-expires-directives/192527 "2010-08-01T11:25:03Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![elucify](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/f17d59/32.png) [@elucify](https://www.ruby-forum.com/u/elucify)\
**Post date:** [August 1, 2010, 11:25am UTC](https://www.ruby-forum.com/t/absolute-rather-than-relative-times-in-expires-directives/192527/1 "2010-08-01T11:25:03Z")

</div>

Hi,

I have a static HTML page that is updated at midnight each day. So I’d  
like to set its expires directive to an absolute  
rather than a relative time.

I was thinking of something like

```
expires at <crontab-line>

```

e.g. expires at 0 0 \* \* \*

My questions:

- Is there an existing solution?
- If not, is anyone working, or planning to work, on one?
- If not, would I have to write a core patch, or could it be done in  
an extension?
- If a core patch, is there a good chance it would be accepted?
- Can anyone suggest a better way than the above?

Perhaps I should just rely on mtime etags  
([GitHub - mikewest/nginx-static-etags: Nginx doesn't generate etags for static content. I'd like it to. Let's see if I can remember some C from college.](http://github.com/mikewest/nginx-static-etags)), and handle the extra  
requests  
and 304 responses.

Mark

---

<div class="post-metadata">

**Author:** ![elucify](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/f17d59/32.png) [@elucify](https://www.ruby-forum.com/u/elucify)\
**Post date:** [August 1, 2010, 11:52am UTC](https://www.ruby-forum.com/t/absolute-rather-than-relative-times-in-expires-directives/192527/2 "2010-08-01T11:52:34Z")

</div>

01.08.2010, 13:23, “Mark J.” [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):

> My questions:
> 
> ššš- Is there an existing solution?

Yes:  
expires @23h59m;

–  
br, Denis F. Latypoff.

---

<div class="post-metadata">

**Author:** ![elucify](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/f17d59/32.png) [@elucify](https://www.ruby-forum.com/u/elucify)\
**Post date:** [August 1, 2010, 1:40pm UTC](https://www.ruby-forum.com/t/absolute-rather-than-relative-times-in-expires-directives/192527/3 "2010-08-01T13:40:50Z")

</div>

On 08/01/10 19:51, Denis F. Latypoff wrote:

> 01.08.2010, 13:23, "Mark J."[removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):
> 
> > I have a static HTML page that is updated at midnight each day. So I’d like to set its expires directive to an absolute  
> > rather than a relative time.  
> > Yes:  
> > expires @23h59m;

Thanks Denis!

That form of the expires directive wasn’t in the English documentation  
at [GitHub - nginxinc/nginx-wiki: ARCHIVED -- Source for the now archived NGINX Wiki section of https://www.nginx.com · GitHub](http://wiki.nginx.org/NginxHttpHeadersModule) .

I’ve re-written the English documentation for the expires directive as  
best I could, which included adding the “@” and  
“modified” forms that were only in the Russian doc.

---

<div class="post-metadata">

**Author:** ![elucify](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/f17d59/32.png) [@elucify](https://www.ruby-forum.com/u/elucify)\
**Post date:** [August 1, 2010, 5:56pm UTC](https://www.ruby-forum.com/t/absolute-rather-than-relative-times-in-expires-directives/192527/4 "2010-08-01T17:56:02Z")

</div>

On Sun, Aug 01, 2010 at 09:57:16AM -0500, Ryan M. wrote:

> > > š š expires @23h59m;
> 
> Obviously, adding any RFC-compliant Cache-Control directive would be  
> desirable. The “public” keyword in particular is needed to allow  
> Firefox to cache images and the like which are delivered over SSL, and  
> “private” is clearly desirable for caching per-user information.  
> Others like “must-revalidate” are less useful in the general sense.
> 
> If this isn’t possible with the current implementation, please let me  
> know and I will take a look at trying to make a simple patch (my first  
> foray into nginx source instructed me that my C skills are way too  
> rusty for deep modification or module-writing with nginx).

These directives

expires @24h00m;  
add\_header Cache-Control private;

return

Expires: Sun, 01 Aug 2010 20:00:00 GMT  
Cache-Control: max-age=14809  
Cache-Control: private

–  
Igor S.

> **[Igor Sysoev](http://sysoev.ru/en/)**

---

<div class="post-metadata">

**Author:** ![elucify](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/f17d59/32.png) [@elucify](https://www.ruby-forum.com/u/elucify)\
**Post date:** [August 2, 2010, 3:15pm UTC](https://www.ruby-forum.com/t/absolute-rather-than-relative-times-in-expires-directives/192527/5 "2010-08-02T15:15:03Z")

</div>

2010/8/1 Igor S. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):

> > 
> 
> These directives
> 
> expires Â Â @24h00m;  
> add\_header Â Cache-Control Â private;
> 
> return
> 
> Expires: Sun, 01 Aug 2010 20:00:00 GMT  
> Cache-Control: max-age=14809  
> Cache-Control: private

Hmm… multiple Cache-Control header lines appear to be valid  
according to RFC 2616, but my fear would be that many popular browsers  
and caches would not behave sensibly with them.

Is anybody out there using multiple Cache-Control header lines for a  
public site in production?

I did some research looking at the HTTP headers used by the “major”  
web companies (Google, MSFT, Yahoo, etc.). I haven’t ever seen  
multiple Cache-Control header lines in a response, which makes me  
think that such a scenario is probably not well-supported by common  
browsers and proxies. In my past experience, Firefox treats just about  
anything except “public”,“private”, or “max-age” as “no-cache”. IE8  
seems to do the same, which I suppose is a safe default behavior if  
you don’t want to fully implement all the logic necessary to support  
all the allowable header combinations in the RFC.

–  
RPM

---

<div class="post-metadata">

**Author:** ![elucify](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/f17d59/32.png) [@elucify](https://www.ruby-forum.com/u/elucify)\
**Post date:** [August 1, 2010, 4:58pm UTC](https://www.ruby-forum.com/t/absolute-rather-than-relative-times-in-expires-directives/192527/6 "2010-08-01T16:58:40Z")

</div>

On Sun, Aug 1, 2010 at 6:39 AM, Mark J. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> Thanks Denis!
> 
> That form of the expires directive wasn’t in the English documentation at  
> [GitHub - nginxinc/nginx-wiki: ARCHIVED -- Source for the now archived NGINX Wiki section of https://www.nginx.com · GitHub](http://wiki.nginx.org/NginxHttpHeadersModule) .
> 
> I’ve re-written the English documentation for the expires directive as best  
> I could, which included adding the “@” and “modified” forms that were only  
> in the Russian doc.

It’s not in the English or Russian documentation, but is it possible  
to add any other Cache-Control directives along with expires?

For example, if you want “Cache-Control: private,max-age=300” you need  
to do it manually with add\_header instead of expires. But then you  
lose the ability to use the other “calculation” features of expires  
(like modified or @). You also don’t get an actual “Expires” header  
for HTTP/1.0 clients and proxies if you have to use add\_header  
instead.

Obviously, adding any RFC-compliant Cache-Control directive would be  
desirable. The “public” keyword in particular is needed to allow  
Firefox to cache images and the like which are delivered over SSL, and  
“private” is clearly desirable for caching per-user information.  
Others like “must-revalidate” are less useful in the general sense.

If this isn’t possible with the current implementation, please let me  
know and I will take a look at trying to make a simple patch (my first  
foray into nginx source instructed me that my C skills are way too  
rusty for deep modification or module-writing with nginx).

–  
RPM

---

<div class="post-metadata">

**Author:** ![elucify](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/f17d59/32.png) [@elucify](https://www.ruby-forum.com/u/elucify)\
**Post date:** [January 23, 2016, 4:29pm UTC](https://www.ruby-forum.com/t/absolute-rather-than-relative-times-in-expires-directives/192527/7 "2016-01-23T16:29:01Z")

</div>

On Thu, Jan 21, 2016 at 02:19:03AM -0500, rgrraj wrote:

Hi there,

> It works fine in 1.9.6. But on 1.9.2 with similar configruation its throwing  
> “expires” directive invalid value in sites-enabled file.  
> Any thoughts ?

“Use 1.9.6” would seem to be the easy option.

Failing that: what is the small configuration that does not do what you  
want in 1.9.2?

Copy-paste enough so that someone else can reproduce the problem that  
you are reporting.

Cheers,

## f

Francis D. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

---

<div class="post-metadata">

**Author:** ![elucify](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/f17d59/32.png) [@elucify](https://www.ruby-forum.com/u/elucify)\
**Post date:** [January 23, 2016, 2:52pm UTC](https://www.ruby-forum.com/t/absolute-rather-than-relative-times-in-expires-directives/192527/8 "2016-01-23T14:52:38Z")

</div>

HI Francis

Thanks for the same.

It works fine in 1.9.6. But on 1.9.2 with similar configruation its  
throwing  
“expires” directive invalid value in sites-enabled file.  
Any thoughts ?

Thanks  
Govind

Posted at Nginx Forum:

> **[Re: Absolute rather than relative times in expires directives](https://forum.nginx.org/read.php?2,115406,264031#msg-264031)**
>
> Hi, I have a static HTML page that is updated at midnight each day. So I'd like to set its expires directive to an absolute rather than a relative time. I was thinking of something like expires at \<crontab-line\> e.g. expires at 0 0

---

<div class="post-metadata">

**Author:** ![elucify](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/f17d59/32.png) [@elucify](https://www.ruby-forum.com/u/elucify)\
**Post date:** [January 24, 2016, 8:21am UTC](https://www.ruby-forum.com/t/absolute-rather-than-relative-times-in-expires-directives/192527/9 "2016-01-24T08:21:47Z")

</div>

Hi Francis

The same works like a charm in 1.9.6 but not in 1.9.2. The error log  
shows  
the follow,

“[emerg] 6151#0: “expires” directive invalid value in” respective sites  
enabled file.

And our configuration is just as follows,

## in nginx.conf

map $time\_iso8601 $expiresc {  
default “3h”;  
~T22 “@00h00”;  
~T23 “@00h00”;  
}

##in sites enabled file,  
location /path/to/files/ {  
expires $expiresc;  
}

doesnt allows to restart nginx and fails with the above error in nginx  
error  
log.

Any thoughts ??

Thanks  
Govind

Posted at Nginx Forum:  
[https://forum.nginx.org/read.php?2,115406,264082#msg-264082](https://forum.nginx.org/read.php?2,115406,264082#msg-264082)

---

<div class="post-metadata">

**Author:** ![elucify](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/f17d59/32.png) [@elucify](https://www.ruby-forum.com/u/elucify)\
**Post date:** [January 25, 2016, 4:05pm UTC](https://www.ruby-forum.com/t/absolute-rather-than-relative-times-in-expires-directives/192527/10 "2016-01-25T16:05:00Z")

</div>

Hello!

On Sun, Jan 24, 2016 at 02:21:01AM -0500, rgrraj wrote:

> map $time\_iso8601 $expiresc {
> 
> doesnt allows to restart nginx and fails with the above error in nginx error  
> log.

The message suggests that you are using not 1.9.2, but an older  
version without variables support in the expires directive.

Variables support in the expires directive was introduced in nginx  
1.7.9, see [Module ngx\_http\_headers\_module](http://nginx.org/r/expires).

–  
Maxim D.

> **[nginx](http://nginx.org/)**

---

<div class="post-metadata">

**Author:** ![elucify](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/f17d59/32.png) [@elucify](https://www.ruby-forum.com/u/elucify)\
**Post date:** [January 24, 2016, 2:45pm UTC](https://www.ruby-forum.com/t/absolute-rather-than-relative-times-in-expires-directives/192527/11 "2016-01-24T14:45:34Z")

</div>

[http://nginx.org/en/CHANGES:](http://nginx.org/en/CHANGES:)  
Changes with nginx 1.9.7 17 Nov  
2015  
…  
\*) Bugfix: the “expires” directive might not work when using  
variables.

## Using the latest version of the branch​ might solve problems…

_B. R._

---

<div class="post-metadata">

**Author:** ![elucify](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/f17d59/32.png) [@elucify](https://www.ruby-forum.com/u/elucify)\
**Post date:** [February 1, 2016, 6:24am UTC](https://www.ruby-forum.com/t/absolute-rather-than-relative-times-in-expires-directives/192527/12 "2016-02-01T06:24:57Z")

</div>

Hi

Thank you all for the suggestions and thoughts.

I did double check the nginx version I am having and it is 1.9.2.  
root@ser2:~# nginx -V  
nginx version: nginx/1.9.2  
built by gcc 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)  
configure arguments:  
–add-module=/tmp/nginx/ngx\_http\_substitutions\_filter\_module-master  
–add-module=/tmp/nginx/headers-more-nginx-module-0.26  
–add-module=/tmp/nginx/ngx\_pagespeed-release-1.9.32.3-beta  
–sbin-path=/usr/local/sbin/nginx --conf-path=/etc/nginx/nginx.conf  
root@ser2:~#

but when I use the expires directive it shows invalid error same as  
before.

Seems like to get the feature I need to update the nginx version.

Thanks  
Govind

Posted at Nginx Forum:

> **[Re: Absolute rather than relative times in expires directives](https://forum.nginx.org/read.php?2,115406,264224#msg-264224)**
>
> Hi, I have a static HTML page that is updated at midnight each day. So I'd like to set its expires directive to an absolute rather than a relative time. I was thinking of something like expires at \<crontab-line\> e.g. expires at 0 0

---

<div class="post-metadata">

**Author:** ![elucify](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/f17d59/32.png) [@elucify](https://www.ruby-forum.com/u/elucify)\
**Post date:** [February 1, 2016, 10:14am UTC](https://www.ruby-forum.com/t/absolute-rather-than-relative-times-in-expires-directives/192527/13 "2016-02-01T10:14:30Z")

</div>

On Mon, Feb 01, 2016 at 12:24:22AM -0500, rgrraj wrote:

Hi there,

> Thank you all for the suggestions and thoughts.
> 
> I did double check the nginx version I am having and it is 1.9.2.

> but when I use the expires directive it shows invalid error same as before.
> 
> Seems like to get the feature I need to update the nginx version.

All I can say is: it works for me.

“http” section of nginx.conf:

===  
http {  
map $time\_iso8601 $expiresc {  
default “3h”;  
~T22 “@00h00”;  
~T23 “@00h00”;  
}

```
server {
    listen 8080;
    location /a/ {
        expires $expiresc;
    }
}

```

# }

Selected output from

$ curl -i [http://127.0.0.1:8080/a/b](http://127.0.0.1:8080/a/b)

HTTP/1.1 200 OK  
Server: nginx/1.9.2  
Date: Mon, 01 Feb 2016 09:09:06 GMT  
Expires: Mon, 01 Feb 2016 12:09:06 GMT  
Cache-Control: max-age=10800

If you get different output, it may be worth investigating properly what  
is happening.

But it may be simpler to just deploy your tested-working version.

Good luck with it,

## f

Francis D. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

---

<div class="post-metadata">

**Author:** ![elucify](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/f17d59/32.png) [@elucify](https://www.ruby-forum.com/u/elucify)\
**Post date:** [February 1, 2016, 1:45pm UTC](https://www.ruby-forum.com/t/absolute-rather-than-relative-times-in-expires-directives/192527/14 "2016-02-01T13:45:23Z")

</div>

Hello!

On Mon, Feb 01, 2016 at 12:24:22AM -0500, rgrraj wrote:

> –add-module=/tmp/nginx/headers-more-nginx-module-0.26  
> –add-module=/tmp/nginx/ngx\_pagespeed-release-1.9.32.3-beta  
> –sbin-path=/usr/local/sbin/nginx --conf-path=/etc/nginx/nginx.conf  
> root@ser2:~#
> 
> but when I use the expires directive it shows invalid error same as before.

This likely means that nginx you are checking for “nginx -V” is  
not the same as one that really works. This may happen if you  
have more than one nginx binary (e.g., one in /usr/, and another  
one in /usr/local), or you haven’t restarted/upgraded running  
nginx binary after upgrading nginx on disk, see here:

> **[Controlling nginx](http://nginx.org/en/docs/control.html#upgrade)**
>
> nginx can be controlled with signals. The process ID of the master process is written to the file /usr/local/nginx/logs/nginx.pid by default. This name may be changed at configuration time, or in nginx.conf using the pid directive. The master process...

–  
Maxim D.

> **[nginx](http://nginx.org/)**
