Use Nginx proxy pass (reverse proxy) to serve an Apache hosted site with SSL

I've searched the forums (and elsewhere on the web) and have found related but seemingly not identical information. Hopefully I'm not duplicating here.

I have a site running on an Apache server. It already has an SSL certificate (via LetsEncrypt) and runs without issue.

I've recently setup a machine 'in front' of it that is running Nginx. That machine serves three domains (with one certificate from LetsEncrypt).

I'd like to pass requests for the domain on the Apache machine through Nginx but am having trouble figuring out the proper settings. I've done this with two Apache serving machines in the past without much difficulty but I'm new to Nginx and clearly not sufficiently proficient with it yet.

The virtual server setup that I have on the Nginx net facing machine (through a router) is:

server {
    listen domain.pointing.to.apache.com:443 ssl;
    server_name  domain.pointing.to.apache.com;
    location / {
        root 192.168.11.14/var/www/html/;
        proxy_set_header X-Forwarded-Host $host:$server_port;
        proxy_set_header X-Forwarded-Server $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass domain.pointing.to.apache.com;
    }
}

But, of course, Nginx does not like this and will not reload after adding the vs. Any advice etc. will be most appreciated.

Note - I guess it's obvious but 192.168.11.14 is behind my router and not exposed directly to the net.

Jason

Edit/Update:

Important info missing from my original inquiry:

  1. The net facing Nginx machine that I want to reverse proxy to Apache is also serving three subdomains of my main domain that I want to reverse proxy (sub1.mydomain.com, sub2.mydomain.com, sub3.mydomain.com). All three share one SSL certificate from LetsEncrypt.

  2. The Apache server on the local network had a LetsEncrypt issued certificate as well that was serving mydomain.com until I put the Nginx machine in front of it.

  3. I have now deleted the SSL certs on the Apache machine, deleted the https virtual server and have a simple virtual server set up for port 80.

  4. My default Nginx setting sends requests to http //www.mydomain.com which simply shares a very boring html page for now.

  5. I've installed SSL certs for the domain https //www.mydomain.com on the Nginx box and want to use the recommendation provided by Tero to reverse proxy https requests on mydomain.com to and from the local Apache box. As follows:

server {

    listen 443 ssl;
    ssl_certificate /etc/letsencrypt/live/www.mydomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/www.mydomain.com/privkey.pem;
    
    server_name www.mydomain.com;
    location / {
        proxy_set_header X-Forwarded-Host $host:$server_port;
        proxy_set_header X-Forwarded-Server $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass https://192.168.11.14;
    }
}

The problem is I'm getting a 502 Bad Gateway error from the Nginx machine...so I guess I have something wrong with the Nginx settings...I'm getting close but not quite there. Additionally, I noticed that attempts to access www.mydomain.com without https no longer serves the boring html page...they get transferred/rewritten to https -> www.mydomain.com and to the same 502 bad gateway.


There are four errors in your configuration:

  1. listen directive accepts only IP addresses, if you want to bind to a specific interface. However, in practice you are fine binding to all interfaces, so listen 443 ssl is enough.

  2. root location specifies the file system path to files that nginx is supposed to serve directly. Since your / location is to be reverse proxied, specifying root is not needed at all, since no files are served by nginx. So, remove root directive.

  3. proxy_pass requires a URL to the upstream server. In this case, it should be proxy_pass https://192.168.11.4.

  4. You haven't specified TLS certificate / private key, they need to be specified with ssl_certificate and ssl_certificate_key directives.

So, overall, your configuration should be:

server {
    listen 443 ssl;
    ssl_certificate /path/to/certificate;
    ssl_certificate_key /path/to/key;
    
    server_name  domain.pointing.to.apache.com;
    location / {
        proxy_set_header X-Forwarded-Host $host:$server_port;
        proxy_set_header X-Forwarded-Server $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass https://192.168.11.4;
    }
}

If you want to use Letsencrypt certificates on the reverse proxy server, you need to serve /.well-known directory from the server:

server {
    listen 80;

    location /.well-known {
        try_files $uri =404;
    }

    location / {
        # Redirect http requests to https
        return 301 https://domain.pointing.to.apache.com;
    }
}

With this configuration, you can run Certbot on the reverse proxy server, which will then validate the domain ownership properly and get the certificate / key.

However, with this configuration, you cannot run Certbot on the server running on local network. If the local network is considered secure, then I suggest using http instead of https between reverse proxy server and local network server.

If https is needed between reverse proxy server and local network server, then you can use this configuration:

server {
    listen 80;

    # Try to serve `.well-known` files from local file system. If not found, send to upstream server
    location /.well-known {
        try_files $uri @local;
    }

    location @local {
        proxy_pass http://192.168.11.4;
    }

    location / {
        return 301 https://domain.pointing.to.apache.com;
    }
}