运维技术

pm2搭建node生产环境 Linux & FreeBSD

CentOS 下的pm2布署

检查npm版本,最小版本v6.1.0

$ npm -v
v5.6.0

如果npm版本小于v.6.1.0 在线升级 npm

$ npm i -g npm

1. 安装pm2 (-g 全局安装)

npm install -g pm2

然后进入到你的node项目布署目录下:

pm2 start index.js --name 'test'# index.js

上面是项目的运行脚本

scort@scort-Lenovo-IdeaPad-U310:~/websocket$ pm2 start index.js --name 'test'
[PM2] Starting /home/scort/websocket/index.js in fork_mode (1 instance)
[PM2] Done.
┌───────┬──────┬─────────┬───┬─────┬───────────┐
│ Name  │ mode │ status  │ ↺ │ cpu │ memory    │
├───────┼──────┼─────────┼───┼─────┼───────────┤
│ test  │ fork │ online  │ 0 │ 0%  │ 19.4 MB   │
└───────┴──────┴─────────┴───┴─────┴───────────┘
 Use `pm2 show <id|name>` to get more details about an app

2. 把pm2加入系统启动中

pm2的启动脚本

vi /usr/lib/systemd/system/pm2-root.service

[Unit]
Description=PM2 process manager
Documentation=https://pm2.keymetrics.io/
After=network.target

[Service]
Type=forking
User=root
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
Environment=PATH=/usr/bin:/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
Environment=PM2_HOME=/root/.pm2
PIDFile=/root/.pm2/pm2.pid

ExecStart=/usr/lib/node_modules/pm2/bin/pm2 resurrect
ExecReload=/usr/lib/node_modules/pm2/bin/pm2 reload all
ExecStop=/usr/lib/node_modules/pm2/bin/pm2 kill

[Install]
WantedBy=multi-user.target

设置为开机启动

systemctl enable pm2-root

保存 pm2 的当前运行环境

$ pm2 save

[PM2] Saving current process list...
[PM2] Successfully saved in /root/.pm2/dump.pm2

然后 reboot 重启系统

 

执行 pm2-root 的命令 

systemctl start pm2-root #启动pm2
systemctl restart pm2-root #重启pm2
systemctl enable pm2-root #停止pm2

 

FreeBSD 下的布署

1、BSD下环境安装,采用 ports 安装 

cd /usr/ports/www/node && make install clean
cd /usr/ports/www/npm && make install clean

2、全局安装PM2 

npm install -g pm2

3、布置应用环境,如上CENTOS相同

先在布署目录下执行  pm2 start index.js --name 'test'# index.js

再保存pm2的运行状态 pm2 save

4、设置PM2随系统自动启动
pm2 的执行脚本,放到 /usr/local/etc/rc.d/ 目录下。

vi /usr/local/etc/rc.d/pm2

#!/bin/sh

# PM2 Startup script
#
# Make the file executable with:
# /usr/local/etc/rc.d/pm2 (chmod +x)
#
# add to /etc/rc.conf
#
# pm2_enable="YES"
# pm2_user="root"

# PROVIDE: pm2
# REQUIRE: NETWORK mongod
# KEYWORD: shutdown
#
 
. /etc/rc.subr
 
name=pm2
rcvar=pm2_enable
 
PM2=/usr/local/lib/node_modules/pm2/bin/pm2
 
load_rc_config $name
 
start_cmd="pm2_start"
stop_cmd="pm2_stop"
restart_cmd="pm2_restart"
reload_cmd="pm2_reload"

: ${pm2_user="freebsd"}
: ${pm2_enable="NO"}
 
pm2_start()
{
        CMD="${PM2} resurrect"
        su -l ${pm2_user} -c "${CMD}"
 
}
 
pm2_stop()
{
        CMD="${PM2} kill"
        su -l ${pm2_user} -c "${CMD}"
}
 
pm2_restart()
{
        pm2_stop
        pm2_start
}
 
pm2_reload()
{
        CMD="${PM2} reload all"
        su -l ${pm2_user} -c "${CMD}"
}
 
run_rc_command "$1"

/etc/rc.conf 下面增加如下启动命令

pm2_enable="YES"
pm2_user="root"

然后 reboot 重启你的系统  进入系统执行

# pm2 list                                                              
┌────────────┬────┬─────────┬──────┬─────┬────────┬─────────┬────────┬───────┬────────────┬──────┬──────────┐
│ App name   │ id │ version │ mode │ pid │ status │ restart │ uptime │ cpu   │ mem        │ user │ watching │
├────────────┼────┼─────────┼──────┼─────┼────────┼─────────┼────────┼───────┼────────────┼──────┼──────────┤
│ test       │ 0  │ 0.0.0   │ fork │ 821 │ online │ 0       │ 4D     │ 25.9% │ 115.1 MB   │ root │ enabled  │
└────────────┴────┴─────────┴──────┴─────┴────────┴─────────┴────────┴───────┴────────────┴──────┴──────────┘
 Use `pm2 show <id|name>` to get more details about an app

你会发现 布署的应用已经自动启动了。

BSD 程序管理命令

/usr/local/etc/rc.d/pm2 start
/usr/local/etc/rc.d/pm2 restart
/usr/local/etc/rc.d/pm2 stop

Tomcat日志catalina.out自动分割(linux)

默认情况下,tomcat的catalina.out日志文件是没有像其它日志一样,按日期进行分割,而是全部输出全部写入到一个catalina.out,这样日积月累就会造成.out日志越来越大,给管理造成了不便,为了实现像其它日志文件一样按日期归档,这里我们采用cronolog来完成日志分割。

一、安装cronolog

yum 安装
使用cronolog包实现按日期分割catalina.out日志文件

yum install cronolog

或是 源码安装

1、下载(最新版本)

wget http://cronolog.org/download/cronolog-1.6.2.tar.gz

2、解压缩

tar zxvf cronolog-1.6.2.tar.gz

3、进入cronolog安装文件所在目录

cd cronolog-1.6.2

4、运行安装

./configure
make
make install

5、查看cronolog安装后所在目录(验证安装是否成功)

which cronolog
/usr/sbin/cronolog


二、修改bin/catalina.sh文件。

具体如下:

shift
  touch "$CATALINA_OUT"
  if [ "$1" = "-security" ] ; then
    if [ $have_tty -eq 1 ]; then
      echo "Using Security Manager"
    fi
    shift
    eval $_NOHUP "\"$_RUNJAVA\"" "\"$LOGGING_CONFIG\"" $LOGGING_MANAGER $JAVA_OPTS $CATALINA_OPTS \
      -D$ENDORSED_PROP="\"$JAVA_ENDORSED_DIRS\"" \
      -classpath "\"$CLASSPATH\"" \
      -Djava.security.manager \
      -Djava.security.policy=="\"$CATALINA_BASE/conf/catalina.policy\"" \
      -Dcatalina.base="\"$CATALINA_BASE\"" \
      -Dcatalina.home="\"$CATALINA_HOME\"" \
      -Djava.io.tmpdir="\"$CATALINA_TMPDIR\"" \
      org.apache.catalina.startup.Bootstrap "$@" start \
      >> "$CATALINA_OUT" 2>&1 "&"
  else
    eval $_NOHUP "\"$_RUNJAVA\"" "\"$LOGGING_CONFIG\"" $LOGGING_MANAGER $JAVA_OPTS $CATALINA_OPTS \
      -D$ENDORSED_PROP="\"$JAVA_ENDORSED_DIRS\"" \
      -classpath "\"$CLASSPATH\"" \
      -Dcatalina.base="\"$CATALINA_BASE\"" \
      -Dcatalina.home="\"$CATALINA_HOME\"" \
      -Djava.io.tmpdir="\"$CATALINA_TMPDIR\"" \
      org.apache.catalina.startup.Bootstrap "$@" start \
      >> "$CATALINA_OUT" 2>&1 "&"
  fi

改为:

shift

  #touch "$CATALINA_OUT"
  if [ "$1" = "-security" ] ; then
    if [ $have_tty -eq 1 ]; then
      echo "Using Security Manager"
    fi
    shift
    eval $_NOHUP "\"$_RUNJAVA\"" "\"$LOGGING_CONFIG\"" $LOGGING_MANAGER $JAVA_OPTS $CATALINA_OPTS \
      -D$ENDORSED_PROP="\"$JAVA_ENDORSED_DIRS\"" \
      -classpath "\"$CLASSPATH\"" \
      -Djava.security.manager \
      -Djava.security.policy=="\"$CATALINA_BASE/conf/catalina.policy\"" \
      -Dcatalina.base="\"$CATALINA_BASE\"" \
      -Dcatalina.home="\"$CATALINA_HOME\"" \
      -Djava.io.tmpdir="\"$CATALINA_TMPDIR\"" \
      org.apache.catalina.startup.Bootstrap "$@" start 2>&1 | /usr/sbin/cronolog "$CATALINA_BASE"/logs/catalina.%Y-%m-%d.out >> /dev/null &
  else
      eval $_NOHUP "\"$_RUNJAVA\"" "\"$LOGGING_CONFIG\"" $LOGGING_MANAGER $JAVA_OPTS $CATALINA_OPTS \      -D$ENDORSED_PROP="\"$JAVA_ENDORSED_DIRS\"" \
      -classpath "\"$CLASSPATH\"" \
      -Dcatalina.base="\"$CATALINA_BASE\"" \
      -Dcatalina.home="\"$CATALINA_HOME\"" \
      -Djava.io.tmpdir="\"$CATALINA_TMPDIR\"" \
      org.apache.catalina.startup.Bootstrap "$@" start 2>&1 | /usr/sbin/cronolog "$CATALINA_BASE"/logs/catalina.%Y-%m-%d.out >> /dev/null &
  fi

修改后,重启 Tomcat

systemctl restart tomcat

然后查看一下 catalina.out 将会自动生成 catalina.2019-03-26.out

[root@Temp logs]# ls -l
总用量 796
-rw-r----- 1 root root 355008 3月  26 00:32 catalina.2019-03-26.log
-rw-r----- 1 root root 453507 3月  26 00:32 catalina.2019-03-26.out
-rw-r----- 1 root root      0 3月  26 00:35 host-manager.2019-03-26.log
-rw-r----- 1 root root    562 3月  26 00:31 localhost.2019-03-26.log
-rw-r----- 1 root root      0 3月  26 00:31 localhost_access_log.2019-03-26.txt
-rw-r----- 1 root root      0 3月  26 00:35 manager.2019-03-26.log


下面我们要做的是定期清理这些过期的文件,我们可以通过crontab来实现
crontab -e

30 3 * * * /bin/find /usr/local/tomcat/logs/ -mtime +7 -type f -name "catalina.*.out" -exec /bin/rm -f {} \;

每天凌晨3点半执行清除7天之前过期日志

 

 

CentOS 7.x 下 JDK 1.8 & Tomcat 9(APR)打造高性能服务

一、编译安装Apr Tomcat

       Tomcat可以使用Apache Portable Runtime来提供卓越的性能及可扩展性,更好地与本地服务器技术的集成。
Apache Portable Runtime是一个高度可移植的库,位于Apache HTTP Server 2.x的核心。
APR有许多用途,包括访问高级IO功能(如sendfile,epoll和OpenSSL),操作系统级功能
(随机数生成,系统状态等)以及本地进程处理(共享内存,NT管道和Unix套接字)。
这些功能不仅仅是一个后端集中的技术,还可以让Tomcat成为通用的网络服务器,可以实现与本地
的其他Web技术更好的集成,并使Java成为一个完整的网络服务器平台。

官方APR要求:

所需基础组件及版本


生产环境情况:

操作系统及基础组件版本

安装所需组件及编译:

通过 yum 安装基础组件

yum -y install apr-devel openssl-devel gcc make expat-devel libtool gcc-c++ libtool* wget

下载源码编译安装arp -> Tomcat

cd /usr/local/src
wget http://tools.itsns.net.cn/tools/apache/apr-1.6.5.tar.gz
wget http://tools.itsns.net.cn/tools/apache/apr-iconv-1.2.2.tar.gz
wget http://tools.itsns.net.cn/tools/apache/apr-util-1.6.1.tar.gz
wget http://tools.itsns.net.cn/tools/apache/apache-tomcat-9.0.17.tar.gz
wget http://tools.itsns.net.cn/tools/apache/jdk-8u202-linux-x64.tar.gz
cd /usr/local/src && tar xf jdk-8u202-linux-x64.tar.gz && mv jdk1.8.0_202/ ../java
cd /usr/local/src && tar xf apache-tomcat-9.0.17.tar.gz && mv apache-tomcat-9.0.17/ ../tomcat

cd /usr/local/src && tar xf apr-1.6.5.tar.gz && cd apr-1.6.5/
./configure --prefix=/usr/local/apr
make && make install

# ↑ 注意:如果报错,请查找 configure 里的 RM='$RM' 改为 RM='$RM  -f'

cd /usr/local/src && tar xf apr-iconv-1.2.2.tar.gz && cd apr-iconv-1.2.2/
./configure   --with-apr=/usr/local/apr  --prefix=/usr/local/apr-iconv
make && make install

cd /usr/local/src && tar xf apr-util-1.6.1.tar.gz && cd apr-util-1.6.1/
./configure --prefix=/usr/local/apr-util --with-apr=/usr/local/apr --with-apr-iconv=/usr/local/apr-iconv/bin/apriconv
make && make install

cd /usr/local/tomcat/bin/ && tar xf tomcat-native.tar.gz && cd  tomcat-native-1.2.21-src/native
./configure --with-apr=/usr/local/apr  --with-java-home=/usr/local/java
make && make install

Tomcat 安装为 CentOS 系统服务:


所有的配置文件均放在启动服务配置内,如果你需要跑多个独立的Tomcat 这是最好的选择。
注意:JAVA_OPTS=-..... 此处配置以4G内存为例优化。

vi /usr/lib/systemd/system/tomcat.service

[Unit]
Description=Tomcat 9 servlet container
After=network.target

[Service]
Type=forking

Environment="JAVA_HOME=/usr/local/java"
Environment="JRE_HOME=/usr/local/java/jre"
Environment="CATALINA_HOME=/usr/local/tomcat"
Environment="CATALINA_BASE=/usr/local/tomcat"
Environment="CATALINA_PID=/usr/local/tomcat/temp/tomcat.pid"
Environment="JAVA_OPTS=-server -Xms1024M -Xmx1024M -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:-UseCompressedClassPointers -XX:MetaspaceSize=50M -XX:MaxMetaspaceSize=500m -XX:MinMetaspaceExpansion=50M -XX:MaxMetaspaceExpansion=50M -Xloggc:/var/log/tomcat_gc.log"
Environment="LD_LIBRARY_PATH=/usr/local/apr/lib"
Environment="LD_RUN_PATH=/usr/local/apr/lib"
ExecStart=/usr/local/tomcat/bin/catalina.sh start
ExecStop=/usr/local/tomcat/bin/catalina.sh stop

Restart=always

[Install]
WantedBy=multi-user.target

chmod +x /usr/lib/systemd/system/tomcat.service

重载系统服务
sudo systemctl daemon-reload

加入系统服务
sudo systemctl enable tomcat.service

启动Tomcat
sudo systemctl start tomcat.service

停止Tomcat
sudo systemctl stop tomcat.service

重启Tomcat
sudo systemctl restart tomcat.service

删除Tomcat 服务
sudo systemctl disable tomcat.service


二、优化配置及TomCat 安全设置


优化好的配置直接覆盖原有配置就可以了
wget http://tools.itsns.net.cn/tools/apache/server.xml


手动优化配置如下:

设置为Tomcat 9 Apr 模式


# vi /usr/local/tomcat/conf/server.xml

默认值:

<Connector port="8080" protocol="HTTP/1.1"connectionTimeout="20000"redirectPort="8443" />

修改为:

<Connector port="8080" protocol="org.apache.coyote.http11.Http11AprProtocol"connectionTimeout="20000"redirectPort="8443" />

默认值:

<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
修改为:<Connector port="8009" protocol="org.apache.coyote.ajp.AjpAprProtocol" redirectPort="8443" />

现在重启tomcat服务,并查看启动日志
# systemctl restart tomcat
# cat /usr/local/tomcat/logs/catalina.out

...
INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib]
INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["http-nio-8080"]
INFO [main] org.apache.tomcat.util.net.NioSelectorPool.getSharedSelector Using a shared selector for servlet write/read
INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["ajp-nio-8009"]
INFO [main] org.apache.tomcat.util.net.NioSelectorPool.getSharedSelector Using a shared selector for servlet write/read
...

注意:如果遇到上面的提示找不到基于APR的Apache Tomcat Native库,因此无法使用APR模式启动。
解决方案:
# cp -R /usr/local/apr/lib/* /usr/lib64
# cp -R /usr/local/apr/lib/* /usr/lib

再次重启tomcat,并查看启动日志

# cat /usr/local/tomcat/logs/catalina.out

...
INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-apr-8080"]
INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-apr-8009"]
...

可以看到已经以apr协议模式启动成功,经基于APR的技术web压力测试,Tomcat的性能飙升。

优化连接数,线程数,缓存

修改 server.xml

maxThreads 连接数限制修改配置

<!--<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"maxThreads="150" minSpareThreads="4"/>—>

# 修改为

<Executorname="tomcatThreadPool"namePrefix="catalina-exec-"maxThreads="500"minSpareThreads="30"maxIdleTime="60000"prestartminSpareThreads = "true"maxQueueSize = "100"/>

参数解释:
maxThreads:最大并发数,默认设置 200,一般建议在 500 ~ 800,根据硬件设施和业务来判断
minSpareThreads:Tomcat 初始化时创建的线程数,默认设置 25
maxIdleTime:如果当前线程大于初始化线程,那空闲线程存活的时间,单位毫秒,默认60000=60秒=1分钟。
prestartminSpareThreads:在 Tomcat 初始化的时候就初始化 minSpareThreads 的参数值,如果不等于 true,minSpareThreads 的值就没啥效果了
maxQueueSize:最大的等待队列数,超过则拒绝请求

Connector 参数优化配置
<Connectorport="8080"protocol="org.apache.coyote.http11.Http11AprProtocol"connectionTimeout="20000"redirectPort="8443"/>

# 修改为

<Connector
executor="tomcatThreadPool"
port="8080"
protocol="org.apache.coyote.http11.Http11AprProtocol"
connectionTimeout="60000"
maxConnections="10000"
redirectPort="8443"
enableLookups="false"
acceptCount="100"
maxPostSize="10485760"
maxHttpHeaderSize="8192"
compression="on"
disableUploadTimeout="true"
compressionMinSize="2048"
acceptorThreadCount="2"
compressibleMimeType="text/html,text/plain,text/css,application/javascript,application/json,application/x-font-ttf,application/x-font-otf,image/svg+xml,image/jpeg,image/png,image/gif,audio/mpeg,video/mp4"
URIEncoding="utf-8"
processorCache="20000"
tcpNoDelay="true"
connectionLinger="5"
server="Server Version 11.0"
/>

