以我的网站为例,用户访问 nomox.cn 跳转到 www.nomox.cn,利用 Nginx 的 301 跳转即可实现。但是许多教程都没有覆盖所有情况,在这里记录下最终解决方法。

三个跳转

  1. 访问 http://nomox.cn 跳转到 http://www.nomox.cn
  2. 访问 http://www.nomox.cn 跳转到 http://www.nomox.cn
  3. 访问 https://nomox.cn 跳转到 http://www.nomox.cn

很多文章只覆盖了前两种跳转,我想是由于 SSL 造成了额外的问题。Https 即经过 SSL 加密的 Http,在发送 Http 之前客户端需要与服务器建立 SSL 连接,但是 Nginx 的 server_name 即 Http header 中的 host 参数,是通过 Http 传播的。也就是说在 SSL 连接建立之前服务器并不能获得要访问的 host,不能获得 host 就无法确定到底使用哪个证书,因此只有一个 Nginx server 配置能够监听 443 端口。

早期如果要将 https://nomox.cn 跳转到 http://www.nomox.cn 比较麻烦,解决方法有两个。一是使用多域名证书,同时包含 nomox.cn 和 www.nomox.cn。二是 Nginx 监听不同的 IP,比如 https://nomox.cn 监听 192.168.1.1 的 443 端口,而 http://www.nomox.cn 监听 192.168.1.2 的 443 端口。

解决方法

使用 TLS SNI 特性,这允许浏览器在 SSL 建立连接阶段就发送 host。这个特性是 TLS1.2 带来的,目前几乎所有的浏览器和服务端都支持这个特性,使用 Nginx 的话通过 nginx -V 命令看到 “TLS SNI support enabled” 就表明支持且已启用。这样就可以用多个 Nginx server 配置同时监听 443 端口了。

我的配置如下:

server{
    listen 80;
    server_name www.nomox.cn nomox.cn;
    return 301 https://www.nomox.cn$request_uri;
}

server{
    listen 443 ssl;
    server_name nomox.cn;
    return 301 https://www.nomox.cn$request_uri;

    ssl_certificate /ssl/fullchain.cer;
    ssl_certificate_key /ssl/nomox.cn.key;
}

server{
    listen 443 ssl;
    server_name www.nomox.cn;

    ssl_certificate /ssl/fullchain.cer;
    ssl_certificate_key /ssl/nomox.cn.key;
    ...
}