Skip to content

Nginx

单页面应用配置

nginx
server {
    listen       80;
    listen  [::]:80;
    server_name  www.example.com;
    charset utf-8;
    index  index.html index.htm;
    root   /usr/share/nginx/html;

    location ~ .*\.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm)$ {
      expires      30d;
    }

    location ~ .*\.(?:js|css)$ {
      expires      7d;
    }

    location / {
      try_files $uri $uri/ /index.html;
    }
}

nginx配置中 server可以listen多个端口,比如上面同时监听了 80端口和ipv6的80端口,还可以增加其余的端口比如 listen 8080;使用分号作为结束符.

SSL 配置

nginx的ssl配置是在服务器打开443端口

nginx
server {
  listen 443 ssl;
  server_name www.example.com;
  charset utf-8;
  index  index.html index.htm;
  root   /usr/share/nginx/html;

  ssl_certificate cert/fullchain.pem;
  ssl_certificate_key cert/privkey.pem;

  ssl_session_cache shared:SSL:10m;
  ssl_session_timeout 5m;

  ssl_ciphers HIGH:!aNULL:!MD5;
  ssl_prefer_server_ciphers on;

  location ~ .*\.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|ttf)$ {
    expires      30d;
  }

  location ~ .*\.(?:js|css)$ {
    expires      7d;
  }

  location / {
    try_files $uri $uri/ /index.html;
  }
}
  1. ssl_certificate 和 ssl_certificate_key

ssl_certificate是证书文件, ssl_certificate_key私钥文件, 把对应的值替换成需要的路径, 可以使用Let's Encrypt生成免费证书,这里有之前的文章

  1. ssl_session_cache 和 ssl_session_timeout

ssl_session_cache SSL会话缓存的大小决定了服务器可以存储的 SSL 会话数量。较大的缓存可以容纳更多的会话,提供更好的性能,但也会占用更多的内存。您可以根据预计的并发连接数和服务器的可用内存来选择合适的大小。通常建议将缓存大小设置为能够容纳大约几千个会话的数量,例如 shared:SSL:10m 表示缓存大小为 10MB。

ssl_session_timeout指定了 SSL 会话的超时时间为 5 分钟(5m)。当一个 SSL 会话在服务器缓存中超过这个时间没有被使用,它将被自动清除。通过设置合适的超时时间,可以在保证会话有效性的同时,释放不再使用的会话,以便为新会话腾出空间。

  1. ssl_ciphers 和 ssl_prefer_server_ciphers

ssl_ciphers HIGH:!aNULL:!MD5;

  • HIGH:!aNULL:!MD5中 high指启用高强度的密码套件,优先选择更安全的加密算法
  • !aNULL 表示禁止使用匿名(NULL)加密算法,确保需要进行身份验证。
  • !MD5 表示禁止使用 MD5 散列算法,因为它已被广泛认为是不安全的。

ssl_prefer_server_ciphers on;

这句配置设置服务器偏好密码套件。当客户端和服务器之间协商密码套件时,启用该配置后,服务器将优先选择自己支持的密码套件,而不是客户端提供的顺序。这可以确保服务器使用自己认为更安全的密码套件,提高安全性。

location

https://nginx.org/en/docs/http/ngx_http_core_module.html#location

nginx
Syntax:	location [ = | ~ | ~* | ^~ ] uri { ... }
location @name { ... }
Default:	—
Context:	server, location
  • = 精确匹配 location = /
  • ~ 正则匹配(区分大小写) location ~ /bbs-api/
  • ~* 正则匹配(不区分大小写) location ~* /bbs-api/
  • ^~ 前缀匹配 location ^~ /bbs-api
  • 普通匹配 location /bbs-api/

rewrite

https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite

nginx
Syntax:	rewrite regex replacement [flag];
Default:	—
Context:	server, location, if
  1. 场景1: 永久跳转

http由于链接的不安全性已经被很多网站替换成了https,而以前被搜索引擎收录的或者外链可能有不少http链接, 对这些链接兼容就需要使用301永久跳转

