文章目录
一、基本配置及配置说明
1.1 典型配置
user nginx; # 运行用户,默认即是nginx,可以不进行设置
worker_processes 1; # Nginx 进程数,一般设置为和 CPU 核数一样
error_log /var/log/nginx/error.log warn; # Nginx 的错误日志存放目录
pid /var/run/nginx.pid; # Nginx 服务启动时的 pid 存放位置
events {
use epoll; # 使用epoll的I/O模型(如果你不知道Nginx该使用哪种轮询方法,会自动选择一个最适合你操作系统的)
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; # Nginx访问日志存放位置
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; # 配置监听的端口
server_name localhost; # 配置的域名
location / {
root /usr/share/nginx/html; # 网站根目录
index index.html index.htm; # 默认首页文件
deny 172.168.22.11; # 禁止访问的ip地址,可以为all
allow 172.168.33.44;# 允许访问的ip地址,可以为all
}
error_page 500 502 503 504 /50x.html; # 默认50x对应的访问页面
error_page 400 404 error.html; # 同上
}
}
server块可以包含多个location块,location指令用于匹配uri,语法:
location[ = | ~ | ~* | ^~ ] uri {
...
}
指令后:
=
精确匹配路径,用于不含正则表达式的uri前,如匹配成功,不再进行后续的查找;^~
用于不含正则表达式的uri前,表示如果 该符号后面的字符 是最佳匹配,采用该规则 ,不再进行后续 的查找;~
用该符号后的正则去匹配路径,区分大小写~*
用正则去匹配路径,不区分大小写。
1.2 全局变量(nginx内置预定义变量)
Nginx有一些常用的全局变量,可以在配置的任何位置使用它们,如下表:
全局变量名 | 功能 |
---|---|
$host | 请求信息中的 Host,如果请求中没有 Host 行,则等于设置的服务器名,不包含端口 |
$request_method | 客户端请求类型,如 GET、POST |
$args | 请求中的参数 |
$arg_PARAMETER | GET 请求中变量名 PARAMETER 参数的值,例如:$http_user_agent(Uaer-Agent 值), $http_referer… |
$content_length | 请求头中的 Content-length 字段 |
$http_user_agent | 客户端agent信息 |
$http_cookie | 客户端cookie信息 |
$remote_addr | 客户端的IP地址 |
$remote_port | 客户端的端口 |
$remote_port | 客户端的端口 |
$http_user_agent | 客户端agent信息 |
$server_protocol | 请求使用的协议,如 HTTP/1.0、HTTP/1.1 |
$server_addr | 服务器地址 |
$server_name | 服务器名称 |
$server_port | 服务器的端口号 |
$scheme | HTTP 方法(如http,https) |
二、常用配置
2.1 反向代理配置
反向代理是工作中最常用的服务器功能,可以将请求转发到本机另一个服务器上,也可以根据访问的路径跳转到不同端口的服务中。也经常被用来解决跨域问题。
下面是一个简单示例:
- 需求:监听
9001
商品,然后把访问不同路径的请求进行反向代理:- 把访问
http://127.0.0.1:9001/edu
的请求转发到http://127.0.0.1:8080
- 把访问
http://127.0.0.1:9001/vod
的请求转发到http://127.0.0.1:8081
- 首先进入 Nginx 的主配置文件:
vim /etc/nginx/nginx.conf
- 增加一个server块:
server{
listen 9001;
server_name localhost;
location ~ /edu/ {
proxy_pass http://127.0.0.1:8080;
}
location ~ /vod/ {
proxy_pass http://127.0.0.1:8081;
}
}
其他反向代理的指令:
proxy_set_header
:在将客户端请求发送给后端服务器之前,更改来自客户端的请求头信息;proxy_content_timeout
:配置Nginx与后端代理服务器尝试建立连接的超时时间;proxy_read_timeout
: 配置Nginx向后端 服务器组发出read请求后,等待相应的超时时间proxy_send_timeout
: 配置Nginx向后端 服务器组发出write请求后,等待相应的超时时间proxy_redirect
: 用于修改后端服务器返回的响应头中的Location和Refresh
2.2 跨域CORS配置
现在前后端分离的项目一统天下,经常本地起了前端服务,需要访问不同的后端地址,不可避免遇到跨域问题。
2.2.1 使用反向代理解决跨域
在前端服务地址为
a.test.com
页面请求b.test.com
的后端服务导致的跨域,可以这样配置:
server {
listen 9001;
server_name a.test.com;
# 请求跨域,约定代理后端服务请求path以/api/开头
location ^~/api/ {
# 这里重写了请求,将正则匹配中的第一个分组的path拼接到真正的请求后面,并用break停止后续匹配
rewrite ^/apis/(.*)$ /$1break;
proxy_pass b.test.com;
# 两个域名之间cookie的传递与回写
proxy_cookie_domain b.test.com a.test.com;
}
}
2.2.2 配置header解决跨域
当浏览器在访问跨源的服务器时,也可以在跨域的服务器上直接设置 Nginx,从而前端就可以无感地开发,不用把实际上访问后端的地址改成前端服务的地址,这样可适性更高
- 对于跨域的地址,新增如下配置
# /etc/nginx/conf.d/b.conf
server {
listen 80;
server_name b.test.com;
add_header 'Access-Control-Allow-Origin'$http_origin; # 全局变量获得当前请求origin,带cookie的请求不支持*
add_header 'Access-Control-Allow-Credentials''true'; # 为 true 可带上 cookie
add_header 'Access-Control-Allow-Methods''GET, POST, OPTIONS'; # 允许请求方法
add_header 'Access-Control-Allow-Headers'$http_access_control_request_headers; # 允许请求的 header,可以为 *
add_header 'Access-Control-Expose-Headers''Content-Length,Content-Range';
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Max-Age' 1728000; # OPTIONS 请求的有效期,在有效期内不用发出另一条预检请求
add_header 'Content-Type''text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204; # 200 也可以
}
location / {
root /usr/share/nginx/html/be;
index index.html;
}
}
然后
nginx -s reload
重新加载配置即可
2.3 开启gzip压缩
gzip 是一种常用的网页压缩技术,传输的网页经过 gzip 压缩之后大小通常可以变为原来的一半甚至更小(官网原话),更小的网页体积也就意味着带宽的节约和传输速度的提升,特别是对于访问量巨大大型网站来说,每一个静态资源体积的减小,都会带来可观的流量与带宽的节省。
2.3.1 Nginx配置gzip
使用 gzip 不仅需要 Nginx 配置,浏览器端也需要配合,需要在请求消息头中包含
Accept-Encoding: gzip
(IE5 之后所有的浏览器都支持了,是现代浏览器的默认设置)。一般在请求 html 和 css 等静态资源的时候,支持的浏览器在 request 请求静态资源的时候,会加上Accept-Encoding: gzip
这个 header,表示自己支持 gzip 的压缩方式,Nginx 在拿到这个请求的时候,如果有相应配置,就会返回经过 gzip 压缩过的文件给浏览器,并在 response 相应的时候加上content-encoding: gzip
来告诉浏览器自己采用的压缩方式(因为浏览器在传给服务器的时候一般还告诉服务器自己支持好几种压缩方式),浏览器拿到压缩的文件后,根据自己的解压方式进行解析。
gzip on; # 默认off,是否开启gzip
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
# 上面两个开启基本就能跑起了,下面的愿意折腾就了解一下
gzip_static on;
gzip_proxied any;
gzip_vary on;
gzip_comp_level 6;
gzip_buffers 16 8k;
# gzip_min_length 1k;
gzip_http_version 1.1;
说明:
- gzip_types:要采用gzip压缩的MIME文件类型,其中text/html被系统强制启用
- gzip_static: 默认off, 该模块启用后,Nginx首先检查 是否存在请求静态文件的gz结尾的上收到相应内容gzip压缩;
- gzip_proxied:默认 off,nginx做为反向代理时启用,用于设置启用或禁用从代理服务器上收到相应内容 gzip 压缩;
- gzip_vary:用于在响应消息头中添加 Vary:Accept-Encoding,使代理服务器根据请求头中的 Accept-Encoding 识别是否启用 gzip 压缩;
- gzip_comp_level:gzip 压缩比,压缩级别是 1-9,1 压缩级别最低,9 最高,级别越高压缩率越大,压缩时间越长,建议 4-6;
- gzip_buffers:获取多少内存用于缓存压缩结果,16 8k 表示以 8k*16 为单位获得;
- gzip_min_length:允许压缩的页面最小字节数,页面字节数从header头中的 Content-Length 中进行获取。默认值是 0,不管页面多大都压缩。建议设置成大于 1k 的字节数,小于 1k 可能会越压越大;
- gzip_http_version:默认 1.1,启用 gzip 所需的 HTTP 最低版本;
这个配置可以插入到 http 模块整个服务器的配置里,也可以插入到需要使用的虚拟主机的 server 或者下面的 location 模块中,也可以 include 到 http 模块中了。
其他更全的配置信息可以查看 <官网文档ngx_http_gzip_module>,配置前是这样的:
配置之后 response 的 header 里面多了一个Content-Encoding: gzip
,返回信息被压缩了:
- 注意了,一般 gzip 的配置建议加上 gzip_min_length 1k,不加的话:
由于文件太小,gzip 压缩之后得到了 -48% 的体积优化,压缩之后体积还比压缩之前体积大了,所以最好设置低于 1kb 的文件就不要 gzip 压缩了
2.3.2 Webpack的gzip配置
当前端项目使用 Webpack 进行打包的时候,也可以开启 gzip 压缩:
// vue-cli3 的 vue.config.js 文件
const CompressionWebpackPlugin = require('compression-webpack-plugin')
module.exports = {
// gzip 配置
configureWebpack: config => {
if (process.env.NODE_ENV === 'production') {
// 生产环境
return {
plugins: [new CompressionWebpackPlugin({
test: /\.js$|\.html$|\.css/, // 匹配文件名
threshold: 10240, // 文件压缩阈值,对超过10k的进行压缩
deleteOriginalAssets: false// 是否删除源文件
})]
}
}
},
...
}
由此打包出来的文件会有一个对应的
.gz
标识 ,因为这个文件超过了10kb
,有的文件没有超过10kb
就没进行gzip
打包。
那么为啥这里 Nginx 已经有了 gzip 压缩,Webpack 这里又整了个 gzip 呢,因为如果全都是使用 Nginx 来压缩文件,会耗费服务器的计算资源,如果服务器的 gzip_comp_level 配置的比较高,就更增加服务器的开销,相应增加客户端的请求时间,得不偿失。
如果压缩的动作在前端打包的时候就做了,把打包之后的高压缩等级文件作为静态资源放在服务器上,Nginx 会优先查找这些压缩之后的文件返回给客户端,相当于把压缩文件的动作从 Nginx 提前给 Webpack 打包的时候完成,节约了服务器资源,所以一般推介在生产环境应用 Webpack 配置 gzip 压缩
2.4 配置负载均衡
负载均衡的主要思想就是把负载均匀合理地分发到多个服务器上,实现压力分流的目的。
主要配置如下:
http {
upstream myserver {
# ip_hash; # ip_hash 方式
# fair; # fair 方式
server 127.0.0.1:8081; # 负载均衡目的服务地址
server 127.0.0.1:8080;
server 127.0.0.1:8082 weight=10; # weight 方式,不写默认为 1
}
server {
location / {
proxy_pass http://myserver;
proxy_connect_timeout 10;
}
}
}
Nginx 提供了好几种分配方式,默认为轮询,就是轮流来。有以下几种分配方式:
- 轮询,默认方式,每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务挂了,能自动剔除;
- weight,权重分配,指定轮询几率,权重越高,在被访问的概率越大,用于后端服务器性能不均的情况;
- ip_hash,每个请求按访问 IP 的 hash 结果分配,这样每个访客固定访问一个后端服务器,可以解决动态网页 session 共享问题。负载均衡每次请求都会重新定位到服务器集群中的某一个,那么已经登录某一个服务器的用户再重新定位到另一个服务器,其登录信息将会丢失,这样显然是不妥的;
- fair(第三方),按后端服务器的响应时间分配,响应时间短的优先分配,依赖第三方插件 nginx-upstream-fair,需要先安装;
2.5 适配PC或移动设备
根据用户设备不同返回不同样式的站点,以前经常使用的是纯前端的自适应布局,但无论是复杂性和易用性上面还是不如分开编写的好,比如我们常见的淘宝、京东…这些大型网站就都没有采用自适应,而是用分开制作的方式,根据用户请求的
user-agent
来判断是返回 PC 还是 H5 站点。
- 原理: 通过使用
$http_user_agent
全局变量来判断用户请求的user-agent
,指向不同的root路径,返回对应站点。
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html/pc;
if ($http_user_agent ~* '(Android|webOS|iPhone|iPod|BlackBerry)') {
root /usr/share/nginx/html/mobile;
}
index index.html;
}
}
2.6 配置Https
- 拿到
xxx.crt
和xxx.key
文拷贝到服务器目录,再配置下:
server {
listen 443 ssl http2 default_server; # SSL 访问端口号为 443
server_name sherlocked93.club; # 填写绑定证书的域名
ssl_certificate /etc/nginx/https/1_a.test.com_bundle.crt; # 证书文件地址
ssl_certificate_key /etc/nginx/https/2_a.test.com.key; # 私钥文件地址
ssl_session_timeout 10m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #请按照以下协议配置
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
# 几个增强安全性的命令:
add_header X-Frame-Options DENY; # 减少点击劫持
add_header X-Content-Type-Options nosniff; # 禁止服务器自动解析资源类型
add_header X-Xss-Protection 1; # 防XSS攻击
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
}
- 写完 nginx -t -q 校验一下,没问题就 nginx -s reload,现在去访问 https://a.test.com/ 就能访问 HTTPS 版的网站了。
三、一些常用技巧
3.1 静态服务
server {
listen 80;
server_name static.test.com;
charset utf-8; # 防止中文文件名乱码
location /download {
alias /usr/share/nginx/html/static; # 静态资源目录
autoindex on; # 开启静态资源列目录
autoindex_exact_size off; # on(默认)显示文件的确切大小,单位是byte;off显示文件大概大小,单位KB、MB、GB
autoindex_localtime off; # off(默认)时显示的文件时间为GMT时间;on显示的文件时间为服务器时间
}
}
3.2 图片防盗链
server {
listen 80;
server_name localhost;
# 图片防盗链
location ~* \.(gif|jpg|jpeg|png|bmp|swf)$ {
valid_referers none blocked 192.168.0.2; # 只允许本机 IP 外链引用
if ($invalid_referer){
return 403;
}
}
}
3.3 请求过滤
# 非指定请求全返回 403
if ( $request_method !~ ^(GET|POST|HEAD)$ ) {
return 403;
}
location / {
# IP访问限制(只允许IP是 192.168.0.2 机器访问)
allow 192.168.0.2;
deny all;
root html;
index index.html index.htm;
}
3.4 配置图片、字体等静态文件缓存
由于图片、字体、音频、视频等静态文件在打包的时候通常会增加了 hash,所以缓存可以设置的长一点,先设置强制缓存,再设置协商缓存;如果存在没有 hash 值的静态文件,建议不设置强制缓存,仅通过协商缓存判断是否需要使用缓存。
# 图片缓存时间设置
location ~ .*\.(css|js|jpg|png|gif|swf|woff|woff2|eot|svg|ttf|otf|mp3|m4a|aac|txt)$ {
expires 10d;
}
# 如果不希望缓存
expires -1;
3.5 单页面项目history路由配置
server {
listen 80;
server_name a.test.com;
location / {
root /usr/share/nginx/html/dist; # vue 打包后的文件夹
index index.html index.htm;
try_files $uri$uri/ /index.html @rewrites;
expires -1; # 首页一般没有强制缓存
add_header Cache-Control no-cache;
}
# 接口转发,如果需要的话
#location ~ ^/api {
# proxy_pass http://be.sherlocked93.club;
#}
location @rewrites {
rewrite ^(.+)$ /index.html break;
}
}
3.6 HTTP 请求转发到 HTTPS
配置完 HTTPS 后,浏览器还是可以访问 HTTP 的地址 http://a.test.com/ 的,可以做一个 301 跳转,把对应域名的 HTTP 请求重定向到 HTTPS 上
erver {
listen 80;
server_name www.sherlocked93.club;
# 单域名重定向
if ($host = 'www.sherlocked93.club'){
return 301 https://a.test.com$request_uri;
}
# 全局非 https 协议时重定向
if ($scheme != 'https') {
return 301 https://$server_name$request_uri;
}
# 或者全部重定向
return 301 https://$server_name$request_uri;
# 以上配置选择自己需要的即可,不用全部加
}
3.7 最佳实践
- 为了使 Nginx 配置更易于维护,建议为每个服务创建一个单独的配置文件,存储在
/etc/nginx/conf.d
目录,根据需求可以创建任意多个独立的配置文件。 - 独立的配置文件,建议遵循以下命名约定
<服务>.conf
,比如域名是test.com
,那么你的配置文件的应该是这样的/etc/nginx/conf.d/test.com
,如果部署多个服务,也可以在文件名中加上 Nginx 转发的端口号,比如test.com.8080.conf
,如果是二级域名,建议也都加上a.test.com.conf
。 - 常用的、复用频率比较高的配置可以放到
/etc/nginx/snippets
文件夹,在 Nginx 的配置文件中需要用到的位置 include 进去,以功能来命名,并在每个 snippet 配置文件的开头注释标明主要功能和引入位置,方便管理。比如之前的gzip、cors
等常用配置,我都设置了 snippet。 - Nginx 日志相关目录,内以
域名.type.log 命名
(比如a.test.com.access.log
和b.test.com.error.log
)位于/var/log/nginx/
目录中,为每个独立的服务配置不同的访问权限和错误日志文件,这样查找错误时,会更加方便快捷。
参考文档:
Nginx 从入门到实践,万字详解!