How to configure nginx reverse-proxy to support external site in iframes - nginx

I'm in the unfortunate situation that I need to extend my react application with an iframe containing an external application.
My application is hosted by a nginx reverse proxy that handles /api and signalr communication.
Unfortunately it also handles the outbout iframe src url.
in this example my site is on the url https://example.com
The iframe src url is in this case "https://external-site.com/someapp/session?token=1234"
When i see the requests in the browser the url has changed to https://example.com/esternal-site.com/someapp/session?token=1234, which needless to say is not working out of the box.
I've been toying with the nginx configuration but has been unable to just pass the request through without modification.
The iframe/destination works as expected when running locally.
I've attempted with a few different configuations inspired by stackoverflow and medium etc. but they've all returned various error codes.
the server runs on port 80, but https is handled by ingress on azure.
This is what i have currently:
upstream bff_service {
server ${BFF_HOST}:${BFF_PORT};
keepalive 32;
keepalive_requests 1000;
keepalive_timeout 75s;
}
server {
listen 80;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
add_header Set-Cookie "msal_client_id=${BFF_MSAL_CLIENT_ID};Path=/;Secure";
}
location /api {
proxy_read_timeout 300s;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host ${BFF_HOST};
proxy_set_header X-NginX-Proxy true;
proxy_pass ${BFF_PROTOCOL}://bff_service;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_redirect off;
}
location ^~ /external-site.com {
add_header Content-Security-Policy "frame-src 'self' https://external-site.com";
proxy_pass https://external-site.com/$request_uri;
}
}
I've also tried adding the lines below to the location:
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-NginX-Proxy true;
I'm looking for a configuration that allows me to embed an iframe with an external location. Perhaps even avoid nginx proxying it at all?

Related

Logging issue with Nginx reverse proxy

