Score:0

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

us flag

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.

Score:2
us flag

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;
    }
}
us flag
Tero, thank you very much for the help. Unfortunately, I must still be doing something incorrectly. I edited the sites-available settings, enabled and tried to reload Nginx but get the following error: 'invalid number of arguments in "ssl_certificate" directive'. The SSL certificate is on the remote server (192.168.11.4 in this example) which shouldn't be a problem...or no?
us flag
You need to have a certificate on the server where nginx is installed, and enter the path to the certificate / key files in the corresponding directives.
us flag
Tero, thanks again. I was afraid that was probably the case. So, my problem is I'm not sure that I understand how to install certificates on my net facing machine for a domain that is to be served from behind that net facing machine. When I run certbot it checks to make sure I (my machine and IP) respond to the IP (domain) I'm attempting to obtain the cert for but my net facing machine will not respond (I don't think) because it doesn't have a virtual server setup to listen for that domain.
us flag
Additionally, I may have an overly complicated setup here in that my main domain is the one to be served by the machine on my local network through a different machine (running Nginx) that serves three subdomains from that domain. (e.g. one.mydomain.com, two.mydomain.com, and three.mydomain.com are on the net facing machine and my domain.com is on the machine behind the net facing machine). Why it's set up this way is a long story...is what I'm shooting for here even possible?
us flag
I added more information how you could handle certificates on the net facing reverse proxy server.
us flag
Tero, thanks again for your help and patience. I feel like I'm almost there. I removed ssl certs from the local network server, switched to serving the site on http (80), used the updated information you provided plus I needed to add server_name for certbot to identity the domain I wanted a cert for. All worked well but now I'm getting a 502 bad gateway error when I try to access the domain. I'll update my inquiry for easier/clearer formatting to show what I have now.
us flag
Please note that when upstream server is over `http`, you need to use `proxy_pass http://192.168.11.4;`. You have `https://192.168.11.4` in your configuration.
us flag
Tero - thanks yet again. Yes, that was a problem. Removing the 's' gets me past the 502 error and now I'm getting a "too many redirects" error...which I think is from Apache on the local machine...I'll need to poke around now and see what I'm doing wrong on that side.
us flag
Tero - Thanks so much for all of your support and patience. The 502 error was caused by some remaining https related settings in my virtual server file on the Apache machine. I completely overlooked them at the bottom of the file. Removed everything and it works perfectly. :-) Needed to make some minor adjustments on my app running behind the reverse proxy (proxy_client_headers) but once those were made it all works like a charm. Thanks again for your help. :-)
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.