Revision Record

2010-01 添加个性图标

这是我建站后的第一件事,实在记不清是什么时候的事了,2010年是我第五次Blog搬家,时间不重要,重要的是内容:) ,给网站加favicon.ico图标(个性图标),在header.php中:
[link rel=”shortcut icon” href=”/wp-content/themes/page-shippou/img/favicon.ico” ]

2011-07 增加置顶及相应的CSS

具体时间记不清了,增加了置顶文章的代码,并且增加了几个CSS样式表,“fontbg”是设置背景颜色的,“zhiding”是文章置顶的样式,另外在置顶样式中修改了默认的超链接显示:

/* frank's css */
#fontbg {
background-color: #99ccff;
margin-top: 5pt;
margin-bottom: 5pt;}

#zhiding {
background-color:#FFFEC6;
margin:0px;
font-weight:bolder;color:#EA0000;
}
#zhiding a{color: #fff; text-decoration: none;}
#zhiding a:hover {text-decoration: underline;}
/* End frank's css */

下面是在在index的php代码:

<?php //置顶代码开始 ?>

<?php if(is_sticky()) { ?>
<div id="zhiding">[置顶] <a href="<?php the_permalink() ?>" rel="bookmark" title="<?php the_title_attribute(); ?>"><?php the_title(); ?></a>
</div>

<?php }else{ ?>
<div class=padding></div>

<div class="post" id="post-<?php the_ID(); ?>">

<h1><a href="<?php the_permalink() ?>" rel="bookmark" title="Permanent Link to <?php the_title_attribute(); ?>"><?php the_title(); ?></a></h1>

<div class="postinfo"><span class="date"><?php the_time('F jS, Y') ?>,由 <strong><?php the_author_nickname(); ?></strong>撰写</span><span class="urcomments"> <?php comments_popup_link('No Comments &#187;', '1 Comment &#187;', '% Comments &#187;'); ?></span><?php edit_post_link(__('Edit', 'page'), '<span class="editpost">', '</span>'); ?><!-- by <?php the_author() ?> --></div>

<div class="clear"></div>

<div class="entry">
<?php the_content(__('Read the rest of this entry &raquo;', 'page')); ?>
</div>
				
<div class="postmetadata clear">
<span class="categorys"><?php the_category(', ') ?> </span>
<?php the_tags('<span class="tags">', ',', '</span>'); ?>
</div>

</div>
<?php } //置顶代码结束?>

2015-03 代码高亮插件

最近在学习Python,JAVA,TCL等语言,所以会在BLOG里填写代码,看到其他博客的代码高亮很是眼馋,于是一直想找一款好用又可移植的插件来高亮代码,优化阅读。在之前的文章中,我一直用pre来标识信息,并且简单自定义了下,如改变了背景。所以在想有没有相应的class,我原来用pre标记的不受影响,当有代码段时,调用pre不同的class,这样灵活方便,而且即使插件不能用了,也就是class不用调用,仍然会用pre,不会影响格式问题!

后来找到了Crayon Syntax Highlighter,不能不说这个很漂亮,但通过在pre调用class的方式不成功,有报错,只能通过下面方法调用,这种方法有严重弊端,当从文本编辑器切换到可视化后,代码中的空格会消失,格式混乱!另外如果插件不工作,后果不堪设想!另外为了TS,我特意换了一个主题,发现问题一样,估计是兼容性的问题。为了使用插件,特意去作者的support网站发了一个帖子,但暂时没有解决方法,也有人跟我的情况一样。。。

