Nginx Rewrite Encoded URI (with percent) Not Working - nginx

I have a WordPress site that needed to 301 redirect old post to new post.
Old post:
https://www.example.com/%e0%b8%aa%e0%b8%a7%e0%b8%b1%e0%b8%aa%e0%b8%94%e0%b8%b5/
New Post:
https://www.example.com/%e0%b8%a5%e0%b8%b2%e0%b8%81%e0%b9%88%e0%b8%ad%e0%b8%99/
I added this rule in nginx.conf for this domain here
server
{
listen 111.222.333.444:80;
server_name example.com www.example.com ;
return 301 https://www.example.com$request_uri;
}
server
{
rewrite_log on;
rewrite ^/%e0%b8%aa%e0%b8%a7%e0%b8%b1%e0%b8%aa%e0%b8%94%e0%b8%b5/$ https://www.example.com/%e0%b8%a5%e0%b8%b2%e0%b8%81%e0%b9%88%e0%b8%ad%e0%b8%99/ permanent;
location / {
# This is cool because no php is touched for static content.
# include the "?$args" part so non-default permalinks doesn't break when using query string
try_files $uri $uri/ /index.php?$args;
}
(the rest of location blocks continue)
}
Restart Nginx.
However, the old URL still return 404 and not a 301.
https://www.example.com/%e0%b8%aa%e0%b8%a7%e0%b8%b1%e0%b8%aa%e0%b8%94%e0%b8%b5/
And I don't see neither old nor new URI in error log at all. What should I do? Thanks!

The percent encoded URL is available in the $request_uri variable. But by the time Nginx is processing rewrite and location statements, the URL has been decoded and normalised.
Use a rewrite or location statement with the decoded values. For example:
rewrite ^/สวัสดี/$ /ลาก่อน/ permanent;
Or:
location = /สวัสดี/ {
return 301 /ลาก่อน/;
}

Related

Nginx redirect rule has no affect

Trying to do a simple redirect:
rewrite https://url.example.com(.*) https://example.com/plugins/url permanent;
Anytime url.example.com is hit, I want it to redirect to that specific path.
EDIT:
Will try to explain this better, as I'm trying to redirect to a specific domain from another.
server {
server_name example.com plugin.example.com;
root /home/www/example.com/public;
}
I see the location used for redirects such as:
location / {
try_files $uri $uri/ /index.php?$query_string;
}
But not sure how to use it in my case, which is to change plugin.example.com to example.com/plugin.
For example:
http://plugin.example.com
https://plugin.example.com
https://plugin.example.com/blah
https://plugin.example.com/blah/more
All of these should redirect to:
https://example.com/plugin
If the original URL is https://url.example.com or https://url.example.com/ then the normalized URI used by the rewrite and location directives will be /. The scheme, host name and query string have all been removed.
To perform a permanent redirect to a URL with a different host name:
Using rewrite (see this document for details):
rewrite ^/$ https://example.com/foo permanent;
Or using location and return (see this document for details):
location = / {
return 301 https://example.com/foo;
}
The second solution is more efficient, as there are no regular expressions to process.
If the original URL includes a query string: The rewrite will append it automatically unless a trailing ? is added. The return will not, but can be added by appending $is_args$args.
If the scheme and host name are unchanged, then both statements can be simplified:
rewrite ^/$ /foo permanent;
Or:
location = / {
return 301 /foo;
}
Redirect from subdomain to subfolder on main site
Do you require a redirect from a subdomain to a subfolder on the main site?
This would be best accomplished by a separate server context, with the appropriate server_name specification.
Else, you could also do this with an if statement testing against $host.
As already pointed out elsewhere, rewrite directive operates based on $uri, which does not contain the hostname.
server_name-based matching (recommended):
Hardcoded redirect with a limited number of hostnames (recommended):
server {
server_name plugin.example.com;
return 301 $scheme://example.com/plugin$request_uri;
}
server {
server_name about.example.com;
return 301 $scheme://example.com/about$request_uri;
}
Regex-based redirect from any subdomain to the main domain:
server {
server_name ~^(?:www\.)?(?<subdomain>.*)\.example\.com$;
return 301 $scheme://example.com/$subdomain$request_uri;
}
Regex-based redirect from a limited number of subdomain to the main domain:
server {
server_name ~^(?:www\.)?(?<subdomain>plugin|about)\.example\.com$;
return 301 $scheme://example.com/$subdomain$request_uri;
}
if-based:
If-statement-based redirect with hardcoded hostnames:
server {
server_name .example.com;
…
if ($host = plugin.example.com) {
return 301 $scheme://example.com/plugin$request_uri;
}
if ($host = about.example.com) {
return 301 $scheme://example.com/about$request_uri;
}
…
}
If-statement-based redirect with a regex-based matching:
server {
server_name .example.com;
…
if ($host ~ ^(?:www\.)?(?<subdomain>plugin|about)\.example\.com$) {
return 301 $scheme://example.com/$subdomain$request_uri;
}
…
}
Please refer to http://nginx.org/r/server_name for more discussion of which option may be best for you.
You can create separate servers for example.com and plugin.example.com. And create redirect inside plugin.example.com server.
server {
server_name plugin.example.com;
return 301 https://example.com/plugin;
}
server {
server_name example.com;
root /home/www/example.com/public;
}

