Multiple TYPO3s behind nginx issue - nginx

I want to host several TYPO3s behind an nginx reverse proxy using the following structure:
Internal server (apache):
http://some.internal.ip/site1
http://some.internal.ip/site2
http://some.internal.ip/site3
External server (nginx, reverse proxy):
http://site1.mydomain.com
http://site2.mydomain.com
http://site3.mydomain.com
So here're the relevant parts of my nginx.conf
http {
...
server {
listen 80;
server_name site1.mydomain.com;
location / {
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 http://some.internal.ip/site1$request_uri;
}
}
...
server {
(like above with site2 and so on)
...
}
(I quickly rewrote the configuration from https to http in order not to make things more complicated then necessary.)
Now, the nginx-Part of this seems to work - it's the Typo3 that seems to cause the trouble as all elements on the site are referred to as
http://some.internal.ip/site1/example.php
instead of
http://site1.mydomain.com/example.php
I'm aware of
[SYS][reverseProxyIP]
and
[SYS][reverseProxyHeaderMultiValue]
which I set accordingly, but that doesn't seem to work - which in turn is what should be expected based on my understanding.
Is there another way to approach this issue or am I simply trying something that simply can't be done this way?

Are you using config.baseUrl = http://some.internal.ip/site1/ on your website?
If you are, I recommend you to use config.absRefPrefix = / instead.
See also Søren Mallings article from 2013 which is still correct.

Related

Is there a preferred nginx config to run wsgidav behind a reverse proxy?

so far I simply use
location /drive/ { # wsgidav
proxy_pass http://127.0.0.1:8080/;
}
and it seems to do the trick. I can put files to the server, get them, browse through directories etc. all from Windows explorer.
However, I can not rename a file on the server. When I attempt it, I get 502 Bad Gateway
14:57:44.803 - INFO : 127.0.0.1 - (anonymous) - [2022-10-14 12:57:44] "MOVE /user/Downloads/Text.txt" dest="https://myserver.com/drive/user/Downloads/Text1.txt", length=0, depth=0, overwrite=F, elap=0.001sec -> 502 Bad Gateway
Am I missing anything in the configuration?
Thx
Sry for the noise, found one myself.
Will just leave this here in case others find it useful.
There is a closed issue regarding the problem that files can't be renamed behind a reverse proxy. One solution suggested to "Configure the reverse proxy to rewrite the Destination header's protocol from 'https:' to 'http:'".
I followed this suggestion and added a mapping rule outside of the config's server section
map $http_destination $driveDestination { # otherwise MOVE results in a 502 Bad Gateway
default $http_destination;
"~*^https://myserver.com/drive/(.+)" /$1;
}
and the following location for the webdav drive
## Begin - wsgidav
location /drive/ { # trailing slash means it will be added
proxy_pass http://127.0.0.1:8080/; # - trailing slash means location will be dropped
# https://github.com/mar10/wsgidav/issues/183
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_buffering off;
client_max_body_size 0;
proxy_request_buffering off;
proxy_set_header Destination $driveDestination; # result of map command above
}
## End - wsgidav
And, alas, it works.

Nginx reverse proxy prevent changing host for other locations

I’m trying to get this done for a couple of days and I can’t. I’m having two web apps, one production and one testing, let’s say https://production.app and https://testing.app. I need to make a reverse proxy under https://production.app/location that points to https://testing.app/location (at the moment I only need one functionality from the testing env in prod). The configuration I created indeed proxies this exact location, but that functionality also loads resources from /static directory resulting in request to https://production.app/static/xyz.js instead of https://testing.app/static/xyz.js, and /static can’t be proxied. Is there a way to change headers only in this proxied traffic so that it’s https://testing.app/static (and of course any other locations)?
Below is my current config (only directives regarding proxy):
server {
listen 443 ssl;
server_name production.app;
root /var/www/production.app;
location /location/ {
proxy_pass https://testing.app/location/;
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-Proto $scheme;
}
}
Have a good day :)
Your question title isn't well written. It has nothing to do about "changing headers", and nginx location, while being essentially tied to the request processing, isn't the right term there too. It should be something like "how to serve the assets requested by proxied page in a different way than the others".
Ok, here we go. First of all, do you really understand what exactly does the following config?
location /location/ {
proxy_pass https://testing.app/location/;
}
The URI prefix /location/ specified after the https://testing.app upstream name has the following effect:
The /location/ prefix specified in the location directive truncated from the processed URI.
Processed UIR is being prepended with the /location/ prefix specified in the proxy_pass directive before being passed to the upstream.
That is, if these prefixes are equal, the following configuration will do the same eliminating those steps (therefore processing the request slightly more efficiently):
location /location/ {
proxy_pass https://testing.app;
}
Understanding this is a key concept to the trick we're going to use.
Since all the requests for static assets made from the /location/ page will have the HTTP Referer header equal to http://production.app/location/ (well, unless you specify no-referer as you page referrer policy, and if you are, the whole trick won't work at all unless you change it), we can rewrite a request URI that matched some conditions (say start with the /static/ or /img/ prefix) redirecting it to some special internal location using the following if block (should be placed at the server configuration level):
if ($http_referer = https://production.app/location/) {
rewrite ^/static/ /internal$uri;
rewrite ^/img/ /internal$uri;
...
}
We can use any prefix, the /internal one used here is only as example, however used prefix should not interfere with your existing routes. Next, we will define that special location using the internal keyword:
location /internal/ {
internal;
proxy_pass https://testing.app/;
}
Trailing slash after the http://testing.app upstream name here is the essential part. It will make the proxied URI returning to its original state, removing the /internal/ prefix added by the rewrite directive earlier and replacing it with a single slash.
You can use this trick for more than one page using regex pattern to match the Referer header value, e.g.
if ($http_referer ~ ^https?://production\.app/(page1|page2|page3)/) {
...
}
You should no try this for anything else but the static assets or it can break the app routing mechanism. This is also only a workaround that should be used for testing purposes only, not something that I can recommend for the production use on a long term basis.
BTW, are you sure you really need that
proxy_set_header Host $host;
line in your location? Do you really understand what does it mean or you are using it just copy-pasting from some other configuration? Check this answer to not be surprised if something goes wrong.