I am using the following Nginx reverse proxy configuration.
server {
listen 80;
listen [::]:80;
server_name www.test.com;
access_log /var/log/nginx/www.test.com.access.log;
error_log /var/log/nginx/www.test.com.error.log warn;
location / {
proxy_pass http://12.23.45.78:8080;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
}
}
By adding the access_log and error_log parameters, it will log the access log.
Now I want to skip some logging, such as not logging favicon.ico and apple-touch-icon.png, so I added the following configuration.
location ~* ^/(?:favicon|apple-touch-icon) {
log_not_found off;
access_log off;
}
But here is the problem, when I do this, http://www.test.com/favicon.ico will not be accessed properly, it prompts "404 Not Found" error.
It seems to indicate that the reverse proxy host is taking over the favicon.ico access without forwarding it to upstream for processing, is this normal Nginx behavior please?
If this is normal behavior, how should I set not to log for a given resource?
Any help is appreciated in advance!
Every request ends up in some location (if not being finished before). Every location uses its own content handler. Unless you specify something explicitly via content handler declaration directive (examples include, bit not limited to proxy_pass, fastcgi_pass, uwsgi_pass, etc.), it will be a static content handler to serve the requested content from local filesystem. Check my ServerFault answers (1, 2) to find out some more details.
In some cases such a task can be solved using the map block, e.g.
map $uri $log {
~^/(?:favicon|apple-touch-icon) off;
default /var/log/nginx/access.log;
}
server {
...
access_log $log;
This approach can work when you need to implement lets say conditional basic auth (example). Unfortunately it won't work with the access_log directive - instead nginx will create the second log file named off for icon requests. So if you want every request to be passed to the 12.23.45.78 upstream, I don't see any other way but to duplicate content handler declaration for both locations. However every other used directive can be moved one level up, thus being inherited by both locations:
server {
listen 80;
listen [::]:80;
server_name www.test.com;
error_log /var/log/nginx/www.test.com.error.log warn;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
location / {
access_log /var/log/nginx/www.test.com.access.log;
proxy_pass http://12.23.45.78:8080;
}
location ~ ^/(?:fav|apple-touch-)icon {
access_log off;
proxy_pass http://12.23.45.78:8080;
}
}
On the other hand, nothing can stop you from serving those two files locally and not passing those requests anywhere. Just put them into some dedicated directory and use a location with a static content handler:
location ~ ^/(?:fav|apple-touch-)icon {
access_log off;
root /full/path/to/folder/with/icons;
}

WildFly console served with nginx

I stuck to configure a simple reverse proxy on AWS.
Since we have one host (reverse proxy nginx) serving the public access I decided to follow the rules and created the following configuration.
server {
listen 9990;
server_name project-wildfly.domain.me;
access_log /var/log/nginx/wildfly.access.log;
error_log /var/log/nginx/wildfly.error.log;
proxy_buffers 16 64k;
proxy_buffer_size 128k;
root /var/www/;
index index.html index.htm;
location /console {
proxy_set_header Host $server_addr:$server_port;
proxy_set_header X-Forwarded-Proto $scheme;
add_header Cache-Control "no-cache, no-store";
proxy_pass http://10.124.1.120:9990/console;
}
location /management {
proxy_set_header Host $server_addr:$server_port;
proxy_set_header X-Forwarded-Proto $scheme;
add_header Cache-Control "no-cache, no-store";
proxy_pass http://10.124.1.120:9990/management;
}
}
This will serve the admin console and I'm able to log in with the user. Then this message appears:
Access Denied
Insufficient privileges to access this interface.
Nothing within the error log. Thanks for any hint!
I had the same issue when configuring Wildfly 15 and nginx 1.10.3 as reverse proxy.
Setup was very similar to the first post, redirecting /management & /console to wildflyhost:9990.
I was able to access the console directly via :9990 and when comparing the network traffic between direct and nginx-proxied traffic, I noticed that Origin and Host were different.
So in my case the solution was to force the Origin and Host headers in Nginx to something that Wildfly is expecting. I couldn't find this solution elsewhere, so I'm posting it here for future reference anyhow although the thread is old.
location /.../ {
proxy_set_header Host $host:9990;
proxy_set_header Origin http://$host:9990;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass_request_headers on;
proxy_pass http://wildflyhost:9990
...
}
Maybe you need turn on management module.
Try this:sh standalone.sh -b 0.0.0.0 -bmanagement 0.0.0.0 &

nginx: rewriting rule to access Mattermost instance

I have a VPS whose primary interface is accessible via two internet names which I'll give here as personal.me and company.com. I am running a Mattermost server and can access it via personal.me using the following nginx rule:
server {
server_name personal.me;
location / {
client_max_body_size 50M;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Frame-Options SAMEORIGIN;
proxy_pass http://localhost:8065;
}
}
This is working perfectly well but I would also like to access the instance via http://company.com/fora/ -- the point being that this time there is a /fora/ path to remove. I know that I should be using https:// but that is a separate matter, for later. I tried:
server {
listen 80;
server_name company.com;
location / {
root [...];
index index.html;
}
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
location /fora/ {
client_max_body_size 50M;
rewrite /fora/ / break;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Frame-Options SAMEORIGIN;
proxy_pass http://localhost:8065;
}
}
but when I navigate to http://company.com/fora/ although the title-bar changes to Mattermost, there is no content --- the page is blank. Since I can access Mattermost via the personal.me URL, I believe that Mattermost is running correctly.
What is wrong with the company.com rule? Is it something to do with not passing the path into Mattermost?
According to Nginx reverse proxy (proxy_pass) does not pass subfolder and http://forum.mattermost.org/t/blank-page-when-installing-mattermost-with-nginx-proxy-pass-as-subdirectory/1604 this isn't possible but I don't get that ... surely removing a bit of the URL is one of nginx's core capabilities?
This seems to be impossible with Mattermost currently as the app assumes it is at the server root.
See this issue on their github and this ticket for further details and to track when/if this becomes a supported feature.
What we do is create a subdomain for each mattermost service we want to access on a domain. I suggest creating a subdomain fora.company.com then use that subdomain in your nginx settings.

Avoid duplication in password protect URL with proxy in nginx

I have a Flask application served using gunicorn, and with NGINX on top of it. I want to use Basic Authentication (user/password) to protect all URL's starting with /admin, which is the back office, but still continue serving all other URLs with gunicorn without password.
Here is my current NGINX config:
server {
listen 80;
server_name example.com;
charset utf-8;
location / {
proxy_pass http://localhost:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /admin {
auth_basic "Administrator Login";
auth_basic_user_file /home/app/.htpasswd;
# the following four directives are duplicated :(
proxy_pass http://localhost:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
If I don't duplicate the proxy_* directives in the second location block, then the URLs starting with /admin doesn't get forwarded to gunicorn and I get a 404.
Is there any way to avoid the configuration duplication? I tried location nesting but apparently in the end NGINX only "executes" a single location block.
The proxy_pass must be within the location block. However, there's no need to duplicate the proxy_set_header directives, they can be moved into the server block. So your mistake was simply the assumption that proxy_pass could live in the server block :-)

NGINX - proxying to a different Wordpress site while retaining URL

I currently have two WORDPRESS websites sitting behind an NGINX proxy cache:
htxtp://local.example.com
htxtp://local.example.org
I want to access a URL from the first site but serve it from the second site whilst not losing the URL structure of the first (to allow website2.com to see the website1.com cookies).
For example:
I want:
htxtp://local.example.com/somepage/
To proxy the page built at:
htxtp://local.example.org/somepage/
BUT I don't want the URL to BE htxtp://local.website2.com.
My NGINX config is as follows:
server {
listen 80;
server_name local.example.com;
access_log logs/local.example.com.access.log;
error_log logs/local.example.com.error.log;
location /somepage {
proxy_pass http://localhost:8080;
proxy_redirect off;
proxy_buffering off;
proxy_set_header Host local.example.org;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location / {
proxy_pass http://localhost:8080;
proxy_redirect off;
proxy_buffering off;
proxy_set_header Host local.example.com;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
Any suggestions? I am trying to work out where the actual redirect is happening.

Resources