参数解释:
protocol:Tomcat 7 设置 nio2 更好:org.apache.coyote.http11.Http11Nio2Protocol
protocol:Tomcat 6 设置 nio 更好:org.apache.coyote.http11.Http11NioProtocol
protocol:Tomcat 8 设置 APR 性能飞快:org.apache.coyote.http11.Http11AprProtocol 具体配置 : <CentOS 7 Tomcat 8.5 基于APR库性能优化>
connectionTimeout:Connector接受一个连接后等待的时间(milliseconds),默认值是60000。
maxConnections:这个值表示最多可以有多少个socket连接到tomcat上
enableLookups:禁用DNS查询
acceptCount:当tomcat起动的线程数达到最大时,接受排队的请求个数,默认值为100。
maxPostSize:设置由容器解析的URL参数的最大长度,-1(小于0)为禁用这个属性,默认为2097152(2M) 请注意, FailedRequestFilter 过滤器可以用来拒绝达到了极限值的请求。
maxHttpHeaderSize:http请求头信息的最大程度,超过此长度的部分不予处理。一般8K。
compression:是否启用GZIP压缩 on为启用(文本数据压缩) off为不启用, force 压缩所有数据
disableUploadTimeout:这个标志允许servlet容器使用一个不同的,通常长在数据上传连接超时。 如果不指定,这个属性被设置为true,表示禁用该时间超时。
compressionMinSize:当超过最小数据大小才进行压缩
acceptorThreadCount:用于接受连接的线程数量。增加这个值在多CPU的机器上,尽管你永远不会真正需要超过2。 也有很多非维持连接,您可能希望增加这个值。默认值是1。
compressableMimeType:配置想压缩的数据类型
URIEncoding:网站一般采用UTF-8作为默认编码。
processorCache:协议处理器缓存的处理器对象来提高性能。 该设置决定多少这些对象的缓存。-1意味着无限的,默认是200。 如果不使用Servlet 3.0异步处理,默认是使用一样的maxThreads设置。 如果使用Servlet 3.0异步处理,默认是使用大maxThreads和预期的并发请求的最大数量(同步和异步)。
tcpNoDelay:如果设置为true,TCP_NO_DELAY选项将被设置在服务器套接字,而在大多数情况下提高性能。这是默认设置为true。
connectionLinger:秒数在这个连接器将持续使用的套接字时关闭。默认值是 -1,禁用socket 延迟时间。

安全相关配置

vi /usr/local/tomcat/conf/server.xml

禁用8005端口 避免 telnet localhost 8005  然后输入 SHUTDOWN 就可以关闭 Tomcat。

为了安全我们要禁用该功能

<Server port="8005" shutdown="SHUTDOWN">
# 修改为
<Server port="-1" shutdown="SHUTDOWN">


应用程序安全&关闭自动部署

<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">

# 修改为

<Host name="localhost" appBase="webapps" unpackWARs="false" autoDeploy="false" reloadable="false">

日志相关说明:在启动文件里,启用了gc.log :Environment=“….. -Xloggc:/var/log/tomcat_gc.log ….."
/var/log/tomcat_gc.log
/usr/local/tomcat/logs/catalina.out

Tomcat的默认工具manager配置

        Tomcat的默认工具manager配置,在很多的生产环境中由于基本用不到、或者是不太需要使用Tomcat默认的manager管理页面时一般都会把Tomcat的默认webapp下的内容给删除了,但是如果需要使用Tomcat默认的manager来管理项目时就需要保留相应的文件目录。在Tomcat中的webapps中有如下目录:docs(Tomcat本地说明文档)、examples(Tomcat相关的deamon示例)、host-manager(主机头管理工具)、manager(项目管理工具)、ROOT(Tomcat默认页),其中需要保留的是host-manager、manager、ROOT这3个目录而从Tomcat 6开始为了安全缺省条件下Tomcat的host-manager、manager是不能访问的(http 401拒绝),如需访问需要分配相关的角色权限。

       首先,需要配置的配置文件是${catalina.home}/conf/tomcat-users.xml先给Tomcat访问相关的功能分配角色和配置登录验证用户密码:username="tomcat" password="tomcat" ,把红色的修改为你的 帐号 / 密码

…略…
-->
  <role rolename="manager-gui"/>
  <role rolename="manager-script"/>
  <role rolename="manager-jmx"/>
  <role rolename="manager-status"/>
  <role rolename="admin-gui"/>
  <role rolename="admin-script"/>
  <user username="tomcat" password="tomcat" roles="manager-gui,manager-script,manager-jmx,manager-status,admin-gui,admin-script"/>
</tomcat-users>

       此处可以配置多个角色,不同版本Tomcat所拥有的角色都不同,在生产环境中建议修改复杂度高的Tomcat用户密码,另外不需要分配所有角色权限,经需要够用的即可,如果不能访问会用相应的提示,在配置好后此时再打开Tomcat的首页还是无法进入Tomcat的管理页面的。

        因为从Tomcat 7开始安全机制下默认仅允许本机访问Tomcat,如需远程访问Tomcat的管理页面还需要配置相应的ip允许规则,配置manager的contest.xml可以在${catalina.home}/conf/Catalina/localhost目录下配置2个contest.xml文件,也可以写成一个,但是建议写成2个便于日常的权限管理,如下:( 假如我的tomcat 目录 /usr/local/tomcat/ )

vi /usr/local/tomcat/conf/Catalina/localhost/manager.xml

<Context privileged="true" antiResourceLocking="false"
         docBase="${catalina.home}/webapps/manager">
    <Valve className="org.apache.catalina.valves.RemoteAddrValve" allow="^192.168.*$" />
</Context>

vi /usr/local/tomcat/conf/Catalina/localhost/host-manager.xml

<Context privileged="true" antiResourceLocking="false"
         docBase="${catalina.home}/webapps/host-manager">
    <Valve className="org.apache.catalina.valves.RemoteAddrValve" allow="^192.168.*$" />
</Context>

       其中allow中是填ip可以使用正则表达式匹配,在内网中建议写成匹配某某网段可以访问的形式,如此Tomcat的manager页面访问配置就完成了。

 

三、其它相关说明

有关系统层优化

如果WEB服务器进行压力测试时报socket不足,则些可以对Linux的一些系统参数修改。

vi /etc/security/limits.conf

增加如下内容

* soft nofile 57766
* hard nofile 65535
Tomcat 多端口 项目部署

Tomcat 安装后本身提供了一个server,端口配置默认是8080,对应目录为:..\Tomcat\webapps
Tomcat 配置多个端口,其实也就是给Tomcat增加多个server,并设置对应目录。下面以增加两个端口号为例

1.修改server.xml  [ /usr/local/tomcat/conf ]
(1)Tomcat提供的如下(优化后的配置):

<Service name="Catalina"> 
    <Executor name="tomcatThreadPool"
	namePrefix="catalina-exec-"
	maxThreads="500"
	minSpareThreads="30"
	maxIdleTime="60000"
	prestartminSpareThreads = "true"
	maxQueueSize = "100" />

<Connector executor="tomcatThreadPool"
	port="8080"
	protocol="org.apache.coyote.http11.Http11AprProtocol"
	connectionTimeout="60000"
	maxConnections="10000"
	redirectPort="8443"
	enableLookups="false"
	acceptCount="100"
	maxPostSize="10485760"
	maxHttpHeaderSize="8192"
	compression="on"
	disableUploadTimeout="true"
	compressionMinSize="2048"
	acceptorThreadCount="2"
	compressibleMimeType="text/html,text/plain,text/css,application/javascript,application/json,application/x-font-ttf,application/x-font-otf,image/svg+xml,image/jpeg,image/png,image/gif,audio/mpeg,video/mp4"
	URIEncoding="utf-8"
	processorCache="20000"
	tcpNoDelay="true"
	connectionLinger="5"
	server="Server Version 11.0" />

  <Connector port="8009" protocol="org.apache.coyote.ajp.AjpAprProtocol" redirectPort="8443" /> 
    <Engine name="Catalina" defaultHost="localhost">
      <Realm className="org.apache.catalina.realm.LockOutRealm">
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
               resourceName="UserDatabase"/>
      </Realm>

      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log" suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" /> 
      </Host>
    </Engine>
  </Service>


(2)新增两个端口号,注意 Service name、Engine name、appBase,Port 端口号 别忘了修改,以免重复。

       Service name="Catalina1"
       port="8081"
       Engine name="Catalina1"
       appBase="webapps1"

<Service name="Catalina1"> 
    <Executor name="tomcatThreadPool"
	namePrefix="catalina-exec-"
	maxThreads="500"
	minSpareThreads="30"
	maxIdleTime="60000"
	prestartminSpareThreads = "true"
	maxQueueSize = "100" />

<Connector executor="tomcatThreadPool"
	port="8081"
	protocol="org.apache.coyote.http11.Http11AprProtocol"
	connectionTimeout="60000"
	maxConnections="10000"
	redirectPort="8443"
	enableLookups="false"
	acceptCount="100"
	maxPostSize="10485760"
	maxHttpHeaderSize="8192"
	compression="on"
	disableUploadTimeout="true"
	compressionMinSize="2048"
	acceptorThreadCount="2"
	compressibleMimeType="text/html,text/plain,text/css,application/javascript,application/json,application/x-font-ttf,application/x-font-otf,image/svg+xml,image/jpeg,image/png,image/gif,audio/mpeg,video/mp4"
	URIEncoding="utf-8"
	processorCache="20000"
	tcpNoDelay="true"
	connectionLinger="5"
	server="Server Version 11.0" />

  <Connector port="8009" protocol="org.apache.coyote.ajp.AjpAprProtocol" redirectPort="8443" /> 
  
    <Engine name="Catalina1" defaultHost="localhost">
    
      <Realm className="org.apache.catalina.realm.LockOutRealm">
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
               resourceName="UserDatabase"/>
      </Realm>

      <Host name="localhost"  appBase="webapps1"
            unpackWARs="true" autoDeploy="true">
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log" suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" /> 
      </Host>
    </Engine>
  </Service>

       Service name="Catalina2"
       port="8082"
       Engine name="Catalina2"
       appBase="webapps2"

<Service name="Catalina2"> 
    <Executor name="tomcatThreadPool"
	namePrefix="catalina-exec-"
	maxThreads="500"
	minSpareThreads="30"
	maxIdleTime="60000"
	prestartminSpareThreads = "true"
	maxQueueSize = "100" />

<Connector executor="tomcatThreadPool"
	port="8082"
	protocol="org.apache.coyote.http11.Http11AprProtocol"
	connectionTimeout="60000"
	maxConnections="10000"
	redirectPort="8443"
	enableLookups="false"
	acceptCount="100"
	maxPostSize="10485760"
	maxHttpHeaderSize="8192"
	compression="on"
	disableUploadTimeout="true"
	compressionMinSize="2048"
	acceptorThreadCount="2"
	compressibleMimeType="text/html,text/plain,text/css,application/javascript,application/json,application/x-font-ttf,application/x-font-otf,image/svg+xml,image/jpeg,image/png,image/gif,audio/mpeg,video/mp4"
	URIEncoding="utf-8"
	processorCache="20000"
	tcpNoDelay="true"
	connectionLinger="5"
	server="Server Version 11.0" />

  <Connector port="8009" protocol="org.apache.coyote.ajp.AjpAprProtocol" redirectPort="8443" /> 
  
    <Engine name="Catalina2" defaultHost="localhost">
    
      <Realm className="org.apache.catalina.realm.LockOutRealm">
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
               resourceName="UserDatabase"/>
      </Realm>

      <Host name="localhost"  appBase="webapps2"
            unpackWARs="true" autoDeploy="true">
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log" suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" /> 
      </Host>
    </Engine>
  </Service>

2.复制 webapps 目录 为 webapps1 和  webapps2

cp -rf    /usr/local/tomcat/webapps /usr/local/tomcat/webapps1
cp -rf    /usr/local/tomcat/webapps /usr/local/tomcat/webapps2

/usr/local/tomcat/webapps1
/usr/local/tomcat/webapps2

3.复制 Catalina 目录 为 Catalina1  和 Catalina2

cp -rf    /usr/local/tomcat/conf/Catalina /usr/local/tomcat/conf/Catalina1
cp -rf    /usr/local/tomcat/conf/Catalina /usr/local/tomcat/conf/Catalina2

/usr/local/tomcat/conf/Catalina1/localhost
/usr/local/tomcat/conf/Catalina2/localhost

现在可以把不同的war包放在不同的位置来访问了

Tomcat 虚拟目录部署

在<Host > ...  </Host> 中增加 <Context path="/vdir" docBase="/opt/apps/vdir" reloadable="true"> </Context>

<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">
	<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" 
    	prefix="localhost_access_log" 
        suffix=".txt" 
        pattern="%h %l %u %t &quot;%r&quot; %s %b" /> 

<Context path="" docBase="/opt/apps/index/" reloadable="true"> </Context>
<Context path="/admin" docBase="/opt/apps/admin/" reloadable="true"> </Context>
<Context path="/weixin" docBase="/opt/apps/weixin/" reloadable="true"> </Context>

</Host>

通过 http://ip:8080 访问/opt/apps/index/ 内容
通过 http://ip:8080/admin 访问/opt/apps/admin/ 内容
通过 http://ip:8080/weixin 来访/opt/apps/weixin/ 内容

Tomcat 多域名共用 8080端口布署

在虚拟目录中可以采用多个域名,共用8080端口的方式来分别访问不同的布署应用。
注意看下面配置 有个 <Alias>..... </Alias>  注意:这里是配置多个域名访问。

<!--##################################################
# www.domain.com 和 www.domain.cn 访问 /opt/apps/index/
###################################################-->
<Host name="www.domain.com" appBase="webapps" unpackWARs="true" autoDeploy="true">
	<Alias>www.domain.cn</Alias>  <!-- 注意:这里是配置多个域名访问 -->
	<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" 
    	prefix="localhost_access_log" 
        suffix=".txt" 
        pattern="%h %l %u %t &quot;%r&quot; %s %b" /> 
        
        <Context path="" docBase="/opt/apps/index/" reloadable="true"> </Context>
</Host>

<!--##################################################
# admin.domain.com 访问 /opt/apps/admin/
###################################################-->
<Host name="admin.domain.com" appBase="webapps" unpackWARs="true" autoDeploy="true">
	<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" 
    	prefix="localhost_access_log" 
        suffix=".txt" 
        pattern="%h %l %u %t &quot;%r&quot; %s %b" /> 
        
        <Context path="" docBase="/opt/apps/admin/" reloadable="true"> </Context>
</Host>

<!--##################################################
# weixin.domain.com 访问 /opt/apps/weixin/
###################################################-->
<Host name="weixin.domain.com" appBase="webapps" unpackWARs="true" autoDeploy="true">
	<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" 
    	prefix="localhost_access_log" 
        suffix=".txt" 
        pattern="%h %l %u %t &quot;%r&quot; %s %b" /> 
        
        <Context path="" docBase="/opt/apps/weixin/" reloadable="true"> </Context>
</Host>

以上配置可以使用域名访问如下:
通过 http://www.domain.com 或者 http://www.domain.cn 来访问 /opt/apps/index/ 内容
通过 http://admin.domain.com 来访问 /opt/apps/admin/ 内容
通过 http://weixin.domain.com 来访问 /opt/apps/weixin/ 内容

 

----->持续更新

 

前端 Nginx https SSL proxy + 后端 Nginx http 应用的布署教程

这里主要讲述《前端 Nginx https SSL proxy + 后端 Nginx http 应用的布署教程》有关nginx后端的服务配置优化这里不再复述,将在别外的贴子分享。 有关如何申请Let's Encrypt SSL/TLS免费证书,已经在《免费SSL安全证书Let's Encrypt SSL/TLS - FreeBSD NGINX 配置教程》贴子里已经有详细说明。 我有代码洁癖,所以在以下的配置文件进行了归集整理,固定的配置进行归集分类,尽可能的减少维护成本。

前端代理服务器 HTTPS and HTTP2

操作系统: FreeBSD
web 代理服务: Nginx
SSL工具: LibreSSL
免费证书: Let’s Encrypt
证书申请工具: py-certbot 依赖包 letsencrypt

后端应用服力器 HTTP

操作系统: FreeBSD
web 应用服务: Nginx / Tomcat

前/后 端的布署结构  

         nginx proxy https (192.168.0.1)

                [ 80 + 443 ]
                      |
                      |
                      ↓
                  [  80  ]

     nginx http / tomcat http (192.168.0.10)

前端代理服务器 nginx proxy https (192.168.0.1)布署结构

nginx and www 目录地址:

nginx 配置目录:/usr/local/etc/nginx/
www   网站目录:/usr/local/www/nginx/

前端nginx 配置目录结构:

nginx 配置文件目录结构
  |--fastcgi_params
  |--uwsgi_params
  |--scgi_params
  |--koi-utf
  |--koi-win
  |--win-utf
  |--mime.types
  |--nginx.conf               #nginx的主配置文件
  |--proxy
  |    |--proxy_cache         # nginx 缓存配置配置文件
  |    |--proxy_hosts         # nginx 反向代理配置文件
  |    |--proxy_letsencrypt   #Let’s Encrypt 申请证书的验证目录
  |    |--proxy_security      #nginx 的安全配置文件
  |    |--proxy_ssl           #nginx SSL 配置文件
  |
  |--vhosts
       |
       |--qi-cloud.com        #虚拟目录网站配置文件
       |--..                  #更多vd域久配置文件

nginx 优化后的配置文件:

root@Proxy:/ # vi /usr/local/etc/nginx/nginx.conf

user  www www;
worker_processes  auto;
pid             /var/run/nginx.pid;
error_log       /dev/null;

worker_rlimit_nofile 102400;

events {
        use kqueue;         #kqueue用在bsd上,epoll用在linux上
        multi_accept on;
        worker_connections  20480;
}

