nginx server rewrite configuration - nginx

I have ngnix configured to load balance four tomcat applications. I have a question about the rewrite/redirect rules for my server configuration section.
How do I make requests for http://zavlb.rand.int.co1 go to http://zavlb.rand.int.co1/zi/za/fpages/aaa/FPAGE_AAA_00_00.xhtml?
upstream zavlb {
ip_hash;
# server applnx1.za.rand.int.co1:8080 weight=2;
server applnx01.za.rand.int.co1:8080 weight=2;
server applnx02.za.rand.int.co1:8080 weight=2;
server applnx03.za.rand.int.co1:8080 weight=2;
server applnx04.za.rand.int.co1:8080 weight=2;
}
server {
listen 80;
server_name zavlb.rand.int.co1;
client_max_body_size 5m;
location / {
proxy_pass http://zavlb;
proxy_set_header Host $host;
}
# redirect server error pages to the static page 404/index.html
#
error_page 404 500 502 503 504 404/index.html;
location = 404/index.html {
root /home/za/www;
access_log /var/log/nginx/access.log combined;
}
}

I apologize if i did not understood this correctly, but it seems to be you a URL redirect? In that case, you can use nginx rewrite module as described here: http://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite. Ex:
rewrite / http://zavlb.rand.int.co1/zi/za/fpages/aaa/FPAGE_AAA_00_00.xhtml last;
However, if you want to serve that file from the backend server (proxy) when requests are hitting your root, you can use nginx try_files, like:
location / {
try_files $uri $uri/ /index.xhtml /zi/za/fpages/aaa/FPAGE_AAA_00_00.xhtml =404;
}
Hope this helps.

Related

Proxy_pass ignoring port

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 {
}
}

How to simulate upstream with Nginx for dynamic subdomains

I would proxy a request like the upstream solution.
server_name ~^(?<subdomain>.+)\.example\.com$;
root /dev/null;
location / {
error_page 502 #nextserver;
resolver 127.0.0.1:53 valid=300s;
proxy_pass "https://$subdomain";
}
location #nextserver {
error_page 502 #error;
resolver 127.0.0.1:53 valid=300s;
proxy_pass "https://$subdomain-blahblah";
}
location #error {
return 502 'Service is not available';
}
As you can see I would check https://$subdomain and if it doesn't exist or it down then checks https://$subdomain-blahblah.
it works fine but the problem happen when the second server is down, then Nginx doesn't provide Service is not available message.
So the scenario is like
check Server A -> down
check Server B -> down
Return custom error
I couldn't use upstream because the name of servers is dynamic.
I would suggest you to solve this problem differently. Check out this sample. It shows how you can approach the problem:
http{
listen 80;
root /path/to/static/files;
upstream_server subdomain1{
server 192.168.1.100:8000;
server 192.168.1.101:8000;
}
upstream_server subdomain2{
server 192.168.1.102:8000;
server 192.168.1.103:8000;
}
location / {
server_name subdomain1.example.com;
proxy_pass http://subdomain1;
include /etc/nginx/proxy_pass;
}
location / {
server_name subdomain2.example.com;
proxy_pass http://subdomain2;
include /etc/nginx/proxy_pass;
}
}

Nginx upstream with http & https

