Redirect root domain to subdomain

Fel asked:

I am trying to redirect:

pt.example.com and example.com

to

https://pt.example.com
  • pt.example.com will redirect to https://pt.example.com. That’s ok.
  • example.com will redirect to https://example.com (not https://pt.example.com as expected)

 server {
            listen 80 default_server;
            listen [::]:80 default_server;
            server_name pt.example.com;
            return 301 https://pt.example.com$request_uri;
    }

How can I correct that?

My answer:


So that HSTS works properly, you need to redirect from http to https on the same hostname, and then redirect on https from the first hostname to the second hostname.

This also means that both hostnames must have a TLS certificate. Ideally they should be alternate names on the same certificate, to simplify maintenance.

Here is a live working example pulled from one of my production sites:

server {
        server_name www.yes-www.org yes-www.org;

        include includes/listen-80;
        include includes/cloudflare;
        include includes/letsencrypt;

        access_log off;

        return 301 https://$host$request_uri;
}

Above, we simply redirect from http to https on the same hostname, whatever it was.

server {
        server_name yes-www.org;

        ssl_certificate /etc/letsencrypt/live/www.yes-www.org/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/www.yes-www.org/privkey.pem;

        include includes/listen-443;
        include includes/cloudflare;
        include includes/ssl;
        include includes/ssl_stapling;
        include includes/hsts;
        include includes/csp_wordpress;
        include includes/letsencrypt;

        return 301 https://www.yes-www.org$request_uri;
}

Here we redirect from one hostname to the other on https. The destination hostname is in the return directive.

If you have additional hostnames to redirect from one hostname to the destination hostname, they can all be served from the same server block as long as they all share the same TLS certificate. Otherwise, duplicate the server block.

server {
        server_name www.yes-www.org;

        root /srv/www/yes-www.org;

        access_log /var/log/nginx/yes-www.org-access.log nginx;
        access_log /var/log/nginx/cache.log cache;
        error_log /var/log/nginx/yes-www.org-error.log;

        ssl_certificate /etc/letsencrypt/live/www.yes-www.org/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/www.yes-www.org/privkey.pem;

        include includes/listen-443;
        include includes/cloudflare;
        include includes/letsencrypt;
        include includes/ssl;
        include includes/ssl_stapling;
        include includes/hsts;
        include includes/csp_wordpress;
        include includes/favicon;
        include includes/wordpress;
        include includes/php;
        include /srv/www/yes-www.org/nginx.conf;

        location ~ /\.(ht|git) {
                deny all;
        }
}

And of course, this just serves the web site.


View the full question and any other answers on Server Fault.

Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.