Multiple "relays" in NGINX - is it possible?

Is it possible to configure NGINX to something like multiple reverse-proxy? So, instead of one proxy_pass:
location /some/path/ {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://localhost:8000;
}
to have multiple proxy_passs (relays)? I need something like load balancer but to send not to one of them, but TO ALL (see the scheme below).
TO BE ACCURATE: IT'S NOT REVERSE PROXY AND IT IS NOT LOAD BALANCING AS WELL.
The response may be retrieving from any of them, maybe the last one or even to be "hardcoded" with some configuration directives - it does not matter (it's enough to be HTTP 200 and will be ignored)... So, the scheme should look like:
.----> server 1
/
<---> NGINX <-----> server 2 (response from 2nd server, but it maybe any of them!)
\
`----> server 3
Maybe some extension for NGINX? Is it possible at all and how to do it if it is?
Yes, it is possible.
What you are searching for is called mirroring. And nginx implements it since version 1.13.4, see the directive mirror for more info.
Example:
location = /mirror1 {
internal;
proxy_pass http://mirror1.backend$request_uri;
}
location = /mirror2 {
internal;
proxy_pass http://mirror2.backend$request_uri;
}
...
location /some/path/ {
mirror /mirror1;
mirror /mirror2;
proxy_pass http://primary.backend;
}
(you can also specify it for whole server (or even http) and disable for locations where you don't need it).
Alternatively you could try post_action (but this is undocumented feature and if I remember correctly is deprecated).

Nginx reverse proxy configuration to handle absolute paths

I am running a web application on http://localhost:9000
that I would like to reverse proxy to http://localhost/myapplication.
The problem is that the application is using absolute paths link which is translated to http://localhost/some-directory/some-file.html with my current configuration.
How do I configure nginx to handle these paths so that they point to http://localhost/myapplication/some-directory/some-file.html instead?
Right now the proxy pass configuration looks like this:
location /myapplication/ {
proxy_pass http://localhost:9000/;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
Similar question to https://serverfault.com/questions/714322/nginx-proxy-pass-and-absolute-paths. So here is my answer from over there (slightly adapted for your example):
The only way I found to make this work is to use the HttpSubModule and adding sub_filter directives. So given your example it could look like this:
sub_filter 'href="/' 'href="/myapplication/';
Obviously the more specific your matching is the more variants you'll have to add. If you go less specific, like just match "/ or '/ then you need less rules but run into the danger of substituting the wrong thing.
You probably also need to add:
sub_filter_types *;
So it doesn't just match text/html (which is the default) but also javascript and css files. Obviously * is the lazy approach which might break things and using specific mimetypes should be preferred.
Ultimately the correct way is to fix the web application. Most web frameworks support something like a base url/root url/url prefix (there doesn't seem to be standard name for this) which you can set to avoid exactly this problem.

Server behind nginx reverse proxy ignores relative path in URL

My title isn't the best, my knowledge of webstuff is quite basic, sorry.
What I want to achieve
I have one box fanbox running nginx on Archlinux that I use as main entry point to my home LAN from the internet (namely work where I can only get out to port 80 and 443) via the reverse proxy facility using a changing domain name over which I have no control and that we will call home.net for now.
fanbox has its ports 80 and 443 mapped to home.net, that part was easy.
I have 2 webservers behind the firewall, web1.lan, web2.lan, web2ilo.lan. Both of these have various applications (which may have same name on different machines) that can directly be accessed on the LAN via standard URLs (the names are given as examples, I have no control over the content):
http://web1.lan/phpAdmin/
http://web1.lan/gallery/
http://web2.lan/phpAdmin/
http://web2.lan/dlna/
...and so on...
Now web2ilo.lan is a particular case. It's the out of band management web interface of the HP server web2.lan. That particular webserver offers only 1 application, so it can only be accessed via its root URL:
http://web2ilo/login.html
My goal is to access these via subpath of home.net like this:
http://home.net/web1/phpAdmin/
http://home.net/web1/gallery/
http://home.net/web2/phpAdmin/
http://home.net/web2/dlna/
http://home.net/web2ilo/login.html
My problem
That nearly works but the web applications tend to rewrite URLs so that after I login to, respectively:
http://home.net/web1/phpAdmin/login.php
http://home.net/web2ilo/login.html
the browser is redirected respectively to
http://home.net/phpAdmin/index.php
http://home.net/index.html
Note that the relative subpaths web1 and web2ilo have gone, which logically give me a 404.
My config
So far, I've searched a lot and I tried many options in nginx without understanding too much what I was doing. Here is my config that reproduces this problem. I've left SSL out for clarity.
server {
listen 443 ssl;
server_name localhost;
# SSL stuff left out for clarity
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
location /web1/ {
proxy_set_header Host $host;
proxy_redirect off;
proxy_pass https://web1.lan/;
}
location /web2/ {
proxy_set_header Host $host;
proxy_redirect off;
proxy_pass https://web2.lan/;
}
location /web2ilo/ {
proxy_set_header Host $host;
proxy_redirect off;
proxy_pass https://web2ilo.lan/;
}
}
After first answers
After the first couple of answers (thanks!), I realise that my setup is far from common and that I may be heading for trouble all alone.
What would then be a better idea to access the webserver behind the firewall without touching frontend ports and domain/hostname ?
You may wish to consider the use of setting proxy_redirect to let nginx know that it should modify the "backend" server response headers (Location and Refresh) to the appropriate front-end URLs. You can either use the default setting to allow nginx to calculate the appropriate values from your location and proxy_pass directives, or explicitly specify the mappings like below:
proxy_redirect http://web1.lan/ /web1/
See: http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_redirect
Note: This only affects response headers - not any links in HTML content, or any Javascript.
If you experience problems with links in content or Javascript, you can either modify the content on the backend servers (which you've indicated may not be possible), or adjust your proxy solution such that front end paths are the same as the back end ones (e.g., rather than http://frontend/web1/phpAdmin you simply have http://frontend/phpAdmin). This would entail adding location directives for each application, e.g.,
location /phpAdmin/ {
proxy_set_header Host $host;
proxy_redirect off;
proxy_pass https://web1.lan/phpAdmin/;
}
Here is a tested example.
In my docker-compose.yml I use the demo image whoami to test:
whoareyou:
image: "containous/whoami"
restart: unless-stopped
networks:
- default
labels:
- "traefik.enable=true"
- "traefik.http.routers.whoareyou.rule=Path(`/whoareyou`)"
- "traefik.http.routers.whoareyou.entrypoints=web"
- "traefik.http.routers.whoareyou.middlewares=https-redirect#file"
- "traefik.http.routers.whoareyou-secure.rule=Path(`/whoareyou`)"
- "traefik.http.routers.whoareyou-secure.entrypoints=web-secure"
- "traefik.http.routers.whoareyou-secure.tls=true"
In my config.yaml I have my https redirect:
http:
middlewares:
https-redirect:
redirectScheme:
scheme: https
I did not find an answer to my question and decided to try a different approach:
I now have containerized most of my servers
I use Traefik (https://containo.us/traefik/) as my "fanbox" (= reverse proxy) as it covers my needs but also solves in a quite easy fashion the SSL certificates stuff.
Thanks all for your suggestions.

Resources