阿里云邮件推送的坑

国内的服务器一直在使用阿里云的,没有办法目前的情况下阿里云确实是国内的No.1

阿里云的ecs默认是关掉25端口的,就算是你申请解封25端口成功了,你也无法用25端口发信,他只允许你用25端口连接到其他的smtp服务器来发信.

使用阿里云的服务,自然而然的想到阿里云的邮件推送服务,而且他还赠送一部分免费的额度,对于我们这种只需要发送触发邮件的人来说,这是非常合适的.

但是这里的一个坑就是smtp协议下只支持25,80,465端口,而465端口一般用来支持STARTTLS, 这个协议比较老,国际标准化组织已经不再推荐,很多的程序例如iredmail默认已经不支持这个端口了。如果你使用的是debian,ubuntu的话,那么这是没有任何问题的,因为自带的postfix 的版本相对来说要新很多, 是3.0 的版本,支持465端口. 如果你使用的是centos7 并且使用的是自带的postfix的话,那么恭喜你,你获奖了。。。

centos7自带的postfix的版本相对来说要低很多,是2.10的版本。。。

而且postfix 的2.10的版本,对于465端口,也就是smtps并不是很支持,你需要使用的stunnel的转发smtps的请求. 详细请看这里:

http://www.postfix.org/TLS_README.html#client_smtps

网上铺天盖地的教程都是apt-get, 我想他们可以也没有想到在centos7 里面会出现问题,不值得花时间去演就演stunnel,那么多的提供标准服务的smtp服务商,舍弃阿里云推送就好了.

如果你的网站位于国外,那么你可以使用sendgrid或者mailgun,都是非常的方便

PHP7 兼容性检测

PHP 7 都出到7.4 了,是时候把手中的discuz论坛升级到PHP 7了,考虑了半天兼容性的问题,准备升级到php 7.3

discuz 的主程序已经升级到最新的discuz 20191201版本了,兼容PHP 7.3应该是没有问题,剩下的就是安装的那些插件的兼容性的问题.

检测PHP7 的兼容性,我们这里使用主流的PHPCompatibility 配合PHP Code_Sniffer

https://github.com/squizlabs/PHP_CodeSniffer
https://github.com/PHPCompatibility/PHPCompatibility

PHPCompatibility 是PHP Code_Sniffer 的插件,因此我们应该先安装PHP Code_Sniffer, 在github上有很多中的安装方式,这里我们选择最近的wget 或者curl下载二进制程序,然后把二进制程序放到全局去

# Download using curl
curl -OL https://squizlabs.github.io/PHP_CodeSniffer/phpcs.phar
curl -OL https://squizlabs.github.io/PHP_CodeSniffer/phpcbf.phar

# Or download using wget
wget https://squizlabs.github.io/PHP_CodeSniffer/phpcs.phar
wget https://squizlabs.github.io/PHP_CodeSniffer/phpcbf.phar

# register as global commands
mv phpcs.phar phpcs
mv phpcbf.phar phpcbf
chmod 755 phpcs
chmod 755 phpcbf
mv phpcs /usr/local/bin/
mv phpcbf /usr/local/bin/

这样就安装完了phpcs,下一步我们需要下载PHPCompatibility这个插件,并且让phpcs使用这个插件

# Download PHPCompability
cd ~
wget https://github.com/PHPCompatibility/PHPCompatibility/archive/9.3.5.zip
unzip 9.3.5.zip
# path is /root/PHPCompability9.3.5
# config phpcs to use PHPCompatibility
phpcs --config-set installed_paths /root/PHPCompability9.3.5

这样phpcs就可以使用PHPCompatibility9.3.5了,当然了也可以使用git的形式来下载,这样更新PHPCompatibility比较方便

加入说我们需要检查的文件folder 是/home/plugin, 那么我们就可以用

phpcs -p --standard=PHPCompatibility --runtime-set testVersion 7.3 --report-full=/home/php.log /home/plugin