[crayon lang="java", title="Code:FlashDisk"]
[/crayon

最后本想放弃了,直接用默认的pre,虽然不好看,但毕竟格式是正常的,却发现有网友介绍了一个非常好用的代码高亮轻插件:“Auto SyntaxHighlighter”,这就是我想要的,Crayon功能多加载慢,能明显感觉出来,而这款插件功能少加载很快!

2015-03 调用SSL Gravatar

下面方法已经不生效,请移至2022-01的更新

最近发现打开主页非常慢,通过firefox的firebug工具,可以很容易检测出来网页加载时都在干什么,这个工具非常棒,看到了两个问题:

  1. Jetpack好像再查什么东西
  2. Gravatar一直访问超时

关于Jetpack,关闭了大部分功能,只留了网站统计功能后,不再报类似的提示;但Gravatar仍然有问题,后来查了下,发现GFW把他屏蔽了,应该是去年的事,还好有些解决办法,只要把下面代码放入主题functions.php中就ok了:

function get_ssl_avatar($avatar) {
   $avatar = preg_replace('/.*\/avatar\/(.*)\?s=([\d]+)&.*/','<img src="https://secure.gravatar.com/avatar/$1?s=$2" class="avatar avatar-$2" height="$2" width="$2">',$avatar);
   return $avatar;
}
add_filter('get_avatar', 'get_ssl_avatar');

更详细的可以参考:Gravatar 头像被屏蔽导致网站速度变慢
题外话:如果启动网站的私有SSL(https),需要host供应商支持,Hostgator每年要50刀…

2017-10 搬迁到Bandwagonhost VPS

由于种种原因,变迁到VPS,并用docker部署WP,详细过程看http://www.zhaocs.info/blog-move-new-vps-bandwagonhost.html

2018-10 重新部署

由于变更VPS的地址,里面很多应用受到影响,所以重新安装并重新部署WP,步骤如上面总结的,不过恢复完发现主页如下错误:

Warning: Use of undefined constant wp_cumulus_widget – assumed ‘wp_cumulus_widget’ (this will throw an Error in a future version of PHP) in /var/www/html/wp-content/plugins/wp-cumulus/wp-cumulus.php on line 375

经过排障,发现使用docker安装的WP是最新版本的,由于PHP已经升级到了7.2,这导致我WP备份版本(4.8.7)中的语法在7.2中出现错误,纠正错误语法即可,详细信息可以参考

https://stackoverflow.com/questions/2941169/what-does-the-php-error-message-notice-use-of-undefined-constant-mean

命令:#nano +375 wp-content/plugins/wp-cumulus/wp-cumulus.php

原始代码:register_sidebar_widget( “WP-Cumulus”, wp_cumulus_widget );

变更代码:register_sidebar_widget( “WP-Cumulus”, wp_cumulus_widget );

2020-08 Docker DNS问题

最近突然发现Wordpress的插件都无法更新了,以为wordpress有问题,尝试重新安装,但发现下载失败:

正在从https://downloads.wordpress.org/release/zh_CN/wordpress-5.4.2.zip下载更新…

下载失败。: URL无效。

安装失败

通过“站点健康”,发现有很多timeout告警,下面是其中之一:

REST API是WordPress及其他应用与服务器通信的一种途径。一个例子是区块编辑器页面,它依赖REST来显示及保存您的页面和文章。

REST API请求因遇到了错误而失败。
错误:cURL error 28: Resolving timed out after 10522 milliseconds(http_request_failed)

通过查找,发现跟DNS相关,但主机的DNS没任何问题,只是docker内有问题:

[root@xxxx ~]# nslookup wordpress.org
;; Got recursion not available from 97.74.106.27, trying next server
Server:         1.0.0.1
Address:        1.0.0.1#53

Non-authoritative answer:
Name:   wordpress.org
Address: 198.143.164.252
[root@xxxx ~]# curl wordpress.org
<html>
<head><title>301 Moved Permanently</title></head>
<body>
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx</center>
</body>
</html>
[root@xxxx ~]# docker exec -it 7b3 bash
root@7b3b7fc556b6:/var/www/html# curl wordpress.org
curl: (6) Could not resolve host: wordpress.org

所以根据这个文章,添加dns信息:DOCKER 容器内部 DNS 解析失败的问题

2020-08 Failed to load plugin

自从Wordpress支持字块后,编辑文章时从会有下面报错:

Failed to load plugin url: http://www.zhaocs.info/wp-content/plugins/auto-syntaxhighlighter/tinymce/ash/langs/zh.js

这次重新部署了blog,把上面DNS的问题解决了,所以想把这个问题也解决了,检查了下,发现此插件是没有langs以及zh.js的文件,所以下载语言tinymce4x_languages,把zh_CN.js 改名成zh.js并上传到相应目录下,fix此问题

2021-01 调整CSS样式

还是很喜欢目前这个主题,但里面的样式表做的不好,导致内容展示很别扭,所以这次好好弄一下

原创声明

首先在文章页面(single.php)添加原创声明

<?php //Frank 版权声明 ?>
<div id="fenge"></div>
本文出自 <a href="www.zhaocs.info" rel="bookmark" title="www.zhaocs.info" data-type="URL" data-id="zhaocs.info">Frank's Blog</a>
	<p><b>版权声明:</b></p><hr style=" height:2px;border:none;border-top:2px dotted #185598;" />
	<b>本文链接:</b><a href="<?php the_permalink() ?>" rel="bookmark" title="<?php the_title_attribute(); ?>"><?php the_title(); ?></a><br>
	<b>版权声明:</b>本文为原创文章,仅代表个人观点,版权归 <a href="www.zhaocs.info" rel="bookmark" title="www.zhaocs.info" data-type="URL" data-id="zhaocs.info"><strong>Frank Zhao</strong></a> 所有,转载时请注明本文出处及文章链接
</div>
<?php //Frank 版权声明 ?>

通过CSS修饰此段声明

#cpstyle{
border-style: solid;
background-color: #FCF2EA;
border-left-color: #FD7927;
border-width: 0px 0px 0px 4px;
padding: 10px 10px 10px 15px;
margin: 20px 30px 20px 0px;
}

在声明和文章之间通过CSS加隔离线

#fenge{
border-style: dashed;
border-width: 0.75px 0px 0px 0px;
border-top-color: #D3D3D3;
padding: 10px 10px 10px 10px;
margin: 30px 30px 0px 0px;
}

修饰引用部分

.entry blockquote {
border-style: solid;
background-color: #EEF6FC;
border-left-color: #3BA3F8;
border-width: 0px 0px 0px 4px;
padding: 10px 15px 10px 15px;
margin: 20px 0px 20px 0px;	
}

