NGINX: Rewrite url and reverse proxy to a different port - nginx

I am having difficulty rewriting url and reverse proxy the request to a spring boot app. Rewrite works but i am losing port number and cause of that it is not working. For example
localhost:80/order.pl converts into localhost/home. The port gets lost and app is not receiving the request
Similar examples online don't work.
server
{
listen 80;
server_name localhost;
set $upstream localhost:8050;
location ~"^\/order.pl$"
{
rewrite "^\/order.pl$ "/home" permanent;
}
location /
{
proxy_set_header X - Forwarded - For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_set_header X - Real - IP $remote_addr;
proxy_buffering off;
proxy_connect_timeout 30;
proxy_send_timeout 30;
proxy_read_timeout 30;
proxy_pass http: //$upstream;
}
}
If I don't do rewrite, reverse proxy is working but with rewrite I am losing port number. Any info would be appreciated.
Thanks

Nginx would not normally specify the port as part of an external redirect if the port number is the same as the default port for the scheme. Port 80 for http and port 443 for https.
You can specify the port explicitly in the rewrite statement.
For example:
location = /order.pl {
return 301 $scheme://$host:$server_port/home;
}
Note: I used curl to test this, as the browser dropped the port from the address-bar for exactly the same reasons.

Related

Nginx redirect subfolder to another port showing original port

