CentOS 7 Nginx 默认配置

在centos 7 下,用nginx official repo安装的nginx stable版本的config 默认配置如下:

user nginx;
worker_processes 1;

error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;


events {
worker_connections 1024;
}


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

log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

access_log /var/log/nginx/access.log main;

sendfile on;
#tcp_nopush on;

keepalive_timeout 65;

#gzip on;

include /etc/nginx/conf.d/*.conf;
}

但是很明显, 这个配置过于简单了,结合军哥的LNMP,我们可以稍微改动一下config:

user nginx;

worker_processes auto;
worker_cpu_affinity auto;

error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

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

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


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

server_names_hash_bucket_size 128;
client_header_buffer_size 32k;
large_client_header_buffers 4 32k;
client_max_body_size 50m;

sendfile on;
sendfile_max_chunk 512k;
tcp_nopush on;

keepalive_timeout 60;

tcp_nodelay on;


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

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


server_tokens off;
access_log off;

server {

listen 80 default_server;
server_name _;
index index.html index.htm index.php;
root /usr/share/nginx/html;


}


include /etc/nginx/conf.d/*.conf;
}

在CentOS7上,nginx的启动是有systemd 来管理的,位置在/usr/lib/systemd/system/nginx.service

配置文件为:

[Unit]
Description=nginx - high performance web server
Documentation=http://nginx.org/en/docs/
After=network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target

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

[Install]
WantedBy=multi-user.target

Nginx安装Sectigo 的essential SSL

以前一直使用的是rapid SSL,但是rapid SSL 最近爆出了一些问题,因此开始转向我以前不是很喜欢的comodo,也就是现在的sectigo.

安装过程和rapid ssl 大同小异,有些不同的地方在rapid ssl 的intermediate certificate 只有一个文件,而comodo sectigo essential 的 chain files 确有三个, 需要注意的是chain files 根据时间的流逝,可能会有新的chain files产生, 而sectigo 的官方support 更新比较慢,建议自己从email 中合成chain file

chain file 从上到下,应该是SectigoRSADomainValidationSecureServerCA,USERTrustRSAAddTrustCA,AddTrustExternalCARoot

在nginx下,crt 是需要和chain file 合在一起的,因此在最后的crt中,应包含的证书,从上到下是 CRT, SectigoRSADomainValidationSecureServerCA,USERTrustRSAAddTrustCA,AddTrustExternalCARoot

 

 

nginx 带query string argument 的URL 跳转

nginx 自带的三个命令,  return, rewrite, try-files功能非常强大,基本可以完成各式各样的跳转, 比如下面的:

server {

    listen 80;

   server_name example.com;

   return 301 https://www.example.com$uri;

}

这样就完成了一个不带www的domain转向带SSL以及www前缀的domain的跳转

$uri: 按照nginx官方文档的话来说,就是current normalized URI in REQUEST

$request_uri: full original request URI (with arguments)

这里很明显就看到了$uri和$request_uri的区别,$uri 是 normalized的,换句话说,就是

  1. 去除了?以及后面的query参数
  2. encoded URL被 decoded

因此这里就出现了一个问题: exapmle.com/test.php?a=b 会跳转到https://www.example.com/test.php, query string丢失了,解决的办法很简单

return 301 https://www.example.com$uri$is_args$args

$is_args is an emprt string if there are no arguments, or a ? to signify the start of the query string.

$args then adds the arguments,

apache2.4 运行cgi的几种方式

我这边的服务器的web server基本上都是nginx的,但是今天在配置smokeping的时候,发现还得是使用apache做为后端来跑cgi,nginx对于cgi以及fastcgi的支持不是太好,google了一整天才发现原来apache的官方文档才是最好的资料. 本文以下内容均以apache2.4 为标准

如果我们想让apache来运行cgi程序,我们首先需要配置apache来允许cgi 程序. 主要有以下几种方式:

首先我们需要注意的是,无论是以哪种方式运行,我们都需要保证在http.conf中,LoadModule命令中要有cgi或者fcgi的模块:

LoadModule cgid_module modules/mod_cgid.so

or

LoadModule fcgid_module modules/mod_fcgid.so

因为fastcgi要比cgi要快很多,因此建议这里都使用fastcgi的module

在通过yum安装完apache 以后,我们可以直接用

yum install mod_fcgid

来安装apache fastcgi module

方式一: ScriptAlias

ScriptAlias 告诉apache有一个目录被专门设定来跑cgi程序, apache也会因此默认这个目录里面都是cgi程序,进而用cgi的handler来执行

ScriptAlias 命令:

ScriptAlias "/cgi-bin/" "/usr/local/apache2/cgi-bin/"

这里需要注意的是, ScriptAlias和Alias不同, ScriptAlias被专门用cgi程序的alias, Alias则是普通意义上的一个目录的map命令

方式二: CGI outside of ScriptAlias directories

我们经常会遇到把cgi程序放在/cgi-bin/外面的情况,我们只需要两步就可以完成这个任务: 1)  用AddHandler或者SetHandler 来设置cgi-script的handler 2) 在Options命令中,必须指定ExecCGI

以下是用options的方式来设定CGI运行:

<Directory "/usr/local/apache2/htdocs/somedir">
Options +ExecCGI

AddHanlder  cgi-script .cgi
</Directory>

以上命令告诉apache 在这个目录下,以.cgi结尾的都是cgi文件

当然了,如果你没有编辑httpd.conf的权利,也是可以在.htaccess中设定的

另外你可以设定某个目录下都是cgi文件,可以使用下面的配置方式:

<Directory "/home/*/public_html/cgi-bin">
Options ExecCGI
SetHandler cgi-script
</Directory>

 

