随着对安全性的关注,无论是个人还是企业或多或少都有从http升级到https的需求,但升级过程说着简单,整个过程却没有那么顺畅。这里我以个人的升级过程为例,给予一些参考。
背景:
在升级之前,我本人是做过部署方案设计的,且以前也从事过相关工作,因此对此次升级是非常乐观的,晚上10点下班到家,预计是12点之前应该可以完成升级。
然而整个过程真可以说是“理想很丰满,现实很骨感”:搞到了凌晨3点还没能完全解决,直到第二天才把遗留的最后一个问题解决了。(不过我很享受这样的过程,每一次未知问题的出现都代表着一次提升的机会。)
接着我会从“方案》实施》排障”顺序分享整个升级过程。
在我升级https前,已经用http一段时间了,此次升级针对的是其中两个HTTP服务:“wordpress”(博客)和“jenkins”(CI/CD)。
在升级上我考虑了两种方案:
其中,“方案1”有一个可预见的问题,由于我的云服务器上只有一个公网IP,因此如果分别都升到HTTPS的话,那么则必须使用不同的端口(非443),这样在使用上是较为不便利的。而“方案2”则可以通过“虚拟服务”的方法解决此问题,同时,“方案2”还可以应对未来可能继续增加的HTTPS或SSL服务。故而选择了“方案2”:
方案2示例图
如上所示,我选择了“Nginx”作为反向代理服务器,对外提供HTTPS能力,保留服务器原本的HTTP服务(由于“Nginx”、“wordpress”和“jenkins”在同一台机器中,因此使用HTTP并不会造成任何问题)。
由于nginx需要对两个服务都支持HTTPS,正常我们可以通过域名或URI进行解决,我选择采用的是域名,其中:
因为HTTPS需要用到证书,因此接着需要搞定证书问题,这里选择的是从“Let’s encrypt”签发免费证书。至此,方案工作已经完成。
这里可以直接参阅“Let’s encrypt”网站进行证书的获取,因为我的操作系统是“CentOS 8”,因此我参阅的是官方提供的如下教程:<https://certbot.eff.org/instructions?ws=other&os=centosrhel8>
最后证书如下所示:
证书示例图
jenkins.homqyy.cn
目录:存放了jenkins.homqyy.cn这个站点的证书和密钥www.homqyy.cn
目录:存放了www.homqyy.cn这个站点的证书和密钥站点目录里面存放的有如下文件:
cert.pem
:站点证书chain.pem
:中间证书fullchain.pem
:完整证书链(站点证书+中间证书)privkey.pem
:站点密钥注意:这里我并没有使用官方的“Nginx”镜像,而是“Nginx”的分支“Hengine”。
由于我的所有服务都是Docker化的,使用的docker-compose
进行编排和管理工作,下面给出一个数据调整过的最简样例文件docker-compose.yml
(对Docker感兴趣的可以跟进我的《Docker系列》文章):
部署样例图
proxy
提供反向代理。(感兴趣的朋友在阅读完后面内容后,可以在准备好本文提及的配置后,将附录的文件放到个人的docker主机上,并按需修改,最终执行docker-compose up -d
以运行上述服务)proxy
服务中的volumes
,属于代理的配置部分,因此需要个人提供。提供的内容为:./proxy/certs
放置到/usr/local/hengine/conf/certs
中,供HTTPS使用。./proxy/conf/nginx.conf
放置到/usr/local/hengine/conf/nginx.conf
,以用个人配置代替hengine的默认配置。接着重点就是编写nginx.conf
(就是上文提到的./proxy/conf/nginx.conf
)文件了,如下所示:
worker_processes 2;
user root;
error_log logs/info.log info;
events {
use epoll;
worker_connections 1024;
}
http {
#
# 重定向 http 到 https
#
server {
listen 80;
server_name *.homqyy.cn;
return 301 https://$host$request_uri;
}
#
# 代理Jenkins服务,提供HTTPS能力
#
server {
listen 443 ssl;
server_name jenkins.homqyy.cn;
ssl_certificate certs/jenkins.homqyy.cn/fullchain.pem;
ssl_certificate_key certs/jenkins.homqyy.cn/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
location / {
proxy_set_header Host $host;
proxy_set_header Connection "";
proxy_set_header X-Real-IP $remote_addr;
proxy_http_version 1.1;
proxy_pass http://jenkins:8080;
}
}
#
# 代理博客服务,提供HTTPS能力
#
server {
listen 443 ssl default_server;
server_name www.homqyy.cn;
ssl_certificate certs/www.homqyy.cn/fullchain.pem;
ssl_certificate_key certs/www.homqyy.cn/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
location / {
proxy_set_header Host $host;
proxy_set_header Connection "";
proxy_set_header X-Real-IP $remote_addr;
proxy_http_version 1.1;
proxy_pass http://blog;
}
}
}
上面有几个关键指令:
listen
:监听的端口,我们这里两个服务都是443
,同时通过ssl
来表明此端口是用SSL(TLS)
加密的,在HTTP中即是HTTPS。server_name
:虚拟服务的名称,就是通过此名称来区分是“jenkins”还是“博客”ssl_certificate
:站点证书,这里务必使用完整的证书链”fullchain.pem
”ssl_certificate_key
:站点密钥proxy_pass
:代理到后端服务一切准备继续,通过docker将proxy
服务启动:docker-compose up -d proxy
随着proxy
的运行和测试共发现两个问题
通过F12
(谷歌浏览器)查看资源加载情况,发现资源加载失败的原因是因为资源路径全是http://
开头的绝对路径。
通过“Hengine”的ngx_http_sub_module
将http://
改为https://
,其配置如下:
...
location / {
...
sub_filter 'https://www.homqyy.cn' 'https://www.homqyy.cn';
sub_filter 'http:\\/\\/www.homqyy.cn' 'https:\\/\\/www.homqyy.cn';
sub_filter_types *;
sub_filter_once off;
proxy_pass http://blog;
}
sub_filter
:如上图所示,我们这里写了两条替换规则,是因为通过F12
分析资源的时候发现,博客中的http资源有两个写法,一个是http://
,另一个是http:\/\/
仍旧无法加载资源:通过F12
发现资源路径仍旧是http://
,后面观察HTTP头部发现响应采用了GZIP的压缩算法,于是我在“Hengine”中增加了proxy_set_header Accept-Encoding
配置,来阻止传递“压缩指示”给博客站点。
再次访问,能正常访问并加载资源,但是在登录账户的时候发现页面被重定向为http
了,这肯定是不能接受的,因为它会导致账号信息以明文传输。浏览官网文档后发现官网有提供反向代理的解决方案:
define('FORCE_SSL_ADMIN', true);
// in some setups HTTP_X_FORWARDED_PROTO might contain
// a comma-separated list e.g. http,https
// so check for https existence
if (strpos($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') !== false)
$_SERVER['HTTPS']='on';
总结官网描述后需做如下两个操作:
wp-config.php
文件中增加define('FORCE_SSL_ADMIN', true);
,增加以后如上面所示。HTTP_X_FORWARDED_PROTO: https
再次尝试“登录”操作,发现一切正常。经过修改后的完整博客代理配置为:
#
# 代理博客服务,提供HTTPS能力
#
server {
listen 443 ssl default_server;
server_name www.homqyy.cn;
ssl_certificate certs/www.homqyy.cn/fullchain.pem;
ssl_certificate_key certs/www.homqyy.cn/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
location / {
proxy_set_header Host $host;
proxy_set_header Accept-Encoding "";
proxy_set_header Connection "";
proxy_set_header HTTP_X_FORWARDED_PROTO "https";
proxy_set_header X-Real-IP $remote_addr;
proxy_http_version 1.1;
sub_filter 'https://www.homqyy.cn' 'https://www.homqyy.cn';
sub_filter 'http:\\/\\/www.homqyy.cn' 'https:\\/\\/www.homqyy.cn';
sub_filter_types *;
sub_filter_once off;
proxy_pass http://blog;
}
}
jenkins的问题主要就是会出现重定向到http
的情况
因此在“Hengine”中增加配置proxy_redirect http://jenkins.homqyy.cn https://jenkins.homqyy.cn;
来解决此问题,最后完整配置如下所示:
#
# 代理Jenkins服务,提供HTTPS能力
#
server {
listen 443 ssl;
server_name jenkins.homqyy.cn;
ssl_certificate certs/jenkins.homqyy.cn/fullchain.pem;
ssl_certificate_key certs/jenkins.homqyy.cn/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
location / {
proxy_set_header Host $host;
proxy_set_header Connection "";
proxy_set_header X-Real-IP $remote_addr;
proxy_http_version 1.1;
proxy_redirect http://jenkins.homqyy.cn https://jenkins.homqyy.cn;
proxy_pass http://jenkins:8080;
}
}
其实通过反向代理进行站点部署还有很多好处,其中包括安全和性能。而从本文最直观的好处就是:既可以避免改动站点代码(改动代码必然带来了风险)从而加快升级过程,同时还可以从容的应对未来增加https或ssl服务的需求。最后我还结合了docker的编排和管理能力,大大的减少了部署、升级等成本。
访问博客站点能看到连接安全图标:
访问博客站点示例图
访问jenkins站点也能看到连接安全图标:
访问jenkins站点示例图
version: '3.8'
services:
proxy:
image: homqyy/hengine
restart: always
ports:
- "443:443/tcp"
- "80:80/tcp"
volumes:
- ./proxy/certs/:/usr/local/hengine/conf/certs/:ro
- ./proxy/conf/nginx.conf:/usr/local/hengine/conf/nginx.conf:ro
blog:
image: wordpress
restart: always
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: exampleuser
WORDPRESS_DB_PASSWORD: examplepass
WORDPRESS_DB_NAME: exampledb
volumes:
- wordpress:/var/www/html
db:
image: mysql:5.7
restart: always
environment:
MYSQL_DATABASE: exampledb
MYSQL_USER: exampleuser
MYSQL_PASSWORD: examplepass
MYSQL_RANDOM_ROOT_PASSWORD: '1'
volumes:
- db:/var/lib/mysql
jenkins:
image: jenkins/jenkins:lts-jdk11
restart: always
environment:
JAVA_OPTS: '-Dhudson.footerURL=https://www.homqyy.cn'
volumes:
- jenkins:/var/jenkins_home
volumes:
wordpress:
db:
jenkins:
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有