Nginx rewrite sends traffic to IP address, not URL - nginx

I have nginx set up as a reverse proxy for a docker microservice. There's a location block that rewrites the url from /wrong to /right:
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
server_name example.com;
location /right {
proxy_pass http://microservice_servers;
}
location /wrong {
rewrite ^/wrong/(\w+) /right/$1 redirect;
}
}
What this is intended to do is rewrite the url from https://example.com/wrong/otherstuff to https://example.com/right/otherstuff.
What actually happens though, is that it rewrites to http://<ip_address>/right/otherstuff.
(One possible complicating factor is that I don't have control of the certs for this site. Those are controlled by the client, who puts them on an app gateway in front of our server. So my nginx config only handles http traffic at port 80, no https from 443. I'm not sure if that's actually relevant, but just in case, there it is.)
I've tried an assortment of changes to the rewrite block, including adding $server_name, changing the flag to last (returns the right content but doesn't change the url), and changing the flag to break (which does not return the expected content).
Any idea what's going on here?

By default, your rewrite...redirect statement will generate a 302 response with the full URL specified in an HTTP Location response header.
You can confirm this using curl -I https://example.com/wrong/otherstuff.
Nginx fills in the protocol and domain name, based on the original request. This server block receives requests over http and we can infer from your question that the Host header uses its IP address.
You either need to specify the full URL in the rewrite statement:
rewrite ^/wrong/(\w+) https://example.com/right/$1 redirect;
Alternatively, use relative URLs:
absolute_redirect off;
See this document for details.

Related

How to redirect all https domain from www to non www using nginx config file nginx.conf?

I want to redirect all domain from www to non-www using Nginx config file nginx.conf.
I have tried using the below configuration but it only work for URL start with HTTP but does not work for HTTPS
I have added below server block
server {
server_name "~^(?!www\.).*" ;
return 301 $scheme://$1$request_uri ;
}
Since you didn't specify listening port in the server block you've shown in your question, it will listen on a plain HTTP TCP port 80 by default. You need to specify
listen 443 ssl;
to listen on an HTTPS TCP port 443. However to make the server block workable via the HTTPS protocol, you'd need to specify an SSL certificate/key (at least), and to made a user browser following a redirect returned by nginx, that certificate should be a valid one, issued for the domain name you want to be redirected, or the browser will complain about invalid certificate and won't follow the redirect location.
So if you want to use some kind of universal server block for redirecting every HTTPS request from www to non-www domain, it will be impossible unless you have a certificate that include every domain name you want do redirect (which seems to be impossible to have for a custom non-predefined list of domain names).
Update
Although this isn't a thing I'd do for myself in a production environment, actually there is a way to achieve workable solution using the lua-resty-auto-ssl (see the documentation examples), OpenResty/lua-nginx-module and the following sever block (remember that server names specified by domain prefix have the lowest priority comparing to exact matched server names, e.g. www.example.com, or server names specified by domain suffix, e.g. *.example.com):
init_by_lua_block {
auto_ssl = (require "resty.auto-ssl").new()
auto_ssl:set("allow_domain", function(domain)
return true
end)
auto_ssl:init()
}
map $host $basename {
~^www\.(.+) $1;
default $host;
}
server {
listen 443 ssl;
server_name www.*;
ssl_certificate_by_lua_block {
auto_ssl:ssl_certificate()
}
ssl_certificate /path/to/dummy.crt;
ssl_certificate_key /path/to/dummy.key;
return 301 https://$basename$request_uri;
}
In order for this to work you'd also need the corresponding plain HTTP block to allow ACME challenge(s) to be successfully completed:
server {
listen 80;
server_name www.*;
location / {
return 301 https://$basename$request_uri;
}
location /.well-known/acme-challenge/ {
content_by_lua_block {
auto_ssl:challenge_server()
}
}
}

Nginx as proxy : how to exclude specific folder under https but not under http

