欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Nginx 全实践

程序员文章站 2022-03-05 10:26:17
...

实验环境

四台 VMWare Workstation 虚拟机:

  • node105:作为测试访问的客户端,以及进行 Tengine 相关实验;
  • node106:Nginx实验,并作为七层反向代理及四层负载均衡;
  • node107和node108:作为后端服务器,安装web应用(httpd/nginx和php-fpm)、MySQL和Redis;

Nginx 全实践

一:Nginx 安装

1.1:Nginx yum 安装

1.1.1:安装 epel 源

  • 安装 epel 源:
[aaa@qq.com ~]# yum install epel-release -y
  • 查看 epel 仓库中的 Nginx 版本:
[aaa@qq.com ~]# yum info nginx
Available Packages
Name        : nginx
Arch        : x86_64
Epoch       : 1
Version     : 1.16.1
Release     : 3.el7
Size        : 563 k
Repo        : epel/x86_64
Summary     : A high performance web server and reverse proxy server
URL         : http://nginx.org/
License     : BSD
Description : Nginx is a web server and a reverse proxy server for HTTP, SMTP, POP3 and
            : IMAP protocols, with a strong focus on high concurrency, performance and low
            : memory usage.

1.1.2:安装 Nginx

  • 安装:
[aaa@qq.com ~]# yum install nginx -y

1.1.3:验证安装

  • 查看生成文件:
[aaa@qq.com ~]# rpm -ql nginx
/etc/logrotate.d/nginx
/etc/nginx/fastcgi.conf
/etc/nginx/fastcgi.conf.default
/etc/nginx/fastcgi_params
/etc/nginx/fastcgi_params.default
/etc/nginx/koi-utf
/etc/nginx/koi-win
/etc/nginx/mime.types
/etc/nginx/mime.types.default
/etc/nginx/nginx.conf
/etc/nginx/nginx.conf.default
/etc/nginx/scgi_params
/etc/nginx/scgi_params.default
/etc/nginx/uwsgi_params
/etc/nginx/uwsgi_params.default
/etc/nginx/win-utf
/usr/bin/nginx-upgrade
/usr/lib/systemd/system/nginx.service
/usr/lib64/nginx/modules
/usr/sbin/nginx
/usr/share/doc/nginx-1.16.1
/usr/share/doc/nginx-1.16.1/CHANGES
/usr/share/doc/nginx-1.16.1/README
/usr/share/doc/nginx-1.16.1/README.dynamic
/usr/share/doc/nginx-1.16.1/UPGRADE-NOTES-1.6-to-1.10
/usr/share/licenses/nginx-1.16.1
/usr/share/licenses/nginx-1.16.1/LICENSE
/usr/share/man/man3/nginx.3pm.gz
/usr/share/man/man8/nginx-upgrade.8.gz
/usr/share/man/man8/nginx.8.gz
/usr/share/nginx/html/404.html
/usr/share/nginx/html/50x.html
/usr/share/nginx/html/en-US
/usr/share/nginx/html/icons
/usr/share/nginx/html/icons/poweredby.png
/usr/share/nginx/html/img
/usr/share/nginx/html/index.html
/usr/share/nginx/html/nginx-logo.png
/usr/share/nginx/html/poweredby.png
/usr/share/vim/vimfiles/ftdetect/nginx.vim
/usr/share/vim/vimfiles/ftplugin/nginx.vim
/usr/share/vim/vimfiles/indent/nginx.vim
/usr/share/vim/vimfiles/syntax/nginx.vim
/var/lib/nginx
/var/lib/nginx/tmp
/var/log/nginx
  • 查看 nginx 命令帮助:
[aaa@qq.com ~]# nginx -h
nginx version: nginx/1.16.1
Usage: nginx [-?hvVtTq] [-s signal] [-c filename] [-p prefix] [-g directives]

Options:
  -?,-h         : this help
  -v            : show version and exit
  -V            : show version and configure options then exit
  -t            : test configuration and exit
  -T            : test configuration, dump it and exit
  -q            : suppress non-error messages during configuration testing
  -s signal     : send signal to a master process: stop, quit, reopen, reload
  -p prefix     : set prefix path (default: /usr/share/nginx/)
  -c filename   : set configuration file (default: /etc/nginx/nginx.conf)
  -g directives : set global directives out of configuration file
  • 验证 nginx 配置文件:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
  • 查看 nginx 版本及配置信息:
[aaa@qq.com ~]# nginx -V
nginx version: nginx/1.16.1
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC) 
built with OpenSSL 1.1.1c FIPS  28 May 2019 (running with OpenSSL 1.1.1g FIPS  21 Apr 2020)
TLS SNI support enabled
configure arguments: --prefix=/usr/share/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --http-client-body-temp-path=/var/lib/nginx/tmp/client_body --http-proxy-temp-path=/var/lib/nginx/tmp/proxy --http-fastcgi-temp-path=/var/lib/nginx/tmp/fastcgi --http-uwsgi-temp-path=/var/lib/nginx/tmp/uwsgi --http-scgi-temp-path=/var/lib/nginx/tmp/scgi --pid-path=/run/nginx.pid --lock-path=/run/lock/subsys/nginx --user=nginx --group=nginx --with-file-aio --with-ipv6 --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-stream_ssl_preread_module --with-http_addition_module --with-http_xslt_module=dynamic --with-http_image_filter_module=dynamic --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_degradation_module --with-http_slice_module --with-http_stub_status_module --with-http_perl_module=dynamic --with-http_auth_request_module --with-mail=dynamic --with-mail_ssl_module --with-pcre --with-pcre-jit --with-stream=dynamic --with-stream_ssl_module --with-google_perftools_module --with-debug --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -m64 -mtune=generic' --with-ld-opt='-Wl,-z,relro -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -Wl,-E'
  • 查看 nginx 启动脚本:
[aaa@qq.com ~]# cat /usr/lib/systemd/system/nginx.service
[Unit]
Description=The nginx HTTP and reverse proxy server
After=network.target remote-fs.target nss-lookup.target

[Service]
Type=forking
PIDFile=/run/nginx.pid
# Nginx will fail to start if /run/nginx.pid already exists but has the wrong
# SELinux context. This might happen when running `nginx -t` from the cmdline.
# https://bugzilla.redhat.com/show_bug.cgi?id=1268621
ExecStartPre=/usr/bin/rm -f /run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t
ExecStart=/usr/sbin/nginx
ExecReload=/bin/kill -s HUP $MAINPID
KillSignal=SIGQUIT
TimeoutStopSec=5
KillMode=process
PrivateTmp=true

[Install]
WantedBy=multi-user.target

1.1.4:Nginx 默认配置

