Nginx – Two Webservers on One LAN with One WAN IP Address: Connecting to Correct Server by Subdomain Name

Apache2nginx

I have two physical servers running on the same LAN. Both are running webservers; one runs apache2, the other nginx. They each have a different domain name, but the same external WAN IP address. Let's say the network layout looks like this:

                WAN
            10.20.30.40
      |----------|----------|
      |                     |
   Domain 1              Domain 2
exampleABC.com     (sub.)exampleXYZ.com
      |                     |
      |----------|----------|
                 |
            Single LAN
                 |
      |----------|----------|
      |                     |
  IP addr 1             IP addr 2
192.168.0.10           192.168.0.20
      |                     |
      |                     |
  Server 1              Server 2
   apache2                nginx

The apache2 server belongs to me, while the nginx server does not. Both servers have dedicated subdomains for each service they provide – for example, (www.)exampleABC.com for the main webpage, cloud.exampleXYZ.com for a reverse-proxied cloud service, media.exampleXYZ.com for media, etc.

For reasons unknown, the nginx server is what takes priority when connecting to the WAN IP address – initially, both domains would lead to the main webpage hosted by nginx, but with the following (current) nginx configuration, exampleABC.com will correctly lead to the apache2 server, while exampleXYZ.com continues to lead to the nginx server.

server {
    listen 80;

    # listen on all subdomains
    server_name exampleABC.com *.exampleABC.com;
    
    location / {
        # transparently proxy to other server (port 443)
        proxy_pass http://192.168.0.10:80;

        # set "Host" header passed to other server to client-requested FQDN so other server knows which subdomain is being requested
        proxy_set_header Host $http_host;
    }
}

server {
    listen 443 ssl;

    server_name exampleABC.com *.exampleABC.com;
    
    location / {
        proxy_pass https://192.168.0.10:443;
        proxy_set_header Host $http_host;
    }
}

However, the subdomains hosted by the apache2 server (docs.exampleABC.com, etc.) continue to connect to nginx. (The nginx subdomains work fine.)

Here's one of the subdomain configurations I have set up via apache2:

<VirtualHost *:80>
    ServerName ft.exampleABC.com
    Redirect permanent / https://ft.exampleABC.com/
    RewriteEngine on
    RewriteCond %{SERVER_NAME} =ft.exampleABC.com
    RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>

<IfModule mod_ssl.c>
    <VirtualHost _default_:443>
        # The ServerName directive sets the request scheme, hostname and port that
        # the server uses to identify itself. This is used when creating
        # redirection URLs. In the context of virtual hosts, the ServerName
        # specifies what hostname must appear in the request's Host: header to
        # match this virtual host. For the default virtual host (this file) this
        # value is not decisive as it is used as a last resort host regardless.
        # However, you must set it for any further virtual host explicitly.

        ServerName ft.exampleABC.com
        #ServerAlias *.exampleABC.com

        ServerAdmin webmaster@localhost
        DocumentRoot /mnt/external/webserver/ft

        # Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
        # error, crit, alert, emerg.
        # It is also possible to configure the loglevel for particular
        # modules, e.g.
        #LogLevel info ssl:warn

        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined

        # For most configuration files from conf-available/, which are
        # enabled or disabled at a global level, it is possible to
        # include a line for only one particular virtual host. For example the
        # following line enables the CGI configuration for this host only
        # after it has been globally disabled with "a2disconf".
        #Include conf-available/serve-cgi-bin.conf
        
        <Directory /mnt/external/webserver/ft>
            Options Indexes FollowSymLinks
            AllowOverride None
            Require all granted
        </Directory>

        #   SSL Engine Switch:
        #   Enable/Disable SSL for this virtual host.
        SSLEngine on

        < snipped: lines added by certbot >

    </VirtualHost>
</IfModule>

# vim: syntax=apache ts=4 sw=4 sts=4 sr noet

I'd like to make it such that, when connecting to exampleABC.com, ft.exampleABC.com, etc., the client is correctly connected to the apache2 server. exampleXYZ.com and its subdomains should still connect to the nginx server, of course.

Other information:

Originally, the client (e.g. web browser) could not verify the authenticity of exampleABC.com's TLS certificate. (Note that I had TLS certificates set up correctly under apache2.) This was resolved by adding my apache2 domains to the certificates of the nginx server.
Though, I don't believe this should have been necessary – my certificates (under apache2) should be passed through the reverse proxy, no?

If I attempt to connect to the apache2 server via curl while manually specifying the Host header (via curl -vL -H "Host: ft.exampleABC.com" https://192.168.0.10), I'll be redirected to the main webpage of the nginx server. I'm not sure what this means.

EDIT:

This is the output of nginx -T, according to the system administrator of the nginx system:

– snip –

Also, the nginx server is running in a container via LinuxServer.io's "SWAG".

EDIT:

LinuxServer.io's SWAG loads a different nginx configuration than the default. The following command gets the correct confs:

docker exec -it swag /usr/sbin/nginx -c /config/nginx/nginx.conf -T

The result of said command can be found at this paste. (too many characters for StackExchange)

Best Answer

I am the owner of the house in which their server is located. I am no expert by any means; I just follow guides pretty well. I have a DuckDNS domain name and I run Docker containers for Plex, Sonarr, SABnzbd, etc. I also run a SWAG container for my reverse proxy.

Unilock has brought their own server in. It has its own domain name and uses apache2 for all its server configs. This server, prior to being on my network, was listening on all the same ports as mine (80, 443, etc.).

I was told that, if Unilock could run their services on non-standard ports, we may be able to change the settings of my pfSense router to run both servers. I was also told that I could add the domain names of their server to the EXTRA_DOMAINS variable of my SWAG container. I did that and it did not help.

I've also added an extra server block in my SITE_CONF default file. The extra block looks like this:

#second server block
server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name <his domain name>; #change this to your subdomain
    #include /config/nginx/ssl.conf;
    client_max_body_size 0;
    location / {
    #include /config/nginx/proxy.conf;
    resolver 127.0.0.11 valid=30s;
    #set $upstream_app 192.168.0.10;
    #set $upstream_port 443;
    #set $upstream_proto https;
    #proxy_pass $upstream_proto://$upstream_app:$upstream_port;
    proxy_pass https://192.168.0.10:443; 
    proxy_max_temp_file_size 2048m;
   }

My main server block is the default file. If I need to post the entire configuration, I will; though it appears unilock has already done so on Pastebin. After I entered the above, I could access unilock's main page, but their subdomains still redirect to my default nginx server start page.