How to enable Nginx redirect subfoler to another port using original port? e.g.,
Service1: http://127.0.0.1:5000
Service2: http://127.0.0.1:8080
Exposed IP port via Nginx is 127.0.0.1:6060
The goal is when accessing http://127.0.0.1:6060/sub, it will access http://127.0.0.1:8080, but the URL user see is still http://127.0.0.1:6060/sub.
I tried two configurations, but they didn't work.
server {
listen 6060;
server_name 127.0.0.1;
location /sub/ {
# method 1: use proxy pass, browser says "static resources not found"
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host:6060;
proxy_pass http://127.0.0.1:8080;
# method 2: use rewrite, the URL will be http://127.0.0.1:8080
rewrite ^/pct/(.*)$ http://127.0.0.1:8080 redirect;
}
location / {
proxy_pass http://127.0.0.1:5000;
}
Thanks.

Flask API & nginx alongside each other

I have a server that I'm trying to set up. I have a Flask server that needs to run on api.domain.com, while I have other subdomains pointing to the server. I have one problem. 2/3 subdomains have no problem using nginx. Meanwhile, my script tries to bind to port 80 on the same machine, therefore failing. Is there a way I can bind my Flask REST script to port 80 ONLY for the subdomain 'api'?
My current config is:
server {
server_name api.domain.me;
location / {
error_page 404 /404.html;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_max_temp_file_size 0;
proxy_pass http://127.0.0.1:5050/;
proxy_cache off;
proxy_read_timeout 240s;
}
}
There's a little problem though, nginx likes to turn all POST requests into GET requests, any ideas?
Thanks!
There is no way binding two different applications on port 80 at the same time.
I would set up your api like this:
Bind your Flask API to Port 8080.
On NGINX you can configure you subdomain pointing to your Flask Application
upstream flask_app {
server 127.0.0.1:8080;
}
sever {
listen 80;
server_name api.domain.com;
location / {
proxy_pass http://flask_app/;
proxy_set_header Host $host;
}
}
I actually found out after a bit of diagnosis.
server {
if ($host = api.domain.me) {
return 301 https://$host
}
# managed by Certbot
had to become:
server {
if ($host = api.domain.me) {
return 497 '{"code":"497", "text": "The client has made a HTTP request to a port listening for HTTPS requests"}';
}
Because Certbot tries to upgrade the request to https but the HTTP method gets changed to GET because of the 301 response code.

Nginx preserve $request_uri

I'm not sure if the behavior I want is actually possible natively with nginx but here goes.
I have a server running on port 81 with the following nginx config:
CONFIGURATION OF SERVER1 NGINX
server {
listen 81;
server_name SERVER_DNS_NAME;
location /server1 {
proxy_pass http://127.0.0.1:8084/;
proxy_set_header Host $host;
}
location / {
proxy_pass http://127.0.0.1:8084;
proxy_set_header Host $host:$server_port;
}
}
I have another server running on port 82 with similar configuration. Now what'd i'd like to do is be able to visit them both from port 80 with just different uris.
For example: URL/server1 would take me to the first server, and URL/server2 would take me to the second.
CONFIGURATION OF NGINX LISTENING ON PORT 80
server {
listen SERVER_IP:80;
location /server1{
proxy_set_header Host $host;
http://SERVER_IP:81;
}
location /server2 {
proxy_pass http://SERVER_IP:82;
proxy_set_header Host $host;
}
This works fine when I go to URL/server1. I am successfully routed to the main page on server1. However as soon as I click any of the links present on the page on server1 I get a 404. This is because the site tries to go to URL/some_subdir_of_server1 (for which there is no mapping) rather than doing URL/server1/some_subdir_of_server1. Is this behavior doable? If so how?
Thanks!
Be careful with trailing slashes: in your example, you have
proxy_pass http://SERVER_IP:81/; which will set the proxy URL to root /

nginx proxied redirects use the port number of the proxy, not the host

I'm setting up a web/app/db stack, and the nginx proxy configuration isn't working the way I thought it would.
so here is an example of the stack...the url of the application is:
https://testapp.com
here is the nginx config:
server {
listen 8886;
server_name _;
root /usr/share/nginx/html;
include /etc/nginx/default.d/*.conf;
#ELB
if ($http_user_agent = 'ELB-HealthChecker/2.0') {
return 200 working;
}
#HTTP to HTTPS
if ($http_x_forwarded_proto != 'https') {
return 301 https://$host$request_uri;
}
location / {
set $proxy_upstream_name "testapp.com";
port_in_redirect off;
proxy_pass http://internal-alb.amazonaws.com:8083/;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
proxy_set_header Access-Control-Allow-Origin $http_origin;}
The app is proxied to an internal AWS alb, and it forwards it to a single (at this point) application server.
I'm able to get the site to serve. However, the application creates a redirect on login, and I get the following response.
Request URL:https://testapp.com/login
Request Method:POST
Status Code:302
Remote Address:34.192.444.29:443
Referrer Policy:no-referrer-when-downgrade
Response Headers
content-language:en-US
content-length:0
date:Mon, 11 Sep 2017 18:35:34 GMT
location:http://testapp.com:8083/testCode
server:openresty/1.11.2.5
status:302
The redirect fails because it's being served on 443, not 8083.
For some reason the app or the proxy isn't updating the port as it doing it's reverse proxy thing, so that the redirect has the proxied port NOT the actual application port 443.
What do I need to do with nginx config to get it to redirect correctly.
thanks.
myles.
The normal behaviour of the nginx is to rewrite the upstream address to the address the page was served from. It looks like instead of using your upstream address (http://internal-alb.amazonaws.com:8083/), your app is responding using a mixture of the two (http://testapp.com:8083). You can either change the app behaviour, or, to fix it at the nginx level, can use the proxy_redirect directive.
I'm reasonably sure the directive to fix this is proxy_redirect http://testapp.com:8083/ https://testapp.com/;

Rewrite nginx host and proxypass to squid

I want to achieve the following:
Request Host:
http://example.com.proxy.myserver.com
Should be rewritten to
http://example.com
and passed to a squid server via nginx proxypass.
server {
listen 80;
server_name ~^(?<subdub>.*)\.proxy\.myserver\.com$;
location / {
rewrite ^ $scheme://$subdub break;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $scheme://$subdub;
proxy_set_header Request-URI $scheme://$subdub;
proxy_pass http://localhost:3128;
proxy_redirect off;
}
}
The problem is, that nginx redirects this request immediately to http://example.com
Any ideas how to get this working?
301 redirect is exactly what nginx shall do with that rewrite rule: because you put $scheme://$subdub at the replacement part, nginx will do a 301, ignoring that "break" flag.
If the replacement string begins with http:// then the client will be redirected, and any further rewrite directives are terminated.
Are you trying to "rewrite" or "redirect"? If it's just for rewrite, you can remove that rewrite directive:
rewrite ^ $scheme://$subdub break;
and it will work because your upstream server could rely on the HOST header to determine the traffic target (virtual hosting).
Also your host header sent to the upstream server is wrong. It should be
proxy_set_header Host $subdub;
$scheme should not be put in the Host header.

Resources