How to only redirect urls located in a nginx Map - redirect

I am in the process of moving my blog from a.com to b.com. Now I want to tell Google /bookmarks that all blogposts (around 100) have been moved to b.com. I only want to redirect the blogposts and nothing else.
After reading about the map module in nginx I tried the following:
map_hash_bucket_size 128;
map $uri $new {
/post http://b.com/post
# (repeated for all 100 posts)
}
And when I put the following line inside the server block:
rewrite ^ $new redirect;
It will redirect all 100 posts but all the other pages on my domain will error with: 302 Found.
Here is my whole server block inside the config:
server {
listen 80;
server_name b.com;
root /my/old/path/;
index index.html;
location = /favicon.ico {
log_not_found off;
access_log off;
}
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
# Deny all attempts to access hidden files such as .htaccess, .htpasswd, .DS_Store (Mac).
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
expires max;
log_not_found off;
}
# example.com/index gets redirected to example.com/
location ~* ^(.*)/index$ {
return 301 $scheme://$host$1/;
}
# example.com/foo/ loads example.com/foo/index.html
location ~* ^(.*)/$ {
try_files $1/index.html #backend;
}
# example.com/a.html gets redirected to example.com/a
location ~* \.html$ {
rewrite ^(.+)\.html$ $scheme://$host$1 permanent;
}
# anything else not processed by the above rules:
# * example.com/a will load example.com/a.html
# * or if that fails, example.com/a/index.html
location / {
try_files $uri.html $uri/index.html $uri #backend;
}
# default handler
# * return error or redirect to base index.html page, etc.
location #backend {
try_files /404.html 404;
}
location ~ \.php$ {
expires off;
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
#NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
include fastcgi_params;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_intercept_errors on;
fastcgi_pass php;
}
# apply the rewrite map
rewrite ^ $new redirect;
}
I am thinking the map interferes with the try_files call for location \ (which I need).

I found a solution for your problem on serverfault:
This is probably failing because you're trying to redirect all
requests, whether they matched something in the map or not.
To prevent this, check to see if there was a match first.
if ($new) {
return 301 $new;
}
So replace
rewrite ^ $new redirect;
with
if ($new) {
return 301 $new;
}
And you should be good to go

I have not been able to figure out how to do this with map, as it's still quite a string module to me. Now I've just put all the rewrites in a list inside my server block (above all location blocks), which is probably very slow. Now the file looks like this:
server {
listen 80;
server_name a.com;
root /my/old/path/;
index index.html;
rewrite /post http://b.com/post
# (x100)
location = /favicon.ico {
log_not_found off;
access_log off;
}
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
# Deny all attempts to access hidden files such as .htaccess, .htpasswd, .DS_Store (Mac).
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
expires max;
log_not_found off;
}
# example.com/index gets redirected to example.com/
location ~* ^(.*)/index$ {
return 301 $scheme://$host$1/;
}
# example.com/foo/ loads example.com/foo/index.html
location ~* ^(.*)/$ {
try_files $1/index.html #backend;
}
# example.com/a.html gets redirected to example.com/a
location ~* \.html$ {
rewrite ^(.+)\.html$ $scheme://$host$1 permanent;
}
# anything else not processed by the above rules:
# * example.com/a will load example.com/a.html
# * or if that fails, example.com/a/index.html
location / {
try_files $uri.html $uri/index.html $uri #backend;
}
# default handler
# * return error or redirect to base index.html page, etc.
location #backend {
try_files /404.html 404;
}
location ~ \.php$ {
expires off;
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
#NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
include fastcgi_params;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_intercept_errors on;
fastcgi_pass php;
}
# apply the rewrite map
rewrite ^ $new redirect;
}

Related

Nginx rewrite or internal redirection cycle while internally redirecting

