最近把各种web服务往nginx上迁,一度踩坑踩到心态爆炸。。。。整完了之后记录一点nginx的配置详解awa

安装nginx

nginx可以直接yum或者apt安装,一般发行版的官方源里都有,一笔带过qwq
例如: apt-get install nginx 或者 yum install nginx

安装php

php我使用的是REMI源,因为…centos官方源的版本过于古老

安装remi源

https://rpms.remirepo.net/wizard/选择你的操作系统和需要的php版本等信息
然后页面会给出相应的安装安装命令
TIPs:

  1. remi有一个前置叫epel,在centos官方源里就有(yum install epel),不需要用第三方源安装
  2. 如果安装速度太慢(就不可能快),可以尝试将URL的前缀换成清华大学的源(https://mirrors.tuna.tsinghua.edu.cn/remi/)
    例如:
    yum install https://mirrors.tuna.tsinghua.edu.cn/remi/enterprise/remi-release-7.rpm

完成remi的安装后,你就可以直接yum安装php了
例如:yum install php74
注意,要配合nginx使用的php必须具有fpm
安装php-fpm: yum install php74-php-fpm

安装mysql

从centos7开始,centos官方源放弃了mysql并采用了mariadb,这是mysql的一个开源分支,作者也是mysql的原作者
虽然有很多人说个人用的话两者相差不大,mariadb也号称”完全兼容mysql”,但是我个人还是不推荐使用mariadb,因为在很多细节上和mysql还是有出入的,而且网上的教程不如mysql丰富
就算你打算使用mariadb,也不推荐使用centos官方源,原因依旧是版本过于古老,官方源中的mariadb甚至不支持utf-8mb4……

在仅配置了官方源的情况下,yum install mysql就会给你安装mariadb!

这里我先mysql官方的yum源
yum install https://dev.mysql.com/get/mysql80-community-release-el7-3.noarch.rpm
之后,你就可以直接yum安装mysql了
注意,yum install mysql 只会安装客户端
你需要yum install mysql-server来安装服务端
在mysql-server第一次启动时,会在log中打印默认的root账户密码
(log文件一般位于/var/log/mysqld.log)
[Note] [MY-010454] [Server] A temporary password is generated for root@localhost: yourPasswd

mysql配置注意事项
mysql8以上采用了新的密码加密算法,这是一个break change,还位于关键的鉴权机制上,导致了为以前版本编写的程序集体木大……
解决方案是在mysql中为用户指定使用mysql_native_password密码加密方式:
alter user user@host identified WITH mysql_native_password by passwd;
注意,请确定你的mysql版本的确含有这个问题,为旧版本的mysql指定这个加密方式将出现错误!

还有基本的创建用户并赋权。。。

create user 'UserName'@'Host' identified WITH mysql_native_password by 'PassWord';
grant ALL on BaesName.* TO 'UserName'@'Host';

别忘了刷新权限….某些情况下它还是有用的
FLUSH PRIVILEGES;

Nginx配置

nginx本质上就是一个转发器,
它充当代理服务器时,可以将你的请求转发给不同的后端服务器,
它配置成php服务器时,可以将你的请求转发php-cgi,
他作为html静态服务器时,可以将你的请求转发给文件系统

从某种意义上来讲,nginx的配置非常简单,结构清晰、简单明了
整个配置文件加起来才几十行,想想某些软件上千行的配置文件qwq

配置文件位置:/etc/nginx/nginx.conf

来梳理一下他的配置文件结构

//一般配置
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配置
http {
    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 = /40x.html {
        }
        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
        }
    }
}

我们主要需要配置的地方在于[虚拟主机配置]以及[路由配置],其他地方一般保持默认即可
从上面,你应该也能看出来,nginx的[虚拟主机配置]是[http配置]的子节点,而[路由配置]则是[虚拟主机配置]的子节点
所以,一个nginx服务器可以有多个虚拟主机,一个虚拟主机也可以配置多个路由

