为Blog启用HTTPS

我的Blog主要是记录并总结一些遇到的问题及解决方法,或是自己的技术积累,其实并不需要HTTPS,但每次打开网站总能看到标题栏提示不安全,这也不是很爽,所以一直想启用HTTPS,但一直没有实施。最近正好有些时间,所以就把这个搞定了,但其实也是遇到了很多问题,在此记录下来。

HTTPS认证过程

首先看下HTTPS的认证过程,我使用电脑通过4G联网访问我的网站,把报文抓了下来,来简单展示认证的几个关键过程,以了解其工作原理(不做详细介绍):

  1. 客户端与服务端的三次握手;
  2. 三次握手成功后,客户端发送Client Hello,其包含客户端随机数、支持的TLS版本、客户端支持的密码套件(Cipher Suite)和客户端共享Key;
  3. 这里有5个包,第1个是ACK,第2个是Server Hello,其包服务器随机数,含支持的TLS版本,服务器支持的密码套件(Cipher Suite)和服务器共享Key,并标记Change Cipher Spec,代表3、4、5包都是加密的,后面3个包中包含了加密扩展,证书和Finished。能解密看里面的内容吗,当然可以,具体可以参考下一小节;
  4. 客户端收到后,用服务端证书中的公钥加密接下来用于通信的秘钥,密文发给服务端(这点我在抓包中没看到,暂时不理解);
  5. 服务端收到后用自己的私钥解密,拿到通信秘钥,后面的通信使用这个秘钥进行加密数据;

如何Decode TLS报文

这里只介绍MacOS,其他系统类似,可以自行查阅。根据相关文档,只有Firefox和Chome支持此种方法把交互的key保持下来,以供Wireshark进行解码。

设置环境变量,游览器会自动调用这个参数:

~ % export SSLKEYLOGFILE=~/Documents/sslkeylog.log
~ % echo $SSLKEYLOGFILE
/Users/xxxxx/Documents/sslkeylog.log

在Wireshark上关联这个文件:Preferences -> Protocols -> TLS -> (Pre)-Master-Secret log filename

然后打开游览器,游览抓包,在报文中就可以看到Decrypted TLS的相关信息了

~ % /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome -incognito

申请SSL/TLS证书

证书可以通过很多途径获得,但各有优缺点:

  • 比如参考我之前的文章,可以进行自签证书,虽然数据也是加密的,但游览器是不认的,因为你是个人,不是权威机构,换句话说,没有给游览器交过保护费,此时查看证书会有个红叉;
  • 可以依托Let’s Encrypt免费签SSL/TLS R3证书,这个游览器是认可的,关键是免费的,不过时间比较短,只有90天,详细可以查看这里
  • 使用域名服务商提供的免费SSL/TLS证书,缺点是需要让互访流量经过域名服务商,换句话就是要用域名提供商代理你的网站流量(也就是做CDN),这样可以做到端到端的加密;

我最近刚把域名从Godaddy transfer到Cloudflare上了, 原因主要是域名注册续费,Godaddy每年都提高续费价钱,个人Blog很难承受的住,果断切到了Cloudflare,这里的续费费用是透明的,每年是一样的。正好Cloudflare提供免费的HTTPS的证书,所以直接通过Cloudflare来实现HTTPS就好了。

Cloudflare相关配置

设置加密规则,我这里使用的的严格加密方式,也就是服务器上需要使用Cloudflare的证书

然后在Origin Server中创建证书,我这里没法截图,因为证书已经生成了,直接文字描述:

  • 使用Cloudflare生成私钥和CSR,2048就好
  • 选择要保护的域名
  • 年限默认15年

生成好后,下载源证书和私钥(注:要自行保留好私钥,Cloudflare不保存私钥信息)到服务器上。

切换博客到Nginx

