plesk & nginx: different domains and subdomains should point to the same file location - nginx

i have a webapplication (on a selfhosted plesk 18.0.48 Obsidian) that should be available by 3 or even more domains.
All Domains should point to the same directory.
The domain names should be preserved.
Currently, each domain has its own plesk subscription.
SSL is a must-have.
the current behavior is:
domain1.de -> /var/www/vhost/webApp1/public;
domain2.de -> /var/www/vhost/webApp2/public;
domain3.de -> /var/www/vhost/webApp3/public;
domainX.de -> /var/www/vhost/webAppX/public;
test.domain1.de -> /var/www/vhost/webApp1/text;
test.domain2.de -> /var/www/vhost/webApp2/text;
test.domain3.de -> /var/www/vhost/webApp3/text;
test.domainx.de -> /var/www/vhost/webAppX/text;
dev.domain1.de -> /var/www/vhost/webApp1/dev;
dev.domain2.de -> /var/www/vhost/webApp2/dev;
dev.domain3.de -> /var/www/vhost/webApp3/dev;
dev.domainx.de -> /var/www/vhost/webAppX/dev;
How could I achieve the following target behavior?:
domain1.de -> /var/www/vhost/webApp/public;
domain2.de -> /var/www/vhost/webApp/public;
domain3.de -> /var/www/vhost/webApp/public;
domainX.de -> /var/www/vhost/webApp/public;
test.domain1.de -> /var/www/vhost/webAppTest/public;
test.domain2.de -> /var/www/vhost/webAppTest/public;
test.domain3.de -> /var/www/vhost/webAppTest/public;
test.domainx.de -> /var/www/vhost/webAppTest/public;
dev.domain1.de -> /var/www/vhost/webAppDev/public;
dev.domain2.de -> /var/www/vhost/webAppDev/public;
dev.domain3.de -> /var/www/vhost/webAppDev/public;
dev.domainx.de -> /var/www/vhost/webAppDev/public;
... and so one.
First, I thought of configuring an nginx reverse proxy via plesk ui
I tried https://stackoverflow.com/a/69956102/7210059 but it does not work, it creates a loop (according to the protocol).
location ~ / {
proxy_pass http://test.domain1.de:443;
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;
}
Second i thought of merging all domains into one subscription, so that i simply can change the root directory of each domain/subdomain.
What is the best approach?

It cannot be done if the domains are in different subscriptions, because the system user accounts and file access permissions are different for each domain. The domain running under system user A cannot access the web space running under system user B etc.
If the domains are in the same subscription, you can use the "Web Hosting Settings" page in Plesk to set them to the same document root directory to achieve your goal. However, sharing the same document root directory for different domains is also not such a great idea. For the main domain example you could instead use the "Add Alias" button to create those as aliases, but for the subdomains that won't work either, because they cannot aliases. So for subdomains you can only set the document root.

Related

airflow 1.10.10 behind Nginx Proxy: Oauth Redirect URL http instead of https

I am deploying Airflow 1.10.10 on Kubernetes using the official Helm Chart (v.7.0.0) but I am running into issues with Oauth.
Here's my setup:
Airflow Webserver with RBAC enabled. Airflow uses Flask Appabuilder in this case.
Server runs behind an Nginx reverse proxy that does https termination.
I try to authenticate against an Azure AD tenant using OAuth
my problem
- When I try to login with the Microsoft account I get the error message "The reply URL specified in the request does not match the reply URLs configured for the application".
- The error is caused by Airflow setting the redirect URL to http://airflow.example.com/oauth_authorized/azure instead of httpS://airflow.example.com/oauhth_authorized/azure
what I think the issue is
Since nginx sends http requests to Flask, flask generates an http url for the redirect url instead of https.
So from what I understand, I need to find a way to tell Airflow/Flask that it should use https to generate the redirect URL instead.
What I tried:
I have two angles of attack:
1. setting the base URL to https explicitly in the webserver_config.py file
I tried putting environ['wsgi.url_scheme'] = 'https' in the config file, but I get a "environ is not defined" error.
Can I even set this in in the config.py file? What would I need to import for it to work?
2. Setting proxy headers in nginx
I tried to set multiple headers in Nginx using Kubernetes annotations, my current settings are:
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
I also tried to set
proxy_set_header Host $host;
but this leads to all traffic being redirected to a comma separated list of domains
airflow.example.com,airflow.example.com
which obviously does not work.
I based these settings on the Flask documentation.
The rest of the Nginx config is the default of the official Nginx ingress controller I have running in my cluster.
Does anybody have an idea what the issue could be? Are my two angles of attack valid or is there a third one that I am missing?
Thanks a lot, any help is appreciated!

