Server Fault is a question and answer site for system and network administrators. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I have these rewrite rules (I tried both with no avail):

location ~* "^/([a-z0-9]{32})\.png$" {
  rewrite ^ /index.php?page=log&id=$1 last;


location ~* "/(?<hash>[a-z0-9]{32})\.png" {
  rewrite ^ /index.php?page=log&id=$hash;


location / {
  try_files $uri $uri/ @rewrites;

location @rewrites {
  rewrite "^/([a-zA-Z0-9]{32})\.png$" /index.php?page=log&id=$1 last;

Basically, I want the URL to actually pass the parameters to my index.php script, and in the script, I got:

header('Content-type: image/png');

But nginx is giving me a "not found", but other rewrites work fine. What gives?

share|improve this question
i'm using nginx 1.2.1 on ubuntu 12.10 – pocesar Jan 17 '13 at 4:51
I can confirm the first method by unlo works. Could you post your error logs and the context in which you put the rewrite? – Sašo Jan 17 '13 at 18:47
for example this is a recent one 2013/01/17 15:21:31 [error] 3276#0: *20993 open() "/var/www/site/b14ad9f3b159f58e4f559662c12d9dcd.png" failed (2: No such file or directory), client: x.x.x.x, server: site, request: "GET /b14ad9f3b159f58e4f559662c12d9dcd.png HTTP/1.1", host: "site", referrer: "" nothing else, no errors. The rewrite is inside /etc/nginx/sites-enabled/site nothing special – pocesar Jan 17 '13 at 19:07
From seeing that I can only tell that the rewrite is either never reached or is completely ignored. Do you have breaks elsewhere, perhaps in a .png$ location? – Sašo Jan 17 '13 at 19:16
nope, that's my only rewrite with pngs. every other rewrite, url based, are below this one, so it wouldn't matter, is there any way I debug all the rewrites that happen, in order, and dump to a file? – pocesar Jan 17 '13 at 19:19
up vote 0 down vote accepted

As per nginx documentation of how the location directive works:

A location can either be defined by a prefix string, or by a regular expression. ... A search of regular expressions terminates on the first match, and the corresponding configuration is used.

Based on addition information from your own answer to this very question, it would seem like you intend on having several location directives to apply simultaneously right at the very same time, which is explicitly not allowed as per the unambiguous documentation.

Remember, nginx is faster and cleaner by design. So, don't expect the quirks!

share|improve this answer
I see, I thought they would 'cascade', so it would work somehow like apache... thanks for clearing that out! – pocesar Jan 24 '13 at 16:44

this one worked for me:

    location / { 
    rewrite "/([a-z0-9]{32})\.png" /index.php?page=log&id=$1 break;

Or if you want separeted location:

location ~* "/([a-z0-9]{32})\.png" {
rewrite /(.*) /index.php?page=log&id=$1 last;
share|improve this answer
didn't work, same 404 error – pocesar Jan 17 '13 at 4:50
could you post all nginx conf? i think you have a more detailed location, which can match request even if its located below rewrite rule... – unlo Jan 18 '13 at 12:43
i enabled rewrite_log in the config, but the regexp isn't even showing there... it's going directly to error.log, failed (2: No such file or directory) – pocesar Jan 23 '13 at 20:28
see if you can fix my answer – pocesar Jan 23 '13 at 21:17
So, you have much preferred location in expires.conf: # Media: \.(?:jpg|jpeg|gif|png|ico|gz|svg|svgz|mp4|ogg|ogv|webm)$. And i think, include of h5bp located before redirect rule, am i right? You must place our rule before include or remove png from expires.conf location. – unlo Jan 24 '13 at 12:54

While @unlo's answer seems correct to me (tried myself on a clean virtualhost), I see one more optimisation. Instead of serving a static file by your script, you may want to use XSendFile feature to make nginx serve these files.

share|improve this answer
how could I do that? – pocesar Jan 23 '13 at 17:23

Mark pointed out so I started removing all the included files, and boiled down to:


that contains

# Basic h5bp rules

include /etc/nginx/conf.d/expires.conf;
include /etc/nginx/conf.d/x-ua-compatible.conf;
include /etc/nginx/conf.d/protect-system-files.conf;

the expires.conf got

# Expire rules for static content

# No default expire rule. This config mirrors that of apache as outlined in the
# html5-boilerplate .htaccess file. However, nginx applies rules by location,
# the apache rules are defined by type. A concequence of this difference is that
# if you use no file extension in the url and serve html, with apache you get an
# expire time of 0s, with nginx you'd get an expire header of one month in the
# future (if the default expire rule is 1 month). Therefore, do not use a
# default expire rule with nginx unless your site is completely static

# cache.appcache, your document html and data
location ~* \.(?:manifest|appcache|html|xml|json)$ {
  expires -1;
  access_log /var/log/nginx/static.log;

# Feed
location ~* \.(?:rss|atom)$ {
  expires 1h;
  add_header Cache-Control "public";

# Favicon
location ~* \.ico$ {
  expires 1w;
  access_log off;
  add_header Cache-Control "public";

# Media: images, video, audio, HTC
location ~* \.(?:jpg|jpeg|gif|png|ico|gz|svg|svgz|mp4|ogg|ogv|webm)$ {
  expires 1M;
  access_log off;
  add_header Cache-Control "public";

# CSS and Javascript
location ~* \.(?:css|js)$ {
  expires 1y;
  access_log off;
  add_header Cache-Control "public";

# WebFonts
# If you are NOT using cross-domain-fonts.conf, uncomment the following directive
location ~* \.(ttf|ttc|otf|eot|woff|font.css)$ {
  expires 1M;
  access_log off;
  add_header Cache-Control "public";

commenting that expires.conf, then it starts working, how can I fix this?

share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.