开始以为直接用Nginx代理下就可以了,后来发现想简单了。原来的博客是通过Apacha建立的,如果用Nginx,就需要替换掉Apacha。但Apacha是支持对PHP代码的解析,而Nginx则不支持,因此想用Nginx,就需要一个中间件,来替代Apacha对PHP代码支持的工作,这个组件就是Nginx的FastCGI模块,Nginx只是将结果反馈给客户端。

优化docker-compose文件

原始文件可以参考我之前的文章:Blog顺利完成搬家之Bandwagonhost VPS 中的 docker-compose.yml文件,下面是适配Nginx的配置:

  • 给每个容器都增加了一个app-network的网络,并bridge所有关联docker;
  • 指定Wordpress FPM版本,在这个版本里,PHP也从之前的7升级到了8,这也为后面的问题埋下了伏笔;
  • 限制Wordpress的CPU利用率,此容器只能使用50%的CPU资源(至于原因可以看这里:https://www.zhaocs.info/blog-revision-record#ftoc-heading-25),注意用了这部分配置,需要在启动时加上兼容flag,如:docker-compose –compatibility up -d
  • FPM版本的默认端口是9000;
  • 增加Nginx容器的配置,其中挂载两个目录,一个是Wordpress,另一个是Nginx相关的配置文件目录,并放通80和443端口;
  • 增加redis,来为Wordpress开启持久对象缓存;
  • 注意不需要暴露到internet的端口不要设置ports参数,如wordpress和redis,都是内部通信,完全没必要设置ports,如果设置了,这些端口被暴露到internet上,有被攻击的风险,我就被攻击了,折腾了好久才彻底解决,具体可以看博客修订记录 23年8月和11月的记录;
[root@xxx my_wordpress]# more docker-compose.yml 
version: '6'

services:
   db:
     image: mysql:5.7
     volumes:
       - ./mysql_data:/var/lib/mysql
     restart: always
     environment:
       MYSQL_ROOT_PASSWORD: xxxx
       MYSQL_DATABASE: wordpress
       MYSQL_USER: wordpress
       MYSQL_PASSWORD: wordpress
     networks:
       - app-network

   redis:
     image: redis:alpine
     restart: always
#     ports:
#       - 6379:6379
     networks:
       - app-network

   wordpress:
     depends_on:
       - db
     image: wordpress:6.2.1-php8.0-fpm
     deploy:
       resources:
         limits:
           cpus: '0.50'
#     ports: 
#       - "9000:9000"
     logging:
       options:
         max-size: "1m"
     volumes:
       - ./wordpress_data:/var/www/html
     restart: always
     environment:
       WORDPRESS_DB_NAME: wordpress
       WORDPRESS_DB_HOST: db:3306
       WORDPRESS_DB_USER: wordpress
       WORDPRESS_DB_PASSWORD: wordpress
     networks:
       - app-network

   nginx:
     depends_on:
       - wordpress
     image: nginx:latest
     volumes:
       - ./wordpress_data:/var/www/html
       - ./nginx-conf:/etc/nginx/conf.d
     restart: always
     ports:
       - 80:80
       - 443:443
     links:
       - wordpress
     networks:
       - app-network

#   phpmyadmin:
#     depends_on:
#       - db
#     image: phpmyadmin/phpmyadmin
#     ports:
#       - "8080:80"
#     restart: always
#     environment:
#       PMA_HOST: db
#       PMA_USER: wordpress
#       PMA_PASSWORD: wordpress
#     networks:
#       - app-network

volumes:
    db_data:

networks:
    app-network:
      driver: bridge

Nginx配置文件

[root@xxx my_wordpress]# more nginx-conf/default.conf 

# redirect http -> https
server {
        listen 80;
        listen [::]:80;
        server_name www.zhaocs.info zhaocs.info;
        return 301 https://www.zhaocs.info$request_uri;
}

server {
        listen 443 ssl http2;
        listen [::]:443 ssl http2;
        server_name www.zhaocs.info;
        root /var/www/html;
        index index.php;
        client_max_body_size 64m;  # if not add, attach file will have issue.

        ssl_certificate /etc/nginx/conf.d/xxx.pem;
        ssl_certificate_key /etc/nginx/conf.d/xxx.key;

        ## This block will handle .htaccess files since Nginx won’t serve them.
        ## The deny_all directive ensures that .htaccess files will never be served to users.
        location ~ /\.ht {
                deny all;
        }
        
        location = /favicon.ico { 
                log_not_found off; 
                access_log off; 
        }
        
        location = /robots.txt { 
                log_not_found off; 
                access_log off; 
                allow all; 
        }

        location / {
                ## Try_files directive is used to check for files that match individual URI requests. 
                ## Instead of returning a 404 Not Found status as a default, however, you’ll pass control 
                ## to WordPress’s index.php file with the request arguments.
                try_files $uri $uri/ /index.php?$args;
        }

        location ~ \.php$ {
                try_files $uri =404;
                fastcgi_split_path_info ^(.+\.php)(/.+)$;
                fastcgi_pass wordpress:9000;
                fastcgi_index index.php;
                include fastcgi_params;
                #fastcgi_intercept_errors on;
                fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                fastcgi_param PATH_INFO $fastcgi_path_info;
        }

        location ~* \.(css|gif|ico|jpeg|jpg|js|png)$ {
                expires max;
                log_not_found off;
        }
        location = /xmlrpc.php {  #因为这个导致了cpu高,关闭此无用接口
                deny all;
        }
}

优化文件目录

为了方便后续的维护,通过软链接的方式统一进行维护,如下:

ln -s /opt/wp-backup/wpbackup.sh /opt/wpbackup.sh
ln -s /opt/wp-backup/tscpupeak.sh /opt/tscpupeak.sh
ln -s /opt/wp-backup/nginx-conf/ /opt/my_wordpress/nginx-conf
ln -s /opt/wp-backup/docker-compose.yml /opt/my_wordpress/docker-compose.yml

my_wordpress是工作目录,wp-backup是备份目录,nginx-conf是nginx的配置文件,wp-backup.sh脚本定期备份mysql数据库和wordpress_data文件并打包存到wp-backup目录,群辉NAS定期对这个目录进行备份同步:

[root@xxxxx]# tree -L 2 /opt/
/opt/
├── my_wordpress
│   ├── docker-compose.yml -> /opt/wp-backup/docker-compose.yml
│   ├── mysql_data
│   ├── nginx-conf -> /opt/wp-backup/nginx-conf/
│   └── wordpress_data
├── tscpupeak.sh -> /opt/wp-backup/tscpupeak.sh
├── wp-backup
│   ├── docker-compose.yml
│   ├── nginx-conf
│   ├── tscpupeak.sh
│   └── wpbackup.sh
└── wpbackup.sh -> /opt/wp-backup/wpbackup.sh

veth端口映射和交互流量

大部分流量都在container间交互了,特别是redis和wordpress两个container,如下:

问题及解决

不兼容的插件导致Wordpress崩溃

恢复Mysql和Wordpress数据后,https解析正常,但发现Wordpress无法正常显示,只显示遇到了致命错误:

此时可以使用下面命令开启Wordpress的debug模式,在wp-config.php配置中:

// 开启WP_DEBUG模式
define( 'WP_DEBUG', true);
// 开启DEBUG日志,一定要记得关闭这个日志功能并清理这个日志文件哦,产生的日志文件在: /wp-content/debug.log
define( 'WP_DEBUG_LOG', true);
// 显示errors and warnings
define( 'WP_DEBUG_DISPLAY', true);
@ini_set( 'display_errors', 'On');

开启后再次打开网站,可以看到如下错误,经过分析,就是因为升级到PHP8以后,部分插件和主题不兼容导致的:

Fatal error: Uncaught Error: Call to undefined function create_function() in /var/www/html/wp-content/plugins/auto-syntaxhighlighter/auto-syntaxhighlighter.php:119 
Stack trace: #0 /var/www/html/wp-settings.php(453): include_once() #1 /var/www/html/wp-config.php(84): require_once('/var/www/html/w...') #2 /var/www/html/wp-load.php(50): require_once('/var/www/html/w...') #3 /var/www/html/wp-blog-header.php(13): require_once('/var/www/html/w...') #4 /var/www/html/index.php(17): require('/var/www/html/w...') #5 {main} thrown in /var/www/html/wp-content/plugins/auto-syntaxhighlighter/auto-syntaxhighlighter.php on line 119

打开phpMyAdmin,连接到MySQL的数据库中,输入下面SQL命令:

SELECT * FROM wp_options WHERE option_name ='active_plugins';
a:13{i:0;s:19:"akismet/akismet.php";i:1;s:49:"auto-syntaxhighlighter/auto-syntaxhighlighter.php";i:3;s:75:"delete-all-comments-of-website/delete-all-comments-of-wordpress-website.php";i:4;s:46:"feed-reading-blogroll/feedreading_blogroll.php";i:5;s:23:"fixed-toc/fixed-toc.php";i:6;s:19:"jetpack/jetpack.php";i:7;s:15:"mulberrykit.php";i:8;s:9:"og/og.php";i:9;s:47:"simple-yearly-archive/simple-yearly-archive.php";i:10;s:37:"tinymce-advanced/tinymce-advanced.php";i:11;s:25:"wp-cumulus/wp-cumulus.php";i:12;s:39:"wp-recentcomments/wp-recentcomments.php";i:13;s:21:"wp-ulike/wp-ulike.php";}

把value改成 a:0:{} 后,关闭所有插件,如果想把网站名称改了,也可以使用下面这些SQL语句找到后直接改数据库的内容:

SELECT * FROM wp_options WHERE option_name ='siteurl';
SELECT * FROM wp_options WHERE option_name ='home';

不兼容的主题导致Wordpress崩溃

使用类似的SQL语句可以找到当前使用的主题,并更改成默认主题,这样就可以恢复了,如下:

但我的主题是经过自己一点一点魔改的,里面加了一些定制的内容。我尝试换成其他主题,但想要适配我的需求,仍然需要时间折腾,所以暂时还是先想办法把问题解决了,下面是开启Debug模式后的告警:

这里有两个问题,一个是”rigister_sidebar调用方法不正确“,另一个是”call_user_func_array() expects“,对于第一个问题,可以直接去主题目录,查找函数,并增加一行指令:

[root@xxx page-shippou]# grep -rn 'register_sidebar' *
functions.php:284:if( function_exists('register_sidebar') ) {
functions.php:285:      register_sidebar(array(
[root@xxx page-shippou]# more functions.php |grep register_sideba -A 5
if( function_exists('register_sidebar') ) {
        register_sidebar(array(
                'name' => 'bottom-sidebar',
        'id' => 'sidebar-1', //添加这行
        'before_widget' => '<li id="%1$s" class="widget %2$s">',
        'after_widget' => '</li>',
        'before_title' => '<h3>',

对于第二个问题,经查找,注释掉非法语句就可以了,详细可以看这里,我这里只有add_action:

[root@xxx page-shippou]# more functions.php |grep add_action -A 3 -B 3
};

// register functions
//add_action('admin_menu', array('pageOptions', 'add'));
/** page options */
class  pageOptions {

说白了还是因为主题太老了,很多新功能没有适配,老语法也不再支持了-_-…

本文出自 Frank's Blog

版权声明:


本文链接:为Blog启用HTTPS
版权声明:本文为原创文章,仅代表个人观点,版权归 Frank Zhao 所有,转载时请注明本文出处及文章链接
你可以留言,或者trackback 从你的网站

留言哦

blonde teen swallows load.xxx videos