I am a newbie to NGINX and have been trying to get this problem sorted out.
Here is the NGINX configuration that works pretty well for most of the part, however when a request is placed without the trailing slash at the end, it redirects to http://$host instead of https://$host. It was forwarding with the port earlier, but I turned off port_in_redirect, which disabled showing up the port number in the browser.
Somehow https://domain.com/xyz/abc still gets redirected to http://domain.com/xyz/abc/
My guess is try_files is somehow not retaining the domain name
I am sure there is something wrong in the configuration, but I have no deep insights on whats causing it
Any inputs is highly appreciate
server {
listen 8080;
server_name _;
location /xyz/abc {
alias /var/www/html/;
try_files $uri $uri/ /xyz/abc/index.html;
}
location ~ ^/xyz/foo/(.*) {
return 301 https://$host/xyz/abc/foo/$1;
}
Below is the curl output
curl -I https://domain.com/xyz/abc
HTTP/1.1 301 Moved Permanently
Server: nginx/1.6.3
Date: Thu, 27 Jan 2016 08:18:27 GMT
Content-Type: text/html
Content-Length: 184
Location: http://domain.com/xyz/abc/
Connection: keep-alive
Related
I am trying to fetch data from a website using sockets and I am getting a redirect but the redirect is same as the previous url
The below code works perfectly
import requests
r = requests.get('https://links.papareact.com/f90',
allow_redirects=False)
print(r.status_code)
print(r.headers["location"])
Here is the output Location header is new url
301
http://pngimg.com/uploads/amazon/amazon_PNG11.png
Here is the socket code which behaves weird
import socket
HOST = "links.papareact.com"
PORT = 80
path = "f90"
headers = f"GET /{path} HTTP/1.1\r\n" + \
f"Host: {HOST}\r\n\r\n"
connection = (HOST, PORT)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(connection)
s.send(headers.encode())
while True:
data = s.recv(4096).decode().strip()
if data.endswith("\r\n\r\n") or not data:
break
print(data)
Output
HTTP/1.1 301 Moved Permanently
Date: Tue, 17 Aug 2021 09:15:33 GMT
Transfer-Encoding: chunked
Connection: keep-alive
Cache-Control: max-age=3600
Expires: Tue, 17 Aug 2021 10:15:33 GMT
Location: https://links.papareact.com/f90
Report-To: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=0ptwEG6zbfCPDGYczBruC%2FNuMmmsfwqSd6emUpu2aRIa9JtNvIpV3rcWZjfdMrP7EV9EM94UxTx4XbEk4P6KBk4PIb%2BLxPrwitq1Fo10u%2FtGnJnCFqFFh8XGutpJsIy13zCaUYGf"}],"group":"cf-nel","max_age":604800}
NEL: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
Server: cloudflare
CF-RAY: 6801cc6c5d301d14-BLR
alt-svc: h3-27=":443"; ma=86400, h3-28=":443"; ma=86400, h3-29=":443"; ma=86400, h3=":443"; ma=86400
Here the Location Header is same as the previous url
Please explain why is this happening and a possible solution to get the expected result ? :(
Here is the socket code which behaves weird
Nothing weird here. The redirect is according to the location header to https:// (encrypted, port 443) while your original request was for http:// (not encrypted, port 80).
This is a pretty common behavior of web sites that they redirect a plain HTTP request to the same path with HTTPS. If you then access this new (HTTPS) location you would likely get the same redirect as you did with your requests.get('https://..., i.e. to http://pngimg.com/uploads/amazon/amazon_PNG11.png.
I'm looking for a solution with redirects to another domain if the response from HTTP server was 404.
acl not_found status 404
acl found_ceph status 200
use_backend minio_s3 rsprep ^HTTP/1.1\ 404\ (.*)$ HTTP/1.1\ 302\ Found\nLocation:\ / if not_found
use_backend ceph if found_ceph
But still not working, this rule goes to minio_s3 backend.
Thank you for you advice.
When the response from this backend has status 404, first add a Location header that will send the browser to example.com with the original URI intact, then set the status code to 302 so the browser executes a redirect.
backend my-backend
mode http
server my-server 203.0.113.113:80 check inter 60000 rise 1 fall 2
http-response set-header Location http://example.com%[capture.req.uri] if { status eq 404 }
http-response set-status 302 if { status eq 404 }
Test:
$ curl -v http://example.org/pics/funny/cat.jpg
* Hostname was NOT found in DNS cache
* Trying 127.0.0.1...
* Connected to example.org (127.0.0.1) port 80 (#0)
> GET /pics/funny/cat.jpg HTTP/1.1
> User-Agent: curl/7.35.0
> Host: example.org
> Accept: */*
The actual back-end returns 404, but we don't see it. Instead...
< HTTP/1.1 302 Moved Temporarily
< Last-Modified: Thu, 04 Aug 2016 16:59:51 GMT
< Content-Type: text/html
< Content-Length: 332
< Date: Sat, 07 Oct 2017 00:03:22 GMT
< Location: http://example.com/pics/funny/cat.jpg
The response body from the back-end's 404 error page will still be sent to the browser, but -- as it turns out -- the browser will not display it, so no harm done. This requires HAProxy 1.6 or later.
#Michael's answer is rather good, but isno't working for me for two reasons:
Mainly because the %[capture.req.uri] tag resolves to empty (HA Proxy 1.7.9 Docker image)
Also due to the fact that the original assumptions are incomplete, due to the fact that the frontend section is missing...
So I struggled for a while, as you find all kinds of answers on the Internet, between those guys who swear the 404 logic should be put in the frontend, vs those who choose the backend, and any possible kind of tags...
This is my answer, which works for me.
My use case is that if an image is not found on the backend behind HA Proxy, then an S3 bucket is checked.
The entry point is: https://myhostname:8080/path/to/image.jpeg
defaults
mode http
global
log 127.0.0.1:514 local0 debug
frontend come_on_over_here
bind :8080
# The following two lines are here to save values while we have access to them. They won't be available in the backend section.
http-request set-var(txn.path) path
http-request set-var(txn.query) query
http-request replace-value Host localhost:8080 dev.local:80
default_backend onprems_or_s3_be
backend onprems_or_s3_be
log global
acl path_photos var(txn.path) -m beg /path/prefix/i/want/to/strip/off
acl p_ext_jpeg var(txn.path) -m end .jpeg
acl is404 status eq 404
http-response set-header Location https://mybucket.s3.eu-west-3.amazonaws.com"%[var(txn.path),regsub(^/path_prefix_i_want_to_strip_off/,/)]?%[var(txn.query)]" if path_photos p_ext_jpeg is404
http-response set-status 301 if is404
server onprems_server dev.local:80 check
I have a server that runs on Nginx (ubuntu 16). I also have a domain name that redirects to the IP of this server. Of course, I want to show the user a domain name in the address bar, not IP (as it is now). To do this, I changed the site configuration settings in the /etc/nginx/sites-aviable folder to the following: (the project is written in symfony, location is mostly from docks on it)
server {
listen 80;
server_name **.***.***.***; #My server ip
return 301 $scheme://example.com$request_uri;
}
server {
listen 80;
server_name example.com www.example.com;
root /var/www/example.com/web;
index app.php app_dev.php;
location / {
try_files $uri /app.php$is_args$args;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
}
# DEV
location ~ ^/(app_dev|config)\.php(/|$) {
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
}
# PROD
location ~ ^/app\.php(/|$) {
try_files $uri =404;
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
internal;
}
# Phpmyadmin Configurations
location /phpmyadmin {
root /usr/share/;
index index.php index.html index.htm;
location ~ ^/phpmyadmin/(.+\.php)$ {
try_files $uri =404;
root /usr/share/;
#fastcgi_pass 127.0.0.1:9000;
#fastcgi_param HTTPS on; # <-- add this line
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME document_root$fastcgi_script_name;
include fastcgi_params;
}
location ~*^/phpmyadmin/(.+\.jpg|jpeg|gif|css|png|js|ico|html|xml|txt))${
root /usr/share/;
}
}
location /phpMyAdmin {
rewrite ^/* /phpmyadmin last;
}
location ~ \.php$ {
return 404;
}
error_log /var/log/nginx/project_error.log;
access_log /var/log/nginx/project_access.log;
}
As a result, now the user sees the domain name in the address bar, but it does not bring joy - the browsers write ERR_TOO_MANY_REDIRECTS and do not show the content.
As I understand, in some place there is a recursive redirect. In addition to */nginx/sites-aviable/example.com there are no other configs in this folder (default file is fully commented out).
Could it be that the server receiving a request to the address **.***.***.***:80 redirect it to example.com, and the domain services, catching the request, will redirect to **.***.***.***:80, and so on a loop?
How then to be? Or is the problem somewhere in local configurations?
UPD It is the contents of the access.log file after the attempt to open the site once:
(the line is repeated 9 times, . . . * - IP of my server)
**. ***. ***. *** - - [03/Oct/2017: 11: 59: 07 +0300] "GET / HTTP/1.1" 301 194 "-" "Mozilla/5.0 (X11; Fedora; Linux x86_64; rv: 54.0) Gecko/20100101 Firefox/54.0"
UPD 2
I try curl -L -I http://mysite
Result of curl:
'HTTP/1.1 302 Moved Temporarily
Server: nginx
Date: Tue, 03 Oct 2017 09:49:32 GMT
Content-Type: text/html
Content-Length: 154
Connection: keep-alive
Location: http://**.***.***.*** //(my server IP)
HTTP/1.1 301 Moved Permanently
Server: nginx/1.10.3 (Ubuntu)
Date: Tue, 03 Oct 2017 09:49:32 GMT
Content-Type: text/html
Content-Length: 194
Connection: keep-alive
Location: http://example.com //(my cite)
....
// some repeats this
....
curl: (52) Empty reply from server'
Redirect 301 is described in my configuration.
Why there is a redirect 302 - I do not know. Is this the result of DNS services?
Try to debug using curl:
For example:
curl -L -I http://yoursite
the option -L will follow redirects and the -I will only show the headers.
In the output search for HTTP/1.1 301 Moved Permanently and the Location: htt.....
Also try to change your conf to either use http or https in many cases is where the loop happends:
return 301 $scheme://
to
return 301 https://
The error was not on the side of my server or the nginx configuration, I did not correctly configure DNS when I had a domain name. Instead of creating an A-record, I set a redirect to the IP of my server
This seems ridiculous but I've not found a working answer in over an hour of searching.
I have a static website running off nginx (which happens to be behind Varnish). The index file is called index.html. I want to redirect anyone who actually visits the URL mydomain.com/index.html back to mydomain.com.
Here is my nginx config for the site:
server {
listen 8080;
server_name www.mydomain.com;
port_in_redirect off;
location / {
root /usr/share/nginx/www.mydomain.com/public;
index index.html;
}
rewrite /index.html http://www.mydomain.com/ permanent;
}
http://www.mydomain.com/index.html responds as expected with a 301 with the location http://www.mydomain.com/ but unfortunately http://www.mydomain.com/ also serves a 301 back to itself so we get a redirect loop.
How can I tell nginx to only serve the 301 if index.html is literally in the request?
Add a new location block to handle your homepage, and use try_files directive (instead of "index index.html;") to look for the index.html file directly. Note that try_files requires you to enter at least 2 choices. So I put the same file twice.
location = / {
root /usr/share/nginx/www.mydomain.com/public;
try_files /index.html /index.html;
}
Looks good based on my experiment:
curl -iL http://www.mydomain.com/index.html
HTTP/1.1 301 Moved Permanently
Server: nginx
Date: Sat, 16 Mar 2013 09:07:27 GMT
Content-Type: text/html
Content-Length: 178
Connection: keep-alive
Location: http://www.mydomain.com/
HTTP/1.1 200 OK
Server: nginx
Date: Sat, 16 Mar 2013 09:07:27 GMT
Content-Type: text/html
Content-Length: 4
Last-Modified: Sat, 16 Mar 2013 08:05:47 GMT
Connection: keep-alive
Accept-Ranges: bytes
[UPDATE]
The root cause of the redirect loop is the 'index' directive, which triggers nginx to do another round of location match again. That's how the rewrite rule outside the location block gets executed again, causing the loop. So the 'index' directive is like a "rewrite...last;" directive. You don't want that in your case.
The trick is to not trigger another location match again. try_files can do that efficiently. That's why I picked it in my original answer. However, if you like, another simple fix is to replace
index index.html;
by
rewrite ^/$ /index.html break;
inside your original "location /" block. This 'rewrite...break;' directive will keep nginx stay inside the same location block, effectively stop the loop. However, the side effect of this approach is that you lose the functionality provided by 'index' directive.
[UPDATE 2]
Actually, index directive executes after rewrite directive. So the following also works. Note that I just added the rewrite...break; line. If the request uri is "/", nginx finds the existing file /index.html from the rewrite rule first. So the index directive is never being triggered for this request. As a result, both directives can work together.
location / {
root /usr/share/nginx/www.mydomain.com/public;
index index.html;
rewrite ^/$ /index.html break;
}
Looks like you really don't want index.php to show up in the address bar, is that correct?
If you add a rewrite directive to the nginx config, you'll get a redirect loop, as you have experienced. If you are open to a javascript solution, you can place this anywhere in your index.html to silently rewrite the address bar:
<script>
history.pushState(null, '', '/');
</script>
For more information
Keep in mind that while most modern browsers support the history API, not all do (namely, most versions of IE).
What I'm trying to do is route all requests to /rdr/extern_url to redirect to extern_url through my web server instead of doing it through PHP.
location /rdr {
rewrite ^/rdr/(.*)$ $1 permanent;
}
What's wrong here is it if I access http://localhost/rdr/http://google.com my browser is telling me:
Error 310 (net::ERR_TOO_MANY_REDIRECTS): There were too many redirects.
How do I redirect properly?
Trivial check:
$ curl -si 'http://localhost/rdr/http://www.google.com' | head -8
HTTP/1.1 301 Moved Permanently
Server: nginx/1.2.0
Date: Sun, 05 Aug 2012 09:33:14 GMT
Content-Type: text/html
Content-Length: 184
Connection: keep-alive
Location: http:/www.google.com
As you can see, there is only one slash after scheme in Location.
After adding the following directive to server:
merge_slashes off;
We'll get the correct reply:
$ curl -si 'http://localhost/rdr/http://www.google.com' | head -8
HTTP/1.1 301 Moved Permanently
Server: nginx/1.2.0
Date: Sun, 05 Aug 2012 09:36:56 GMT
Content-Type: text/html
Content-Length: 184
Connection: keep-alive
Location: http://www.google.com
It becomes clear from the comments you may want to pass hostname without the schema to your redirecting service. To solve this problem you need to define two locations to process both cases separately:
server {
listen 80;
server_name localhost;
merge_slashes off;
location /rdr {
location /rdr/http:// {
rewrite ^/rdr/(.*)$ $1 permanent;
}
rewrite ^/rdr/(.*)$ http://$1 permanent;
}
}
Here I've defined /rdr/http:// as a sub-location of /rdr just to keep the redirector service in one block -- it's perfectly valid to create both locations at server-level.