修饰Pre code样式

对Pre进行修饰

.entry pre {
box-sizing:border-box; 	
overflow:scroll;
-webkit-overflow-scrolling:touch;
/* font-family:monospace, Menlo, Monaco, Consolas, 'Courier New'; */
font-size:11px;
padding:9.5px;
margin-top:0px;
margin-bottom:10px;
line-height:1.42857;
color:#333333;
word-break:break-all;
word-wrap:break-word;
border:1px solid #CCCCCC;
border-radius:4px;
background-color:#F5F5F5;
}

改后发现不是所有的Pre都起作用,经过Chome + F12 debug查看了下应用样式,发现新的Wordpress又增加了一个额外的CSS (“wp-includes/css/dist/block-library/style.min.css“),这样可以方便用户 bypass 主题的样式表自定义自己的,这样更安全

不过我没有研究,直接找到后,把code中的两个样式去掉就行了,不过wordpress升级后,估计会变回去,到时在研究下如何基于wordpress自定义用户样式表

修饰图片样式

这样是可以修饰,看上去美观多了

.entry img {
border:0.75px solid #000; 
padding:2px;
max-width:580px;
height:auto;
margin:3px; 
border-radius: 0px; 
box-shadow: 0 0 2px 1px rgba(14, 13, 13, 0.5);
}

可是图片的右边框有问题,感觉超出范围了。。。这是什么原因造成的?

通过Chrome的开发者界面,找到了原因,内容部分在div中设置的是650,减去两边留白后,内容部分为598,我在修饰图片时,又增加了一定的padding和margin(减掉我加的,应该是586),所以超出了边框。但又不能简单的加上宽度,这样所有图片都被拉伸到这个宽度了,是否有其他办法?图片自适应大小主要靠下面CSS(”wp-includes/css/dist/block-library/style.min.css“)中“wp-block-code code”样式实现的:

max-width: 100%

这个100%就是598,那么既然我只能用百分比来完成图片自适应,那么直接改小这个百分比就可以了 ?,因此调整到98%后恢复正常!

2021-02 自定义额外CSS

wordpress自动升级了,之前在style.min.css中改的那两处失效了,简单看了下,其实可以直接用wordpress自带的自定义额外CSS功能,这样即使升级了,也不会覆盖了,这样更安全,以后慢慢把之前改的CSS挪到这里把~

.wp-block-code code{white-space:pre;overflow-wrap:break-word}
.wp-block-image img{max-width:98%}

2021-08 解决“white-space:pre”在Safari上不生效

查了下,发现增加word-wrap参数即可解决此问题,可以参考:Safari 浏览器 white-space: pre 无效,如下:

.wp-block-code code{white-space:pre; word-wrap:normal; overflow-wrap:break-word; -webkit-overflow-scrolling:touch; }
.wp-block-image img{max-width:98%}

2021-10 解决上传2m的限制

之前就有这个问题,稍微大点就上传不了了,并报警:

上传的文件大小超过php.ini文件中定义的upload_max_filesize值。

所以这回想彻底解决这个问题,查了下需要改php.ini,但docker版本的Wordpress没有这个文件,所以查了下发现直接在Wordpress目录下新建立一个php.ini,然后重启docker即可生效,如下:

[root@frank wordpress_data]# more php.ini
#file_uploads = On
memory_limit = 32M
upload_max_filesize = 32M
post_max_size = 32M
max_execution_time = 360
[root@frank my_wordpress]# docker-compose down
Stopping my_wordpress_wordpress_1 ... done
Stopping my_wordpress_db_1        ... done
Removing my_wordpress_wordpress_1 ... done
Removing my_wordpress_db_1        ... done
Removing network my_wordpress_default
[root@frank my_wordpress]# docker-compose up -d
Creating network "my_wordpress_default" with the default driver
Creating my_wordpress_db_1 ... done
Creating my_wordpress_wordpress_1 ... done

2024-04更新:经过确认,用Nginx替换Apache后,此种方法就失效了,最终把php.ini 重命名为.user.ini后,可以正常功能,也可以参考这篇文章,并可在“站点健康”里查看“媒体”:

[root@frank-blog wordpress_data]# more .user.ini
upload_max_filesize = 32M
post_max_size = 64M
memory_limit = 128M
[root@frank-blog wordpress_data]# docker restart xxxx

2022-01 “is-style-stripes” no any effect

更新后的Wordpress对表格增加了样式,可以根据需求选择,如下:

但问题是编辑时是有效果的,但是更新后效果就消失了。通过Chrome的F12开发者模式,逐一检查了CSS,发现都去掉所有相关CSS后均没有太多变化,此时怀疑是主题的CSS把Wordpress的Inline CSS样式表给覆盖了,所以找到主题CSS,并注释掉跟Table/tr/td/th,更新后发现Inline CSS样式生效了~

不过看上去表格和文字很紧凑,没有任何空隙,很不好看,想用cellpadding,但发现html5已经移除了此属性,因此就在Wordpress的Inline CSS样式表中增加:

table tr td{padding:8px;}

并在“is-style-stripes”中修饰了下表格,增加上下边框,为了防止wordpress升级导致“is-style-stripes”被重置,把这部分代码也加进Inline CSS样式表中:

.wp-block-table.is-style-stripes {border-spacing:0;border-collapse:inherit;background-color:transparent;border-width:1px 0px 1px 0px;border-style:solid;}

2022-01 再次修复Gravatar

2015年修复的方法目前已经不工作了,下了几个Gravator缓存插件也有同样的问题,真的很郁闷。后来查到了有一个Cravator,不过不知道如何调用,而且需要安装第三方wordpress插件,所以就暂时放弃了。最后找到一种方法,目前还有效果,就是去掉2015年加的那段函数,并添加下面新的函数:

//Gravatar 头像修复
if ( ! function_exists( 'get_cravatar_url' ) ) {
function get_cravatar_url( $url ) {
$sources = array(
'www.gravatar.com',
'0.gravatar.com',
'1.gravatar.com',
'2.gravatar.com',
'secure.gravatar.com',
'cn.gravatar.com'
);
return str_replace( $sources, 'cravatar.cn', $url );
}
add_filter( 'um_user_avatar_url_filter', 'get_cravatar_url', 1 );
add_filter( 'bp_gravatar_url', 'get_cravatar_url', 1 );
add_filter( 'get_avatar_url', 'get_cravatar_url', 1 );
};

2022-06 更新Wordpress后自定义CSS消失

更新新版本后,自定义CSS部分消失了,因此按照此篇的记录,重新又加了回来,为了方便日后维护,把目前所有CSS都列出来:

.wp-block-code code{white-space:pre; word-wrap:normal; overflow-wrap:break-word; -webkit-overflow-scrolling:touch; }
.wp-block-image img{max-width:98%}
table tr td{padding:8px;}
.wp-block-table.is-style-stripes {border-spacing:0;border-collapse:inherit;background-color:transparent;border-width:1px 0px 1px 0px;border-style:solid;}

2022-09 更新Wordpress Container

最近使用Wordpress自带的监控检查,发现php少了一个module,经过查看,是因为新版本需要这个module,但我使用的docker container已经两年没动过了:

Module 'intl' not installed
[root@frank]# docker image inspect wordpress:latest |grep -i version
                "PHP_VERSION=7.4.8",
                "WORDPRESS_VERSION=5.4.2",
        "DockerVersion": "18.09.7",
                "PHP_VERSION=7.4.8",
                "WORDPRESS_VERSION=5.4.2",

为了解决这个问题,需要移除这个Container,让其重新下载最新的image。因为我把Wordpress的文件都存在本地了,而不是在Docker内,所以这个过程不会造成任何影响,起来后直接使用:

[root@frank my_wordpress]# docker image rm wordpress
[root@frank my_wordpress]# docker-compose up -d
[root@frank my_wordpress]# docker image inspect wordpress:latest |grep -i version
                "PHP_VERSION=7.4.30",
        "DockerVersion": "20.10.12",
                "PHP_VERSION=7.4.30",

2022-09 确认上传图片告警问题

最近写Blog时发现图片无法上传,并报“Cannot read properties of undefined (reading ‘get’)”,当时就把我整蒙了……话说我没装太多插件呀,一通Google也没查出啥,都说冲突导致。我尝试把所有插件都关了,发现问题仍然存在……

因为这个告警不知所云,所以就用Chrome的开发者模式看看到底是啥情况,经过查看,发现在调用媒体上传api接口时,连接失败,如下:

根据这些告警查询,发现跟防火墙有关。。。难道被限制了?切换成自己的4G后,发现恢复了。。。?

2023-08 KVM CPU Peak

禁止xmlrpc.php

前段时间更新了Blog的架构,从Apacha 改到了Nginx,并通过Cloudflare证书给Blog开启了HTTPS,具体可以看这里:为Blog启用HTTPS;但过了一段时间后,发现网站反应有些慢,另外有一次还因为KVM CPU高导致停止服务……问题出现在8月份:

离我改变Blog架构过去了2个月,感觉跟架构没关系,估计是遇到了什么攻击或者搬瓦工的物理机有问题,所以确认了以下几点问题,并找到了RCA:

  • 开工单确认搬瓦工物理机是否有问题,答复没有发现问题;
  • 根据Nginx的访问记录,发现很多访问xmlrpc.php(比如19w的访问记录中9w是访问这个),这个是Wordpress提供的一个RPC接口,可以让用户通过远程调用wordpress发布文章,但现在用的少了(有些插件也会使用此接口),我通过Nginx把这种访问关闭了(更多信息可以参考这篇文章),然后CPU高的问题就解决了,具体信息可block步骤可以看下面;
  • 为了观察CPU历史利用率,我使用了sar,通过这个很方便的监控系统历史信息,这部分的使用方法已更新到了:Linux/Unix tips

下面是xmlrpc.php的访问记录:

[root@frank ~]# docker inspect 9525|grep LogPath
        "LogPath": "/var/lib/docker/containers/95258822aee1c85814c8fd0cd0da33d5992e6e4dd8dc9964b5255d02b8d959c8/95258822aee1c85814c8fd0cd0da33d5992e6e4dd8dc9964b5255d02b8d959c8-json.log",
[root@frank ~]#
[root@frank ~]#
[root@frank ~]# more /var/lib/docker/containers/95258822aee1c85814c8fd0cd0da33d5992e6e4dd8dc9964b5255d02b8d959c8/95258822aee1c85814c8fd0cd0da33d5992e6e4dd8dc9964b5255d02b8d959c8-json.log |grep xmlrpc
......
{"log":"172.70.90.12 - - [23/Jul/2023:11:18:07 +0000] \"POST /xmlrpc.php HTTP/1.1\" 301 169 \"-\" \"Apache-HttpClient/4.5.2 (Java/1.8.0_151)\" \"14.29.175.111\"\n","stream":"stdout","time":"2023-07-23T11:18:07.825208304Z"}
{"log":"172.70.90.12 - - [23/Jul/2023:11:18:08 +0000] \"POST /xmlrpc.php HTTP/1.1\" 301 169 \"-\" \"Apache-HttpClient/4.5.2 (Java/1.8.0_151)\" \"14.29.175.111\"\n","stream":"stdout","time":"2023-07-23T11:18:08.165354552Z"}
{"log":"172.70.90.12 - - [23/Jul/2023:11:18:08 +0000] \"POST /xmlrpc.php HTTP/1.1\" 301 169 \"-\" \"Apache-HttpClient/4.5.2 (Java/1.8.0_151)\" \"14.29.175.111\"\n","stream":"stdout","time":"2023-07-23T11:18:08.507107015Z"}

在Nginx的配置文件中Block对其的访问:

        location = /xmlrpc.php {
                deny all;
        }

不过这种方法只能限制Get访问,无法阻止POST请求,然后对xmlrpc的访问大多来自POST请求,因此经过查找,直接使用Cloudflare上的WAF限制所有访问xmlrpc的POST流量即可,下面是对应的WAF配置(详细可以参考这篇文章,这篇写得很不错,列出了POST请求的格式),点进去可以看到被drop的201个对应的POST请求:

关闭wp-cron

WordPress中的定时更新是通过网站访问来触发的,访问越多,定时请求就越多,就会导致wp-cron影响性能,如下:

[2023-09-06 20:39:50.334][root@xxxx~]# more /var/lib/docker/containers/71793f20807549fc228d1aa10236ab6fd976c81462f1baf221b40e26705dae0d/71793f20807549fc228d1aa10236ab6fd976c81462f1baf221b40e26705dae0d-json.log |grep wp-cron
[2023-09-06 20:39:53.767]{"log":"172.69.34.23 - - [06/Sep/2023:07:31:43 +0000] \"POST /wp-cron.php?doing_wp_cron=1693985502.8978710174560546875000 HTTP/2.0\" 200 0 \"-\" \"WordPress/6.3.1; https://www.zhaocs.info\" \"104.243.22.186\"\n","stream":"stdout","time":"2023-09-06T07:31:43.469696049Z"}
[2023-09-06 20:39:53.768]{"log":"162.158.91.44 - - [06/Sep/2023:07:33:06 +0000] \"POST /wp-cron.php?doing_wp_cron=1693985586.3080959320068359375000 HTTP/2.0\" 200 0 \"-\" \"WordPress/6.3.1; https://www.zhaocs.info\" \"104.243.22.186\"\n","stream":"stdout","time":"2023-09-06T07:33:06.534990307Z"}
[2023-09-06 20:39:53.789]{"log":"172.70.206.248 - - [06/Sep/2023:07:35:09 +0000] \"POST /wp-cron.php?doing_wp_cron=1693985709.4064030647277832031250 HTTP/2.0\" 200 0 \"-\" \"WordPress/6.3.1; https://www.zhaocs.info\" \"104.243.22.186\"\n","stream":"stdout","time":"2023-09-06T07:35:09.617742509Z"}
[2023-09-06 20:39:53.789]{"log":"172.70.207.86 - - [06/Sep/2023:07:40:39 +0000] \"POST /wp-cron.php?doing_wp_cron=1693986037.9497890472412109375000 HTTP/2.0\" 200 0 \"-\" \"WordPress/6.3.1; https://www.zhaocs.info\" \"104.243.22.186\"\n","stream":"stdout","time":"2023-09-06T07:40:39.414912266Z"}

详细方法可以访问Wordpress的官网:Hooking WP-Cron Into the System Task Scheduler

启用持久对象缓存Redis

部署Redis

每次请求都需要服务器对php进行解析,为了降低服务器的压力,使用redis来进行缓存解析后的页面,这样降低服务器压力,启用很简单,首先更新docker-compose.yml:

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

然后再设置wp-config.php

// 联接redis
define('WP_REDIS_HOST', 'redis');
define('WP_REDIS_PORT', '6379');

最后在Wordpress中安装redis插件,启用即可,我是用的是 Redis Object Cache

确认Redis使用状态

首先可以在访问网站时,可以通过查看源代码,看到最下面有相关cache的信息,如下:

<!--
Performance optimized by Redis Object Cache. Learn more: https://wprediscache.com

Retrieved 3501 objects (2 MB) from Redis using Predis (v2.1.2).
-->

其次可以登录到容器中,使用命令查阅状态,下面是常用的信息:

[root@frank ]# docker exec -it 1003 sh
/data # redis-cli info memory |grep -E "used_memory_human:|used_memory_rss_human|maxmemory_human"
used_memory_human:2.60M          #已使用内存大小
used_memory_rss_human:4.98M      #从系统角度看redis占用内存大小 
maxmemory_human:0B               #最大可使用的内存,默认0,代表没有限制
/data #
/data # redis-cli info stats |grep -E "total_connections_received|rejected_connections|instantaneous_ops_per_sec|keyspace_hits|keyspace_misses|expired_keys|evicted_keys"
total_connections_received:1108  #redis接受的链接数
instantaneous_ops_per_sec:0      #瞬时qps
rejected_connections:0           #拒绝链接数
expired_keys:61                  #过期数量
evicted_keys:0                   #删除数量
keyspace_hits:60653              #命中次数
keyspace_misses:13419            #未命中次数

增加安全插件?

只禁止xmlrpc后仍然会有CPU Peak,根据access log发现很多访问登录界面,所以尝试部署WAF来禁止非法登录,增加WP的安全性,本想单独部署开源WAF与Nginx配合,但看上去有些麻烦,所以只是找了一个可用的免费插件来实现WAF功能:Wordfence,免费版本可以提供基础防护。只是增加WAF后,虽然防护了很多非法登录,但仍然没有完全解决CPU Peak。。。由于最后通过iptables加强了防护(如最后部分),ssh密码也加强了,所以最后为了节省资源,还是删除了此安全插件。

限制Docker的CPU利用率

要想彻底解决问题,需要Narrow down问题,找到根因,再看如何处理。只是CPU Peak不是一直发生,所以尝试通过限制docker的CPU利用率来确认问题,如下:

   wordpress:
     depends_on:
       - db
     image: wordpress:6.2.1-php8.0-fpm
     deploy:
       resources:
         limits:
           cpus: '0.50'
     ports: 

先限制Wordpress的容器,0.5代表只能使用物理资源的50%,增加配置后,需要通过下面命令启动docker-compose才能激活配置:

docker-compose --compatibility up -d

可以通过下面命令查看容器的资源利用率:

[root@frank ~]# docker stats
CONTAINER ID        NAME                       CPU %               MEM USAGE / LIMIT     MEM %               NET I/O             BLOCK I/O           PIDS
10b2t584b303        my_wordpress_nginx_1       0.20%               3.453MiB / 503.9MiB   0.69%               54.1MB / 120MB      0B / 0B             2
62c94ay54872        my_wordpress_wordpress_1   42.96%              102.7MiB / 503.9MiB   20.39%              1.69GB / 163MB      0B / 0B             4
3a2a9jb8r7bx        my_wordpress_db_1          3.68%               120.6MiB / 503.9MiB   23.94%              123MB / 1.65GB      0B / 0B             32

增加安全策略

如何限制docker的流量,看上去是一个比较麻烦的问题。本想尝试使用firewall来限制,发现又跟docker冲突,具体原因可以通过”docker 和 iptables“关键字直接baidu或Google。网上的方法各种各样,充斥了很多不正确的信息,经过多次测试和查找后,通过下面的方法也无法达成我的需求,所以已经删除,最终的解决方法其实很简单,只要在docker建立时只export 443和80即可,其他container即使不export端口,其也会在container起来后使用internal 端口来进行通信,这样就可以达成只允许443和80对外访问

  • 只允许源地址为Cloudflare CDN的流量访问443和80端口;
  • 只允许访问宿主机的SSH端口;
  • 除了上面两个例外,Deny所有进来的流量;