Debugging Nginx Configuration

By default, Nginx logs only standard errors to default Nginx error log file or a file specified by error_log directive in site-specific server configuration.

We can control many aspects about error logging which will help us debug our Nginx configuration.

Important: After any change to any Nginx configuration file, you must test and reload Nginx configuration for changes to take effect. On CentOS, you can simply run nginx -t && service nginx reload command.

更多

AWS Lightsail IO 大坑

这两天帮朋友的企业网站迁移到aws amazon lightsail, 选用的环境是军哥的LNMP,php 7.2 和mysql 5.7.22, 用的是2GB的 RAM版本

这个环境在linode上编译只需要67分钟左右,但是在lightsail上竟然需要106分钟。。十分不可思议。。用bench.sh bash script测试了一下才发现IO只有40多。。于此同时linode上的IO有400多。。

哎,lightsail 的IO 真是坑王啊。。如果不运行数据库,只是简单的nginx 还是非常不错的

01/25/2019 更新:

今天测了一个4vCPU 16GB的lightsail, I/O的平均速度到了130,还是马马虎虎可以接受的

———————————————————————-
CPU model : Intel(R) Xeon(R) CPU E5-2676 v3 @ 2.40GHz
Number of cores : 4
CPU frequency : 2400.035 MHz
Total size of Disk : 320.0 GB (0.9 GB Used)
Total amount of Mem : 15884 MB (162 MB Used)
Total amount of Swap : 0 MB (0 MB Used)
System uptime : 0 days, 0 hour 2 min
Load average : 0.18, 0.11, 0.05
OS : CentOS 7.5.1804
Arch : x86_64 (64 Bit)
Kernel : 3.10.0-862.3.2.el7.x86_64
———————————————————————-
I/O speed(1st run) : 134 MB/s
I/O speed(2nd run) : 131 MB/s
I/O speed(3rd run) : 125 MB/s
Average I/O speed : 130.0 MB/s

monit 在 centos 7 和debian 8, debian 9下的使用

在老的centos 6 和 debian 7 中,monit 是通过对 pid 的监控来判断程序是否die 或者有问题的, 但是在 centos 7 和 debian 8 和debian 9下,只要service 不是以forking 的形式启动,systemd 就不会让service 创建 pid file,即使你在service 的配置文件中创建了 PidFile 的命令,这个命令是会被忽略的

因为在由systemd 控制的linux 系统中,monit 无法通过pid 的形式来监控程序,在这里我们就需要用到monit 的的match 命令,比如说nginx 来可以match ‘nginx’, 来完成对nginx 的监控

CentOS 上使用 NFS 的教程以及介绍

NFS 可以把NFS server 上的文件及文件共享给NFS client 服务器

