Nginx Proxying to Multiple IP Addresses for CMS’ Website Preview

nginxPROXY

First-time poster, so bear with me.

I'm relatively new to Nginx, but have managed to figure out what I've needed… until now.

Nginx v1.0.15 is proxying to PHP-FPM v.5.3.10, which is listening at http://127.0.0.1:9000. [Knock on wood] everything has been running smoothly in terms of hosting our CMS and many websites.

Now, we've developed our CMS and configured Nginx such that each supported website has a preview URL (e.g. http://[WebsiteID].ourcms.com/) where the site can be, you guessed it, previewed in those situations where DNS doesn't yet resolve to our server, etc.

Specifically, we use Nginx's Map module (http://wiki.nginx.org/HttpMapModule) and a regular expression in the server_name of the CMS' server{ } block to 1) lookup a website's primary domain name from its preview URL and then 2) forward the request to the "matched" primary domain.

The corresponding Nginx configuration:

map $host $h {
    123.ourcms.com  www.example1.com;
    456.ourcms.com  www.example2.com;
    789.ourcms.com  www.example3.com;
}

and

server {
    listen              [OurCMSIPAddress]:80;
    listen              [OurCMSIPAddress]:443 ssl;
    root                /var/www/ourcms.com;
    server_name         ~^(.*)\.ourcms\.com$;
    ssl_certificate     /etc/nginx/conf.d/ourcms.com.chained.crt;
    ssl_certificate_key /etc/nginx/conf.d/ourcms.com.key;

    location / {
        proxy_pass http://127.0.0.1/;
        proxy_set_header Host $h;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

(Note: I do realize that the regex in the server_name should be "tighter" for security reasons and match only the format of the website ID (i.e. a UUID in our case).)

This configuration works for 99% of our sites… except those that have a dedicated IP address for an installed SSL certificate. A "502 Bad Gateway" is returned for these and I'm unsure as to why.

This is how I think the current configuration works for any requests that match the regex (e.g. http://123.ourcms.com/):

  1. Nginx looks up the website's primary domain from the mapping, and
  2. as a result of the proxy_pass http://127.0.0.1 directive, passes the request back to Nginx itself, which
  3. since the proxied request has a hostname corresponding to the website's primary domain name, via the proxy_set_header Host $h directive, Nginx handles the request as if it was as direct request for that hostname.

Please correct me if I'm wrong in this understanding.

Should I be proxying to those website's dedicated IP addresses? I tried this, but it didn't seem to work? Is there a setting in the Proxy module that I'm missing?

Thanks for the help.

MB

Best Answer

except those that have a dedicated IP address for an installed SSL certificate.

It looks to me like you are listening on only one IP address. You will also need 'listen' directives for the additional IPs for the SSL domains. Unless you have an wildcard SSL certificate, I would think that you would need one server{} definition for each of these hosts.

Here's a related pattern that I use that might be helpful if you are trying to avoid the need to maintain your the configs for your SSL Nginx domains completely by hand:

Part of my Nginx configuration is stored under source control as a template. The "init" script for Nginx has been modified so that every time Nginx is reloaded or restarted, a Perl script is scalled that fills in the template variables depending on the environment (alpha, beta, production, etc). A new plain text file is written out and Nginx includes the "rendered" template as an include file.

This allows for new possibilities for automation and DRY. Perhaps it would help in your situation.

Related Topic