标签 nginx 下的文章

语法: sendfile on | off;
默认值: sendfile off;
上下文: http,server,location,if in location
}

指定是否使用sendfile系统调用来传输文件。
sendfile系统调用在两个文件描述符之间直接传递数据(完全在内核中操作),从而避免了数据在内核缓冲区和用户缓冲区之间的拷贝,操作效率很高,被称之为零拷贝。
参考文章:https://www.jianshu.com/p/70e1c396c320

Syntax:    tcp_nopush on | off;
Default:    tcp_nopush off;
Context:    http, server, location

TCP_NOPUSH 是 FreeBSD 的一个 socket 选项,对应 Linux 的 TCP_CORK,Nginx 里统一用 tcp_nopush 来控制它,并且只有在启用了 sendfile 之后才生效。启用它之后,数据包会累计到一定大小之后才会发送,减小了额外开销,提高网络效率。

Syntax:    tcp_nodelay on | off;
Default:    tcp_nodelay on;
Context:    http, server, location

TCP_NODELAY 也是一个 socket 选项,启用后会禁用 Nagle 算法,尽快发送数据,某些情况下可以节约 200ms(Nagle 算法原理是:在发出去的数据还未被确认之前,新生成的小数据先存起来,凑满一个 MSS 或者等到收到确认后再发送)。Nginx 只会针对处于 keep-alive 状态的 TCP 连接才会启用 tcp_nodelay。当连接转换为keep-alive状态时,启用该选项。此外,它在SSL连接上启用,用于无缓冲代理和WebSocket代理。

可以看到 TCP_NOPUSH 是要等数据包累积到一定大小才发送,TCP_NODELAY 是要尽快发送,二者相互矛盾。实际上,它们确实可以一起用,最终的效果是先填满包,再尽快发送。
官方文档参考:http://nginx.org/en/docs/http/ngx_http_core_module.html#tcp_nodelay

Syntax:    keepalive_timeout timeout [header_timeout];
Default:    keepalive_timeout 75s;
Context:    http, server, location

第一个参数设置一个超时,在这个超时期间,保持活动的客户端连接将在服务器端保持打开。0值禁用保持连接的客户端连接。第二个可选参数在Keep-Alive: timeout=time响应报头字段中设置一个值。两个参数可能不同。Keep-Alive: timeout=time报头字段被Mozilla和Konqueror识别。MSIE会在大约60秒内自行关闭保持连接。

keepalive_timeout 60;
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
fastcgi_buffer_size 64k;
fastcgi_buffers 4 64k;
fastcgi_busy_buffers_size 128k;
fastcgi_temp_file_write_size 256k;
fastcgi_intercept_errors on;

fastcgi模块参数

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;
gzip_vary on;
gzip_proxied   expired no-cache no-store private auth;
gzip_disable   "MSIE [1-6]\.";

开启gzip压缩

server_tokens off;

启用或禁用在错误页面和服务器响应报头字段中发出nginx版本。build参数(1.11.10)允许随nginx版本一起发出build名称。此外,作为我们商业订阅的一部分,从版本1.9.13开始,错误页面上的签名和服务器响应头字段值可以使用变量字符串显式设置。空字符串禁止发送Server字段。

map $http_x_forwarded_for  $clientRealIp {
  ""      $remote_addr;
  ~^(?P<firstAddr>[0-9\.]+),?.*$  $firstAddr;
}

过CDN,获取真实客户端IP,$clientRealIp

====
其它待补充

环境 centos8,编译方式安装的nginx/1.20.1, php 是dnf安装的php/7.2.24

nginx 执行用户、php 执行用户、文件权限都检查了,确定没有问题

nginx 的php配置也确定没有问题,但就是访问php页面出现 File not found

查看nginx报错内容,看到如下错误:"Primary script unknown"

2021/07/07 20:40:02 [error] 8853#0: *164 FastCGI sent in stderr: "Primary script unknown" while reading response header from upstream, client: 192.168.1.95, server: localhost, request: "GET /index.php HTTP/1.1", upstream: "fastcgi://unix:/run/php-fpm/www.sock:", host: "192.168.1.69"

最终解决的方法:

#/www/wwwroot/phpwebdir/是我的网站根目录
chcon -R -t httpd_sys_content_t /www/wwwroot/phpwebdir/
chcon -R -t httpd_sys_content_t /www/server/nginx/sbin/nginx 
/www/server/nginx/sbin/nginx -s reload

原因是selinux 在作祟,如上命令是配置 网站目录和nginx执行文件的 selinux 上下文
具体selinux这个安全机制至今还没有搞明白咋玩
用以下命令可以查看文件或目录的上下文

ll -dZ /www/wwwroot/phpwebdir/

修改之前是

drwxrw-rw-. 7 www www unconfined_u:object_r:admin_home_t:s0 4096 Jul  7 20:28 /www/wwwroot/phpwebdir/

修改之后是

drwxrw-rw-. 7 www www unconfined_u:object_r:httpd_sys_content_t:s0 4096 Jul  7 20:28 /www/wwwroot/phpwebdir/

或者干脆关闭selinux(需要重启服务器)
/etc/selinux/config :

SELINUX=disabled

现在被恶意请求了,把恶意请求单独打到一个日志文件,然后提取客户端IP,去重,然后封掉这些IP

创建文件

vim  filterIp.sh

文件内容

#! /bin/bash
sed 's/src:\([0-9\.]\+\).*/\1/g' $1 | sort -n | uniq

用这个脚本处理日志文件, 提取到客户端IP,这些IP是排序,去重了的

chmod a+x filterIp.sh
./filterIp.sh xxx.log

我的 xxx.log 的日志格式是这样的,如果保存日志不一样,则需要改一下 filterIp.sh 中的sed处理规则

src:60.173.147.155 cdn:58.215.115.71 - [16/Jun/2021:10:02:01 +0800] "GET /xx.html?xx3 HTTP/1.1" 403 564 "xx" "Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1)"

http {} 中:

map $http_x_forwarded_for  $clientRealIp {
                ""      $remote_addr;
                ~^(?P<firstAddr>[0-9\.]+),?.*$  $firstAddr;
        }

         log_format  main  'src:$clientRealIp cdn:$remote_addr $remote_user [$time_local] "$request" '
                          '$status $body_bytes_sent "$http_referer" '
                          '"$http_user_agent"';

        access_log  logs/access.log  main;

测试环境:
centos 7系统,预先安装好bt 宝塔系统,安装好samba,宝塔里面安装好 lnmp软件,php设置 取消 exec 函数限制:

将www用户添加到dev组

usermod -G dev www

php 写了一个脚本,实现监控目录下文件的变量,然后重启nginx的例子:

<?php

class NginxRewrite {

    public  $dir   = "/www/wwwroot/";
    private $files = [];

    public function __construct() {
        $this->files = $this->readDir();
    }

    public function run() {
        $oldFiles = $this->files;
        while (true) {
            $_files = $this->readDir();
            foreach ($_files as $f=>$t) {
                if (!isset($oldFiles[$f]) || $oldFiles[$f]!=$t) {
                    $oldFiles = $_files;
                    @exec("nginx -t", $out, $status);
                    if ($status === 0) {
                        echo "rewrite change, nginx reload\n";
                        @exec("nginx -s reload");
                    }
                    break;
                }
            }
            sleep(10);
        }
    }

    //目录目标目录
    private function readDir($dir = null) {
        $dir = $dir ? $dir : $this->dir;
        $files = scandir($dir);
        $deep  = count(explode(DIRECTORY_SEPARATOR, $this->dir));
        //var_dump($deep);

        $res = [];
        foreach ($files as $file) {
            if ($file == '..' || $file == '.')
                continue;

            $_path = rtrim($dir, '\\/') . DIRECTORY_SEPARATOR . $file;
            $_deep = count(explode(DIRECTORY_SEPARATOR, $_path));
            if (is_dir($_path) && $_deep - $deep < 2) {
                //var_dump($_deep - $deep, $_path);
                $res = array_merge($res, $this->readDir($_path));
            } elseif (is_file($_path) && preg_match("/nginx\.htaccess$/", $file)) {
                $res[$_path] = filemtime($_path);
            }
        }
        return $res;
    }

}

$mod = new NginxRewrite();
$mod->run();