http {
        server_tokens off;
        include mime.types;

        default_type application/octet-stream;
        source_charset utf-8;
        server_names_hash_bucket_size 256;
        client_header_buffer_size 256k;
        large_client_header_buffers 4 256k;

        client_max_body_size 50m;
        client_body_buffer_size 256k;
        client_header_timeout 3m;
        client_body_timeout 3m;

        send_timeout 300;
        sendfile on;
        tcp_nopush on;
        keepalive_timeout 120;
        tcp_nodelay on;
        reset_timedout_connection on;

        limit_conn_zone $binary_remote_addr zone=addr:5m;
        limit_conn addr 100;

        open_file_cache max=100000 inactive=20s;
        open_file_cache_valid 30s;
        open_file_cache_min_uses 2;
        open_file_cache_errors on;

        gzip on;
        gzip_disable "msie6";
        gzip_proxied any;
        gzip_min_length 1k;
        gzip_buffers 4 16k;
        gzip_http_version 1.0;
        gzip_comp_level 4;
        gzip_types text/plain application/x-javascript text/css application/xml;
        gzip_vary on;

        proxy_connect_timeout   300;  #这里的时间设置,避免后台服务执行超时问题
        proxy_send_timeout      300;  #这里的时间设置,避免后台服务执行超时问题
        proxy_read_timeout      600;  #这里的时间设置,避免后台服务执行超时问题
        proxy_buffer_size       256k;
        proxy_buffers   128     256k;
        proxy_busy_buffers_size 256k;
        proxy_temp_file_write_size      256k;
        proxy_next_upstream error       timeout invalid_header http_500 http_503 http_404;
        proxy_max_temp_file_size        128m;
        proxy_cache_path /var/tmp/nginx/proxy_cache levels=1:2 keys_zone=proxy_cache_one:300m inactive=1d max_size=5g;

        access_log off;

        server{  #拦截所有指向过来的域名,没有配置时返回403
                listen   80 default;
                server_name     _;
                return 403;
        }

        include vhosts/*;
}

root@Proxy:/ # vi /usr/local/etc/nginx/proxy/proxy_cache

        location ~ /purge(/.*)
        { #清理nginx的静态缓存权限
                allow 127.0.0.1;
                allow 10.10.0.0/16;
                allow 192.168.0.0/16;
                deny all;
        }

        location ~* ^.+.gzjs$ { #已是压缩后的数据不再进行gzip压缩处理
                add_header Content-Encoding gzip;
                gzip off;
        }

root@Proxy:/ # vi /usr/local/etc/nginx/proxy/proxy_hosts

      location /
        {
                proxy_cache proxy_cache_one;
                proxy_cache_valid 200 301 302 304 20m;
                proxy_cache_key $host$uri$is_args$args;
                expires 30m;

                proxy_redirect  off;

                proxy_set_header Host $http_host;
                proxy_set_header X-Forwarded-Proto https;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Scheme $scheme;
                proxy_set_header Accept-Encoding "";

                proxy_pass_header       User-Agent;
                proxy_pass  http://$proxy_vps_add;

                #这里是解决https前端代理时后端传过来的url地址带有http url时不显示图片及css问题
                #这里用nginx的sub_filter,把http替换为https url,很多人卡在这个上面
                sub_filter_types text/css text/xml;
                sub_filter http://$host $scheme://$host;
                sub_filter_once off;
        }

root@Proxy:/ # vi /usr/local/etc/nginx/proxy/proxy_letsencrypt

        location /.well-known/ { #这是主要是为了申请证书及证书续签时的验证
                default_type "text/plain";
                alias /usr/local/www/nginx/.well-known/;
        }

root@Proxy:/ # vi /usr/local/etc/nginx/proxy/proxy_security 

        location ~ ^/images/.*\.(do|php|jsp|cgi|pl|asp|aspx)$
        {
                deny all;
        }

        location ~ ^/static/.*\.(do|php|jsp|cgi|pl|asp|aspx)$
        {
                deny all;
        }

        location ~ ^/data/(attachment|avatar)/.*\.(do|php|jsp|cgi|pl|asp|aspx)$
        {
                deny all;
        }

        if ($fastcgi_script_name ~ \..*\/.*(do|php|jsp|cgi|pl|asp|aspx)) {
                return 403;
        }

root@Proxy:/ # vi /usr/local/etc/nginx/proxy/proxy_ssl

        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA";
        ssl_prefer_server_ciphers on;
        ssl_ecdh_curve secp384r1;

        ssl_session_cache shared:SSL:10m;
        ssl_session_timeout 1440m;
        ssl_session_tickets on;

        resolver 8.8.8.8 8.8.4.4 valid=300s;
        resolver_timeout 10s;

root@Proxy:/ # vi /usr/local/etc/nginx/vhosts/qi-cloud.com

server
{
        #启动http、https、http2
        listen  80;
        listen  443 ssl http2;

        #配置域名
        server_name     qi-cloud.com;
        server_name     www.qi-cloud.com;

        #Let’s Encrypt 申请证书及续签证书时的验证目录配置文件,这个必须放在前面。
        include proxy/proxy_letsencrypt;

        #将不带www访问过来的url转换为https://www.访问
        if ($host != 'www.qi-cloud.com')  {
               return 301 https://www.qi-cloud.com$request_uri;
        }

        #将http访问过来的url转换为https访问
        if ($scheme = 'http') {
               return 301 https://www.qi-cloud.com$request_uri;
        }

        #Let’s Encrypt 针对qi-cloud.com域名的证书地址
        ssl_certificate     /usr/local/etc/letsencrypt/live/qi-cloud.com/fullchain.pem;
        ssl_certificate_key /usr/local/etc/letsencrypt/live/qi-cloud.com/privkey.pem;

        #反向代理后端服务器的地址及http端口
        set $proxy_vps_add  192.168.0.10:80;

        #加载其它的公共配置文件
        include proxy/proxy_ssl;       #Htts ssl相关配置文件
        include proxy/proxy_cache;     #nginx SSL 配置文件
        include proxy/proxy_security;  #nginx 的安全配置文件 
        include proxy/proxy_hosts;     #nginx 反向代理配置文件

}

后端应用服务器 nginx http(192.168.0.10)布署结构

nginx and www 目录地址:

nginx 配置目录:/usr/local/etc/nginx/
www   网站目录:/usr/local/www/nginx/

后端nginx 配置目录结构:

nginx 配置文件目录结构
  |--fastcgi_params
  |--uwsgi_params
  |--scgi_params
  |--koi-utf
  |--koi-win
  |--win-utf
  |--mime.types
  |--nginx.conf               #nginx的主配置文件
  |--vhosts_params            #vd虚拟主机公共配置文件
  |--vhosts
       |
       |--qi-cloud.com        #虚拟目录网站配置文件
       |--..                  #更多vd域久配置文件

nginx 优化后的配置文件:

root@Proxy:/ # vi /usr/local/etc/nginx/nginx.conf
load_module /usr/local/libexec/nginx/ngx_stream_module.so;
load_module /usr/local/libexec/nginx/ngx_mail_module.so;
load_module /usr/local/libexec/nginx/ngx_http_perl_module.so;

user  www www;
worker_processes  auto;

pid        /var/run/nginx.pid;

error_log /dev/null;

worker_rlimit_nofile 102400;

events {
        use kqueue;         #kqueue用在bsd上,epoll用在linux上
        multi_accept on;
        worker_connections  20480;
}

http {
        server_tokens off;
        include mime.types;

        default_type application/octet-stream;
        source_charset utf-8;
        server_names_hash_bucket_size 256;
        client_header_buffer_size 256k;
        large_client_header_buffers 4 256k;

        client_max_body_size 50m;
        client_body_buffer_size 256k;
        client_header_timeout 3m;
        client_body_timeout 3m;

        send_timeout 300;
        sendfile on;
        tcp_nopush on;
        keepalive_timeout 120;
        tcp_nodelay on;
        reset_timedout_connection on;

        limit_conn_zone $binary_remote_addr zone=addr:5m;
        limit_conn addr 100;

        open_file_cache max=100000 inactive=20s;
        open_file_cache_valid 30s;
        open_file_cache_min_uses 2;
        open_file_cache_errors on;

        gzip on;
        gzip_disable "msie6";
        gzip_proxied any;
        gzip_min_length 1k;
        gzip_buffers 8 32k;
        gzip_http_version 1.0;
        gzip_comp_level 4;
        gzip_types text/plain application/x-javascript text/css application/xml;
        gzip_vary on;

        fastcgi_connect_timeout 300;
        fastcgi_send_timeout 300;
        fastcgi_read_timeout 300;
        fastcgi_buffer_size 256k;
        fastcgi_buffers 4 256k;
        fastcgi_busy_buffers_size 512k;
        fastcgi_temp_file_write_size 256k;
        fastcgi_temp_path /var/tmp/nginx/fastcgi_temp;
        fastcgi_cache_path /var/tmp/nginx/fastcgi_cache levels=1:2 keys_zone=ngx_fcgi_cache:10m inactive=5m max_size=2g;
        fastcgi_cache_valid   200 302  1h;
        fastcgi_cache_valid   301 1d;
        fastcgi_cache_valid   any 1m;
        fastcgi_cache_min_uses  1;
        fastcgi_cache_use_stale error timeout invalid_header http_500;

        access_log off;

        server{
                listen   80 default;
                server_name     _;
                return 403;
        }

        include vhosts/*;
}

root@Proxy:/ # vi /usr/local/etc/nginx/vhosts_params

location ~ .*\.(php|php5)?$ { #支持php脚本运行
        gzip off;
        fastcgi_pass unix:/tmp/php-fcgi.sock;  #采用sock通道链接,提升效率
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_intercept_errors off;
        fastcgi_cache ngx_fcgi_cache;
        fastcgi_cache_key $scheme$request_method$host$request_uri;
}

location ~ .*\.(pl|cgi)?$ {   #支持perl脚本运行
        gzip off;
        fastcgi_pass unix:/tmp/perl-fcgi.sock;  #采用sock通道链接,提升效率
        fastcgi_index index.cgi;
        include fastcgi_params;
        fastcgi_intercept_errors off;
        fastcgi_cache ngx_fcgi_cache;
        fastcgi_cache_key $scheme$request_method$host$request_uri;
}

location ~ ^/nginxstatus/ {
        stub_status on;
}

location ~* ^.+.gzjs$ {
        add_header Content-Encoding gzip;
        gzip off;
}

root@Proxy:/ # vi /usr/local/etc/nginx/vhosts/qi-cloud.com

server
        { #后台nginx 网站配置信息
        listen  80;
        server_name  www.qi-cloud.com;

        index   index.html index.htm index.php;
        root /usr/local/www/qi-cloud.com;

        include vhosts_params;
}

免费SSL安全证书Let's Encrypt SSL/TLS - FreeBSD NGINX 配置教程

Let's Encrypt是最近很火的一个免费SSL证书发行项目,Let's Encrypt是由ISRG提供的免费免费公益项目,自动化发行证书,但是证书只有90天的有效期。

本文主要介绍,如何申请 Let's Encrypt  证书,管理证书,自动续签证书及nginx的https的配置方法。
首先安装 certbot 管理工具,linux 下采用 yum 进行安装,这里不再复述,这里主要以 FreeBSD 系统为例。

建议在 FreeBSD 下采用ports方式编译安装

[root@freebsd:~]# cd /usr/ports/security/py-certbot && make install clean

安装完毕后执行以下命令生成证书,请将下面的邮箱更换成你的邮箱地址。

如果有多个域名 请在后面增加 -d youdomain.com 即可。

[root@freebsd:~] certbot certonly -m luffy@qi-cloud.com --agree-tos --webroot -w /usr/local/www/nginx -d qi-cloud.com -d www.qi-cloud.com

完成证书的生成后会提示如下信息

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at
   /usr/local/etc/letsencrypt/live/gnustav.org/fullchain.pem. Your
   cert will expire on 2016-12-16. To obtain a new or tweaked version
   of this certificate in the future, simply run certbot again. To
   non-interactively renew *all* of your certificates, run "certbot
   renew"
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le

证书路径存放在以下位置,以你刚才提交的域名进行命名。

/usr/local/etc/letsencrypt/renewal/qi-cloud.com.conf
/usr/local/etc/letsencrypt/live/qi-cloud.com/

编译nginx配置文件 vi /usr/local/etc/nginx/nginx.conf

server
{
        listen  80;
        listen  443 ssl http2;
        server_name     qi-cloud.com;
        server_name     www.qi-cloud.com;

        #配置http访问的均跳转到https访问
        if ($scheme = http) {
                return   301 https://$host$request_uri;
        }

        #配置网站的根目录
        index   index.html index.htm index.php;
        root /usr/local/www/nginx;

        #配置https证书
        ssl_certificate     /usr/local/etc/letsencrypt/live/qi-cloud.com/fullchain.pem;
        ssl_certificate_key /usr/local/etc/letsencrypt/live/qi-cloud.com/privkey.pem;

        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA";
        ssl_prefer_server_ciphers on;
        ssl_ecdh_curve secp384r1;

        ssl_session_cache shared:SSL:10m;
        ssl_session_timeout 1440m;
        ssl_session_tickets on;

        resolver 8.8.8.8 8.8.4.4 valid=300s;
        resolver_timeout 10s;

        .........
}

Let’s Encrypt的证书只有几个月的有效期,下面到期可以重新刷新更新证书

[root@freebsd:~]# certbot renew --webroot -w /usr/local/www/nginx

当然你也可以设置 crontab 计划任务来每天刷新执行  每天早上5.00执行更新。

[root@freebsd:~]# crontab -e

0 5 * * * /usr/local/bin/certbot renew --webroot -w /usr/local/www/nginx

然后重新nginx服务

[root@freebsd:~]# service nginx restart

打开网站 https://www.qi-cloud.com 看到安全证书了

让 pure-ftpd 的 -P (forcepassiveip) 参数,只用在远端连接

pureftpd 如果配置了远端 -p (--passiveportrange) 模式后,在内网连接时无法连接的问题,可以通过修改以下代码重新编译解决问题 创建 /etc/localnet 文件,该文件格式为 AAA.BBB.CCC.DDD/WWW...

pureftpd 如果配置了远端 -p (--passiveportrange) 模式后,在内网连接时无法连接的问题,可以通过修改以下代码重新编译解决问题。

创建 /etc/localnet 文件,该文件格式为:

AAA.BBB.CCC.DDD/WWW.XXX.YYY.ZZZ 如: 192.168.0.0/255.255.0.0

diff -Nur src.orig/ftpd.c src.patch/ftpd.c
--- src.orig/ftpd.c 2006-06-12 18:44:25.000000000 +0800
+++ src.patch/ftpd.c    2006-06-12 22:52:37.590994047 +0800
@@ -405,6 +405,48 @@
     (void) title;
 }
 
+// add by twu2 20060612 begin
+// check local net in /etc/localnet
+static void check_local_net(const struct sockaddr_storage * const addr)
+{
+    FILE *fp;
+    unsigned long a1 = 0U;
+    unsigned long a2 = 0U;
+    unsigned long mask = 0U;
+    unsigned int b1, b2, b3, b4;
+    unsigned int m1, m2, m3, m4;
+    char buf[1024];
+
+    if (addr == NULL) return;
+    // only for IPV4 now
+    if (STORAGE_FAMILY(*addr) != AF_INET) return;
+    a1 = ntohl(STORAGE_SIN_ADDR(*addr));
+    fp = fopen("/etc/localnet", "rt");
+    // no localnet file
+    if (fp == NULL) return;
+    while (1) {
+        if (fgets(buf, 1024, fp) == NULL) break;
+        b1 = b2 = b3 = b4 = m1 = m2 = m3 = m4 = 0;
+        if ((sscanf(buf, "%u.%u.%u.%u/%u.%u.%u.%u", &b1, &b2, &b3, &b4, &m1, &m2, &m3, &m4) != 8) ||
+            b1 > 255U || b2 > 255U || b3 > 255U || b4 > 255U ||
+            (b1 | b2 | b3 | b4) == 0U ||
+            m1 > 255U || m2 > 255U || m3 > 255U || m4 > 255U ||
+            (m1 | m2 | m3 | m4) == 0U)
+            continue;
+        a2 = b1 << 24 | b2 << 16 | b3 << 8 | b4;
+        mask = m1 << 24 | m2 << 16 | m3 << 8 | m4;
+        // correct format
+        if ((a1 & mask) == (a2 & mask)) {
+            // same subnet
+            is_local = 1;
+            break;
+        }
+    }
+    fclose(fp);
+    return;
+}
+// add by twu2 20060612 end
+
 /* Check whether an address is valid, return 1 if ok, 0 otherwise.
  * Unfortunately, multicasting with the FTP protocol is impossible,
  * you have to use things like MTP instead. So prohibit multicast.
@@ -2123,7 +2165,11 @@
     }
     switch (psvtype) {
     case 0:
-        if (STORAGE_FAMILY(force_passive_ip) == 0) {
+// add by twu2 20060612 begin
+        // if the connection from local subnet, don't do force passive ip convert
+        //if (STORAGE_FAMILY(force_passive_ip) == 0) {
+        if (is_local || STORAGE_FAMILY(force_passive_ip) == 0) {
+// add by twu2 20060612 end
             a = ntohl(STORAGE_SIN_ADDR(dataconn));
         } else if (STORAGE_FAMILY(force_passive_ip) == AF_INET6) {
             (void) close(datafd);
@@ -4448,6 +4494,9 @@
         die(421, LOG_ERR, MSG_GETPEERNAME ": %s" , strerror(errno));
     }
     fourinsix(&peer);
+// add by twu2 20060612 begin
+    check_local_net(&peer);
+// add by twu2 20060612 end
     if (checkvalidaddr(&peer) == 0) {
         die(425, LOG_ERR, MSG_INVALID_IP);
     }
@@ -4486,6 +4535,9 @@
 #endif
     iptropize(&peer);
     logfile(LOG_INFO, MSG_NEW_CONNECTION, host);
+// add by twu2 20060612 begin
+    logfile(LOG_INFO, is_local == 1 ? "from local" : "from remote");
+// add by twu2 20060612 end
 
 #ifndef NO_BANNER
 # ifdef BORING_MODE
diff -Nur src.orig/globals.h src.patch/globals.h
--- src.orig/globals.h  2006-02-15 16:55:00.000000000 +0800
+++ src.patch/globals.h 2006-06-12 21:34:39.361685659 +0800
@@ -73,6 +73,9 @@
 GLOBAL0(signed char force_ls_a);
 GLOBAL0(struct sockaddr_storage peer);
 GLOBAL0(struct sockaddr_storage force_passive_ip);
+// add by twu2 20060612 begin
+GLOBAL(signed char is_local, 0);
+// add by twu2 20060612 end
 GLOBAL0(const char *force_passive_ip_s);
 GLOBAL0(unsigned short int peerdataport);
 GLOBAL0(double maxload);

CentOS 中yum 有未完成事务提示清除办法

本文讲的是linux中yum 有未完成事务提示 清除办法, 使用yum安装东西时,如果有强制退出过yum或yum异常结束,再下次使用yum命令时会提示:There are unfinished transactions remaining. You might consider runni


这是一个能发现未完成或被中断的yum事务的程序。

[root@qc-nginx ~]# yum update
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
 * base: mirrors.aliyun.com
 * extras: mirrors.cn99.com
 * updates: mirrors.huaweicloud.com
Resolving Dependencies
There are unfinished transactions remaining. You might consider running yum-complete-transaction, or "yum-complete-transaction --cleanup-only" and "yum history redo last", first to finish them. If those don't work you'll have to try removing/installing packages by hand (maybe package-cleanup can help).
The program yum-complete-transaction is found in the yum-utils package.
--> Running transaction check

可以通过以下方法处理:

 

一、安装 yum-complete-transaction

yum -y install yum-utils

二、清除yum缓存 yum clean all

[root@qc-nginx ~]# yum clean all
Loaded plugins: fastestmirror
Cleaning repos: base extras updates zabbix zabbix-non-supported
Cleaning up everything
Maybe you want: rm -rf /var/cache/yum, to also free up space taken by orphaned data from disabled or removed repos
Cleaning up list of fastest mirrors
[root@qc-nginx ~]#

三、执行清理未完成事务 yum-complete-transaction --cleanup-only

[root@qc-nginx ~]# yum-complete-transaction --cleanup-only
Loaded plugins: fastestmirror
Determining fastest mirrors
 * base: mirrors.cn99.com
 * extras: mirrors.cn99.com
 * updates: mirrors.huaweicloud.com
base                                                    | 3.6 kB  00:00:00     
extras                                                  | 3.4 kB  00:00:00     
updates                                                 | 3.4 kB  00:00:00     
zabbix                                                  | 2.9 kB  00:00:00     
zabbix-non-supported                                    |  951 B  00:00:00     
(1/5): extras/7/x86_64/primary_db                       | 149 kB  00:00:00     
(2/5): base/7/x86_64/group_gz                           | 166 kB  00:00:00     
(3/5): zabbix/x86_64/primary_db                         |  87 kB  00:00:01     
(4/5): updates/7/x86_64/primary_db                      | 2.7 MB  00:00:02     
(5/5): base/7/x86_64/primary_db                         | 5.9 MB  00:00:05     
zabbix-non-supported/x86_64/primary                     | 1.6 kB  00:00:00     
zabbix-non-supported                                                   4/4
Cleaning up unfinished transaction journals
Cleaning up 2018-06-16.22:14.54
[root@qc-nginx ~]# 

 

高性能、全功能的全文检索解决方案-xunsearch 的安装、索引、导入和骨架的生成

xunsearch 是一个高性能、全功能的全文检索解决方案。 旨在帮助一般开发者针对既有的海量数据,快速而方便地建立自己的全文搜索引擎。

今天折腾itsns.net.cn 集成 XunSearch 全文搜索引擎,这里记录一下笔记本。

XunSearch 介绍:

Xunsearch 是一个高性能、全功能的全文检索解决方案。 旨在帮助一般开发者针对既有的海量数据,快速而方便地建立自己的全文搜索引擎。 采用结构化分层设计,包含后端服务、前端开发包两大部分,层次清晰而不交叉。 其中后端是采用 C/C++ 编写的守护进程,而前端采用最为流行的脚本语言 PHP ,对于 web 搜索项目更为方便。 具体参见架构设计。并且全面开源,并使用最流行的开源许可协议 GPL 发布。您可以免费获取本项目的全部源代码, 自由的使用它,并在许可条件下修改和再分发。(  XunSearch 下载地址  )

XunSearch 布署架构:

Xunsearch 分为后端服务和前端开发包两大部分,这两个部分允许部署在不同服务器中。后端是采用 C/C++ 开发的守护进程,包括索引服务器(xs-indexd)、搜索服务器(xs-searchd)。 索引服务器用于集中处理索引变动,并自动调用工具程序优化和更新数据库;搜索服务器 借鉴了 nginx 的作法,使用进程、线程混合工作模式处理高并发的搜索请求。

              ==============================
              |   Your Search Application  |
              ==============================
                  /\                /\
................ /||\ ............ /||\ ....................
:                 ||                ||                     :
:             +-----------------------------+              :
:             |  [PHP]  | other lang (TODO) |              :
:             |-----------------------------|              :
:             |   SDK: (xunsearch devkit)   |              :
:             +-----------------------------+              :
:                 /                   \                    :
:                /                     \                   :
:    +-----------------+          +-------------------+    : 
:    |  Index-server   |          |   Search-server   |    :
:    |-----------------|          |-------------------|    : 
:    |   xs-indexd     |          |    xs-searchd     |    :
:    |   xs-import     |          |     1*master      |    :
:    |   xs-logging    |          | N*worker(M*thread)|    :
:    +-----------------+          +-------------------+    :
:                |                       |                 :
:                |                       |                 :
:             +-----------------------------+              :
:             |     Xapian-core + scws      |              :
:             +-----------------------------+              :  
:                |          |            |                 :
:      +------------+  +--------+  +---------------+       :
:      | Local Disk |  | Memory |  | Remote socket |       :
:      +------------+  +--------+  +---------------+       :
:                                                          :
...................... Xun Search ..........................

 

开始安装工作:

首先交代一下基础环境

系统:centos 7

xunsearch版本:1.4.9

PHP版本:7.1

php、mysql和apache的安装和启动我这里就不说了,直接说xunsearch

1.安装基础工具和库
yum -y install make gcc gcc-c++ libtool autoconf automake zlib-devel

 

2.下载xunsearch

切换到/usr/local/src目录,这是我的个人喜好,你也可以到其他目录下载

# cd /usr/local/src
# wget -c -t 1 http://www.xunsearch.com/download/xunsearch-full-latest.tar.bz2

解压文件

# tar -xjf xunsearch-full-latest.tar.bz2

切换到解压的目录

# cd xunsearch-full-1.4.9/

 

3.运行安装脚本
# sh setup.sh

中途会让你选择安装目录,他默认目录在/usr/local/xunsearch中,如果不需要更改,可以直接按enter键,然后输入y即可

选择完目录,就等待完成安装即可

 

安装完成后会提示如下信息:

+=================================================+
| Installation completed successfully, Thanks you |
| 安装成功,感谢选择和使用 xunsearch                 |
+-------------------------------------------------+
| 说明和注意事项:                                  |
| 1. 开启/重新开启 xunsearch 服务程序,命令如下:     |
|    /usr/local/xunsearch/bin/xs-ctl.sh restart
|    强烈建议将此命令写入服务器开机脚本中              |
||
| 2. 所有的索引数据将被保存在下面这个目录中:           |
|    /usr/local/xunsearch/data
|    如需要转移到其它目录,请使用软链接。              |
||
| 3. 您现在就可以在我们提供的开发包(SDK)基础上        |
|    开发您自己的搜索了。                           |
|    目前只支持 PHP 语言,参见下面文档:              |
|    /usr/local/xunsearch/sdk/php/README
+=================================================+

 

4、启动xunsearch服务

出于性能和多数需求考虑 xunsearch 服务端和 SDK API 通讯时没有加密和验证处理, 并且默认情况 xs-ctl.sh 启动的服务程序是绑定并监听在 127.0.0.1 上。如果您的 SDK 调用和 xunsearch 服务端不在同一服务器,请使用 -b inet 方式启动脚本, 并注意借助类似 iptables 的防火墙来控制 xunsearch 的 8383/8384 两个端口的访问权限。 启动脚本用法举例如下,以下均为合法使用方式:

/usr/local/xunsearch/bin/xs-ctl.sh -b local start    // 监听在本地回环地址 127.0.0.1 上
/usr/local/xunsearch/bin/xs-ctl.sh -b inet start     // 监听在所有本地 IP 地址上
/usr/local/xunsearch/bin/xs-ctl.sh -b 10.10.58.100 start  // 监听在指定 IP 上
/usr/local/xunsearch/bin/xs-ctl.sh -b unix start     // 分别监听在 tmp/indexd.sock 和 tmp/searchd.sock
5、查看xunsearch 运行情况
[root@xunsearch ~]# netstat -anlpt         #执行查看端口命令
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name          
tcp        0      0 10.10.58.100:8383      0.0.0.0:*               LISTEN      1098/xs-indexd: ser 
tcp        0      0 10.10.58.100:8384      0.0.0.0:*               LISTEN      1270/xs-searchd: ma       
[root@xunsearch ~]# 

 

1.创建项目配置:

官方的配置教程:http://www.xunsearch.com/doc/php/guide/ini.first

官方的配置辅助工具:http://www.xunsearch.com/tools/iniconfig

我这里的配置如下:

project.name = blog 
server.index = 8383
server.search = 8384

[cid]    
type = id

[title]    
type = title 

[text]    
type = body

 

我的配置的几点说明:

(1).配置内容存放在php-sdk/php/app/blog.ini中

(2).配置的项目名为blog

(3).cid字段是主键、title字段是我的文章标题、text字段是我的文章内容,这些东西根据你的实际情况你们都可以该,而且字段数可多可少,但必须要有个主键字段

 

2.建立索引,这部分是用xunsearch自带的工具为原有的数据创建索引,如果原来没有数据,创建索引也没多少意义

执行创建索引命令格式:

util/Indexer.php --rebuild --source=mysql://你的数据库用户名:你的数据库密码@你的数据库IP/你的数据库名 --sql="你要执行的SQL语句" --filter=debug --project=你的项目名 >日志文件名

切换到sdk目录

cd /usr/local/xunsearch/sdk/php

我们来为我们的例子创建索引

util/Indexer.php --rebuild --source=mysql://root:@localhost/our --sql="SELECT cid,title,text FROM test" --filter=debug --project=blog >log.txt

说明:我是在本机装的,用的是root用户,无密码,our数据库,test数据表,日志写到当前目录下的log.txt文件内

 

以下部分是生成搜索骨架

如果你当前在/usr/local/xunsearch/sdk/php目录下就可以直接执行生成骨架命令,如果不在,那现切换到该目录下,切换命令:

cd /usr/local/xunsearch/sdk/php

生成骨架命令格式:

util/SearchSkel.php -p 项目名 -o 生成的目录

我们生成一下我们的例子的骨架:

util/SearchSkel.php -p blog -o /var/www/html

命令执行完会在/var/www/html目录下生成一个blog文件夹

可以通过  http://localhost/blog/search.php  访问一下你的骨架搜索文件。

如果你想把生成的骨架文件移动到其它目录也是可以的

 

接下来你做的就是进行融合到你的代码里吧

BookStack 文章 PDF 导出及解决中文乱码问题

BookStack PDF导出,有两个选择,默认情况下使用 dompdf ,但也可以安装 wkhtmltopdf 来追求更完美的效果。

PDF渲染

默认情况下,BookStack使用dompdf将页面导出为PDF文档。使用dompdf的好处是,它不需要任何额外的安装或设置,但渲染功能有些有限。
作为替代方案,您可以使用wkhtmltopdf生成PDF文档。wkhtmltopdf使用qt webkit呈现引擎提供更准确的整体结果。

使用wkhtmltopdf

wkhtmltopdf的预编译二进制文件可以在其网站的下载页面上找到。bookstack将在bookstack安装的基本文件夹中检查名为wkhtmltopdf的文件。如果找到,它将使用它来呈现PDF。如果不存在,它将检查.env文件中的wkhtmltopdf变量。可以使用此变量将备用位置设置为wkhtmltopdf:

配置 .env 使wkhtmltopdf 生效
vi .env
wkhtmltopdf=/user/local/bin/wkhtmltopdf
更新BookStack配置缓存
php artisan cache:clear
php artisan view:clear
php artisan config:cache
下面以FreeBSD为例,安装 wkhtmltopdf 和 中文 字体
cd /usr/ports/converters/wkhtmltopdf && make install clean
cd /usr/ports/x11-fonts/wqy && make install clean
cd /usr/ports/print/adobe-cmaps  && make install clean
刷新字体生效
fc-cache -f -v

因为系统没有安装对中文字体的支持,所以导出的PDF会如下图产生乱码

11111.jpg

安装完字体,刷新生效后再次导出,中文方块乱码问题就解决了

222222.jpg

关于npm audit fix

执行npm install 出现如下提醒 按照控制台提示的命令,输入‘npm audit fix’后,控制台提示: 输入:‘npm audit fix --force’后,控制台提示: 重新输入‘npm audit’: 终于一切正常...

执行npm install 出现如下提醒:

added 253 packages from 162 contributors and audited 1117 packages in 42.157s
found 5 vulnerabilities (1 low, 4 high)

run `npm audit fix` to fix them, or `npm audit` for details html

按照控制台提示的命令,输入‘npm audit fix’后,控制台提示:


1 package update for 5 vulns involved breaking changes
(use `npm audit fix --force` to install breaking changes; or do it by hand)

 

输入:‘npm audit fix --force’后,控制台提示:

added 199 packages from 111 contributors, removed 64 packages and updated 23 packages in 42.194sfixed 5 of 5 vulnerabilities in 1117 scanned packages

1 package update for 5 vulns involved breaking changes
(installed due to `--force` option)


重新输入‘npm audit’:

=== npm audit security report ===
found 0 vulnerabilities
in 4598 scanned packages


终于一切正常。

出于好奇,从npm官网上查阅了对于npm audit fix的相关介绍。
npm audit : npm@5.10.0 & npm@6,允许开发人员分析复杂的代码,并查明特定的漏洞和缺陷。
npm audit fix :npm@6.1.0, 检测项目依赖中的漏洞并自动安装需要更新的有漏洞的依赖,而不必再自己进行跟踪和修复。


同时,官网中还提供了一些其他的命令,整理如下:

1. 运行audit fix,但是只更新pkglock, 不更新node_modules:
$ npm audit fix --package-lock-only

2. 只更新dependencies中安装的包,跳过devDependencies中的包:
$ npm audit fix --only=prod

3.运行命令,得到audit fix将会更新的内容,并且输出json格式的安装信息,但是并不真的安装更新:
$ npm audit fix --dry-run --json

4. 得到json格式的详细检测报告
$ npm audit --json

附:npm-audit 官网地址:https://docs.npmjs.com/cli/audit

如何与NPM package-lock.json愉快地玩耍

升级了 Node,前端使用Gulp进行打包时却突然碰到了报错:$ gulp gulp[85]: ../src/node_contextify.cc:631:static void node::contextify::ContextifyScript::New(const v8::FunctionCallbackInfo&): Assertion `args[1]->IsString()' failed. Aborted ERROR: Job failed: exit code 134

最近写文章都会交代一下背景。

因为按标题的套路,这本应该是一篇教程类的文章,但这种文章其实挺无趣的。

之所以想写这篇,是因为确实碰到了一些很麻烦的事情。

闲言少叙,我们进入正题。

 

最近升级了 Node,最新版本(Node 11),在对QPM前端使用Gulp进行打包时却突然碰到了报错:

$ gulp
gulp[85]: ../src/node_contextify.cc:631:static void node::contextify::ContextifyScript::New(const v8::FunctionCallbackInfo&): Assertion `args[1]->IsString()' failed.
Aborted
ERROR: Job failed: exit code 134

看了一眼这个错误信息,一下子就发现,这并不是来自JS层的错误,而是来自Node原生层

 

模块版本兼容问题

通过搜索,找到一篇解决方案,文中给出了如下解决办法:

rm -fr node_modules
rm -fr package-lock.json
npm cache clean --force
npm install

所以这是什么原理呢?

没看到文章有解释,另外这文章本身也写得不是很清楚。抱着半信半疑的态度,在脚本中加上了 npm cache clean --force,结果问题依旧。

接着搜索了一下,很快发现一些和这个问题有关的issue:

 

  1. nodejs/node: node 10.0.0安装模块时core dump
  2. nodejs/node: 新发布的版本与Gulp ^3.9.0不兼容
  3. gulpjs/gulp: 将graceful-fs的升级合并回Gulp 3
  4. gulpjs/gulp: node 10中崩溃
  5. isaacs/node-graceful-fs v3.x分支与Node.js master不兼容
  6. isaacs/node-graceful-fs v3.0.11依赖natives 1.1.1,后者与node 10不兼容

 

通过 npm ls,一下子就看到了 natives

模块的版本是1.1.1,于是定位到真正的问题: gulp

依赖 vinyl-fs, vinyl-fs依赖 graceful-fs, graceful-fs依赖 natives,而 natives 在1.1.3之前都不兼容Node 10。

那么解决方案就简单了,想办法升级一下模块不就好了?

 

如何升级间接依赖

首先想到的是Gulp是否有解决这个问题, npm info gulp 看了一下,发现最新版本是 4.0.0

然后 npm ls 一下,发现本机装的已经是4.0.0 了,也就是说,Gulp根本没有升级的可能。

那要如何升级这个间接的依赖呢?

这里我绕了个弯子, package.json 中直接依赖的模块无法升级, npm update 也不能搞定。

于是想到,如果显式安装一下这个模块,是不是能解决问题?

npm install natives@1.1.6

安装完之后还要在 package.json

中将直接依赖 natives

删除(因为我并不直接依赖它,留着没用)。然后再次查看依赖:

▶ npm ls natives
seed@1.0.0 /Users/TooBug/work/oa/learn/frontend
└─┬ gulp@3.9.1
  └─┬ vinyl-fs@0.3.14
    └─┬ graceful-fs@3.0.11
      └── natives@1.1.6

这次对了。

但是,这个操作我是在本机进行的,这个操作到底改了什么呢?

如果去CI上再次执行 npm install,会不会依然安装到旧版本呢?

毕竟 package.json 并没有任何改动。

于是翻看了一下 git diff ,发现了本文的主角 package-lock.json

被修改了,其中的 natives 由1.1.1变成了1.1.6。

    "natives": {                                                                                         
      "version": "1.1.6",                                                                                
      "resolved": "http://registry.npm.taobao.org/natives/download/natives-1.1.6.tgz",                   
      "integrity": "sha1-pgO0pJirdxc2ErnqGs3sTZgPALs="                                                   
    },

于是怦然大悟:本来npm在安装模块是是按语义化版本安装最新版的,但是在CI上却没有安装 natives

1.1.6版本,而是安装了 natives

1.1.1版本,这正是因为 package-lock.json

装版本锁定了,从而导致了与Node 10的不兼容问题。

这也能很好地解释,为什么其它项目没有这样的问题,因为其它的项目在代码仓库中没有包含 package-lock.json,在安装时自然就安装了 natives 1.1.6版本。

于是再回头看一开始搜到的文章提出的解决办法:

rm -fr node_modules
rm -fr package-lock.json
npm cache clean --force
npm install

其实是非常有效的,因为它将 package-lock.json

直接删除了,然后重新安装一遍最新版本,生成新的 package-lock.json,从而解决问题。

 

延伸:如何正确地在项目中使用 package-lock.json

最后,也补充说明一下 package-lock.json

的正确用法。(虽然我知道,但还是不小心踩坑了。如果不清楚它的用法的话,可能会在坑里待更长时间爬不出来。)

首先,需要确保 npm 的版本在5.6以上,因为在5.0 - 5.6中间,对 package-lock.json 的处理逻辑更新过几个版本。5.6以上的才是符合认知的逻辑。

然后,在项目中如果没有锁版本的必要,可以不使用 package-lock.json,在安装模块时指定 --no-lock 即可。

如果项目中有 package-lock.json ,则安装模块时会以这个文件中指定的版本和地址为准,直接下载安装。(除非它和 package.json 中指定的版本不相符。)

最后,如果已经锁定了版本的情况下,需要更新直接依赖,则直接安装指定版本, package.json 和 package-lock.json

都会同步更新。如果需要更新间接依赖的话,则需要像本文这样,手工安装一下,保证 package-lock.json

被更新到。或者如果其它模块的锁定并不是那么重要时,也可以直接删除 package-lock.json ,然后重新安装一遍,相当于把所有(直接依赖+间接依赖)模块全部更新一遍。

How To Install HyperFastCgi On FreeBSD 12

Prerequisites FreeBSD 12. Mono. Mono-basic (optional). Libgdiplus. Nginx. Step 1 — Prepare Your Server Update Ports portsnap fetch update Install Git cd /usr/ports/devel/git/...

Prerequisites

FreeBSD 12.
Mono.
Mono-basic (optional).
Libgdiplus.
Nginx.

Step 1 — Prepare Your Server

Update Ports

portsnap fetch update

Install Git

cd /usr/ports/devel/git/
make install

Install GCC

Clang/LLVM is the system compiler on the several platforms in FreeBSD 12 and later, and GCC is not installed by default.

cd /usr/ports/lang/gcc8/
make config install clean

Add GCC alias

cd /usr/local/bin/gcc
ls - gcc*
gcc-ar8*     gcc-nm8*     gcc-ranlib8* gcc8*        
ln -s gcc8 gcc

Install Automake

cd /usr/ports/devel/automake/
make config install clean

Install libtool

cd /usr/ports/devel/libtool/
make install clean

Install libevent

cd /usr/ports/devel/libevent/
make config install clean

 

Step 2 — Install HyperFastCgi

git clone https://github.com/xplicit/HyperFastCgi.git
cd ./HyperFastCgi/
./autogen.sh --prefix=/usr/local
gmake
gmake install

Test HyperFastCgi

hyperfastcgi4 --version
HyperFastCgi.exe 0.4.4.0
(c) Sergey Zhukov

 

Step 3 — Configure HyperFastCgi

Move the simple configuration file ./HyperFastCgi/samples/server.config to /usr/local/etc/hyperfastcgi4/server.config and edit:

<configuration>
	<server type="HyperFastCgi.ApplicationServers.SimpleApplicationServer">
		<!-- Host factory defines how host will be created. SystemWebHostFactory creates host in AppDomain in standard ASP.NET way --> 
		<host-factory>HyperFastCgi.HostFactories.SystemWebHostFactory</host-factory>
		<!-- <threads> creates threads at startup. Value "0" means default value --> 
		<threads min-worker="40" max-worker="0" min-io="4" max-io="0" />
		<!--- Sets the application host root directory -->
		<!-- <root-dir>/usr/local/www/nginx</root-dir> -->
	</server>
	<listener type="HyperFastCgi.Listeners.NativeListener">
		<apphost-transport type="HyperFastCgi.Transports.NativeTransport">
			<multithreading>Single</multithreading>
		</apphost-transport>
	    <protocol>InterNetwork</protocol>
	    <address>127.0.0.1</address>
	    <port>9000</port>
	</listener>
    <apphost type="HyperFastCgi.AppHosts.AspNet.AspNetApplicationHost">
		<log level="Debug" write-to-console="true" />
		<add-trailing-slash>false</add-trailing-slash>
    </apphost>
    <web-applications>
    	<web-application>
    		<name>ApplicationServer</name>
    		<vhost>a1.domain.com</vhost>
    		<vport>443</vport>
    		<vpath>/</vpath>
    		<path>/usr/local/www/nginx/a1.domain.com</path>
    	</web-application>
    </web-applications>
</configuration>

Step 4 — Configure Nginx to Use HyperFastCgi

upstream fastcgi_backend {
  #server unix:/tmp/my-web-app.socket;
  server 127.0.0.1:9000;
  keepalive 32;
}

# HTTP server
server {
        listen   80;
        listen [::]:80;

        server_name  a1.domain.com www.a1.domain.com;
        access_log   /var/log/nginx/a1.domain.com.access.log;

        # Redirect to https
        rewrite ^ https://a1.domain.com$request_uri? permanent; #301-redirect
}


# HTTPS server
server {

        listen 443 ssl spdy;

        server_name  a1.domain.com www.a1.domain.com;
        access_log   /var/log/nginx/a1.domain.com.access.log;

	location / {
	    root /usr/local/www/nginx/a1.domain.com/;
	    index index.aspx;
	    fastcgi_index index.aspx;
	    fastcgi_keep_conn on;
	    fastcgi_pass fastcgi_backend;
	    include /usr/local/etc/nginx/fastcgi_params;
	}

	… (ssl options)

}

Step 5 — Run HyperFastCgi

Command line

hyperfastcgi4 /config=/path/to/server.config /loglevels=Standard /printlog

More details here.

System startup script (/usr/local/etc/rc.d)

#!/bin/sh

# PROVIDE: hyperfastcgi
# REQUIRE: LOGIN nginx
# KEYWORD: shutdown

. /etc/rc.subr

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/local/bin/mono
name="hyperfastcgi4"
rcvar="${name}_enable"
command="/usr/local/bin/hyperfastcgi4"
procname="/usr/local/bin/mono"
config="/usr/local/etc/hyperfastcgi4/server.config"
logfile="/var/log/hyperfastcgi4.log"
#Specifies what log levels to log. It can be any of the following values, or multiple if comma separated: Debug, Notice, Warning, Error, Standard (Notice,Warning,Error), All (Debug,Standard)
loglevels=Standard
command_args="/config=${config} /logfile=${logfile} /loglevels=${loglevels} >> $logfile &"

load_rc_config $name
run_rc_command "$1"

Add the following line in the /etc/rc.conf:

hyperfastcgi4_enable="YES"

Appendix 1 Uninstall HyperFastCgi

cd ./HyperFastCgi/
gmake uninstall

FreeBSD 使用 ZFS 文件系统内核调优

vi /boot/loader.conf

kern.geom.label.disk_ident.enable="0"
kern.geom.label.gptid.enable="0"
vfs.zfs.min_auto_ashift=12
vfs.zfs.prefetch_disable=0
vfs.zfs.arc_max="128M"
vfs.zfs.vdev.cache.size="5M"
zfs_load="YES"
autoboot_delay="2"
loader_logo=none
aesni_load="YES"

Freebsd 下如何最有效率的安装软件

FreeBSD的默认下载工具是fetch,既慢又不好用。在FreeBSD下安装软件有一些很有效率的方式,下面就给大家介绍一下。

一、加速ports的升级速度

ports从网上下载软件包自动安装,那么从那里下载呢?首先,我们需要安装axel来取代默认的下载工具fetch,这样可以提高ports的安装速度:

cd /usr/ports/ftp/axel
make install clean

然后,我们需要一个源地址管理。跟ubuntu上的/etc/source.list文件一样,freebsd用的文件是/etc/make.conf,我们可以修改其文件,达到加速下载的目的。

#修改 /et/make.conf

vi /etc/make.conf

#加入以下内容

FETCH_CMD=axel
FETCH_BEFORE_ARGS= -n 10 -a
FETCH_AFTER_ARGS=
DISABLE_SIZE=yes
MASTER_SITE_OVERRIDE?=\
http://ports.hshh.org/${DIST_SUBDIR}/\
http://ports.cn.freebsd.org/${DIST_SUBDIR}/\
ftp://ftp.freeBSDchina.org/pub/FreeBSD/ports/distfiles/${DIST_SUBDIR}/
MASTER_SITE_OVERRIDE?=${MASTER_SITE_BACKUP}  

这样处理后,在公司的网络环境下,FreeBSD的下载速度明显提高了,有时居然能达到1M/s,这样升级及安装软件方便极了;呵呵,终于可以摆脱fetch的龟速了。

 

二、更新ports目录树

既然ports的树目录全部下载到本地,那么即使FreeBSD有新的软件包或者添置了新的软件,本地目录树也不会更新。所以,我们每隔一段时间需要更新本地目录树。我来介绍一种在FreeBSD中方便、快捷的更新ports的方法:使用portsnap来更新ports目录树。

 

①配置portsnap:

我们使用portsnap,首先要设置一下它的配置文件,位于/etc/portsnap.conf:

[root@bsd01 /usr/ports]# vi /etc/portsnap.conf  

SERVERNAME=portsnap.freebsd.org

修改成:

SERVERNAME=portsnap.hshh.org

这个是他的更新服务器。另外还有几个国内比较快的portsnap服务器:

portsnap.hshh.org
portsnap2.hshh.org
portsnap3.hshh.org (网通)
portsnap4.hshh.org

②首次使用portsnap:

在你的FreeBSD首次使用portsnap必须执行下面2步:

[root@bsd01 ~]# portsnap fetch
[root@bsd01 ~]# portsnap extract

portsnap fecth是从网上获取portsnap快照的最新压缩包,听闻这个压缩包官方没小时更新一次。

portsnap extract 则是把这个压缩包创立到/usr/ports。哪怕你以前已经手工安装了ports,他也会重新创立一次。

(注:这2步可以合成使用,指令为 [root@bsd01 ~]# portsnap fetch extract)

[root@bsd01 ~]# portsnap fetch
[root@bsd01 ~]# portsnap update

③以后使用portsnap更新,只需要执行下面2步:

同样,这2步可以合成使用:

[root@bsd01 ~]# portsnap fetch update

portsnap第一次运行extract命令时,可能需要一段时间,以后更新使用update的时候,速度就快很多了。

VMWare清理Linux虚拟机磁盘

       关于这个问题,早就想写出来总结一下了。玩过VMWare的都知道,Windows虚拟机清理磁盘非常简单,在GUI界面下选择磁盘清理就可以了,但是此操作对Linux系统无解。

注意,这里说的VMWare包括Windows平台的VMWare Workstation和Mac OSX的VMWare Fusion。

这里以VMWare Fusion为例,记录一下是如何清理的。

Linux虚拟机里磁盘清理

清理已经删除的软件的.deb软件安装包

sudo apt-get autoclean

使用zero数据填充磁盘的剩余空间,以便在下一步的清理阶段可以回收这些空间

sudo cat /dev/zero > zero;sync;sleep 1;sudo rm zero

宿主系统下清理vmdk虚拟机文件

这时候,我们把虚拟机关机。然后打开Terminal程序,进入到VMWare Fusion的安装目录

cd '/Applications/VMware Fusion.app/Contents/Library'

这时候我们先清理磁盘碎片(这一步并不会回收磁盘空间)

./vmware-vdiskmanager -d path_to_your/disc.vmdk

这里要注意一下,因为为了便于移动,一般情况下我们的虚拟机磁盘是分成多个文件的。所以有些文章里边说”path_to_your/disc.vmdk”指的是”disc-s001.vmdk”, “disc-s002.vmdk”,如果你这样执行,会报错,说指定的文件不是虚拟机文件。 

其实这里是虚拟机磁盘的入口文件”disc.vmdk”,这个文件其实是一个文本文件,它列出了所有的虚拟机文件。

接下来我们回收磁盘空间

./vmware-vdiskmanager -k path_to_your/disc.vmdk

上面的两步都要执行一段时间,耐心等待或者去活动一下就好了。

 

P.S. 说起来也比较奇怪,VMWare官方对于这个问题的教程就是在GUI界面里边直接清理磁盘就好了,但是就像我们一开始提到的,根本没有效果。也不知道为什么不更新。

FreeBSD 11.1 发行版在线升级到 FreeBSD 11.2 发行版

用 freebsd-update 命令更新一个新的发行版,第一步会较花时间,根据网络情况,多则可能会花数小时。

举例由旧版本(目前是 FreeBSD 11.1)更新到 FreeBSD 11.2:

freebsd-update -r 11.2-RELEASE upgrade

完成上一步后,使用这条命令将升级后的文件安装到磁盘上。

freebsd-update install

内核和内核模块会首先被打上补丁。此时必须重新启动计算机。如果您使用的是定制的内核,请使用 nextboot 命令来选择下一次用于引导系统的内核 /boot/GENERIC (它会被更新),然后重启系统:

nextboot -k GENERIC
reboot

在系统重新上线后,需要再次运行 freebsd-update。 升级的状态被保存着,这样 freebsd-update 就无需重头开始,但是会删除所有旧的共享库和目标文件。

再次执行以下命令继续这个阶段的升级:

freebsd-update install
reboot

查看当前版本号,正常的话应该显示更新后的 11.2 版本号:

uname -a

更新 ports(如果有源码安装的程序则需要更新 ports),更新 ports 之后您可能需要重新编译部分程序:

portsnap fetch extract

更新 pkg 程序,直接运行 pkg 时 pkg 会自动检查是否有新版本:

pkg

使用 portupgrade 更新通过 ports 安装的程序:

portupgrade -arR

再次重启系统:

reboot

至此,完成了 FreeBSD 的全部升级。

xrandr调整分辨率、旋转屏幕很好用

freebsd10.0、archlinux 3.17下实验木有问题(系统更新很快,很多老命令在新版本下不一定好用了)
以前只会修改xorg.conf来控制多个显示器的显示,后来发现xrandr可以动态的调整多个显示器,在后来发现xrandr 功能无比强悍。列举些xrandr常用的方法,备忘。
运行xrandr会得到诸如:
Screen 0: XXXX
LVDS1 connected XXX
DP1 XXX
VGA1 XXX
等信息,LVDS1、VGA1等是xrandr识别到的输出设备的名称,这些名称一般跟在--output后面,表示对相应的设备进行设置和操作。
1 xrandr --output VGA1 --auto
打开VGA1输出,并自动设置最佳分辨率
2 xrandr --output VGA1 --off
关闭VGA1输出
3 xrandr --fb 2048x768 --output VGA1 --panning 1024x768+0+0 --output LVDS1 --panning 1024x768+1024+0
fb是framebuffer,指定总的分辨率,这里总分辨率为2048x768,VGA1显示1024x768,LVDS1显示1024x768,LVDS1和VGA1拼接成2048x768。(panning这个单词查了下是平底锅的意思,让我百思不得其解,可能我的stardict字典太差,仔细理解下可能就是调整屏幕框框的意思,和平底锅很类似吧)
4 xrandr --output VGA1 --transform a,b,c,d,e,f,g,h,i
a、b、c、d、e、f、g、h、i是所需的参数,这些参数构成一个变换矩阵,xrandr使用变换矩阵调整屏幕,变换矩阵为adgbehcfi,这个矩阵实质上是一个单应矩阵(Homography),平移、旋转、缩放、仿射等变化都是单应的特例,单应矩阵就不详细介绍了,随便找个计算机视觉的书看了就懂。
例如将屏幕旋转T,则单应矩阵为cosTsinT0−sinTcosT0001,将命令行中的abcdefghi换成对应数值就可以了。
例如旋转T并且水平平移x竖直平移y,则单应矩阵为cosTsinTx−sinTcosTy001,将命令行中的abcdefghi换成对应数值就可以了。
5 xrandr --output VGA1 --mode 1024x768
VGA1设置1024x768分辨率
如果显卡没有对应的mode可以通过
xrandr -newmode "1024x768" 63.5 1024 1072 1176 1328 768 771 775 798 -hsync +vsync
xrandr --addmode VGA1 1024x768
进行添加,mode后面的那一串参数可以通过gtf来获取,如gtf  1024 768 60就是获得1024x768 60Hz刷新率的mode参数

CentOS 7.x 通过yum install 安装 Mysql 8.x + Php7.2.x + supervisord + supervisord + redis + beanstalkd + Nginx 环境

rpm -ivh http://repo.mysql.com/mysql80-community-release-el7.rpm
yum install mysql-server
systemctl enable mysqld

rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm 
rpm -Uvh https://mirror.webtatic.com/yum/el7/webtatic-release.rpm
yum -y install php72w php72w-cli php72w-common php72w-devel php72w-embedded php72w-fpm php72w-gd php72w-mbstring php72w-mysqlnd php72w-opcache php72w-pdo php72w-xml php72w-pecl-memcached php72w-pecl-redis

systemctl enable php-fpm 

yum install supervisor
systemctl enable supervisord.service 

yum install memcached
systemctl enable memcached

vi /etc/sysconfig/memcached

PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="64"
OPTIONS="-l 127.0.0.1"

yum install redis
systemctl enable redis

yum install beanstalkd
systemctl enable beanstalkd 
vi /etc/sysconfig/beanstalkd 编辑配置

ADDR=-l 127.0.0.1
PORT=-p 11300
USER=-u beanstalkd
MAX_JOB_SIZE=-z 65535 
BINLOG_DIR=-b /var/lib/beanstalkd/binlog 
BINLOG_SIZE=-s 10485760

yum install nginx
systemctl enable nginx

Extmail web下邮件乱码的问题

主要是perl的Text::Iconv模块的兼容性不好,将这个模块卸载掉就可以了

FreeBSD :

Uinstall:

cd /usr/ports/converters/p5-Text-Iconv && make deinstall clean

Install:

cd /usr/ports/chinese/p5-Encode-HanExtra && make install clean

How to overcome “'aclocal-1.15' is missing on your system” warning when compiling?

$ ./configure
[...]
$ make gawk
CDPATH="${ZSH_VERSION+.}:" && cd . && /bin/bash /home/kaz/gawk/missing aclocal-1.15 -I m4
/home/kaz/gawk/missing: line 81: aclocal-1.15: command not found
WARNING: 'aclocal-1.15' is missing on your system.
         You should only need it if you modified 'acinclude.m4' or
         'configure.ac' or m4 files included by 'configure.ac'.
         The 'aclocal' program is part of the GNU Automake package:
         <http://www.gnu.org/software/automake>
         It also requires GNU Autoconf, GNU m4 and Perl in order to run:
         <http://www.gnu.org/software/autoconf>
         <http://www.gnu.org/software/m4/>
         <http://www.perl.org/>
make: *** [aclocal.m4] Error 127

安装

$ wget https://ftp.gnu.org/gnu/automake/automake-1.16.1.tar.gz
$ tar -xzvf automake-1.16.1.tar.gz
$ cd automake-1.16.1
$ ./configure  --prefix=/usr
$ make
$ make install
$ aclocal --version

OSX 10.13 以后实现终端FTP命令

10.13 以后就没了........这样操作亲测可以恢复。


1,brew install telnet 
2,brew install inetutils 
3,brew link --overwrite inetutils

dspam.conf 配置文件详解

dspam.conf 配置文件详解:
   

配置文件基于DSPAM-3.10,如果使用其他版本的DSPAM,请参照其他版本的dspam.conf配置文件

Home /var/lib/dspam
指定DSPAM存储的基本目录

StorageDriver /usr/lib/dspam/libmysql_drv.so
指定后台库使用的存储驱动,选项包括:
libhash_drv.so
libmysql_drv.so
libpgsql_drv.so
libsqlite_drv.so
libsqlite3_drv.so
一般来说,MYSQL是一个较好的解决方案,同时适合小型或大规模的运行。

TrustedDeliveryAgent="/usr/bin/procmail"
受信任的传递代理:
DSPAM信任的用户发送邮件时,调用的本地投递代理和参数。使用%u来确定DSPAM处理邮件的对象。它通常是一个好办法,也可以允许MTA在运行时指定参数。

#UntrustedDeliveryAgent "/usr/bin/procmail -d %u"
不可信的投递代理:
DSPAM不可信的用户发送邮件时,调用的本地投递代理和参数,因为DSPAM不会允许不信任的用户通过,所有参数应当在这里指定,使用%u来确定DSPAM处理邮件的对象,如果您打算允许不可信的处理,这个参数是必需的。

#Delivery
SMTP或LMTP投递:
在二者之间选择一个,你可以使用SMTP或LMTP投递到邮件服务器,而不是使用投递代理。编译时需要指定--enable-daemon,如果不使用daemon模式,需要指定IP地址或UNIX SOCKET
DeliveryHost        127.0.0.1
DeliveryPort        10026
DeliveryIdent       localhost
DeliveryProto       SMTP

#FallbackDomains on
如果要指定某个域作为备用域,启用此选项。例如,您可以创建一个用户 @example.org ,如果系统已知用户的bob@example.org不能解析,可以默认使用 @domain.com 用户。注意:这里需要指定fallbackDomain的域名,dspam_admin优先于fallbackdomain上的example.org 

#QuarantineAgent
DSPAM认为是垃圾邮件,默认的行为是被隔离所有邮件。如果要改变这个行为,可以指定一个隔离代理,DSPAM认为是垃圾邮件发送到隔离代理。使用%u来确定DSPAM处理邮件的对象。

#EnablePlusedDetail     on
DSPAM通过在用户名前面添加的“+”,选择性的处理"plused users" (addresses in the user+detail form),所以对“user”来说都是在内部发生 ,都被投递为“user+detail” 。如果LDA可以处理“plused users”,并且在上面配置LMTP投递,这时才有用。

#PlusedCharacter        +
使用字符作为用户名和地址的分隔符。如果你要改变这个值,请调整QuarantineMailbox,使用新的分隔符。默认值是“+”。

#PlusedUserLowercase    on
使用这个功能,使 DSPAM  "plused users" 用户名为小写。

#QuarantineMailbox      +quarantine
隔离邮箱:
DSPAM的LMTP代码可以发送垃圾邮件到LMTP的“plused”信箱(如user+quarantine),让LDA和邮件客户端来隔离处理再训练或删除。“Cyrus IMAP和其他LDAs可能支持plused”邮箱。 如果你不修改PlusedCharacter 参数,邮箱名字使用默认字符+

OnFail error
如果本地投递或隔离失败,该怎么办?如果设置为"unlearn",DSPAM将在忽略邮件之前退出并返回未成功代码。默认的选项是 “error”,不会忽略邮件,并返回相应的错误代码。某些系统在本地投递失败时会导致邮件被重新排队投递,并可能导致邮件被处理多次。这时"unlearn"选项是非常有用的,如果有一个非常大的故障期间,可能会导致负荷加重。

Trusted Users:
受信任的用户:
只有指定的用户将被允许在DSPAM执行管理功能,所有其他用户试图运行DSPAM将受到限制。

#Debug *
#Debug bob bill
对部分或所有用户启用Debug,重要说明: DSPAM必须编译成"--enable-Debug",才能使用这个选项。除非你在进行故障排除,否则不应该在生产环境中进行Debug。

#DebugOpt: 
Debug选项:
可以选择一个或多个
process       标准邮件处理
classify        邮件分类,使用--classify
spam          纠正遗漏的垃圾邮件
fp               纠正误报
inoculation 信息接种 (source=inoculation)
corpus       邮件资料库 (source=corpus)
备注:
    信息接种(message inoculation)就是将垃圾邮件作为一种"疫苗"来接种垃圾邮件过滤器,message inoculation 由Bill Yerazunis 在CRM114中提出,意思是,某个垃圾邮件过滤器对一封新类型的垃圾邮件发生了误判,用户发现了误判邮件,垃圾邮件过滤器用这封邮件训练,并组织一封信息接种,同时将信息接种传递给信息接种组的其他过滤器,从而使其他垃圾邮件过滤器不会对这种类型的邮件发生误判。信息接种的力量非常强大,如果多个过滤器组合,共享垃圾邮件信息,正确率会相当高。

#ClassAliasSpam badstuff
#ClassAliasNonspam goodstuff
分类别名 :
spam/nospam的某一类别名,对于区分垃圾邮件以外的类别,这是非常有用的。

TrainingMode teft
训练模式可接受的值为:
toe       遇到错误才学习,优点:数据库写操作少、学习效率高, 缺点:准确性低一些
teft       学习所有,优点:简单实时,缺点:数据库增长很快,I/O频繁容易出错 
tum      学习到成熟,没有足够的数据只标记介于Teft和Toe之间的一个方法
notrain  不训练或存储签名,大型ISP系统的邮件训练,优点:准确率很高,缺点:学习需要的时间很长

TestConditionalTraining on
测试条件训练:
默认情况下,DSPAM将重新训练某些错误,直到条件不再符合,这可以加速学习。但是,一些人认为这可能会增加错误的风险。

#Feature
指定默认激活的功能:
也可以在命令行中指定,下面列出的可用功能
Feature noise         Bayesian Noise Reduction(BNR)
Feature whitelist     自动白名单
Feature tb=5         训练缓冲区
默认是5,在训练期间,训练缓冲区会淡化统计数据,目的是防止误判,而且还可以大大减少DSPAM在初期训练时的捕获率,这个数字可以从0(无缓冲)到10(最大缓冲)。如果你怀疑误报,应该启用这个选项。

Algorithm graham burton
指定使用的统计算法,忽略所有默认的配置。选项包括:
# naive Naive-Bayesian(全部Token)算法由于其简单高效性在文本分类中应用较广
# graham Graham-Bayesian (A Plan for Spam)
# burton Burton-Bayesian (SpamProbe)垃圾邮件探测
# robinson Robinson的几何平均值测试 (已经过时)
# chi-square Fisher-Robinson的chi-square算法
备注:你可以同时使用多种算法规则,推荐使用Bayesian算法或chi-square算法
  
Tokenizer chain
指定tokenizer使用,
更多DSPAM分词技术详情,请参考: http://blog.dspam.org.cn/post-3.html
tokenizer负责将邮件解析成单独的标记。你需要在资源多少与准确性之间权衡,可以选择使用较少或更详细的tokenizer,新安装一般推荐使用 "osb" ,可用选项:
# word uniGram tokenizer(单词分割)
将邮件分割成words/tokens,例如: "free" and "viagra"
# chain biGram tokenizer(组合词分割),系统默认设置
Single words + chains
例如:"free" and "viagra" and "free viagra"
# sbph   Sparse Binary Polynomial Hashing (稀疏二元多项式哈希)
该方法的分类准确度较高,但特征数量庞大、计算复杂度很高。
例如:"the quick * fox jumped" and "the * * fox jumped"
# obs    Orthogonal Sparse biGram (正交稀疏双词法)
类似于SBPH,仅使用biGrams。
例如: "the * * fox" and "the * * * jumped"

PValue bcr
指定用于计算概率值的技术,忽略任何默认配置。这些选项包括:
# bcr      Bayesian Chain Rule (Graham's Technique - "A Plan for Spam")
# robinson    Robinson's Technique (使用chi-Square)
# markov      马尔可夫权重技术(参考 Markovian discrimination)
备注:
Markovian discrimination是一种垃圾邮件的过滤方法,使用的短语和句子发生的概率来决定一封邮件是否为垃圾邮件或正常邮件,Markovian过滤被比贝叶斯过滤器更有效,仅使用词语,忽略上下文在一个句子发生的概率。

WebStats on
启用DSPAM的统计信息,启用后,统计信息会写入 $USER.stats 文件

#ImprobabilityDrive on
计算ham/spam的比率,并且会在邮件头增加 X-DSPAM-Improbability

Preference
选项设置
除非由用户(参见AllowOverride部分)或default.prefs文件覆盖。如果找到用户的优先级或default.prefs,用户的首选项将优先于默认值。
下面列出几个比较重要的选项,其他的请自行参考dspam.conf配置文件 
Preference "trainingMode=TEFT"      训练模式
Preference "spamAction=quarantine"  遇到垃圾邮件的处理方式(quarantine:扔到隔离区,tag:给邮件Subject增加标记,deliver:直接投递)
Preference "spamSubject=[SPAM]"     tag操作的时候在邮件Subject前面增加标记
Preference "enableWhitelist=on"     使用自动白名单
Preference "whitelistThreshold=10"  自动白名单的阀值
Preference "signatureLocation=message"  在邮件中标记签名,用作重新训练,可以设置(message | headers )

AllowOverride
指定用户首选项,可能会覆盖默认的配置和命令行的配置,不受信任的用户的首选项将被忽略。

mysql_drv需要知道如何连接到你的MySQL数据库
#MySQLServer            /var/lib/mysql/mysql.sock
#MySQLPort
#MySQLUser              dspam
#MySQLPass              changeme
#MySQLDb                dspam
#MySQLCompress          true
#MySQLReconnect         true
如果你使用MySQL >= 5.0.13 和有问题的DSPAM连接到 MySQL ,请设置MySQLReconnect为true,让mysql_drv尝试重新建立无效的连接或死连接。如果想要通过 TCP 连接,请设置MySQL 服务器的 IP 地址和端口。

#MySQLWrite 选项
如果使用的是集群复制,可以指定一个单独的服务器来执行所有写入。
#MySQLWriteServer       /var/lib/mysql/mysql.sock
#MySQLWritePort
#MySQLWriteUser         dspam
#MySQLWritePass         changeme
#MySQLWriteDb           dspam_write
#MySQLCompress          true
#MySQLReconnect         true

#MySQLReadSignaturesFromWriteDb on
如果你的同步不是实时,如果没有找到签名,重新训练可能会失败,一个解决办法是,给所有的签名读取写数据库:

#MySQLConnectionCache   10
如果你正在client/server(daemon)模式下运行DSPAM,取消注释,来设置连接缓冲的大小(服务器和客户端之间的连接数),连接缓存表示数据库连接的最大数*可用的*可能会有的最大并发数来设置,每个连接只能被一个线程使用,其他所有的线程将被阻塞,直到另一个连接可用。

#MySQLSupressQuote      on
如果你有mysql4.1 quote bug,使用这个,DSPAM-3.10已经放弃这个选项

#MySQLVirtualTable          dspam_virtual_uids
#MySQLVirtualUIDField       uid
#MySQLVirtualUsernameField  username
如果你使用vpopmail或其他类型的虚拟工具,并希望改变dspam执行username/uid 的表查询,可以覆盖他。

#MySQLUIDInSignature    on
MySQL支持用户id插入DSPAM签名,可以创建一个单一的垃圾邮件或fp别名(指向任意用户),签名中的uid会切换到正确的用户,你只需要一个垃圾邮件别名。

备注:
PostgreSQL的选项请参考MySQL部分,SQLite、Hash、LDAP请自行参考dspam.conf.default

#IgnoreHeader
忽略邮件头:
如果DSPAM在其他工具之后,可以对传入的邮件添加一个邮件头,它可能是有利的,可以忽略这些邮件头,特别是他们来自另一个垃圾邮件过滤器。如果你没有使用这些工具,然而,把适当的邮件头注释掉,使得DSPAM能够借此来检查是否有伪造邮件的迹象。
更多IgnoreHeader参数请参考: http://blog.dspam.org.cn/post-26.html

#Lookup "sbl.yourdomain.com"
使用RBLs功能,不推荐使用,因为他们往往不准确。

#RBLInoculate off
如果你想使用其它RBL'd的接种信息,设置为on

Notifications   off
通告:向用户发送邮件通知(第一条信息、隔离全部、等等。)

#TxtDirectory /var/lib/dspam/txt
保存通知邮件的目录和标记(参考 tagSpam/tagNonspam)

#QuarantineWarnSize 2097152
DSPAM给每个用户发送"Quarantine Full"的邮件时,如果启用了通知,可以指定一个大小(见上文)。该值以字节为单位。默认值为 2097152-> 2 MB。

PurgeSignatures 14          # Stale signatures
PurgeNeutral    90          # Tokens with neutralish probabilities
PurgeUnused     90          # Unused tokens
PurgeHapaxes    30          # Tokens with less than 5 hits (hapaxes)
PurgeHits1S     15          # Tokens with only 1 spam hit
PurgeHits1I     15          # Tokens with only 1 innocent hit
清理配置:设置dspam_clean的清除默认选项,如果不是以其他方式在命令行上指定。

#PurgeSignature off     # Specified in purge.sql
#PurgeNeutral   90
#PurgeUnused    off     # Specified in purge.sql
#PurgeHapaxes   off     # Specified in purge.sql
#PurgeHits1S    off     # Specified in purge.sql
#PurgeHits1I    off     # Specified in purge.sql
使用purge.sql清除基于SQL的配置

LocalMX 127.0.0.1
用于源地址跟踪,告诉DSPAM哪些邮件交换是本地的,因此跟踪邮件来源的头在收到时应该被忽略。注意:你使用的主机地址出现在邮件头的[]中。默认情况下,DSPAM考虑下面的IP地址为LocalMX:
#       10.0.0.0/8      - Private IP addresses (RFC 1918)
#       127.0.0.0/8     - Localhost Loopback Address (RFC 1700)
#       169.254.0.0/16  - Zeroconf / APIPA (RFC 3330)
#       172.16.0.0/12   - Private IP addresses (RFC 1918)
#       192.168.0.0/16  - Private IP addresses (RFC 1918)

SystemLog on
UserLog   on
日志记录
禁用用户日志,将无法使用这些图表。
禁用系统日志,将无法使用管理图表

#TrainPristine on
此选项会导致DSPAM停止所有邮件的签名和写入DSPAM信息到邮件头,不要使用这个开关,除非原来提交的邮件可以再培训,并且原来的邮件头没有任何修改。

Opt out
DSPAM 默认的过滤行为,如果值设置为in,用户必须添加一个 .dspam文件到/var/dspam/opt-in/目录,并命名user.dspam文件才能实现过滤。默认值是opt-out,意味着所有用户都将被过滤,除非将 /var/dspam/opt-out/user.nodspam文件删除。

#TrackSources spam nonspam virus
指定(如果有的话)源地址,跟踪并报告给syslog(mail.info)。如果你运行防火墙或黑名单想要这个信息,这是非常有用的。垃圾邮件报告同时列入RABL( Reactive Autonomous Blackhole List)黑名单文件。

#ParseToHeaders on
解析为:接收邮件的头。这必须设置为'on',才能使用下列功能。

#ChangeModeOnParse on
自动改变类型(spam or innocent)取决于spam或notspam 是否被指定,并更改来源为'error' ,如果你没有使用别名,而是通过LMTP发送,这倒是很方便。

#ChangeUserOnParse full
自动更改用户名,来匹配指定的邮件头。例如:spam-bob@example.org设置用户名为bob,将会忽略任何用户通过。如果你使用虚拟的邮件地址作为用户名,这不一定是可取的,选项:
on or user   @符号之前的部分
full               完整的邮件地址

#Broken returnCodes
指定'returnCodes',如果是垃圾邮件,会导致DSPAM返回一个99的退出代码,如果不是垃圾邮件,就返回0,如果发生错误,就是负数代码

#Broken case
指定'case',强制DSPAM输入的用户名为小写字母。

#Broken lineStripping 
指定'lineStripping',DSPAM删除信息中的^M字符 

#MaxMessageSize 4194304
指定DSPAM处理的信息大小。如果邮件大于该值,它将不能处理。值以字节为单位。

#ClamAVPort     3310
#ClamAVHost     127.0.0.1
#ClamAVResponse accept
如果你运行的是clamd , DSPAM使用TCP为基础的病毒检查,注释以下值,使用病毒检查。
#ClamAVResponse选项:
reject         (拒绝或停止失败的消息)。
accept         (接受消息或悄悄的接受消息)
spam         (处理垃圾邮件的方式 quarantine/tag/whatever) 

#ServerHost             127.0.0.1
#ServerPort             24
#ServerQueueSize        32
#ServerPID              /var/run/dspam.pid 
如果你使用--daemon将DSPAM作为一台daemonized服务器,上面的参数将覆盖默认值。使用ServerPass选项,可以为每个客户机设置帐户。DSPAM服务器基于该参数处理和投递消息。

#ServerMode dspam
指定要启动的LMTP服务器的类型:
dspam:            DSPAM专有的DLMTP服务器,用于和dspamc进行通信
standard:         标准的LMTP服务器,用于和postfix或其它MTA通信
auto:              DLMTP 和 LMTP; 自动检测ServerPass.IDENT

#ServerPass.Relay1      "secret"
#ServerPass.Relay2      "password"
如果支持DLMTP(dspam)模式,dspam客户端将需要验证,因为它们要作为传递参数。上面的idents将用来确定哪些客户会说DLMTP ,如果你使用的LMTP和DLMTP来自同一台主机,请使用下面服务器主机名以外的(由MTA发送一个标准的LMTP LHLO ) 

#ServerParameters        "--deliver=innocent -d %u"
--deliver=innocent,意思是只发送认为正常的信件,垃圾邮件将被截留(投递到隔离区)。

#ServerIdent             "localhost.localdomain"
如果支持标准LMTP模式,服务器参数需要指定这里,因为他们将不会通过邮件服务器。该ServerIdent指定响应码为250的ident连接客户端,应设置为你的服务器的主机名或别名。

#ServerDomainSocketPath  "/var/run/dspam/dspam.sock"
如果你想使用socket,而不是一个TCP,注释以下内容。如果你的客户端和服务器运行在同一台机器上,强烈建议你使用socket,因为它节约了很多带宽的开销。

#ClientHost     /var/run/dspam/dspam.sock
#ClientIdent    "secret@Relay1"
或者
#ClientHost     127.0.0.1
#ClientPort     10028
#ClientIdent    "secret@Relay1"
如果你运行的DSPAM是在client/server模式,取消注释并设置这些参数。一个ClientHost开头的将被视为一个dspam.sock。

#RABLQueue      /var/spool/rabl
建立RABL( Reactive Autonomous Blackhole List)队列文件,如果报告一个流式的blackhole名单,可以使用rabl_client进程监视目录内的IP地址。 

#DataSource      document
如果你使用任何类型的数据里面不包括邮件一样的头(如文件),注释以下行,这将导致整个输入被当作一条消息

#ProcessorWordFrequency  occurrence
处理单词频率,默认情况下,单词在每封邮件中只统计一次。如果你分类大文件,你可能希望每出现一次就计算一次。

ProcessorURLContext on
处理 URL 上下文,默认情况下,一个URL上下文生成的URLs,它作为单独的文件记录了他们的tokens。如果要在同一上下文使用URL tokens,关闭此功能。

ProcessorBias on
偏好导致过滤器更倾向于'innocent' ,通常大大降低了误报。它是大多数贝叶斯过滤器(包含DSPAM)的默认行为
注意:你可能不希望这样,可以使用“Markovian Weighting”,除非你怀疑误报。

#StripRcptDomain off
从收件人剪切域(包括签名)。这是特别有用,如果收件人的名字等于实际用户帐户,作为收件人和域往往会导致与dspam-web的权限问题。

#GroupConfig /var/lib/dspam/group
组的配置文件,如何让用户能够结合他们的训练数据,以得到更好的结果。请参阅README文件的详细信息。

#Include /etc/dspam/dspam.d/
包括配置项的目录,支持拆分配置文件。

centos7 yum install redis 最新版本

直接yum 安装的redis 不是最新版本

yum install redis
如果要安装最新的redis,需要安装Remi的软件源,官网地址:http://rpms.famillecollet.com/

yum install -y http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
然后可以使用下面的命令安装最新版本的redis:

yum --enablerepo=remi install redis

安装完毕后,即可使用下面的命令启动redis服务

service redis start 或者 systemctl start redis

redis安装完毕后,我们来查看下redis安装时创建的相关文件,如下:
rpm -qa |grep redis
rpm -ql redis

查看redis版本:
redis-cli --version

设置为开机自动启动:
chkconfig redis on 或者 systemctl enable redis.service
Redis开启远程登录连接,redis默认只能localhost访问,所以需要开启远程登录。解决方法如下:

在redis的配置文件 /etc/redis.conf 中

将bind 127.0.0.1 改成了 bind 0.0.0.0

然后要配置防火墙 开放端口6379

连接redis

redis-cli


另外:
redis 3.2后新增protected-mode配置,默认是yes,即开启。

解决方法分为两种:
1、设置 protected-mode 为 no
2、配置bind或者设置密码

测试的时候我使用了配置bind 方式,没有加密码,正式生产环境可以使用加密码方式。

CentOS 最简单的安装 node 8.x 方式

安装之前删除原来的node和npm (我原来是用yum安装的,如果是第一次安装可以省略这一步):

yum remove nodejs npm -y
cd /usr/share/
wget https://npm.taobao.org/mirrors/node/v8.11.3/node-v8.11.3-linux-x64.tar.gz
sudo tar -xvf node-v8.11.3-linux-x64.tar.gz
chown -R root:root node-v8.11.3-linux-x64
cd node-v8.11.3-linux-x64/bin && ls 

这个时候我们测试:

./node -v
./npm -v

这里还是,如果我们之前已经安装过了,那么我们要先删除之前建立的链接文件:

sudo rm -rf /usr/bin/node
sudo rm -rf /usr/bin/npm

然后建立链接文件:

sudo ln -s /usr/share/node-v8.11.3-linux-x64/bin/node /usr/bin/node
sudo ln -s /usr/share/node-v8.11.3-linux-x64/bin/npm /usr/bin/npm

注意这里的第一个路径不要直接复制粘贴,要写当前文件的真正的路径,这个可以通过pwd获取。

然后我们可以通过node -v    npm -v等测试已经安装成功。

MySQL从5.7.21升级到8.0.11的更新之路

MySQL从5.7.21升级到8.0.11

my.cnf配置的一些关健点,说明一下

Symbolic links现在默认就是禁用了,无需再去标记禁用了,如果你标记的话,会有个提醒:

'Disabling symbolic links using --skip-symbolic-links (or equivalent) is the default. Consider not using this option as it' is deprecated and will be removed in a future release.

再有就是“expire-logs-days”参数已经没有了,取而代之的是“binlog_expire_logs_seconds”,如名,单位是秒,不要搞错了。

据说,purge方式也不一样,但我没细究,回头看看。错误提示如下:

The syntax 'expire-logs-days' is deprecated and will be removed in a future release. Please use binlog_expire_logs_seconds instead.

SQL Mode的NO_AUTO_CREATE_USER也没有了。

In MySQL 8.0.11, several deprecated features related to account management have been removed, such as use of the GRANT statement to modify nonprivilege characteristics of user accounts, the NO_AUTO_CREATE_USER SQL mode, the PASSWORD() function, and the old_passwords system variable.

Using GRANT to create users. Instead, use CREATE USER. Following this practice makes the NO_AUTO_CREATE_USER SQL mode immaterial for GRANT statements, so it too is removed.

实际应用时,发现不用加密手段,根本登录不上MySQL(比如用phpMyAdmin等就不行,用命令行就没事)。

查了下,发现是MySQL 8.0改了默认加密方式为“caching_sha2_password”:

In MySQL 8.0, caching_sha2_password is the default authentication plugin rather than mysql_native_password.

咋整?那就改回来呗,改回“mysql_native_password”。

default_authentication_plugin=mysql_native_password

另外MySQL的X Plugin默认跟随启动,作用我还没具体了解,早在5.7就有了,但一直没用它。

跟随启动后,如果你是用socket,它会在相同目录生成mysqlx.sock。并且他的连接方式强制要SSL,至少第一次要,如果我没理解错,官方是这么写的:

This means that the first use of an account must be done using an SSL connection with the X Plugin authentication cache enabled. Once this initial authentication over SSL has succeeded non-SSL connections can be used.

所以你也能在日志文件看到告警,如果你没有配置SSL的话:

Plugin mysqlx reported: 'Failed at SSL configuration: "SSL context is not usable without certificate and private key"

文档虽说mysqlx-ssl与ssl相等,但mysqlx-ssl=0或者skip、disabled都没用。并无办法禁用这一警告,如果谁知道方法和文档位置,麻烦告知下,谢谢。

而且这个的实际应用能有多少,也是个疑问。

之前说MySQL已经不用MyISAM存储了。确实没错,核心引擎已经不再使用MyISAM了,改为InnoDB了。但MyISAM引擎仍然是可用的,但是有限支持,具体可以看文档,传送门

In MySQL 8.0, it is normally necessary to use ENGINE to specify the MyISAM storage engine because InnoDB is the default engine.

In MySQL 8.0, the MyISAM storage engine provides no partitioning support. Partitioned MyISAM tables created in previous versions of MySQL cannot be used in MySQL 8.0. For more information, see Section 23.6.2, “Partitioning Limitations Relating to Storage Engines”.

其实想知道MySQL怎么禁用MyISAM这些插件,像MariaDB很容易禁用,给MySQL配上禁用参数,只会提示不认识这个参数。。

还有现在utf8mb4默认编码使用的是utf8mb4_0900_ai_ci,据说有优化,先用着看看有没有坑吧。。。

十分推荐升级,性能和效率提升很多。其他坑暂时没遇到过,正在尝试调优。

好了,就先简单说到这,其他需要补充的,后续再补充。

MySQL 8.0之前的版本,当使用--all-databases 参数导出数据的时候,不加--routines和--events选项也可以导出触发器、存储过程等信息,因为这些信息都存放于proc和event表中,导出所有表即可导出这些信息。

但是在MySQL 8.0中,proc表和event表都不再使用,并且定义触发器、存储过程的数据字典表不会被导出。所以在8.0中使用mysqldump、mysqlpump导出数据的时候,如果需要导出触发器、存储过程等内容,一定需要加上--routines和--events选项。

Centos7 选定默认启动内核,及删除无用内核

#使用cat /boot/grub2/grub.cfg |grep menuentry  查看系统可用内核

[root@bigapp-slave27 ~]# cat /boot/grub2/grub.cfg |grep menuentry

if [ x"${feature_menuentry_id}" = xy ]; then

  menuentry_id_option="--id"

  menuentry_id_option=""

export menuentry_id_option

menuentry 'CentOS Linux (3.10.0-514.16.1.el7.x86_64) 7 (Core)' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-327.el7.x86_64-advanced-6f5840d0-55ac-4d3b-899b-61c0297c5347' {

menuentry 'CentOS Linux (3.10.0-327.el7.x86_64) 7 (Core)' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-327.el7.x86_64-advanced-6f5840d0-55ac-4d3b-899b-61c0297c5347' {

menuentry 'CentOS Linux (0-rescue-d57307c454c0437d91c309347178cdf5) 7 (Core)' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-0-rescue-d57307c454c0437d91c309347178cdf5-advanced-6f5840d0-55ac-4d3b-899b-61c0297c5347' {

 

#查看当前内核

[root@bigapp-slave27 ~]# uname -r

3.10.0-514.16.1.el7.x86_64

 

#修改开机时默认使用的内核

grub2-set-default 'CentOS Linux (3.10.0-327.el7.x86_64) 7 (Core)'

 

#查看内核修改结果

[root@bigapp-slave27 ~]# grub2-editenv list

saved_entry=CentOS Linux (3.10.0-327.el7.x86_64) 7 (Core)

 

#查看系统安装了哪些内核包

[root@bigapp-slave27 ~]# rpm -qa | grep kernel

kernel-3.10.0-327.el7.x86_64

kernel-headers-3.10.0-514.6.1.el7.x86_64

kernel-tools-libs-3.10.0-327.el7.x86_64

kernel-3.10.0-514.16.1.el7.x86_64

kernel-tools-3.10.0-327.el7.x86_64

 

#使用yum remove 或rpm -e 删除无用内核

yum remove kernel-3.10.0-693.11.1.el7.x86_64

通过yum update 升级报错 Error: initscripts conflicts with centos-release-7-4.1708.el7.centos.x86_64 解决方法

通过yum update 升级报错 Error: initscripts conflicts with centos-release-7-4.1708.el7.centos.x86_64 解决方法

[root@localhost ~]# yum update
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
 * base: mirrors.aliyun.com
 * extras: mirrors.cn99.com
 * updates: mirrors.cn99.com
Resolving Dependencies
--> Running transaction check

......此处省略......

--> Running transaction check
---> Package lz4.x86_64 0:1.7.5-2.el7 will be installed
--> Processing Conflict: initscripts-9.49.41-1.el7.x86_64 conflicts redhat-release < 7.5-0.11
--> Finished Dependency Resolution
Error: initscripts conflicts with centos-release-7-4.1708.el7.centos.x86_64
 You could try using --skip-broken to work around the problem
 You could try running: rpm -Va --nofiles --nodigest

编译 vi /et/yum.conf

# PUT YOUR REPOS HERE OR IN separate files named file.repo                                               
# in /etc/yum.repos.d                                                                                    
#exclude=centos-release*                                                                                 
#exclude=kernel* centos-release*     -------------- > 这条注释掉

git自动化部署之webhooks的使用(php版本)

在github的webhooks中设定对应信息
设定要请求的服务器命令调用地址, 如: http://itsns.net.cn/webhooks
设定密钥key, 如: ABCDEFAAKEYM
在服务器上编写对应的命令(纯PHP代码)
编写 http://itsns.net.cn/webhooks 请求的方法如下:

<?php
// GitHub Webhook Secret.
// Keep it the same with the 'Secret' field on your Webhooks / Manage webhook page of your respostory.
$secret = "";
// 项目根目录, 如: "/var/www/webbbs"
$path = "";
// Headers deliveried from GitHub
$signature = $_SERVER['HTTP_X_HUB_SIGNATURE'];
if ($signature) {
  $hash = "sha1=" . hash_hmac('sha1', $HTTP_RAW_POST_DATA, $secret);
  if (strcmp($signature, $hash) == 0) {
      echo shell_exec("cd {$path} && /usr/bin/git reset --hard origin/master && /usr/bin/git clean -f && /usr/bin/git pull 2>&1");
      exit();
  }
}
http_response_code(404);

命令说明:

shell_exec("cd {$path} && /usr/bin/git reset --hard origin/master && /usr/bin/git clean -f && /usr/bin/git pull 2>&1");

/usr/bin/git reset --hard origin/master 强制恢复版本到前一个稳定版
/usr/bin/git clean -f 清理提交的更改
/usr/bin/git pull 2>&1 拉取最新的版本到本地

也可以调用本地脚本,创建shell脚本文件webhooks.sh, 并写入:

#!/bin/bash

WEB_PATH='/var/www/webbbs'
WEB_USER='nginx'
WEB_USERGROUP='nginx'

echo "Start deployment"
cd $WEB_PATH
echo "pulling source code..."
git reset --hard origin/master
git clean -f
git pull
git checkout master
echo "changing permissions..."
chown -R $WEB_USER:$WEB_USERGROUP $WEB_PATH
echo "Finished."

 

freebsd兼容linux

11.2 Installation

Linux® libararies are not installed on FreeBSD by default and Linux binary compatibility is not enabled by default. Linux libraries can be installed using the FreeBSD Ports Collection. Alternately, Linux libraries can be installed manually.

Using the Ports Collection is by far the easiest way to install Linux libraries:

# cd
/usr/ports/emulators/linux_base-f10# make install distclean

Once the port is installed, enable Linux binary compatibility by loading the linux module. Type the following as root:

# kldload linux

In order for Linux compatibility to always be enabled at boot time, add the following line to /etc/rc.conf:

linux_enable="YES"

To verify that the module is loaded, use kldstat(8):

% kldstat
Id Refs Address    Size     Name
 1    2 0xc0100000 16bdb8   kernel
 7    1 0xc24db000 d000     linux.ko

Users who prefer to statically link Linux binary compatibility into the kernel should add options COMPAT_LINUX to the custom kernel configuration file. Compile and install the new kernel as described in .

11.2.1 Installing Libraries Manually

While using the Ports Collection is recommended, Linux libraries can be installed manually. The Linux shared libraries required by a program and the runtime linker should be copied to /compat/linux. Any shared libraries opened by Linux programs run under FreeBSD will look in this directory first. For example, if a Linux program loads /lib/libc.so, FreeBSD will first try to open /compat/linux/lib/libc.so, and if that does not exist, it will then try /lib/libc.so. Shared libraries should be installed to /compat/linux/lib rather than to the paths that the Linux ld.so reports.

Generally, one will need to look for the shared libraries that Linux binaries depend on only the first few times that a Linux program is installed on FreeBSD. After a while, there will be a sufficient set of Linux shared libraries on the system to be able to run newly imported Linux binaries without any extra work.

11.2.1.1 How to Install Additional Shared Libraries

If the linux_base port is installed and an application still complains about missing shared libraries, there are two methods root can use to determine which shared libraries the Linux binaries need.

If a Linux system is available, determine which shared libraries the application needs, and copy them to the FreeBSD system.

In this example, FTP was used to download the Linux binary of Doom on a Linux system . To check which shared libraries it needs, run ldd linuxdoom:

% ldd linuxdoom
libXt.so.3 (DLL Jump 3.1) => /usr/X11/lib/libXt.so.3.1.0
libX11.so.3 (DLL Jump 3.1) => /usr/X11/lib/libX11.so.3.1.0
libc.so.4 (DLL Jump 4.5pl26) => /lib/libc.so.4.6.29

Copy all the files in the last column into /compat/linux on the FreeBSD system, with the names in the first column as symbolic links pointing to them. This example will result in the following files on the FreeBSD system:

/compat/linux/usr/X11/lib/libXt.so.3.1.0
/compat/linux/usr/X11/lib/libXt.so.3 -> libXt.so.3.1.0
/compat/linux/usr/X11/lib/libX11.so.3.1.0
/compat/linux/usr/X11/lib/libX11.so.3 -> libX11.so.3.1.0
/compat/linux/lib/libc.so.4.6.29
/compat/linux/lib/libc.so.4 -> libc.so.4.6.29

Note: If a Linux shared library already exists with a matching major revision number to the first column of the ldd output, it does not need to be copied to the file named in the last column, as the existing library should work. It is advisable to copy the shared library if it is a newer version, though. The old one can be removed, as long as the symbolic link points to the new one. For example, these libraries exist on the system:

/compat/linux/lib/libc.so.4.6.27
/compat/linux/lib/libc.so.4 -> libc.so.4.6.27

and a binary claims to require a later version according to the output of ldd:

libc.so.4 (DLL Jump 4.5pl26) -> libc.so.4.6.29

If it is only one or two versions out of date in the trailing digit, do not worry about copying /lib/libc.so.4.6.29, because the program should work fine with the slightly older version. However, it is safe to replace the libc.so:

/compat/linux/lib/libc.so.4.6.29
/compat/linux/lib/libc.so.4 -> libc.so.4.6.29

Note: The symbolic link mechanism is only needed for Linux binaries as the FreeBSD runtime linker takes care of looking for matching major revision numbers.

11.2.2 Installing Linux® ELF Binaries

ELF binaries sometimes require an extra step of “branding”. If an unbranded ELF binary is executed, it will generate an error message like the following:

% ./my-linux-elf-binary
ELF binary type not known
Abort

To help the FreeBSD kernel distinguish between a FreeBSD ELF binary and a Linux binary, use brandelf(1):

% brandelf -t Linux my-linux-elf-binary

Since the GNU toolchain places the appropriate branding information into ELF binaries automatically, this step is usually not necessary.

11.2.3 Installing a Linux RPM Based Application

FreeBSD uses its own package database to track all software installed from the Ports Collection. However, the Linux RPM database is not supported.

In order to install a Linux RPM-based application, first install the archivers/rpm2cpio package or port. Once installed, root can use this command to install a .rpm as follows:

# cd /compat/linux# rpm2cpio -q < /path/to/linux.archive.rpm | cpio -id

If necessary, brandelf the installed ELF binaries, but not the libraries. Note that this will prevent a clean uninstall.

11.2.4 Configuring the Hostname Resolver

If DNS does not work or this error appears:

resolv+: "bind" is an invalid keyword resolv+:
"hosts" is an invalid keyword

Configure /compat/linux/etc/host.conf as follows:

order hosts, bind
multi on

This order specifies that /etc/hosts is searched first and DNS is searched second. When /compat/linux/etc/host.conf does not exist, Linux applications use /etc/host.conf and complain about the incompatible FreeBSD syntax. Remove bind if a name server is not configured using /etc/resolv.conf.

centos 7 部署升级 gitlab-ce-10.*.* 提示 error: Failed dependencies:

10.x以后开始依赖policycoreutils-python,我之前在使用9.x时还没有依赖该项

升级时会提示

rpm -Uvh gitlab-ce-10.1.0-ce.0.el7.x86_64.rpm                                               
warning: gitlab-ce-10.1.0-ce.0.el7.x86_64.rpm: Header V4 RSA/SHA1 Signature, key ID f27eab47: NOKEY
error: Failed dependencies:
        policycoreutils-python is needed by gitlab-ce-10.1.0-ce.0.el7.x86_64

安装gitlab的依赖项

yum install policycoreutils-python

CentOS7下编译安装pure-ftpd+mysql 认证

pure-ftpd,一个很好用的ftp服务端。可以和mysql整合,通过mysql建立和验证帐户,并实现流量限制、磁盘配额限制等功能。这就说明,可以通过自己开发的PHP程序来实现Web管理。其它的功能,大家可以到官网上去看。

1、需要安装以下支持

sudo rpm -ivh http://repo.mysql.com/mysql57-community-release-el7.rpm
yum install –y mysql-community-devel
yum install –y pam-devel

2、下载pure-ftpd最新的源码,解压进入源码目录

wget https://download.pureftpd.org/pub/pure-ftpd/releases/pure-ftpd-1.0.47.tar.gz

解压:tar pure-ftpd-1.0.47.tar.gz

3、编译参数

#cd pure-ftpd-1.0.45/

./configure \
--prefix=/usr/local/pureftpd/ \
--with-everything \
--with-sysquotas \
--with-altlog \
--with-puredb \
--with-extauth \
--with-pam \
--with-cookie \
--with-throttling \
--with-ratios \
--with-quotas \
--with-ftpwho \
--with-welcomemsg \
--with-uploadscript \
--with-virtualhosts \
--with-virtualchroot \
--with-diraliases \
--with-nonroot  \
--with-peruserlimits \
--with-language=english \
--with-mysql

 

编译项的解释说明

--prefix =/usr/local/pureftpd/	#安装路径,例如:/usr/local/pureftpd
--with-sysquotas \			#使用系统磁盘配额 ( 非虚拟)
--with-altlog \				#支持选择日志格式( 类似Apache)
--with-puredb \				#支持虚拟用户 ( FTP登陆用户而非系统用户)
--with-extauth \			#支持扩展验证模块
--with-pam \				#启用PAM验证支持 ( 默认=禁用)
--with-cookie \				#启用Cookie支持 ( -F 选项)
--with-throttling \			#支持带宽控制 ( 默认=禁用)
--with-ratios \				#支持 上传/ 下载 速度控制
--with-quotas \				#支持 .ftpquota 文件(指定磁盘配额使用)
--with-ftpwho \				#支持pure-ftpwho(查看在线用户的程序)
--with-welcomemsg \			#支持 welcome.msg 向后兼容(已经过时)
--with-uploadscript \		#上传后允许执行外部脚本 ( 测试阶段)
--with-virtualhosts \		#在不同的IP地址提供虚拟服务器功能
--with-virtualchroot \		#允许在chroot 的环境下通过符合连接跳转到外部
--with-diraliases \			#启用目录别名
--with-nonroot  \			#普通模式或者说是限制模式. 如果你在该服务器上没有root权限那只有启用该项
--with-peruserlimits \     #支持每个用户的并发限制
--with-language=simplified-chinese \        #语言支持< english | traditional-chinese | simplified-chinese>
--with-ldap			#在LDAP目录中提供用户数据库
--with-mysql \		#在MySQL数据库中存放用户数据
--with-pgsql		#在PostgreSQL数据库中存放用户数据
--with-everything	#安装几乎所有的功能,包括altlog、cookies、throttling、ratios、ftpwho、upload script、virtual
					#users(puredb)、quotas、virtual hosts、directory aliases、external authentication、Bonjour
					#privilege separation。

然后加入系统服务来启动

#改变权限

chown root.root /etc/rc.d/init.d/pureftpd #所有用户都可以执行单只有root可以修改
chmod +x /etc/rc.d/init.d/pureftpd #将pureftpd 放入linux启动管理体系中
chkconfig --add pureftpd #打开自启动
chkconfig pureftpd on

 

#相关使用命令

service pureftpd start  #启动服务
#pureftpd 启动脚本
#!/bin/sh
#chkconfig: 2345 80 90
#description:pureftpd
/usr/local/pureftpd/sbin/pure-ftpd /usr/local/pureftpd/etc/pure-ftpd.conf&

当然你也可以直接用源安装方式

yum -y install pure-ftpd

设置开机启动

systemctl start  pure-ftpd.service
systemctl enable pure-ftpd.service

GIT 升级步骤讲解

GIT 升级步骤讲解。

 

       *.                  *.
      ***                 ***
     *****               *****
    .******             *******
    ********            ********
   ,,,,,,,,,***********,,,,,,,,,
  ,,,,,,,,,,,*********,,,,,,,,,,,
  .,,,,,,,,,,,*******,,,,,,,,,,,,
      ,,,,,,,,,*****,,,,,,,,,.
         ,,,,,,,****,,,,,,
            .,,,***,,,,
                ,*,.

     _______ __  __          __
    / ____(_) /_/ /   ____ _/ /_
   / / __/ / __/ /   / __ `/ __ \
  / /_/ / / /_/ /___/ /_/ / /_/ /
  \____/_/\__/_____/\__,_/_.___/
这里下载GitLab 最新包:https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/
停止服务
gitlab-ctl stop

gitlab-ctl restart postgresql       #升级或备份必须要启动 postgresql 

备份数据
gitlab-rake gitlab:backup:create

安装升级包
rpm -Uvh gitlab-ce-8.16.4-ce.0.el7.x86_64.rpm

升级命令
gitlab-ctl pg-upgrade

重新加载配置
gitlab-ctl reconfigure

启动服务
gitlab-ctl restart

停止服务
gitlab-ctl stop

unzip xxxx.zip
备份汉化目录
cp -rf /opt/gitlab/embedded/service/gitlab-rails/  /home/gitlab-rails

拷贝汉化文件
\cp  ./gitlab-zh/*  /opt/gitlab/embedded/service/gitlab-rails/  -rf
这里下载汉化包,要对应相关版本。
https://gitlab.com/xhang/gitlab

CentOS Linux ulimit -n 设置永久生效

      通过ulimit -n命令可以查看linux系统里打开文件描述符的最大值,一般缺省值是1024,对一台繁忙的服务器来说,这个值偏小,所以有必要重新设置linux系统里打开文件描述符的最大值。

      这个值可用ulimit 命令来修改,如:ulimit -n 65535。但ulimit命令修改的数值只对当前登录用户的目前使用环境有效,系统重启或者用户退出后就会失效。

      永久生效需要进行下面设置:

      vi /etc/security/limits.conf

      追加如下内容:

      * soft nofile 65535
      * hard nofile 65535

     其中 * 代表所有用户。

     重新登录,通过ulimit -n 或者 ulimit -a 查看是否生效

Linux 下批量替换文件内容脚本

#!/bin/bash
OLD="ABCDEF"
NEW="123456"
DPATH="/home/you/foo/*.txt"
BPATH="/home/you/bakup/foo"
TFILE="/tmp/out.tmp.$$"
[ ! -d $BPATH ] && mkdir -p $BPATH || :
for f in $DPATH
do
  if [ -f $f -a -r $f ]; then
    /bin/cp -f $f $BPATH
   sed "s/$OLD/$NEW/g" "$f" > $TFILE && mv $TFILE "$f"
  else
   echo "Error: Cannot read $f"
  fi
done
/bin/rm $TFILE

以上代码,将文件 ABCDEF 字符,替换成 123456

linux下查找某目录下所有文件包含某字符串的命令

#从文件内容查找匹配指定字符串的行:
$ grep "被查找的字符串" 文件名

#从文件内容查找与正则表达式匹配的行:
$ grep –e “正则表达式” 文件名

#查找时不区分大小写:
$ grep –i "被查找的字符串" 文件名

#查找匹配的行数:
$ grep -c "被查找的字符串" 文件名

#从文件内容查找不匹配指定字符串的行:
$ grep –v "被查找的字符串" 文件名

#从根目录开始查找所有扩展名为.txt的文本文件,并找出包含"linux"的行
find . -type f -name "*.txt" | xargs grep "linux" 

extmail 密码加密方式修改为plain-md5的方法

extmail默认密码加密方式是md5crypt,但是有些时候会遇到这样的问题——老的邮件系统中的用户密码是md5加密的。

此时需要将extmail的密码加密方式修改为md5,通过官方解释(md5和md5crypt没有区别),修改为plain-md5即可。但是,这只解决了web登陆的验证问题,没有解决smtp以及pop3的验证问题。

通过 http://www.extmail.org/forum/viewthread.php?tid=3175 帖子解决了验证问题,内容摘录如下:

courier-authlibauth_generic手册里提到crypted密码的格式支持3类:

1)传统的crypted 的密码,如crypt()或md5-salted的密码
2){MD5}为前缀,后面是base64编码后的md5密码
3){SHA}为前缀(实际还支持{SAH256},这个看source知道)后面是base64编码的sha密码

如何能实现2呢?在目前的extmail/extman实现里,md5密码只支持以16进制形式存在的密码,例如:

d41d8cd98f00b204e9800998ecf8427e



经过base64编码后依然无法通过authlib的认证,后来仔细看Digest::MD5手册里的介绍,发现md5函数返回的是二进制的、产度为16个字节的密文,而md5_hex(也就是目前extmail/extman使用的)是其16进制的形式(长度32个字节)。

于是测试用md5函数产生md5密文并用base64编码后,加上{MD5}前缀,塞到mysql里,发现通过了authtest的测试!再查看了一下courier-authlib的checkpasswd.c及checkpasswdmd5.c和md5目录下的md5加密函数,证实了就是校验二进制+base64编码后的md5密文,而不是hex后的密文。

问题是如何从hex格式的密文转成binary格式?很多用户从其他系统转到ext*下时,密码大多是md5 hex格式的,于是编写如下代码实现转换:

use MIME::Base64;

my $s = 'd41d8cd98f00b204e9800998ecf8427e';

$s =~ s/(..)/bin($1)/ge;
$s = '{MD5}'.encode_base64($s);
$s =~ s/\s+//; # remove newline

print $s, "\n";

sub bin {
      my $n = shift;
      sprintf("%c", hex($n));
}



这样常规的md5密文就被转成符合要求的{MD5}XXXXX格式了。刚才这个脚本的执行结果:

{MD5}1B2M2Y8AsgTpgAmY7PhCfg==

 

为extmail增加邮件短信通知功能

extmail本身预留了短信提醒的接口,但代码基本没写,于是,花了点时间,实现了收到邮件后短信提示的功能,实现方法大致如下:

1、extmail/html/default/filter.html 文件中MAIL2SMS选项卡部分修改为:

 

    (因草稿中丢失格式,暂时不确定原来的内容,看说明部分,目的是增加一个接收手机号码的文本框。)

 

   

 checked>

 

*说明:在WEBMAIL后台增加一个接收手机号码的输入框。这个手机号码对应变量mail2smsNum

2、extmail/lang/zh_CN 文件中修改一下字符模板,修改”mail2sms”一行,增加”mail2sms_num_error”一行:

mail2sms => ‘启用邮件到达提醒。 手机号码:’,

mail2sms_num_error => ‘输入的用于短信通知的手机号码非法,请重试’,

*说明:可再按此方法处理繁体及英文字符配置文件,”mail2sms_num_error”是在输入的手机号码非法后提供错误反馈用,也可以不做处理。

3、/etc/maildroprc增加发送手机短信的脚本命令:

MAIL2SMS=”/var/www/extsuite/extmail/tools/sendsms.sh”

*说明:具体路径可自己定义,但要注意执行权限

4、增加发送手机短信的脚本,sendsms.sh:

#!/bin/sh

sendsms()

{

;

#发送脚本,可用curl处理

}

#加入其他判断

sendsms “$2″ “$3″;

5、修改extmail/libs/Ext/App/Filter.pm:

第一处,sub extension_list中:

#datahf.net zhangyu edit

my $mail2smsNum = $obj->{mail2smsNum};

MAIL2SMS_NUM => $mail2smsNum,

#end

第二处,extension_mgr中:

if ($q->cgi(‘mail2sms’)) {

$obj->{mail2sms} = 1;

#datahf.net zhangyu edit

my $telnum = $q->cgi(‘mail2smsNum’);

if (!$telnum or $telnum !~ /^1\d{10}$/) {

$self->error($lang_filter{mail2sms_num_error});

return;

}

$obj->{mail2smsNum} = $telnum;

} else {

$obj->{mail2sms} = 0;

$obj->{mail2smsNum} = ”;

}

#add end

6、修改extmail/libs/Ext/MailFilter.pm:

第一处:parse中:

my $mail2smsNum = 0;

elsif ($res =~ /^mail2sms: (.*)/) {

$mail2sms = 1;

$self->{mail2sms} = $mail2sms;

$mail2smsNum = $1;

$self->{mail2smsNum} = $mail2smsNum;

}

第二处,save中:

# datahf.net zhangyu add or edit

if ($self->{mail2sms}) {

$buf1 .= “#*mail2sms: $self->{mail2smsNum}\n”;

$buf1 .= “/^(From|Sender):(.*)/\n”;

$buf1 .= “FROMsms=`\$DECODER \”\$MATCH2\”`\n”;

$buf1 .= “FROMsmsADD=getaddr(\$FROMsms)\n”;

$buf1 .= “/^Subject:(.*)/\n”;

$buf1 .= “SUBJECTsms=`\$DECODER \”\$MATCH1\”`\n”;

$buf1 .= “CONTENT=\”收到来自$FROMsmsADD的新邮件,标题为:\$SUBJECTsms\”\n”;

$buf1 .= “CONTENTgb=`echo \$CONTENT|iconv -f utf-8 -t gb2312`\n”;

$buf1 .= “TELnum=\”$self->{mail2smsNum}\”\n”;

$buf1 .= “`\$MAIL2SMS \$LOGNAME \$TELnum \”\$CONTENTgb\”`\n”;

$buf1 .= “\n”;

}

# end

#extmail的过滤器考虑的问题较为简单,比如一旦加入白名单,便不会后续的过滤了,还有一些小问题,因改动太大,暂且如此。

7、登陆webmail后启用一下短信提示功能,同时输入合法的手机号码(11位以1开头的数字序列),保存即可。

 

Package libqrencode was not found in the pkg-config search path.

cpanm (App::cpanminus) 1.6922 on perl 5.016003 built for x86_64-linux-thread-multi
Work directory is /root/.cpanm/work/1557338319.8927 
You have make /usr/bin/make
You have LWP 6.05
You have /usr/bin/tar: tar (GNU tar) 1.26 
Copyright (C) 2011 Free Software Foundation, Inc.   
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
这是自由软件:您可以自由地更改并重新发布它。   
在法律所允许的范围内不含任何担保。   
  
由 John Gilmore 和 Jay Fenlason 所写。    
You have /usr/bin/unzip    
Searching Text::QRCode on cpanmetadb ...  
--> Working on Text::QRCode
Fetching http://www.cpan.org/authors/id/K/KU/KURIHARA/Text-QRCode-0.05.tar.gz
-> OK  
Unpacking Text-QRCode-0.05.tar.gz    
Entering Text-QRCode-0.05  
Checking configure dependencies from META.yml  
Checking if you have ExtUtils::MakeMaker 6.36 ... Yes (6.68)  
Configuring Text-QRCode-0.05    
Running Makefile.PL   
Cannot determine perl version info from lib/Text/QRCode.pm    
Checking if your kit is complete...  
Looks good  
Package libqrencode was not found in the pkg-config search path.   
Perhaps you should add the directory containing `libqrencode.pc'   
to the PKG_CONFIG_PATH environment variable    
No package 'libqrencode' found  
*** Unknown error occured in libqrencode version check process. at Makefile.PL line 112.    
-> N/A 
-> FAIL Configure failed for Text-QRCode-0.05. See /root/.cpanm/work/1557338319.8927/build.log for details. 
cd /home/qrencode-3.4.4
./configure --prefix=/usr
make && make install
export PKG_CONFIG_PATH=/usr/lib/pkgconfig

NGINX-CVE-2019-11043漏洞允许在某些nginx和php fpm配置上远程执行代码。

过去的24小时里,nginx周围出现了一个新的安全风险,记录在cve-2019-11043中。此漏洞允许在某些nginx和php fpm配置上远程执行代码。如果不运行nginx,此漏洞不会影响您。

不幸的是,nginx+php-fpm是大多数的选择,建议所有系统管理员立即采取措施:

将php包升级到最新版本。
修复这个问题的新版本将于10月24日发布。
请参见 https://www.php.net/archive/2019.php 35; 2019-10-24-1
Upstream PHP包,修复程序如下:

7.1.33
7.2.24
7.3.11

更新nginx配置文件。
由于nginx配置中只有两个更改,我们在这里重点介绍它们:

将NGINX如下配置

	location / {
		rewrite ^ /index.php$request_uri;
	}

修改为

	location / {
		rewrite ^ /index.php;
	}

注意删除$request-uri

以及

    location ~ ^\.... {
        fastcgi_split_path_info ^(.+?\.php)(\/.*|)$;
        include fastcgi_params;
        fastcgi_param SCRIPTFILENAME $document_root$fastcgi_script_name;
        .......
    }

修改为

    location ~ ^\.... {
        fastcgi_split_path_info ^(.+?\.php)(\/.*|)$;
        try_files $fastcgi_script_name =404;
        include fastcgi_params;
        fastcgi_param SCRIPTFILENAME $document_root$fastcgi_script_name;
        .......
    }

注意添加:$try_files $fastcgi_script_name =404;