[aaa@qq.com ~]# grep -v "#" /etc/nginx/nginx.conf | grep -v "^$"
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
include /usr/share/nginx/modules/*.conf;
events {
    worker_connections 1024;
}
http {
    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;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 2048;
    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;
    include /etc/nginx/conf.d/*.conf;
    server {
        listen       80 default_server;
        listen       [::]:80 default_server;
        server_name  _;
        root         /usr/share/nginx/html;
        include /etc/nginx/default.d/*.conf;
        location / {
        }
        error_page 404 /404.html;
        location = /404.html {
        }
        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
        }
    }
}

1.1.5:启动 Nginx

  • 设置开机启动:
[aaa@qq.com ~]# systemctl enable nginx
Created symlink from /etc/systemd/system/multi-user.target.wants/nginx.service to /usr/lib/systemd/system/nginx.service.
  • 启动 Nginx:
[aaa@qq.com ~]# systemctl start nginx
  • 查看 nginx 运行状态:
[aaa@qq.com ~]# systemctl status nginx
nginx.service - The nginx HTTP and reverse proxy server
   Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; vendor preset: disabled)
   Active: active (running) since Wed 2020-12-02 03:53:55 CST; 7s ago
  Process: 3014 ExecStart=/usr/sbin/nginx (code=exited, status=0/SUCCESS)
  Process: 3010 ExecStartPre=/usr/sbin/nginx -t (code=exited, status=0/SUCCESS)
  Process: 3009 ExecStartPre=/usr/bin/rm -f /run/nginx.pid (code=exited, status=0/SUCCESS)
 Main PID: 3016 (nginx)
   CGroup: /system.slice/nginx.service
           ├─3016 nginx: master process /usr/sbin/nginx
           └─3017 nginx: worker process

Dec 02 03:53:55 node105.yqc.com systemd[1]: Starting The nginx HTTP and reverse proxy server...
Dec 02 03:53:55 node105.yqc.com nginx[3010]: nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
Dec 02 03:53:55 node105.yqc.com nginx[3010]: nginx: configuration file /etc/nginx/nginx.conf test is successful
Dec 02 03:53:55 node105.yqc.com systemd[1]: Failed to parse PID from file /run/nginx.pid: Invalid argument
Dec 02 03:53:55 node105.yqc.com systemd[1]: Started The nginx HTTP and reverse proxy server.
  • 查看 Nginx 进程:
[aaa@qq.com ~]# ps -ef | grep nginx | grep -v grep
root       3016      1  0 03:53 ?        00:00:00 nginx: master process /usr/sbin/nginx
nginx      3017   3016  0 03:53 ?        00:00:00 nginx: worker process

1.1.6:访问 Nginx

Nginx 全实践

1.2:Nginx 编译安装

1.2.1:准备编译环境

  • 安装编译基础环境以及常用工具:
yum install -y vim lrzsz tree screen psmisc lsof tcpdump wget ntpdate gcc gcc-c++ glibc glibc-devel pcre pcre-devel openssl openssl-devel systemd-devel net-tools iotop bc zip unzip zlib-devel bash-completion nfs-utils automake libxml2 libxml2-devel libxslt libxslt-devel perl perl-ExtUtils-Embed

1.2.2:下载 Nginx 源码包

Nginx 官方下载地址:https://nginx.org/en/download.html

[aaa@qq.com ~]# cd /usr/local/src/
[aaa@qq.com src]# ll
total 1016
-rw-r--r-- 1 root root 1039530 Oct 19 17:33 nginx-1.18.0.tar.gz

1.2.3:解压 Nginx 源码包

[aaa@qq.com src]# tar zxvf nginx-1.18.0.tar.gz

[aaa@qq.com src]# ll nginx-1.18.0
total 768
drwxr-xr-x 6 1001 1001   4096 Dec  2 03:58 auto
-rw-r--r-- 1 1001 1001 302863 Apr 21  2020 CHANGES
-rw-r--r-- 1 1001 1001 462213 Apr 21  2020 CHANGES.ru
drwxr-xr-x 2 1001 1001   4096 Dec  2 03:58 conf
-rwxr-xr-x 1 1001 1001   2502 Apr 21  2020 configure
drwxr-xr-x 4 1001 1001     68 Dec  2 03:58 contrib
drwxr-xr-x 2 1001 1001     38 Dec  2 03:58 html
-rw-r--r-- 1 1001 1001   1397 Apr 21  2020 LICENSE
drwxr-xr-x 2 1001 1001     20 Dec  2 03:58 man
-rw-r--r-- 1 1001 1001     49 Apr 21  2020 README
drwxr-xr-x 9 1001 1001     84 Dec  2 03:58 src

1.2.4:生成 Makefile

  • 这一步是检查系统环境是否符合编译安装的要求,是否支持编译参数中的模块,并根据指定的编译参数生成 Makefile 文件,为接下来的编译安装作好准备:
./configure --prefix=/apps/nginx \
  --user=nginx \
  --group=nginx \
  --with-http_ssl_module \
  --with-http_v2_module \
  --with-http_realip_module \
  --with-http_stub_status_module \
  --with-http_gzip_static_module \
  --with-pcre \
  --with-stream \
  --with-stream_ssl_module \
  --with-stream_realip_module

1.2.5:编译并安装

  • 编译是根据 Makefile 生成安装所需的相应模块文件:
[aaa@qq.com nginx-1.18.0]# make
  • 安装是创建相应目录,并将编译过程生成的模块和文件复制到相应目录:
[aaa@qq.com nginx-1.18.0]# make install

1.2.6:创建 Nginx 用户

  • 创建 Nginx 用户,指定 UID 为 2000,shell 为 nologin:
[aaa@qq.com ~]# useradd -u 2000 -s /sbin/nologin nginx
  • 验证 Nginx 用户:
[aaa@qq.com ~]# id nginx
uid=2000(nginx) gid=2000(nginx) groups=2000(nginx)

1.2.7:创建额外的配置文件目录

[aaa@qq.com ~]# mkdir /apps/nginx/conf.d
[aaa@qq.com ~]# chown nginx:nginx -R /apps/nginx/conf.d/

1.2.8:创建 nginx 软链接

[aaa@qq.com ~]# ln -sv /apps/nginx/sbin/nginx /usr/bin/nginx
‘/usr/bin/nginx’ -> ‘/apps/nginx/sbin/nginx’

1.2.9:验证编译安装

  • 查看安装生成的文件目录:
[aaa@qq.com ~]# ll /apps/nginx/
total 4
drwxr-xr-x 2 root root 4096 Dec  2 04:18 conf
drwxr-xr-x 2 root root   38 Dec  2 04:18 html
drwxr-xr-x 2 root root    6 Dec  2 04:18 logs
drwxr-xr-x 2 root root   18 Dec  2 04:18 sbin
  • 查看 Nginx 版本及编译配置参数:
[aaa@qq.com ~]# /apps/nginx/sbin/nginx -V
nginx version: nginx/1.18.0
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC) 
built with OpenSSL 1.0.2k-fips  26 Jan 2017
TLS SNI support enabled
configure arguments: --prefix=/apps/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre --with-stream --with-stream_ssl_module --with-stream_realip_module

1.2.10:Nginx 默认配置

[aaa@qq.com ~]# grep -v "#" /apps/nginx/conf/nginx.conf | grep -v "^$"   
worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       80;
        server_name  localhost;
        location / {
            root   html;
            index  index.html index.htm;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}

1.2.11:创建 Nginx 启动脚本

  • 编辑启动脚本:
[aaa@qq.com ~]# vim /usr/lib/systemd/system/nginx.service
[Unit]
Description=The nginx HTTP and reverse proxy server
After=network.target remote-fs.target nss-lookup.target

[Service]
Type=forking
PIDFile=/apps/nginx/logs/nginx.pid
# Nginx will fail to start if /run/nginx.pid already exists but has the wrong
# SELinux context. This might happen when running `nginx -t` from the cmdline.
# https://bugzilla.redhat.com/show_bug.cgi?id=1268621
ExecStartPre=/usr/bin/rm -f /apps/nginx/logs/nginx.pid
ExecStartPre=/apps/nginx/sbin/nginx -t
ExecStart=/apps/nginx/sbin/nginx
ExecReload=/bin/kill -s HUP $MAINPID
KillSignal=SIGQUIT
TimeoutStopSec=5
KillMode=process
PrivateTmp=true

[Install]
WantedBy=multi-user.target
  • 重载 systemd:
[aaa@qq.com ~]# systemctl daemon-reload

1.2.12:启动 Nginx

  • 设置开机启动:
[aaa@qq.com ~]# systemctl enable nginx
Created symlink from /etc/systemd/system/multi-user.target.wants/nginx.service to /usr/lib/systemd/system/nginx.service.
  • 启动 Nginx:
[aaa@qq.com ~]# systemctl start nginx
  • 查看 Nginx 运行状态:
[aaa@qq.com ~]# ssytemctl status nginx
-bash: ssytemctl: command not found
[aaa@qq.com ~]# systemctl status nginx
● nginx.service - The nginx HTTP and reverse proxy server
   Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; vendor preset: disabled)
   Active: active (running) since Wed 2020-12-02 04:27:38 CST; 12s ago
  Process: 6208 ExecStart=/apps/nginx/sbin/nginx (code=exited, status=0/SUCCESS)
  Process: 6206 ExecStartPre=/apps/nginx/sbin/nginx -t (code=exited, status=0/SUCCESS)
  Process: 6205 ExecStartPre=/usr/bin/rm -f /apps/nginx/logs/nginx.pid (code=exited, status=0/SUCCESS)
 Main PID: 6210 (nginx)
   CGroup: /system.slice/nginx.service
           ├─6210 nginx: master process /apps/nginx/sbin/nginx
           └─6211 nginx: worker process

Dec 02 04:27:38 node106.yqc.com systemd[1]: Starting The nginx HTTP and reverse proxy server...
Dec 02 04:27:38 node106.yqc.com nginx[6206]: nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
Dec 02 04:27:38 node106.yqc.com nginx[6206]: nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
Dec 02 04:27:38 node106.yqc.com systemd[1]: Failed to parse PID from file /apps/nginx/logs/nginx.pid: Invalid argument
Dec 02 04:27:38 node106.yqc.com systemd[1]: Started The nginx HTTP and reverse proxy server.
  • 查看 Nginx 进程:
[aaa@qq.com ~]# ps -ef | grep nginx | grep -v grep
root       6210      1  0 20:27 ?        00:00:00 nginx: master process /apps/nginx/sbin/nginx
nginx      6211   6210  0 20:27 ?        00:00:00 nginx: worker process

1.2.13:访问 Nginx

Nginx 全实践

1.3:Tengine 编译安装

以下内容摘自 Tengine 官方:

Tengine是由淘宝网发起的Web服务器项目。
它在Nginx的基础上,针对大访问量网站的需求,添加了很多高级功能和特性。
Tengine的性能和稳定性已经在大型的网站如淘宝网天猫商城等得到了很好的检验。
它的最终目标是打造一个高效、稳定、安全、易用的Web平台。

特性

1.3.1:下载 Tengine 源码包

Tengine 官网:http://tengine.taobao.org/

本次实验采用 Tengine-2.1.2:http://tengine.taobao.org/download/tengine-2.1.2.tar.gz

[aaa@qq.com ~]# wget -O /usr/local/src/tengine-2.1.2.tar.gz http://tengine.taobao.org/download/tengine-2.1.2.tar.gz

1.3.2:解压 Tengine 源码包

[aaa@qq.com ~]# cd /usr/local/src/
[aaa@qq.com src]# tar zxvf tengine-2.1.2.tar.gz 
[aaa@qq.com src]# ll tengine-2.1.2
total 664
-rw-r--r-- 1 50469 users    889 Dec 31  2015 AUTHORS.te
drwxr-xr-x 6 50469 users   4096 Dec 31  2015 auto
-rw-r--r-- 1 50469 users 236013 Dec 31  2015 CHANGES
-rw-r--r-- 1 50469 users  18359 Dec 31  2015 CHANGES.cn
-rw-r--r-- 1 50469 users 359556 Dec 31  2015 CHANGES.ru
-rw-r--r-- 1 50469 users  23875 Dec 31  2015 CHANGES.te
drwxr-xr-x 2 50469 users   4096 Dec 31  2015 conf
-rwxr-xr-x 1 50469 users   2435 Dec 31  2015 configure
drwxr-xr-x 4 50469 users    103 Dec 31  2015 contrib
drwxr-xr-x 3 50469 users     20 Dec 31  2015 docs
-rw-r--r-- 1 50469 users    441 Dec 31  2015 good_configure
drwxr-xr-x 2 50469 users     38 Dec 31  2015 html
-rw-r--r-- 1 50469 users   1676 Dec 31  2015 LICENSE
drwxr-xr-x 2 50469 users     20 Dec 31  2015 man
drwxr-xr-x 4 50469 users     53 Dec 31  2015 modules
drwxr-xr-x 3 50469 users     19 Dec 31  2015 packages
-rw-r--r-- 1 50469 users   3223 Dec 31  2015 README
-rw-r--r-- 1 50469 users   3775 Dec 31  2015 README.markdown
drwxr-xr-x 9 50469 users     82 Dec 31  2015 src
drwxr-xr-x 4 50469 users     41 Dec 31  2015 tests
-rw-r--r-- 1 50469 users     43 Dec 31  2015 THANKS.te

[aaa@qq.com src]# cd tengine-2.1.2

1.3.3:生成 Makefile

Tengine 的编译参数和 Nginx 基本相同,以下为 Tengine 特有的编译参数:

--dso-path

Set the installation directory for the DSO modules.

--dso-tool-path

Set the installation path for the dso_tool script.

--without-dso

Disable the DSO (Dynamic Shared Object) feature.

--with-jemalloc

Enable Tengine to link the jemalloc library for memory management.

--with-jemalloc=path

Set the path to the source code of the jemalloc library.

P.S.
Tengine-2.1.2 中不支持 --with-stram* 的编译参数,想必 stream 相关的功能已默认加载;

./configure --prefix=/apps/tengine \
  --user=nginx \
  --group=nginx \
  --with-http_ssl_module \
  --with-http_v2_module \
  --with-http_realip_module \
  --with-http_stub_status_module \
  --with-http_gzip_static_module \
  --with-pcre \
  --with-file-aio \
    --with-ipv6

1.3.4:编译并安装

[aaa@qq.com tengine-2.1.2]# make && make install

1.3.5:创建 nginx 软链接

Tengine 也是采用 nginx 命令,这里为了方便区分,建立的是 tengine 软链接;

[aaa@qq.com ~]# ln -sv /apps/tengine/sbin/nginx /usr/bin/nginx
‘/usr/bin/nginx’ -> ‘/apps/tengine/sbin/nginx’

1.3.6:验证编译安装

  • 查看 tengine 编译安装生成的文件目录:
[aaa@qq.com ~]# ll /apps/tengine/
total 8
drwxr-xr-x 2 root root 4096 Dec  5 16:52 conf
drwxr-xr-x 2 root root   38 Dec  5 16:52 html
drwxr-xr-x 2 root root 4096 Dec  5 16:52 include
drwxr-xr-x 2 root root   22 Dec  5 16:55 logs
drwxr-xr-x 2 root root    6 Dec  5 16:52 modules
drwxr-xr-x 2 root root   33 Dec  5 16:52 sbin
  • 查看 tengine 版本及编译参数:
[aaa@qq.com ~]# nginx -V
Tengine version: Tengine/2.1.2 (nginx/1.6.2)
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC) 
TLS SNI support enabled
configure arguments: --prefix=/apps/tengine --user=nginx --group=nginx --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre --with-file-aio
nginx: [emerg] invalid port in resolver "fe80::1%eth0" in /apps/tengine/conf/nginx.conf:123

Tengine 有一个自动解析/etc/resolve.conf文件构造resolver的功能,但这个功能还不支持IPv6,所以解析报错:
nginx: [emerg] invalid port in resolver “fe80::1%eth0” in /apps/tengine/conf/nginx.conf:123

可以通过删除 /etc/resolv.conf 中的 nameserver fe80::1%eth0 这条 ipv6 解析条目来临时解决(重启网络后会失效):

[aaa@qq.com ~]# vim /etc/resolv.conf             
# Generated by NetworkManager
nameserver 192.168.1.1
nameserver fe80::1%eth0

[aaa@qq.com ~]# cat /etc/resolv.conf 
# Generated by NetworkManager
nameserver 192.168.1.1
  • 接下来 tengine 的编译参数就可以完整加载了(后续的启动也不会再报相同的错误):
[aaa@qq.com ~]# tengine -V
Tengine version: Tengine/2.1.2 (nginx/1.6.2)
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC) 
TLS SNI support enabled
configure arguments: --prefix=/apps/tengine --user=nginx --group=nginx --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre --with-file-aio --with-ipv6
loaded modules:
    ngx_core_module (static)
    ngx_errlog_module (static)
    ngx_conf_module (static)
    ngx_dso_module (static)
    ngx_syslog_module (static)
    ngx_events_module (static)
    ngx_event_core_module (static)
    ngx_epoll_module (static)
    ngx_procs_module (static)
    ngx_proc_core_module (static)
    ngx_openssl_module (static)
    ngx_regex_module (static)
    ngx_http_module (static)
    ngx_http_core_module (static)
    ngx_http_log_module (static)
    ngx_http_upstream_module (static)
    ngx_http_v2_module (static)
    ngx_http_static_module (static)
    ngx_http_gzip_static_module (static)
    ngx_http_autoindex_module (static)
    ngx_http_index_module (static)
    ngx_http_auth_basic_module (static)
    ngx_http_access_module (static)
    ngx_http_limit_conn_module (static)
    ngx_http_limit_req_module (static)
    ngx_http_realip_module (static)
    ngx_http_geo_module (static)
    ngx_http_map_module (static)
    ngx_http_split_clients_module (static)
    ngx_http_referer_module (static)
    ngx_http_rewrite_module (static)
    ngx_http_ssl_module (static)
    ngx_http_proxy_module (static)
    ngx_http_fastcgi_module (static)
    ngx_http_uwsgi_module (static)
    ngx_http_scgi_module (static)
    ngx_http_memcached_module (static)
    ngx_http_empty_gif_module (static)
    ngx_http_browser_module (static)
    ngx_http_user_agent_module (static)
    ngx_http_upstream_ip_hash_module (static)
    ngx_http_upstream_consistent_hash_module (static)
    ngx_http_upstream_check_module (static)
    ngx_http_upstream_least_conn_module (static)
    ngx_http_upstream_keepalive_module (static)
    ngx_http_upstream_dynamic_module (static)
    ngx_http_stub_status_module (static)
    ngx_http_write_filter_module (static)
    ngx_http_header_filter_module (static)
    ngx_http_chunked_filter_module (static)
    ngx_http_v2_filter_module (static)
    ngx_http_range_header_filter_module (static)
    ngx_http_gzip_filter_module (static)
    ngx_http_postpone_filter_module (static)
    ngx_http_ssi_filter_module (static)
    ngx_http_charset_filter_module (static)
    ngx_http_userid_filter_module (static)
    ngx_http_footer_filter_module (static)
    ngx_http_trim_filter_module (static)
    ngx_http_headers_filter_module (static)
    ngx_http_upstream_session_sticky_module (static)
    ngx_http_reqstat_module (static)
    ngx_http_copy_filter_module (static)
    ngx_http_range_body_filter_module (static)
    ngx_http_not_modified_filter_module (static)

1.3.7:Tengine 默认配置

[aaa@qq.com ~]# grep -v "#" /apps/tengine/conf/nginx.conf | grep -v "^$"     
worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       80;
        server_name  localhost;
        location / {
            root   html;
            index  index.html index.htm;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}

1.3.8:创建 Tengine 启动脚本

  • 编辑启动脚本:
[aaa@qq.com ~]# vim /usr/lib/systemd/system/nginx.service
[Unit]
Description=The nginx HTTP and reverse proxy server
After=network.target remote-fs.target nss-lookup.target

[Service]
Type=forking
PIDFile=/apps/tengine/logs/nginx.pid
ExecStartPre=/usr/bin/rm -f /apps/tengine/logs/nginx.pid
ExecStartPre=/apps/tengine/sbin/nginx -t
ExecStart=/apps/tengine/sbin/nginx
ExecReload=/bin/kill -s HUP $MAINPID
KillSignal=SIGQUIT
TimeoutStopSec=5
KillMode=process
PrivateTmp=true

[Install]
WantedBy=multi-user.target
  • 重载 systemd:
[aaa@qq.com ~]# systemctl daemon-reload

1.3.9:启动 Tengine

[aaa@qq.com ~]# systemctl start nginx
[aaa@qq.com ~]# systemctl enable nginx
Created symlink from /etc/systemd/system/multi-user.target.wants/nginx.service to /usr/lib/systemd/system/nginx.service.

1.3.10:访问 Tengine

Nginx 全实践

二:Nginx 基础配置实践

2.1:server_name 配置

2.1.1:http 配置段导入 conf.d 下的配置文件

  • 删除默认 server 配置,并为 http 配置段导入 conf.d 下的配置文件:
[aaa@qq.com ~]# vim /apps/nginx/conf/nginx.conf
http {
    ……
    include /apps/nginx/conf.d/*.conf;
    ……
}
  • 重载 nginx:
[aaa@qq.com ~]# systemctl reload nginx

2.1.2:新建一个 PC 端站点

  • 编辑配置文件:
[aaa@qq.com ~]# vim /apps/nginx/conf.d/www.yqc.com.conf
server {
  listen 192.168.1.106:80;
  server_name www.yqc.com;
  location / {
    root /data/nginx/yqc/www;
  }
}
  • 检查配置文件:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
  • 重载nginx:
[aaa@qq.com ~]# systemctl reload nginx
  • 准备 PC 端测试页面:
[aaa@qq.com ~]# mkdir /data/nginx/yqc/www -pv
mkdir: created directory ‘/data’
mkdir: created directory ‘/data/nginx’
mkdir: created directory ‘/data/nginx/yqc’
mkdir: created directory ‘/data/nginx/yqc/www’

[aaa@qq.com ~]# vim /data/nginx/yqc/www/index.html
PC site
  • 访问测试

2.1.3:新建一个移动端站点

  • 编辑配置文件:
[aaa@qq.com ~]# vim /apps/nginx/conf.d/wap.yqc.com.conf
server {
  listen 192.168.1.106:80;
  server_name wap.yqc.com;
  location / {
    root /data/nginx/yqc/wap;
  }
}
  • 检查配置文件并重载nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx
  • 准备移动端测试页:
[aaa@qq.com ~]# mkdir /data/nginx/yqc/wap
[aaa@qq.com ~]# vim /data/nginx/yqc/wap/index.html
wap site
  • 访问测试

2.2:location 匹配

2.2.1:不指定匹配方式

  • 编辑配置文件:
[aaa@qq.com ~]# vim /apps/nginx/conf.d/www.yqc.com.conf 
server {
  listen 192.168.1.106:80;
  server_name www.yqc.com;

  location / {
    root /data/nginx/yqc/www;
    index index.html;
  }

  location /images {
    root /data/nginx/yqc/www;
  }

  location /text {
    root /data/nginx/yqc;
  }
}

访问以 /images 开始的 URI,root 为 /data/nginx/yqc/www;
访问以 /text 开始的 URI, root 为 root /data/nginx/yqc;

  • 准备测试页面:
[aaa@qq.com ~]# mkdir /data/nginx/yqc/text
[aaa@qq.com ~]# vim /data/nginx/yqc/text/test.txt
test text
  • 访问测试

    http://www.yqc.com/images/ironman.jpg
    http://www.yqc.com/text/test.txt

2.2.2:精确匹配

  • 编辑配置文件:
[aaa@qq.com ~]# vim /apps/nginx/conf.d/www.yqc.com.conf
server {
  listen 192.168.1.106:80;
  server_name www.yqc.com;
  
  location / {
    root /data/nginx/yqc/www;
    index index.html;
  }
  
  location = /ironman.jpg {
    root /data/nginx/yqc/www/images;
  }
}

访问 http://www.yqc.com/ironman.jpg 时,root 为 /data/nginx/yqc/www/images;

  • 检查配置文件并重载nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# !sys
systemctl reload nginx
  • 验证访问
    http://www.yqc.com/ironman.jpg

2.2.3:正则表达式匹配 - 区分大小写

  • 编辑配置文件:
server {
  listen 192.168.1.106:80;
  server_name www.yqc.com;

#  location / {
#    root /data/nginx/yqc/www;
#    index index.html;
#  }

  location ~ /images/.*\.JPG {
    root /data/nginx/yqc/www;
  }
}
  • 检查配置文件并重载nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# !sys
systemctl reload nginx
  • 准备测试文件:
[aaa@qq.com ~]# ll /data/nginx/yqc/www/images/
total 1340
-rw-r--r-- 1 root root 1113986 Dec  2 12:37 batman.JPG
-rw-r--r-- 1 root root  254358 Dec  2 09:53 ironman.jpg
  • 访问测试:
    仅能访问大写的 JPG,而不能识别 jpg 结尾的 URI;

2.2.4:正则表达式匹配 - 不区分大小写

  • 将上述配置改为 ~*
server {
  listen 192.168.1.106:80;
  server_name www.yqc.com;

#  location / {
#    root /data/nginx/yqc/www;
#    index index.html;
#  }

  location ~* /images/.*\.JPG {
    root /data/nginx/yqc/www;
  }
}
  • 检查配置文件并重载nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# !sys
systemctl reload nginx
  • 访问测试
    可以访问 jpg 结尾的图片;

2.2.5:正则表达式匹配 - 匹配 URI 起始

验证: ^~~ 的匹配优先级高;

  • 编辑配置文件:
server {
  listen 192.168.1.106:80;
  server_name www.yqc.com;

#  location / {
#    root /data/nginx/yqc/www;
#    index index.html;
#  }

  location ~ /images/.*\.jpg {
    root /data/nginx/yqc/www;
  }

  location ^~ /images {
    root /data/nginx/yqc;
  }
}
  • 准备测试图片:
[aaa@qq.com ~]# mkdir /data/nginx/yqc/images
[aaa@qq.com ~]# cp ironman.jpg /data/nginx/yqc/images/ironman111.jpg
  • 访问测试:
    可以访问http://www.yqc.com/images/ironman111.jpg;
    但不能访问http://www.yqc.com/images/ironman.jpg;
    因为优先匹配location ^~ /images,而根据其中指定的 root,存在 /data/nginx/yqc/images/ironman111.jpg,但不存在 /data/nginx/yqc/images/ironman111.jpg

2.3:Nginx 安全

2.3.1:allow/deny 访问控制

通过匹配请求的源 IP 地址,对访问进行控制;

  • 编辑配置文件:
[aaa@qq.com ~]# vim /apps/nginx/conf.d/www.yqc.com.conf 
server {
  listen 192.168.1.106:80;
  server_name www.yqc.com;

  location / {
    root /data/nginx/yqc/www;
    index index.html;
    allow 192.168.1.66;
    deny all;
  }
}
~           
  • 检查配置文件并重载nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx
  • 192.168.1.66 访问:

Nginx 全实践

  • 192.168.1.9 访问:

Nginx 全实践

2.3.2:basic 用户认证

  • 安装 httpd-tools,以使用 htpasswd 命令:
[aaa@qq.com ~]# yum install httpd-tools -y
  • 创建用户认证文件,并添加第一个认证用户:
[aaa@qq.com ~]# htpasswd -cbm /apps/nginx/conf/.htpasswd user1 123456
Adding password for user user1
  • 添加第二个用户:
[aaa@qq.com ~]# htpasswd -bm /apps/nginx/conf/.htpasswd user2 123456 
Adding password for user user2
  • 查看用户认证文件:
[aaa@qq.com ~]# cat /apps/nginx/conf/.htpasswd 
user1:$apr1$D9a1alP8$/PI5dWmw.puO6OBGcpL/F1
user2:$apr1$CLtPB5Sc$YFk83BEiQO2hLEGPyxic90
  • 编辑 nginx 配置文件:
[aaa@qq.com ~]# vim /apps/nginx/conf.d/www.yqc.com.conf 
server {
  listen 192.168.1.106:80;
  server_name www.yqc.com;

  location / {
    root /data/nginx/yqc/www;
    index index.html;
    auth_basic "username/password";
    auth_basic_user_file /apps/nginx/conf/.htpasswd;
  }
}
  • 检查配置文件并重载nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx
  • 访问测试:

Nginx 全实践

2.3.3:limit_except

  • 编辑配置文件
[aaa@qq.com ~]# vim /apps/nginx/conf.d/www.yqc.com.conf
server {
  listen 192.168.1.106:80;
  server_name www.yqc.com;
  error_page 500 502 503 504 404 /error.html;
  access_log /data/nginx/logs/www-yqc-com_access.log;
  error_log /data/nginx/logs/www-yqc-com_error.log;
  client_max_body_size 10m;
  client_body_buffer_size 16k;
  client_body_temp_path /data/nginx/temp 1 2 2;
  location / {
    root /data/nginx/yqc/www;
    index index.html;
  }

  location = /error.html {
    root /data/nginx/yqc/redirect;
  }

  location /upload {
    root /data/nginx/yqc/www;
    index index.html;
    limit_except GET {
      allow 192.168.1.105;
      deny all;
    }
  }
}

配置:

  • 仅允许 192.168.1.105 执行除 GET 之外的其它操作;
  • 其他 IP 仅允许 GET(允许GET的同时意味着也允许HEAD);
  • 检查配置文件并重载nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx
  • 创建目录:
[aaa@qq.com ~]# mkdir /data/nginx/yqc/www/upload
[aaa@qq.com ~]# chown -R nginx:nginx /data/nginx
  • 使用192.168.1.105 上传文件:
[aaa@qq.com ~]# curl -XPUT /etc/issue http://www.yqc.com/upload
curl: (3) <url> malformed
<html>
<head><title>405 Not Allowed</title></head>
<body>
<center><h1>405 Not Allowed</h1></center>
<hr><center>nginx/1.18.0</center>
</body>
</html>

405 表示Nginx已经允许 PUT 操作,但程序不支持上传功能;

  • 使用192.168.1.111 上传文件:
aaa@qq.com:~# curl -XPUT /etc/issue http://www.yqc.com/upload
curl: (3) <url> malformed
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.18.0</center>
</body>
</html>

403 表示 PUT 被 Nginx 拒绝;

2.3.4:隐藏 Nginx 版本

  • 更改 Nginx 源码信息:
[aaa@qq.com ~]# vim /usr/local/src/nginx-1.18.0/src/http/ngx_http_header_filter_module.c
static u_char ngx_http_server_string[] = "Server: yqc" CRLF;
  • 重新编译安装nginx:
[aaa@qq.com ~]# systemctl stop nginx
[aaa@qq.com ~]# cd /usr/local/src/nginx-1.18.0/

[aaa@qq.com nginx-1.18.0]# ./configure \
--prefix=/apps/nginx \
--user=nginx --group=nginx \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_realip_module \
--with-http_stub_status_module \
--with-http_gzip_static_module \
--with-pcre \
--with-stream \
--with-stream_ssl_module \
--with-stream_realip_module \
--add-module=/usr/local/src/echo-nginx-module

[aaa@qq.com nginx-1.18.0]# make && make install

[aaa@qq.com nginx-1.18.0]# systemctl start nginx
  • 访问验证响应报文头部

没改过来,不深究了;

2.3.5:编译升级 OpenSSL

升级 openssl 主要是为了解决 heartbleed 安全漏洞;

heartbleed 漏洞存在于 OpenSSL 的 1.0.1 至 1.0.1f(含)版本中,较新版本及先前版本均不受影响;

[aaa@qq.com ~]# yum info openssl
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
 * base: mirrors.aliyun.com
 * extras: mirrors.aliyun.com
 * updates: mirrors.aliyun.com
Installed Packages
Name        : openssl
Arch        : x86_64
Epoch       : 1
Version     : 1.0.2k
Release     : 19.el7
Size        : 814 k
Repo        : installed
From repo   : base
Summary     : Utilities from the general purpose cryptography library with TLS implementation
URL         : http://www.openssl.org/
License     : OpenSSL
Description : The OpenSSL toolkit provides support for secure communications between
            : machines. OpenSSL includes a certificate management tool and shared
            : libraries which provide various cryptographic algorithms and
            : protocols.

此次系统上的 OpenSSL 版本为 1.0.2k,已不存在此安全漏洞,仅为了测试升级步骤;

  • 查看当前 openssl 版本:

    当前为 1.0.2k;

[aaa@qq.com ~]# nginx -V
nginx version: nginx/1.18.0
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC) 
built with OpenSSL 1.0.2k-fips  26 Jan 2017
TLS SNI support enabled
configure arguments: --prefix=/apps/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre --with-stream --with-stream_ssl_module --with-stream_realip_module
  • 下载并解压 openssl 源码包:

openssl 官网:https://www.openssl.org

本次下载的为 openssl-1.1.1h,下载地址为:https://www.openssl.org/source/openssl-1.1.1h.tar.gz

[aaa@qq.com ~]# cd /usr/local/src/
[aaa@qq.com src]# tar zxvf openssl-1.1.1h.tar.gz
  • 重新编译安装 nginx:
[aaa@qq.com ~]# systemctl stop nginx
[aaa@qq.com ~]# cd /usr/local/src/nginx-1.18.0/

[aaa@qq.com nginx-1.18.0]# ./configure \
--prefix=/apps/nginx \
--user=nginx --group=nginx \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_realip_module \
--with-http_stub_status_module \
--with-http_gzip_static_module \
--with-pcre \
--with-stream \
--with-stream_ssl_module \
--with-stream_realip_module \
--add-module=/usr/local/src/echo-nginx-module \
--with-openssl=/usr/local/src/openssl-1.1.1h

[aaa@qq.com nginx-1.18.0]# make && make install
  • 验证 openssl 版本:

    版本升级为 1.1.1h

[aaa@qq.com ~]# nginx -V
nginx version: nginx/1.18.0
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC) 
built with OpenSSL 1.1.1h  22 Sep 2020
TLS SNI support enabled
configure arguments: --prefix=/apps/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre --with-stream --with-stream_ssl_module --with-stream_realip_module --add-module=/usr/local/src/echo-nginx-module --with-openssl=/usr/local/src/openssl-1.1.1h

2.4:Nginx 日志

2.4.1:access_log 访问日志

  • 编辑配置文件:
[aaa@qq.com ~]# vim /apps/nginx/conf.d/www.yqc.com.conf         
server {
  listen 192.168.1.106:80;
  server_name www.yqc.com;
  error_page 500 502 503 504 404 /error.html;
  access_log /data/nginx/logs/www-yqc-com_access.log;
  location / {
    root /data/nginx/yqc/www;
    index index.html;
  }

  location = /error.html {
    root /data/nginx/yqc/redirect;
  }
}
  • 创建相应日志目录:
[aaa@qq.com ~]# mkdir /data/nginx/logs
  • 检查配置文件并重载nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx
  • 访问并查看日志:
[aaa@qq.com ~]# tail -f /data/nginx/logs/www-yqc-com_access.log 
192.168.1.9 - user1 [02/Dec/2020:13:45:31 +0800] "GET /tom.jpg HTTP/1.1" 404 6 "-" "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36"
192.168.1.9 - user1 [02/Dec/2020:13:45:37 +0800] "GET /tom.jpg HTTP/1.1" 404 6 "-" "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36"
192.168.1.9 - user1 [02/Dec/2020:13:45:50 +0800] "GET /images/batman.JPG HTTP/1.1" 200 1113986 "-" "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36"
192.168.1.66 - - [02/Dec/2020:13:46:14 +0800] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:83.0) Gecko/20100101 Firefox/83.0"

2.4.2:error_log 错误日志

  • 编辑配置文件:
[aaa@qq.com ~]# vim /apps/nginx/conf.d/www.yqc.com.conf         
server {
  listen 192.168.1.106:80;
  server_name www.yqc.com;
  error_page 500 502 503 504 404 /error.html;
  access_log /data/nginx/logs/www-yqc-com_access.log;
  error_log /data/nginx/logs/www-yqc-com_error.log;
  location / {
    root /data/nginx/yqc/www;
    index index.html;
  }

  location = /error.html {
    root /data/nginx/yqc/redirect;
  }
}
  • 检查配置文件并重载nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx
  • 访问并查看日志:
[aaa@qq.com ~]# tail -f /data/nginx/logs/www-yqc-com_error.log 
2020/12/02 13:53:10 [error] 5113#0: *65 open() "/data/nginx/yqc/www/images/tom.jpg" failed (2: No such file or directory), client: 192.168.1.9, server: www.yqc.com, request: "GET /images/tom.jpg HTTP/1.1", host: "www.yqc.com"

2.5:Nginx 应用

2.5.1:root 与 alias

root 与 alias 的区别:

  • 在 location 中指定 root 时,location 指定的 URI 的文件系统路径为:root + URI;
    比如:

    location /images {
      root /data/nginx/yqc/www;
    }
    

    如果要访问的是 http://www.yqc.com/images/1.jpg,那么文件的路径为:/data/nginx/yqc/www/images/1.jpg

  • 在 location 中指定 alias 时,location 指定的 URI 的文件系统路径为:alias;

比如:

location /images {
  alias /data/nginx/yqc/www;
}

如果要访问的是 http://www.yqc.com/images/1.jpg,那么文件的路径为:/data/nginx/yqc/www/1.jpg

指定 root 与 alias

  • 编辑配置文件:
[aaa@qq.com ~]# vim /apps/nginx/conf.d/www.yqc.com.conf 
server {
  listen 192.168.1.106:80;
  server_name www.yqc.com;

  location / {
    root /data/nginx/yqc/www;
    index index.html;
  }

  location /images {
    root /data/nginx/yqc/www;
  }

  location /images-alias {
    alias /data/nginx/yqc/www;
  }
}
  • 重载nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx
  • 准备 root 测试图片:
[aaa@qq.com ~]# mkdir /data/nginx/yqc/www/images
[aaa@qq.com ~]# cp ironman.jpg /data/nginx/yqc/www/images/
  • 准备 alias 测试图片:
[aaa@qq.com ~]# cp batman.jpg /data/nginx/yqc/www/

访问指定了 root 的 URI

  • 浏览器访问 http://www.yqc.com/images/ironman.jpg

Nginx 全实践

访问指定了 alias 的 URI

  • 浏览器访问 http://www.yqc.com/images-alias/batman.jpg

Nginx 全实践

2.5.2:error_page 错误页面

  • 编辑配置文件:
[aaa@qq.com ~]# vim /apps/nginx/conf.d/www.yqc.com.conf                   
server {
  listen 192.168.1.106:80;
  server_name www.yqc.com;
  error_page 500 502 503 504 404 /error.html;

  location / {
    root /data/nginx/yqc/www;
    index index.html;
  }

  location = /error.html {
    root /data/nginx/yqc/redirect;
  }
}
  • 检查配置文件并重载nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx
  • 准备错误页面:
[aaa@qq.com ~]# mkdir /data/nginx/yqc/redirect
[aaa@qq.com ~]# vim /data/nginx/yqc/redirect/error.html 
sorry
  • 访问测试:

Nginx 全实践

2.5.3:try_files

  • 编辑配置文件:
[aaa@qq.com ~]# vim /apps/nginx/conf.d/www.yqc.com.conf 
server {
  listen 192.168.1.106:80;
  server_name www.yqc.com;
  error_page 500 502 503 504 404 /error.html;
  access_log /data/nginx/logs/www-yqc-com_access.log;
  error_log /data/nginx/logs/www-yqc-com_error.log;
  location / {
    root /data/nginx/yqc/www;
    index index.html;
  }

  location = /error.html {
    root /data/nginx/yqc/redirect;
  }

  location ^~ /images {
    root /data/nginx/yqc/www;
    try_files $uri $uri.jpg /images/default.jpg;
  }
}
  • 检查配置文件并重载nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx
  • 准备测试图片:
[aaa@qq.com ~]# ll /data/nginx/yqc/www/images/
total 1372
-rw-r--r-- 1 root root 1113986 Dec  2 12:37 batman.JPG
-rw-r--r-- 1 root root   31912 Dec  2 14:20 default.jpg
-rw-r--r-- 1 root root  254358 Dec  2 09:53 ironman.jpg
  • 访问不存在的文件,显示default.jpg:

Nginx 全实践

  • 访问不加jpg后缀的图片:

Nginx 全实践

2.5.4:auto_index 显示列表

可以使用该选项配置下载服务器;

  • 编辑配置文件:
server {
  listen 192.168.1.106:80;
  server_name www.yqc.com;
  error_page 500 502 503 504 404 /error.html;
  access_log /data/nginx/logs/www-yqc-com_access.log;
  error_log /data/nginx/logs/www-yqc-com_error.log;
  location / {
    root /data/nginx/yqc/www;
    index index.html;
  }

  location = /error.html {
    root /data/nginx/yqc/redirect;
  }

  location /download {
    root /data/nginx/yqc/www;
    autoindex on;
    autoindex_exact_size off;
    autoindex_localtime on;
    autoindex_format html;
    limit_rate 1k;
  }
}

配置为:

  • 开启自动索引;
  • 不显示文件精确大小(即以 K、M等单位显示);
  • 显示为当前系统时间;
  • 显示格式为 html;
  • 设置每个连接的速率限制为 1KB/s;(这个限制是针对单个连接的,如果一个客户端同时开了多个连接,则总的速率限制为 limit_rate 乘以连接数)
  • 准备下载目录及文件:
[aaa@qq.com ~]# mkdir /data/nginx/yqc/www/download
[aaa@qq.com ~]# cp /usr/local/src/nginx-1.18.0/* /data/nginx/yqc/www/download -R
  • 检查配置文件并重载nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx
  • 访问及下载测试:

Nginx 全实践

  • 下载速度为 1KB/s 左右:

Nginx 全实践

2.5.5:stub_status 状态页

  • 编辑配置文件:
[aaa@qq.com ~]# vim /apps/nginx/conf.d/www.yqc.com.conf
server {
  listen 192.168.1.106:80;
  server_name www.yqc.com;
  error_page 500 502 503 504 404 /error.html;
  access_log /data/nginx/logs/www-yqc-com_access.log;
  error_log /data/nginx/logs/www-yqc-com_error.log;
  location / {
    root /data/nginx/yqc/www;
    index index.html;
  }

  location = /error.html {
    root /data/nginx/yqc/redirect;
  }

  location = /status {
    stub_status;
    allow 192.168.1.0/24;
    allow 127.0.0.1;
    deny all;
  }
}

配置:

  • 仅允许192.168.1.0/24 和 本地访问状态页;
  • 检查配置文件并重载nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx
  • 访问状态页:

Nginx 全实践

2.5.6:favicon.ico 网站图标

浏览器发送请求时,会自动请求获取页面的图标文件;
如果图标文件不存在,会产生 404 错误;

设置不记录错误日志

  • 查看修改前的错误日志:
2020/12/03 11:31:23 [error] 4460#0: *28 open() "/data/nginx/yqc/www/favicon.ico" failed (2: No such file or directory), client: 192.168.1.9, server: www.yqc.com, request: "GET /favicon.ico HTTP/1.1", host: "www.yqc.com", referrer: "https://www.yqc.com/"
  • 修改配置文件:
[aaa@qq.com ~]# cat /apps/nginx/conf.d/www.yqc.com.conf
server {
  ……

  location = /favicon.ico {
    log_not_found off;
    access_log off;
  }
}

配置 URI 为 /favicon.ico 时:

  • 不记录“文件未找到”的错误日志;
  • 不记录访问日志;
  • 检查配置文件并重载nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx
  • 访问并查看是否有新的错误日志

设置网站图标

  • 编辑配置文件:
[aaa@qq.com ~]# vim /apps/nginx/conf.d/www.yqc.com.conf 
server {
  ……
  location = /favicon.ico {
    root /data/nginx/yqc/www/images;
    #log_not_found off;
    access_log off;
    expires 90d;
  }
}
  • 准备图标文件:
[aaa@qq.com ~]# mv buding.jpg /data/nginx/yqc/www/images/favicon.ico
  • 检查配置文件并重载 nginx:
[aaa@qq.com ~]# nginx -t                                
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx
  • 访问测试:

Nginx 全实践

三:Nginx 高级配置实践

3.1:Nginx 编译安装第三方模块

第三模块是对nginx 的功能扩展;
第三⽅模块需要在编译安装Nginx 的时候使⽤参数–add-module=PATH指定路径添加;
nginx⽀持第三⽅模块需要从源码重新编译⽀持;
有的模块是由公司的开发⼈员针对业务需求定制开发的,有的模块是开源爱好者开发好之后上传到github进⾏开源的模块;

3.1.1:echo 模块

https://github.com/openresty/echo-nginx-module

克隆

  • 安装 git:
[aaa@qq.com ~]# yum install git -y
  • 从 github 克隆echo模块:
[aaa@qq.com ~]# cd /usr/local/src
[aaa@qq.com src]# git clone https://github.com/openresty/echo-nginx-module.git

[aaa@qq.com src]# ll echo-nginx-module/
total 76
-rw-r--r-- 1 root root  3184 Dec  2 16:33 config
-rw-r--r-- 1 root root  1345 Dec  2 16:33 LICENSE
-rw-r--r-- 1 root root 54502 Dec  2 16:33 README.markdown
drwxr-xr-x 2 root root  4096 Dec  2 16:33 src
drwxr-xr-x 2 root root  4096 Dec  2 16:33 t
drwxr-xr-x 2 root root    52 Dec  2 16:33 util
-rw-r--r-- 1 root root   986 Dec  2 16:33 valgrind.suppress

重新编译安装 Nginx

  • 查看 nginx 之前的编译参数:
[aaa@qq.com ~]# nginx -V
nginx version: nginx/1.18.0
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC) 
built with OpenSSL 1.0.2k-fips  26 Jan 2017
TLS SNI support enabled
configure arguments: --prefix=/apps/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre --with-stream --with-stream_ssl_module --with-stream_realip_module
[aaa@qq.com ~]#
  • 添加 echo 模块,重新生成 Makefile:
[aaa@qq.com ~]# cd /usr/local/src/nginx-1.18.0/

[aaa@qq.com nginx-1.18.0]# ./configure \
--prefix=/apps/nginx \
--user=nginx --group=nginx \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_realip_module \
--with-http_stub_status_module \
--with-http_gzip_static_module \
--with-pcre \
--with-stream \
--with-stream_ssl_module \
--with-stream_realip_module \
--add-module=/usr/local/src/echo-nginx-module
  • 重新编译安装 nginx:
[aaa@qq.com nginx-1.18.0]# make && make install

测试 echo 模块

  • 编译配置文件:
server {
  listen 192.168.1.106:80;
  server_name www.yqc.com;
  error_page 500 502 503 504 404 /error.html;
  access_log /data/nginx/logs/www-yqc-com_access.log;
  error_log /data/nginx/logs/www-yqc-com_error.log;
  location / {
    root /data/nginx/yqc/www;
    index index.html;
  }

  location = /error.html {
    root /data/nginx/yqc/redirect;
  }

  location = /status {
    stub_status;
    allow 192.168.1.0/24;
    allow 127.0.0.1;
    deny all;
  }

  location /main {
    index index.html;
    default_type text/html;
    echo "hello world,main-->";
    echo_reset_timer;
    echo_location /sub1;
    echo_location /sub2;
    echo "took $echo_timer_elapsed sec for total.";
  }

  location /sub1 {
    echo_sleep 1;
    echo sub1;
  }

  location /sub2 {
    echo_sleep 1;
    echo sub2;
  }
}
  • 检查配置文件并重启nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl restart nginx

新装模块需要重启生效;

  • 访问测试:
[aaa@qq.com ~]# curl http://www.yqc.com/main
hello world,main-->
sub1
sub2
took 2.003 sec for total.

3.1.2:concat 模块(Tengine)

⽹站中的css、js等⽂件都是⼩⽂件,单个⽂件⼤⼩⼏k甚⾄⼏个字节,所以⽂件的特点是⼩⽽多,会造成⽹站加载时http请求较多,且⽹络传输时间⽐较短,甚⾄有时候请求时间⽐传输时间还长;
当公司⽹站中的这类⼩⽂件很多时,⼤量的http请求就会造成传输效率低,影响⽹站的访问速度和客⼾端体验,这时合并http请求就⾮常有必要了;
concat模块就提供了合并⽂件http请求的功能,这个模块由淘宝开发,功能和apache的mod_concat模块类似。

编译 concat 动态模块

  • 安装 lua 和 lua-devel:
[aaa@qq.com ~]# yum install lua lua-devel
  • 查看之前的 tengine 编译参数
[aaa@qq.com ~]# nginx -V
Tengine version: Tengine/2.1.2 (nginx/1.6.2)
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC) 
TLS SNI support enabled
configure arguments: --prefix=/apps/tengine --user=nginx --group=nginx --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre --with-file-aio --with-ipv6
loaded modules:
    ngx_core_module (static)
    ngx_errlog_module (static)
    ……
  • 重新编译 tengine,将concat和lua编译为动态模块:
[aaa@qq.com ~]# cd /usr/local/src/tengine-2.1.2/
[aaa@qq.com tengine-2.1.2]# ./configure --prefix=/apps/tengine \
  --user=nginx \
  --group=nginx \
  --with-http_ssl_module \
  --with-http_v2_module \
  --with-http_realip_module \
  --with-http_stub_status_module \
  --with-http_gzip_static_module \
  --with-pcre \
  --with-file-aio \
  --with-ipv6 \
  --with-http_lua_module=shared \
  --with-http_concat_module=shared

[aaa@qq.com tengine-2.1.2]# make
  • 安装动态模块:
[aaa@qq.com tengine-2.1.2]# make dso_install

关于 make dso_install 的官方说明:

它将会复制动态库文件到你的动态模块目录,或者你也可以手工拷贝动态模块文件(文件是在objs/modules)到你想要加载的目录.

你能够使用dso_tool(在Nginx安装目录的sbin下)这个工具来编译第三方模块.

示例

./dso_tool --add-module=/home/dso/lua-nginx-module

将会编译ngx_lua模块为动态库,然后安装到默认的模块路径.如果你想要安装到指定位置,那么需要指定–dst选项(更多的选项请使用dso_tool -h查看).

加载 concat 动态模块

  • 查看模块文件:
[aaa@qq.com ~]# ll /apps/tengine/modules/
total 2784
-rwxr-xr-x 1 root root   93937 Dec  5 18:04 ngx_http_concat_module.so
-rwxr-xr-x 1 root root 2755475 Dec  5 18:04 ngx_http_lua_module.so
  • 编辑配置文件,加载 concat 动态模块:
dso {
  load ngx_http_concat_module.so;
  load ngx_http_lua_module.so;
}
  • 检查配置文件并重载 tengine:
[aaa@qq.com ~]# nginx -t
the configuration file /apps/tengine/conf/nginx.conf syntax is ok
configuration file /apps/tengine/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx

验证 concat 模块

  • 编辑配置文件,加入 concat 模块参数:
        location / {
            root   html;
            index  index.html index.htm;
            concat on;
        }
  • 检查配置文件并重载 tengine:
[aaa@qq.com ~]# nginx -t
the configuration file /apps/tengine/conf/nginx.conf syntax is ok
configuration file /apps/tengine/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx

未报错,表示已支持 concat 功能;

3.2:Nginx 自定义访问日志

3.2.1:Nginx 内置变量

  • $remote_addr
    客户端地址(公网IP,有可能是代理服务器的 IP);

  • $args
    URL 中的指令参数;

  • $document_root
    所请求的资源对应的 root 路径;

  • d o c u m e n t u r i U R L 中 的 U R I ( 不 包 含 指 令 参 数 ) ; 即 s e r v e r n a m e 、 document_uri URL中的URI(不包含指令参数); 即server_name、 documenturiURLURIservernamedocument_uri 和 $args 组成完整的 URL;

  • $host
    请求的Host;

  • $http_user_agent
    客户端的浏览器信息;

  • $http_cookie
    客户端的cookie信息;

  • $limit_rate
    limit_rate的值(未设置则显示默认值0);

  • $remote_port
    客户端的请求端口;

  • $remote_user
    通过basic验证的用户名;

  • $request_body_file
    nginx作为反向代理时,请求的后端服务器上的本地资源名称;

  • $request_method
    请求资源所用的method(GET、HEAD、PUT等);

  • $request_filename
    请求资源在文件系统上的绝对路径;

  • $request_uri
    请求的完整URI;
    $document_uri 和 $args 组成 $request_uri;

  • $scheme
    请求的协议,如http、https、ftp等;

  • $server_protocol
    请求资源所用的协议(包括版本),如HTTP/1,0、HTTP/1,1、HTTP/2.0等;

  • $server_addr
    服务器的IP地址;

  • $server_name
    server_name指定的虚拟服务器名称;

  • $server_port
    服务端的监听端口;

  • $upstream_cache_status
    缓存状态;

    ·MISS 未命中,请求被传送到后端
    ·HIT 缓存命中
    ·EXPIRED 缓存已经过期请求被传送到后端
    ·UPDATING 正在更新缓存,将使用旧的应答
    ·STALE 后端将得到过期的应答
    
  • $proxy_add_x_forwarded_for

    KaTeX parse error: Double subscript at position 12: proxy_add_x_̲forwarded_for变量…remote_addr用逗号分开:

    • X-Forwarded-For:简称XFF头,它代表客户端,也就是HTTP的请求端真实的IP,只有在通过了HTTP 代理或者负载均衡服务器时才会添加该项。它不是RFC中定义的标准请求头信息。
      X-Forwarded-For 的记录格式:client1, proxy1, proxy2
      X-Forwarded-For头信息可以有多个,中间用逗号分隔,第一项为真实的客户端ip,剩下的就是曾经经过的代理或负载均衡的ip地址,经过几个就会出现几个。

    在默认情况下,Nginx并不会对X-Forwarded-For头做任何的处理,除非用户使用proxy_set_header 参数设置:
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    ​ 如果没有"X-Forwarded-For" 请求头,则KaTeX parse error: Double subscript at position 12: proxy_add_x_̲forwarded_for等于remote_addr($remote_addr变量的值是客户端的IP);

    当Nginx设置X-Forwarded-For于$proxy_add_x_forwarded_for后会有两种情况发生:

    1、如果从CDN过来的请求没有设置X-Forwarded-For头(通常这种事情不会发生),而到了我们这里Nginx设置将其设置为$proxy_add_x_forwarded_for的话,X-Forwarded-For的信息应该为CDN的IP,因为相对于Nginx负载均衡来说客户端即为CDN,这样的话,后端的web程序时死活也获得不了真实用户的IP的。

    2、CDN设置了X-Forwarded-For,我们这里又设置了一次,且值为$proxy_add_x_forwarded_for的话,那么X-Forwarded-For的内容变成 ”客户端IP,Nginx负载均衡服务器IP“如果是这种情况的话,那后端的程序通过X-Forwarded-For获得客户端IP,则取逗号分隔的第一项即可。

  • $http_x_forwarded_for

    Nginx中还有一个$http_x_forwarded_for变量,这个变量中保存的内容就是请求中的X-Forwarded-For信息。如果后端获得X-Forwarded-For信息的程序兼容性不好的话(没有考虑到X-Forwarded-For含有多个IP的情况),最好就不要将X-Forwarded-For设置为 KaTeX parse error: Double subscript at position 12: proxy_add_x_̲forwarded_for。应…http_x_forwarded_for或者干脆不设置。

  • $fastcgi_script_name
    此变量保存的是请求的 URI,或者是以 / 结尾的 URI(即访问的是默认主页);

    比如在 location ~ \.php$ 中配置

    root /data/nginx/yqc/www;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name
    当访问的 URI 为 /appv1/test.php 时,
    $document_root 指向 /data/nginx/yqc/www,
    $fastcgi_script_name 指向 /appv1/test.php,
    最终 SCRIPT_FILENAME 的值,即请求的 URI 指向的文件系统路径为:/data/nginx/yqc/www/appv1/test.php;

    $fastcgi_script_name
    

    request URI or, if a URI ends with a slash, request URI with an index file name configured by the fastcgi_index directive appended to it. This variable can be used to set the SCRIPT_FILENAME and PATH_TRANSLATED parameters that determine the script name in PHP. For example, for the “/info/” request with the following directives

    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME /home/www/scripts/php$fastcgi_script_name;
    

    the SCRIPT_FILENAME parameter will be equal to “/home/www/scripts/php/info/index.php”.

    When using the fastcgi_split_path_info directive, the $fastcgi_script_name variable equals the value of the first capture set by the directive.

3.2.2:Nginx 自定义变量

Syntax: set $variable value;

Default: —

Context: server, location, if

示例:

set $name magedu;
echo $name;
set $my_port $server_port;
echo $my_port;
echo "$server_name:$server_port";

3.2.3:自定义默认格式的访问日志

  • 定义日志格式:
[aaa@qq.com ~]# vim /apps/nginx/conf/nginx.conf
worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    log_format format1 '$remote_addr - $remote_user [$time_local] "$request"'
                              '$status $body_bytes_sent "$http_referer" '
                              '"$http_user_agent" "$http_x_forwarded_for"'
                              '$server_name:$server_port';
    include /apps/nginx/conf.d/*.conf;
}
  • 调用日志格式:
[aaa@qq.com ~]# vim /apps/nginx/conf.d/www.yqc.com.conf
server {
  listen 192.168.1.106:80;
  server_name www.yqc.com;
  error_page 500 502 503 504 404 /error.html;
  access_log /data/nginx/logs/www-yqc-com_access.log format1;
  error_log /data/nginx/logs/www-yqc-com_error.log;
  limit_rate 1024;
  location / {
    root /data/nginx/yqc/www;
    index index.html;
    limit_rate 1024;
  }

  location = /error.html {
    root /data/nginx/yqc/redirect;
  }

  location = /status {
    stub_status;
    allow 192.168.1.0/24;
    allow 127.0.0.1;
    deny all;
  }
}
  • 检查配置文件并重载nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx
  • 访问并查看日志:
[aaa@qq.com ~]# !tail
tail -f /data/nginx/logs/www-yqc-com_access.log 
192.168.1.9 - user1 [02/Dec/2020:18:12:31 +0800] "GET / HTTP/1.1"200 8 "-" "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36" "-"www.yqc.com:80

3.2.4:自定义 json 格式的访问日志

定义为 json 格式的访问日志,方便后期配合 ELK 对日志进行收集、统计和分析;

  • 定义 json 日志格式:
[aaa@qq.com ~]# vim /apps/nginx/conf/nginx.conf
worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    log_format format1 '$remote_addr - $remote_user [$time_local] "$request"'
                              '$status $body_bytes_sent "$http_referer" '
                              '"$http_user_agent" "$http_x_forwarded_for"'
                              '$server_name:$server_port';
    log_format format2 '{"@timestamp":"$time_iso8601",'
                '"host":"$server_addr",'
                '"clientip":"$remote_addr",'
                '"size":$body_bytes_sent,'
                '"responsetime":$request_time,'
                '"upstreamtime":"$upstream_response_time",'
                '"upstreamhost":"$upstream_addr",'
                '"http_host":"$host",'
                '"uri":"$uri",'
                '"domain":"$host",'
                '"xff":"$http_x_forwarded_for",'
                '"referer":"$http_referer",'
                '"tcp_xff":"$proxy_protocol_addr",'
                '"http_user_agent":"$http_user_agent",'
                '"status":"$status"}';
    include /apps/nginx/conf.d/*.conf;
}
  • 调动 json 日志格式:
[aaa@qq.com ~]# vim /apps/nginx/conf.d/www.yqc.com.conf         
server {
  listen 192.168.1.106:80;
  server_name www.yqc.com;
  error_page 500 502 503 504 404 /error.html;
  access_log /data/nginx/logs/www-yqc-com_access.log format2;
  error_log /data/nginx/logs/www-yqc-com_error.log;
  limit_rate 1024;
  location / {
    root /data/nginx/yqc/www;
    index index.html;
    limit_rate 1024;
  }

  location = /error.html {
    root /data/nginx/yqc/redirect;
  }

  location = /status {
    stub_status;
    allow 192.168.1.0/24;
    allow 127.0.0.1;
    deny all;
  }
}
  • 检查配置文件并重载nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx
  • 访问并查看日志:
[aaa@qq.com ~]# tail -f /data/nginx/logs/www-yqc-com_access.log
{"@timestamp":"2020-12-02T20:45:10+08:00","host":"192.168.1.106","clientip":"192.168.1.9","size":0,"responsetime":0.000,"upstreamtime":"-","upstreamhost":"-","http_host":"www.yqc.com","uri":"/index.html","domain":"www.yqc.com","xff":"-","referer":"-","tcp_xff":"-","http_user_agent":"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36","status":"304"}

3.3:Nginx 压缩

  • 编辑配置文件:
[aaa@qq.com ~]# vim /apps/nginx/conf.d/www.yqc.com.conf 
server {
  listen 192.168.1.106:80;
  server_name www.yqc.com;
  error_page 500 502 503 504 404 /error.html;
  access_log /data/nginx/logs/www-yqc-com_access_json.log format2;
  error_log /data/nginx/logs/www-yqc-com_error.log;
  gzip on;
  gzip_comp_level 3;
  gzip_min_length 1k;
  gzip_types text/plain application/javascript application/x-javascript text/cssapplication/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
  gzip_vary on;
  location / {
    root /data/nginx/yqc/www;
    index index.html;
  }

  location = /error.html {
    root /data/nginx/yqc/redirect;
  }

  location = /status {
    stub_status;
    allow 192.168.1.0/24;
    allow 127.0.0.1;
    deny all;
  }
}

配置:

  • 开启 gzip;
  • 压缩级别为 3;
  • 启用压缩的最小文件大小为 1k;
  • 定义压缩文件媒体类型;
  • 启用 gzip_vary,在响应头部中显示“Vary: Accept-Encoding” ;
  • 检查配置文件并重置nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx
  • 准备测试文件:
[aaa@qq.com ~]# ll -h /var/log/messages 
-rw-------. 1 root root 457K Dec  2 22:27 /var/log/messages

[aaa@qq.com ~]# cp /var/log/messages /data/nginx/yqc/www/messages.html
  • 验证压缩:
[aaa@qq.com ~]# curl --head --compressed http://www.yqc.com/messages.html
HTTP/1.1 200 OK
Server: nginx/1.18.0
Date: Wed, 02 Dec 2020 14:37:13 GMT
Content-Type: text/html
Last-Modified: Wed, 02 Dec 2020 14:28:38 GMT
Connection: keep-alive
Vary: Accept-Encoding
ETag: W/"5fc7a496-721cf"
Content-Encoding: gzip
  • 验证小于1k的文件不执行压缩:
[aaa@qq.com ~]# ll /data/nginx/yqc/www/index.html -h
-rw-r--r-- 1 nginx nginx 8 Dec  2 09:33 /data/nginx/yqc/www/index.html

[aaa@qq.com ~]# curl --head --compressed http://www.yqc.com/index.html   
HTTP/1.1 200 OK
Server: nginx/1.18.0
Date: Wed, 02 Dec 2020 14:37:58 GMT
Content-Type: text/html
Content-Length: 8
Last-Modified: Wed, 02 Dec 2020 01:33:03 GMT
Connection: keep-alive
ETag: "5fc6eecf-8"
Accept-Ranges: bytes

3.4:Nginx 实现 https

3.4.1:构建私有 CA

证书颁发机构(CA, Certificate Authority);

这里生成一个私钥 Key 和 自签名的 crt 证书,将自己作为一个私有 CA,后续为自己颁发 CA 证书;

  • 生成私有 CA 的私钥和自签名证书:

umask 077:设置创建文件或目录时的 umask 为 077,即创建的文件权限为 600,目录权限为 700;

[aaa@qq.com ~]# (umask 077; openssl req -newkey rsa:4096 -nodes -sha256 -keyout /etc/pki/CA/private/ca.key -x509 -days 3650 -out /etc/pki/CA/ca.crt)
Generating a 4096 bit RSA private key
...............................++
...........................................................................................................................................++
writing new private key to '/etc/pki/CA/private/ca.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:Shanxi
Locality Name (eg, city) [Default City]:Taiyuan
Organization Name (eg, company) [Default Company Ltd]:yqc
Organizational Unit Name (eg, section) []:Ops
Common Name (eg, your name or your server's hostname) []:yqc.ca
Email Address []:aaa@qq.com
  • 查看私钥和自签名 CA 证书:
[aaa@qq.com ~]# ll /etc/pki/CA/private/ca.key
-rw------- 1 root root 3272 Dec  3 10:12 /etc/pki/CA/private/ca.key

[aaa@qq.com ~]# ll /etc/pki/CA/ca.crt 
-rw------- 1 root root 2074 Dec  3 10:12 /etc/pki/CA/ca.crt

3.4.2:生成私钥和证书签署请求

csr 表示 Certificate Signature Request,证书签署请求;

  • 创建ssl目录(用于存放私钥和证书):
[aaa@qq.com ~]# mkdir /apps/nginx/ssl
  • 生成私钥和csr:
[aaa@qq.com ~]# openssl req -newkey rsa:4096 -nodes -sha256 -keyout /apps/nginx/ssl/www.yqc.com.key -out /apps/nginx/ssl/www.yqc.com.csr
Generating a 4096 bit RSA private key
...................++
..........................++
writing new private key to '/apps/nginx/ssl/www.yqc.com.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:Shanxi
Locality Name (eg, city) [Default City]:Taiyuan
Organization Name (eg, company) [Default Company Ltd]:yqc.com
Organizational Unit Name (eg, section) []:Ops
Common Name (eg, your name or your server's hostname) []:www.yqc.com
Email Address []:aaa@qq.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
  • 查看生成的文件:
[aaa@qq.com ~]# ll /apps/nginx/ssl/
total 8
-rw------- 1 root root 1740 Dec  3 10:27 www.yqc.com.csr
-rw------- 1 root root 3272 Dec  3 10:27 www.yqc.com.key

3.4.3:签发证书

  • 使用私有 CA 签发证书:
[aaa@qq.com ~]# openssl x509 -req -days 3650 -in /apps/nginx/ssl/www.yqc.com.csr -CA /etc/pki/CA/ca.crt -CAkey /etc/pki/CA/private/ca.key -CAcreateserial -out /apps/nginx/ssl/www.yqc.com.crt
Signature ok
subject=/C=CN/ST=Shanxi/L=Taiyuan/O=yqc.com/OU=Ops/CN=www.yqc.com/aaa@qq.com
Getting CA Private Key
  • 验证证书***和登记内容:
[aaa@qq.com ssl]# openssl x509 -in /apps/nginx/ssl/www.yqc.com.crt -noout -serial -subject      
serial=FA5590CFB34CBE92
subject= /C=CN/ST=Shanxi/L=Taiyuan/O=yqc.com/OU=Ops/CN=www.yqc.com/aaa@qq.com

[aaa@qq.com ssl]# cat /etc/pki/CA/ca.srl 
FA5590CFB34CBE92

3.4.4:www.yqc.com 的 https 访问

  • 编辑配置文件:
[aaa@qq.com ~]# vim /apps/nginx/conf.d/www.yqc.com.conf
server {
#  listen 192.168.1.106:80;
  listen 192.168.1.106:443;
  server_name www.yqc.com;
  ssl_certificate /apps/nginx/ssl/www.yqc.com.crt;
  ssl_certificate_key /apps/nginx/ssl/www.yqc.com.key;
  ssl_session_cache shared:sslcache:20m;
  ssl_session_timeout 10m;
  error_page 500 502 503 504 404 /error.html;
  access_log /data/nginx/logs/www-yqc-com_access_json.log format2;
  error_log /data/nginx/logs/www-yqc-com_error.log;
  gzip on;
  gzip_comp_level 3;
  gzip_min_length 1k;
  gzip_types text/plain text/html application/javascript application/x-javascript text/cssapplication/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
  gzip_vary on;
  
  location / {
    root /data/nginx/yqc/www;
    index index.html;
  }

  location = /error.html {
    root /data/nginx/yqc/redirect;
  }

  location = /status {
    stub_status;
    allow 192.168.1.0/24;
    allow 127.0.0.1;
    deny all;
  }
}
  • 检查配置文件并重载nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx
  • 测试访问:

Nginx 全实践

  • 继续访问:

Nginx 全实践

  • 查看证书信息:

Nginx 全实践

3.4.5:wap.yqc.com 的 https 访问

  • 生成私钥和证书签署申请:
[aaa@qq.com ~]# openssl req -newkey rsa:4096 -nodes -sha256 -keyout /apps/nginx/ssl/wap.yqc.com.key -out /apps/nginx/ssl/wap.yqc.com.csr
Generating a 4096 bit RSA private key
..........................................................................................................................++
..................................................................................++
writing new private key to '/apps/nginx/ssl/wap.yqc.com.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN      
State or Province Name (full name) []:Shanxi
Locality Name (eg, city) [Default City]:Taiyuan
Organization Name (eg, company) [Default Company Ltd]:yqc
Organizational Unit Name (eg, section) []:Ops
Common Name (eg, your name or your server's hostname) []:wap.yqc.com
Email Address []:aaa@qq.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
  • 签发证书:
[aaa@qq.com ~]# openssl x509 -req -days 3650 -in /apps/nginx/ssl/wap.yqc.com.csr -CA /etc/pki/CA/ca.crt -CAkey /etc/pki/CA/private/ca.key -CAcreateserial -out /apps/nginx/ssl/wap.yqc.com.crt
Signature ok
subject=/C=CN/ST=Shanxi/L=Taiyuan/O=yqc/OU=Ops/CN=wap.yqc.com/aaa@qq.com
Getting CA Private Key
  • 配置 nginx:
[aaa@qq.com ~]# vim /apps/nginx/conf.d/wap.yqc.com.conf 
server {
#  listen 192.168.1.106:80;
  listen 192.168.1.106:443 ssl;
  server_name wap.yqc.com;
  ssl_certificate /apps/nginx/ssl/wap.yqc.com.crt;
  ssl_certificate_key /apps/nginx/ssl/wap.yqc.com.key;
  ssl_session_cache shared:sslcache:20m;
  ssl_session_timeout 10m;
  location / {
    root /data/nginx/yqc/wap;
  }
}
  • 检查配置文件并重置 nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx
  • 验证访问:

Nginx 全实践

3.5:Nginx 防盗链

盗链的定义:
如果别⼈只链接了⾃⼰网站的某个单独资源,⽽不是打开了⽹站的整个页⾯,就是盗链;

$http_referer 变量中记录的就是链接自己站点的网站域名;

通过定义 valid_referer 的值,来定义有效的 referer;

valid_referer 的值包括以下几种类型:

  • none:请求报⽂⾸部没有referer⾸部,⽐如⽤⼾直接在浏览器输⼊域名访问web⽹站,就没有referer信息。
  • blocked:请求报⽂有referer⾸部,但⽆有效值,⽐如为空。
  • server_names:referer⾸部中包含本主机名及即nginx 监听的server_name。
  • arbitrary_string:⾃定义指定字符串,可使⽤*作通配符。
  • regular expression:被指定的正则表达式模式匹配到的字符串,要使⽤~开头。

相关内置变量:

  • $invalid_referer,如果访问资源命中 valid_refer 所记录的 referer 类型,则为空;否则为 1;

3.5.1:盗链演示

模拟场景:

wap.yqc.com 盗取 www.yqc.com 下的 /images/ironman.jpg;

  • 编辑盗链页面:
[aaa@qq.com ~]# vim /data/nginx/yqc/wap/test.html
<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8">
		<title>盗链页面</title>
	</head>
	<body>
		<a href="http://www.yqc.com">测试盗链</a>
		<img src="http://www.yqc.com/images/ironman.jpg">
	</body>
</html>
  • 访问测试:
    http://wap.yqc.com/test.html

Nginx 全实践

  • 查看www.yqc.com访问日志:

    “referer”:“http://wap.yqc.com/”

{"@timestamp":"2020-12-04T11:08:14+08:00","host":"192.168.1.106","clientip":"192.168.1.9","size":249006,"responsetime":0.000,"upstreamtime":"-","upstreamhost":"-","http_host":"www.yqc.com","uri":"/images/ironman.jpg","domain":"www.yqc.com","xff":"-","referer":"http://wap.yqc.com/","tcp_xff":"-","http_user_agent":"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36","status":"200"}

3.5.2:防盗链配置

  • 在 www.yqc.com 的 location /images配置中定义防盗链配置:
  location /images {
    root /data/nginx/yqc/www;
    index index.html;
    valid_referers none blocked server_names ~\.google\. ~\.baidu\.;
    if ( $invalid_referer = 1 ) {
      return 403;
    }
  }
  • 检查配置文件并重置 nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx
  • 访问盗链测试页面:

Nginx 全实践

  • 查看日志:
{"@timestamp":"2020-12-04T11:37:50+08:00","host":"192.168.1.106","clientip":"192.168.1.9","size":555,"responsetime":0.000,"upstreamtime":"-","upstreamhost":"-","http_host":"www.yqc.com","uri":"/images/ironman.jpg","domain":"www.yqc.com","xff":"-","referer":"http://wap.yqc.com/","tcp_xff":"-","http_user_agent":"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36","status":"403"}

3.6:Nginx 转发 FastCGI 请求

CGI 和 FastCGI:

CGI,Common Gateway Interface,通用网关接口,Nginx 基于 CGI 协议转发客户端的动态资源请求至 PHP 程序,由这些程序处理完请求后,返回结果给 Nginx,再由 Nginx 返回客户端相应的数据;

早期的 CGI 协议,对于每一个请求都会创建一个 CGI 进程,解析并处理完毕后再关闭进程,效率很低;

FastCGI 处理完请求后,不会立即关闭进程,而是保留并继续处理新的请求,使得不用反复创建新的进程,提升了处理效率;

php-fpm:

FPM,FastCGI Process Manager,FastCGI 进程管理器,提供 FastCGI 进程启动和管理的功能;

FastCGI 的进程运行模式为 master-worker 模式:

  • 一个 master 进程,负责监听并接收来自 web 服务转发的客户端请求;
  • 多个 worker 进程,每个 worker 进程都有一个 PHP 解析器,用于 PHP 代码的解析处理;

Nginx 的 FastCGI 相关功能由 ngx_http_fastcgi_module 模块提供;

3.6.1:准备 PHP 环境

安装 php-fpm

  • yum 安装 php-fpm:
[aaa@qq.com ~]# yum install php-fpm -y

配置 php-fpm

  • php-fpm.conf:

    修改 daemonize = yes,设置为后台启动;

[aaa@qq.com ~]# grep -v ';' /etc/php-fpm.conf | grep -v '^$'
include=/etc/php-fpm.d/*.conf
[global]
pid = /run/php-fpm/php-fpm.pid
error_log = /var/log/php-fpm/error.log
daemonize = yes
  • www.conf:

    • 启动 php-fpm worker 进程的用户要和启动 nginx worker 进程的用户一致,因为涉及文件权限问题;

    • 当 php-fpm 和 nginx 不在同一服务器时,需要:

      • 设置 fastcgi 监听在可通信的 IP 地址上,或者直接监听所有地址 listen = 0.0.0.0:9000
      • 注释 listen.allowed_clients = 127.0.0.1,或者设置为相应的 nginx 服务器地址;
    • pm.max_children 的值是在实行进程动态管理(pm = dynamic)时,能够启动的 worker 进程数的最大值;

    • pm.start_servers 的值是在实行进程动态管理(pm = dynamic)时,初始启动的 worker 进程数,所以需要 ≥ pm.min_spare_servers 指定的最小空闲进程数,并 ≤ pm.max_spare_servers 指定的最大空闲进程数;

    • pm.max_requests 的值是单个 worker 进程累计能够处理的最大请求数,当达到这个请求数后,会回收 worker 进程,并重新启动一个 worker 进程;

[aaa@qq.com ~]# grep -v ';' /etc/php-fpm.d/www.conf | grep -v '^[[:space:]]*$'
[www]
listen = 127.0.0.1:9000
listen.allowed_clients = 127.0.0.1
user = nginx
group = nginx
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
pm.max_requests = 5000
pm.status_path = /pm_status
ping.path = /ping
ping.response = pong
slowlog = /var/log/php-fpm/www-slow.log
php_admin_value[error_log] = /var/log/php-fpm/www-error.log
php_admin_flag[log_errors] = on
php_value[session.save_handler] = files
php_value[session.save_path] = /var/lib/php/session

启动 php-fpm

  • 启动 php-fpm:
[aaa@qq.com ~]# systemctl start php-fpm
[aaa@qq.com ~]# systemctl enable php-fpm
Created symlink from /etc/systemd/system/multi-user.target.wants/php-fpm.service to /usr/lib/systemd/system/php-fpm.service.
  • 查看端口:
[aaa@qq.com ~]# ss -tnl | grep 9000
LISTEN     0      128    127.0.0.1:9000                     *:* 

准备 PHP 测试页面

  • 创建 php 资源目录及信息页:
[aaa@qq.com ~]# mkdir /data/nginx/yqc/www/php
[aaa@qq.com ~]# vim /data/nginx/yqc/www/php/index.php
<?php
  phpinfo();
?>

3.6.2:Nginx 配置 FastCGI 转发

  • 配置所有以 .php 结尾的 URI 请求,都转发至 php-fpm 进行处理:

    定义php资源请求的根目录为 /data/nginx/yqc/www/php;

  location ~ \.php$ {
    root /data/nginx/yqc/www/php;
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include /apps/nginx/conf/fastcgi_params;
  }
  • 配置php状态页和/ping测试的请求转发:
  location ~ ^/(pm_status|ping)$ {
    fastcgi_pass 127.0.0.1;
    fastcgi_param PATH_TRANSLATED $document_root$fastcgi_script_name;
    include /apps/nginx/conf/fastcgi_params;
  }
  • 检查配置文件并重载nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# !sys
systemctl reload nginx
  • 访问php信息页:

Nginx 全实践

  • 访问 PHP 状态页和 ping 测试:
[aaa@qq.com ~]# curl http://www.yqc.com/pm_status
pool:                 www
process manager:      dynamic
start time:           05/Dec/2020:16:00:44 +0800
start since:          1071
accepted conn:        9
listen queue:         0
max listen queue:     0
listen queue len:     128
idle processes:       4
active processes:     1
total processes:      5
max active processes: 2
max children reached: 0
slow requests:        0

[aaa@qq.com ~]# curl http://www.yqc.com/ping
pong

四:Nginx Rewrite 模块

ngx_http_rewrite_module 包含的指令:

  • if
  • set
  • break
  • return
  • rewrite_log
  • rewrite

4.1:if 条件判断

4.1.1:文件判断

测试 if 语句,访问的资源存在则显示 “file exists.”,不存在则显示 “file doesn’t exist.”;

  • 编辑配置文件:
server {
  ……
  location /echo {
    root /data/nginx/yqc/www;
    default_type text/html;
    if ( -f $request_filename ) {
      echo "file exists.";
    }
    if ( !-f $request_filename ) {
      echo "file doesn't exist.";
    }
  }
}
  • 检查配置文件并重载 nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx
  • 准备测试文件:
[aaa@qq.com ~]# cp /etc/fstab /data/nginx/yqc/www/echo/fstab.html
  • 测试访问存在的资源:

Nginx 全实践

  • 测试访问不存在的资源:

Nginx 全实践

4.1.2:条件判断

判断访问所用协议,如果是 http,则显示 “if_http: http”,如果是 https,则显示 “if_https: https”;

  • 编辑配置文件:
server {
  ……
  location /echo {
    root /data/nginx/yqc/www;
    default_type text/html;
#    if ( -f $request_filename ) {
#      echo "file exists.";
#    }
#    if ( !-f $request_filename ) {
#      echo "file doesn't exist.";
#    }
    if ( $scheme = http ) {
      echo "if_http: $scheme";
    }
    if ( $scheme = https ) {
      echo "if_https: $scheme";
    }
  }
}
  • 检查配置文件并重载 nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx
  • 访问测试:
    https://www.yqc.com/echo/fstab.html

Nginx 全实践

4.2:set 自定义变量

  • 编辑配置文件:
server {
  ……
  location /echo {
    root /data/nginx/yqc/www;
    default_type text/html;
    set $name www.yqc.com;
    set $nginx_port $server_port;
    echo "$name:$nginx_port";
  }
}
  • 检查配置文件并重载 nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx
  • 访问测试:

Nginx 全实践

4.3:break 中断

测试 break 只会中断同一 location 中的 ngx_http_rewrite_module 模块中的指令,其它指令则继续运行;

  • 编辑配置文件:
server {
  ……
  location /echo {
    root /data/nginx/yqc/www;
    default_type text/html;
    set $name www.yqc.com;
    echo $name;
    break;
    set $nginx_port $server_port;
    echo "$name:$nginx_port";
  }
}
  • 检查配置文件并重载 nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx
  • 访问测试:

    break 并未中断后边的 echo 指令,但却中断了后边的 set 指令,使得显示时 $nginx_port 的值为空;

Nginx 全实践

4.4:return

测试 return 只会中断同一作用区域的所有指令,对自身所在作用区域之外的指令没有影响;

4.4.1:return in if

  • 编辑配置文件:
server {
  ……
  location /echo {
    root /data/nginx/yqc/www;
    default_type text/html;
    if ( -f $request_filename ) {
      echo "file exists.";
      return 666 "return test";
    }
    if ( !-f $request_filename ) {
      echo "file doesn't exist.";
    }
  }
}

  • 检查配置文件并重载 nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx
  • 访问存在的资源:

    返回 return 的提示信息,并返回状态码 666;

Nginx 全实践

  • 访问不存在的资源:

    echo 指令正常显示;

Nginx 全实践

4.4.2:return in location

测试将 return 上提一层,放在 location 中的效果;

  • 编辑配置文件:
server {
  ……
  location /echo {
    root /data/nginx/yqc/www;
    default_type text/html;
    echo "return failed.";
    if ( -f $request_filename ) {
      echo "file exists.";
    }
    if ( !-f $request_filename ) {
      echo "file doesn't exist.";
    }
    return 666 "return test";
    echo "return failed.";
  }
}
  • 检查配置文件并重载 nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx
  • 访问测试:

    该 location 中的所有 echo 指令均未执行;

    访问 server 下的其它资源,不受影响;

Nginx 全实践

Nginx 全实践

Nginx 全实践

4.4.3:return in server

继续上提一层,放在 server 中,测试该 server 的其它页面是否可以访问;

  • 编辑配置文件:
[aaa@qq.com ~]# cat /apps/nginx/conf.d/www.yqc.com.conf 
server {
#  listen 192.168.1.106:80;
  listen 192.168.1.106:443 ssl;
  server_name www.yqc.com;
  ssl_certificate /apps/nginx/ssl/www.yqc.com.crt;
  ssl_certificate_key /apps/nginx/ssl/www.yqc.com.key;
  ssl_session_cache shared:sslcache:20m;
  ssl_session_timeout 10m;
  error_page 500 502 503 504 404 /error.html;
  access_log /data/nginx/logs/www-yqc-com_access_json.log format2;
  error_log /data/nginx/logs/www-yqc-com_error.log;
  gzip on;
  gzip_comp_level 3;
  gzip_min_length 1k;
  gzip_types text/plain application/javascript application/x-javascript text/cssapplication/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
  gzip_vary on;
  location / {
    root /data/nginx/yqc/www;
    index index.html;
  }

  location = /error.html {
    root /data/nginx/yqc/redirect;
  }

  location = /status {
    stub_status;
    allow 192.168.1.0/24;
    allow 127.0.0.1;
    deny all;
  }

  location = /favicon.ico {
    root /data/nginx/yqc/www/images;
    #log_not_found off;
    access_log off;
    expires 90d;
  }

  location /echo {
    root /data/nginx/yqc/www;
    default_type text/html;
    echo "return failed.";
    if ( -f $request_filename ) {
      echo "file exists.";
    }
    if ( !-f $request_filename ) {
      echo "file doesn't exist.";
    }
    echo "return failed.";
  }

  return 666 "return test"; 
}
  • 检查配置文件并重载 nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx
  • 测试访问:

    访问该 server 的所有资源,均返回 666;

Nginx 全实践

Nginx 全实践

4.5:rewrite_log

开启 rewrite 模块日志,查看相应日志内容;

  • 开启 rewrite_log,并设置 error_log 的级别为 notice:
[aaa@qq.com ~]# cat /apps/nginx/conf.d/www.yqc.com.conf    
server {
  ……
  error_log /data/nginx/logs/www-yqc-com_error.log notice;
  ……
  
  location /echo {
    root /data/nginx/yqc/www;
    default_type text/html;
    rewrite_log on;
    set $name www.yqc.com;
    echo $name;
    break;
    set $nginx_port $server_port;
    echo "$name:$nginx_port";
  }
}
  • 检查配置文件并重载 nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx
  • 访问并触发 break 指令,查看日志:
    https://www.yqc.com/echo
[aaa@qq.com ~]# tail -f /data/nginx/logs/www-yqc-com_error.log
2020/12/03 17:00:53 [warn] 21064#0: *31 using uninitialized "nginx_port" variable, client: 192.168.1.9, server: www.yqc.com, request: "GET /echo HTTP/1.1", host: "www.yqc.com"

4.6:rewrite 重定向

4.6.1:redirect 临时重定向

将 wap.yqc.com 临时重定向至 www.baidu.com,查看响应状态码;

  • 编辑配置文件:
[aaa@qq.com ~]# vim /apps/nginx/conf.d/wap.yqc.com.conf   
server {
#  listen 192.168.1.106:80;
  listen 192.168.1.106:443 ssl;
  server_name wap.yqc.com;
  ssl_certificate /apps/nginx/ssl/wap.yqc.com.crt;
  ssl_certificate_key /apps/nginx/ssl/wap.yqc.com.key;
  ssl_session_cache shared:sslcache:20m;
  ssl_session_timeout 10m;
  location / {
    root /data/nginx/yqc/wap;
    index index.html;
    rewrite / http://www.baidu.com redirect;
  }
}
  • 检查配置文件并重载 nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx
  • 访问并查看响应状态码:

Nginx 全实践

4.6.2:permanent 永久重定向

将 wap.yqc.com 永久重定向至 www.baidu.com,查看响应状态码;

永久重定向会缓存 A 记录,即浏览器会保存此次 DNS 的解析记录;而临时重定向则不会;

  • 编辑配置文件:
[aaa@qq.com ~]# vim /apps/nginx/conf.d/wap.yqc.com.conf 
server {
#  listen 192.168.1.106:80;
  listen 192.168.1.106:443 ssl;
  server_name wap.yqc.com;
  ssl_certificate /apps/nginx/ssl/wap.yqc.com.crt;
  ssl_certificate_key /apps/nginx/ssl/wap.yqc.com.key;
  ssl_session_cache shared:sslcache:20m;
  ssl_session_timeout 10m;
  location / {
    root /data/nginx/yqc/wap;
    index index.html;
    # rewrite / http://www.baidu.com redirect;
    rewrite / http://www.baidu.com permanent;
  }
}
  • 检查配置文件并重载 nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx
  • 访问并查看响应状态码:

Nginx 全实践

4.6.3:标记 break 后的单次重写

测试场景:

  • 访问 /break 开头的 URI,重写到 /test1 后标记 break;
  • 同一个 location 中,在重写到 /test1 的指令后添加一条重写到 /test2 的指令(测试 break 后不会执行同一 location 中的 rewrite 指令);
  • 在 /test1 的 location 中添加一条 rewrite 指令,重写至 /test3,(测试 break 后也会执行新的 URI 匹配到的 location 中的 rewrite 指令);
  • 编辑 URI 重写规则:/break–>/test1–>/test2–>/test3,全部标记为 break(测试标记为 break 的重写 URI 只会再被 rewrite 一次,即这次连续重写只会进行到 test2);
  • 将 /test1 的location 中的 rewrite 指回 /break(测试 break 不会出现循环重写);

break 后不执行同一 location 的其它 rewrite

  • 编辑配置文件(测试从 /break 重写至 /test1 后,不会执行同一 location 中重写至 /test2 的指令):
[aaa@qq.com ~]# vim /apps/nginx/conf.d/wap.yqc.com.conf 
server {
  listen 192.168.1.106:80;
  server_name wap.yqc.com;
  location / {
    root /data/nginx/yqc/wap;
    index index.html;
  }

  location /break {
    root /data/nginx/yqc/wap;
    index index.html;
    rewrite ^/break/(.*) /test1/$1 break;
    rewrite ^/test1/(.*) /test2/$1 break;
  }

  location /test1 {
    root /data/nginx/yqc/wap;
    index index.html;
  }

  location /test2 {
    root /data/nginx/yqc/wap;
    index index.html;
  }
}
  • 检查配置文件并重载 nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx
  • 准备测试页面:
[aaa@qq.com ~]# mkdir /data/nginx/yqc/wap/{break,test1,test2,test3}
[aaa@qq.com ~]# vim /data/nginx/yqc/wap/break/index.html
break page
[aaa@qq.com ~]# vim /data/nginx/yqc/wap/test1/index.html
test1 page
[aaa@qq.com ~]# vim /data/nginx/yqc/wap/test2/index.html
test2 page
[aaa@qq.com ~]# vim /data/nginx/yqc/wap/test3/index.html
test3 page
  • 访问测试 break 后不会执行同一 location 中的其它 rewrite 指令:

    只重写至 /test1;

[aaa@qq.com ~]# curl -L http://wap.yqc.com/break/
test1 page

标记为 break 的新 URI 会重新匹配 location

  • 编辑配置文件,在 location /test1 中添加重写至 /test3 的 rewrite 指令:
[aaa@qq.com ~]# cat /apps/nginx/conf.d/wap.yqc.com.conf
server {
  listen 192.168.1.106:80;
  server_name wap.yqc.com;
  error_log /data/nginx/logs/wap-yqc-com_error.log notice;
  rewrite_log on;
  location / {
    root /data/nginx/yqc/wap;
    index index.html;
  }
  
  location /break {
    root /data/nginx/yqc/wap;
    index index.html;
    rewrite ^/break/(.*) /test1/$1 break;
    rewrite ^/test1/(.*) /test2/$1 break;
  }

  location /test1 {
    root /data/nginx/yqc/wap;
    index index.html;
    rewrite ^/test1/(.*) /test3/$1 break;
  }

  location /test2 {
    root /data/nginx/yqc/wap;
    index index.html;
  }

  location /test3 {
    root /data/nginx/yqc/wap;
    index index.html;
  }
}
  • 检查配置文件并重载 nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx
  • 访问测试:

    重写流程:break–>test1–>test3;

[aaa@qq.com ~]# curl -L http://wap.yqc.com/break/
test3 page

break 的重写 URI 只会再被重写一次

  • 编辑配置文件:

    重写流程:break–>test1–>test2–>test3

[aaa@qq.com ~]# vim /apps/nginx/conf.d/wap.yqc.com.conf
server {
  listen 192.168.1.106:80;
  server_name wap.yqc.com;
  error_log /data/nginx/logs/wap-yqc-com_error.log notice;
  rewrite_log on;
  location / {
    root /data/nginx/yqc/wap;
    index index.html;
  }
  
  location /break {
    root /data/nginx/yqc/wap;
    index index.html;
    rewrite ^/break/(.*) /test1/$1 break;
  }

  location /test1 {
    root /data/nginx/yqc/wap;
    index index.html;
    rewrite ^/test1/(.*) /test2/$1 break;
  }

  location /test2 {
    root /data/nginx/yqc/wap;
    index index.html;
    rewrite ^/test2/(.*) /test3/$1 break;
  }

  location /test3 {
    root /data/nginx/yqc/wap;
    index index.html;
  }
}
  • 检查配置文件并重载 nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx
  • 访问测试:

    重写至进行到 test2 即停止;

[aaa@qq.com ~]# curl -L http://wap.yqc.com/break/
test2 page
  • 查看 rewrite 日志:
2020/12/03 23:18:31 [notice] 21902#0: *11 "^/break/(.*)" matches "/break/", client: 192.168.1.105, server: wap.yqc.com, request: "GET /break/ HTTP/1.1", host: "wap.yqc.com"
2020/12/03 23:18:31 [notice] 21902#0: *11 rewritten data: "/test1/", args: "", client: 192.168.1.105, server: wap.yqc.com, request: "GET /break/ HTTP/1.1", host: "wap.yqc.com"
2020/12/03 23:18:31 [notice] 21902#0: *11 "^/test1/(.*)" matches "/test1/index.html", client: 192.168.1.105, server: wap.yqc.com, request: "GET /break/ HTTP/1.1", host: "wap.yqc.com"
2020/12/03 23:18:31 [notice] 21902#0: *11 rewritten data: "/test2/index.html", args: "", client: 192.168.1.105, server: wap.yqc.com, request: "GET /break/ HTTP/1.1", host: "wap.yqc.com"

break 可以防止重写循环

  • 将 location /test1 中的 rewrite 规则指回 /break:

    现在的 rewrite 规则形成一个循环;

  location /break {
    root /data/nginx/yqc/wap;
    index index.html;
    rewrite ^/break/(.*) /test1/$1 break;
    rewrite ^/test1/(.*) /test2/$1 break;
  }
  
  location /test1 {
    root /data/nginx/yqc/wap;
    index index.html;
    rewrite ^/test1/(.*) /break/$1 break;
  }
  • 检查配置文件并重载 nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx
  • 访问测试:

    两条 rewrite 规则在这次请求中都只执行了一次,URI 被重新指回 /break;

[aaa@qq.com ~]# curl -L http://wap.yqc.com/break/
break page
  • 查看重写日志:
[aaa@qq.com ~]# tail -f /data/nginx/logs/wap-yqc-com_error.log
2020/12/03 19:08:03 [notice] 21605#0: *9 "^/break/(.*)" matches "/break/", client: 192.168.1.105, server: wap.yqc.com, request: "GET /break/ HTTP/1.1", host: "wap.yqc.com"
2020/12/03 19:08:03 [notice] 21605#0: *9 rewritten data: "/test1/", args: "", client: 192.168.1.105, server: wap.yqc.com, request: "GET /break/ HTTP/1.1", host: "wap.yqc.com"
2020/12/03 19:08:03 [notice] 21605#0: *9 "^/test1/(.*)" matches "/test1/index.html", client: 192.168.1.105, server: wap.yqc.com, request: "GET /break/ HTTP/1.1", host: "wap.yqc.com"
2020/12/03 19:08:03 [notice] 21605#0: *9 rewritten data: "/break/index.html", args: "", client: 192.168.1.105, server: wap.yqc.com, request: "GET /break/ HTTP/1.1", host: "wap.yqc.com"

4.6.4:标记 last 后的多次重写

last 实际应用场景不多;

测试场景:

  • 同一个 location 中,在重写到 /test1 的指令后添加一条重写到 /test2 的指令(测试 break 后不会执行同一 location 中的 rewrite 指令);

  • 编辑 URI 重写规则:/last–>/test1–>/test2–>/test3–>/test4–>/test5,全部标记为 last(测试标记为 last 的重写 URI 会被连续重写多次,直至所有重写规则流程结束);

  • 编辑 URI 重写规则:/last–>/test1–>/last……,标记为 last(测试 last 可能导致的重写循环);

  • 模拟需要多次重写的应用场景:
    appv1 改版为 appv2,后又改版为 appv3,此时如果想让仍保留着 appv1 访问路径的用户,直接访问 appv3,通过连续两个标记 break 的 rewrite 规则即可实现,即 /appv1–> /appv2 --> /appv3,因为第一次 rewrite 后生成的新 URI(/appv2 )还能在经过一次 rewrite,从而重写为 appv3;
    然而如果再进行了一次版本升级,想让用户通过 /appv1 访问到 /appv4,就要通过 last 来实现多次重写了;
    P.S.
    当然,这种应用场景基本遇不到,因为实际中只需添加 /appv1 --> /appv4 的 rewrite 规则即可,不需要连续重写;
    顶多再分别单独添加 /appv2 --> /appv4、 /appv3 --> /appv4 的 rwrite 规则,即可将所有旧版本的 URL 重定向至新版本;

last 后同样不会执行同一 location 的其它 rewrite 规则

  • 编辑配置文件:
[aaa@qq.com ~]# vim /apps/nginx/conf.d/wap.yqc.com.conf    
server {
  listen 192.168.1.106:80;
  server_name wap.yqc.com;
  location / {
    root /data/nginx/yqc/wap;
    index index.html;
  }

  location /last {
    root /data/nginx/yqc/wap;
    index index.html;
    rewrite ^/last/(.*) /test1/$1 last;
    rewrite ^/test1/(.*) /test2/$1 last;
  }

  location /test1 {
    root /data/nginx/yqc/wap;
    index index.html;
  }

  location /test2 {
    root /data/nginx/yqc/wap;
    index index.html;
  }
}
  • 检查配置文件并重载 nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx
  • 测试访问:

    仅执行了 /last --> /test1 的重写,而未执行同一 location 中 /test1 --> /test2 的重写;
    最终显示内容为 /test1 的内容;

[aaa@qq.com ~]# curl -L http://wap.yqc.com/last/ 
test1 page

标记为 last 的新 URI 会多次匹配执行 rewrite 规则

  • 编辑配置文件:

    重写规则:break–>test1–>test2–>test3–>test4–>test5

[aaa@qq.com ~]# vim /apps/nginx/conf.d/wap.yqc.com.conf
server {
  listen 192.168.1.106:80;
  server_name wap.yqc.com;
  error_log /data/nginx/logs/wap-yqc-com_error.log notice;
  rewrite_log on;
  location / {
    root /data/nginx/yqc/wap;
    index index.html;
  }
  
  location /last {
    root /data/nginx/yqc/wap;
    index index.html;
    rewrite ^/last/(.*) /test1/$1 last;
  }

  location /test1 {
    root /data/nginx/yqc/wap;
    index index.html;
    rewrite ^/test1/(.*) /test2/$1 last;
  }

  location /test2 {
    root /data/nginx/yqc/wap;
    index index.html;
    rewrite ^/test2/(.*) /test3/$1 last;
  }

  location /test3 {
    root /data/nginx/yqc/wap;
    index index.html;
    rewrite ^/test3/(.*) /test4/$1 last;
  }

  location /test4 {
    root /data/nginx/yqc/wap;
    index index.html;
    rewrite ^/test4/(.*) /test5/$1 last;
  }

  location /test5 {
    root /data/nginx/yqc/wap;
    index index.html;
  }
}
  • 检查配置文件并重载 nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx
  • 访问测试:

    会一直重写至 test5;

[aaa@qq.com ~]# curl -L http://wap.yqc.com/last/
test5 page
  • 查看 rewrite 日志:
2020/12/03 23:41:53 [notice] 22000#0: *15 "^/last/(.*)" matches "/last/", client: 192.168.1.105, server: wap.yqc.com, request: "GET /last/ HTTP/1.1", host: "wap.yqc.com"
2020/12/03 23:41:53 [notice] 22000#0: *15 rewritten data: "/test1/", args: "", client: 192.168.1.105, server: wap.yqc.com, request: "GET /last/ HTTP/1.1", host: "wap.yqc.com"
2020/12/03 23:41:53 [notice] 22000#0: *15 "^/test1/(.*)" matches "/test1/", client: 192.168.1.105, server: wap.yqc.com, request: "GET /last/ HTTP/1.1", host: "wap.yqc.com"
2020/12/03 23:41:53 [notice] 22000#0: *15 rewritten data: "/test2/", args: "", client: 192.168.1.105, server: wap.yqc.com, request: "GET /last/ HTTP/1.1", host: "wap.yqc.com"
2020/12/03 23:41:53 [notice] 22000#0: *15 "^/test2/(.*)" matches "/test2/", client: 192.168.1.105, server: wap.yqc.com, request: "GET /last/ HTTP/1.1", host: "wap.yqc.com"
2020/12/03 23:41:53 [notice] 22000#0: *15 rewritten data: "/test3/", args: "", client: 192.168.1.105, server: wap.yqc.com, request: "GET /last/ HTTP/1.1", host: "wap.yqc.com"
2020/12/03 23:41:53 [notice] 22000#0: *15 "^/test3/(.*)" matches "/test3/", client: 192.168.1.105, server: wap.yqc.com, request: "GET /last/ HTTP/1.1", host: "wap.yqc.com"
2020/12/03 23:41:53 [notice] 22000#0: *15 rewritten data: "/test4/", args: "", client: 192.168.1.105, server: wap.yqc.com, request: "GET /last/ HTTP/1.1", host: "wap.yqc.com"
2020/12/03 23:41:53 [notice] 22000#0: *15 "^/test4/(.*)" matches "/test4/", client: 192.168.1.105, server: wap.yqc.com, request: "GET /last/ HTTP/1.1", host: "wap.yqc.com"
2020/12/03 23:41:53 [notice] 22000#0: *15 rewritten data: "/test5/", args: "", client: 192.168.1.105, server: wap.yqc.com, request: "GET /last/ HTTP/1.1", host: "wap.yqc.com"

last 导致的重写循环

  • 编辑配置文件:

    形成 last<–>test1 的重写循环;

[aaa@qq.com ~]# vim /apps/nginx/conf.d/wap.yqc.com.conf 
server {
  listen 192.168.1.106:80;
  server_name wap.yqc.com;
  error_log /data/nginx/logs/wap-yqc-com_error.log notice;
  rewrite_log on;
  location / {
    root /data/nginx/yqc/wap;
    index index.html;
  }

  location /last {
    root /data/nginx/yqc/wap;
    index index.html;
    rewrite ^/last/(.*) /test1/$1 last;
  }

  location /test1 {
    root /data/nginx/yqc/wap;
    index index.html;
    rewrite ^/test1/(.*) /last/$1 last;
  }
}
  • 检查配置文件并重载 nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx
  • 访问测试:

    报 500 错误;

[aaa@qq.com ~]# curl -L http://wap.yqc.com/last/
<html>
<head><title>500 Internal Server Error</title></head>
<body>
<center><h1>500 Internal Server Error</h1></center>
<hr><center>nginx/1.18.0</center>
</body>
</html>
  • 查看 rewrite 日志:

    在第一次重写为 /test1 后,又执行了 10次重写操作,最后报 500 错误;

  1 2020/12/03 23:54:47 [notice] 22025#0: *18 "^/last/(.*)" matches "/last/", client: 192.168.1.105, server: wap.yqc.com, request: "GET /last/ HTTP/1.1", host: "wap.yq
    c.com"
  2 2020/12/03 23:54:47 [notice] 22025#0: *18 rewritten data: "/test1/", args: "", client: 192.168.1.105, server: wap.yqc.com, request: "GET /last/ HTTP/1.1", host: "w
    ap.yqc.com"
  3 2020/12/03 23:54:47 [notice] 22025#0: *18 "^/test1/(.*)" matches "/test1/", client: 192.168.1.105, server: wap.yqc.com, request: "GET /last/ HTTP/1.1", host: "wap.
    yqc.com"
  4 2020/12/03 23:54:47 [notice] 22025#0: *18 rewritten data: "/last/", args: "", client: 192.168.1.105, server: wap.yqc.com, request: "GET /last/ HTTP/1.1", host: "wa
    p.yqc.com"
  5 2020/12/03 23:54:47 [notice] 22025#0: *18 "^/last/(.*)" matches "/last/", client: 192.168.1.105, server: wap.yqc.com, request: "GET /last/ HTTP/1.1", host: "wap.yq
    c.com"
  6 2020/12/03 23:54:47 [notice] 22025#0: *18 rewritten data: "/test1/", args: "", client: 192.168.1.105, server: wap.yqc.com, request: "GET /last/ HTTP/1.1", host: "w
    ap.yqc.com"
  7 2020/12/03 23:54:47 [notice] 22025#0: *18 "^/test1/(.*)" matches "/test1/", client: 192.168.1.105, server: wap.yqc.com, request: "GET /last/ HTTP/1.1", host: "wap.
    yqc.com"
  8 2020/12/03 23:54:47 [notice] 22025#0: *18 rewritten data: "/last/", args: "", client: 192.168.1.105, server: wap.yqc.com, request: "GET /last/ HTTP/1.1", host: "wa
    p.yqc.com"
  9 2020/12/03 23:54:47 [notice] 22025#0: *18 "^/last/(.*)" matches "/last/", client: 192.168.1.105, server: wap.yqc.com, request: "GET /last/ HTTP/1.1", host: "wap.yq
    c.com"
 10 2020/12/03 23:54:47 [notice] 22025#0: *18 rewritten data: "/test1/", args: "", client: 192.168.1.105, server: wap.yqc.com, request: "GET /last/ HTTP/1.1", host: "w
    ap.yqc.com"
 11 2020/12/03 23:54:47 [notice] 22025#0: *18 "^/test1/(.*)" matches "/test1/", client: 192.168.1.105, server: wap.yqc.com, request: "GET /last/ HTTP/1.1", host: "wap.
    yqc.com"
 12 2020/12/03 23:54:47 [notice] 22025#0: *18 rewritten data: "/last/", args: "", client: 192.168.1.105, server: wap.yqc.com, request: "GET /last/ HTTP/1.1", host: "wa
    p.yqc.com"
 13 2020/12/03 23:54:47 [notice] 22025#0: *18 "^/last/(.*)" matches "/last/", client: 192.168.1.105, server: wap.yqc.com, request: "GET /last/ HTTP/1.1", host: "wap.yq
    c.com"
 14 2020/12/03 23:54:47 [notice] 22025#0: *18 rewritten data: "/test1/", args: "", client: 192.168.1.105, server: wap.yqc.com, request: "GET /last/ HTTP/1.1", host: "w
    ap.yqc.com"
 15 2020/12/03 23:54:47 [notice] 22025#0: *18 "^/test1/(.*)" matches "/test1/", client: 192.168.1.105, server: wap.yqc.com, request: "GET /last/ HTTP/1.1", host: "wap.
    yqc.com"
 16 2020/12/03 23:54:47 [notice] 22025#0: *18 rewritten data: "/last/", args: "", client: 192.168.1.105, server: wap.yqc.com, request: "GET /last/ HTTP/1.1", host: "wa
    p.yqc.com"
 17 2020/12/03 23:54:47 [notice] 22025#0: *18 "^/last/(.*)" matches "/last/", client: 192.168.1.105, server: wap.yqc.com, request: "GET /last/ HTTP/1.1", host: "wap.yq
    c.com"
 18 2020/12/03 23:54:47 [notice] 22025#0: *18 rewritten data: "/test1/", args: "", client: 192.168.1.105, server: wap.yqc.com, request: "GET /last/ HTTP/1.1", host: "w
    ap.yqc.com"
 19 2020/12/03 23:54:47 [notice] 22025#0: *18 "^/test1/(.*)" matches "/test1/", client: 192.168.1.105, server: wap.yqc.com, request: "GET /last/ HTTP/1.1", host: "wap.
    yqc.com"
 20 2020/12/03 23:54:47 [notice] 22025#0: *18 rewritten data: "/last/", args: "", client: 192.168.1.105, server: wap.yqc.com, request: "GET /last/ HTTP/1.1", host: "wa
    p.yqc.com"
 21 2020/12/03 23:54:47 [notice] 22025#0: *18 "^/last/(.*)" matches "/last/", client: 192.168.1.105, server: wap.yqc.com, request: "GET /last/ HTTP/1.1", host: "wap.yq
    c.com"
 22 2020/12/03 23:54:47 [notice] 22025#0: *18 rewritten data: "/test1/", args: "", client: 192.168.1.105, server: wap.yqc.com, request: "GET /last/ HTTP/1.1", host: "w
    ap.yqc.com"
 23 2020/12/03 23:54:47 [error] 22025#0: *18 rewrite or internal redirection cycle while processing "/test1/", client: 192.168.1.105, server: wap.yqc.com, request: "GE
    T /last/ HTTP/1.1", host: "wap.yqc.com"

模拟用到 last 多次重写的场景

appv1 改版为 appv2,后又改版为 appv3,此时如果想让仍保留着 appv1 访问路径的用户,直接访问 appv3,通过连续两个标记 break 的 rewrite 规则即可实现,即 /appv1–> /appv2 --> /appv3,因为第一次 rewrite 后生成的新 URI(/appv2 )还能在经过一次 rewrite,从而重写为 appv3;
然而如果再进行了一次版本升级,想让用户通过 /appv1 访问到 /appv4,就要通过 last 来实现多次重写了;

需要在追加 /appv3 --> /appv4 的重写规则时,将 /appv2 --> /appv3 的重写规则标记为 last;

P.S.
当然,这种应用场景基本遇不到,因为实际中只需添加 /appv1 --> /appv4 的 rewrite 规则即可,不需要连续重写;
顶多再分别单独添加 /appv2 --> /appv4、 /appv3 --> /appv4 的 rwrite 规则,即可将所有旧版本的 URL 重定向至新版本;

  • 编辑配置文件:
[aaa@qq.com ~]# cat /apps/nginx/conf.d/wap.yqc.com.conf 
server {
  listen 192.168.1.106:80;
  server_name wap.yqc.com;
  error_log /data/nginx/logs/wap-yqc-com_error.log notice;
  rewrite_log on;
  location / {
    root /data/nginx/yqc/wap;
    index index.html;
  }
  
  location /appv1{
    root /data/nginx/yqc/wap;
    index index.html;
    rewrite ^/appv1/(.*) /appv2/$1 break;
  }

  location /appv2{
    root /data/nginx/yqc/wap;
    index index.html;
    rewrite ^/appv2/(.*) /appv3/$1 last;
  }

  location /appv3{
    root /data/nginx/yqc/wap;
    index index.html;
    rewrite ^/appv3/(.*) /appv4/$1 break;
  }

  location /appv4{
    root /data/nginx/yqc/wap;
    index index.html;
  }
}
  • 准备测试文件:
[aaa@qq.com ~]# mkdir /data/nginx/yqc/wap/appv{1..4}
[aaa@qq.com ~]# vim /data/nginx/yqc/wap/appv1/index.html
appv1
[aaa@qq.com ~]# vim /data/nginx/yqc/wap/appv2/index.html
appv2
[aaa@qq.com ~]# vim /data/nginx/yqc/wap/appv3/index.html
appv3
[aaa@qq.com ~]# vim /data/nginx/yqc/wap/appv4/index.html
appv4
  • 检查配置文件并重载 nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx
  • 访问测试:
    rwrite 规则如果都标记为 break,则重写至 /appv3 即停止;
    将 /appv2 --> /appv3 的 rewrite 规则标记为 last,即可继续向后重写;
    将 /appv3 --> /appv4 的rewrite 规则标记为 break,即可防止继续向后重写;
[aaa@qq.com ~]# curl -L http://wap.yqc.com/appv1
appv4

4.6.5:rewrite 案例

rewrite 自动跳转 https

实现访问 http://www.yqc.com 时,自动跳转到 https://www.yqc.com;

  • 编辑配置文件:
[aaa@qq.com ~]# cat /apps/nginx/conf.d/www.yqc.com.conf 
server {
  listen 192.168.1.106:80;
  listen 192.168.1.106:443 ssl;
  server_name www.yqc.com;
  ssl_certificate /apps/nginx/ssl/www.yqc.com.crt;
  ssl_certificate_key /apps/nginx/ssl/www.yqc.com.key;
  ssl_session_cache shared:sslcache:20m;
  ssl_session_timeout 10m;
  error_page 500 502 503 504 404 /error.html;
  access_log /data/nginx/logs/www-yqc-com_access_json.log format2;
  error_log /data/nginx/logs/www-yqc-com_error.log notice;
  gzip on;
  gzip_comp_level 3;
  gzip_min_length 1k;
  gzip_types text/plain application/javascript application/x-javascript text/cssapplication/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
  gzip_vary on;
  location / {
    root /data/nginx/yqc/www;
    index index.html;
    if ( $scheme = http ) {
      rewrite (.*) https://www.yqc.com permanent;
    }
  }
  ……
}
  • 检查配置文件并重载 nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx
  • 访问测试

Nginx 全实践

rewrite 跳转默认页面

当访问的资源不存在时,自动跳转至默认页面;

  • 编辑配置文件:
  location / {
    root /data/nginx/yqc/www;
    index index.html;
    if ( !-f $request_filename ) {
      rewrite (.*) http://www.yqc.com/default.html;
    }
  }
  • 检查配置文件并重载 nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx
  • 访问测试:

Nginx 全实践

五:Nginx http 反向代理

Nginx 反向代理功能涉及的模块:

  • ngx_http_proxy_module: 将客⼾端的请求以http协议转发⾄指定服务器进⾏处理。
  • ngx_stream_proxy_module:将客⼾端的请求以tcp协议转发⾄指定服务器处理。
  • ngx_http_fastcgi_module:将客⼾端对php的请求以fastcgi协议转发⾄指定服务器助理。
  • ngx_http_uwsgi_module:将客⼾端对Python的请求以uwsgi协议转发⾄指定服务器处理。

5.1:准备后端 Web 服务器

后端 Web 服务采用 httpd;

  • 安装 httpd:
~]# yum install httpd -y
  • 启动 httpd 并设置为开机启动
~]# systemctl start httpd
~]# systemctl enable httpd
Created symlink from /etc/systemd/system/multi-user.target.wants/httpd.service to /usr/lib/systemd/system/httpd.service.
  • 准备测试页面:
[aaa@qq.com ~]# echo "node107 httpd page" > /var/www/html/index.html

[aaa@qq.com ~]# echo "node108 httpd page" > /var/www/html/index.html
  • 访问测试:
[aaa@qq.com ~]# curl http://192.168.1.107
node107 httpd page
[aaa@qq.com ~]# curl http://192.168.1.108
node108 httpd page

5.2:proxy_pass

5.2.1:代理单台 Web 服务器

将 www.yqc.com 和 www.yqc.com/images 代理至后端 web 服务器 node107;

注意 proxy_pass 后指定的 URL,末尾代 / 和不代 / 的区别:

  • / ,表示无论 location 指定的是哪个 URI,都直接跳转至后端服务器的根 /(即指向 httpd 服务器的 /var/www/html,在此目录下要有指定的资源);
  • 不代 /,表示访问 location 指定 URI 在后端服务器中对应的相同路径(后端 web 服务器要存在相应的资源目录);
  • 编辑 nginx 配置文件:
  location / {
    proxy_pass http://192.168.1.107:80;
  }
  
  location /images {
    proxy_pass http://192.168.1.107:80;
  }
  • 后端 web 服务器准备相应资源目录:
[aaa@qq.com ~]# mkdir /var/www/html/images
[aaa@qq.com ~]# scp 192.168.1.106:/data/nginx/yqc/www/images/ironman.jpg /var/www/html/images/
  • 删除 nginx 服务器的对应资源:

    测试确实是从httpd返回的访问资源;

[aaa@qq.com ~]# mv /data/nginx/yqc/www/images/ironman.jpg /root
  • 重置nginx后访问测试:
[aaa@qq.com ~]# curl www.yqc.com
node107 httpd page

http://www.yqc.com/images/ironman.jpg

Nginx 全实践

  • 日志:
{"@timestamp":"2020-12-04T16:54:52+08:00","host":"192.168.1.106","clientip":"192.168.1.105","size":19,"responsetime":0.002,"upstreamtime":"0.002","upstreamhost":"192.168.1.107:80","http_host":"www.yqc.com","uri":"/","domain":"www.yqc.com","xff":"-","referer":"-","tcp_xff":"-","http_user_agent":"curl/7.29.0","status":"200"}

{"@timestamp":"2020-12-04T17:09:16+08:00","host":"192.168.1.106","clientip":"192.168.1.9","size":249054,"responsetime":0.029,"upstreamtime":"0.021","upstreamhost":"192.168.1.107:80","http_host":"www.yqc.com","uri":"/images/ironman.jpg","domain":"www.yqc.com","xff":"-","referer":"-","tcp_xff":"-","http_user_agent":"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36","status":"200"}
  • 测试 proxy_pass 指定的 URL 代 / 的效果:
  location /images {
    proxy_pass http://192.168.1.107:80/;
  } 
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# !sys
systemctl reload nginx
[aaa@qq.com ~]# curl www.yqc.com/images/ironman.jpg
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL /ironman.jpg was not found on this server.</p>
</body></html>
You have new mail in /var/spool/mail/root
[aaa@qq.com ~]# curl www.yqc.com/images
node107 httpd page

访问 www.yqc.com/images/ironman.jpg,被代理至后端 web 服务器后,实际的URL为 http://192.168.1.107/ironman.jpg,这个资源路径是不存在的;
访问 www.yqc.com/images,实际URL 为后端 web 服务器的根路径 http://192.168.1.107;

所以一般建议不要代 / 去指定后端服务器,这样可以保证前后端资源路径的一致性;

5.3:proxy_cache* 代理缓存

5.3.1:非缓存场景下的压测

  • node107 准备测试页面:
[aaa@qq.com ~]# ll -h /var/log/messages 
-rw-------. 1 root root 305K Dec  4 17:30 /var/log/messages
You have new mail in /var/spool/mail/root
[aaa@qq.com ~]# cp /var/log/messages /var/www/html/messages.html
  • 安装 httpd-tools:
[aaa@qq.com ~]# yum provides */bin/ab
httpd-tools-2.4.6-95.el7.centos.x86_64 : Tools for use with the Apache HTTP Server
Repo        : base
Matched from:
Filename    : /usr/bin/ab

