13

I need to replicate the following Apache rewrite rules in Nginx config on Ubuntu 12.04. What is the nginx equivalent to :

RewriteCond %{REQUEST_URI} ^(.*)//(.*)$
RewriteRule . %1/%2 [R=301,L]
Giacomo1968
  • 53,069
  • 19
  • 162
  • 212
codecowboy
  • 690
  • 3
  • 14
  • 32
  • http://stackoverflow.com/questions/14832780/nginx-merge-slashes-redirect – cnst Mar 23 '13 at 22:28
  • Whoever found this online and tries to copy-paste the suggested answers, **beware** if you're using a Virtualbox setup with custom ports. I had to change it to be e.g. `rewrite (.*)//+(.*) $scheme://$host:4321$1/$2 permanent;` where *4321* is the external port of the Virtualbox'd nginx my browser connects to. – ᴍᴇʜᴏᴠ Nov 20 '17 at 21:53

6 Answers6

8

I'd like to suggest this approach:

# remove multiple sequences of forward slashes
# rewrite URI has duplicate slashes already removed by Nginx (merge_slashes on), just need to rewrite back to current location
# note: the use of "^[^?]*?" avoids matches in querystring portion which would cause an infinite redirect loop
if ($request_uri ~ "^[^?]*?//") {
rewrite "^" $scheme://$host$uri permanent;
}

It uses the default behaviour of nginx — merging of slashes, so we do not need to replace slashes, we simply redirecting

found here

SleepWalker
  • 181
  • 1
  • 2
  • 1
    'if' is evil: https://www.nginx.com/resources/wiki/start/topics/depth/ifisevil/ – MacroMan Feb 14 '18 at 11:47
  • This doesn't work for SSL via certbot if you have nginx as a reverse proxy via `proxy_pass` – Jonathan Aug 26 '19 at 22:49
  • It seems to me that the regex only captures URIs containing two slashes just after the first question mark, which contradicts the comment just above. – Fabien Mar 17 '21 at 11:07
5

I found kwo's response to not work. Looking at my debug log, this is what happens:

2014/08/18 15:51:04 [debug] 16361#0: *1 http script regex: "(.*)//+(.*)"
2014/08/18 15:51:04 [notice] 16361#0: *1 "(.*)//+(.*)" does not match "/contact-us/", client: 59.167.230.186, server: *.domain.edu, request: "GET //////contact-us//// HTTP/1.1", host: 
"test.domain.edu"

I found this worked for me:

if ($request_uri ~* "\/\/") {
  rewrite ^/(.*)      $scheme://$host/$1    permanent;
}

Ref: http://rosslawley.co.uk/archive/old/2010/01/10/nginx-how-to-url-cleaning-removing/

Giacomo1968
  • 53,069
  • 19
  • 162
  • 212
DaveQB
  • 51
  • 1
  • 3
2

Try this:

merge_slashes off;
rewrite (.*)//+(.*) $1/$2 permanent;

There might be multiple redirects for slashes > 3 or multiple groups of slashes.

kwo
  • 129
  • 3
  • 'merge_slashes off' made no difference and resulted in no change. – Anup Nair Apr 30 '18 at 07:34
  • 1
    Why doesn't `merge_slashes on;` just work? Is nginx buggy? – Jonathan Aug 26 '19 at 22:51
  • 2
    @Jonathan - I just came across this as well. My understanding, is that `merge_slashes on` doesn't do what you are thinking. It basically tells nginx to take // and / and /// as a single slash (not to merge and redirect on its own) – Andrew Newby Jan 15 '20 at 16:41
  • You can drastically reduce the number of redirects if you make the first group lazy: `(.*?)//+(.*)` – neoascetic Jun 24 '21 at 10:23
0

I speak from experience of running multiple production servers and dev servers for a team. Do not do this in nginx. Instead, use your router within your application server (JS/PHP etc).

Nginx is not reliable for substantive work. For example, redirects, rewrites, and if clauses are non-deterministic if you change your setup to use SSL, a reverse proxy, hidden ports, and so on. So you may get it working correctly in one environment, but it could be impossible to get working in another.

Stick to a proper programming language for solving problems, even as simple as merging double slashes. You'll thank me later.

Jonathan
  • 1,678
  • 10
  • 28
  • 47
  • While I agree your view, I believe we should give people the option to form their own opinion about the matter. I prefer Apache to Nginx, on the same reason than yours. Note, Apache mod_rewrite can be considered as a simple programming language, too. :-) – peterh Mar 16 '20 at 17:09
0

I like this solution:

if ($request_uri ~ "//") {
    return 301 $uri;
}

See https://stackoverflow.com/a/27071557/548473

-1

URL example.com//dir1////dir2///dir3 and more Try this it's working for me

merge_slashes off; location ~ ^(.*?)//+(.*?)$ { return 301 $1/$2; }

SoniNow
  • 1
  • 1