nginx 实现了动态域名,动态加载用户的匹配文件的方法
/root/nginx_config_tpl/www.nginx.tpl

server
{
    listen 80;
    server_name ~^(\w+)\.USER_NAME\.tell520\.com$;
    set $www $1;
    index index.php index.html index.htm default.php default.htm default.html;
    root /www/wwwroot/USER_NAME/$www;

#SSL-START SSL相关配置,请勿删除或修改下一行带注释的404规则
#error_page 404/404.html;
#SSL-END

#ERROR-PAGE-START  错误页配置,可以注释、删除或修改
#error_page 404 /404.html;
#error_page 502 /502.html;
#ERROR-PAGE-END

#PHP-INFO-START  PHP引用配置,可以注释或修改
    include enable-php-71.conf;
#PHP-INFO-END

#REWRITE-START URL重写规则引用,修改后将导致面板设置的伪静态规则失效
    location / {
        include /www/wwwroot/USER_NAME/*/nginx.htaccess;
        access_log  /www/wwwroot/USER_NAME/nginx.log;
    }
#REWRITE-END

#禁止访问的文件或目录
location ~ ^/(\.user.ini|\.htaccess|\.git|\.svn|\.project|LICENSE|README.md)
{
return 404;
}

#一键申请SSL证书验证目录相关设置
location ~ \.well-known{
allow all;
}

location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
{
expires      30d;
error_log off;
access_log /dev/null;
}

location ~ .*\.(js|css)?$
{
expires      12h;
error_log off;
access_log /dev/null;
}
}

自动创建samba用户,并创建用户的网站目录和默认的例子文件脚本:

#! /bin/bash

if [ $# -ne 1 ]; then
   echo -e "use: ./create_dev_user.sh username"
   exit 1
fi


useradd $1 -g dev
echo -e "123456\n123456\n" | smbpasswd -a $1
mkdir /www/wwwroot/$1
mkdir /www/wwwroot/$1/test

touch /www/wwwroot/$1/test/index.php
cat>/www/wwwroot/$1/test/index.php<<EOF
<?php

echo "<pre>";
echo "hello world!\n";
var_export(\$_GET);
echo "</pre>";

EOF

touch /www/wwwroot/$1/test/nginx.htaccess
cat>/www/wwwroot/$1/test/nginx.htaccess<<EOF

rewrite ^([^\.]*)/(\w+)/(\w+).html\$ \$1/index.php?r=\$2/\$3 last;
rewrite ^([^\.]*)$ \$1/index.php?r=index/index last;
if (!-e \$request_filename) {
    rewrite ^(.*)\$ /index.php/\$1 last;
}

EOF


chown $1:dev /www/wwwroot/$1/ -R
chmod 776 /www/wwwroot/$1/ -R

sed "s/USER_NAME/$1/" /root/nginx_config_tpl/www.nginx.tpl > /www/server/nginx/conf/vhost/$1.conf

echo -e "\033[34mAdd hosts to browse the example site : 192.168.2.164 test.$1.tell520.com\033[0m"
echo -e "\033[34mAdd network drive : \\\\192.168.2.164\dev\033[0m"
echo -e "\033[34mUser AND Password : $1, 123456\033[0m"

nginx -t && nginx -s reload

samba配置文件:

# See smb.conf.example for a more detailed config file or
# read the smb.conf manpage.
# Run 'testparm' to verify the config is correct after
# you modified it.

[global]
server string = dev Servera Version %v
interfaces = ens192 192.168.2.164/24
workgroup = SAMBA
security = user

passdb backend = tdbsam

printing = cups
printcap name = cups
load printers = yes
cups options = raw

[dev]
comment = dev dir
path = /www/wwwroot/yxb
browseable = Yes
writable = Yes
available = Yes
valid users = @dev
public = No


[homes]
comment = Home Directories
valid users = %S, %D%w%S
browseable = Yes
read only = No
inherit acls = Yes

[printers]
comment = All Printers
path = /var/tmp
printable = Yes
create mask = 0600
browseable = No

[print$]
comment = Printer Drivers
path = /var/lib/samba/drivers
write list = @printadmin root
force group = @printadmin
create mask = 0664
directory mask = 0775