-p: 打印progress到console上面

–standard: 表示使用哪个标准

–runtime-set testVersion 7.3 : 表示用PHP7.3的标准来检查

–report-full: 表示将结果输出到某一文件

 

检查完毕,删掉了不兼容php7.3 的插件,然后就开始准备升级discuz到7.3了

AWS Lightsail Singapore Benchmark

AWS对于IO的限制,配置越高,限制越少,这里我们benchmark 一下80刀的这一款,4 cores,16GB RAM, 320GB SSD

测试使用的程序:

wget -qO- bench.sh | bash

下面是结果:

----------------------------------------------------------------------
CPU model : Intel(R) Xeon(R) CPU E5-2676 v3 @ 2.40GHz
Number of cores : 4
CPU frequency : 2399.858 MHz
Total size of Disk : 320.0 GB (1.1 GB Used)
Total amount of Mem : 15883 MB (171 MB Used)
Total amount of Swap : 0 MB (0 MB Used)
System uptime : 0 days, 0 hour 9 min
Load average : 0.15, 0.15, 0.09
OS : CentOS 7.6.1810
Arch : x86_64 (64 Bit)
Kernel : 3.10.0-957.1.3.el7.x86_64
----------------------------------------------------------------------
I/O speed(1st run) : 134 MB/s
I/O speed(2nd run) : 130 MB/s
I/O speed(3rd run) : 130 MB/s
Average I/O speed : 131.3 MB/s
----------------------------------------------------------------------

测试了几次,基本都是这个IO速度

 

PHP SimpleXMLElement 对象

今天在用RedbeanPHP 写数据库接口的时候,发现从SimpleXMLElement对象里面出来的值,按理说都是string, 怎么也不能赋值给RedbeanPHP, 用var_dump看了一下,发现SimpleXMLElement对象比较有意思,里面嵌套的对象以及property 的type 都是object,而且都是SimpleXMLElement 对象,在google上搜了一下发现问这个问题的不少。

https://stackoverflow.com/questions/416548/forcing-a-simplexml-object-to-a-string-regardless-of-context

比如说XML是这样的:

<channel>
<item>
<title>This is title 1</title>
</item>
</channel>

下面这样确实能够输出string:

$xml = simplexml_load_string($xmlstring);
echo $xml->channel->item->title;

但是除了echo 以外,下面这样就不能被当成string了

$foo = array( $xml->channel->item->title );

这是因为$XML->channel->item->title 的type 其实仍然为SimpleXMLElement的对象

我们可以用typecast来解决这个问题:

$foo = array( (string) $xml->channel->item->title );

The above code internally calls __toString() on the SimpleXMLObject. This method is not publicly available, as it interferes with the mapping scheme of the SimpleXMLObject, but it can still be invoked in the above manner.

另外看到有人这么写也可以:

$foo = array( $xml->channel->item->title.'' );

通过gettype查看确实变成了string,具体原理不知道

利用AWK来分析nginx日志

分析nginx日志有各种各样的可视化工具,但是这样比较繁琐,需要安装和配置,大部分的时候我们只需要简单的分析,这里awk 完全可以满足我们的需求。

  1. 统计日志中访问最多的10个ip

 方法一

awk '{a[$1]++}END{for(i in a)print a[i],i|"sort -k1 -nr|head -n10"}' access.log

方法二

awk '{print $1}' access.log |sort |uniq -c |sort -k1 -nr |head -n10

 

2. 统计日志中访问大于100次的IP

方法一

awk '{a[$1]++}END{for(i in a){if(a[i]>100)print i,a[i]}}' access.log

方法二

awk '{a[$1]++;if(a[$1]>100){b[$1]++}}END{for(i in b){print i,a[i]}}' access.log

3. 统计2019年12月24日一天内访问最多的10个IP

方法一