I am having troubles with nginx.
Here is my config.
server {
listen 80;
listen [::]:80;
server_name www.test.local;
return 301 http://test.local$request_uri;
}
server {
server_name test.local;
root /usr/share/nginx/test/htdocs/web;
# error_log /var/log/nginx/test.error.log;
# access_log /var/log/nginx/test.access.log;
rewrite ^/app\.php/?(.*)$ /$1 permanent;
location / {
index app.php;
try_files $uri #rewriteapp;
}
location #rewriteapp {
rewrite ^(.*)$ /app.php/$1 last;
}
location ~ ^/app\.php(/|$) {
fastcgi_pass 172.17.0.1:48000;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
internal;
}
location /uploads/ {
root /usr/share/nginx/test/htdocs/web/uploads;
try_files $uri $uri/;
access_log off;
expires 30d;
}
location /images/ {
root /usr/share/nginx/test/htdocs/web/images;
try_files $uri $uri/;
access_log off;
expires 30d;
}
location /css/ {
root /usr/share/nginx/test/htdocs/web/css;
try_files $uri $uri/;
access_log off;
expires 30d;
}
location /js/ {
root /usr/share/nginx/test/htdocs/web/js;
try_files $uri $uri/;
access_log off;
expires 30d;
}
location /fonts/ {
root /usr/share/nginx/test/htdocs/web/fonts;
try_files $uri $uri/;
access_log off;
expires 30d;
}
location = /favicon.ico {
return 204;
access_log off;
log_not_found off;
}
}
I want my locations as http://test.local/css/ link to /usr/share/nginx/test/htdocs/styles/ as i did it in my config.
But when im entering for example http://test.local/css/flow.css im getting next error:
2016/05/13 15:55:30 [error] 5#5: *64 rewrite or internal redirection cycle while internally redirecting to "/css/flow.css///////////", client: 192.168.99.1, server: test.local, request: "GET /css/flow.css HTTP/1.1", host: "test.local", referrer: "http://test.local/"
Whats the problem here?
You have two problems with your configuration.
The first problem is that your root directives are wrong, so the file is not found.
The second problem is that the default action is to add another / to the end of the URI.
You need to add a valid default action to your try_files directive, such as a 404 response:
try_files $uri $uri/ =404;
So, back to the first problem. Your configuration states that /css/example.css is located at /usr/share/nginx/test/htdocs/web/css/css/example.css. Notice that /css/ is replicated. Same goes for /images/, /js/ and /fonts/. See this document for details of the root directive.
In most configurations, it is sufficient to specify the root at the server block level and allow it to be inherited by almost all location blocks, rather than repeating it in each location.
Your question states that /css/ files should be found in /usr/share/nginx/test/htdocs/styles/. This requires an alias directive. See this document for details of the alias directive. For example:
location /css/ {
alias /usr/share/nginx/test/htdocs/styles/;
access_log off;
expires 30d;
}

Nginx server removes www and 301 redirects to wrong host

