Nginx学习

Nginx是什么

Nginx 是一个高性能的 Web 服务器和反向代理服务器
最常见的作用有这几个:

  • 静态资源服务器:直接返回 html/js/css/img
  • 反向代理:把请求转发给后端服务(Node/Java/Python)
  • 负载均衡:把流量分发到多台后端
  • 网关能力:HTTPS 终止、重定向、缓存、压缩(gzip/brotli)、跨域头等

Nginx的配置文件

在 nginx 中,其中比较重要的有以下几个文件,它们都是有层层关联的:

/etc/nginx/nginx.conf
/etc/nginx/conf.d/default.conf

/etc/nginx/nginx.conf

nginx 主配置文件,引用了 /etc/nginx/conf.d/ 目录下的所有配置文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
user  nginx;
worker_processes auto;

error_log /var/log/nginx/error.log notice;
pid /run/nginx.pid;


events {
worker_connections 1024;
}


http {
include /etc/nginx/mime.types;
default_type application/octet-stream;

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;

keepalive_timeout 65;

#gzip on;

include /etc/nginx/conf.d/*.conf;
}

/etc/nginx/conf.d/default.conf

1
2
3
4
5
6
7
8
9
10
11
12
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}

/usr/share/nginx/html

默认的静态资源目录,其目录下的 index.html 就是 nginx 的欢迎页面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html {
color-scheme: light dark;
}
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>
If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.
</p>

<p>
For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br />
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.
</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

利用Docker启动Nginx镜像

1
docker run -it --rm -p 9000:80 nginx:alpine

root和index


location

location 用以匹配路由,配置语法如下

location [ = | ~ | * | ^ ] uri { … }

其中 uri 前可提供以下修饰符

  • = 精确匹配,优先级最高。
  • ^~ 前缀匹配,优先级其次。如果同样是前缀匹配,走最长路径。
  • ~ 正则匹配,优先级再次 (~* 只是不区分大小写,不单列)。如果同样是正则匹配,走第一个路径。
  • / 通用匹配,优先级再次。

location修饰符

location优先级


proxy_pass

proxy_pass 反向代理,也就是用来解决跨域的配置

当使用 proxy_pass 代理路径时,有两种情况

1. 转发时 保留 /api 路径

1
2
3
location /api/ {
proxy_pass http://localhost:3000;
}

结尾没有 / 斜杠
前端请求:/api/user –> 转发到后端:http://localhost:3000/api/user

2. 转发时 去掉 /api 路径

1
2
3
location /api/ {
proxy_pass http://localhost:3000/;
}

末尾加 / 斜杠
前端请求:/api/user –> 转发到后端:http://localhost:3000/user

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
server {
listen 80;
server_name localhost;

root /usr/share/nginx/html;
index index.html index.htm;

# 建议使用此种 proxy_pass 不加 URI 的写法,原样路径即可
# http://localhost:8300/api1/hello -> proxy:3000/api1/hello
location /api1 {
# 可通过查看响应头来判断是否成功返回
add_header X-Config A;
proxy_pass http://api:3000;
}

# http://localhost:8300/api2/hello -> proxy:3000/hello
location /api2/ {
add_header X-Config B;
proxy_pass http://api:3000/;
}

# http://localhost:8300/api3/hello -> proxy:3000/hello/hello
location /api3 {
add_header X-Config C;
proxy_pass http://api:3000/hello;
}

# http://localhost:8300/api4/hello -> proxy:3000//hello
location /api4 {
add_header X-Config D;
proxy_pass http://api:3000/;
}
}

add_header

控制响应头。

很多特性都是通过响应头控制,因此基于此指令可做很多事情,比如:

Cache
CORS
HSTS
CSP

Cache

1
2
3
location /static {
add_header Cache-Control max-age=31536000;
}

CORS

1
2
3
location /api {
add_header Access-Control-Allow-Origin *;
}

HSTS

HTTPS,SSL相关

1
2
3
4
5
location / {
listen 443 ssl;

add_header Strict-Transport-Security max-age=7200;
}

CSP

1
2
3
location / {
add_header Content-Security-Policy "default-src 'self';";
}

最佳实践

  • /index.html:304
  • /assets/*.[hash].(js|css|…):一年强缓存 + immutable
  • gzip/brotli 开启
  • SPA try_files 回退
  • redirect、rewrite配置
  • HTTPS + HTTP2 + 基础安全头
  • 发布前 nginx -t,发布后灰度验证

缓存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# HTML 走协商缓存(每次都向服务端校验)
location ~* \.html?$ {
expires -1; # 不走 Expires 强缓存
add_header Cache-Control "no-cache";
etag on; # 默认一般就是 on,显式写更清晰
if_modified_since exact; # 默认即可,显式写
try_files $uri =404;
}

# JS,CSS走强缓存
location /static/ {
expires 30d;
add_header Cache-Control "public, max-age=2592000, immutable";
try_files $uri =404;
}

接口转发解决跨域

Gzip压缩

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 开启 gzip
gzip on;
gzip_vary on; # 响应头加 Vary: Accept-Encoding,避免代理缓存错配
gzip_proxied any; # 被代理请求也允许压缩
gzip_comp_level 6; # 压缩等级 1-9,6 是常用平衡点
gzip_min_length 1024; # 小于 1KB 不压缩
gzip_buffers 16 8k;
gzip_http_version 1.1;

# 压缩的 MIME 类型(注意 text/html 通常默认已启用)
gzip_types
text/plain
text/css
text/javascript
application/javascript
application/json
application/xml
application/rss+xml
image/svg+xml
font/ttf
font/otf
application/vnd.ms-fontobject
application/x-font-ttf
application/font-woff
application/font-woff2;

History路由

1
2
3
location / {
try_files $uri /index.html;
}

Redirect重定向

Redirect(重定向):告诉浏览器“去另一个 URL”,浏览器地址栏会变,状态码通常是 301/302/307/308

使用场景:

  • 域名跳转(a.com -> b.com)
  • 协议跳转(http -> https)
  • 旧链接永久迁移(SEO 友好,用 301/308)
1
2
3
location = /old-path {
return 301 /new-path;
}

Rewrite重写

Rewrite(重写):Nginx 在服务器内部改 URI 去匹配资源,通常不告诉浏览器,地址栏不变

使用场景:

  • SPA 回退(try_files $uri /index.html 本质类似内部重写思路)
  • 历史路径内部兼容映射
  • 隐藏后端真实路径结构
1
2
3
location /old/ {
rewrite ^/old/(.*)$ /new/$1 last;
}

限制访问source-map文件

1
2
3
4
5
6
7
# 禁止访问 sourcemap
location ~* \.map$ {
access_log off;
log_not_found off;
add_header Cache-Control "no-store" always;
return 404;
}

实现业务逻辑

比如实现移动端跳转xx链接,pc端不变

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
server {
listen 80;
server_name example.com;

location / {
# 默认不跳转
set $is_mobile 0;

# 简单 UA 判断
if ($http_user_agent ~* "(Android|iPhone|iPad|iPod|Mobile)") {
set $is_mobile 1;
}

# 移动端跳到 H5/落地页
if ($is_mobile = 1) {
return 302 https://m.example.com$request_uri;
}

# PC 保持原页面
proxy_pass http://pc_upstream;
}
}

黑白名单配置