server {listen 80;server_name static.mrsingsing.com;charset utf-8; # 防止中文文件名乱码location /download {alias /usr/share/nginx/html/static; # 静态资源目录autoindex on; # 开启静态资源列目录autoindex_exact_size off; # on(默认)显示文件的确切大小,单位是byte;off显示文件大概大小,单位KB、MB、GBautoindex_localtime off; # off(默认)时显示的文件时间为GMT时间;on显示的文件时间为服务器时间}}
server {listen 80;server_name *.mrsingsing.com;# 图片防盗链location ~* \.(gif|jpg|jpeg|png|bmp|swf)$ {# 只允许本机 IP 外链引用,将百度和谷歌也加入白名单,有利于 SEOvalid_referers none blocked server_names ~\.google\. ~\.baidu\. *.qq.com;if ($invalid_referer){return 403;}}}
deny
和 allow
是 ngx_http_access_module
模块中的语法。在实际生产中,经常和 ngx_http_geo_module
模块配合使用。
location / {# 禁止访问deny 192.168.1.100;# 允许 IP 段访问(已排除 100)allow 192.168.1.10/200;# 允许该单独 IP 访问allow 10.110.50.16;# 剩下未匹配到的全部禁止访问deny all;}
由于图片、字体、音频、视频等静态文件在打包的时候通常会增加了 hash
,所以缓存可以设置的长一点,先设置强制缓存,再设置协商缓存;如果存在没有 hash
值的静态文件,建议不设置强制缓存,仅通过协商缓存判断是否需要使用缓存。
# 图片缓存时间设置location ~ .*\.(css|js|jpg|png|gif|swf|woff|woff2|eot|svg|ttf|otf|mp3|m4a|aac|txt)$ {expires 10d;}# 如果不希望缓存expires -1;
server {listen 80;server_name mrsingsing.com;location / {# vue 打包后的文件夹root /usr/share/nginx/html/vue-/dist;index index.html index.htm;# 解决页面刷新 404 问题try_files $uri $uri/ /index.html @rewrites;# 首页一般没有强制缓存expires -1;add_header Cache-Control no-cache;}# 接口转发给后端处理location ~ ^/api {proxy_pass http://api.mrsingsing.com;}location @rewrites {rewrite ^(.+)$ /index.html break;}}
配置完 HTTPS 后,浏览器还是可以访问 HTTP 的地址 http://mrsingsing.com/
的,可以做一个 301
跳转,把对应域名的 HTTP 请求重定向到 HTTPS 上。
server {listen 80;server_name www.mrsingsing.com;# 单域名重定向if ($host = 'www.mrsingsing.com'){return 301 https://www.mrsingsing.com$request_uri;}# 全局非 HTTPS 协议时重定向if ($scheme != 'https') {return 301 https://$server_name$request_uri;}# 或者全部重定向return 301 https://$server_name$request_uri;# 以上配置选择自己需要的即可,不用全部加}
有时候我们可能需要配置一些二级或者三级域名,希望通过 Nginx 自动指向对应目录。例如:
test.mrsingsing.com
自动指向 /usr/share/nginx/html/doc/test
服务器地址pre.mrsingsing.com
自动指向 /usr/share/nginx/html/doc/pre
服务器地址server {listen 80;server_name ~^([\w-]+)\.mrsingsing\.com$;root /usr/share/nginx/html/doc/$1;}
和之前的功能类似,有时候我们希望把二级或者三级域名链接重写到我们希望的路径,让后端就可以根据路由解析不同的规则:
test.mrsingsing.com/api?id=1
自动转发到 127.0.0.1:8080/test/api?id=1
pre.mrsingsing.com/api?id=1
自动转发到 127.0.0.1:8080/pre/api?id=1
server {listen 80;server_name ~^([\w-]+)\.mrsingsing\.com$;location / {proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header Host $http_host;proxy_set_header X-NginX-Proxy true;proxy_pass http://127.0.0.1:8080/$1$request_uri;}}
通过 nginx-http-concat
模块(淘宝开发的第三方模块,需单独安装)用一种特殊的请求 URL 规则(例如:https://www.example.com/??a.js,b.js,c.js
),前端可将多个资源请求合并成一个请求,服务端 Nginx 会获取各个资源并拼接成一个结果进行返回。
# JavaScript 资源 http-concat# nginx-http-concat 模块的参数远不止下面三个,剩下的请查阅文档location /static/js/ {# 是否打开资源合并开关concat on;# 允许合并的资源类型concat_types application/javascript;# 是否允许合并不同类型的资源concat_unique off;# 允许合并的最大资源数目concat_max_files 5;}
Nginx 可以通过向页面底部或者顶部插入额外的 CSS 和 JS 文件,从而实现修改页面内容。这个功能需要额外模块的支持,例如:nginx_http_footer_filter
或者 ngx_http_addition_module
(都需要安装)。
工作中,经常需要切换各种测试环境,而通过 switchhosts
等工具切换后,有时还需要清理浏览器 DNS 缓存。可以通过 页面内容修改 + Nginx 反向代理
来实现轻松快捷的环境切换。
这里首先在本地编写一段 JavaScript 代码(switchhost.js
),里面的逻辑是:在页面插入 hosts 切换菜单以及点击具体某个环境时,将该 host
的 IP 和 hostname
储存在 Cookie 中,最后刷新页面;接着编写一段 CSS 代码(switchhost.css
)用来设置该 hosts
切换菜单的样式。
然后 Nginx 脚本配置:
server {listen 80;listen 443 ssl;expires -1;# 想要代理的域名server_name m-element.kaola.com;set $root /Users/cc/Desktop/server;charset utf-8;ssl_certificate /usr/local/etc/nginx/m-element.kaola.com.crt;ssl_certificate_key /usr/local/etc/nginx/m-element.kaola.com.key;# 设置默认 $switch_host,一般默认为线上 host,这里的 1.1.1.1 随便写的set $switch_host '1.1.1.1';# 设置默认 $switch_hostname,一般默认为线上 'online'set $switch_hostname '';# 从 Cookie 中获取环境 IPif ($http_cookie ~* "switch_host=(.+?)(?=;|$)") {set $switch_host $1;}# 从 Cookie 中获取环境名if ($http_cookie ~* "switch_hostname=(.+?)(?=;|$)") {set $switch_hostname $1;}location / {expires -1;index index.html;proxy_set_header Host $host;# 把 HTML 页面的 gzip 压缩去掉,不然 sub_filter 无法替换内容proxy_set_header Accept-Encoding '';# 反向代理到实际服务器 IPproxy_pass http://$switch_host:80;# 全部替换sub_filter_once off;# ngx_http_addition_module 模块替换内容。# 这里在头部插入一段 CSS,内容是 hosts 切换菜单的 CSS 样式sub_filter '</head>' '</head><link rel="stylesheet" type="text/css" media="screen" href="/local/switchhost.css" />';# 将页面中的'网易考拉'文字后面加上环境名,便于开发识别目前环境sub_filter '网易考拉' '网易考拉:${switch_hostname}';# 这里用了另一个模块nginx_http_footer_filter,其实上面的模块就行,只是为了展示用法# 最后插入一段js,内容是hosts切换菜单的js逻辑set $injected '<script language="javascript" src="/local/switchhost.js"></script>';footer '${injected}';}# 对于/local/请求,优先匹配本地文件# 所以上面的/local/switchhost.css,/local/switchhost.js会从本地获取location ^~ /local/ {root $root;}}
动静分离就是把动态和静态的请求分开。方式主要有两种:一种 是纯粹把静态文件独立成单独的域名,放在独立的服务器上,也是目前主流推崇的方案。另外一种方法就是动态跟静态文件混合在一起发布, 通过 Nginx 配置来分开。
upstream static {server 192.167.4.31:80;}upstream dynamic {server 192.167.4.32:8080;}server {listen 80; #监听端口server_name www.mrsingsing.com; 监听地址# 拦截动态资源location ~ .*\.(php|jsp)$ {proxy_pass http://dynamic;}# 拦截静态资源location ~ .*\.(jpg|png|htm|html|css|js)$ {root /data/; #html目录proxy_pass http://static;autoindex on;; #自动打开文件列表}}
当主 Nginx 服务器宕机之后,切换到备份 Nginx 服务器
安装 keepalived
yum install keepalived -y
然后编辑 /etc/keepalived/keepalived.conf
配置文件,并在配置文件中增加 vrrp_script
定义一个外围检测机制,并在 vrrp_instance
中通过定义 track_script
来追踪脚本执行过程,实现节点转移:
global_defs{notification_email {acassen@firewall.loc}notification_email_from Alexandre@firewall.locsmtp_server 127.0.0.1smtp_connect_timeout 30 # 上面都是邮件配置,没卵用router_id LVS_DEVEL # 当前服务器名字,用 hostname 命令来查看}vrrp_script chk_maintainace { # 检测机制的脚本名称为 chk_maintainacescript "[[ -e/etc/keepalived/down ]] && exit 1 || exit 0" # 可以是脚本路径或脚本命令# script "/etc/keepalived/nginx_check.sh" # 比如这样的脚本路径interval 2 # 每隔 2 秒检测一次weight -20 # 当脚本执行成立,那么把当前服务器优先级改为-20}vrrp_instanceVI_1 { # 每一个 vrrp_instance 就是定义一个虚拟路由器state MASTER # 主机为 MASTER,备用机为 BACKUPinterface eth0 # 网卡名字,可以从 ifconfig 中查找virtual_router_id 51 # 虚拟路由的 id 号,一般小于 255,主备机 id 需要一样priority 100 # 优先级,master 的优先级比 backup 的大advert_int 1 # 默认心跳间隔authentication { # 认证机制auth_type PASSauth_pass 1111 # 密码}virtual_ipaddress { # 虚拟地址 vip172.16.2.8}}
其中检测脚本 nginx_check.sh,这里提供一个:
#!/bin/bashA=`ps -C nginx --no-header | wc -l`if [ $A -eq 0 ];then/usr/sbin/nginx # 尝试重新启动nginxsleep 2 # 睡眠2秒if [ `ps -C nginx --no-header | wc -l` -eq 0 ];thenkillall keepalived # 启动失败,将keepalived服务杀死。将vip漂移到其它备份节点fifi
复制一份到备份服务器,备份 Nginx 的配置要将 state
后改为 BACKUP
,priority
改为比主机小。设置完毕后各自 service keepalived start
启动,经过访问成功之后,可以把 Master
机的 keepalived
停掉,此时 Master
机就不再是主机了 service keepalived stop
,看访问虚拟 IP 时是否能够自动切换到备机 ip addr
。再次启动 Master
的 keepalived
,此时 vip
又变到了主机上。
根据用户设备不同返回不同样式的站点,以前经常使用的是纯前端的自适应布局,但无论是复杂性和易用性上面还是不如分开编写的好,比如我们常见的淘宝、京东......这些大型网站就都没有采用自适应,而是用分开制作的方式,根据用户请求的 user-agent
来判断是返回 PC 还是 H5 站点。
server {listen 80;server_name mrsingsing.com;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;}}
HTTP 运行在 TCP 连接之上,自然也有着跟 TCP 一样的三次握手、慢启动等特性。
启用持久连接情况下,服务器发出响应后让 TCP 连接继续打开着。同一对客户/服务器之间的后续请求和响应可以通过这个连接发送。
为了尽可能的提高 HTTP 性能,使用持久连接就显得尤为重要了。
HTTP/1.1 默认支持 TCP 持久连接,HTTP/1.0 也可以通过显式指定 Connection: keep-alive 来启用持久连接。对于 TCP 持久连接上的 HTTP 报文,客户端需要一种机制来准确判断结束位置,而在 HTTP/1.0 中,这种机制只有 Content-Length。而在 HTTP/1.1 中新增的 Transfer-Encoding: chunked 所对应的分块传输机制可以完美解决这类问题。
nginx 同样有着配置 chunked 的属性 chunked_transfer_encoding,这个属性是默认开启的。
Nginx 在启用了 GZip 的情况下,不会等文件 GZip 完成再返回响应,而是边压缩边响应,这样可以显著提高 TTFB(Time To First Byte,首字节时间,WEB 性能优化重要指标)。这样唯一的问题是,Nginx 开始返回响应时,它无法知道将要传输的文件最终有多大,也就是无法给出 Content-Length 这个响应头部。
所以,在 HTTP1.0 中如果利用 Nginx 启用了 GZip,是无法获得 Content-Length 的,这导致 HTTP1.0 中开启持久链接和使用 GZip 只能二选一,所以在这里 gzip_http_version 默认设置为 1.1。
参考资料: