Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

I'm trying to get a rewrite rule working and I've discovered that if the URL begins with a question mark, Nginx fails to return 404 error as expected. Instead, index.html as defined in the root directive is served for all urls beginning with "?". (e.g. example.com/?page-does-not-exist works for the home page but should not)

This is making it impossible to get a redirect from example.com/?format=feed&type=rss -> example.com/rss.xml working. This is for a blog migrated from Joomla to Jekyll.

Put simply, visiting example.com/123 returns a 404, and visiting example.com/?123 does not. The latter returns the site's home page at the URL example.com?/123. (There is no file or folder '123', so requests for it should always fail.)

Everything works perfectly with the site, including the HTTPS redirect, except for the expected 404 redirects not happening for URLs starting with a question mark. How do I fix this?

Here's my configuration:

server {
    server_name example.com;
    root /var/www/example.com;
    index index.html;
    listen 443;
    ssl on;      
    ...

    rewrite "/?format=feed&type=rss" https://example.com/rss.xml permanent;

    location ~* \.(?:ico|css|js|gif|jpeg|jpg|png|txt|svg|eot|woff|ttf)$ {
            expires max;
            add_header Pragma public;
            add_header Cache-Control "public, must-revalidate, proxy-revalidate";
            add_header Access-Control-Allow-Origin *;
            valid_referers none blocked example.com;
            if ($invalid_referer) {
                    return 403;
            }
    }
}

# HTTP --> HTTPS
server {
        listen 80;
        server_name www.example.com example.com;
        return 301 https://example.com$request_uri;
}
share|improve this question

2 Answers 2

up vote 3 down vote accepted

The question mark signifies the end of the path portion of the uri and the beginning of the query string. Hence why nginx will not return 404 based on the portion after the question mark; the requested resource does exist and the query string parameters are just passed to it.

Regarding the other part of the question, I believe that nginx's rewrite statement does not actually match against the query string portion of the uri.

You should however be able to do something along the lines of:

if ($args ~ "format=feed&type=rss") {
    rewrite ^ https://example.com/rss.xml? permanent;
}
share|improve this answer
    
Nginx's docs say 'if is evil' and recommend against using it, plus this unfortunately didn't work when I just tested it. I still get the home page for example.com/?format=feed&type=rss instead of a redirect or 404. –  Tom Brossman Apr 18 at 22:36
    
Do you actually have & in your query strings? I assumed that was a mistake in the question and you really meant &? (HTML encoding things in the query string seems like really weird practice.) –  Håkan Lindqvist Apr 18 at 22:38
    
I have subscribers requesting both types subscribed to the RSS feed, so ultimately I'd like both to work. I'm getting hits for /?format=feed&type=rss and /?format=feed&type=rss. –  Tom Brossman Apr 18 at 22:41
    
Ok, and my suggestion does not work for the /?format=feed&type=rss case? (Which seems like the sane case.) –  Håkan Lindqvist Apr 18 at 22:44
    
No, didn't work and I'm sure I copied it exactly. it returns example.com/rss.xml?format=feed&type=rss with a "The page isn't redirecting properly" error. Tested with it in the main server block + in a location / {...} block, same thing. (plus obviously reloading Nginx each time. –  Tom Brossman Apr 18 at 22:59

NGinx interprets everything that follows a ? as a query string, not as a path.

It will only return a 404 for a non-existing path, not for a query string.

eg :

  • example.com/123 : if path /123 exists and if there is an index file for this path then it's OK, else it will return a 404

  • example.com/?123 : if there is an index file in the root directory for example.com then it's OK. It does not check if directory ?123 exists as it does not consider this as a path but as a query string.

share|improve this answer
    
So is it possible to either redirect or rewrite requests for example.com/?123 to something else. or is this impossible with Nginx? (I can ask this as a new question if that's best) –  Tom Brossman Apr 18 at 22:38
    
You are right to ask it here, i think it's possible, will have look at it right now. But there is something that confuse me : you do a rewrite for /?format=feed&type=rss, so i am not sure which exact case you want to handle. –  user216707 Apr 18 at 22:42
    
Joomla's default RSS feed for the old site was example.com/?format=feed&type=rss which some feed readers (I'm guessing?) replace with example.com/?format=feed&type=rss as the second type has 3x the hits in my logs. I want both to redirect or rewrite to example.com/rss.xml permanently –  Tom Brossman Apr 18 at 22:49
1  
So the previous answer provides the solution. IfIsEvil, for sure, but have a look at the first sample on the IfIsEvil page : There are cases where you simply cannot avoid using an if –  user216707 Apr 18 at 22:58

Your Answer

 
discard

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.