虚拟主机配置
这里,你可以配置这个虚拟主机所监听的端口,ssl,和servername等
[虚拟主机]里的大部分配置也可以写在[路由配置]里,当一个[路由配置]里的设置和它的[虚拟主机]中的设置冲突时,将以[路由配置]里的为准
(root,index,rewrite等指令都符合上述规则)

例子:

//配置ssl
listen 443 ssl;
server_name example.com
ssl_certificate “/etc/pki/nginx/server.crt”;
ssl_certificate_key “/etc/pki/nginx/private/server.key”;

路由配置
路由配置是nginx配置中的灵魂,它的格式如下

location <匹配规则> {
    //配置语句
}

相应的虚拟主机接收到连接时,会根据连接的URI和所有的location进行匹配,然后执行相应location内的配置语句

location的匹配规则由匹配语句类型和匹配语句组成,格式如下:
<匹配语句类型> <匹配语句>

你也可以不使用<匹配语句类型>而直接填写<匹配语句>,这时,你的匹配语句相当于^~

例子:

//匹配所有php文件
location ~ .php$ {}
//匹配所有对robot.txt的访问
location = /robot.txt {}
//匹配所有上面都不满足的请求
location / {}

如果一个请求不符合任何location,则会得到nginx的404响应
如果一个请求同时满足多个location,则按照下面的规则选取第一个location

<匹配语句类型> 为 =
没有<语句类型>时,RUI和<匹配语句>完全符合
<匹配语句类型> 为 ^~
<匹配语句类型> 为 正则表达式(*) ,具体按location在配置文件中的顺序
没有<语句类型>时,RUI和<匹配语句>符合部分起始路径
通用匹配 (/)
接下来是配置语句,
上面说了,nginx本质上是个转发器,那么,在默认情况下(匹配的location里啥也没有),那么nginx默认从网站跟目录中读取静态文件,网站目录由配置项”root”定义,如果这个配置也没有(location里没有,server里也没有),那么默认是”/usr/share/nginx/html

如果你需要将请求转发给后端的其他服务器,那么可以像这样
proxy_pass: https://example.com;
注意,这里的URL后头有没有”/”来结尾是有讲究的
例子:

server_name: test2.example.com;
location /dir/ {
    proxy_pass: https://test1.example.com;
}

这时,你访问test2.example.com/dir/,那么你实际访问的是https://test1.example.com/dir,它把location匹配到的部分也加上去了

但是,如果你的配置长这样

server_name: test2.example.com;
location /dir/ {
    proxy_pass: https://test1.example.com/;
}

同样访问test2.example.com/dir/,那么你实际访问的是https://test1.example.com/,没有加上location匹配到的部分

再加一个例子,将请求转发给php-cgi处理

location ~ .php$ {
    astcgi_pass 127.0.0.1:9000;
    fastcgi_param SCRIPT_FILENAME $document_root/$uri;
    include fastcgi_params
}

nginx还有许多配置项目可供使用,这里我在讲解nginx处理一个请求的顺序中进行讲解

nginx处理一个请求的过程/顺序
nginx处理一请求一共分为11个阶段(post-read、server-rewrite、find-config、rewrite、post-rewrite、preaccess、access、post-access、try-files、content、log)
各种配置项目在不同的阶段生效并处理请求,这也是为啥某些配置项目会覆盖掉之前配置项目的操作

先来一个例外,set指令
例如:set $a 2333;
这个指令可以创建或者赋值一个变量,它在所有阶段前运行

1.post-read阶段
ngx_realip模块提供的配置项目再此阶段执行,例如set_real_ip_from 和real_ip_header
这些配置可以更改请求的来源IP
这里仅执行server节点中的配置,location中的指令会在阶段6中执行
(推荐在这里配置,不要拖到阶段6)

2.server-rewrite阶段
在server节点中的rewrite配置项在此阶段生效(注意,定义在location节点中的rewrite在阶段4执行)
rewrite配置项,使用方式如下:
rewrite <正则表达式> <目标URL> <附加选项>
正则表达式匹配当前请求的uri,把匹配成功的uri重写成目标uri
附加选项有俩:
如果匹配成功,则根据<目标URL>进行”内部跳转”(即转到find-config阶段继续执行)
如果匹配成功,则不再匹配当前同级别的其他rewrite指令
(注意,其实在本阶段执行的rewrite不会涉及到”内部跳转”,因为没有必要,此阶段的下一阶段就是find-config)

