Proxy_pass ignoring port - nginx

I have a CentOS server running NGINX listening to 80 and a DB servering an app on 8080. I want to be able to Type
http://example.com/dev/abc
and have it actually access
http://example.com:8080/apex/abc or http://localhost:8080/apex/abc
I have used this location configuration
location /dev {
proxy_pass http://example.com:8080/apex;
}
However when I try it out the url displayed is
http://example.com/apex/apex
the page is not found and the log says:
2018/06/14 12:51:33 [error] 7209#0: *2067 open()
"/usr/share/nginx/html/apex/apex" failed (2: No such file or directory),
client: 124.157.113.187, server: _, request: "GET /apex/apex HTTP/1.1", host: "example.com"
Looks like two strange things are happening
1) Port 80 not 8080 is being used despite the proxy_pass
2) why is apex twice "/apex/apex/"
Help please :)
Adding entire Server block from config file:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name example.com;
root /usr/share/nginx/html;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location /dev {
proxy_pass http://example.com:8080/apex;
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
Update - More information on what the app that might help
The app is Oracle Application Express (APEX) it listens on port 8080.
The URL works as follows:
HTTP://example.com:8080/apex/f?p=[APP]:[Page]:[Session] etc
Where [APP],[Page] and [Session] are all corrisponding numbers
The development environment url is actualy:
http://example.com:8080/apex/f?p=4550
This is the default so if I try http://example.com:8080/apex/ it defaults to http://example.com:8080/apex/f?p=4550 and takes you to the login page
Everything after the app number never changes so that is what I want to replaced by /dev/ http://example.com:8080/apex/f?p=4550:1 -> http://example.com/dev/:1
Once I have leant how this works, I plan to setup three proxy_pass's
example.com/dev ->
http://example.com:8080/apex/f?p=4550
example.com/desktop ->
http://example.com:8080/apex/f?p=1001
example.com/mobile ->
http://example.com:8080/apex/f?p=201
Where the only thing that changes is the app number.
Rewrites are working fine for all three but I don't want the rewrite to be visible in the URL
Here are the rewrites:
location ~ /dev {
rewrite ^/dev(.*) http://smallblockpro.com:8080/apex$1 last;
}
location ~ /desktop/ {
rewrite ^/desktop/(.*) http://smallblockpro.com:8080/apex/f?p=1001:$1 last;
}
location ~ /desktop {
rewrite ^/desktop(.*) http://smallblockpro.com:8080/apex/f?p=1001:$1 last;
}
location ~ /mobile/ {
rewrite ^/mobile/(.*) http://smallblockpro.com:8080/apex/f?p=201:$1 last;
}
location ~ /mobile {
rewrite ^/mobile(.*) http://smallblockpro.com:8080/apex/f?p=201:$1 last;
}

location ~ /desktop/ {
rewrite ^/desktop/(.*) http://smallblockpro.com:8080/apex/f?p=1001:$1 last;
}
The reason you're getting the :8080 port number shown up to the user is because you use absolute URLs in your rewrite directives, which results in NGINX producing 301 Moved responses directly to the user — your presumed expectation that it'll still go through proxy_pass after a rewrite like that is incorrect, see http://nginx.org/r/rewrite:
If a replacement string starts with “http://”, “https://”, or “$scheme”, the processing stops and the redirect is returned to a client.
If you want to just create the mapping between /desktop/$1 on the front-end and /apex/f?p=1001:$1 on the back-end of your Oracle Application Express (APEX), then the best way would be to use the following code on your nginx front-end server:
location /desktop/ {
rewrite ^/desktop/?(.*)$ /apex/f?p=1001:$1 break;
return 400;
proxy_pass http://smallblockpro.com:8080;
}
I would recommend copy-pasting it for each of /dev/, /mobile/ and /desktop/; also, I would not recommend to keep a slash-less versions, as per ServerFault's nginx-reverse-proxy-url-rewrite and how-to-remove-the-path-with-an-nginx-proxy-pass, as nginx already takes care of the requests without the trailing slash in a situation such as yours with the code as I propose above.

Here's the copy-paste from what I'm using on our ORDS / SDW ( sqldev-web ) development server.
Here's a basic example with ORDS for the REST side of the house.
The access is to:
https://xyz.oraclecorp.com/sdw/klrice/metadata-catalog/
Then it's proxied to:
https://xyz.oraclecorp.com:8083/ords/klrice/metadata-catalog/
With this config. Beside not to rewrite to an absolute URI as that will do a full browser redirect vs just rewriting the url for the proxy pass.
location /sdw/ {
rewrite /sdw/(.*) /ords/$1 break;
proxy_pass https://xyz.oraclecorp.com:8083/ords/;
proxy_redirect off;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
The issue you will face is this
rewrite ^/desktop/(.*) http://smallblockpro.com:8080/apex/f?p=1001:$1 last;
APEX will see and write links/redirects/includes ( javascript/css/...) as the .../apex/XYZ which will hit the nginx server and that will not know what to do with a /apex/
Here's an example of that based on my above setup. Notice my request to /sdw/ turns into a Location redirect to /ords/
wget -S https://xyz.oraclecorp.com/sdw/
--2018-06-21 17:10:28-- https://xyz.oraclecorp.com/sdw/
Resolving xyz.oraclecorp.com... 123.456.789.123
Connecting to xyz.oraclecorp.com|123.456.789.123|:443... connected.
HTTP request sent, awaiting response...
HTTP/1.1 302 Found
Server: nginx/1.12.1
Location: https://xyz.oraclecorp.com/ords/f?p=4550:1:375440000433:::::
Location: https://xyz.oraclecorp.com/ords/f?p=4550:1:375440000433::::: [following]
So the easiest thing to do is match up the ords deployment ( /apex/ ) to what the rewrite/redirects are and use proxy pass to internalize the :8080 stuff. So
location ~ /desktop/ {
rewrite ^/desktop/(.*) http://smallblockpro.com/apex/f?p=1001:$1 last;
}
location ~ /apex/ {
proxy_pass http://smallblockpro.com:8080/apex/;
proxy_redirect off;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
This option will let your users have a nice entry point of /desktop/ but then that redirect the /apex/ for the app itself.
There is another option with ORDS url-mappings.xml to keep the /desktop/ also which would be something like this to add in mappings to ords so it knows the /desktop/. Then the nginx could do the same proxy pass for each of the entry urls.
url-mapping.xml file contents
<pool-config xmlns="http://xmlns.oracle.com/apex/pool-config">
<pool name="mypool" base-path="/desktop" />
</pool-config>
then in nginx
location ~ /desktop/ {
proxy_pass http://smallblockpro.com:8080/desktop/;
proxy_redirect off;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

Before you read further go through below SO thread which explains about the extra /apex/
Nginx proxy_pass only works partially
Two issues in your config
You need to pass the correct URL to backend service
You need to make sure you handle any redirects and replace the url correctly
Below is the config I think should work for you
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name example.com;
root /usr/share/nginx/html;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location /dev/ {
proxy_pass http://example.com:8080/apex/;
proxy_redirect http://example.com:8080/apex/ $scheme://$host/dev/;
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}

Related

Nginx: create a location to redirect to another location

I'm trying to redirect a location to another location, but for some reason it doesn't work. My nginx service is running under a Docker container on 8080:80 port.
I have /portal that shows my web application correctly and I would like nginx redirects from / to /portal. I've tried some approaches using location / or location = /, but with no success.
The /portal can be accessed normally by
http://localhost:8080/portal
but for some reason when I access
http://localhost:8080/
the browser redirects to
https://localhost/portal
instead of redirecting to:
http://localhost:8080/portal
Locations:
upstream webportal {
server portal_container:8080;
}
location / {
return 301 /portal;
}
location /portal {
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_pass http://webportal;
}
I was able to fix the problem by adding absolute_redirect off; to my location:
location / {
absolute_redirect off;
return 301 /portal;
}

Problem with nginx location and proxy_pass

I have a rule in my nginx.conf that does not work and I have no idea why. According to the documentation it should work. Part of the config looks like this.
The first rule on port 8100 works and redirects the call http://example.com/api/domains to https://localhost:8181/oan/resources/domains
# Working
server {
listen 8100 default_server;
server_name example.com;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
root /var/www/html/example;
location /api {
proxy_pass https://localhost:8181/oan/resources; break;
}
# For ReactJS to handle routes
location / {
if (!-e $request_filename) {
rewrite ^(.*)$ / break;
}
}
}
# Not working
server {
listen 8200;
server_name api.example.com;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
location / {
proxy_pass https://localhost:8181/oan/resources; break;
}
}
The last call to port 8200: http://api.example.com:8200/domains SHOULD redirect to: https://localhost:8181/oan/resources/domains but does NOT do that.
What is wrong with this config and how can I get the last rule on port 8200 do the correct stuff, always redirect to https://localhost:8181/oan/resources/$uri
When you use proxy_pass with an optional URI within a prefix location block, Nginx will transform the requested URI by performing a straight text substitution.
In your case, the prefix location value is / and the optional URI value is /oan/resources. So a requested URI of /foo will be transformed into /oan/resourcesfoo.
For correct operation, both values should end with / or neither end with /.
For example:
location / {
proxy_pass https://localhost:8181/oan/resources/;
}
See this document for details.

NGINX location directives for the same location

I have a Nexus Repository Manager OSS 3.0 running behind NGINX as a private docker registry. My Docker client (not the official docker client) is expecting a 200 OK and an empty JSON string {} to be returned from /v2/. The problem i'm running into is that Nexus returns the 200 OK but an empty string.
My work-around is to have NGINX return a file containing an empty JSON string for /v2/ requests and proxy /v2/* requests to Nexus.
server {
listen 443 ssl;
server_name nexus.example.com;
ssl_certificate ssl/server.crt;
ssl_certificate_key ssl/server.key;
location = /v2/ {
root /home/ubuntu/www;
index empty.json;
}
location /v2/ {
proxy_pass http://localhost:5000;
proxy_set_header Host $http_host; # required for docker client's sake
proxy_set_header X-Real-IP $remote_addr; # pass on real client's IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 900;
}
}
I would expect this to work, but it directs all traffic (/v2/, /v2/_catalog, /v2/myimage/manifests/latest, etc) to the proxy_pass. How can I make /v2/ requests go to the location to sever the empty.json file?
So you have placed a file at /home/ubuntu/www/v2/empty.json?
The problem is that the index directive will rewrite the URI to /v2/empty.json which is then processed by the location /v2/ block.
One solution would be to create another location to match the rewritten URI and serve it as a static file:
root /home/ubuntu/www;
location = /v2/ {
index empty.json;
}
location = /v2/empty.json {
}
Another solution is to use the error_page directive. But you will still need to specify a location and root to handle the static file(s):
location = /v2/ {
return 405;
error_page 405 =200 /static/empty.json;
}
location / {
root /home/ubuntu/www;
}

Serving a.html from apache while requesting b.html

I'm creating a nginx reverse proxy to apache. Apache runs on port 8080 and nginx on 80.
I hope to achieve the following;
When I request the page http://server/test.html it should be proxyed to http://server:8080/unknown.html
Later on I'll do some eval stuff on the pages and redirect the users to the right pages, but I can't even get this to work. I get the test.html back as response all the time.
My nginx config:
server {
listen 80;
root /var/www/;
index index.php index.html index.htm;
server_name example.com;
location / {
# try_files $uri $uri/ /index.php;
}
location ~ \.html$ {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
#rewrite ^/unknown.html;
proxy_pass http://127.0.0.1:8080;
proxy_redirect http://127.0.0.1/test.html http://127.0.0.1:8080/unknown.html;
}
location ~ /\.ht {
deny all;
}
}
I have zero experience yet, but I'm eager to learn how to get this working...
Firstly, the proxy_redirect directive is the opposite of what you need. It is only used to rewrite the Location response headers in 3xx responses from upstream. See this document for details.
You can use a rewrite ... break statement within the location block that performs the proxy_pass, for example:
location ... {
rewrite ^/test.html$ /unknown.html break;
proxy_pass ...;
}
See this document for details.

Dynamic routing with NGINX

I am an amateur of NGINX, I want to setup NGINX as a Reverse Proxy for my web server.
I would like to know that the NGINX these things as listed below:
When a browser send request with URL: http://nginxproxy.com/client/1.2.3.4/, this request should be passed to the client with IP 1.2.3.4 http://1.2.3.4/, the browser should still show the URL nginxproxy/client/1.2.3.4/
And the same for:
nginxproxy.com/client/2.3.4.5 --> //2.3.4.5
nginxproxy.com/client/2.3.4.6 --> //2.3.4.6
All the others requests that doesn't mach the pattern should come to my default server myserver.
Can I do this by using NGINX?
After researching, I tried with the below configuration:
But unlucky, It doesn't work. The address was changed to http:/1.2.3.4 on browser's address bar, instead of http:/nginxproxy.com/client/1.2.3.4 as expected.
server {
listen 80;
location ~ ^/client {
rewrite ^/client/?(.*) /$2 break;
proxy_pass $scheme://$1;
}
location / {
proxy_pass http://myserver.com;
}
}
Any help is much appreciated.
Doing some more research and based on #Cole input, here is my answer:
location ~ ^/client/(?<site>[^/]+)/? {
rewrite ^.*\/client\/(?<site>[^\/]+)\/?(.*) /$2 break; #passing all the remaining request URIs after <site> group to client server
proxy_pass $scheme://$site;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host/client/$site; #this help to keep the address as it is on the browser's address bar
proxy_set_header X-Forwarded-Proto $scheme;
}
location / {
proxy_pass $scheme://myserver.com
}
server {
listen 80;
location /client/ {
rewrite ^/client/(?<site>[^/]+)/? $scheme://$site;
}
location / {
proxy_pass $scheme://myserver.com;
}
}

Resources