前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >利用Nginx将服务从http升级到https

利用Nginx将服务从http升级到https

作者头像
Homqyy
发布2023-03-06 13:26:28
2K0
发布2023-03-06 13:26:28
举报
文章被收录于专栏:知行合一知行合一

前言

随着对安全性的关注,无论是个人还是企业或多或少都有从http升级到https的需求,但升级过程说着简单,整个过程却没有那么顺畅。这里我以个人的升级过程为例,给予一些参考。

代码语言:javascript
复制
背景:
在升级之前,我本人是做过部署方案设计的,且以前也从事过相关工作,因此对此次升级是非常乐观的,晚上10点下班到家,预计是12点之前应该可以完成升级。
然而整个过程真可以说是“理想很丰满,现实很骨感”:搞到了凌晨3点还没能完全解决,直到第二天才把遗留的最后一个问题解决了。(不过我很享受这样的过程,每一次未知问题的出现都代表着一次提升的机会。)

接着我会从“方案》实施》排障”顺序分享整个升级过程。

方案

在我升级https前,已经用http一段时间了,此次升级针对的是其中两个HTTP服务:“wordpress”(博客)和“jenkins”(CI/CD)。

在升级上我考虑了两种方案:

  • 方案1:直接将“wordpress”和“jenkins”服务分别升级到HTTPS
  • 方案2:通过反向代理来提供HTTPS的能力,最后卸载成HTTP后代理到“wordpress”和“jenkins”

其中,“方案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”镜像,而是“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使用。
    • nginx配置文件:将个人的nginx配置./proxy/conf/nginx.conf放置到/usr/local/hengine/conf/nginx.conf,以用个人配置代替hengine的默认配置。

接着重点就是编写nginx.conf(就是上文提到的./proxy/conf/nginx.conf)文件了,如下所示:

代码语言:javascript
复制
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的运行和测试共发现两个问题

  • 访问站点的时候,资源加载失败。
  • 登录博客的时候,是http,而非期望的https
【定位分析】

通过F12(谷歌浏览器)查看资源加载情况,发现资源加载失败的原因是因为资源路径全是http://开头的绝对路径。

【解决方案】

通过“Hengine”的ngx_http_sub_modulehttp://改为https://,其配置如下:

代码语言:javascript
复制
        ...

        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了,这肯定是不能接受的,因为它会导致账号信息以明文传输。浏览官网文档后发现官网有提供反向代理的解决方案

代码语言:javascript
复制
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';

总结官网描述后需做如下两个操作:

  1. wp-config.php文件中增加define('FORCE_SSL_ADMIN', true);,增加以后如上面所示。
  2. 代理到wordpress的时候添加头部:HTTP_X_FORWARDED_PROTO: https

再次尝试“登录”操作,发现一切正常。经过修改后的完整博客代理配置为:

代码语言:javascript
复制
    #
    # 代理博客服务,提供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问题

jenkins的问题主要就是会出现重定向到http的情况

因此在“Hengine”中增加配置proxy_redirect http://jenkins.homqyy.cn https://jenkins.homqyy.cn;来解决此问题,最后完整配置如下所示:

代码语言:javascript
复制
    #
    # 代理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站点示例图

附录

docker-compose.yml

代码语言:javascript
复制
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:
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022年5月8日20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 方案
  • 实施
    • 获取证书
      • 部署Nginx
      • 排障
        • 博客问题
          • 【定位分析】
          • 【解决方案】
          • 【测试结果】
        • jenkins问题
        • 最后
        • 附录
          • docker-compose.yml
          相关产品与服务
          容器镜像服务
          容器镜像服务(Tencent Container Registry,TCR)为您提供安全独享、高性能的容器镜像托管分发服务。您可同时在全球多个地域创建独享实例,以实现容器镜像的就近拉取,降低拉取时间,节约带宽成本。TCR 提供细颗粒度的权限管理及访问控制,保障您的数据安全。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档