[aaa@qq.com ~]# yum install httpd-tools -y
  • 进行压测:

    以对比后续配置代理缓存后的压测结果;

[aaa@qq.com ~]# ab -c 500 -n 5000 http://www.yqc.com/messages.html
Concurrency Level:      500
Time taken for tests:   14.377 seconds
Complete requests:      5000
Failed requests:        0
Write errors:           0
Total transferred:      1560810000 bytes
HTML transferred:       1559405000 bytes
Requests per second:    347.79 [#/sec] (mean)
Time per request:       1437.663 [ms] (mean)
Time per request:       2.875 [ms] (mean, across all concurrent requests)
Transfer rate:          106021.26 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    3   8.2      0      53
Processing:    69 1363 237.0   1422    1538
Waiting:        5 1355 238.2   1415    1495
Total:         76 1366 229.1   1423    1539

5.3.2:代理缓存配置

定义缓存路径及参数

  • 在 http 配置段定义代理缓存:

    配置:

    • 定义缓存路径为 /data/nginx/proxycache;
    • 缓存目录结构为 1:1:1,即三层目录结构,每层目录名均由一位十六进制数字表示,即每层可以有2^4个目录,总共可以有 16×16×16=4096 个缓存目录;
    • 指定缓存名称为 proxycache,大小为 20m;
    • 缓存有效时间为 120s,120s 内未被命中的缓存将被删除;
    • 缓存占用的最大磁盘空间为 1g;
[aaa@qq.com ~]# vim /apps/nginx/conf/nginx.conf
http {
  ……
  proxy_cache_path /data/nginx/proxycache levels=1:1:1 keys_zone=proxycache:20m inactive=120s max_size=1g;
}

调用缓存

  • 在 location / 中调用缓存,并设置相关参数:

    配置:

    • 调用缓存 proxycache;
    • 向后端 web 服务器转发请求时,在报文头部添加 client,值为 $remote_addr,将客户端 ip 传送给后端服务器;
    • 指定要缓存的内容为 $request_uri(即缓存用户请求的完整 URI);
    • 定义状态码为 301 时,缓存时长为 1h(因为 301 永久重定向一般不会修改);
    • 定义状态码为 200、302 时,缓存时长为 10m(因为 200 和 302 表示成功的访问,短时间不会产生大的变动);
    • 定义其它状态码的缓存时长为 1m(这其中可能包括错误的访问缓存,故障一般会尽快处理,所以缓存不能过长,以让用户及时访问到恢复了的页面);
  location / {
    proxy_pass http://192.168.1.107:80;
    proxy_cache proxycache;
    proxy_set_header clientip $remote_addr;
    proxy_cache_key $request_uri;
    proxy_cache_valid 301 1h;
    proxy_cache_valid 200 302 10m;
    proxy_cache_valid any 1m;
  }
  • 检查配置文件并重载 nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# !sys
systemctl reload nginx

验证缓存效果

  • 重新进行压测,对比未配置缓存时的数据(需要先访问一次压测资源,以生成缓存):

    配置缓存前,每秒处理的请求数量为:347.79 个
    配置缓存后,每秒处理的请求数量为:720.92 个

[aaa@qq.com ~]# curl http://www.yqc.com/messages.html 

[aaa@qq.com ~]# ab -c 500 -n 5000 http://www.yqc.com/messages.html
Concurrency Level:      500
Time taken for tests:   6.936 seconds
Complete requests:      5000
Failed requests:        0
Write errors:           0
Total transferred:      1560810000 bytes
HTML transferred:       1559405000 bytes
Requests per second:    720.92 [#/sec] (mean)
Time per request:       693.557 [ms] (mean)
Time per request:       1.387 [ms] (mean, across all concurrent requests)
Transfer rate:          219769.85 [Kbytes/sec] received
  • 查看缓存目录及文件:
[aaa@qq.com ~]# tree /data/nginx/proxycache/
/data/nginx/proxycache/
└── 9
    └── 5
        └── 3
            └── 478ab3190259513b48f079a5b5d8f359

3 directories, 1 file

[aaa@qq.com ~]# ll -h /data/nginx/proxycache/9/5/3/478ab3190259513b48f079a5b5d8f359 
-rw------- 1 nginx nginx 306K Dec  4 18:24 /data/nginx/proxycache/9/5/3/478ab3190259513b48f079a5b5d8f359
[aaa@qq.com ~]# ll -h /var/www/html/messages.html  
-rwxrwxrwx 1 root root 305K Dec  4 17:39 /var/www/html/messages.html
  • 缓存文件头部会添加访问的响应码(用于确定此缓存文件的缓存时长):
[aaa@qq.com ~]# head -n10 /data/nginx/proxycache/9/5/3/478ab3190259513b48f079a5b5d8f359
KEY: /messages.html
HTTP/1.1 200 OK
Date: Fri, 04 Dec 2020 10:31:13 GMT
Server: Apache/2.4.6 (CentOS)
Last-Modified: Fri, 04 Dec 2020 09:39:50 GMT
ETag: "4c249-5b5a04207e0f1"
Accept-Ranges: bytes
Content-Length: 311881
Connection: close

5.4:add_header 添加报文头部信息

  • 编辑配置文件,添加头部信息:
  location / {
    proxy_pass http://192.168.1.107:80;
    proxy_set_header clientip $remote_addr;
    proxy_cache proxycache;
    proxy_cache_key $request_uri;
    proxy_cache_valid 301 1h;
    proxy_cache_valid 200 302 10m;
    proxy_cache_valid any 1m;
    add_header X-Via $server_addr;
    add_header X-Cache $upstream_cache_status;
    add_header X-Accel $server_name;
  }
  • 重载 nginx 并测试访问,查看响应头部:

    第一次访问的缓存状态为 MISS,未命中缓存,因为还未生成缓存;
    第二次访问的缓存状态为 HIT,表示命中缓存;

[aaa@qq.com ~]# curl -I http://www.yqc.com/messages.html
HTTP/1.1 200 OK
Server: nginx/1.18.0
Date: Fri, 04 Dec 2020 10:54:04 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 311881
Connection: keep-alive
Vary: Accept-Encoding
Last-Modified: Fri, 04 Dec 2020 09:39:50 GMT
ETag: "4c249-5b5a04207e0f1"
X-Via: 192.168.1.106
X-Cache: MISS
X-Accel: www.yqc.com
Accept-Ranges: bytes

[aaa@qq.com ~]# curl -I http://www.yqc.com/messages.html
HTTP/1.1 200 OK
Server: nginx/1.18.0
Date: Fri, 04 Dec 2020 10:54:07 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 311881
Connection: keep-alive
Vary: Accept-Encoding
Last-Modified: Fri, 04 Dec 2020 09:39:50 GMT
ETag: "4c249-5b5a04207e0f1"
X-Via: 192.168.1.106
X-Cache: HIT
X-Accel: www.yqc.com
Accept-Ranges: bytes

5.5:upstream 添加后端服务器组

5.5.1:实现七层负载均衡

  • 定义后端服务器组(upstream 应用于 http 配置段,与 server 配置段平级):

    定义一个 upstream 后端服务器组,添加两台后端 web 服务器;

upstream webserver {
  server 192.168.1.107:80 weight=1 fail_timeout=5s max_fails=3;
  server 192.168.1.108:80 weight=1 fail_timeout=5s max_fails=3;
}
  • www.yqc.com 的 location / 调用 webserver 服务器组:

    并向后端服务器透传客户端 IP 地址;
    注释代理缓存配置,以验证负载均衡效果;

  location / {
    proxy_pass http://webserver/;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    #proxy_cache proxycache;
    #proxy_cache_key $request_uri;
    #proxy_cache_valid 301 1h;
    #proxy_cache_valid 200 302 10m;
    #proxy_cache_valid any 1m;
    add_header X-Via $server_addr;
    add_header X-Cache $upstream_cache_status;
    add_header X-Accel $server_name;
  }
  • 重载 nginx 并访问测试:
[aaa@qq.com ~]# curl http://www.yqc.com
node107 httpd page
[aaa@qq.com ~]# curl http://www.yqc.com
node108 httpd page
[aaa@qq.com ~]# curl http://www.yqc.com
node107 httpd page
[aaa@qq.com ~]# curl http://www.yqc.com
node108 httpd page

5.5.2:查看客户端 IP 透传日志

  • 更改后端httpd 的日志格式:

    combined 日志格式中添加 X-Forwarded-For;

[aaa@qq.com ~]# vim /etc/httpd/conf/httpd.conf
    LogFormat "%{X-Forwarded-For}i %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined

[aaa@qq.com ~]# systemctl restart httpd
  • 访问并查看后端httpd日志,验证客户端 IP 透传效果:
[aaa@qq.com ~]# tail -f /var/log/httpd/access_log
# 从 192.168.1.105 用curl访问的日志:
192.168.1.105 192.168.1.106 - - [05/Dec/2020:11:03:54 +0800] "GET / HTTP/1.0" 200 19 "-" "curl/7.29.0"

# 从 192.168.1.9 用chrome访问的日志:
192.168.1.9 192.168.1.106 - - [05/Dec/2020:11:20:24 +0800] "GET / HTTP/1.0" 304 - "-" "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36"
  • 如果后端 web 服务是 nginx,则main配置格式默认就有 $http_x_forwarded_for,其中同样记录了请求中的X-Forwarded-For信息:
    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;
  • 将 node108 的web服务改为 nginx:
[aaa@qq.com ~]# yum install epel-release -y
[aaa@qq.com ~]# yum install nginx -y
[aaa@qq.com ~]# systemctl stop httpd
[aaa@qq.com ~]# systemctl start nginx
[aaa@qq.com ~]# cp /var/www/html/index.html /usr/share/nginx/html/index.html
  • 访问并查看nginx日志,验证客户端 IP 透传效果:
[aaa@qq.com ~]# tail -f /var/log/nginx/access.log
# 从 192.168.1.105 用curl访问的日志:
192.168.1.106 - - [05/Dec/2020:11:50:32 +0800] "GET / HTTP/1.0" 200 19 "-" "curl/7.29.0" "192.168.1.105"

# 从 192.168.1.9 用chrome访问的日志:
192.168.1.106 - - [05/Dec/2020:11:50:46 +0800] "GET / HTTP/1.0" 200 19 "-" "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36" "192.168.1.9"

六:Nginx tcp 负载均衡

6.1:主配置文件添加 stream 配置段

  • 编辑nginx.conf,添加 stream 配置段:
[aaa@qq.com ~]# vim /apps/nginx/conf/nginx.conf
stream {
  log_format stream '$remote_addr [$time_local] '
                 '$protocol $status $bytes_sent $bytes_received '
                 '$session_time "$upstream_addr" '
                 '"$upstream_bytes_sent" "$upstream_bytes_received" "$upstream_connect_time"';
  include /apps/nginx/stream_conf.d/*.conf;
}
  • 创建 stream 配置文件目录:

    以实现 stream 相关的配置文件模块化;

[aaa@qq.com ~]# mkdir /apps/nginx/stream_conf.d/
  • 检查配置文件并重载nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx

6.2:Redis 负载均衡

6.2.1:后端服务器安装 Redis

  • node107 和 node108 分别安装 Redis;
~]# yum install redis -y
  • 配置 redis 监听在所有 IP:
~]# vim /etc/redis.conf
  • 启动 redis:
~]# systemctl enable redis
Created symlink from /etc/systemd/system/multi-user.target.wants/redis.service to /usr/lib/systemd/system/redis.service.
~]# systemctl start redis

~]# ss -tnl | grep 6379
LISTEN     0      511          *:6379                     *:* 
  • 进入redis,分别设置 name 为 node107 和 node108:

    以便验证负载均衡的效果;

[aaa@qq.com ~]# redis-cli
127.0.0.1:6379> set name node107
OK
127.0.0.1:6379> get name
"node107"

[aaa@qq.com ~]# redis-cli
127.0.0.1:6379> set name node108
OK
127.0.0.1:6379> get name
"node108"

6.2.2:Nginx 配置 Redis 代理

  • 编辑配置文件:
[aaa@qq.com ~]# vim /apps/nginx/stream_conf.d/redis.conf 
upstream redis {
  server 192.168.1.107:6379 weight=1 fail_timeout=5s max_fails=3;
  server 192.168.1.108:6379 weight=1 fail_timeout=5s max_fails=3;
}

server {
  listen 192.168.1.106:6379;
  proxy_connect_timeout 3s;
  proxy_timeout 30s;
  proxy_pass redis;
  access_log /data/nginx/logs/stream_redis_access.log stream;
}
  • 检查配置文件并重载nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx
  • 查看监听端口:
[aaa@qq.com ~]# ss -tnl | grep 6379
LISTEN     0      511    192.168.1.106:6379                     *:*
  • 访问验证:
#  首次调度到 192.168.1.107:
[aaa@qq.com ~]# redis-cli -h 192.168.1.106
192.168.1.106:6379> get name
"node107"
192.168.1.106:6379> quit

#  第二次调度到 192.168.1.108:
[aaa@qq.com ~]# redis-cli -h 192.168.1.106
192.168.1.106:6379> get name
"node108"
  • 查看日志:
[aaa@qq.com ~]# tail -f /data/nginx/logs/stream_redis_access.log
192.168.1.105 [05/Dec/2020:13:54:56 +0800] TCP 200 9941 40 4.376 "192.168.1.107:6379" "40" "9941" "0.001"
192.168.1.105 [05/Dec/2020:13:55:30 +0800] TCP 200 9941 40 32.544 "192.168.1.108:6379" "40" "9941" "0.001"

6.3:MySQL 负载均衡

6.3.1:后端服务器安装 MariaDB

  • 分别在 node107 和node108 上安装 mariadb-server:
~]# yum install mariadb-server -y
  • 启动mariadb:
~]# systemctl start mariadb 
~]# systemctl enable mariadb 
  • 授权远程登录用户 test:
MariaDB [(none)]> GRANT ALL ON *.* TO 'test'@'192.168.1.%' IDENTIFIED BY '123456';
MariaDB [(none)]> FLUSH PRIVILEGES;
  • 分别创建 node107 和 node108 数据库:

    以便验证负载均衡效果;

MariaDB [(none)]> CREATE DATABASE node107;

MariaDB [(none)]> CREATE DATABASE node108;

6.3.2:Nginx 配置 MySQL 代理

  • 编辑配置文件:
[aaa@qq.com ~]# vim /apps/nginx/stream_conf.d/mysql.conf
upstream mysql {
  server 192.168.1.107:3306 weight=1 fail_timeout=5s max_fails=3;
  server 192.168.1.108:3306 weight=1 fail_timeout=5s max_fails=3;
}

server {
  listen 192.168.1.106:3306;
  proxy_connect_timeout 3s;
  proxy_timeout 30s;
  proxy_pass mysql;
  access_log /data/nginx/logs/stream_mysql_access.log stream;
}
  • 检查配置文件并重载nginx:
[aaa@qq.com ~]# nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[aaa@qq.com ~]# systemctl reload nginx
  • 验证监听端口:
[aaa@qq.com ~]# ss -tnl | grep 3306
LISTEN     0      511    192.168.1.106:3306                     *:* 
  • 访问验证:
#  首次调度到 192.168.1.107:
[aaa@qq.com ~]# mysql -h192.168.1.106 -utest -p
Enter password: 
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 4
Server version: 5.5.68-MariaDB MariaDB Server

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| node107            |
| performance_schema |
| test               |
+--------------------+
5 rows in set (0.01 sec)

MariaDB [(none)]> QUIT
Bye

# 第二次调度到 192.168.1.108
[aaa@qq.com ~]# mysql -h192.168.1.106 -utest -p
Enter password: 
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 5
Server version: 5.5.68-MariaDB MariaDB Server

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| node108            |
| performance_schema |
| test               |
+--------------------+
5 rows in set (0.01 sec)
  • 查看日志:
[aaa@qq.com ~]# tail -f /data/nginx/logs/stream_mysql_access.log 
192.168.1.105 [05/Dec/2020:14:07:18 +0800] TCP 200 361 145 17.681 "192.168.1.107:3306" "145" "361" "0.002"
192.168.1.105 [05/Dec/2020:14:07:57 +0800] TCP 200 361 140 34.734 "192.168.1.108:3306" "140" "361" "0.001"