Rewrite rule with + in old url using nginx - nginx

I am moving a bunch of photos that were hosted with Gallery2 to a new subdomain hosted by Zenfolio. I am trying to make some redirects from the old domain to the new one for more popular photo albums. Unfortunately, G2 uses + in album names with spaces and Nginx does not seem to be redirecting those to the proper place.
Here's an example config I'm using. Any assistance is appreciated!
server {
listen 80; ## listen for ipv4; this line is default and implied
listen [::]:80; ## listen for ipv6
keepalive_timeout 70;
# Make site accessible from http://localhost/
server_name old.domain.com;
root /var/www/old.domain.com/public_html;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to index.html
# Uncomment to enable naxsi on this location
# include /etc/nginx/naxsi.rules
rewrite /photos/2013+example+race/ http://photos.domain.com/13-example-race permanent;
try_files $uri #404_redirect;
}
location #404_redirect {
return 301 http://photos.domain.com;
}
}

Since it's a regular expression, + has a meaning (repeats 1 or more times), so you should try to escape the +
rewrite /photos/2013\+example\+race/ http://photos.domain.com/13-example-race permanent;

Related

How to configure nginx to redirect to https ... except for one directory

I'm setting up an nginx webserver to support multiple virtual hosts. Following best practice, I want any http:// request to be redirected to the equivalent https://.
That much is straightforward, but I want to have one exception: any request for any file under /.well-known/ should be served as http, without the https redirect. Anyone who's worked with LetsEncrypt will recognize the '.well-known' directory as the place that LetsEncrypt looks for verification files. These must be served over HTTP.
So far, I have a configuration file for 'default' that looks like:
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
root /var/www/default/www;
index index.php index.html index.htm;
location ^~ /.well-known/ {
allow all;
}
location / {
return 301 https://$host$request_uri;
}
}
Then, for each virtual host, I have a separate file that looks like:
server {
listen 443 ssl;
server_name myexamplevirtualhost.com;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
# lots more SSL-related stuff
location / {
try_files $uri $uri/ =404;
}
}
server {
listen 80;
server_name myexamplevirtualhost.com;
location / {
return 301 https://$server_name$request_uri;
}
location /.well-known/ { }
}
If I request, for example, http://myexamplevirtualhost.com/, I get redirected to https://myexamplevirtualhost.com/ -- which is what I want. Similarly, a direct request for https://myexamplevirtualhost.com/ works as intended.
However, if I try: http://myexamplevirtualhost.com/.well-known/foo123, instead of the server simply serving up http://myexamplevirtualhost.com/.well-known/foo123 (which is the goal), it does a redirect to https://myexamplevirtualhost.com/.well-known/foo123.
I've tried a lot of different things -- changing the order of location rules, etc. -- but I still can't seem to get the behaviour I want.
What am I doing wrong?
If you have HSTS (HTTP Strict Transport Security) enabled you won't be able to "turn off" https for certain pages, since https will be forced for the whole domain. You might be able to use some convoluted setup of HTTP 302 redirects to make this work, but I'm not sure why you would want to. Let's Encrypt will have no trouble renewing certs if your .well-known directory is served over HTTPS.

NGINX: remove part of url permanantly

