Add trailing slash when it's missing in nginx

26,966

Solution 1

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.

Solution 2

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 {
    server_name    DOMAIN.com;
    return         301 $scheme://www.$server_name$request_uri;
}

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

    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";
          fastcgi_pass     127.0.0.1:9000;

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

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

IMPORTANT! IMPORTANT! IMPORTANT! IMPORTANT!

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:
26,966
vincent.io
Author by

vincent.io

I'm an Entrepreneur and Product Designer, combining my backgrounds in design, business and software development to build products that deliver great experiences. I'm cofounder and CEO at Content Optimization service ContentKing. Apart from ContentKing I am the chairman of C-Squared, a non-profit organization based in Brno, Czech Republic that connects companies to local tech communities. From time to time I dabble in code and build robots. The first robot I ever built committed suicide by taking the stairs. I fixed that bug in the second revision, but it didn’t do much more than avoiding stairs. Originally from The Netherlands, I'm currently living in Brno, Czech Republic. In my spare time I love running, reading and hiking. On top of that I have a passion for aviation, and hope to fly my own HondaJet one day.

Updated on September 18, 2022

Comments

  • vincent.io
    vincent.io over 1 year

    I'm running Magento on Nginx using this config: http://www.magentocommerce.com/wiki/1_-_installation_and_configuration/configuring_nginx_for_magento.

    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?

  • vincent.io
    vincent.io over 10 years
    Thank you for your answer, but that doesn't solve my problem.
  • DanCat
    DanCat almost 7 years
    Could you go into detail on the behavior of the regex?
  • helb
    helb over 6 years
    @DanCat Something like "group of any number of non-period characters not followed by a slash"