两个概念,NFS Server(Master) 和 NFS Client

NFS Server 可以把本服务器上的文件和文件夹共享给NFS Client, NFS Client 可以在共享的文件和文件夹上进行读写操作,并且实时返回给NFS Master

NFS Server 一般作为存储服务器,常见为使用RAID 5 和 RAID 10 的存储服务器,容量比较大. 对于一些图片站和网盘站点,网站所在的服务器一般为NFS Client,NFS Client 把图片和文件直接存储在NFS Server上

为了方便对NFS进行user id 和 group id 进行统一管理,我们一般需要NFS Server 和 NFS Client 使用同一种操作系统, 比如说centos 和 centos. 当然了,分别使用不同的操作系统,比如说centos 和 debian 也是可以的,就是有点麻烦而已.

下面进行详细的安装步骤:

无论是CentOS 6 和 CentOS 7, 安装步骤基本都一致,这里推荐CentOS 7. RHEL系的操作系统越新越好用

服务器配置:

NFS Server Hostname: server.unixmen.local
NFS Server IP Address: 192.168.1.101/24

 

NFS Client Hostname: client.unixmen.local
NFS Client IP Address: 192.168.1.102/24

NFS服务器端配置:

CentOS 6:

yum install nfs-utils nfs-utils-lib

chkconfig nfs on 
service rpcbind start
service nfs start

CentOS 7:

yum install nfs-utils nfs-utils-lib

systemctl enable rpcbind
systemctl enable nfs-server
systemctl enable nfs-lock
systemctl enable nfs-idmap

systemctl start rpcbind
systemctl start nfs-server
systemctl start nfs-lock
systemctl start nfs-idmap

因为CentOS 7 在系统上改了好多,所以安装稍微有点不同,其实都是同一个库

下面配置共享目录,假设我们需要共享/home 目录给client

vi /etc/exports

然后添加下面:

/home  192.168.0.102 (rw,sync,no_root_squash,no_subtree_check)

参数的解释:

rw: 这个选项允许client server 在共享目录上进行读和写的操作

ro: 只读

sync: 将数据同步写入内存缓冲区与磁盘中,效率低,但可以保证数据的一致性;

no_root_squash: 登入 NFS 主机使用分享目录的使用者,如果是 root 的话,那么对于这个分享的目录来说,他就具有 root 的权限!

root_squash: 在登入 NFS 主机使用分享之目录的使用者如果是 root 时,那么这个使用者的权限将被压缩成为匿名使用者,通常他的 UID 与 GID 都会变成 nobody 那个系统账号的身份

all_squash: 将远程访问的所有普通用户及所属组都映射为匿名用户或用户组 (nfsnobody)

no_all_squash: 与all_squash 相反, 默认配置

anonuid=xxx: 将远程访问的所有用户都映射为匿名用户,并指定该用户为本地用户(UID=xxx);
anongid=xxx: 将远程访问的所有用户组都映射为匿名用户组账户,并指定该匿名用户组账户为本地用户组账户(GID=xxx);

这里需要注意的, NFS 进行映射的时候,用的是uid 和 gid, 而非是用户名和group 的名字. 所以通常的做法是, 在NFS server 和 NFS client 上使用相同的用户名和用户组,以及相同UID和 GID

相同的用户名和用户组这个好解决, UID 和 GID不同的话,需要update uid 和 gid以使他们相同. 在centos 上我们经常使用军哥的lnmp,用户名和用户组都为www,加入uid 为501, gid 为501, 则我们可以用

(rw, sync, no_subtree_check, all_squash, anonuid=501, anongid=501)

async: 将数据先保存在内存缓冲区中,必要时才写入磁盘;

subtree: 若输出目录是一个子目录,则nfs服务器将检查其父目录的权限(默认设置);
no_subtree:即使输出目录是一个子目录,nfs服务器也不检查其父目录的权限,这样可以提高效率;

配置完成以后,我们需要export这个配置来时他生效:

exportfs -a

下面我们需要配置NFS Client

安装NFS:

yum install nfs-utils nfs-utils-lib

mount 共享目录给 /home

mount -t nfs 192.168.1.101:/home /home

然后我们就可以通过df -h 看到mount 的目录或者mount 来查看

