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'm running Magento on Nginx using this config:

Now I want to 301 all URLs without trailing slash to their counterpart that includes a trailing slash. For example: /contacts to /contacts/.

I've tried virtually all the nginx directives on this I could find, but to no avail. For example, the directive specified in nginx- Rewrite URL with Trailing Slash leads to a redirect to /index.php/.

Which directive should I add and where?

share|improve this question

I've found the solution: I added the following line above the "try_files" directive in the "location /"-block:

rewrite ^([^.]*[^/])$ $1/ permanent;

which does the magic.

share|improve this answer

This is very, very tricky because you have to consider all possibilities in your URLs. Let's have a closer look at that configuration you posted there and optimize it while trying to implement your wish. I have to correct the complete configuration because it contains more than one security risk for your website (and continue reading after the configuration).

server {
    return         301 $scheme://www.$server_name$request_uri;

server {
    index          index.html index.php;
    listen         80 default;
    root           /var/www;

    location / {

        # Hide ALL kind of hidden stuff.
        location ~ /\. {
            return 403;

        # Protect Magento's special directories in document root.
        location ~* ^/(app|includes|lib|media/downloadable|pkginfo|report/config\.xml|var)/? {
            return 403;

        # Directly deliver known file types.
        location ~* \.(css|gif|ico|jpe?g|js(on)?|png|svg|webp)$ {
            access_log      off;
            add_header      Cache-Control   "public";
            add_header      Pragma          "public";
            expires         30d;
            log_not_found   off;
            tcp_nodelay     off;
            try_files       $uri =404;

        # Do not allow direct access to index.php
        location ~* ^(.*)index\.php$ {
            return 301 $1;

        # Extremely risky ... oh boy!
        location ~* \.php/ {
            rewrite ^(.*\.php)/ $1 last;

        # Not direct index.php access and not one of those ultra
        # risky php files with a path appended to their script name,
        # let's try to add a slash if it's missing.
        location ~* ^(.*)[^/]+$ {
            return 301 $1/;

        location ~* \.php$ {
          include          fastcgi_params;
          fastcgi_index    index.php;
          fastcgi_param    PATH_INFO          $fastcgi_path_info;
          fastcgi_param    PATH_TRANSLATED    $document_root$fastcgi_path_info;
          fastcgi_param    SCRIPT_NAME        $fastcgi_script_name;
          fastcgi_param    SCRIPT_FILENAME    $document_root$fastcgi_script_name;
          fastcgi_param    MAGE_RUN_CODE      "default";
          fastcgi_param    MAGE_RUN_TYPE      "store";

          # Ensure it's an actual PHP file!
          try_files        $uri =404;

    location ^~ /var/export/ {
        auth_basic              "Restricted";
        auth_basic_user_file    htpasswd;
        autoindex               on;


I can't test this configuration, I've written it down to my best knowledge. Please execute nginx -t before attempting to reload your nginx and report back if this reports any errors. Do not, I repeat, do not test this on your production site and test everything you can think of.

share|improve this answer
Thank you for your answer, but that doesn't solve my problem. – vvanscherpenseel Oct 30 '13 at 8:39

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.