配置跨域
下述的 add_header
末尾都可以加上了 always
,它表示不管 HTTP 返回状态码是多少都会使 add_header
生效,有些时候服务端可能会返回 4XX
的 HTTP 状态码,这时候如果少了 always
会导致 add_header
失效,从而导致浏览器报跨域错误。
1 2 3 4 5 6 7 8 9 10 11 12
| location / { add_header 'Access-Control-Allow-Origin' '*' always; add_header 'Access-Control-Allow-Credentials' 'true' always; add_header 'Access-Control-Allow-Methods' 'GET,HEAD,PUT,POST,DELETE,PATCH,OPTIONS' always; add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Origin' always;
if ($request_method = 'OPTIONS') { return 204; }
... }
|
或者使用通配符,允许所有头部、所有域、所有方法跨域,存在安全隐患(不推荐使用)
1 2 3 4 5 6 7 8 9 10 11 12
| location / { add_header 'Access-Control-Allow-Origin' '*' always; add_header 'Access-Control-Allow-Headers' '*' always; add_header 'Access-Control-Allow-Methods' '*' always; add_header 'Access-Control-Allow-Credentials' 'true' always;
if ($request_method = 'OPTIONS') { return 204; }
... }
|
通过 CURL 命令测试配置是否生效
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| $ curl -I http://www.example.com/slider.e37972.js
HTTP/1.1 200 OK Server: Nginx/2.2.3 Date: Tue, 25 Dec 2018 17:59:53 GMT Content-Type: application/javascript Content-Length: 53386 Last-Modified: Tue, 25 Dec 2018 17:56:47 GMT Connection: keep-alive Access-Control-Allow-Origin: * Access-Control-Allow-Credentials: true Access-Control-Allow-Methods: GET,HEAD,PUT,POST,DELETE,PATCH,OPTIONS Access-Control-Allow-Headers: Accept,Authorization,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Origin Accept-Ranges: bytes
|
删除指定的 Heder
相关指令:
proxy_set_header
is to set a request headeradd_header
is to add header to responseproxy_hide_header
is to hide a response header
如果要替换响应中已经存在的 Header,仅仅使用 add_header
是不够的,因为它将堆叠值(堆叠来自服务器和自己添加的 Header),所以必须分两步执行操作:
- 删除 Header:
proxy_hide_header Access-Control-Allow-Origin;
- 添加自定义 Header:
add_header Access-Control-Allow-Origin "*" always;
假设需要删除响应中已存在的跨域 Header,然后往响应中添加自定义的跨域 Header,配置示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| location / { proxy_hide_header Access-Control-Allow-Origin; proxy_hide_header Access-Control-Allow-Methods; proxy_hide_header Access-Control-Allow-Headers; proxy_hide_header Access-Control-Allow-Credentials;
add_header 'Access-Control-Allow-Origin' '*' always; add_header 'Access-Control-Allow-Credentials' 'true' always; add_header 'Access-Control-Allow-Methods' 'GET,HEAD,PUT,POST,DELETE,PATCH,OPTIONS' always; add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Origin' always;
proxy_pass http://example.com; 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_set_header X-Forwarded-Proto $scheme; proxy_set_header REMOTE-HOST $remote_addr; }
|
配置 GZip 压缩
1 2 3 4 5 6 7 8 9 10 11
| http { gzip on; gzip_min_length 1k; gzip_buffers 4 16k; gzip_comp_level 3; gzip_vary off; gzip_disable "MSIE [1-6]\."; gzip_types text/plain text/css text/xml text/javascript application/json application/x-javascript application/xml application/xml+rss application/javascript;
... }
|
1 2 3 4 5 6 7 8 9 10 11
| $ curl -I -H "Accept-Encoding: gzip, deflate" http://www.example.com/slider.e37972.js
HTTP/1.1 200 OK Server: Nginx/2.2.3 Date: Tue, 25 Dec 2018 17:54:06 GMT Content-Type: application/javascript Last-Modified: Tue, 25 Dec 2018 17:52:31 GMT Connection: keep-alive Content-Encoding: gzip
|
Nginx 反向代理配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| http { upstream applications { server 192.168.68.43:8081 weight=1; server 192.168.68.45:8082 weight=1; }
server { listen 80; server_name localhost;
location / { proxy_pass http://applications; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-Port $remote_port; proxy_set_header REMOTE-HOST $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } } }
|
配置 Web 静态资源的浏览器端缓存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| server { root /home/wwwroot/hexo-blog;
location ~ .*\.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|eot|ttf|woff|woff2)$ { expires 7d; }
location ~ .*\.(?:js|css)$ { expires 7d; }
location ~ .*\.(?:htm|html)$ { # 根据具体的项目业务,决定是否需要配置浏览器端的静态页面缓存,以下配置表示是不缓存任何Html页面 add_header Cache-Control "private, no-store, no-cache, must-revalidate, proxy-revalidate"; }
... }
|
Nginx 利用 Referer 指令实现防盗链
语法说明
1 2 3 4 5 6 7 8 9 10
| 语法: valid_referers none | blocked | server_names | string …; 配置段: server, location 指定合法的来源'referer', 他决定了内置变量$invalid_referer的值,如果referer头部包含在这个合法网址列表中,这个变量被设置为0,否则设置为1. 不区分大小写。
参数说明: none "Referer" 为空 blocked "Referer"不为空,但是里面的值被代理或者防火墙删除了,这些值都不以http://或者https://开头,而是"Referer: XXXXXXX"这种形式 server_names "Referer"来源头部包含当前的server_names(当前域名) arbitrary string 任意字符串,定义服务器名或者可选的URI前缀.主机名可以使用*开头或者结尾,在检测来源头部这个过程中,来源域名中的主机端口将会被忽略掉 regular expression 正则表达式,~表示排除https://或http://开头的字符串.
|
两种配置案例
1 2 3 4 5 6 7 8 9 10 11 12
| # 配置案例一:限制来源只能是none、blocked、主机域名、百度、谷歌、必应
location ~* \.(gif|jpg|png|webp)$ {
valid_referers none blocked *.baidu.com *.google.com *.bing.com server_names ~\.baidu\. ~\.google\. ~\.bing\.;
if ($invalid_referer) { return 403; }
root /opt/www/image; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| # 配置案例二:屏蔽所有来自指定域名(例如搜狗)的访问
location ~* \.(gif|jpg|png|webp)$ {
valid_referers sogou.com *.sogou.com ~\.sogou\.;
# 此处必须是匹配空字符串 if ($invalid_referer = ''){ return 403; }
root /opt/www/image; }
|
测试配置是否生效
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 34 35 36
| $ curl -v -k -I --referer https://www.sogou.com https://example.com
* About to connect() to www.example.com port 443 ( * Trying www.example.com... * Connected to www.example.com (14.215.177.38) port 443 ( * Initializing NSS with certpath: sql:/etc/pki/nssdb * skipping SSL peer certificate verification * SSL connection using TLS_RSA_WITH_AES_256_CBC_SHA256 * Server certificate: * subject: CN=www.example.cn * start date: 3月 19 00:00:00 2019 GMT * expire date: 3月 18 12:00:00 2020 GMT * common name: www.example.cn * issuer: CN=TrustAsia TLS RSA CA,OU=Domain Validated SSL,O="TrustAsia Technologies, Inc.",C=CN > HEAD / HTTP/1.1 > User-Agent: curl/7.29.0 > Host: www.example.com > Accept: */* > Referer: https://www.sogou.com > < HTTP/1.1 403 Forbidden HTTP/1.1 403 Forbidden < Server: Nginx/2.2.3 Server: Nginx/2.2.3 < Date: Thu, 02 Jan 2020 23:38:13 GMT Date: Thu, 02 Jan 2020 23:38:13 GMT < Content-Type: text/html Content-Type: text/html < Content-Length: 612 Content-Length: 612 < Connection: keep-alive Connection: keep-alive
< * Connection
|
Nginx 放宽 GET 请求中 URL 的最大长度限制
client_header_buffer_size
的默认值: client_header_buffer_size 1k
large_client_header_buffers
的默认值: large_client_header_buffers 4 4k
1 2 3 4 5 6 7 8 9
| http { include mime.types; default_type application/octet-stream;
client_header_buffer_size 512k; large_client_header_buffers 4 1m;
... }
|
Nginx 反向代理响应超时解决方案
Nginx 访问出现 504 Gateway Time-out
,这一般是由于程序执行时间过长导致响应超时,例如程序需要执行 90 秒,而 Nginx 最大响应等待时间为 30 秒,这样就会出现超时。
1 2 3 4 5
| location / { proxy_connect_timeout 1800s; #Nginx跟后端服务器连接超时时间(代理连接超时) proxy_send_timeout 1800s; #后端服务器数据回传时间(代理发送超时) proxy_read_timeout 1800s; #连接成功后,后端服务器响应时间(代理接收超时) }
|
Nginx 反向代理设置响应端口
Nginx 默认反向代理后的端口为 80
,因此存在取被代理后的端口为 80
的问题,这就可能会导致业务逻辑出错;主要原因是在 Nginx 的配置文件中, 配置 Host
属性时没有设置响应的端口。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| server { listen 8080;
location /ime-server { proxy_pass http://ime-server/ime-server; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header REMOTE-HOST $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }
... }
|
在如上的配置内容中,Host
属性只配置了 $host
,没有对应的 port
,这就导致在被代理的地方取得错误的端口,以 Java 代码为例:
1 2 3 4
| String scheme = httpRequest.getScheme(); String serverName = httpRequest.getServerName(); int port = httpRequest.getServerPort(); String requestURI = scheme+"://"+serverName+":"+port+"/ime-server/rest/"+serviceName+"/wmts";
|
这时,Java 代码取得的 port
为 80
,即使 Nginx 监听的端口为 8080
。此时需要修改 Nginx 的配置文件,将 Host
属性后面的配置内容改为 $host:$server_port
,配置示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| server { listen 8080;
location /ime-server { proxy_pass http://ime-server/ime-server; proxy_set_header Host $host:$server_port; proxy_set_header X-Real-IP $remote_addr; proxy_set_header REMOTE-HOST $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }
... }
|
Nginx 反向代理指定 404 页面
Nginx 配置了反向代理后,若希望统一指定反向代理后的 404 页面,可以使用 proxy_intercept_errors
和 error_page
指令实现,更多内容可参考这里。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| http { proxy_intercept_errors on; error_page 404 /404.html;
# 或者 # error_page 404 http://cloud.example.com;
upstream www.example.com { server localhost:8080; } server { listen 80; server_name www.example.com; location / { proxy_pass http://www.example.com; index index.html index.htm; } } }
|
Nginx 关闭日志
- 关闭访问日志:
access_log off;
- 关闭错误日志:
error_log /dev/null;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| worker_processes 4;
error_log /dev/null;
...
http { include mime.types; include /usr/local/nginx-1.24.0/conf/conf.d/*.conf; default_type application/octet-stream;
access_log off;
... }
|
Nginx 443 端口绑定多个 SSL 证书
Nginx 支持 SNI(Server Name Indication),它允许客户端在发起 SSL 握手请求时提供要访问的域名。当 Nginx 为不同的域名配置不同的 SSL 证书时,它可以根据这个域名来选择合适的 SSL 证书进行处理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| server { listen 443 ssl; server_name example1.com; ssl_certificate /path/to/example1.com.crt; ssl_certificate_key /path/to/example1.com.key; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers HIGH:!aNULL:!MD5; # 其他配置... } server { listen 443 ssl; server_name example2.com; ssl_certificate /path/to/example2.com.crt; ssl_certificate_key /path/to/example2.com.key; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers HIGH:!aNULL:!MD5; # 其他配置... }
|
在上述配置示例中,Nginx 监听 443 端口,并根据不同的 server_name
来应用不同的 SSL 证书。这样,即使是在同一个 443 端口,Nginx 也能根据不同的域名提供不同的安全服务。