I have a weird 301 redirection issue. My server is set up to handle multiple domains pointing to the server, i.e.
The main domain: https://maindomain.com
An N number of custom domains: http://somecustomdomain.com, http://anothercustomdomain.com, etc.
However there is a strange 301 issue when visiting a custom domain and including www., like: http://www.somecustomdomain.com. On the maindomain this works fine:
When visiting https://www.maindomain.com/some-uri it will redirect to: https://maindomain.com/some-uri
However, when visiting a custom domain it redirects from: http://www.somecustomdomain.com/some-uri to https://maindomain.com/some-uri (!!). You would expect it to redirect to: http://somecustomdomain.com/some-uri
I have tried debugging this issue (ensured that my browser does not cache the 301 redirects) and I have not been able to resolve the issue. I have three nginxs confiugrations inside my sites-available directory. They are listed here:
maindomain.com
catch-all (I have tried removing this file, so only maindomain.com exists, but problem still occours)
www.maindomain.com (I have tried removing this file, so only maindomain.com exists, but problem still occours)
maindomain.com contents
server {
listen 80;
server_name maindomain.com;
return 301 https://maindomain.com$request_uri;
}
server {
listen 443 ssl;
server_name maindomain.com;
root /home/forge/maindomain.com/public;
# FORGE SSL (DO NOT REMOVE!)
ssl_certificate /etc/nginx/ssl/maindomain.com/30126/server.crt;
ssl_certificate_key /etc/nginx/ssl/maindomain.com/30126/server.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
index index.html index.htm index.php;
charset utf-8;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
access_log off;
error_log /var/log/nginx/maindomain.com-error.log error;
error_page 404 /index.php;
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
}
location ~ /\.ht {
deny all;
}
}
catch-all contents
server {
listen 80;
server_name ~^(.+)$;
root /home/forge/maindomain.com/public;
index index.html index.htm index.php;
charset utf-8;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
access_log off;
error_log /var/log/nginx/maindomain.com-error.log error;
error_page 404 /index.php;
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
}
location ~ /\.ht {
deny all;
}
}
www.maindomain.com contents
server {
listen 80;
server_name www.maindomain.com;
return 301 $scheme://maindomain.com$request_uri;
}
If i CURL into http://www.somecustomdomain.com/some-uri this is the content I receive:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta http-equiv="refresh" content="1;url=https://maindomain.com/some-uri" />
<title>Redirecting to https://maindomain.com/some-uri</title>
</head>
<body>
Redirecting to https://maindomain.com/some-uri.
</body>
</html>%
You need an extra server configuration for www domains:
server {
server_name ~^(www\.)?(?<domain>.+)$;
location / {
return 301 $scheme://$domain/$uri;
}
}

Nginx Config Endless Loop (redirect HTTP to HTTPS)

I'm a bit stuck. I'm setting up a new installation of JTL-Shop3 on Nginx. But whenever I call https://www.domain.tld/ it becomes http://www.domain.tld/ and the other way around and ends up showing an error because the webpage is redirecting in a loop.
Here is my nginx config for Non-SSL
# redirect non www to www
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
server_name trendboxx.eu www.trendboxx.eu;
return 301 https://www.trendboxx.eu$request_uri;
}
And here the config for the SSL vhost
server {
listen 443 ssl;
ssl on;
ssl_certificate /srv/www/trendboxx.eu/certificates/www.trendboxx.eu.crt;
ssl_certificate_key /srv/www/trendboxx.eu/certificates/www.trendboxx.eu.key;
server_name www.trendboxx.eu;
access_log /srv/www/trendboxx.eu/logfiles/nginx.access.log;
error_log /srv/www/trendboxx.eu/logfiles/nginx.error.log;
root /srv/www/trendboxx.eu/public_html;
index index.php;
location / {
# try file => folder => JTL-Shop3 Search
try_files $uri $uri/ /index.php?q=$uri$args;
}
# error pages
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
# JTL-Shop3 expires for static files
location ~* \.(eot|ttf|woff|css|less)$ {
expires max;
add_header Access-Control-Allow-Origin *;
add_header Pragma public;
add_header Cache-Control "public, must-revalidate, proxy-revalidate";
access_log off;
log_not_found off;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
expires max;
add_header Pragma public;
add_header Cache-Control "public, must-revalidate, proxy-revalidate";
access_log off;
log_not_found off;
}
# PHP handler
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_read_timeout 180;
proxy_read_timeout 180;
}
# deny access to hidden files
location ~ /\. {
deny all;
}
}
I am gratefull for every hint on how to solve this problem.

How do I force redirect all 404's (or every page, whether invalid or not) to the homepage?