I have redesigned a website and changed the url formats too.
Now i need to change the old url to new one.
Here is my old url:
http://www.example.com/forum/showPost/2556/Urgent-Respose
The new url will be:
http://www.example.com/2556/Urgent-Respose
How to redirect to new url using nginx by removing /forum/showPost from url?
Edited:
Also this url:
http://www.tikshare.com/business/showDetails/1/Pulkit-Sharma-and-Associates,-Chartered-Accountants-in-Bangalore
New url:
http://www.tikshare.com/classifieds/1/Pulkit-Sharma-and-Associates,-Chartered-Accountants-in-Bangalore
Above link is complete removing whereas this link is to replace business/showDetails with classifieds
There are a number of options. You could protect the rewrite within a location block which would be quite efficient as the regular expression is only tested if the URI prefix matches:
location ^~ /forum/showPost {
rewrite ^/forum/showPost(.*)$ $1 permanent;
}
See this document for more.
You used permanent in your question - which generates a 301 response.
If you use redirect instead of permanent - a 302 response will be generated.
If you use last instead of permanent - an internal redirect will occur and the browser address bar will continue to show the old URL.
In response to your comment:
rewrite ^/forum/showPost(.*)$ /post$1 permanent;
server
{
listen 80; ## Listen on port 80 ##
server_name example.com; ## Domain Name ##
index index.html index.php; ## Set the index for site to use ##
charset utf-8; ## Set the charset ##
location ^~ /forum/showPost {
rewrite ^/forum/showPost(.*)$ $1 permanent;
}
location ^~ /business/showDetails {
rewrite ^(.*)business/showDetails(.*)$ classifieds$1 permanent;
}
}

Non-www to www domain using Nginx on Ubuntu 12.04 LTS on Ec2 instance

After seeing this post http://www.ewanleith.com/blog/900/10-million-hits-a-day-with-wordpress-using-a-15-server I changed my server from apache2 to nginx. I am no computer geek just, savvy. I followed the steps. After that, the site was perfect, except for one thing: non-www to www thing. I searched all over the net on how to do this. I tried the modrewrite thing they said but just getting worst. For now, it is directed to www because I use wordpress and set it in general settings http://www.pageantly.com. Yet, I have static directories and it is in plain non-www. Please take a look on my default.conf in /etc/nginx/conf.d/ as well as the tutorial with link above:
server {
server_name pageantly.com www.pageantly.com;
root /var/www/;
listen 8080;
## This should be in your http block and if it is, it's not needed here.
index index.html index.htm index.php;
include conf.d/drop;
location / {
# This is cool because no php is touched for static content
try_files $uri $uri/ /index.php?q=$uri&$args;
}
location ~ \.php$ {
fastcgi_buffers 8 256k;
fastcgi_buffer_size 128k;
fastcgi_intercept_errors on;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/dev/shm/php-fpm-www.sock;
}
# BEGIN W3TC Page Cache cache
location ~ /wp-content/w3tc/pgcache.*html$ {
add_header Vary "Accept-Encoding, Cookie";
}
[...]
}
# END W3TC Page Cache core
}
Ideally, each domain (sub-domains included) should have a separate server block. Going by that, your configuration would look like:
# Following block redirects all traffic coming to pageantly.com to www.pageantly.com
server {
server_name pageantly.com;
listen 8080;
# Send a 301 permanent redirect to any request which comes on this domain
return 301 http://www.pageantly.com$request_uri;
}
# Following block handles requests for www.pageantly.com
server {
server_name www.pageantly.com;
listen 8080;
root /var/www;
[...] # all your default configuration for the website
}
Another unclean and inefficient way to achieve this would be to introduce an if statement which reads domain value and branches flow accordingly either to redirect traffic (in case of pageantly.com) or to process requests (in case of www.pageantly.com) but I would recommend you avoid going by that route.
Hope this helps.
If you are using Route 53 on AWS; then you do NOT have to do any such thing. On Route53 itself we can create an alias and configure so that non-www is redirected to www.

Redirect urls in nginx

I have a problem.
My app server is nginx, on which my blog was hosted.
when i visited my sitemap with this url:
http://www.ikbear.com/sitemap.xml, it works.But when i visited my sitemap with this url:
http://ikbear.com/sitemap.xml, it doesn't work. So i want to redirect http://ikbear.com/sitemap.xml to http://www.ikbear.com/sitemap.xml, would you tell me how can i do that in nginx? Thanks!
Actually I'm going to venture a guess that you'll have the same trouble redirecting that url as actually serving it.
First, here's the syntax for a basic redirect:
server {
# ...
# redirect sitemap.xml to sitemap.xml.php
rewrite ^(/sitemap.xml)$ /sitemap.xml.php;
# ...
}
What might work for you is getting both www and not-www serving correctly. A common strategy is to serve all www to non-www, or vice versa. Here's an example of that:
server {
listen 80;
server_name www.mydomain.com;
# forward everything from www.domain.com to domain.com
rewrite ^(.*) http://domain.com$1 permanent;
}
server {
listen 80;
server_name domain.com *.domain.com;
location / {
root /var/www/domain/htdocs;
index index.html index.htm index.php;
# ... etc.
}
}

