常用的nginx配置
前言
虽然说作为一个前端攻城师一般情况下是不会担心nginx的相关配置的,如果有运维同学的话,一般是找他们帮忙搞定这些事情的。但是小一点的公司的话可能就根本没有运维了,这时候我们就需要“自己动手,丰衣足食”了!
nginx简介
Nginx(发音同engine x)是一款由俄罗斯程序员Igor Sysoev所开发轻量级的网页服务器、反向代理服务器以及电子邮件(IMAP/POP3)代理服务器。由于其各种优势各种好(自行了解),所以很热很火🔥,基本上大大小小的公司都在使用了。
以前的前端可能不会涉及到这方面,但是由于node.js火爆之后,前端以及向所谓的“全栈”方向转移了,然后基于node.js的各种工程、工具也是越来越多。这时候前端需要的越来越多了,而nginx似乎成为了“刚需”(对自己而言),虽然不需要深入的了解nginx什么原理啊什么机制啊,但是最基础的还是需要的,最起码最起码会做一些基本的配置,满足自己的日常需要。
基础配置
首先,最基础的莫过于配置一个server,然后指向自己项目的根目录,以便能通过域名或者ip访问。下边看一个最基础版本的开发环境配置:
# nginx.conf
http {
include 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 logs/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
gzip on;
autoindex on; #文件列表
autoindex_exact_size off;
autoindex_localtime on;
# 开启ssi支持,默认是off
ssi on;
# 默认值是off,开启后在处理SSI文件出错时不输出错误提示:”[an error occurred while processing the directive] ”
ssi_silent_errors on;
# 默认是text/html,如果需要shtml支持,则需要设置:ssi_types text/shtml
ssi_types text/shtml;
expires -1;
if_modified_since off;
add_header Last-Modified "";
add_header Etag "";
add_header Access-Control-Allow-Origin *;# 允许任何域
add_header Access-Control-Allow-Headers X-Requested-With;
add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
server {
listen 80;
server_name localhost;
#access_log logs/host.access.log main;
location / {
root /git/;
index index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
server {
listen 80;
server_name fed.com;
location / {
root /git/fed/;
}
}
}
上边其实就是nginx作为基本的文件服务的基本配置,意思就是启动了两个server,一个是localhost
一个fed.com
,记得需要在本机hosts中加入127.0.0.1 fed.com
;然后在浏览器中访问localhost
的话,显示的内容就是本机的/git/
目录下的内容,而访问fed.com
的话则会显示本机/git/fed/
下的内容。
nginx是支持include语法的,所以在一般场景下,我们都会针对于不同的server_name创建不同的.conf
文件,一般情况下是在nginx配置目录下新建一个子文件夹conf.d
,然后只需要在http
配置中的最后加上include /usr/local/etc/nginx/conf.d/*.conf;
就OK了,也就是:
http {
include /path/to/nginx/conf.d/*.conf;
}
然后上边的fed.com
就可以单独拿出来了,可以把它命名为fed.com.conf
,然后再这个文件中的内容就是上边配置信息:
server {
listen 80;
server_name fed.com;
location / {
root /git/fed/;
}
}
有好多时候开发环境是需要反向代理的,这个通过nginx是很容易就做到的,如下:
server {
listen 80;
server_name dev.example.com dev2.example.com; #配置多个name
location / {
proxy_pass http://127.0.0.1:3000;
proxy_redirect off;
proxy_set_header Host $host;
# 下边俩个配置的介绍
# http://gong1208.iteye.com/blog/1559835
# http://bbs.linuxtone.org/thread-9050-1-1.html
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 10m;
}
}
在浏览器中访问dev.example.com
或者dev2.example.com
可以看到其实是代理到了本机监听3000
端口的服务上去了。
负载均衡
如果网站流量相对比较大的时候,一台server已经满足不了需求了,一般情况下我们可能需要加上负载均衡了,nginx中同样也提供了方法:
upstream back-server {
# PS: 地址瞎编的
server 123.56.67.110:8000 weight 2;
server 123.56.67.111:8000 weight=1 max_fails=2 fail_timeout=30s ;
server 123.56.67.112:8090 backup;
}
server {
listen 80;
location / {
proxy_pass http://back-server;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
}
}
简单说下上边配置的意思,nginx默认支持的调度算法是轮询
(自带的还有一个ip_hash
调度算法,按照访问ip的hash结果分配):
每个请求按时间顺序逐一分配到不同的后端服务器,如果后端某台服务器宕机,故障系统被自动剔除,使用户访问不受影响。Weight 指定轮询权值,Weight值越大,分配到的访问机率越高,主要用于后端每个服务器性能不均的情况下。
除去weight
的值,其他字段意思分别是:
-
max_fails
: 允许请求失败的次数,默认为1;超过后返回proxy_next_upstream
模块定义的错误。 -
fail_timeout
: 有两层含义,一是在指定时间内最多可以有max_fails
次失败;还有就是在max_fails
次失败后,在该指定时间内不分配请求到这台server。 -
backup
: 预留机器,当其他机器都不正常的时候就会访问到这台server了。 -
proxy_next_upstream
: 该指令属于http_proxy
模块,指定后端返回什么样的异常响应时,使用其他server
场景记
这里再简要介绍下一些场景下的配置。
支持HTML5的pushstate
这种场景很简单,就是单页面的场景,但是又希望使用的不是hash来改变浏览器地址,而是通过HTML5的pushstate
来改变地址;如果此时我们后端没有server只是静态html文件的话,一旦刷新就会404了。
在nginx中,我们通过rewrite
指令来达到我们的目的:
server {
server_name myserver.com;
location / {
root /git/myproject/;
rewrite ^/(.*)$ /index.html break;
}
}
如果说我们不希望所有的地址都rewrite到index.html,例如在项目中还有js、css等目录的时候,此时需要的就是返回对应的js、css等文件了。那么只需要稍加修改就可以了:
server {
server_name myserver.com;
location / {
root /git/myproject/;
rewrite ^/(?!js|css).*$ /index.html break;
}
}
rewrite
的语法就是:
rewrite regex replacement [flag];
可以看到后边紧跟的分别是:一个正则、符合正则的替换为的字符串值、最后是一个可省略的flag
标记。
flag
可以有如下值:
-
last
: 相当于Apache的[L]标记,表示完成rewrite,会停止rewrite检测,但是跟break有本质的不同,last的语句不一定是最终结果 -
break
: 本条规则匹配完成后,终止匹配,不再匹配后面的规则,会停止rewrite检测,也就是说当含有break flag的rewrite语句被执行时,该语句就是rewrite的最终结果 -
redirect
: 返回302临时重定向,浏览器地址会显示为跳转后的URL -
permanent
: 返回301永久重定向,浏览器地址会显示为跳转后的URL
这里比较难理解的是last
和rewrite
的区别了,这里只需要简单记住:last
一般写在server和if中,而break
则一般写在location
中就可以了。
某个path下的访问的内容需要重新定义
这里的重新定义一般包含两种情况:
-
访问到其他目录(文件服务)
-
访问其他server(一般反向代理服务)
访问到其他目录
假设访问static路径下的内容的时候,其实是希望从另一目录得到的,那么此时就需要重新配置了:
server {
listen 80;
server_name fed.com;
location / {
root /git/fed/;
}
location /static/ {
root /git/static/;
break;
}
}
上边的配置的结果就是访问fed.com/static/*
的内容的时候其实返回的是目录/git/static/static/*
的内容。
注意上边的结果是/git/static/static/*
,而不是/git/static/*
,这是很值得注意的一点。其实这也就是涉及到了root
和alias
指令的区别了,如果改成下边的:
server {
listen 80;
server_name fed.com;
location / {
root /git/fed/;
}
location /static/ {
alias /git/static/;
break;
}
}
那么访问fed.com/static/*
下的内容的话就是返回的/git/static/*
的内容了。
访问其他server
例如访问/api/
下的就统一发送到后端的接口服务上去的话,可以这样配置:
server {
listen 80;
server_name fed.com;
location / {
root /git/fed/;
}
location /api {
proxy_pass http://server.com;
proxy_set_header Host $host;
}
}
这样访问/api/*
的话就会代理到http://server.com
服务上了。
ajax跨域请求直接得到本地fake数据
server {
listen 80;
server_name fed.com;
add_header Access-Control-Allow-Origin *;# 允许任何域
add_header Access-Control-Allow-Headers X-Requested-With;
add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
location / {
root /git/fed/;
if ($request_method = OPTIONS) {
return 204;
}
}
}
注意上边除了增加了跨站资源共享的响应头之外,还判断了如果是OPTIONS
请求的话直接返回204了。如果没有的话,浏览器遇到跨域的时候首先会发一个options请求来检测支不支持跨域以及允许哪些请求方法跨域,这时由于直接使用nginx,没有启用node之类的服务,所以请求过来后nginx发现没有他自己能返回的东西,最后这个options请求就会响应为405
了。
当然网上还有一种方案,就是对所有的405错误进行处理:
server {
listen 80;
server_name fed.com;
add_header Access-Control-Allow-Origin *;# 允许任何域
add_header Access-Control-Allow-Headers X-Requested-With;
add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
location / {
root /git/fed/;
error_page 405 =200 $uri;
}
}
参考:
- http://nginx.org/en/docs/
- https://zh.wikipedia.org/wiki/Nginx
- http://tengine.taobao.org/book/index.html
- http://iqbon.iteye.com/blog/1882319
- http://segmentfault.com/a/1190000002873747
- http://gong1208.iteye.com/blog/1559835
- http://bbs.linuxtone.org/thread-9050-1-1.html
- http://segmentfault.com/a/1190000002873747
- http://saiyaren.iteye.com/blog/1914865
- http://readystate4.com/2012/05/17/nginx-and-apache-rewrite-to-support-html5-pushstate/
- «http://segmentfault.com/a/1190000002797606»
- http://blog.cafeneko.info/2010/10/nginx_rewrite_note/