1 画图解释一次web请求的过程。涉及tcp/ip, dns, nginx,wsgi。
- 浏览器通过DNS把域名解析成对应的IP地址
- 根据这个IP地址在互联网上找到对应的服务器,建立Socket连接
- 客户端服务器发送HTTP协议请求,请求服务器里的文档资源
- 在服务器端,实际上还有复杂的业务逻辑:服务器可能有多台,到底指向哪台服务器处理请求,这需要一个负载平衡设备来平均分配所有用户的请求
- 还有请求的数据是存储在分布式缓存里还是一个静态文件中,或是在数据库里;
- 当数据返回浏览器时,浏览器解析数据发现还有一些静态资源(如:css,js或者图片)时又会发起另外的请求,而这些请求可能会在CDN上,那么CDN服务器又会处理这个用户的请求。
- 客户端与服务器断开。由客户端解释HTML文档,在客户端屏幕上渲染图形结果。
2 编译安装nginx, 详细解读常用参数。
2.1 基于ansible role实现编译安装nginx
利用ansible控制端10.0.0.8机器,在被控制端10.0.0.18上部署nginx
==首先打通ansible控制端与被控制端的基于key验证==
[root@ansible-rocky ~]$ ssh-copy-id 10.0.0.18
[root@ansible-rocky ~]$ ssh 10.0.0.18
Last login: Wed Jan 11 12:18:28 2023 from 10.0.0.8
[root@rocky8 ~]$ hostname -I
10.0.0.18
然后创建nginx项目目录实现基于role的部署任务
#nginx role项目目录总览
[root@ansible-rocky opt]$ tree /opt
/opt
├── hosts_nginx
├── nginx_role.yml
└── roles
└── nginx
├── handlers
│ └── main.yml
├── tasks
│ └── main.yml
└── templates
├── nginx.conf.j2
└── nginx.service.j2
#task文件
[root@ansible-rocky roles]$ cat nginx/tasks/main.yml
- name: add group nginx
group: name=nginx system=yes gid=80
- name: add user nginx
user: name=nginx group=nginx uid=80 system=yes shell="/sbin/nologin" create_home=no
- name: install dependent package
yum: name={{item}} state=latest
loop:
- gcc
- make
- pcre-devel
- openssl-devel
- zlib-devel
- perl-ExtUtils-Embed
- name: get nginx source
unarchive:
src: "{{ url }}"
dest: "/usr/local/src"
remote_src: yes
- name: compile and install
shell:
cmd: "./configure --prefix={{install_dir}} --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 && make && make install"
chdir: "/usr/local/src/nginx-{{ version }}"
creates: "{{install_dir}}/sbin/nginx"
- name: config file
template:
src: nginx.conf.j2
dest: "{{install_dir}}/conf/nginx.conf"
owner: nginx
group: nginx
notify: restart service
tags:
- config
- name: create directory
file:
path: "{{install_dir}}/conf/conf.d"
state: directory
owner: nginx
group: nginx
- name: change install directory owner
file:
path: "{{install_dir}}"
owner: nginx
group: nginx
recurse: yes
- name: copy service file
template:
src: nginx.service.j2
dest: "/lib/systemd/system/nginx.service"
- name: check config
shell:
cmd: "{{install_dir}}/sbin/nginx -t"
register: check_nginx_config
changed_when:
- check_nginx_config.stdout.find('successful')
- false
- name: start service
systemd:
daemon_reload: yes
name: nginx.service
state: started
enabled: yes
#创建handler文件
[root@ansible-rocky roles]$ cat nginx/handlers/main.yml
- name: restart service
service:
name: nginx
state: restarted
#装备两个template文件
[root@ansible-rocky roles]$ cat nginx/templates/nginx.conf.j2
user nginx;
worker_processes {{ ansible_processor_vcpus*2 }};
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
log_format access_json '{"@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",'
'"xff":"$http_x_forwarded_for",'
'"referer":"$http_referer",'
'"tcp_xff":"$proxy_protocol_addr",'
'"http_user_agent":"$http_user_agent",'
'"status":"$status"}';
# logging
access_log {{install_dir}}/logs/access-json.log access_json;
error_log {{install_dir}}/logs/error.log warn;
keepalive_timeout 65;
include {{install_dir}}/conf/conf.d/*.conf;
}
[root@ansible-rocky roles]$ cat nginx/templates/nginx.service.j2
[Unit]
Description=The nginx HTTP and reverse proxy server
After=network.target remote-fs.target nss-lookup.target
[Service]
Type=forking
PIDFile={{install_dir}}/logs/nginx.pid
ExecStartPre=/bin/rm -f {{install_dir}}/logs/nginx.pid
ExecStartPre={{install_dir}}/sbin/nginx -t
ExecStart={{install_dir}}/sbin/nginx
ExecReload=/bin/kill -s HUP \$MAINPID
KillSignal=SIGQUIT
TimeoutStopSec=5
KillMode=process
PrivateTmp=true
LimitNOFILE=100000
[Install]
WantedBy=multi-user.target
#在hosts文件中定义wensrvs需要的变量
[root@ansible-rocky opt]$ cat hosts_nginx
[websrvs]
10.0.0.18
[websrvs:vars]
version="1.22.1"
url="http://nginx.org/download/nginx-{{ version }}.tar.gz"
install_dir="/apps/nginx"
#在playbook中调用角色
[root@ansible-rocky opt]$ cat nginx_role.yml
- hosts: websrvs
remote_user: root
roles:
- nginx
#运行playbook
[root@ansible-rocky opt]$ ansible-playbook -i hosts_nginx nginx_role.yml
PLAY [websrvs] ****************************************************************************************
TASK [Gathering Facts] ********************************************************************************
ok: [10.0.0.18]
TASK [nginx : add group nginx] ************************************************************************
changed: [10.0.0.18]
TASK [nginx : add user nginx] *************************************************************************
changed: [10.0.0.18]
TASK [nginx : install dependent package] **************************************************************
changed: [10.0.0.18] => (item=gcc)
ok: [10.0.0.18] => (item=make)
changed: [10.0.0.18] => (item=pcre-devel)
changed: [10.0.0.18] => (item=openssl-devel)
ok: [10.0.0.18] => (item=zlib-devel)
changed: [10.0.0.18] => (item=perl-ExtUtils-Embed)
TASK [nginx : get nginx source] ***********************************************************************
changed: [10.0.0.18]
TASK [nginx : compile and install] ********************************************************************
changed: [10.0.0.18]
TASK [nginx : config file] ****************************************************************************
changed: [10.0.0.18]
TASK [nginx : create directory] ***********************************************************************
changed: [10.0.0.18]
TASK [nginx : change install directory owner] *********************************************************
changed: [10.0.0.18]
TASK [nginx : copy service file] **********************************************************************
changed: [10.0.0.18]
TASK [nginx : check config] ***************************************************************************
ok: [10.0.0.18]
TASK [nginx : start service] **************************************************************************
changed: [10.0.0.18]
RUNNING HANDLER [nginx : restart service] *************************************************************
changed: [10.0.0.18]
PLAY RECAP ********************************************************************************************
10.0.0.18 : ok=13 changed=11 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
在被控制端检查是否安装完成
2.2 编译安装参数详解
编译安装参数示例:
./configure --prefix={{install_dir}} \
--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
在编译安装参数中--with开头的选项
默认是禁用的,想要使用的话就需要在编译的时候加上;without开头的选项
默认是开启的,不想要启用此模块的话就需要在编译的时候加上。
通用配置选项参数:
选项 | 解释说明 |
---|---|
–prefix=<path> | Nginx安装的根路径,所有其它路径都要依赖该选项 |
–sbin-path=<path> | 指定nginx二进制文件的路径,没指定的话 这个路径依赖<prefix>选项 |
–conf-path=<path> | 命令行未指定配置文件,将会通过这里指定的路径加载配置文件 |
–error-log-path=<path> | 写入错误日志文件地址,默认值:<prefix>/logs/error.log。安装后,可以使用 nginx.conf 中的 error_log 指令更改。 |
–pid-path=<path> | nginx master进程pid写入的文件位置,默认值:<prefix>/logs/nginx.pid。安装后,可以使用 nginx.conf 中的 pid 指令更改。 |
–lock-path=<path> | 共享存储器互斥锁文件路径 |
–user=<user> | nginx 运行用户。默认值:nobody。安装后,可以使用 nginx.conf 中的 user 指令更改。 |
–group=<group> | nginx 运行组。默认值:--user 指定的值。安装后,可以使用 nginx.conf 中的 user 指令更改。 |
默认开启的模块
选项 | 解释说明 |
---|---|
–without-http_gzip_module | 禁用 ngx_http_gzip_module 模块 |
–without-http_userid_module | 禁用 ngx_http_userid_module 模块,该模块设置适用于客户端标识的 cookie |
–without-http_access_module | 禁用 ngx_http_access_module 模块,该模块允许限制对某些客户端地址的访问 |
–without-http_rewrite_module | 禁用 URL 转发(rewrite) |
–without-http_proxy_module | 禁用 HTTP 服务器代理(proxy)模块 |
–without-http-cache | 禁用 HTTP 缓存 |
默认未开启模块
选项 | 解释说明 |
---|---|
–with-http_ssl_module | 启用 HTTPS 协议支持,需要 OpenSSL 库。默认情况下未构建此模块 |
–with-http_v2_module | 启用 HTTP/2 协议支持。默认情况下未构建此模块。 |
–with-http_realip_module | 启用 ngx_http_realip_module 模块的功能,该模块将客户端地址更改为在指定的 “header “ 字段中发送的地址。默认情况下未构建此模块 |
–with-http_sub_module | 启用 ngx_http_sub_module 模块,该模块通过将一个指定的字符串替换为另一个指定的字符串来修改响应。默认情况下未构建此模块 |
–with-http_gzip_static_module | 启用 ngx_http_gzip_static_module 模块,该模块支持发送扩展名为 “.gz” 的预压缩文件,而不是常规文件。默认情况下未构建此模块 |
–with-http_auth_request_module | 启用 ngx_http_auth_request_module 模块,该模块基于子请求的结果实现客户端授权。默认情况下未构建此模块 |
–with-http_stub_status_module | 启用 ngx_http_stub_status_module 模块,该模块提供对基本状态信息的访问。默认情况下未构建此模块 |
–add-module=path | 启用外部模块 |
–add-dynamic-module=path | 启用外部动态模块 |
–modules-path=path | nginx 动态模块的目录。默认值:<prefix>/modules目录 |
perl模块相关选项参数
选项 | 解释说明 |
---|---|
–without-pcre | 禁用PCRE库 |
–with-pcre | 强制使用PCRE库 |
邮件模块相关配置选项参数
选项 | 解释说明 |
---|---|
–with-mail | 激活POP3/IMAP4/SMTP代理模块,默认未激活 |
–with-mail_ssl_module | 允许ngx_mail_ssl_module模块这个模块使得POP3/IMAP/SMTP可以使用SSL/TLS.配置已经定义了HTTP SSL模块,但是不支持客户端证书检测 |
–without-mail_pop3_module | 启用mail模块后,单独禁用pop3模块 |
–without-mail_imap_module | 启用mail模块后,单独禁用imap模块 |
–without-mail_smtp_module | 启用mail模块后,单独禁用smtp模块 |
–without-http | 完全禁用http模块,如果只想支持mall,可以使用此项设置 |
–with-openssl=DIR | 设定OpenSSL库文件路径 |
stream模块相关参数
选项 | 解释说明 |
---|---|
–with-stream | 开启stream模块 |
–with-stream_ssl_module | 启用 stream 模块的 SSL/TLS 协议支持。构建和运行此模块需要 OpenSSL 库。默认情况下未构建此模块 |
–with-stream_realip_module | 启用 ngx_stream_realip_module 模块的功能,该模块将客户端地址更改为 PROXY 协议标头中发送的地址。默认情况下未构建此模块 |
–without-stream_access_module | 禁用 ngx_stream_access_module 模块,该模块允许限制对某些客户端地址的访问 |
3 基于nginx完成动静分离部署 lnmp。php到后端php-fpm, static/ 在nginx本地。
nginx处理静态能力很强,但是动态处理能力不足,因此可以利用nginx实现动静分离技术
==本次实现利用两台机器实现动静分离:==
- nginx服务器:10.0.0.18
- LAMP架构服务器:10.0.0.28
3.1 搭建nginx服务器
==这部分是基于2.1编译安装实现的nginx服务器==
#创建虚拟主机server
[root@rocky8 ~]$ cat /apps/nginx/conf/conf.d/test.conf
server {
listen 80;
server_name www.yanlinux.org;
root /apps/nginx/html/;
}
#准备主页文件
[root@rocky8 ~]$ cat /apps/nginx/html/index.html
<h1>This is static web-page!</h1>
#重新加载配置
[root@rocky8 ~]$ nginx -t
[root@rocky8 ~]$ nginx -s reload
3.2 搭建LAMP架构
#安装软件
[root@rocky8 ~]$ yum -y install httpd php php-mysqlnd php-json mysql-server
[root@rocky8 ~]$ systemctl enable --now httpd php-fpm mysqld
#修改php主页信息
[root@rocky8 ~]$ cat /var/www/html/index.php
<?php
echo "this is dynamic web-page";
?>
LAMP架构搭建完成
3.3 实现动静分离
#在nginx服务器上修改配置文件实现动静分离
[root@rocky8 ~]$ cat /apps/nginx/conf/conf.d/test.conf
server {
listen 80;
server_name www.yanlinux.org;
location / {
root /apps/nginx/html/;
index index.html;
}
location ~ \.php$ {
proxy_pass http://10.0.0.28;
}
}
#重载配置
[root@rocky8 ~]$ 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
[root@rocky8 ~]$ nginx -s reload
4 nginx 利用rewrite完成 全栈ssl配置。
==基于2.1编译安装的nginx==
字签名证书创建
[root@rocky8 ~]$ cd /apps/nginx/
[root@rocky8 /apps/nginx]$ mkdir ssl
[root@rocky8 /apps/nginx]$ cd ssl/
[root@rocky8 /apps/nginx/ssl]$ openssl req -newkey rsa:4096 -nodes -sha256 -keyout www.yanlinux.org.key -x509 -days 3650 -out www.yanlinux.org.crt
Generating a RSA private key
.........................................................................++++
.................................++++
writing new private key to 'www.yanlinux.org.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) []:Jiangsu
Locality Name (eg, city) [Default City]:Nanjing
Organization Name (eg, company) [Default Company Ltd]:yanlinux.org
Organizational Unit Name (eg, section) []:it
Common Name (eg, your name or your server's hostname) []:www.yanlinux.org
Email Address []:
[root@rocky8 /apps/nginx/ssl]$ ll
total 8
-rw-r--r-- 1 root root 2057 Jan 11 16:20 www.yanlinux.org.crt
-rw------- 1 root root 3272 Jan 11 16:19 www.yanlinux.org.key
实现HSTS
#创建server子配置文件
[root@rocky pc]$ vi /apps/nginx/conf/conf.d/pc.conf
server {
listen 80;
listen 443 ssl;
ssl_certificate /apps/nginx/ssl/www.yanlinux.org.crt;
ssl_certificate_key /apps/nginx/ssl/www.yanlinux.org.key;
ssl_session_cache shared:sslcache:20m;
ssl_session_timeout 10m;
server_name www.yanlinux.org;
root /apps/nginx/html;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; #在首部加上HSTS
location / { #实现跳转
if ( $scheme = http ) {
rewrite ^/(.*)$ https://www.yanlinux.org/$1 redirect;
}
root /apps/nginx/html;
}
}
#重载配置文件
[root@rocky8 ~]$ 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
[root@rocky8 ~]$ nginx -s reload
5 通过zabbix监控nginx状态,web网站健康状态。
nginx 模板参考:https://git.zabbix.com/projects/ZBX/repos/zabbix/browse/templates/app/nginx_http
5.1 配置nginx服务
#在10.0.0.18上安装nginx
[15:10:39 root@rocky8 ~]$ vi /etc/nginx/nginx.conf
http{
server {
......
location / {
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
#添加下面几行
location /basic_status {
stub_status;
allow 127.0.0.1;
allow 10.0.0.101;
deny all;
}
}
}
[15:13:05 root@rocky8 ~]$ systemctl enable --now nginx.service
[15:14:59 root@rocky8 ~]$ curl http://127.0.0.1/basic_status
Active connections: 1
server accepts handled requests
1 1 1
Reading: 0 Writing: 1 Waiting: 0