如果需要开机启动时自动mount,我们需要编辑/etc/fstab

192.168.1.101:/home /home nfs rw,sync,hard,intr 0 0

移除NFS mount

umount /home

Nginx 处理请求的顺序问题

对于Name-Based virtual servers, nginx 只会测试request 中的header field “Host” 来决定把这个请求route 给谁. 如果这个请求不存在Host这个field, 或者Host 的值不能match 任何一个server_name, 那么nginx就会把这个请求route 给这个port 的default server. 如果我们没有在conf中指明哪个server block 为default_server, 那么nginx 就会把第一个server block认为是default server.

name-based virtual server 的例子如下:

server {
 listen 80;
 server_name example.org www.example.org;
 ...
}

server {
 listen 80;
 server_name example.net www.example.net;
 ...
}

server {
 listen 80;
 server_name example.com www.example.com;
 ...
}

default_server 的例子如下:

server {
 listen 80 default_server;
 server_name example.net www.example.net;
 ...
}

 

对于mixed name-based and ip-based virtual server, 例如:

server {
 listen 192.168.1.1:80;
 server_name example.org www.example.org;
 ...
}

server {
 listen 192.168.1.1:80;
 server_name example.net www.example.net;
 ...
}

server {
 listen 192.168.1.2:80;
 server_name example.com www.example.com;
 ...
}

nginx 的处理顺序是先ip和port 的组合,然后才是server_name.

举个例子就是,如果在192.168.1.1:80上收到了一个www.example.com 的请求的话,那么这个请求就会被发到192.168.1.1:80 的default server, 因为对于这个ip和port 的组合,里面没有这个server_name.

 

php-fpm 内存过高,CPU占有率过高带来的优化和调整

如果不是昨天我的论坛遭受到了NTP DDos攻击,我也不会遇到这个问题.

首先,这些问题都是和php-fpm 的配置有关,如果你使用的是军哥的LNMP,那么这个配置文件位于

/usr/local/php/etc/php-fpm.conf

首先先解决内存过高的问题,这个是由于php-fpm占用了内存以后并没有及时释放造成的,但是我们可以通过配置文件强制他释放内存,可以在配置文件里面加上

pm.max_requests = 500

500这个值适用于大部分的服务器配置,但是如果你的内存过大或者过小,可以适当增大或者减小这个值,取决于你的内存的实际使用率. 

既然说到了php-fpm 的配置,那么就得好好的说下php-fpm 的 process management

php-fpm 的process management 有两种工作方式,一种是static, 一种是dynamic, 对于小的cloud 或者vps 一般用static,但是其实大部分时间我们都在使用dynamic

pm = dynamic
pm.max_children = 160
pm.start_servers = 20
pm.min_spare_servers = 20
pm.max_spare_servers = 40

和process management 有直接关系的是这四个参数, pm.max_children 在pm=static 的时候有用,在pm = dynamic 的时候, 剩下三个参数才开始起作用

这里问题的关键在于,如何设置pm.max_children 的值

对于不同的php application,每个php-fpm instance 占用的内存也不一样,需要具体application 具体分析,但是这里我们可以去个average , 30M

假设你的服务器有8G的内存,其中的6GB 可以划给php-fpm, 那么

pm.max_children = 6000MB / 30MB =200

也就是说在这种情况下,200这个值是比较合适的. 这里需要注意的是,赋予max_children 一个很高的值,并不代表会带来高性能,也许会拖垮整个服务器

剩下的三个参数,按照实际情况,设置的差不多就行了

你可以用如下的命令来实际查看一下single php-fpm usage:

ps --no-headers -o "rss,cmd" -C php-fpm | awk '{ sum+=$1 } END { printf ("%d%s\n", sum/NR/1024,"M") }'

另外别忘了开启php-fpm 的 slowlog,这样方便你以后查看日志来进行debug

slowlog = /usr/local/php/var/log/slow.log

对于CPU 占有率过高的问题,这个其实并不是php-fpm 的问题,而是你写的php 代码的问题,这个时候可以通过设置pm.status_path 开查看到底是哪个php application 占用的cpu 资源

详细可以参见这篇文章:

https://brandonwamboldt.ca/understanding-the-php-fpm-status-page-1603/