11

I would like the following URLs on my site to be equivalent:

/foo/bar
/foo/bar/
/foo/bar/index.html

and further I would like the second two forms to issue HTTP 301 redirects to the first form. I am just serving static pages, and they are arranged according to the third form. (In other words, when a user requests /foo/bar they should receive the file at /usr/share/.../foo/bar/index.html).

My nginx.conf currently contains the following:

rewrite ^(.+)/$ $1 permanent;
index index.html;
try_files $uri $uri/index.html =404;

This works for requests for /foo/bar/index.html, but when I request /foo/bar or /foo/bar/ Safari tells me that “too many redirects occurred”—I assume there’s an infinite redirect loop or something like that. How can I get nginx to map URLs to files in the way I’ve described?

Edit: My full configuration

Here is my entire nginx.conf with my domain name replaced with “example.com”.

user www-data;
worker_processes 1;
pid /run/nginx.pid;

events {
  worker_connections 768;
}

http {
  sendfile on;
  tcp_nopush on;
  tcp_nodelay on;
  keepalive_timeout 65;
  types_hash_max_size 2048;
  server_tokens off;

  server_names_hash_bucket_size 64;

  include /etc/nginx/mime.types;
  default_type application/octet-stream;

  access_log /var/log/nginx/access.log;
  error_log /var/log/nginx/error.log;

  gzip on;
  gzip_disable "msie6";
  gzip_vary on;
  gzip_proxied any;
  gzip_comp_level 6;
  gzip_buffers 16 8k;
  gzip_http_version 1.1;
  gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss application/atom+xml text/javascript image/svg+xml;

  server {
    server_name www.example.com;
    listen 80;
    return 301 $scheme://example.com$request_uri;
  }

  server {
    server_name example.com 123.45.67.89 localhost;
    listen 80 default_server;

    # Redirect /foobar/ to /foobar
    rewrite ^(.+)/$ $1 permanent;

    root /usr/share/nginx/www/example.com;
    index index.html;
    try_files $uri $uri/index.html =404;

    error_page 404 /404.html;
    error_page 500 502 503 504 /50x.html;

    location = /50x.html {
      root /usr/share/nginx/html;
    }
  }
}
  • Do these files actually exist on the filesystem? – Michael Hampton May 20 '14 at 18:51
  • @MichaelHampton Yes. Requests for /foo/bar/index.html should return the file at /usr/share/nginx/www/foo/bar/index.html or however it’s set up. All of the paths on the website correspond directly to filesystem paths. – bdesham May 20 '14 at 19:23
  • @bdesham I can't reproduce. Here what I get with your config paste.ubuntu.com/7501697 – Alexey Ten May 22 '14 at 14:52
  • @AlexeyTen It’s odd that you’re getting something different. Thanks for looking into it. I’ve posted a configuration that ended up working for me. – bdesham May 22 '14 at 15:31
16

Having this regex on your server block:

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

would redirect all trailing slash URL's to the respective non trailing slash.

  • 1
    This addresses only part of the question. – bdesham May 11 '15 at 18:15
  • 4
    This addresses the full title of the question. – Jivan Jun 28 '16 at 7:43
5

I was able to get my desired behavior by using this as the final server block in my configuration:

server {
  server_name example.com 123.45.67.89 localhost;
  listen 80 default_server;

  # Redirect /foobar/ and /foobar/index.html to /foobar
  rewrite ^(.+)/+$ $1 permanent;
  rewrite ^(.+)/index.html$ $1 permanent;

  root /usr/share/nginx/www/example.com;
  index index.html;
  try_files $uri $uri/index.html =404;

  error_page 404 /404.html;
  error_page 500 502 503 504 /50x.html;

  location = /50x.html {
    root /usr/share/nginx/html;
  }
}
  • This doesn't seem to work for me - the /index.html URL is answered with HTTP 200 instead of a redirect; the "rewrite" lines are ignored. Is this still current? – Christoph Burschka Feb 13 '18 at 11:39
0
if ($request_uri ~ (.*?\/)(\/+)$ ) {
return 301 $scheme://$host$1;
}

This rule will take care of any number of trailing slashes and will retain URL. It will also take care of base URL trailing slashes

-1

Never use rewrite:

  location ~ (?<no_slash>.*)/$ {
       return 301 $scheme://$host$no_slash;
  }

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.