awk '$4>="[24/Dec/2019:00:00:01" && $4<="[24/Dec/2019:23:59:59" {a[$1]++}END{for(i in a)print a[i],i|"sort -k1 -nr|head -n10"}' access.log

方法二

sed -n '/\[24\/Dec\/2019:00:00:01/,/\[24\/Dec\/2019:23:59:59/p' access.log |sort |uniq -c |sort -k1 -nr |head -n10

4. 统计访问最多的前10个页面 ($request)

awk '{a[$7]++}END{for(i in a)print a[i],i|"sort -k1 -nr|head -n10"}' access.log

5. 统计蜘蛛抓取次数

grep 'Baiduspider' access.log |wc -l

统计蜘蛛抓取404的次数

grep 'Baiduspider' access.log |grep '404' | wc -l

 

 

Cloudflare 配合nginx 来禁止某些国家, user agent 的访问

其实目前cloudflare 的免费版已经在control panel 里面可以完美的实现这些功能,但是cloudflare 能做到的只是禁止某些国家或者user agent 的访问,如果我们想更好的优化这些流量,比如说对不同的geo跳转到不同的网站,或者对于某些蜘蛛来说显示不同的网站,那么就需要nginx 的配合了, 在这里我们主要利用的是nginx 的map 这个功能.

对于geo 的控制

如果你的网站在cloudflare 的保护下,那么cloudflare 默认会在header里面加上’HTTP_CF_IPCOUNTRY’, 这就相当于cloudflare 提供了免费的IP数据库,利用nginx 的map 功能,比如说禁止来自US, CA, UK, AU的流量, 那就就可以按照如下配置:

在nginx 的全局中

map $http_cf_ipcountry $allow {
default yes;
US no;
CA no;
UK no;
AU no;
}

在server中

if ($allow = no) {
return 403;
}

在这里需要注意的是,按照nginx 的官方文档,map 只能位于http block里面,return 就比较自由了,可以在server,location block里面

深入一点,return的可以不仅仅是403,还可以是301, 302等等,比如说把US,CA,UK和 AU 的流量跳转到google,可以这么配置:

if ($allow = no) {
return 301 https://www.google.com;
}

在更加深入一点,活用map功能,我们可以不仅仅是map GEO,还可以map user agent等等,这里就需要正则的配合了.

Centos 7 编译安装nginx

基本说明见这里: https://www.iamhippo.com/2019-12/1167.html

1) update system and install building software

yum clean all
yum update -y

disable selinux

vi /etc/selinux/config
reboot
yum groupinstall -y 'Development Tools'

2) add nginx username and group, identical to the one nginx offical repo creates:

useradd --system --home /var/cache/nginx --shell /sbin/nologin --comment "nginx user" --user-group nginx

 check user and group created

3) download nginx dependencies source code

cd ~
wget https://ftp.pcre.org/pub/pcre/pcre-8.43.tar.gz && tar xzvf pcre-8.43.tar.gz
wget https://www.zlib.net/zlib-1.2.11.tar.gz && tar xzvf zlib-1.2.11.tar.gz
wget http://www.openssl.org/source/openssl-1.1.1d.tar.gz && tar xzvf openssl-1.1.1d.tar.gz
wget https://nginx.org/download/nginx-1.16.1.tar.gz && tar zxvf nginx-1.16.1.tar.gz
cd nginx-1.16.1
./configure --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-pcre=../pcre-8.43 --with-pcre-jit --with-zlib=../zlib-1.2.11 --with-openssl=../openssl-1.1.1d --with-openssl-opt=no-nextprotoneg --with-debug
make
make install

# go to home

cd ~

# symlink /usr/lib64/nginx/modules to /etc/nginx/modules

ln -s /usr/lib64/nginx/modules /etc/nginx/modules
mkdir /var/cache/nginx -p
mkdir /etc/nginx/vhost -p
vi /usr/lib/systemd/system/nginx.service
[Unit]
Description=nginx - high performance web server
Documentation=http://nginx.org/en/docs/
After=network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target