Currently every invalid page is 500 (Internal Server Error) because I probably messed up with my server block configuration.
I decided to shut down my website a while ago and created a simple one-page, thank-you homepage. However old links and external sites are still trying to access other parts of the site, which no longer exists.
How do I force redirect all non-homepage (any invalid URL) to the homepage?
I tried with the following block, but it didn't work:
location / {
try_files $uri $uri/ $document_uri/index.html;
}
My current configuration is (I don't even serve PHP files right now, ie homepage is simple html):
server {
server_name www.example.com example.com;
access_log /srv/www/example.com/logs/access.log;
error_log /srv/www/example.com/logs/error.log;
root /srv/www/example.com/public_html;
index index.php index.html;
location / {
try_files $uri $uri/ $document_uri/index.html;
}
# Disable favicon.ico logging
location = /favicon.ico {
log_not_found off;
access_log off;
}
# Allow robots and disable logging
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
# Enable permalink structures
if (!-e $request_filename) {
rewrite . /index.php last;
}
# Handle php requests
location ~ \.php$ {
try_files $uri = 404;
include /etc/nginx/fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_send_timeout 900;
fastcgi_read_timeout 900;
fastcgi_connect_timeout 900;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
# Disable static content logging and set cache time to max
location ~* \.(jpg|jpeg|gif|png|css|js|ico|xml)$ {
access_log off;
log_not_found off;
expires max;
}
# Deny access to htaccess and htpasswd files
location ~ /\.ht {
deny all;
}
# Deny access to hidden files (beginning with a period)
location ~ /\. {
access_log off; log_not_found off; deny all;
}
}
Setting the error page to the home page like this
error_page 404 /index.html;
has a small problem, the status code of the home page will be "404 not found", if you want to load the home page with a "200 ok" status code you should do it like this
error_page 404 =200 /index.html;
This will convert the "404 not found" error code to a "200 ok" code, and load the home page
The second method which #jvperrin mentioned is good too,
try_files $uri $uri/ /index.html;
but you need to keep 1 thing in mind, since it's the location / any asset that doesn't match another location and is not found will also load the index.html, for example missing images, css, js files, but in your case I can see you already have another location that's matching the assets' extensions, so you shouldn't face this problem.
To get a true redirect you could do this:
in server block define the error-page you want to redirect like this:
# define error page
error_page 404 = #myownredirect;
error_page 500 = #myownredirect;
Then you define that location:
# error page location redirect 302
location #myownredirect {
return 302 /;
}
In this case errors 404 and 500 generates HTTP 302 (temporary redirect) to / (could of course be any URL)
If you use fast-cgi for php or other these blocks must have the following added to send the errors "upstrem" to server-block:
fastcgi_intercept_errors on;
This solution for nginx hosted site:
Edit your virtual hosting file
sudo nano /etc/nginx/sites-available/vishnuku.com
Add this snippet in the server block
# define error page
error_page 404 = #notfound;
# error page location redirect 301
location #notfound {
return 301 /;
}
In your php block put the fastcgi_intercept_errors set to on
location ~ \.php$ {
include /etc/nginx/fastcgi_params;
# intercept errors for 404 redirect
fastcgi_intercept_errors on;
fastcgi_pass unix:/run/php/php7.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
Final code will look like this
server {
listen 80;
server_name vishnuku.com;
root /var/www/nginx/vishnuku.com;
index index.php index.html;
access_log /var/log/nginx/vishnuku.com.log;
error_log /var/log/nginx/vishnuku.com.error.log;
location / {
try_files $uri $uri/ /index.php?$args /;
}
# define error page
error_page 404 = #notfound;
# error page location redirect 301
location #notfound {
return 301 /;
}
location ~ \.php$ {
include /etc/nginx/fastcgi_params;
fastcgi_intercept_errors on;
fastcgi_pass unix:/run/php/php7.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
location ~ /\.ht {
deny all;
}
location = /nginx.conf {
deny all;
}
}
Try adding the following line after your index definition:
error_page 404 /index.html;
If that doesn't work, try changing your try_files call to the following instead:
try_files $uri $uri/ /index.html;
Hopefully one of those works for you, I haven't tested either yet.
Must use
"fastcgi_intercept_errors on;"
along with the custom redirect location like
error_page 404 =200 /index.html or
as above
location #myownredirect {
return 302 /;
}
Try this:
error_page 404 $scheme://$host/index.html;
Hi first there are a lot of different ways to redirect all the 404 to the home page
this helps you in SEO
make such u use
fastcgi_intercept_errors on;
than add this following to your config
error_page 404 =301 http://yourdomain.com/;
error_page 403 /error403.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /var/www/html;
}
Came here when I was looking to implement similar where I'm using Nginx as a reverse proxy to a self-hosted MinIO bucket, and none of the above answers have this. So, if you're using proxy_pass and are intercepting errors, you can also handle this logic to redirect to the index.html page.
Handling URLs such as:
http://localhost/ - 200 OK
http://localhost/index.html - 200 OK
http://localhost/non-existant/ - 404 Not Found
server {
listen 80;
server_name localhost;
location / {
rewrite ^/$ /static/index.html break;
proxy_intercept_errors on;
proxy_pass http://something-to-proxy/static/;
}
error_page 404 /index.html;
}
Another-correct way to redirect from error page to the home page. The setup example applies to the nginx server configuration file:
...
http {
...
server{
...
#Catch 40x errors:
error_page 400 401 402 403 404 = #RedirectToHome;
#Catch 50x errors:
error_page 500 501 502 503 504 = #RedirectToHome;
#We are now redirecting to the homepage of the site
location #RedirectToHome {
return 301 http://www.example.com;
#return 301 https://www.example.com;
#return 301 /;
}
...
}
}
You should avoid setting return 301 /; if port forwarding to the server was performed somewhere, because this nginx redirection will then be performed to the port on which the server is listening for incoming connections. Therefore, it is better to set the correct hostname(site name) in this configuration.

