以我的网站为例,用户访问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;
    ...
}