决定还是攻克SSL难题

请注意,本文编写于 1633 天前,最后修改于 1631 天前,其中某些信息可能已经过气。

最后成果
最后成果

主要原因还是省钱。不想租VPS,而且文件什么的放在别的地方,总有种不爽的感觉。
目前的问题在于,我只有一个公网IP,访问服务器下的不同服务,只能靠端口号进行区分。当时一度觉得只能租个VPS解决问题,但,我突然想到。机房也没那么多钱养这么多IP啊,一个IP下明明挂了那么多网页,为啥他们不用端口号就可以直接访问呢。
查了一下,果然。Apache和Nginx都有设置这种类似端口转发的功能。大概就是能知道访问的客户端用的是哪个域名,然后在后台给出对应的端口。客户端看起来,就像是一个IP多个域名一样。
顺便的,这个东西的设置和SSL在一起,如果能一起搞好岂不美滋滋。电信目前只封了80,443还留着,苟延残喘试一下!
本文会根据实际进度更新
目前有小突破,一点不夸张地说。零基础面对PHP,Nginx之类的东西一点点成功都足够我拍手庆祝的了。
为了测试,我增加了一个https://lab.fkun.tech 这样的二级域名。看到没有,我已经把s加上去了。当然不知道里面有什么文件的人访问是不会有什么结果的,毕竟只是测试用的页面。
首先对nginx的配置文件下手。
在config文件下,看到最后一句。

 include /opt/etc/nginx/vhost/*.conf;

很明显,这说明前面的配置并不完全,还有这个文件夹里所有conf结尾的文件。
打开一看,不错,有Typecho,default这样的文件,分别控制着不同的页面。
这次要先处理默认页面,也就是这个default。
点开看看

server {
listen 768 ssl http2;
server_name localhost;
ssl_certificate /xxxxxx.pem;
ssl_certificate_key /xxxxx.key;
ssl_session_cache    shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
root /opt/wwwroot/default/;
index index.html index.htm index.php tz.php;
include /opt/etc/nginx/conf/php-fpm.conf;
#otherconf
}

这已经是我改完的文件了,listen顾名思义,就是监听的端口。只要发现有从这个端口进来的请求,就会进行配置。
servername这个项目在我这里似乎有些鸡肋,改成网址,或者localhost都行。
接下来就是ssl证书。
这里搞了我很久,最后找到答案以后真的就是 噗.jpg 我申请的证书是sslforfree这个网站上的。以前也用过很多其他的,包括阿里云官方的。不过后来发现这个sslforfree验证的很快,免费,而且没什么限制。
下载下来两个crt和一个key。我本来也就没几个网站,接触ssl比较少。以前搞ssl就胡乱一传就完事儿了,现在纯手动操作果然上来就出了问题。
开始我一直在怀疑时nginx配置文件有问题,因为改动丝毫没有影响。
甚至我换了端口,他都不会有变化。
之后,我总算是学乖了去终端查nginx的信息

nginx -t

用这个就可以test现在的状态。
balabala一长串,主要错误时key mismatch。就是说我的key和certificate不匹配。这算哪门子事儿啊,用openssl指令查模量校对。一样啊,亏我还一个一个字符对比了一遍。
打开网易云,闭上眼睛,沉思了一普朗克时间,打开浏览器开始查资料。
看到有个人说自己是证书的顺序放错了,我就很奇怪,这还有个顺序不成?盯着三个文件发呆,灵光一现,把ca_bundle和certificate两个文件的内容和在了一起。再用nginx测试了一下,我靠,竟然过了。

多次测试
多次测试

后来知道,有些网站给的SSL是分开来的,有些程序自动会合并两个文件,而手动合并,竟然也可以。不过大家操作的时候要注意编码不要改动,再就是多一个空格都会识别失败。顺序的问题试一试就知道了。

然后很残念的就是nginx本身并不支持php的解析,也就是你整的php文件在访问的时候都TM会以文件的形式下载下来。我电脑上已经有快100个重复的文件了。
所以

include /opt/etc/nginx/conf/php-fpm.conf;

这个很重要,他引入了php的解析器,在另一些服务器上,可能会用到127.0.0.1:9000转发去做解析。这边反正用这个就行了,不多讨论。
刚说完不多讨论,我在如法炮制Typecho的配置文件时就撞墙了。撞得很懵逼。
真不知道Typecho是娇贵在哪儿了,要么就直接502要么就给我下载index.php,硬是跑不起来。Typecho本身的问题已经排除,我放个空的index都打不开,一顿胡乱操作,直接整烂了。远程连接那边的电脑,用局域网都上不去博客。只好用最后的重置大法,路由器上改一下服务端口,所有对应的配置文件就会重写。总算是恢复了。
天色不早,23:33。这周五放假,明后又都只有一节课,真是美好的一周啊!
明天继续肝。
非常舒服的睡了一觉之后,只用了五分钟,就解决了博客全站的SSL问题,光速打昨天的脸。
猜想昨天一直搞不好的原因是纠结在了nginx和php,没考虑Typecho本身。代码其实还是昨天那几个,只是多加了伪静态的支持就可以正常解析页面了,小绿锁也应声出现。但刚出现的小绿锁会在一瞬间消失,原因是网站内有非SSL的元素,比如插入的图片之类的。这种情况一般很麻烦,要用F12逐一查看报错的元素并进行修改。不过我们这次不需要这样做,Typecho的插件虽然比不上Wordpress,但还是有不少大佬开发的插件的。比如,内容替换插件。TEDUriReplace界面傻瓜直接,添加一条规则,从http到https,一瞬间,所有图片链接就都上了锁。小绿锁也可以一直续着了。
你以为这就完了?没这么简单,还有个昨天就出现,不伤大雅但有时候还是很憋屈的问题。
有些浏览器在不输入前缀的情况下会自动先访问HTTPS,但是有的则不会。如果用户没有输入HTTPS开头的网址,网页就会报400的错,The plain HTTP request was sent to HTTPS port,意思直观。你访问了个HTTPS的端口,但是你却没写前缀。懂点技术的此时就可以添上前缀,继续愉快的访问。但若是不知所云,一通乱点,也不会有什么效果。还以为我网站炸了不是么。
有人会说,简单啊,301重定向啊。Naive!我这可是运行在家里的服务器,别说80了,一开始没封的443现在也给安排上了。访问网站本来就要加端口,还要怎么重定向,自己定自己?
我还真头铁的尝试了,写两个server listen同一个端口,不带ssl的定向到另一个。但这样nginx -t都跑不过。此法失败,过于莽撞。那怎么办呢,两分钟查资料,发现一个非常巧妙的解决方法。确实妙,只需添加一行代码。

error_page 497 https://$host:233333$request_uri;

曲线救国,自己定自己。是什么原理呢,直接http不是报错么,好啊,我就检测你这个错误。一旦出错就往https上连,于是在报错的瞬间,网址就被重写了。这个方法针对非默认端口的网页非常有效,到这里,SSL之路基本就走完了,熟悉了操作,我把全站所有的服务都上了绿锁。漂亮啊(★ ω ★)。
最后贴上Typecho配置最终的代码

server {
listen XXX ssl;
server_name localhost;
ssl_certificate /opt/etc/nginx/XXXX.pem;
ssl_certificate_key /opt/etc/nginx/XXXX.key;
ssl_session_cache    shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
error_page 497 https://$host:XXX$request_uri;
root /opt/wwwroot/Typecho/;
index index.html index.htm index.php tz.php;
include /opt/etc/nginx/conf/php-fpm.conf;
include /opt/etc/nginx/conf/typecho.conf;

location / {
index index.html index.php;
if (-f $request_filename/index.html) {
    rewrite (.*) $1/index.html break;
}
if (-f $request_filename/index.php) {
    rewrite (.*) $1/index.php;
}
if (!-f $request_filename) {
    rewrite (.*) /index.php;
}
}

location ~ .*\.php(\/.*)*$ {
# fastcgi_index   index.php;
include snippets/fastcgi-php.conf;
    fastcgi_pass 127.0.0.1:9000;
# fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
    # include fastcgi_params;
}
}

评论区

评论列表