[root@xxxxx ~]# iptables -D DOCKER-USER 1 #一定要删除RETRUN策略,这个屁用没有,还会导致docker端口泄露!
[root@xxxxx ~]# iptables -I DOCKER-USER -j DROP #必须在最后加这个策略,关闭docker非443和80的其他端口!
[root@xxxxx ~]# iptables -I DOCKER-USER  -s 0.0.0.0/0 -p tcp -m multiport --dport 80,443 -m comment --comment "drop all non-cloudflare 80 and 443 traffics" -j DROP
[root@xxxxx ~]# for i in `curl https://www.cloudflare.com/ips-v4`; do iptables -I DOCKER-USER -s $i -p tcp -m multiport --dport 80,443 -m comment --comment "allow cloudflare cnd address" -j ACCEPT; done
[root@xxxxx ~]# iptables -I DOCKER-USER -s 172.16.0.0/12 -p tcp -m state --state ESTABLISHED,RELATED -m comment --comment "allow traffics from local to internet" -j ACCEPT   #允许从本机发起的报文,related是自动识别回复报文并允许,这个可以让wordpress插件更新正常工作,注意172.16是docker网段
[root@xxxxx ~]# iptables -I DOCKER-USER -s <akismet's server address> -m comment --comment "allow akismet" -j ACCEPT
[root@xxxxx ~]# iptables -I DOCKER-USER -s 172.16.0.0/12 -p tcp -m multiport --dport 80,443 -m comment --comment "allow akismet from local to akismet" -j ACCEPT   #允许主机发起的80和443请求,这个可以让Akismet(172.18.0.5.54290 > api.akismet.com.https)正常工作,注意172.16是docker网段
[root@xxxxx ~]# iptables -I DOCKER-USER -s 172.16.0.0/12 -d 172.16.0.0/12 -m comment --comment "allow internal inter-communicate" -j ACCEPT
[root@xxxxx ~]# iptables -I INPUT -p tcp --dport <ssh port> -m comment --comment "allow ssh to server" -j ACCEPT
[root@xxxxx ~]# iptables -D INPUT 1  #如果IP变更,需要删掉对应变化的entry
[root@xxxxx ~]# iptables -A INPUT -s x.x.x.x/32 -p tcp -m tcp --dport <ssh port> -m comment --comment "allow ssh to server from home " -j ACCEPT  #插入变化IP后的entry
[root@xxxxx ~]# iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT #允许主机发起的请求数据
[root@xxxxx ~]# iptables -P INPUT DROP
[root@xxxxx ~]# iptables-save > wp-backup/iptables-20230912
[root@frank ~]# iptables -L -nv --line-number
Chain INPUT (policy DROP 39 packets, 1786 bytes)
num   pkts bytes target     prot opt in     out     source               destination         
1      245 17330 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:<ssh port> /* allow ssh to server */
2       76  7382 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            state RELATED,ESTABLISHED