3.find-config阶段
此阶段将uri和location进行匹配,
名词”内部重定向”的意思就是返回这一步以重新匹配location

4.rewrite阶段*
该阶段执行location节点中的rewrite的匹配

5.post-rewrite阶段
执行上一阶段匹配成功的rewrite所需的”内部跳转”
本阶段和上一阶段一起构成完整的rewrite指令执行步骤

6.preaccess阶段
allow和deny指令在此阶段工作
这两个指令的作用是访问控制,允许/拒绝某(些)来源IP的访问
例如:

location / {
allow 192.168.1.0/24;
allow 127.0.0.1;
deny all;
}

这样配置可以仅允许192.168.0.0/24和本机访问,因为其余IP都被deny all了
nginx中,如果存在多个allow/deny,那么他们将按照顺序执行
如果来源IP匹配第一条allow规则,那么接下来的allow和deny都不会去匹配了

此阶段还包含了nginx的限流限频配置,支持令牌桶算法和漏斗算法,这里不再详述…
注意,其实第一阶段的ngx_realip模块也在本阶段注册处理程序….但是这都开始判断allow和deny了,你还搁着改来源IP算啥事嘛。。。推荐尽量在server节点中配置ngx_realip相关的项目

7.post-access阶段
这个阶段啥也没有,是nginx核心自己处理一些工作的阶段

8.try-files阶段
顾名思义,该阶段专门处理try_files配置项
try_files 指令接受两个以上任意数量的参数,每个参数都指定了一个 URI,nginx会从第一个参数开始,从文件系统检查该对象是否存在,一旦 某个对象存在,当前URI就会被更改为这个对象所对应的参数 URI,注意,这里不会发生”内部跳转”,如果除最后一个参数外的对象全部不存在,则根据最后一个参数进行”内部跳转”
检查对象是否存在时,由root配置项目指定根目录,然后接上参数URi,如果参数uri不以/结尾,则判断是否存在该文件,如果以/结尾,则判断是否存在该文件夹
举个栗子

root=/web/root_dir;
try_files /testfile /testdir/ /final_page;

那么,nginx会先检查/web/root_dir/testfile这个文件是否存在,
若不存在,则检查/web/root_dir/testdir/这个文件夹是否存在,
若不存在,则根据/final_page这个uri发起”内部跳转”

8.content阶段
该阶段负责向后端(可能是另外的web服务器,也可能是php-cgi)进行连接,
执行配置项proxy_pass和fastcgi_pass等配置项目
index配置项也在此阶段生效
index接收若干个参数,每个参数指定一个默认文件名
如果执行到index配置项时,uri以/结尾,那么index会从第一个参数开始尝试,探测每一个参数所指定的默认文件是否存在,若存在,则将该参数接到uri后面并发起”内部重定向”

9.log阶段
执行和log相关的处理
配置项acces_log和error_log在此阶段生效

MAP节点
在上文中,我提到set配置项可以提供一个变量,但是这个配置项是简陋的,很多时候达不到我们的需求,这时,nginx提供一个http节点下的,和server节点同级的——MAP,使用它可以实现更复杂的定义变量
例子:

map $uri $smyhw {
    ~(?(?<=/)\w+$) $smyhw_name;
    default "";
}

你应该看到了,这个节点有俩参数,第一个参数是原始参数,第二个参数是你要自定义参数
该节点每行一个匹配语句,这个语句的规则同location的匹配规则,拥有匹配类型和匹配语句,唯一不同的是,这里的匹配类型和匹配语句间不能有空格
每一行的第二个参数是”当原始参数匹配该行的规则时,自定义变量将被赋的值”
这里可以使用正则表达式的”捕获”来取得变量
default配置行提供当每一行都不匹配时自定义变量的默认值