title: How to remove trailing slash from URL in nginx only if directory doesn't exist?
body: <p>I am running a server on nginx 1.4.1 with PHP-FastCGI.  Currently I have it setup so that it removes trailing slashes from my URLs and issues a 301 redirect.  However, when I visit a directory that exists, I am forced into a redirect loop.  My current document root looks like this:</p>
  
  <pre><code>- index.php (app)
  - webgrind
      - index.php
  - static 
      - css
  </code></pre>
  
  <p>Currently I cannot visit example.com/webgrind or any other directory.  My access logs repeatedly read similar to:</p>
  
  <pre><code>GET /webgrind/ HTTP/1.1" 301 178 "-"
  GET /webgrind  HTTP/1.1" 301 178 "-"
  </code></pre>
  
  <p>This is the server block in my nginx.conf:</p>
  
  <pre><code>server {
          listen 80;
          server_name example.com;
  
          location / {
              try_files $uri $uri/ /index.php?$args;
              root /var/www/example/public;
              index  index.php index.html index.htm;
          }
  
          rewrite ^/(.*)/$ /$1 permanent;
  
          location = /favicon.ico {
              access_log     off;
              log_not_found  off;
          }
  
          location ~ \.php$ {
              try_files $uri $uri/ /index.php?$args;
              root /var/www/example/public;
              index index.php index.html index.htm;
  
              fastcgi_pass   unix:/var/run/php5-fpm.sock;
              fastcgi_index  index.php;
              fastcgi_param  SCRIPT_FILENAME  /var/www/example/public$fastcgi_script_name;
              fastcgi_param  APPLICATION_ENV testing;
              fastcgi_param  PATH /usr/bin:/bin:/usr/sbin:/sbin;
              fastcgi_intercept_errors on;
              include        fastcgi_params;
          }
      }
  </code></pre>
  
  <p>I am aware that <code>rewrite ^/(.*)/$ /$1 permanent;</code> is the offending line.  If I remove it and visit example.com/webgrind, a 301 is issued for me to redirect to example.com/webgrind/ since it is a directory.  However, my application will now accept both trailing and non-trailing slashes (i.e. example.com/users/ and example.com/users) and this is not what I want.</p>
  
  <p>Wrapping the 'if' directive around my rewrite as follows still creates a redirect loop for my directories (<a href="http://wiki.nginx.org/IfIsEvil" rel="noreferrer">if is evil</a>, apparently, but a rewrite directive in this case is considered safe):</p>
  
  <pre><code>if (!-d $request_filename) {
      rewrite ^/(.*)/$ /$1 permanent;
  }
  </code></pre>
  
  <p><em>(I know that visiting webgrind/index.php would solve my problem, but I'd like to avoid costly and unprofessional redirect loops when my production directories are pushed live.)</em></p>
  
  <p>So how can I conditionally strip trailing slashes only for resources that don't exist (my web application paths)?</p>
  
  <p><strong>UPDATE</strong>:  My (unaltered) fastcgi_params config:</p>
  
  <pre><code>fastcgi_param   QUERY_STRING            $query_string;
  fastcgi_param   REQUEST_METHOD          $request_method;
  fastcgi_param   CONTENT_TYPE            $content_type;
  fastcgi_param   CONTENT_LENGTH          $content_length;
  
  fastcgi_param   SCRIPT_FILENAME         $request_filename;
  fastcgi_param   SCRIPT_NAME             $fastcgi_script_name;
  fastcgi_param   REQUEST_URI             $request_uri;
  fastcgi_param   DOCUMENT_URI            $document_uri;
  fastcgi_param   DOCUMENT_ROOT           $document_root;
  fastcgi_param   SERVER_PROTOCOL         $server_protocol;
  
  fastcgi_param   GATEWAY_INTERFACE       CGI/1.1;
  fastcgi_param   SERVER_SOFTWARE         nginx/$nginx_version;
  
  fastcgi_param   REMOTE_ADDR             $remote_addr;
  fastcgi_param   REMOTE_PORT             $remote_port;
  fastcgi_param   SERVER_ADDR             $server_addr;
  fastcgi_param   SERVER_PORT             $server_port;
  fastcgi_param   SERVER_NAME             $server_name;
  
  fastcgi_param   HTTPS                   $https;
  
  # PHP only, required if PHP was built with --enable-force-cgi-redirect
  fastcgi_param   REDIRECT_STATUS         200;
  </code></pre>