Nginx rewrite non-www-prefixed domain to www-prefixed domain

I see the Nginx HttpRewriteModule documentation has an example to rewrite a www-prefixed domain to a non-www-prefixed domain:
if ($host ~* www\.(.*)) {
set $host_without_www $1;
rewrite ^(.*)$ http://$host_without_www$1 permanent; # $1 contains '/foo', not 'www.mydomain.com/foo'
}
How can I do the reverse-- rewrite a non-www-prefixed domain to a www-prefixed domain? I thought maybe I could do something like the following but Nginx doesn't like the nested if statement.
if ($host !~* ^www\.) { # check if host doesn't start with www.
if ($host ~* ([a-z0-9]+\.[a-z0-9]+)) { # check host is of the form xxx.xxx (i.e. no subdomain)
set $host_with_www www.$1;
rewrite ^(.*)$ http://$host_with_www$1 permanent;
}
}
Also I wanted this to work for any domain name without explicitly telling Nginx to rewrite domain1.com -> www.domain1.com, domain2.com -> www.domain2.com, etc. since I have a large number of domains to rewrite.
As noted in the Nginx documentation, you should avoid using the if directive in Nginx where possible, because as soon as you have an if in your configuration your server needs to evaluate every single request to decide whether to match that if or not.
A better solution would be multiple server directives.
server {
listen 80;
server_name website.com;
return 301 $scheme://www.website.com$request_uri;
}
server {
listen 80;
server_name www.website.com;
...
}
If you're trying to serve an SSL (HTTPS) enabled site, you got more or less three different options.
Set up multiple IP addresses having each server directive listening on their own IP (or different ports if that's an option for you). This options needs SSL certificates for both website.com and www.website.com, so either you have a wild card certificate, a UNI certificate (multiple domains) or just plainly two different certificates.
Do the rewrite in the application.
Use the dreaded if directive.
There is also an option to use SNI, but I'm not sure this is fully supported as of now.
if ($host !~* ^www\.) {
rewrite ^(.*)$ http://www.$host$1 permanent;
}
Well I guess I don't really need the outer "if" statement since I'm only checking for domains of the form xxx.xxx anyways. The following works for me, though it's not robust. Let me know if there is a better solution.
if ($host ~* ^([a-z0-9\-]+\.(com|net|org))$) {
set $host_with_www www.$1;
rewrite ^(.*)$ http://$host_with_www$1 permanent;
}
Edit: Added hyphen to the regular expression since it is a valid character in a hostname.
if ($host ~* ^[^.]+\.[^.]+$) {
rewrite ^(.*)$ https://www.$host$1 permanent;
}
It's only possible to get valid hostnames because the request will never make it to your server otherwise, so there's no need to build your own validation logic.
The nginx documentation cautions against the use of if for rewriting. Please see the link here: http://wiki.nginx.org/Pitfalls#Server_Name
HTTP & HTTPS without if conditions:
server {
listen 80;
listen 443;
server_name website.com;
return 301 $scheme://www.website.com$request_uri;
}
server {
listen 80;
listen 443 default_server ssl;
server_name www.website.com;
# Your config goes here #
}
Solution for multiple domains, working on nginx 1.17 for me:
server {
listen 80;
server_name .example.com;
set $host_with_www $host;
if ($host !~* www\.(.*)) {
set $host_with_www www.$host;
}
return 301 https://$host_with_www$request_uri;
}
In this config example additionally rewrites HTTP on HTTPS, if you don't want rewrite — replace https:// with http:// in return string.
If you want keep protocol — use $scheme variable.

Resources