I have some problem about nginx with http and https bypass, In upstream block
upstream block:
upstream bypass{
server 192.168.99.1:80; #http
server 192.168.99.2:443 backup; #https
}
When http 80 have a problem (server down, etc), I want to redirect to https 443,
This block does not work for me.
location block:
location / {
proxy_pass https://bypass;
proxy_redirect off;
}
How can I resolve this?
This works well: Create server config section for each backend on different port and forward to both ports internally without ssl.
In this example, you can see how the first server acts as main server with cached content (available via https) and if cache content is not available, use the second server (via http).
(using nginx 1.19.6, just for reference)
upstream backends {
server 127.0.0.1:8082;
server 127.0.0.1:8081 backup;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com;
# ssl certs etc here
location / {
proxy_pass http://backends;
proxy_next_upstream error timeout http_404 http_403;
}
access_log /var/log/nginx/access.log upstreamlog;
}
server {
listen 8081;
location / {
add_header X-Cache MISS;
proxy_pass http://server1;
proxy_set_header Host server1;
}
}
server {
listen 8082;
location / {
add_header X-Cache HIT;
proxy_pass https://server2;
proxy_set_header Host server2;
}
}
Taking a shot in the dark. Assuming you were having issues mixing HTTP and HTTPS in the upstream, you could try this in the location block:
location {
try_files #bypass-http #bypass-https =404;
location #bypass-http {
proxy_pass http://bypass;
proxy_redirect off;
}
location #bypass-https {
proxy_pass https://bypass;
proxy_redirect off;
}
}
And if that didn't work, split the bypass upstream block into bypass1 and bypass2 and reference them accordingly in their corresponding location blocks:
upstream bypass1{
server 192.168.99.1:80; #http
}
upstream bypass2{
server 192.168.99.2:443; #https
}
location {
try_files #bypass-http #bypass-https =404;
location #bypass-http {
proxy_pass http://bypass1;
proxy_redirect off;
}
location #bypass-https {
proxy_pass https://bypass2;
proxy_redirect off;
}
}
A third option would be reference them both on port 80, and ensure the second upstream server redirects HTTP requests to HTTPS.

How to redirect requests on IP to domain

Every once in a while someone is trying to access our website through the public ip instead of one of our domains (yes we have multiple country specific domains .dk, .it, .es etc. however we also have .com as the "general").
Now I would like to redirect those requests coming in on the IP-adress to our www.domain.com domain instead. How would I do that in nginx without touching anything BUT requests going directly to the IP?
Here is my nginx.conf
upstream unicorn {
server unix:/tmp/unicorn.mysite.sock fail_timeout=0;
}
server {
listen 80 default deferred;
root /home/deployer/apps/mysite/current/public;
proxy_set_header X-Request-Start "t=${msec}";
if (-f $document_root/system/maintenance.html) {
return 503;
}
error_page 503 #maintenance;
location #maintenance {
rewrite ^(.*)$ /system/maintenance.html last;
break;
}
location ~ ^/assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
try_files $uri/index.html $uri #unicorn;
location #unicorn {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://unicorn;
}
error_page 500 502 503 504 /500.html;
client_max_body_size 4G;
keepalive_timeout 10;
}
So the question would be, how do I modify this to redirect e.g. http://123.123.123.123/some_page to http://www.mysite.com/some_page but leave all other like http://www.mysite.dk/some_pageunchanged?
You could setup a catchall server with the following directives:
listen 80 default_server;
server_name _;
If you have multiple server stanzas, you can use default_server to specify the configuration that is used if the hostname doesn't match any of the other server_name entries. Using an ip number fits this scenario. The server_name _; line acts as a null server_name entry.
It's also useful if one of your servers has multiple domain names.

Nginx proxy_next_upstream doesn't work

I want nginx to search my local host for the file first and on a 404 error it should search server 1.1.1.1.
I am able to fetch the file that is located on local host, but not able to get from server 1.1.1.1.
server {
listen 80;
server_name localhost;
access_log /var/log/nginx/access.log main;
location /products/ {
proxy_next_upstream http_404;
root /var/foo;
}
}
server {
listen 80;
server_name 1.1.1.1;
location /products/ {
#########
}
}
I guess proxy_next_upstream is not switching to the server.
Any help on this would be appreciated.
The proxy_next_upstream directive is a configuration directive to control re-request from a group of upstream servers by a proxy_pass if request to one of them fails. It doesn't make sense without proxy_pass and an upstream block defined. You may use it if you proxy to multiple upstream servers like this:
upstream backends {
server 192.2.0.1;
server 192.2.0.2;
...
}
server {
...
location / {
proxy_pass http://backends;
proxy_next_upstream error timeout http_404;
}
}
If you want nginx to search for a file on disk, and if it's not found - proxy request to another server, configure it e.g. using try_files fallback instead:
location / {
root /path/to/root;
try_files $uri #fallback;
}
location #fallback {
proxy_pass http://...
}
See http://nginx.org/r/try_files for more info about the try_files directive.

Resources