nginx
rewrite ^/(.*)$ https://www.example.com/$1 permanent;

permanent标识301永久跳转, 还有一种比较直接的301跳转方式, 它们的效果是一致的,rewrite更灵活一些.

nginx
return 301 https://www.luoage.com$request_uri;
  1. 场景2: 改写path

例如有a,b两个服务共用个门户url, 当访问的path以/b/开头都进入到b服务,b服务的接口是以/api开头, 这样就可以使用rewrite改写path, 如下

nginx
location ^~ /b/ {
  proxy_pass http://b-service:80;
  rewrite ^/b/(.*) /$1 break;
}

注意

rewrite需必须放在proxy_pass之后

proxy_pass

  • 反向代理

url path以bbs-api开头的请求代理到bbs-api服务

nginx
location ^~ /bbs-api/ {
  proxy_pass http://bbs-api:80;
  proxy_set_header Host $host;
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

注意

头部设置需要放在proxy_pass之后

  • 负载均衡
nginx
http {
  upstream backend {
    server backend1.example.com;
    server backend2.example.com;
    server backend3.example.com;
  }

  server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
  }
}

proxy_pass和nginx内置的upstream模块配合使用,将访问请求到后端的一个服务上,默认轮训,还有一些算法比如 ip_hash

nginx
upstream backend {
    ip_hash;
    server backend1.example.com;
    server backend2.example.com;
    server backend3.example.com;
}

return

https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#return

nginx
Syntax:	return code [text];
return code URL;
return URL;
Default:	—
Context:	server, location, if
nginx
server {
  listen 8080;
  server_name localhost;

  location / {
    return 404;
  }
}
sh
$ curl -I localhost:8080

HTTP/1.1 404 Not Found
Server: nginx/1.27.0
Date: Sun, 30 Jun 2024 11:38:37 GMT
Content-Type: application/octet-stream
Content-Length: 14
Connection: keep-alive

if

https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#if

nginx
Syntax:	if (condition) { ... }
Default:	—
Context:	server, location
  • 字符串相同或者不同可以使用 =!=
  • 正则区分大小写 ~, !~
  • 正则不区分大小写 ~*, !~*
nginx
if ($request_method = POST) {
    return 405;
}

nginx跨域

这里还有个小插曲,在nginx的文档中我并没有找到 $http_origin 这个变量, 但是看到不少文章使用这个变量,查阅一番才发现原来 $http_ 只是一个前缀,后面可以携带http头部任意的内容,大写转成了小写,中横线转换成了下划线, 举个例子,下面是我找到的百度header头

Accept: application/json, text/javascript, */*; q=0.01
Accept-Encoding: gzip, deflate, br, zstd
Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7
Cache-Control: no-cache
Connection: keep-alive
Cookie: test
Host: www.baidu.com
Origin: https://www.baidu.com
Pragma: no-cache
Ps-Dataurlconfigqid: 0xc50507d500119afd
Referer: https://www.baidu.com/?tn=68018901_16_pg
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0
sec-ch-ua: "Not/A)Brand";v="8", "Chromium";v="126", "Microsoft Edge";v="126"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "macOS"

如果限制只有 macOS 才能访问网址这个网址要怎么做?对非macOS字符串做404操作

nginx
if ($http_sec_ch_ua_platform !~* macos) {
  return 400;
}

那么接下来这个变量 $http_origin 就很好理解了,对应上面的 https://www.baidu.com

nginx
  add_header 'Access-Control-Allow-Origin' $http_origin;
  add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
  add_header 'Access-Control-Allow-Headers' 'Accept, Content-Type, Referer, User-Agent, Origin, X-Requested-With';
  add_header 'Access-Control-Allow-Credentials' 'true';
  add_header 'Access-Control-Max-Age' 86400;

  if ($request_method = 'OPTIONS') {
    # add_header 'Content-Type' 'text/plain; charset=utf-8';
    # add_header 'Content-Length' 0;
    return 204;
  }

注意

add_header 指令只能在 location 块使用

nginx设置文件上传大小限制

http {
    client_max_body_size 20M;
}

Reference