我的需求:
http://iyaozhen.com -> https://iyaozhen.com
http://www.iyaozhen.com -> https://iyaozhen.com
这两个已经实现:
server { listen 80; listen [::]:80; server_name iyaozhen.com www.iyaozhen.com; return 301 https://iyaozhen.com$request_uri; }
我还需要 https://www.iyaozhen.com -> https://iyaozhen.com
按理我是需要这样配置:
server { listen 443 ssl; listen [::]:443 ssl; server_name www.iyaozhen.com; return 301 https://iyaozhen.com$request_uri; }
但我发现这样配置的话所以网站都不能访问了,而且我不配置的话同样能跳转过去(不知道为什么)。
这都是小问题,更大的问题是 https://demo.iyaozhen.com/ (或者其它有设置 DNS 解析,但没在 Nginx 里面设置 server 的域名)能访问到 iyaozhen.com 的内容(https 那里有红x)。
# prevent processing requests with undefined server names server { listen 80 default_server; listen [::]:80 default_server; server_name _; return 444; }
主域 iyaozhen.com 的配置:
server { listen 443 ssl spdy; listen [::]:443 ssl spdy; # SSL configuration # don’t use SSLv3 ref: POODLE ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # 省略其它的设置…… ssl_prefer_server_ciphers on; ssl_session_timeout 1d; ssl_session_cache shared:SSL:10m; # HSTS (ngx_http_headers_module is required) (15768000 secOnds= 6 months) add_header Strict-Transport-Security max-age=15768000; server_name iyaozhen.com; }
我发现问题的根源是简单的 listen 443 然后做跳转是不行的,必须要配置证书啥的。这怎么办?
![]() | 1 mN71eOOprFyMsnPx 2015-07-09 11:24:45 +08:00 ![]() 一个IP地址正常情况是只支持一个 https vhost,所以你访问 demo 访问到了 iyaozhen.com。这个 demo 有红叉是因为访问的域名和ssl证书认证的域名不一致。访问是demo.iyaozhen.com,证书是 www.iyaozhen.com 以及 iyaozhen.com。 如果要一个IP支持多个 https vhost,请开启 nginx 的 SNI 支持。但是,不建议这样做。因为可能访问https 都会出现红叉。 |
![]() | 2 iyaozhen OP @FifiLyu 嗯,这个我知道。我是单域名证书。我不是要 https://demo.iyaozhen.com/ 能访问到我的主域博客。而是 https://demo.iyaozhen.com/ 不能访问,http://demo.iyaozhen.com/ 能正常访问其本来的站点。 |
![]() | 3 ryd994 2015-07-09 11:53:37 +08:00 via Android ![]() 要http正常的话只要正确填写server_name即可 https的怎么都不会正常 |
![]() | 4 geekzu 2015-07-09 11:58:26 +08:00 via Android ![]() 只要你想让443 能通过https访问,必须要配置证书 |
![]() | 5 geekzu 2015-07-09 11:58:41 +08:00 via Android 即使是只做跳转 |
![]() | 6 iyaozhen OP @geekzu 看来是这样。跳转这个是个小问题。但 https://demo.iyaozhen.com/ (或者其它有设置 DNS 解析,但没在 Nginx 里面设置 server 的域名)能访问到 iyaozhen.com 的内容(https 那里有红x)。这个怎么解决。 |
![]() | 7 geekzu 2015-07-09 13:11:10 +08:00 via Android ![]() @iyaozhen 这个因为是共享ip没法解决,除非你给 demo.iyaozhen.com 也配置上ssl |
8 chon 2015-07-09 13:15:47 +08:00 ![]() @iyaozhen https连接建立是在判断server_name之前的,所以所有的https连接都会指向 iyaozhen.com 。 可以加一行判断host的: if ($host !~* ^iyaozhen.com$ ) { return 404; } 不知道有没有更好的方案。 |
![]() | 9 iyaozhen OP @geekzu 明白了,我没有许可的证书(泛域名证书)再设置 443 端口的 default_server。单域名证书,有点略坑呀。 |
![]() | 11 imlonghao 2015-07-09 13:44:11 +08:00 via Android 没人用 HSTS 做 http 跳转 https 的么? |
![]() | 12 iyaozhen OP @imlonghao 有啊,配置里面不是写了嘛。不过 IE9 等不支持 HSTS,还是要再加个 server 做跳转。 |
![]() | 13 alect 2015-07-09 14:35:54 +08:00 ![]() lz自己把自己坑了,申请证书的时候加上不要用裸域名而是带www的,否则有些直接给你签发的证书就只有裸域名了 |
![]() | 14 dallaslu 2015-07-09 14:47:36 +08:00 ![]() 配一个 80 端口的 server: server_name iyaozhen.com www.iyaozhen.com; if ($host ~ ^(www\.)?iyaozhen\.com) { rewrite ^(.*) https://iyaozhen.com$1 permanent; } 只配一个 443 端口的 server: server_name iyaozhen.com www.iyaozhen.com; if ($host ~ ^www\.iyaozhen\.com) { rewrite ^(.*) https://iyaozhen.com$1 permanent; } if ($host !~ ^(www\.)?iyaozhen\.com) { rewrite ^(.*) http://$host$1 permanent; } (未经测试) |
16 pupboss 2015-07-09 14:52:17 +08:00 server { listen 80; server_name pupboss.com; return 301 https://$server_name$request_uri; } server { listen 80; listen 443 ssl; server_name www.pupboss.com; rewrite ^/(.*)$ https://pupboss.com/$1 permanent; } |
![]() | 17 iyaozhen OP @dallaslu 谢谢,你这种方式应该也可以。目前我是这样解决的: server { listen 80; listen [::]:80; listen 443 ssl; listen [::]:443 ssl; server_name www.iyaozhen.com; return 301 https://iyaozhen.com$request_uri; } 按理说 www.iyaozhen.com 是没有配置证书的,只监听 443 端口,不过实际测试发现 https://www.iyaozhen.com 能跳转到 https://iyaozhen.com。 顺带请教个问题 !~ 是 !=,~ 是 = 吗?这是什么语法? |
![]() | 18 iyaozhen OP @pupboss 好方法,我就是像你这样配置的。 是的,HSTS 在只访问 http 时是没用的。 HSTS 的作用应该是访问了一次 https 的网站后,浏览器检测到了这个协议,当你以后输入域名时(即使手动输入 http://)会跳转到对应的 https 网站。 |
![]() | 19 iyaozhen OP @alect 应该也是给我签了带 www 的。https://www.ssllabs.com/ssltest/index.html 检测结果: Common names iyaozhen.com Alternative names iyaozhen.com www.iyaozhen.com Prefix handling Both (with and without WWW) |
![]() | 20 mN71eOOprFyMsnPx 2015-07-09 15:22:57 +08:00 ![]() @iyaozhen 因为你只有一个 ssl 站点,任何域名解析到你的IP地址。都能通过https://test.abc.com 访问到 https://iyaozhen.com 的内容。这个你是关不掉的。 变通的做法是,开启 SNI 支持。然后,新建一个 nginx 的 ssl 站点,root指向一个目录,目录下没有任何东西。不过,这样肯定不好。 如果是用的 Linux ,使用 iptables 做一个域名白名单防火墙,443端口只允许 iyaozhen 域名访问。 白名单设置参考: https://github.com/fifilyu/module-http-whitelist 中的 “代替方案” |
![]() | 21 iyaozhen OP @FifiLyu 嗯,谢谢。目前采用的是更粗暴的方法。 把 iyaozhen.com 的 server 设置为 default_server 然后在里面做判断: if ($host != iyaozhen.com) { return 444; } |
![]() | 22 mN71eOOprFyMsnPx 2015-07-09 15:30:20 +08:00 @iyaozhen 233 确实粗暴。 |
![]() | 23 iyaozhen OP @pupboss 有个小小的疑问。像你那样配置,按理说 www.iyaozhen.com 是没有配置证书的,只监听 443 端口,不过实际测试发现 https://www.iyaozhen.com 能跳转到 https://iyaozhen.com。 这是为什么? |
![]() | 24 alect 2015-07-09 16:52:47 +08:00 ![]() 倒是对lz已经成功实现的一个功能提一个建议 lz想把http请求都转换为https请求,个人不建议用301,而是用hsts实现 然后就只要考虑把www请求转发到裸域就行了 |
25 pupboss 2015-07-09 18:24:35 +08:00 ![]() @iyaozhen 我觉得这个类似脚本语言,一行一行运行,上面没错误就不报错,如果上面写了证书信息,而且是错误的,我觉得会报错,直接给 rewrite 掉,差不多就相当于程序里面的 return 了,下面再错误都没关系 |
![]() | 26 iyaozhen OP |
![]() | 27 iyaozhen OP @pupboss 嗯,好像是的。而且我域名证书带 www 和不带的都可以。或者说是 Nginx 自己智能做了处理。比如说我访问 https://xxx.iyaozhen.com 用的是主域的证书,显示连接(算法)没问题,但域名没有公审记录。 |
28 pupboss 2015-07-09 19:08:09 +08:00 |
![]() | 31 dallaslu 2015-07-09 21:36:19 +08:00 ![]() @iyaozhen ~ 是正则匹配的意思,!~ 就是不匹配后面的正则。上面有位V友的回复提到 !~*,其中*的意思是不区分大小写。 |
![]() | 32 dallaslu 2015-07-09 21:41:57 +08:00 @iyaozhen 如果 http 协议通过 301 跳转到 https,那么浏览器会记住这个选择,以后再访问 http://iyaozhen.com 时,就会直接访问 https://iyaozhen.com 而不再经过服务器跳转,这里并没有任何问题。 问题在于,如果初次通过 https 访问,但是没有设置HSTS;然后再访问 http 链接,浏览器就会正常执行一次 http 请求,顺带把之前从 https 中获取的 cookie 发出去了,这时就可能会被嗅探到。 所以 HSTS 要比单纯的 301 要好。 以上是个人理解。 |
![]() | 33 dallaslu 2015-07-09 21:47:16 +08:00 |
![]() | 34 iyaozhen OP @dallaslu 原来 Nginx 正则语法是这样的。谢谢 “顺带把之前从 https 中获取的 cookie 发出去了,这时就可能会被嗅探到。”这个倒是没有考虑到。不过我 301 和 HSTS 都配置了。 |
![]() | 35 caola 2015-07-09 23:21:47 +08:00 ![]() 为什么要把 80 的 443 端口的分开写两次呢? 下面是我自己的主要配置,并开启了SPDY(www的跳转到根域名) ================================ server { listen 80; listen 443 ssl spdy; server_name cao.la www.cao.la; index index.php index.html; root /home/wwwroot/caola; ssl_certificate cert/cao.la.crt; ssl_certificate_key cert/cao.la.pem; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #允许的协议 ssl_ciphers AES128:AES256:GCM:!DH:!RC4:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS; #加密算法 ssl_session_timeout 10m; #客户端会话缓存时间 ssl_session_cache builtin:1000 shared:SSL:10m; #SSL会话缓存类型和大小 ssl_prefer_server_ciphers on; #优化SSL,服务器密码优先于客户端 ssl_buffer_size 1400; # 1400 bytes to fit in one MTU spdy_headers_comp 6; #SPDY报头压缩级别[0-9] add_header X-Frame-Options SAMEORIGIN; #拒绝被嵌入框架(iframe…) add_header Strict-Transport-Security "max-age=8640000; includeSubDomains"; #子域没有全部部署https请去掉includeSubDomains add_header X-Content-Type-Options: nosniff; #禁用浏览器的类型猜测 if ($ssl_protocol = "") { return 301 https://$server_name$request_uri; } if ($host != 'cao.la' ) { return 301 https://cao.la$request_uri; } } |