I can rewrite some specific http folders to https folders, but i can't rewrite all https except these specific folders from https to http; i'm stuck in a loop
Using NGinx 1.12 as a proxy, handling both http and https
i have one server section to handle http 80 and one server section to handle https (i know they can be together in the same section).
both of them are beginning that way
location / {
proxy_pass
server {
listen 80;
i have
location ~ ^/(xxx|yyy|zzz)/.*$ {
rewrite ^ https://www.example.com$uri permanent;
}
and anytime i'm in http, it is redirecting to https fine for the xxx,yyy and zzz folders. so far, so good.
but under server {
listen 443 ssl;
, i would like to redirect everything except the xxx,yyy,zzz folder to go back to http.
I did try to do the reverse in the https section meaning :
location / {
rewrite ^ http://www.example.com$uri permanent;
}
and
location ~ ^/(xxx|yyy|zzz)/.*$ {
#do nothing
}
but it is not working, either i get a 404 error or a loop
The only solution i found as Nginx is a proxy is making Apache handling the redirect on its side.
so,
a. nginx 80 is redirecting to nginx 443 specific folders.
b. all https is redirect by nginx 443 to apache 443, and then in apache 443 conf i do a test, if it the specific folders, i stop, and otherwise i redirect to nginx 80.
It's working, but i'm sure it is possible to make nginx handle it and avoid this 1 loop. if someone as a beautiful answer :-)

Fourth-Level Subdomain Forwarding

I've recently been trying to set up a reverse proxy that would forward certain 4th-level subdomains to particular locations. So, for example, this is what I'm trying to accomplish (configuration in my nginx file):
server {
listen 80;
server_name *.server.domain.com;
rewrite ^ https://$server_name$request_uri;
}
The goal here being that if someone went to, for example, http://item1.server.domain.com, they would be re-routed to https://item1.server.domain.com. However, with this configuration, the URL gets rewritten to https://%2A.server.domain.com.
Is there a way to fix this so that the full domain (item1) gets added correctly to the rewritten URL? Ideally, I wanted it to eventually be able to rewrite any subdomain on server.domain.com directly to https.
Thanks!
The $server_name variable contains the text from the value of the server_name directive. The %2A is a URL encoded representation of the leading *.
Use $host or $http_host to obtain the hostname actually requested by the client. See this document for more.
For example:
server {
listen 80;
server_name *.server.domain.com;
return 301 https://$host$request_uri;
}
Note: Restart nginx and clear the browser cache between each test. Check the configuration using nginx -T.

nginx dynamic HTTP/S resolves to https://_

I'm trying to let all traffic for my nginx be redirected to HTTPS, independent of server name. So, any other vhost should be redirected to its HTTPS counterpart.
example.com -> https://example.com
test.com -> https://test.com
...
Yet, instead of using the incoming $server_name or $host (tried both), it keeps redirecting to a plain https://_. Is my config incorrect?
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
return 301 https://$server_name$request_uri;
}
Okay, rather silly. If you have previously setup any non-working configuration (e.g. one which will result in the faulty redirect), the browser will remember this redirect without asking the server again (as according to HTTP 301 - permanently moved). So, either clear the browser's data or try with a different one.

nginx redirect twice from https to http

i have 2 servers, one has ssl and i config it like this,
in the server with SSL certification(which is https:// www.example.com):
location ~^/abc/.* {
proxy_pass http://www.example.com:8214/
}
in another server(which is http:// www.anotherExample.com):
server {
listen 8214;
server_name www.anotherExample.com;
rewrite ^/(.*)$ http://www.anotherExample.com:8080/$1 permanent;
}
and after access https:// www.example.com/abc/api/getGroup
it can't redirect to http:// www.anotherExample.com:8080/api/getGroup
Anything wrong???
There are a couple of things you could do to improve your configuration.
location ^~ /abc/ {
proxy_pass http://www.example.com:8214$uri;
#You should have other directives set here as well.
}
Also, consider setting up an upstream.
Then, for your server block:
server{
listen 8124;
server_name www.anotherExample.com;
rewrite ^/abc/(.*)$ http://www.anotherExample.com:8080/$1 permanent;
}
server{
listen 8080;
server_name www.anotherExample.com;
location ^~ /api/ {
#your_config_here
}
}
The explanation:
In your first location block, you shouldn't have .* in the expression. Nginx will match this for you. Then, when you're proxying, you can explicitly tell Nginx to send the URI as well.
Next, you're sending the URI www.anotherExample.com:8124, which includes /abc/, so you want to extract everything after that.
Lastly, because you've rewritten it to point to 8080 port, you'll need to define a separate server block for this.
I don't know what you're aiming to achieve, but so much proxying and redirects isn't necessary in most cases, and might lead to poor performance. Another consideration that you should take into account is you're sending unencrypted information to anotherExample.com, which, if not on the same local network, might be a security vulnerability.

Resources