404 error on nginx location directive

I am trying to convert my apache redirection directives to nginx one, for now I have the following directive:
server {
listen 80;
index index.php index.html;
server_name myvisit_head;
root /var/www/mv/head/myvisit/;
access_log /var/log/nginx/myvisit-access.log;
error_log /var/log/nginx/myvisit-error.log;
# Use gzip compression
# gzip_static on; # Uncomment if you compiled Nginx using --with-http_gzip_static_module
gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 5;
gzip_buffers 16 8k;
gzip_http_version 1.0;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/$
# error pages
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /var/www;
}
# Deny access to hidden files
location ~* /\.ht {
deny all;
access_log off;
log_not_found off;
}
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~* /myvisitv3 {
rewrite /(myvisitv3|myvisitV3|myVisitv3|myVisitV3)([-_])(.*).(html|php)$ /myvisitv3.php?libAdresse=$3 break;
}
# Pass PHP scripts on to PHP-FPM
include global/php-fpm.conf;
location ~* \.php$ {
try_files $uri /index.php;
fastcgi_index index.php;
fastcgi_pass php5-fpm-sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param PHP_VALUE "auto_prepend_file=/var/www/profile/external/header.php \n
auto_append_file=/var/www/profile/external/footer.php";
include /etc/nginx/fastcgi_params;
}
}
but when I try to access the url I get a 404 not found error.
I have tried both with location, request_uri directive but the result is the same
here's my apache rules:
RewriteEngine on
RewriteRule ^(myvisitv3|myvisitV3|myVisitv3|myVisitV3)([-_])(.*).(html|php)$ myvisitv3.php?libAdresse=$3 [L,QSA]
RewriteRule ^(openVisit|openvisit).(html|php)$ openvisitv3.php [L,QSA]
RewriteRule ^(favicon).(ico|png|bmp|jpg)$ web/img/favicon.ico [L,QSA]
These rules use case insensitive matching to spare us the hassle of handling those so many cases.
location ~* /myvisitv3[-_](.*)\.(?:html|php) {
try_files $uri $uri/ /myvisitv3.php?libAdresse=$1;
}
location ~* /openvisit\.(?:html|php)$ {
try_files $uri $uri/ /openvisitv3.php;
}
location ~* /favicon\.(?:ico|png|bmp|jpg)$ {
try_files $uri $uri/ /web/img/favicon.ico;
}