Keycloak Admin console not accessible

I'm trying to setup Keycloak on a root server but I cannot access the admin console from the internet.
I've installed the keycloak server and put it behind an nginx reverse proxy on the same machine. I've setup a letsencrypt cert for the domain. I've also setup the admin user for keycloak via script.
When I visit the server with it's domain https://<my-domain> I'm forwarded to https://<my-domain>/auth and there is the keycloak welcome page with a link to "Administration Console". This link points to https://<my-domain>/admin but shows a 404.
At first I thought this might be a problem with nginx so I followed the guide in the docs to setup a load-balancer (https://www.keycloak.org/docs/latest/server_installation/index.html#_setting-up-a-load-balancer-or-proxy). There, under "Verify Configuration" it tells you to open the path https://<my-domain>/auth/realms/master/.well-known/openid-configuration which works as expected and I get a json file with several links and other information in it. However, none of those links do work - all give me a 404.
When I try https://<my-domain>/auth/realms/master I get a JSON response.
So some links do work so I think it's not a problem with nginx but with keycloak itself.
So the basic question is: How do I configure Keycloak so that I can access the admin console via internet? I've read that by default you can only access it on localhost but there must be a way to overwrite this default?
The relevant nginx config:
upstream keycloak {
server 127.0.0.1:8080;
}
server {
listen 443 ssl http2;
# some ssl configuration for letsencrypt
location / {
proxy_pass http://keycloak;
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 $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Some parts in keycloak/standalone/configuration/standalone.xml that I've edited:
<subsystem xmlns="urn:jboss:domain:undertow:10.0" ...>
...
<server name="default-server">
<http-listener name="default"
socket-binding="http"
redirect-socket="proxy-https"
enable-http2="true"
proxy-address-forwarding="true" />
...
</server>
...
</subsystem>
...
<interfaces>
<interface name="management">
<any-address />
</interface>
<interface name="public">
<any-address />
</interface>
</interfaces>
<socket-binding-group name="standard-sockets" ...>
...
<socket-binding name="proxy-https" port="443" />
...
</socket-binding-group>
EDIT
I was able to fix it. The problem was that keycloak was redirecting the initial page from https://<my-domain>/ to https://<my-domain>/auth but then in all other links this additional /auth was missing. So the admin link was pointing to https://<my-domain>/admin/master/console without the /auth part and this page wasn't existing. When I was manually typing the URL with /auth in it I got a page with a "loading.." message but all style and JavaScript files linked where also missing the /auth part in their URLs so nothing was working.
To fix this I had now changed in standalone.xml the line <web-context>auth</web-context> to <web-context>/</web-context> and now everything behaves as expected. There is no redirecting anymore at the start page and all links do work without the /auth part in it.
However, it would be interesting why it wasn't working in the first place and how one solve this if the /auth redirection was intended.
You helped me solve my issue. I was setting the java system property keycloak.frontendUrl (or env KEYCLOAK_FRONTEND_URL), and apparently it wants a full url, not just the hostname. Appending /auth fixed my redirect problems.
It looks like keycloak.hostname.fixed.hostname (KEYCLOAK_HOSTNAME) may also cause problems if /auth isn't appended.
See docs for details on the hostname provider here: https://www.keycloak.org/docs/latest/server_installation/index.html#hostname
I had the same issue with keycloak instances behind nginx reverse proxy in my kubernetes cluster. I fixed it by setting the env PROXY_ADDRESS_FORWARDING to true. PROXY_ADDRESS_FORWARDING=true
add this ENV KC_TRANSACTION_XA_ENABLED=false
Try open
/auth/admin/master/console/
in a Browser.
Additional Info:
https://www.keycloak.org/docs/latest/getting_started/index.html
https://www.keycloak.org/docs-api/8.0/rest-api/index.html
Oh, and I recommend to use a dockerized Keycloak. The upgrade path to a newer Version if much easier.

phpMyAdmin inside docker container via nginx reverse proxy

I installed phpMyAdmin docker image and run it with
# docker run --name phpmyadmin -d --link mariadb:db -p 8081:80 -e PMA_ABSOLUTE_URI=http://servm3/pma --restart unless-stopped phpmyadmin/phpmyadmin
Accessing http://servm3:8081 works fine. The variable PMA_ABSOLUTE_URI is for reverse proxies as seen on the docker page.
Then I set up nginx (locally installed, not inside docker) to act as a reverse proxy (working for several other apps like guacamole).
Inside my nginx.conf I have:
location /pma/ {
proxy_pass http://localhost:8081/;
proxy_buffering off;
}
Accessing http://servm3/pma shows the favicon on the browser tab but instead of the login page only a blank page is shown. Removing the preceding "/" and restarting nginx only gives a 404.
# docker logs phpmyadmin
shows nothing except from the php and nginx service start info, nothing related to phpmyadmin.
Local nginx access log shows several 304 and 404 codes and some 200, error log is not present. Detailled log can be found here on pastebin.
I hope somebody will be able to tell me how to make nginx work as a reverse proxy for the phpMyAdmin docker container.
If some important information is missing please let me know.
Be sure to include the rewrite:
location ~ \/pma {
rewrite ^/pma(/.*)$ $1 break;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
proxy_pass http://localhost:8081;
}
You'll also want to set the PMA_ABSOLUTE_URI environment variable in your docker-compose.yml:
PMA_ABSOLUTE_URI: https://yourdomain.com/pma/
Provided you're running 4.6.5 or later of the docker phpmyadmin you should be set. To update you can docker pull to pull down the latest. i.e.
docker pull phpmyadmin/phpmyadmin
Just remove the ending backslash of /pma/:
location /pma {
proxy_pass http://localhost:8081/;
proxy_buffering off;
}
With it the browser treats it as a directory and request for assets accordingly, which is unexpected for PMA.
Don't need rewrite.
nginx.conf:
location ^~ /pma/ {
proxy_pass http://pma-container/;
absolute_redirect off;
}
docker-compose.yml:
PMA_ABSOLUTE_URI: https://yourdomain.com/pma/
Notice: keep trailing slash on location, proxy_pass, PMA_ABSOLUTE_URI
There's not a lot that can be done. Problem is that phpmyadmin is serving its pages from localhost, and even if nginx translates accesses from http://servm3/pma to http://localhost, all links in HTML content ignore the lattest and, even if they're relative, they don't take into account the /pma part. So, all those 404 errors you're seeing are from resources that, inside HTML, are referenced as relative links like styles.css, that when referenced/clicked become http://servm3/styles.css, that doesn't exist in the server.
Unfortunately reverse proxies work at the header level so, even if they are able to change headers like Location on the fly, they leave HTML content untouched, and hence the problems. There're workarounds involving changing HTML code on the fly, but they're not easy, are unreliable at most and they hinder performance considerably, so the only practical solution is that websites explicitly support some kind of base path setting. In this case, the solution would be that phpmyadmin Docker image allowed setting the base path using an environment variable in docker-compose.yaml, instead of defaulting to root.
Another workaround in the mean time would be not using a relative path, but a subdomain. If you're in control of DNS settings for servm3, you could use something like phpmyadmin.servm3, and proxy_pass without problems.
If you have a docker setup that will have many different domains but one database(like a multistore magento shop, or a multi domain wordpress) it might be undesireable to forward all the traffic to one single domain. Or even having to hardcode it in the ENV variable.
It's easier to portforward based on subdomain.
In your nginx config define a map, listing your port numbers
map $subdomain $port_number {
default "013";
phpmyadmin "014";
mailhog "017";
}
This will make it so that when the variable $subdomain matches any entry in the map below, the variable $port_number will be set to the corresponding value. In my example is default "013" if nothing is matched.
Then add the following directive to your server directive.
server_name server_name ~^(?:(?<subdomain>[^.]+)\.|)(?<base_domain>.+\.localhost)$;
These regexes set 2 variables $subdomain and base_domain
If the request is example.com.localhost
$subdomain will have example
$base_domain will have com.localhost
$port_number will have 013
If the request is example.com.localhost
$subdomain will have phpmyadmin
$base_domain will have example.com.localhost
$port_number will have 014
[Optional] If you need the actual domain in a variable you could use an if statement like this:
set $lookup_domain $host;
if ($port_number != "013") {
set $lookup_domain $base_domain;
}
and $lookup_domain will contain the actual domain you're interested in.
You can then use a proxy pass like this:
location / {
proxy_pass http://docker-host:${backend}${port_number};
proxy_pass_header Content-Type;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade; # allow websockets
proxy_pass_header Connection;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
}
Where the $backend variable contains in my case the base port range for my webapp set.
So the proxy url becomes someting like http://docker-host:20013 depending on the app. Feel free to skip that and set the ports to actual ports or whatever, or to modify it to follow any other logic.
don't know if you're still looking for an answer.
just follow this answer from Joshua Ostrom.
The problem is I dont know why it doesn't behave like it should but, you need to add index.php at the end like https://yourdomain.com/pma/index.php.
I had the same issue

Set up a Ghost blog at /blog on Meteor

I am not sure if this is possible but there is a way to host a Ghost blog at a subfolder instead of a subdomain https://www.allaboutghost.com/how-to-install-ghost-in-a-subdirectory/
I have set up everything on that end the way it says and now the only thing that is needed is to exclude /blog from the FlowRouter.notFound function. is there a way to do that or set up the route to listen to nginx?
// EDIT
Here's the nginx config
server {
listen 80;
server_name localhost;
location ^~ /blog {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://127.0.0.1:2368;
proxy_redirect off;
}
}
here's ghost config
config = {
// ### Production
// When running Ghost in the wild, use the production environment.
// Configure your URL and mail settings here
production: {
url: 'https://www.raiseyourflag.com/blog',
//everything else
}
}
There are two separate issues here.
Setting up Ghost to be served a subdirectory through Nginx. The tutorial you linked to covers exactly that.
Integrating the blog with a second site based on Meteor.
It's not clear if you've completed the first step or not, so let's make sure that's taken care of first:
# Make sure your config.js for Ghost includes /blog in the url key in the development section: 'http://127.0.0.1:2368/blog'
# Start Ghost in in the development enviroment: NODE_ENV=development node index.js
# Check that something is actually running on port 2368: sudo netstat -plnt | grep ':2368'
# Go here in your browser, you should see your Ghost blog and be able to browse it: http://127.0.0.1:2368/blog
If you have gotten that far, your Ghost blog is working and you are ready to access it through Nginx on port 80. To simplify the problem for this step, move any Meteor code out of the way temporarily so this can be verified.
Your Nginx configuration looks good. Just reload Nginx once more for
good measure, and then check this URL in your browser now:
http://127.0.0.1/blog
Now you should see your Ghost blog again, but now accessed through Nginx and proxied to the other port.
Once you've confirmed that step is working, add put the Meteor frontend code back in place. From the perspective of any frontend code, /blog is just like any URL handled by the web server.
If you go to /blog and see a NotFound page served by Meteor, that means that the client-side Meteor framework must have loaded from /somewhere/, presumably /index.html. In this case, there's a problem with the Nginx configuration. Perhaps there is more to it whant you have posted?

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