Chain FORWARD (policy DROP 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination         
......        

Chain OUTPUT (policy ACCEPT 462 packets, 169K bytes)
num   pkts bytes target     prot opt in     out     source               destination         

Chain DOCKER (2 references)
num   pkts bytes target     prot opt in     out     source               destination         
......

Chain DOCKER-ISOLATION-STAGE-1 (1 references)
num   pkts bytes target     prot opt in     out     source               destination         
......

Chain DOCKER-ISOLATION-STAGE-2 (2 references)
num   pkts bytes target     prot opt in     out     source               destination         
......      

Chain DOCKER-USER (1 references)  #注意下面不需要加任何策略
num   pkts bytes target     prot opt in     out     source               destination         
1      711  586K ACCEPT     all  --  *      *       172.16.0.0/12        172.16.0.0/12        /* allow docker inter-communicate */
2        0     0 ACCEPT     all  --  *      *       195.234.111.252      0.0.0.0/0            /* allow akismet */
3        0     0 ACCEPT     all  --  *      *       195.234.111.251      0.0.0.0/0            /* allow akismet */
4       51 32821 ACCEPT     all  --  *      *       192.0.123.250        0.0.0.0/0            /* allow akismet */
5        0     0 ACCEPT     all  --  *      *       192.0.96.248         0.0.0.0/0            /* allow akismet */
6        0     0 ACCEPT     all  --  *      *       192.0.96.247         0.0.0.0/0            /* allow akismet */
7        0     0 ACCEPT     all  --  *      *       192.0.80.246         0.0.0.0/0            /* allow akismet */
8        0     0 ACCEPT     all  --  *      *       192.0.80.244         0.0.0.0/0            /* allow akismet */
9       69  7498 ACCEPT     tcp  --  *      *       172.16.0.0/12        0.0.0.0/0            multiport dports 80,443 /* allow akismet from local to akismet */
10      35 54660 ACCEPT     tcp  --  *      *       172.16.0.0/12        0.0.0.0/0            state RELATED,ESTABLISHED /* allow traffics from local to internet */
11       0     0 ACCEPT     tcp  --  *      *       131.0.72.0/22        0.0.0.0/0            multiport dports 80,443 /* allow cloudflare cnd address */
12      38  6154 ACCEPT     tcp  --  *      *       172.64.0.0/13        0.0.0.0/0            multiport dports 80,443 /* allow cloudflare cnd address */
13       0     0 ACCEPT     tcp  --  *      *       104.24.0.0/14        0.0.0.0/0            multiport dports 80,443 /* allow cloudflare cnd address */
14       0     0 ACCEPT     tcp  --  *      *       104.16.0.0/13        0.0.0.0/0            multiport dports 80,443 /* allow cloudflare cnd address */
15       0     0 ACCEPT     tcp  --  *      *       162.158.0.0/15       0.0.0.0/0            multiport dports 80,443 /* allow cloudflare cnd address */
16       0     0 ACCEPT     tcp  --  *      *       198.41.128.0/17      0.0.0.0/0            multiport dports 80,443 /* allow cloudflare cnd address */
17       0     0 ACCEPT     tcp  --  *      *       197.234.240.0/22     0.0.0.0/0            multiport dports 80,443 /* allow cloudflare cnd address */
18       0     0 ACCEPT     tcp  --  *      *       188.114.96.0/20      0.0.0.0/0            multiport dports 80,443 /* allow cloudflare cnd address */
19       0     0 ACCEPT     tcp  --  *      *       190.93.240.0/20      0.0.0.0/0            multiport dports 80,443 /* allow cloudflare cnd address */
20       0     0 ACCEPT     tcp  --  *      *       108.162.192.0/18     0.0.0.0/0            multiport dports 80,443 /* allow cloudflare cnd address */
21       0     0 ACCEPT     tcp  --  *      *       141.101.64.0/18      0.0.0.0/0            multiport dports 80,443 /* allow cloudflare cnd address */
22       0     0 ACCEPT     tcp  --  *      *       103.31.4.0/22        0.0.0.0/0            multiport dports 80,443 /* allow cloudflare cnd address */
23       0     0 ACCEPT     tcp  --  *      *       103.22.200.0/22      0.0.0.0/0            multiport dports 80,443 /* allow cloudflare cnd address */
24       0     0 ACCEPT     tcp  --  *      *       103.21.244.0/22      0.0.0.0/0            multiport dports 80,443 /* allow cloudflare cnd address */
25       0     0 ACCEPT     tcp  --  *      *       173.245.48.0/20      0.0.0.0/0            multiport dports 80,443 /* allow cloudflare cnd address */
26       1    40 DROP       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            multiport dports 80,443 /* drop all non-cloudflare 80 and 443 traffics */
27       7   380 DROP       all  --  *      *       0.0.0.0/0            0.0.0.0/0           
[root@frank-blog my_wordpress]# more docker-compose.yml 
......
   redis:
     image: redis:alpine
     restart: always
#     ports:
#       - '127.0.0.1:6379:6379'
     networks:
       - app-network

   wordpress:
     depends_on:
       - db
     image: wordpress:php8.2-fpm
#     deploy:
#       resources:
#         limits:
#           cpus: '0.50'
#     ports: 
#       - '127.0.0.1:9000:9000'

   nginx:
     depends_on:
       - wordpress
     image: nginx:stable
     volumes:
       - ./wordpress_data:/var/www/html
       - ./nginx-conf:/etc/nginx/conf.d
     restart: always
     ports:
       - 80:80
       - 443:443
     links:
......
[root@frank-blog my_wordpress]# docker ps -a
CONTAINER ID   IMAGE                  COMMAND                  CREATED       STATUS       PORTS                                                                      NAMES
111111111111   nginx:stable           "/docker-entrypoint.…"   2 weeks ago   Up 2 weeks   0.0.0.0:80->80/tcp, :::80->80/tcp, 0.0.0.0:443->443/tcp, :::443->443/tcp   my_wordpress-nginx-1
111111111112   wordpress:php8.2-fpm   "docker-entrypoint.s…"   2 weeks ago   Up 2 weeks   9000/tcp                                                                   my_wordpress-wordpress-1
111111111113   redis:alpine           "docker-entrypoint.s…"   2 weeks ago   Up 2 weeks   6379/tcp                                                                   my_wordpress-redis-1
111111111114   mysql:8.2.0            "docker-entrypoint.s…"   4 weeks ago   Up 4 weeks   3306/tcp, 33060/tcp                                                        my_wordpress-db-1

2023-11 Docker容器感染kdevtmpfsi

自从增加iptables防护后,KVM的CPU利用率恢复了一段时间,但最近1个月又开始高了,由于换了新工作,实在没时间搞,导致BLOG 无法访问近1个多月。。。因为没找到原因,导致重新部署wordpress仍然被攻击。。。所以断断续续搞了好久,才彻底解决, 最后发现还是iptables防护策略不完善导致的,原因可以看这个BLOG,博主解释的很清楚!最终策略增加了如上标红的最终直接关闭export端口,如上高亮显示的内容,下面简单记录下如何解决的步骤:

  • 通过top发现占用CPU高是“kdevtmpfsi”这个进程,而且是docker的33 user,直接关闭wordpress的docker;
  • 然后通过命令查找病毒文件,find / -name “*kdevtmpfsi*find / -name “*kinsing*” ,并删除这两个文件;
  • 增加iptables防护,限制SSH访问,更改强密码,具体看上面2023-08中标红的策略,在每增加之前,以及关闭container不需要expose的端口,这个很关键,所有docker expose的端口都被暴露在internet上,导致别人攻击了我的PHP 9000端口,设定堵死后,删除expose端口后就一劳永逸了,也不需要搞什么docker 和iptables兼容的问题了~

强烈建议部署完docker版本的wordpress后,找相关网站测试下端口,确认expose的端口是否被外部访问,正常对外应该只开443和80,其他docker暴露的应该都只作对内!

本文出自 Frank's Blog

版权声明:


本文链接:Revision Record
版权声明:本文为原创文章,仅代表个人观点,版权归 Frank Zhao 所有,转载时请注明本文出处及文章链接

留言哦

blonde teen swallows load.xxx videos