[Service]
Type=forking
PIDFile=/var/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t -c /etc/nginx/nginx.conf
ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID

[Install]
WantedBy=multi-user.target

reload systemd daemon

systemctl daemon-reload

start service and auto boot

systemctl start nginx
systemctl enable nginx

check if nginx startup on reboot

systemctl is-enabled nginx.service

check if nginx is running

systemctl status nginx

Nginx config

对于在centos 7, debian 9/10 上自己编译的nginx来说,默认的nginx 配置有点弱,于是根据军哥的LNMP的配置,我做了一些修改. 以后凡是自己按照nginx官方repo 的configure编译的nginx,都可以使用如下的nginx.conf,需要在nginx.conf 所在的目录设置一个vhost目录, 所有的individual host 的配置,都放在vhost里面,方便管理. 

user  nginx nginx;

worker_processes auto;
worker_cpu_affinity auto;

error_log  /var/log/nginx/error.log  crit;

pid        /var/run/nginx.pid;

#Specifies the value for maximum file descriptors that can be opened by this process.
worker_rlimit_nofile 51200;

events
    {
        use epoll;
        worker_connections 51200;
        multi_accept off;
        accept_mutex off;
    }

http
    {
        include       mime.types;
        default_type  application/octet-stream;

        server_names_hash_bucket_size 128;
        client_header_buffer_size 32k;
        large_client_header_buffers 4 32k;
        client_max_body_size 50m;
		
        proxy_buffer_size 128k;
        proxy_buffers 4 256k;
        proxy_busy_buffers_size 256k;

        sendfile on;
        sendfile_max_chunk 512k;
        tcp_nopush on;

        keepalive_timeout 60;

        tcp_nodelay on;

        fastcgi_connect_timeout 300;
        fastcgi_send_timeout 300;
        fastcgi_read_timeout 300;
        fastcgi_buffer_size 64k;
        fastcgi_buffers 4 64k;
        fastcgi_busy_buffers_size 128k;
        fastcgi_temp_file_write_size 256k;

        gzip on;
        gzip_min_length  1k;
        gzip_buffers     4 16k;
        gzip_http_version 1.1;
        gzip_comp_level 2;
        gzip_types     text/plain application/javascript application/x-javascript text/javascript text/css application/xml application/xml+rss;
        gzip_vary on;
        gzip_proxied   expired no-cache no-store private auth;
        gzip_disable   "MSIE [1-6]\.";

        #limit_conn_zone $binary_remote_addr zone=perip:10m;
        ##If enable limit_conn_zone,add "limit_conn perip 10;" to server section.

        server_tokens off;
        access_log off;

server
    {
        listen 80 default_server;
        #listen [::]:80 default_server ipv6only=on;
        server_name _;
        index index.html index.htm;
        root  html;

        #error_page   404   /404.html;

        # Deny access to PHP files in specific directory
        #location ~ /(wp-content|uploads|wp-includes|images)/.*\.php$ { deny all; }

        #include enable-php.conf;

        location /nginx_status
        {
            stub_status on;
            access_log   off;
        }

        location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
        {
            expires      30d;
        }

        location ~ .*\.(js|css)?$
        {
            expires      12h;
        }

        location ~ /.well-known {
            allow all;
        }

        location ~ /\.
        {
            deny all;
        }

#       access_log  /home/wwwlogs/access.log;
    }
include vhost/*.conf;
}

Debian 9/10 编译安装nginx

Debian 9, Debian 10 都适用于此教程.

实际上,Nginx 的官方repo编译的nginx,已经把能加上的module全部都加上了,因此在一般情况下,建议使用nginx的官方repo来安装nginx. 但是如果说你想添加第三方的module,或者使用最新的openssl 的话,在或者更改一下nginx 的安装路径的话,就需要自己编译了. 此篇教程尽量按照nginx官方repo的configure来编译安装openssl.

在一台全新安装的Debian 9或者Debian 10上:

更多