Nginx学习笔记
nginx目录结构
路径 | 说明 |
---|---|
/var/log/nginx |
存放nginx 运行日志 |
/etc/nginx |
nginx 配置所在文件夹 |
/etc/nginx/nginx.conf |
nginx 主配置文件 |
/etc/nginx/conf.d |
存放所有server 块配置文件 |
Nginx配置文件构成
一个Nginx配置文件通常包含3个模块:
- 全局块:比如工作进程数,定义日志路径;
- Events块:设置处理轮询事件模型,每个工作进程最大连接数及http层的keep-alive超时时间;
- http块:路由匹配、静态文件服务器、反向代理、负载均衡等。
其中http块又可以进一步分成3块,http全局块里的配置对所有站点生效,server块配置仅对单个站点生效,而location块的配置仅对单个页面或url生效。
# 全局块
...
# events块
events {
...
}
# http块
http
{
# http全局块
...
# 虚拟主机server块
server
{
# server全局块
...
# location块
location [PATTERN]
{
...
}
location [PATTERN]
{
...
}
}
server
{
...
}
# http全局块
...
}
nginx默认配置
nginx包括一个主配置文件nginx.conf
和多个server
块配置(存放于/etc/nginx/conf.d/
)
查看去掉注释后的nginx.conf
文件,grep去除了带 #
的行和 ^$
(即空白行)
cat /etc/nginx/nginx.conf | grep -vE "#|^$"
nginx
主配置文件:nginx.conf
user www-data; # 启动nginx的用户
worker_processes auto; # 工作进程数,建议配置为CPU核心数
pid /run/nginx.pid; # 设置记录主进程ID的文件
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768; # 定义工作进程最大连接数
}
http {
##
# Basic Settings
##
sendfile on; #开启高效文件传输模式,sendfile指令指定nginx是否调用sendfile函数来输出文件
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65; # 设置超时时间(秒)
types_hash_max_size 2048;
# server_tokens off;
# server_names_hash_bucket_size 64;
# server_name_in_redirect off;
include /etc/nginx/mime.types; #文件扩展名与文件类型映射表
default_type application/octet-stream; #默认文件类型
##
# 设置ssl
##
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;
# 请求日志和错误日志
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
##
# Gzip Settings
##
gzip on; #开启gzip压缩输出
# gzip_vary on;
# gzip_proxied any;
# gzip_comp_level 6;
# gzip_buffers 16 8k;
# gzip_http_version 1.1;
# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
##
# Virtual Host Configs
##
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
注意到倒数第二行和倒数第三行的include
,它表示将/etc/nginx/conf.d/
目录下以.conf结尾的文件和目录/etc/nginx/site-enabled/下的所有文件直接包含进来。
你可以理解为将文件的内容直接复制到这里(即/etc/nginx/nginx.conf
中)。
为了方便维护我们
server
相关配置,不会让某一个配置文件过于庞大。通常是将所有的虚拟主机配置文件(也就是server
配置块的内容)存放在/etc/nginx/conf.d/
或者/etc/nginx/sites-enabled/
目录中,在主配置文件中已经默认声明了会读取这两个文件夹下所有*.conf
文件。
根据使用习惯,我一般会在/etc/nginx/conf.d/
建立配置文件来配置server块的内容
首先将默认的配置文件拷贝到/etc/nginx/conf.d/
中
cp /etc/nginx/sites-enabled/default /etc/nginx/conf.d/default.conf
查看默认的server
块配置:
cat /etc/nginx/conf.d/default.conf | grep -vE "#|^$"
默认配置如下:
server {
# 侦听 80 端口,分别配置了 IPv4 和 IPv6
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
# 定义服务器的默认网站根目录位置
root /usr/share/nginx/html;
# 定义主页的文件名
index index.html index.htm;
# 定义虚拟服务器的名称
server_name localhost;
# location 块
location / {
try_files $uri $uri/ =404;
}
}
nginx监听多端口
1.首先在文件nginx.conf
的http { ... }
块中加#
注释掉include /etc/nginx/sites-enabled/*;
2.复制nginx默认的server块配置到/etc/nginx/conf.d
文件夹中
cp /etc/nginx/sites-enabled/default /etc/nginx/conf.d/default.conf
3.新建配置文件,监听80之外的端口
新建一个配置文件myweb.conf
,新建文件夹/var/myweb
,里面创建一个文件index.html
根目录为/var/myweb
,监听端口为6543
,根目录和端口号可以自定义
server {
listen 6543 default_server;
listen [::]:6543 default_server;
root /var/myweb;
index index.html index.htm;
server_name _;
location / {
try_files $uri $uri/ =404;
}
}
4.重载nginx
nginx -t # 检查nginx配置文件是否正确,ok表示配置文件语法正确
nginx -s reload # 重载nginx
location规则
匹配符 | 匹配规则 | 优先级 |
---|---|---|
= |
精确匹配 | 1 |
^~ |
前缀匹配,以某个字符串开头 | 2 |
~ |
区分大小写的正则匹配 | 3 |
~* |
不区分大小写的正则匹配 | 4 |
!~ |
区分大小写的不匹配正则 | 5 |
!~* |
不区分大小写的不匹配正则 | 6 |
/uri |
返回最长匹配的location ,与location 所在位置顺序无关 |
7 |
/ |
通用匹配,任何请求都会匹配到 | 8 |
规则:先精确匹配,没有则查找带有 ^~的前缀匹配,没有则进行正则匹配,最后才返回前缀匹配的结果(如果有的话)
如果优先级相同的话,按照匹配程序选择,匹配程度越高越优先;如果匹配程度相同,则按照nginx中的配置文件中的先后顺序进行选择。
正向代理和反向代理
正向代理(forward proxy):是一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。客户端必须要进行一些特别的设置才能使用正向代理。
客户端必须设置正向代理服务器,当然前提是要知道正向代理服务器的IP地址,还有代理程序的端口。
正向代理的用途:
- 访问原来无法访问的资源,如某些404网站
- 可以做缓存,加速访问资源
- 对客户端访问授权,上网进行认证
- 代理可以记录用户访问记录(上网行为管理),对外隐藏用户信息
反向代理(reverse proxy):实际运行方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个服务器。
反向代理的用途:
- 保证内网的安全,可以使用反向代理提供WAF功能,阻止web攻击
- 负载均衡,通过反向代理服务器来优化网站的负载
nginx使用反向代理
后端服务的接口设置为8080
,nginx
监听的端口为80
使用proxy_pass进行请求转发
/
结尾,不然会有奇奇怪怪的错误!location / {
proxy_pass http://localhost:8080;
}
-
如果
proxy-pass
的地址只配置到端口,不包含/
或其他路径,那么location
将被追加到转发地址中location /path/ { proxy_pass http://localhost:8080; }
例如访问
http://localhost/path/page.html
将被代理到http://localhost:8080/path/page.html
-
如果
proxy-pass
的地址包括/
或其他路径,那么location
不会追加到转发地址中location /path/ { proxy_pass http://localhost:8080/zh-cn/; }
例如访问
http://localhost/path/page.html
将被代理到http://localhost:8080/zh-cn/page.html
更多例子请访问这个链接 !!!
设置代理请求headers
用户可以重新定义或追加header
信息传递给后端服务器。可以包含文本、变量及其组合。默认情况下,仅重定义两个字段:
proxy_set_header Host $proxy_host;
proxy_set_header Connection close;
由于使用反向代理之后,后端服务无法获取用户的真实IP,所以,一般反向代理都会设置以下header信息。
location /path/ {
proxy_set_header Host $host; # 保留代理之前的host
proxy_set_header X-Real-IP $remote_addr; # 保留代理之前的真实客户端ip
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 在多级代理的情况下,记录每次代理之前的客户端真实ip
proxy_pass http://localhost:8080;
}
负载均衡
使用 upstream
定义一组服务 。
upstream 位于 http上下文中,与server 并列,不要放在server中
-
轮询
轮询可用的服务器进行转发
upstream index { server 127.0.0.1:6002; server 127.0.0.1:6001; } server { listen 6500 default_server; listen [::]:6500 default_server; root /home/zfp/myweb; index index.html index.htm; server_name _; location / { try_files $uri $uri/ =404; proxy_pass http://index; } }
-
最小连接数
将下一个请求分配给活动连接数最少的服务器(较为空闲的服务器)
upstream index { least_conn; server 127.0.0.1:6002; server 127.0.0.1:6001; }
请注意,使用轮循机制或最少连接的负载平衡,每个客户端的请求都可能分发到不同的服务器。不能保证同一客户端将始终定向到同一服务器。
-
ip-hash
upstream index { ip_hash; server 127.0.0.1:6002; server 127.0.0.1:6001; }
此方法可确保来自同一客户端的请求将始终定向到同一服务器,除非此服务器不可用。
-
随机
每个请求都将传递到随机选择的服务器。
two
是可选参数,nginx
在考虑服务器权重的情况下随机选择两台服务器,然后使用指定的方法选择其中一台,默认为选择连接数最少(least_conn
)的服务器。upstream index { random two least_conn; server 127.0.0.1:6002; server 127.0.0.1:6001; }
-
权重
每接收到4个请求,3个转发到
http://localhost:6002
,1个转发到http://localhost:6001
upstream index { server 127.0.0.1:6002 weight=3; server 127.0.0.1:6001 weight=1; }
在反向代理中,如果后端服务器在某个周期内响应失败次数超过规定值,nginx会将此服务器标记为失败,并在之后的一个周期不再将请求发送给这台服务器。
通过fail_timeout
来设置检查周期,默认为10秒。
通过max_fails
来设置检查失败次数,默认为1次。
在以下示例中,如果nginx无法向服务器发送请求或在30秒内请求失败次数超过3次,则会将服务器标记为不可用30秒。
upstream index {
server 127.0.0.1:6002;
server 127.0.0.1:6001 max_fails=3 fail_timeout=30s;
}
https配置
使用openssl生成证书
openssl genrsa -des3 -out server.key 2048
openssl req -new -key server.key -out server.csr
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
nginx配置
如果证书设置了密码需要将密码保存到文件中,并通过下面的语句访问
ssl_password_file /etc/nginx/conf.d/server.pass;
详细配置如下:
upstream index{
server 127.0.0.1:6002 weight=3;
server 127.0.0.1:6001 weight=1;
}
server {
# 启用 https
listen 6500 default_server ssl http2;
root /home/zfp/myweb;
index index.html index.htm;
# 后面跟上证书的key和crt文件
ssl_certificate /etc/nginx/conf.d/server.crt;
ssl_certificate_key /etc/nginx/conf.d/server.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
# 证书如果设置了密码需要添加下面这一行
ssl_password_file /etc/nginx/conf.d/server.pass;
# 设置ssl会话缓存
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
server_name _;
location / {
try_files $uri $uri/ =404;
proxy_pass http://index;
}
location /nginx_status {
stub_status on;
}
}
tcp反向代理
注意: stream
块和http
块处于同一级,所以设置tcp反向代理需要在nginx.conf
中操作
在nginx.conf
中添加mysql
的反向代理
#HTTP代理
http {
...
}
#TCP代理
stream {
server {
listen 13306;
proxy_pass localhost:3306;
}
}
负载均衡
stream {
upstream backend-mysql {
server localhost:3306;
server localhost:3307;
keepalive 8;
}
server {
listen 13306;
proxy_pass backend-mysql;
}
}
使用keepalive
定义连接池里空闲连接的数量。
keepalive_timeout
默认60s
。如果连接池里的连接空闲时间超过这个值,则连接关闭。
重写
return
服务端停止处理并将状态码status code
返回给客户端
return code URL
return code text
return code
return URL
status code
类型
状态码
-
2xx 成功
-
3xx 表示重定向
-
- 301 永久重定向
- 302 临时重定向
-
4xx 请求地址出错
-
- 403 拒绝请求
- 404 请求找不到
-
5xx 服务器内部错误
下面是一个临时将请求链接重定向到其他端口的例子
server {
listen 6004 default_server;
listen [::]:6004 default_server;
root /home/zfp/myweb;
index index.html index.htm;
server_name _;
# 临时重定向
# 这里需要写真实ip,不能用localhost,重定向不是反向代理
# 将http://192.168.153.131:6004/重定向到https://192.168.153.131:6500/
return 302 https://192.168.153.131:6500;
location / {
try_files $uri $uri/ =404;
}
location /nginx_status {
stub_status on;
}
}
域名变更,将老域名的请求永久重定向到新域名
server {
listen 80;
listen 443 ssl;
server_name www.old-name.com old-name.com;
return 301 $scheme://www.new-name.com;
}
请求的地址前加上www
server {
listen 80;
listen 443 ssl;
server_name domain.com;
return 301 $scheme://www.domain.com$request_uri;
}
rewrite
如果指定的正则表达式与请求URI
匹配,则URI
将按照字符串中的指定进行更改。指令按其在配置文件中出现的先后顺序执行。
server {
# ...
rewrite ^(/download/.*)/media/(\w+)\.?.*$ $1/mp3/$2.mp3 last;
rewrite ^(/download/.*)/audio/(\w+)\.?.*$ $1/mp3/$2.ra last;
return 403;
# ...
}
上面是使用该指令的示例 nginx
重写规则。它匹配以字符 /download 开头的 URL,然后在路径后面的某个位置包含 /media/ 或 /audio/ 目录。它会将目录替换为 /mp3/,并添加相应的文件扩展名 .mp3 或 .ra。
例如,/download/cdn-west/media/file1 变成了 /download/cdn-west/mp3/file1.mp3。
使用重写规则建议打开重写日志
rewrite_log on;
last和break
规则:
-
last
:如果当前规则不匹配,停止处理后续rewrite
规则,使用重写后的路径,重新搜索location
及其块内指令 -
break
:如果当前规则不匹配,停止处理后续rewrite
规则,执行{}
块内其他指令
在/home/AdminLTE-3.2.0/pages
下创建一个1.txt
,里面内容是this is a file
假设请求地址为http://192.168.153.131:8000/old/1.txt
例1:不适用last和break
server {
listen 8000;
server_name _;
rewrite_log on;
location / {
rewrite ^/old/(.*) /new/$1;
rewrite ^/new/(.*) /pages/$1;
#根目录
root /home/AdminLTE-3.2.0;
#首页
index index.html index2.html index3.html;
}
location /pages/1.txt {
return 200 "this is rewrite test!";
}
}
http://192.168.153.131:8000/pages/1.txt
,最后输出this is rewrite test!
例2:使用break
server {
listen 8000;
server_name _;
rewrite_log on;
location / {
rewrite ^/old/(.*) /new/$1 break;
rewrite ^/new/(.*) /pages/$1;
#根目录
root /home/AdminLTE-3.2.0;
#首页
index index.html index2.html index3.html;
}
location /pages/1.txt {
return 200 "this is rewrite test!";
}
}
rewrite
语句后地址变为http://192.168.153.131:8000/new/1.txt
,阻止执行第二条rewrite
语句,以新路径/new/1.txt
去匹配location
, 先匹配到location /
, 有匹配到location
里的rewrite ^/new/(.*) /pages/$1
规则,重定向到/pages/1.txt
匹配到了location /pages/1.txt
,最终返回了this is rewrite test!
例3:使用last
server {
listen 8000;
server_name nginx-dev;
rewrite_log on;
location / {
rewrite ^/old/(.*) /new/$1 last;
rewrite ^/new/(.*) /pages/$1;
#根目录
root /home/AdminLTE-3.2.0;
#首页
index index.html index2.html index3.html;
}
location /pages/1.txt {
return 200 "this is rewrite test!";
}
}
http://192.168.153.131:8000/new/1.txt
,阻止执行第二条rewrite语句,以新路径/new/1.txt
执行location /
下剩余指令,没有发现/home/AdminLTE-3.2.0/new/1.txt
文件,返回404 not found
其他一些指令
1. gzip压缩
默认情况下,nginx
仅使用压缩MIME
类型是text/html
的响应。若要使用其他MIME
类型压缩响应,可以使用gzip_types
指令并列出其他类型。
gzip on; # 打开gzip压缩
gzip_types text/plain application/xml; # 添加压缩文件类型
gzip_min_length 1000; # 指定压缩响应的最小长度,
2. sendfile
sendfile
指令通常用于上传和下载文件的请求中。
默认情况下,nginx
处理文件传输本身,并在发送之前将文件复制到缓冲区中。启用sendfile
指令可消除将数据复制到缓冲区的步骤,直接将一个文件复制到另一个文件。
将sendfile
指令与tcp_nopush
指令一起使用。这使nginx
能够在获得数据块后立即在一个数据包中发送HTTP
响应标头。
location /download {
sendfile on;
tcp_nopush on;
...
}
3. try_files
try_files
指令可用于检查指定的文件或目录是否存在;如果不存在,则重定向到指定位置。
如下,如果原始URI
对应的文件不存在,nginx
将内部重定向到/home/zfp/myweb/1.txt
server {
listen 6002 default_server;
listen [::]:6002 default_server;
root /home/zfp/myweb;
index index.html index.htm;
server_name _;
location / {
try_files $uri $uri/ /1.txt;
}
location /nginx_status {
stub_status on;
}
}
最后一个参数也可以为状态码
在下面的示例中,如果指令的所有参数都无法解析为现有文件或目录,则会返回404错误。
try_files $uri $uri/ =404;
4. error_page
为错误指定显示的页面。值可以包含变量。
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
nginx小技巧
1.http和https共用一个端口
方案1:
使用错误页将http
请求重定向为https
请求,这样就解决了原先的http请求无缝切换为https请求
error_page 497 https://$http_host$request_uri;
方案2:
之前是6501端口监听http请求,6500端口监听https请求
现在是6501监听到http请求将强制使用https,不需要用户开放6500端口来处理https请求
在使用TCP(stream)
代理转发流量时,可以使用ssl_preread_protocol
变量区分SSL/TLS和其他协议。
nginx.conf
中添加下列配置:
stream {
upstream web {
server 192.168.153.131:6502; # 多使用一个端口来处理http请求
}
upstream https {
server 192.168.153.131:6500;
}
log_format basic 'ssl_version: $ssl_preread_protocol | upstream: $upstream';
access_log /var/log/nginx/nginx-access.log basic ;
# 根据不同的访问协议转发给不同的上游
map $ssl_preread_protocol $upstream {
"" web;
"TLSv1.3" https;
default https;
}
# HTTPS and HTTP on the same port
server {
listen 6501; # 监听6501端口
proxy_pass $upstream;
ssl_preread on; # 开启ssl_preread功能
}
}
监听6501端口,根据不同请求进行转发:
http
请求转发到http://192.168.153.131:6502
, https
请求转发到https://192.168.153.131:6500
修改原来的server
配置
server {
listen 6502;
server_name localhost;
return 301 https://192.168.153.131:6501;
}
server {
# listen 6501 default_server;
listen 6500 default_server ssl http2;
root /home/zfp/myweb;
index index.html index.htm;
# error_page 497 https://$http_host$request_uri;
ssl_certificate /etc/nginx/conf.d/server.crt;
ssl_certificate_key /etc/nginx/conf.d/server.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_password_file /etc/nginx/conf.d/server.pass;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
server_name _;
location / {
try_files $uri $uri/ =404;
}
}