2

I'm transitioning from Apache to Nginx and I'm trying to figure out how to get my subdomain rewrite rules to work.

Apache

The Apache configuration I have basically moves all traffic to HTTPS and changes .net and .org domains to the main .com domain. Some of our users still think that every URL should start with "www" so the setup removes it if there is also another subdomain. URLs without any subdomain are redirected to https://www.example.com which isn't necessarily mandatory for the site to work.

# HTTP
<VirtualHost *:80>
    RewriteEngine on

    # Redirect http://example.tld -> https://www.example.com
    RewriteCond %{SERVER_PORT} !^443$
    RewriteCond %{HTTP_HOST} ^example\.(com|net|org)
    RewriteRule ^(.*)$ https://www.example.com$1

    # Redirect http://www.subdomain.example.tld -> https://subdomain.example.com
    RewriteCond %{SERVER_PORT} !^443$
    RewriteCond %{HTTP_HOST} ^www.([^\.]+)\.example\.(com|net|org)
    RewriteRule ^(.*)$ https://%1.example.com$1

    # Redirect http://subdomain.example.tld -> https://subdomain.example.com
    RewriteCond %{SERVER_PORT} !^443$
    RewriteCond %{HTTP_HOST} ^([^\.]+)\.example\.(com|net|org)
    RewriteRule ^(.*)$ https://%1.example.com$1 [NC,R,L]

    # ...

</VirtualHost>

# HTTPS
<VirtualHost *:443>
    RewriteEngine on

    # Redirect https://example.tld -> https://www.example.com
    RewriteCond %{HTTP_HOST} ^example\.(com|net|org)
    RewriteRule ^(.*)$ https://www.example.com$1

    # Redirect https://www.subdomain.example.tld -> https://subdomain.example.com
    RewriteCond %{HTTP_HOST} ^www.([^\.]+)\.example\.(com|net|org)
    RewriteRule ^(.*)$ https://%1.example.com$1

    # Redirect https://subdomain.example.(net|org) -> https://subdomain.example.com
    RewriteCond %{HTTP_HOST} ^([^\.]+)\.example\.(net|org)
    RewriteRule ^(.*)$ https://%1.example.com$1 [NC,R,L]

    # Otherwise serve https://subdomain.example.com

    # ...

</VirtualHost>

Nginx

The Nginx configuration I have so far works in most cases but I don't know how to remove "www" when the URL is in the form http(s)://www.subdomain.example.tld. According to https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/#server-name-if "if is evil" so I tried to keep them out of the most common use cases.

# Redirect http://subdomain.example.com -> https://subdomain.example.com
# Redirect http://example.com -> https://example.com
server {
    listen       80;
    server_name  .example.com;
    return       301 https://$host$request_uri;
}

# Redirect https://subdomain.example.(net|org) -> https://subdomain.example.com
server {
    listen       80;
    server_name  .example.net .example.org;
    if ($host ~* "^([^.]+(\.[^.]+)*)\.example\.(net|org)$") {
            set $subdomain $1;
            rewrite ^(.*)$ https://$subdomain.example.com$1 permanent;
            break;
    }
    return 301 https://www.example.com;
}

# Otherwise serve https://subdomain.example.com
server {
    listen       443 ssl;
    server_name  .example.com;

    # ...
}

So my question is how do I remove the "www" part when there is another subdomain already present the right Nginx way? In an optimal case the Nginx configuration should work the same way my old Apache config did. There are many questions and answers which cover simple cases where subdomains can be listed by hand in the configuration file. This is not an option for me.

Michael Hampton
  • 244,070
  • 43
  • 506
  • 972
Steve
  • 143
  • 1
  • 8
  • You should be using www, but that's a discussion for another day. Why don't you just add another `server` block for it? – Michael Hampton Mar 27 '14 at 15:37
  • Coming from Apache world I never realized that in Nginx configuration the `server_name` can be a regex too. – Steve Mar 28 '14 at 12:35

1 Answers1

1

After realizing that server_name can also be a regex this is what I have now. Another positive surprise was that the same server block can handle HTTP and HTTPS cases. I just had to comment out the ssl on; line from my ssl.inc config file. As far as I can tell this setup seems to work like my old Apache configuration.

# Redirect http://example.tld -> https://www.example.com
server {
    listen       80;
    server_name  www.example.com www.example.net www.example.org;
    return       301 https://www.example.com$request_uri;
}

# Redirect http(s)://example.tld -> https://www.example.com
server {
    listen       80;
    listen       443 ssl;
    server_name  example.com example.net example.org;
    return       301 https://www.example.com$request_uri;

    include conf.d/ssl.inc;
}

# Serve https://subdomain.example.com
server {
    listen       443 ssl;
    server_name  ~^[^\.]+\.example\.com$;

    include conf.d/ssl.inc;
    include conf.d/common.inc;
}

# Redirect http(s)://www.whatever.subdomain.example.tld -> https://subdomain.example.com
server {
    listen       80;
    listen       443 ssl;
    server_name  ~\.(?<subdomain>[^\.]+)\.example\.(com|net|org)$  ~^(?<subdomain>[^\.]+)\.example\.(net|org)$;
    return       301 https://$subdomain.example.com$request_uri;

    include conf.d/ssl.inc;
}
Andrew Schulman
  • 8,811
  • 21
  • 32
  • 47
Steve
  • 143
  • 1
  • 8