Home > nginx, WordPress > Finally using nginx's "try_files" directive

Finally using nginx's "try_files" directive

OLD:

error_page 404 = /wordpress/index.php?q=$request_uri;

or:

if (!-e $request_filename) {
   rewrite ^/(.*) /wordpress/index.php?uri=$request_uri last;
}

NEW:

try_files $uri $uri/ /wordpress/index.php?q=$uri&$args;

Why make life more complicated if you don't need to?

Also thanks to Igor's patch you can have multiple of these, i.e.:

location /wordpress {
   try_files $uri $uri/ /wordpress/index.php?q=$uri&$args;
}

location /anotherapp {
   try_files $uri $uri/ /anotherapp/controllerfile.php?q=$uri&$args;
}

etc.

This is good, as Drupal, WordPress and many other packages (including anything I develop anymore) use the Front Controller pattern of development, which makes deploying applications a lot simpler and helps support a consistent framework across the entire application.

NOTE: Updated on 1/5/10 to include the $args 🙂

Categories: nginx, WordPress
  1. Vahid
    March 25th, 2009 at 19:28 | #1

    So how exactly would this look like in a normal nginx config, is that all we post?

  2. mike
    March 26th, 2009 at 00:07 | #2

    Well, for example my config is so... I use this site for wordpress or normal physical files, so no other apps. Otherwise I'd need to throw in some more location {} blocks. But I like to keep it simple.

    server {
       listen 80;
       server_name michaelshadle.com;
       index index.php index.html;
       root /home/mike/web/michaelshadle.com;
       include /etc/nginx/defaults.conf;
       include /etc/nginx/expires.conf;
       try_files $uri $uri/ /wordpress/index.php?q=$uri;
       location ~ \.php$ {
          fastcgi_pass 127.0.0.1:11000;
       }               
    }
    
  3. Dr Tux
    March 29th, 2009 at 02:36 | #3

    Hmm.. seems that this requires wordpress to be installed into directory, not at the main url, ie http://site.com/blog instead of http://site.com - I got myself a rewrite loop with this since my wordpress uses later configuration. Still looking into it.
    Dr T

  4. mike
    March 29th, 2009 at 12:29 | #4

    Have you tried nginx 0.7.44? I believe he put in the fix that stops the infinite redirection. At least with location /foo { try_files with handler /foo/foo.php } - that was a bug/something that did not work in 0.7.43 without a patch.

    If not, post it on the mailing list. Perhaps it's something he can patch.

  5. Flynn
    May 4th, 2009 at 07:25 | #5

    Works well for me, with WordPress (2.7.1) in the domain root:

    try_files $uri $uri/ /index.php?q=$uri;
    

    Nginx 0.7.50

  6. Jason
    May 24th, 2009 at 14:34 | #6

    I've got an issue where everything works but I cannot page my posts on the main page (ie "older posts" link). The important part is my permalink setting is category/postname. Paging works great everywhere except index.php.

    Any ideas?

  7. mike
    May 24th, 2009 at 20:40 | #7

    Post your entire config to pastebin or something. ask on #nginx on freenode, or the nginx mailing list.

  8. Andrew
    June 11th, 2009 at 14:31 | #8

    So, I got this to work by updating to the latest stable build (0.7.59) but I can't get any images, styleshets or js code to even show.

    Any clue how I can fix that?

  9. Andrew
    June 11th, 2009 at 14:44 | #9

    I was able to fix it by adding this location directive (I put it right below the main /)

    location ~* ^.+\.(htm|html|jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|doc|xls|exe|pdf|ppt|txt|tar|mid |midi|wav|bmp|rtf|js)$ {
       root /;
    }
    
  10. mike
    June 11th, 2009 at 15:23 | #10

    That does not look right at all. That's setting the root to be the root of your filesystem?

  11. lury
    July 15th, 2009 at 03:43 | #11

    Thank you!

    this fixed redirect loop problem with drupal, nginx and imagecache...
    but i have no idea how.

  12. mike
    July 15th, 2009 at 08:05 | #12

    I will issue a statement of caution - with Drupal, it will work, but depending on the plugins and modules you use it might break. This is something I need to draft up in a bug or something.

    I used to be able to have just:

    try_files $uri $uri/ /index.php?q=$uri&$args;
    

    However, $uri winds up inheriting a "/" at the beginning which breaks certain code. WordPress handles it just fine. Drupal can too, probably with a very simple line of code in how it parses URIs. For now this appears to be the safest bet:

    if (!-e $request_filename) {
       rewrite ^/(.*)$ /index.php?q=$1 last;
    }
    

    Note: Drupal also hosts some stuff people shouldn't be accessing in the webroot (ugh) so marking those in a block as "internal" will keep people from accessing them. I still haven't validated that rule yet (I am just starting to support Drupal) but I always maintain my "do it in the simplest possible way" rule. A lot of the examples out there look like a mess and can probably be done a hell of a lot cleaner.

  13. Otto
    July 17th, 2009 at 07:40 | #13

    Why are you adding the ?q= stuff? It's not necessary in the slightest.

    if (!-e $request_filename) {
       rewrite ^ /index.php last;
    }
    

    Done. WordPress handles parsing the URL internally, all you have to do is force index.php to load. That's it.

  14. Otto
    July 17th, 2009 at 07:42 | #14

    Or, if you prefer try_files:

    try_files $uri $uri/ /wordpress/index.php;
    
  15. mike
    July 17th, 2009 at 08:18 | #15

    you are right. just a habit i suppose. might be interesting to look at the internals though, forcing the "q" parameter might cut down on some processing overhead (or vice-versa)

    i need to look into trying to submit a patch to drupal to get them to handle the stuff with a / prefix being ignored. or ask someone. it must be a simple fix.

  16. jason wagner
    October 5th, 2009 at 11:13 | #16

    Thank you!! The try_files line worked perfect for me.

    location /blog/ {
       try_files $uri $uri/ /blog/index.php?q=$uri;
    }
    
  17. Matthias Marschall
    March 11th, 2010 at 02:38 | #17

    We're using the permalink settings by wordpress. An article gets an URL like: http://www.agileweboperations.com/20-devops-guys. I cannot make it work:

    The try_files approach works for the homepage and the backoffice (/wp-admin), but not for the pretty permalink urls.

    The !-e approach works for home and permalinks but does not recognize /wp-admin as an existing directory and tries to redirect, too, which fails.

    Anyone experienced similar issues? If it helps I can post my full nginx.conf of course...

  18. makuchaku
    April 18th, 2010 at 21:01 | #18

    OMG! Can't tell you that how many people you have saved from going insane 😀
    Thanks for your post - just what's needed 🙂

  19. Ben
    May 5th, 2010 at 20:20 | #19

    Thank you so much for this, it took me ages to find that I had to add &$args, something none of the other examples on other websites have shown, there are a few small things such as the theme preview in the WordPress admin that require this in order to work.

  20. chico200987
    October 26th, 2010 at 15:33 | #20

    Thank you very much, you get me out of the hell ! ;p

  1. No trackbacks yet.
You must be logged in to post a comment.