Nginx return under location

I am currently facing a small problem using nginx to redirect to another host. I want to for example redirect https://service.company.com/new/test.html to https://new-service.company.com/test.html .
For now I have following configuration, which redirects me to https://new-service.company.com/new/test.html .
server {
# SSL
ssl_certificate /etc/nginx/cert/chained_star_company.com.crt;
ssl_certificate_key /etc/nginx/cert/star_company.com.key;
listen 443;
server_name service.company.com;
location /new/$1 {
return 301 $scheme://service-new.company.com/$1;
}
}
I also tried following with the same result:
return 301 $scheme://service-new.company.com/$request_uri
You want to rewrite the URI and redirect. You can achieve it using location and return directives, but a rewrite directive would be the simplest approach:
rewrite ^/new(.*)$ https://new-service.company.com$1 permanent;
See this document for more.
BTW, the problem with your location block solution, was the regular expression capture, wasn't. Use:
location ~ ^/new(.*)$ {
return 301 https://new-service.company.com$1$is_args$args;
}
See this document for more.

Nginx - if pattern 404 - go to

I have list of urls like:
domain.com/some-url-key-with-possible-id-after-it-99999.html
I need to try that URL, and IF it returns 404, redirect to:
domain.com/some-url-key-with-possible-id-after-it.html
Is that possible?
location ~ /([a-zA-Z0-9\-]+)-([0-9]+).html$ {
## IF ABOVE IS 404
return 301 http://domain.com/$1.html;
## ENDIF
}
I found something like this:
server {
listen 12440;
root /some/path/here/nginx/html/noahc/;
server_name www.domain.net, domain.net;
port_in_redirect off;
location /{
error_page 404 = #foobar;
}
location #foobar {
rewrite .* / permanent;
}
}
But it doesn't satisfy me, because I need to redirect to url with variable from request pattern. It could be ok, if I'll be able to pass ([a-zA-Z0-9-]+)-([0-9]+) to it as an argument.
So you have a URI and you would like to rewrite it if the static file does not exist. Use try_files to test for file existence.
root /path/to/docroot;
location ~ ^(/[a-zA-Z0-9-]+)-[0-9]+\.html$ {
try_files $uri #rewrite;
}
location #rewrite {
return 301 $1.html;
}
You can use return 301 or rewrite ... last in the named location, depending on how visible you want the rewrite to be.
See this document for help with nginx directives.

make a subdirectory show the content of a subdomain in nginx

I want to handle this:
blog.example.com => example.com/blog
blog.example.com/xxx => example.com/blog/xxx
in both samples there is nothing in blog subdirectory, and the code which should handle the blog is in subdomain. and just i want to show the url as showed above.
so. i want to forward(redirect without changing url) a subdirectory to subdomain.
is there any nginx configuration to do that?
You could have the following in your NGINX configuration.
server {
listen 80;
server_name blog.example.com;
location / {
return 301 $scheme://example.com/blog$request_uri;
}
}
server {
listen 80;
server_name example.com;
location /blog/ {
<your code goes here>
}
}
This takes any incoming requests to blog.example.com and redirects to example.com/blog along with the requested URI eg. blog.example.com/latest would redirect to example.com/blog/latest
location = /blog {
return 302 /blog/;
}
location /blog/ {
proxy_pass http://blog.example.com/;
}
Note that the / in proxy_pass is very important (without it the /blog part won't be stripped out in the request to upstream).
Some further details on the rationale of two independent location statements are available at https://serverfault.com/questions/562756/how-to-remove-the-path-with-an-nginx-proxy-pass/562850#562850.

redirect any path but only exclude /

I will be changing my domain for another, only want to serve "/" in the old domain, but other paths will be redirected to the new domain following the url context.
location ^/(.*)$ {
# only serve /, other paths will be redirected to the new domain
rewrite ^/(.*)$ https://new.com/$1 permanent;
}
location / {
# only serve a html in old.com/ to explain the domain change
index index.html;
}
this is redirecting every request, including root context, what I am missing?
You missed the part that index makes internal redirect and you always end up in first location.
There is more elegant and nginx-y way to achieve your goal:
location = / {
try_files /index.html =404;
}
location / {
return 301 https://new.com$request_uri;
}

Resources