nginx配置文件详解-最全-生产
nginx配置详解
这篇是目前最完整的Nginx配置参数中文说明了。
定义Nginx运行的用户和用户组
user www www;
nginx进程数,建议设置为等于CPU总核心数。
worker_processes 8;
全局错误日志定义类型,[ debug | info | notice | warn | error | crit ]
error_log /var/log/nginx/error.log info;
进程文件
pid /var/run/nginx.pid;
一个nginx进程打开的最多文件描述符数目,理论值应该是最多打开文件数(系统的值ulimit -n)与nginx进程数相除,但是nginx分配请求并不均匀,所以建议与ulimit -n的值保持一致。
worker_rlimit_nofile 65535;
工作模式与连接数上限
events
{
参考事件模型,use [ kqueue | rtsig | epoll | /dev/poll | select | poll ]; epoll模型是Linux 2.6以上版本内核中的高性能网络I/O模型,如果跑在FreeBSD上面,就用kqueue模型。
use epoll;
单个进程最大连接数(最大连接数=连接数*进程数)
worker_connections 65535;
}
设定http服务器
http
{
include mime.types; #文件扩展名与文件类型映射表
default_type application/octet-stream; #默认文件类型
charset utf-8; #默认编码
server_names_hash_bucket_size 128; #服务器名字的hash表大小
client_header_buffer_size 32k; #上传文件大小限制
large_client_header_buffers 4 64k; #设定请求缓
client_max_body_size 8m; #设定请求缓
sendfile on; #开启高效文件传输模式,sendfile指令指定nginx是否调用sendfile函数来输出文件,对于普通应用设为 on,如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络I/O处理速度,降低系统的负载。注意:如果图片显示不正常把这个改成off。
autoindex on; #开启目录列表访问,合适下载服务器,默认关闭。
tcp_nopush on; #防止网络阻塞
tcp_nodelay on; #防止网络阻塞
keepalive_timeout 120; #长连接超时时间,单位是秒
FastCGI相关参数是为了改善网站的性能:减少资源占用,提高访问速度。下面参数看字面意思都能理解。
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
fastcgi_buffer_size 64k;
fastcgi_buffers 4 64k;
fastcgi_busy_buffers_size 128k;
fastcgi_temp_file_write_size 128k;
gzip模块设置
gzip on; #开启gzip压缩输出
gzip_min_length 1k; #最小压缩文件大小
gzip_buffers 4 16k; #压缩缓冲区
gzip_http_version 1.0; #压缩版本(默认1.1,前端如果是squid2.5请使用1.0)
gzip_comp_level 2; #压缩等级
gzip_types text/plain application/x-javascript text/css application/xml;
压缩类型,默认就已经包含text/html,所以下面就不用再写了,写上去也不会有问题,但是会有一个warn。
gzip_vary on;
limit_zone crawler $binary_remote_addr 10m; #开启限制IP连接数的时候需要使用
upstream blog.ha97.com {
upstream的负载均衡,weight是权重,可以根据机器配置定义权重。weigth参数表示权值,权值越高被分配到的几率越大。
server 192.168.80.121:80 weight=3;
server 192.168.80.122:80 weight=2;
server 192.168.80.123:80 weight=3;
}
虚拟主机的配置
server
{
监听端口
listen 80;
域名可以有多个,用空格隔开
server_name www.ha97.com ha97.com;
index index.html index.htm index.php;
root /data/www/ha97;
location ~ .*.(php|php5)?$
{
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi.conf;
}
图片缓存时间设置
location ~ .*.(gif|jpg|jpeg|png|bmp|swf)$
{
expires 10d;
}
JS和CSS缓存时间设置
location ~ .*.(js|css)?$
{
expires 1h;
}
日志格式设定
log_format access ‘remoteaddr–remoteaddr–remote_user [timelocal]“timelocal]“request” ‘
‘statusstatusbody_bytes_sent “httpreferer”‘‘”httpreferer”‘‘”http_user_agent” $http_x_forwarded_for’;
定义本虚拟主机的访问日志
access_log /var/log/nginx/ha97access.log access;
对 “/” 启用反向代理
location / {
proxy_pass http://127.0.0.1:88;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
后端的Web服务器可以通过X-Forwarded-For获取用户真实IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
以下是一些反向代理的配置,可选。
proxy_set_header Host $host;
client_max_body_size 10m; #允许客户端请求的最大单文件字节数
client_body_buffer_size 128k; #缓冲区代理缓冲用户端请求的最大字节数,
proxy_connect_timeout 90; #nginx跟后端服务器连接超时时间(代理连接超时)
proxy_send_timeout 90; #后端服务器数据回传时间(代理发送超时)
proxy_read_timeout 90; #连接成功后,后端服务器响应时间(代理接收超时)
proxy_buffer_size 4k; #设置代理服务器(nginx)保存用户头信息的缓冲区大小
proxy_buffers 4 32k; #proxy_buffers缓冲区,网页平均在32k以下的设置
proxy_busy_buffers_size 64k; #高负荷下缓冲大小(proxy_buffers*2)
proxy_temp_file_write_size 64k;
设定缓存文件夹大小,大于这个值,将从upstream服务器传
}
设定查看Nginx状态的地址
location /NginxStatus {
stub_status on;
access_log on;
auth_basic “NginxStatus”;
auth_basic_user_file conf/htpasswd;
htpasswd文件的内容可以用apache提供的htpasswd工具来产生。
}
本地动静分离反向代理配置
所有jsp的页面均交由tomcat或resin处理
location ~ .(jsp|jspx|do)?{
proxy_set_header Host{ proxy_set_header Hosthost;
proxy_set_header X-Real-IP remoteaddr;proxysetheaderX−Forwarded−Forremoteaddr;proxysetheaderX−Forwarded−Forproxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:8080;
}
所有静态文件由nginx直接读取不经过tomcat或resin
location ~ .*.(htm|html|gif|jpg|jpeg|png|bmp|swf|ioc|rar|zip|txt|flv|mid|doc|ppt|pdf|xls|mp3|wma)expires15d;location .∗.(js|css)?expires15d;location .∗.(js|css)?
{ expires 1h; }
}
}
linux下通过pip安装最新uwsgi
通过yum install uwsgi 安装的uwsgi在进行测试的时候,发现版本是2.0.15,但是启动uwsgi测试的时候报参数错误,后来改用pip安装(先yum remove uwsgi删除老的uwsgi)就成功了。uwsgi安装完成之后的样子
安装pip
-
wget https://bootstrap.pypa.io/get-pip.py
-
python ./get-pip.py
安装uwsgi,一个干净的linux系统安装uwsgi过程中,会遇到以下两个错误。
-
Exception: you need a C compiler to build uWSGI
-
----------------------------------------
-
Failed building wheel for uwsgi
-
Running setup.py clean for uwsgi
-
Failed to build uwsgi
-
Installing collected packages: uwsgi
-
Running setup.py install for uwsgi ... error
解决办法:yum install gcc-*
另外一个错误:
fatal error: Python.h: No such file or directory
解决办法:yum install python-devel
安装成功的打印信息:
-
[root@VM_68_155_centos ~]# pip install uwsgi
-
Collecting uwsgi
-
Using cached uwsgi-2.0.16.tar.gz
-
Building wheels for collected packages: uwsgi
-
Running setup.py bdist_wheel for uwsgi ... done
-
Stored in directory: /root/.cache/pip/wheels/3a/e7/aa/24207bb9d885fe11fab3f7ad7d9d80c538a423d98494d43fd7
-
Successfully built uwsgi
-
Installing collected packages: uwsgi
-
Successfully installed uwsgi-2.0.16
-
[root@VM_68_155_centos ~]#
编辑一个简单的测试文件hello.py:
-
def application(env,start_response):
-
start_response( '200 OK',[('Content-Type','text/html')])
-
return "Hello,world"
启动uwsgi : uwsgi --http-socket :80 --wsgi-file hello.py
-
[root@VM_68_155_centos ~]# /usr/bin/uwsgi --http-socket :80 --wsgi-file hello.py
-
*** Starting uWSGI 2.0.16 (64bit) on [Fri Feb 23 15:31:16 2018] ***
-
compiled with version: 4.8.5 20150623 (Red Hat 4.8.5-16) on 23 February 2018 07:28:20
-
os: Linux-3.10.0-514.26.2.el7.x86_64 #1 SMP Tue Jul 4 15:04:05 UTC 2017
-
nodename: VM_68_155_centos
-
machine: x86_64
-
clock source: unix
-
detected number of CPU cores: 1
-
current working directory: /root
-
detected binary path: /usr/bin/uwsgi
-
!!! no internal routing support, rebuild with pcre support !!!
-
dropping root privileges as early as possible
-
uWSGI running as root, you can use --uid/--gid/--chroot options
-
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) ***
-
*** WARNING: you are running uWSGI without its master process manager ***
-
your processes number limit is 3895
-
your memory page size is 4096 bytes
-
detected max file descriptor number: 100001
-
lock engine: pthread robust mutexes
-
thunder lock: disabled (you can enable it with --thunder-lock)
-
uwsgi socket 0 bound to TCP address :80 fd 3
-
dropping root privileges after socket binding
-
uWSGI running as root, you can use --uid/--gid/--chroot options
-
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) ***
-
Python version: 2.7.5 (default, Aug 4 2017, 00:39:18) [GCC 4.8.5 20150623 (Red Hat 4.8.5-16)]
-
*** Python threads support is disabled. You can enable it with --enable-threads ***
-
Python main interpreter initialized at 0x7d64c0
-
dropping root privileges after plugin initialization
-
uWSGI running as root, you can use --uid/--gid/--chroot options
-
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) ***
-
your server socket listen backlog is limited to 100 connections
-
your mercy for graceful operations on workers is 60 seconds
-
mapped 72904 bytes (71 KB) for 1 cores
-
*** Operational MODE: single process ***
-
WSGI app 0 (mountpoint='') ready in 0 seconds on interpreter 0x7d64c0 pid: 6557 (default app)
-
dropping root privileges after application loading
-
uWSGI running as root, you can use --uid/--gid/--chroot options
-
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) ***
-
*** uWSGI is running in multiple interpreter mode ***
-
spawned uWSGI worker 1 (and the only) (pid: 6557, cores: 1)
测试uwsgi-server
-------------------------------------------------------------------------------------------------------------
-----------------------------------------------------------
----------------------------
|
## 二、启动停止重启
uWSGI 通过 xxx.ini 启动后会在相同目录下生成一个 xxx.pid 的文件,里面只有一行内容是 uWSGI 的主进程的进程号。
uWSGI 启动:
uwsgi --ini xxx.ini
uwsgi 重启:
uwsgi --reload xxx.pid
uwsgi 停止:
uwsgi --stop xxx.pid
----------------
前端必须知道的Nginx的常用配置
Nginx主要功能
- 负载均衡
- 反向代理
- 动静分离
- 配置https
负载均衡
负载均衡是一门计算机网络技术,主要用来优化资源使用、最大化吞吐率、最小化响应时间、同时避免过载的目的。
如果一个网站只有一台服务器的话,如果这台服务器宕机了,那么整个网站将无法正常访问。当访问网站人数过多,并发量达到一定规模,超过服务器性能的极限,整个网站也将无法访问。而负载均衡就是用来解决这一类的问题。
负载均衡是通过后端引入一个负载均衡器和至少一个额外的web服务器来缓解这类问题(增加的web服务器和原本的web服务器提供相同的内容)。用户访问的时候,先访问到负载均衡器,再通过负载均衡器将请求转发给后台服务器。
通过这种方法,当有一台服务器宕机时,负载均衡器就分配其他的服务器给用户,极大的增加的网站的稳定性。
负载均衡器主要可以转发http、https、tcp、udp四种请求规则
负载均衡器如何给用户分配服务器? 负载均衡器有多种负载均衡算法,基本就是给每台服务器一个不同的权重,通过权重来给用户分配服务器。
负载均衡不需要前端进行配置,主要是服务端进行配置,前端稍作了解即可。
反向代理
反向代理是前端经常会用到的一项功能,主要是为了解决浏览器跨域访问的问题。当协议、域名、端口号有一项或多项不同时,便违反了同源策略,需要跨域。前端跨域用的较多的有:
1.jsonp跨域: 使用html的';
这个功能其实为Nginx在前端开发中的应用提供了无限可能。例如,可以通过区分本地、测试和线上环境,为本地/测试环境页面增加很多开发辅助功能:给本地页面加一个常驻二维码便于手机端扫码调试;本地调试线上页面时,在js文件底部塞入sourceMappingURL,便于本地debug等等。
总结
上述只是通过一些简单的小例子,希望能够引起广大前端童靴对Niginx的兴趣。事实上,Nginx不仅仅局限于这些微小的工作,在实际生产中作用其实更加巨大。对于有志于“大前端”的童靴,了解和熟悉Nginx绝对是必修技能之一。
链接:https://juejin.im/post/5bacbd395188255c8d0fd4b2
--------------------------------------------------------------
快速部署Python应用:Nginx+uWSGI配置详解
在PHP里,最方便的就是deployment了,只要把php文件丢到支持PHP的路径里面,然后访问那个路径就能使用了;无论给主机添加多少PHP应用,只要把目录改好就没你的事了,完全不用关心php-cgi运行得如何,deployment极为方便。
反观Python,部属起来真是头痛,常见的部署方法有:
◆fcgi:用spawn-fcgi或者框架自带的工具对各个project分别生成监听进程,然后和http服务互动。
◆wsgi:利用http服务的mod_wsgi模块来跑各个project。
无论哪种都很麻烦,apache的mod_wsgi配置起来很麻烦,内存占用还大,如果要加上nginx作为静态页面的服务器那就更麻烦了;我的应用基本上到后来都是是各个project各自为战,且不说管理上的混乱,这样对负载也是不利的,空闲的project和繁忙的project同样需要占用内存。
如果Python中能有个什么东西像php-cgi一样监听同一端口,进行统一管理和负载平衡,那真是能省下大量的部署功夫。偶然看到了uWSGI,才发现居然一直不知道有那么方便地统一部署工具。uWSGI,既不用wsgi协议也不用fcgi协议,而是自创了一个uwsgi的协议,据说该协议大约是fcgi协议的10倍那么快,有个比较见下图:
uWSGI的主要特点如下:
◆超快的性能。
◆低内存占用(实测为apache2的mod_wsgi的一半左右)。
◆多app管理。
◆详尽的日志功能(可以用来分析app性能和瓶颈)。
◆高度可定制(内存大小限制,服务一定次数后重启等)。
正式开工
uwsgi的文档虽然很多也很详细,这里是uwsgi的官方文档:http://projects.unbit.it/uwsgi/wiki/Doc。
1.安装uwsgi
ubuntu有uwsgi的ppa:
- add-apt-repository ppa:stevecrozz/ppa
- apt-get update
- apt-get install uwsgi
2. 用uwsgi代替mod_wsgi
Nginx的整体配置说来话长,这里不再多说,假设已经明白Nginx的基本配置,那么uwsgi就类似这么配置:
- location / {
- include uwsgi_params
- uwsgi_pass 127.0.0.1:9090
- }
这就是把所有url传给9090端口的uwsgi协议程序来互动。再到project目录建立myapp.py,使得application调用框架的wsgi接口,比如web.py就是:
- ......
- app = web.application(urls, globals())
- appapplication = app.wsgifunc()
再比如django就是:
- .......
- from django.core.handlers.wsgi import WSGIHandler
- application = WSGIHandler()
然后运行uwsgi监听9090,其中-w后跟模块名,也就是刚才配置的myapp
- uwsgi -s :9090 -w myapp
运行网站发现已经部署完成了。
3.uwsgi的参数
以上是单个project的最简单化部署,uwsgi还是有很多令人称赞的功能的,例如:
并发4个线程:
- uwsgi -s :9090 -w myapp -p 4
主控制线程+4个线程:
- uwsgi -s :9090 -w myapp -M -p 4
执行超过30秒的client直接放弃:
- uwsgi -s :9090 -w myapp -M -p 4 -t 30
限制内存空间128M:
- uwsgi -s :9090 -w myapp -M -p 4 -t 30 --limit-as 128
服务超过10000个req自动respawn:
- uwsgi -s :9090 -w myapp -M -p 4 -t 30 --limit-as 128 -R 10000
后台运行等:
- uwsgi -s :9090 -w myapp -M -p 4 -t 30 --limit-as 128 -R 10000 -d uwsgi.log
4.为uwsgi配置多个站点
为了让多个站点共享一个uwsgi服务,必须把uwsgi运行成虚拟站点:去掉“-w myapp”加上”–vhost”:
- uwsgi -s :9090 -M -p 4 -t 30 --limit-as 128 -R 10000 -d uwsgi.log --vhost
然后必须配置virtualenv,virtualenv是Python的一个很有用的虚拟环境工具,这样安装:
- apt-get install Python-setuptools
- easy_install virtualenv
然后设置一个/多个app基准环境:
- virtualenv /var/www/myenv
应用环境,在此环境下安装的软件仅在此环境下有效:
- source /var/www/myenv/bin/activate
- pip install django
- pip install mako
- ...
最后配置nginx,注意每个站点必须单独占用一个server,同一server不同location定向到不同的应用不知为何总是失败,估计也算是一个bug。
- server {
- listen 80;
- server_name app1.mydomain.com;
- location / {
- include uwsgi_params;
- uwsgi_pass 127.0.0.1:9090;
- uwsgi_param UWSGI_PYHOME /var/www/myenv;
- uwsgi_param UWSGI_SCRIPT myapp1;
- uwsgi_param UWSGI_CHDIR /var/www/myappdir1;
- }
- }
- server {
- listen 80;
- server_name app2.mydomain.com;
- location / {
- include uwsgi_params;
- uwsgi_pass 127.0.0.1:9090;
- uwsgi_param UWSGI_PYHOME /var/www/myenv;
- uwsgi_param UWSGI_SCRIPT myapp2;
- uwsgi_param UWSGI_CHDIR /var/www/myappdir2;
- }
- }
这样,重启nginx服务,两个站点就可以共用一个uwsgi服务了。
5.实战应用
最初的设置完毕以后,再添加的应用,只需要在Nginx里面进行少量修改,无需重启uwsgi,就能立刻部署完毕。uwsgi自带了基于django的监控uwsgi运行状态的工具,就拿它来部署好了:
- server {
- listen 80;
- root /var/www/django1.23;
- index index.html index.htm;
- server_name uwsgiadmin.django.obmem.info;
- access_log /var/log/nginx/django.access.log;
- location /media/ {
- root /var/www/django1.23/adminmedia;
- rewrite ^/media/(.*)$ /$1 break;
- }
- location / {
- include uwsgi_params;
- uwsgi_pass 127.0.0.1:9090;
- uwsgi_param UWSGI_PYHOME /var/www/django1.23/vtenv;
- uwsgi_param UWSGI_CHDIR /var/www/django1.23/uwsgiadmin;
- uwsgi_param UWSGI_SCRIPT uwsgiadmin_wsgi;
- }
- }
于是uwsgi的监控信息可以在http://uwsgiadmin.django.obmem.info看到(用户名密码都是admin)。再比如LBForum论坛程序的部署:根据安装说明安装完毕,再按部署说明修改完配置文件,然后只需修改nginx配置文件:
- server {
- listen 80;
- root /var/www/django1.23;
- index index.html index.htm;
- server_name lbforum.django.obmem.info;
- access_log /var/log/nginx/django.access.log;
- location / {
- include uwsgi_params;
- uwsgi_pass 127.0.0.1:9090;
- uwsgi_param UWSGI_PYHOME /var/www/django1.23/vtenv;
- uwsgi_param UWSGI_CHDIR /var/www/django1.23/LBForum/sites/default;
- uwsgi_param UWSGI_SCRIPT lbforum_wsgi;
- }
- }
于是http://lbforum.django.obmem.info就是论坛程序了。
后记
虽然写出来寥寥几行,配置的时候我可吃尽了uwsgi的苦头,有些想当然的用法完全不能成立,–no-site参数一加上去其他都好使LBForum怎么都部署不了,一开始多站点公用uwsgi怎么都成功不了等等。
Python世界很有趣,一直会发现有趣的东西,但是Python世界也很折腾人,大部分东西都是dev版本,文档缺失,各种兼容问题。
原文地址:http://obmem.info/?p=703
-------------------
nginx
#运行用户
user nobody;
#启动进程,通常设置成和cpu的数量相等
worker_processes 1;
#全局错误日志及PID文件
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
#工作模式及连接数上限
events {
#epoll是多路复用IO(I/O Multiplexing)中的一种方式,
#仅用于linux2.6以上内核,可以大大提高nginx的性能
use epoll;
#单个后台worker process进程的最大并发链接数
worker_connections 1024;
# 并发总数是 worker_processes 和 worker_connections 的乘积
# 即 max_clients = worker_processes * worker_connections
# 在设置了反向代理的情况下,max_clients = worker_processes * worker_connections / 4 为什么
# 为什么上面反向代理要除以4,应该说是一个经验值
# 根据以上条件,正常情况下的Nginx Server可以应付的最大连接数为:4 * 8000 = 32000
# worker_connections 值的设置跟物理内存大小有关
# 因为并发受IO约束,max_clients的值须小于系统可以打开的最大文件数
# 而系统可以打开的最大文件数和内存大小成正比,一般1GB内存的机器上可以打开的文件数大约是10万左右
# 我们来看看360M内存的VPS可以打开的文件句柄数是多少:
# $ cat /proc/sys/fs/file-max
# 输出 34336
# 32000 < 34336,即并发连接总数小于系统可以打开的文件句柄总数,这样就在操作系统可以承受的范围之内
# 所以,worker_connections 的值需根据 worker_processes 进程数目和系统可以打开的最大文件总数进行适当地进行设置
# 使得并发总数小于操作系统可以打开的最大文件数目
# 其实质也就是根据主机的物理CPU和内存进行配置
# 当然,理论上的并发总数可能会和实际有所偏差,因为主机还有其他的工作进程需要消耗系统资源。
# ulimit -SHn 65535
}
http {
#设定mime类型,类型由mime.type文件定义
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 指令指定 nginx 是否调用 sendfile 函数(zero copy 方式)来输出文件,
#对于普通应用,必须设为 on,
#如果用来进行下载等应用磁盘IO重负载应用,可设置为 off,
#以平衡磁盘与网络I/O处理速度,降低系统的uptime.
sendfile on;
#tcp_nopush on;
#连接超时时间
#keepalive_timeout 0;
keepalive_timeout 65;
tcp_nodelay on;
#开启gzip压缩
gzip on;
gzip_disable "MSIE [1-6].";
#设定请求缓冲
client_header_buffer_size 128k;
large_client_header_buffers 4 128k;
#设定虚拟主机配置
server {
#侦听80端口
listen 80;
#定义使用 www.nginx.cn访问
server_name www.nginx.cn;
#定义服务器的默认网站根目录位置
root html;
#设定本虚拟主机的访问日志
access_log logs/nginx.access.log main;
#默认请求
location / {
#定义首页索引文件的名称
index index.php index.html index.htm;
}
# 定义错误提示页面
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
#静态文件,nginx自己处理
location ~ ^/(images|javascript|js|css|flash|media|static)/ {
#过期30天,静态文件不怎么更新,过期可以设大一点,
#如果频繁更新,则可以设置得小一点。
expires 30d;
}
#PHP 脚本请求全部转发到 FastCGI处理. 使用FastCGI默认配置.
location ~ .php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
#禁止访问 .htxxx 文件
location ~ /.ht {
deny all;
}
}
}
------------------------------------------------------------
---------------------------
ginx静态资源文件无法访问,403 forbidden错误
博客分类:- nginx
----------------------------------
前端开发者必备的Nginx知识及应用
Nginx
是一款自由的、开源的、高性能的HTTP服务器和反向代理服务器;同时也是一个IMAP
、POP3
、SMTP
代理服务器;Nginx
可以作为一个HTTP
服务器进行网站的发布处理,另外Nginx
可以作为反向代理进行负载均衡的实现。
Nginx
现在几乎是众多大型网站的必用技术,大多数情况下,我们不需要去详细的配置它,但是了解它在应用程序中所担当的角色,以及如何解决这些问题是非常有必要的。下面就从基本概念开始介绍:
正向代理与反向代理
代理是在服务器和客户端之间架设的一层服务器,代理将接收客户端的请求并将它转发给服务器,然后将服务器的响应转发给客户端。
不管是正向代理还是反向代理,实现的都是上面的功能。
正向代理
位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并制定目标(原始服务器),然后代理向原始服务器 转交请求并将获得的内容返回给客户端。
正向代理是为客户端服务的,客户端可以根据正向代理访问到它本身无法访问到的服务器资源。
正向代理对客户端是透明的,对服务端是非透明的,即服务端并不知道自己接收到的是来自代理的访问还是来自真实客户端的访问。
反向代理
反向代理(
Reverse Proxy
)方式是值以代理服务器来接收连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到结构返回给请求连接的客户端,此时代理服务器对外表现为一个反向代理服务器。
反向代理是为服务端服务的,反向代理可以帮助服务器接收来自客户端的请求,帮助服务器做请求的转发、负载均衡等。
反向代理对服务端是透明的,对客户端是非透明的,即客户端并不知道自己访问的是代理服务器,而服务器知道反向代理在为它服务。
基本配置
配置结构
events {
}
http
{
server
{
location path
{
...
}
location path
{
...
}
}
server
{
...
}
}
main
: Nginx的全局配置,对全局生效。events
: 配置影响Nginx服务器或与用户的网络连接。http
: 可以嵌套多个server
,配置代理、缓存、日志等绝大多数功能和第三方模块的配置。server
: 配置虚拟主机的相关参数,一个http
中可以有多个server
。location
: 配置请求的路由,以及各种页面的处理情况。upstream
: 配置后端服务器的具体地址,负载均衡不可或缺的部分。
常用内置变量
下面是Nginx
一些配置中的内置全局变量,你可以在配置的任意位置使用它们。
变量名 | 功能 |
---|---|
$host |
请求信息中的Host ,如果请求中没有Host 行,则等于设置的服务器名 |
$request_method |
客户端请求类型,如GET 、POST 等 |
$remote_addr |
客户端的IP 地址 |
$remote_port |
客户端的端口 |
$args |
请求中的参数 |
$content_length |
请求头中的Content-length 字段 |
$http_user_agent |
客户端User-Agent 信息 |
$http_cookie |
客户端的cookie 信息 |
$server_protocol |
请求使用的协议,如HTTP/1.0 、HTTP/1.1 |
$server_addr |
服务器地址 |
$server_name |
服务器名称 |
$server_port |
服务器端口号 |
前端可以用Nginx做些什么
解决跨域
跨域定义
跨域指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript
施加的安全限制。
同源定义
如果两个页面的协议、端口、域名都相同,则这两个页面同源。
URL | 结构 | 原因 |
---|---|---|
http://clearlove.com/dir/a.html | 成功 | |
http://clearlove.com/dir2/b.html | 成功 | |
https://clearlove.com/dir/a.html | 失败 | 不同协议(http和https) |
http://clearlove.com:81/dir/a.html | 失败 | 不同端口(80和81) |
http://meiko.com/dir/a.html | 失败 | 不同域名(clearlove和meiko) |
Nginx解决跨域的原理
例如:
- 前端server的域名为:fe.server.com
- 后端服务的域名为:dev.server.com
现在在fe.server.com
对dev.server.com
发起请求一定会出现跨域。
现在我们只需要启动一个Nginx服务器,将server_name
设置为fe.server.com
,然后设置相应的location
以拦截前端需要跨域的请求,最后将请求代理回dev.server.com
。如下面的配置:
server {
listen 80;
server_name fe.server.com;
location / {
proxy_pass dev.server.com;
}
}
这样可以完美绕过浏览器的同源策略:fe.server.com
访问Nginx
的fe.server.com
属于同源访问,而Nginx
对服务端转发的请求不会触发浏览器的同源策略。
请求过滤
根据状态码过滤
error_page 500 501 502 503 504 506 /50x.html; location = /50x.html { #将根路径改为存放html的路径。 root /root/static/html; }
根据请求类型过滤
if ( $request_method !~ ^(GET|POST|HEAD)$ ) {
return 403;
}
其他
可以根据URL
、文件请求类型
等进行过滤。
配置gzip
gzip
是规定的三种标准HTTP
压缩格式之一。目前绝大多数的网站都在使用gzip
传输 HTML
、CSS
、JavaScript
等资源文件。
对于文本文件,gzip
的效果非常明显,开启后传输所需流量大约会降至 1/4 ~ 1/3。
并不是每个浏览器都支持gzip
的,如何知道客户端是否支持gzip
呢,请求头中的Accept-Encoding
来标识对压缩的支持。
启用gzip
同时需要客户端和服务端的支持,如果客户端支持gzip
的解析,那么只要服务端能够返回gzip
的文件就可以启用gzip
了,我们可以通过Nginx
的配置来让服务端支持gzip
。下面的respone
中Content-Encoding: gzip
,指服务端开启了gzip
的压缩方式。
gzip on;
gzip_http_version 1.1;
gzip_comp_level 5;
gzip_min_length 1000;
gzip_types text/csv text/xml text/css text/plain text/javascript application/javascript application/x-javascript application/json application/xml;
gzip
- 开启或者关闭
gzip
模块 - 默认值为
off
- 可配置为
on
/off
gzip_http_version
- 启用
gZip
所需的HTTP
最低版本 - 默认值为
HTTP/1.1
这里为什么默认版本不是1.0
呢?
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
。
gzip_comp_level
- 压缩级别,级别越高压缩率越大,当然压缩时间也就越长(传输快但比较消耗cpu)。
- 默认值:
1
- 压缩级别取值:
1-9
gzip_min_length
- 设置允许压缩的页面最小字节数,
Content-Length
小于该值的请求将不会被压缩。 - 默认值:
0
- 当设置的值较小时,压缩后的长度可能比原文件大,建议设置
1000
以上
gzip_types
- 要采用gzip压缩的文件类型(
MIME
类型) - 默认值:
text/html
(默认不压缩js/css
)
负载均衡
Nginx如何实现负载均衡
upstream
指定后端服务器地址列表
upstream balanceServer {
server 10.1.22.33:12345;
server 10.1.22.34:12345; server 10.1.22.35:12345; }
在server
中拦截响应请求,并将请求转发到upstream
中配置的服务器列表。
server {
server_name fe.server.com;
listen 80;
location /api {
proxy_pass http://balanceServer;
}
}
上面的配置只是指定了Nginx
需要转发的服务端列表,并没有指定分配策略。
Nginx实现负载均衡的策略
轮询策略
默认情况下采用的策略,将所有客户端请求轮询分配给服务端。这种策略是可以正常工作的,但是如果其中某一台服务器压力太大,出现延迟,会影响所有分配在这台服务器下的用户。
upstream balanceServer {
server 10.1.22.33:12345;
server 10.1.22.34:12345; server 10.1.22.35:12345; }
最小连接数策略
将请求优先分配给压力较小的服务器,它可以平衡每个队列的长度,并避免向压力大的服务器添加更多的请求。
upstream balanceServer {
least_conn;
server 10.1.22.33:12345;
server 10.1.22.34:12345; server 10.1.22.35:12345; }
最快响应时间策略
依赖于Nginx Plus,优先分配给响应时间最短的服务器。
upstream balanceServer {
fair;
server 10.1.22.33:12345;
server 10.1.22.34:12345; server 10.1.22.35:12345; }
客户端IP绑定
来自同一个IP
的请求永远只分配一台服务器,有效解决了动态网页存在的session
共享问题。
upstream balanceServer {
ip_hash;
server 10.1.22.33:12345;
server 10.1.22.34:12345; server 10.1.22.35:12345; }
负载均衡服务器配置参数
Nginx实现负载均衡的策略中,每一台服务器后面都可以携带的参数有:
down
: 当前服务器不参与负载均衡。weight
: 权重,值越大,服务器的负载量就越大。max_fails
: 允许请求失败的次数,默认为1。fail_timeout
:max_fails
次失败后暂停的时间。backup
: 备份机,只有其它所有的非backup
机器down
或者忙时才会请求backup
机器。
如下面的配置是指:负载中有三台服务器,当请求到达时,nginx按时间顺序和权重把请求分配给三台服务器处理,例如有100个请求,有30%是服务器33处理,有50%的请求是服务器34处理,有20%的请求是服务器35处理。
upstream balanceServer {
server 10.1.22.33:12345 weight=30;
server 10.1.22.34:12345 weight=50; server 10.1.22.35:12345 weight=20; }
如下面的配置是指:负载中有三台服务器,服务器33的失败超时时间为60s,服务器34暂不参与负载,服务器35只用作备份机。
upstream balanceServer {
server 10.1.22.33:12345 fail_timeout=60s;
server 10.1.22.34:12345 down; server 10.1.22.35:12345 backup; }
静态资源服务器
location ~* \.(png|gif|jpg|jpeg)$ {
root /root/static/;
autoindex on;
access_log off;
expires 10h;# 设置过期时间为10小时
}
匹配以png|gif|jpg|jpeg
为结尾的请求,并将请求转发到本地路径,root
中指定的路径即Nginx
本地路径。同时也可以进行一些缓存的设置。
访问限制
经常会遇到希望网站让某些特定用户的群体(比如只让公司内网)访问,或者控制某个url不让人访问。配置如下:
location / {
deny 192.168.1.100;
allow 192.168.1.10/200;
allow 10.110.50.16;
deny all;
}
其实deny
和allow
是ngx_http_access_module
模块(已内置)中的语法。采用的是从上到下匹配方式,匹配到就跳出不再继续匹配。
上述配置的意思就是,首先禁止192.168.1.100访问,然后允许192.168.1.10-200 ip段内的访问(排除192.168.1.100),同时允许10.110.50.16这个单独ip的访问,剩下未匹配到的全部禁止访问。实际生产中,经常和ngx_http_geo_module
模块(可以更好地管理ip地址表,已内置)配合使用。
适配PC与移动环境
现在很多网站都存在PC站和H5站两个站点,因此根据用户的浏览环境自动切换站点是很常见的需求。
Nginx
可以通过内置变量$http_user_agent
,获取到请求客户端的userAgent
,从而知道用户处于移动端还是PC,进而控制重定向到H5站还是PC站。比如,PC端站点是mysite.com,H5端是mysite-H5.com。配置如下:
location / {
# 移动、pc设备适配
if ($http_user_agent ~* '(Android|webOS|iPhone|iPod|BlackBerry)') {
set $mobile_request '1';
}
if ($mobile_request = '1') {
rewrite ^.+ http://mysite-H5.com;
}
}
总结
上述只是通过一些简单的应用,希望能够引起广大前端童靴对Niginx
的兴趣。事实上,Nginx
不仅仅局限于这些微小的工作,在实际生产中作用其实更加巨大。对于有志于“大前端”的童靴,了解和熟悉Nginx
绝对是必修技能之一。
https://segmentfault.com/a/1190000020290454
------------------------------------------------------------
-----------------------2019-09-24--------------------
使用 Nginx 部署前后端分离项目,解决跨域问题
前后端分离这个问题其实松哥和大家聊过很多了,上周松哥把自己的两个开源项目部署在服务器上以帮助大家可以快速在线预览(喜大普奔,两个开源的 Spring Boot + Vue 前后端分离项目可以在线体验了),然后群里就有小伙伴想让松哥来聊聊如何结合 Nginx 来部署前后端分离项目?今天我们就来聊一聊这个话题。
不得不说的跨域
很多人对前后端分离部署感到困惑,其实主要是困惑跨域问题怎么解决。因为前后端分离项目在开发的时候,前端通过 nodejs 来运行,需要一个单独的端口,后端通过 Tomcat 或者 Jetty 来运行,也需要端口,两个不同的端口,就造成了跨域。
但是松哥之前多次和大家聊过这个问题,这种跨域并不是我们传统开发中真正的跨域,这个所谓的跨域只在开发环境中存在,生产环境下就不存在这个跨域问题了。所以我们不能按照以往的通过 JSONP 或者 CORS 之类的手段来解决这个跨域问题。
前后端分离开发中,前端为了能够模拟出测试数据,并且模拟出请求,一般需要借助于 nodejs 来运行,这是开发时候的状态,开发时候的配置大家可以参考这篇文章:
- 前后端分离历险记
等开发完成后,我们会对前端项目编译打包,编译打包完成之后,就只剩下一堆 js、css 以及 html 文件了,我们把这些编译打包后的文件拷贝到后端项目中,这样再去运行就不存在跨域问题了(例如将编译打包后的静态文件拷贝到 Spring Boot 项目的 src/main/resources/static
目录下)。这种方式我就不再多说了,相信大家都会,今天咱们主要来看看如何结合 Nginx 来部署。
Nginx 大杀器
结合 Nginx 来部署前后端分离项目算是目前的主流方案。一来部署方便,二来通过动静分离也可以有效提高项目的运行效率。
大家知道我们项目中的资源包含动态资源和静态资源两种,其中:
- 动态资源就是那些需要经过容器处理的资源,例如 jsp、freemarker、各种接口等。
- 静态资源则是那些不需要经过容器处理,收到客户端请求就可以直接返回的资源,像 js、css、html 以及各种格式的图片,都属于静态资源。
将动静资源分开部署,可以有效提高静态资源的加载速度以及整个系统的运行效率。
在前后端分离项目部署中,我们用 Nginx 来做一个反向代理服务器,它既可以代理动态请求,也可以直接提供静态资源访问。我们来一起看下。建议大家先阅读松哥以前关于 Nginx 的一篇旧文,可以有效帮助大家理解后面的配置:
- Nginx 极简入门教程!
后端部署
后端接口的部署,主要看项目的形式,如果就是普通的 SSM 项目,那就提前准备好 Tomcat ,在 Tomcat 中部署项目,如果是 Spring Boot 项目,可以通过命令直接启动 jar,如果是微服务项目,存在多个 jar 的话,可以结合 Docker 来部署(参考一键部署 Spring Boot 到远程 Docker 容器),无论是那种形式,对于我们 Java 工程师来说,这都不是问题,我相信这一步大家都能搞定。
后端项目可以在一个非 80 端口上部署,部署成功之后,因为这个后端项目只是提供接口,所以我们并不会直接去访问他。而是通过 Nginx 请求转发来访问这个后端接口。
松哥这里以我去年为一个律所的小程序为例,后端是一个 Spring Boot 工程,那么我可以通过 Docker 部署,也可以直接通过命令来启动,这里简单点,直接通过命令来启动 jar ,如下:
nohup java -jar jinlu.jar > vhr.log &
后端启动成功之后,我并不急着直接去访问后端,而是安装并且去配置一个 Nginx,通过 Nginx 来转发请求,Nginx 的基本介绍与安装,大家可以参考(Nginx 极简入门教程!),我这里就直接来说相关的配置了。
这里我们在 nginx.conf 中做出如下配置:
首先配置上游服务器:
upstream zqq.com{
server 127.0.0.1:9999 weight=2;
}
在这里主要是配置服务端的地址,如果服务端是集群化部署,那么这里就会有多个服务端地址,然后可以通过权重或者 ip hash 等方式进行请求分发。
然后我们在 server 中配置转发规则:
location /jinlu/ {
proxy_pass http://zqq.com;
tcp_nodelay on;
proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }
这样配置完成后,假设我目前的域名是 javaboy.org,那么用户通过 http://www.javaboy.org/jinlu/**
格式的地址就可以访问到我服务端的接口。
前端部署
以 Vue 为例,如果是 SPA 应用,项目打包之后,就是一个 index.html 还有几个 js、css、images 以及 fonts ,这些都是静态文件,我们将静态文件首先上传到服务器,然后在 nginx.conf 中配置静态资源访问,具体配置如下:
location ~ .*\.(js|css|ico|png|jpg|eot|svg|ttf|woff|html|txt|pdf|) { root /usr/local/nginx/html/;#所有静态文件直接读取硬盘 expires 30d; #缓存30天 }
当然我这里是按照资源类型来拦截的,即后缀为 js、css、ico 等的文件,统统都不进行请求分发,直接从本地的 /usr/local/nginx/html/ 目录下读取并返回到前端(我们需要将静态资源文件上传到 /usr/local/nginx/html/
目录下)。
如果我们的服务器上部署了多个项目,这种写法就不太合适,因为多个项目的前端静态文件肯定要分门别类,各自放好的,这个时候我们一样可以通过路径来拦截,配置如下:
location /jinlu-admin/ {
root /usr/local/nginx/html/jinlu-admin/;#所有静态文件直接读取硬盘
expires 30d; #缓存30天 }
这样,请求路径是 /jinlu-admin/ 格式的请求,则不会进行请求分发,而是直接从本机的 /usr/local/nginx/html/jinlu-admin/
目录下返回相关资源。采用这方方式配置静态资源,我们就可以部署多个项目了,多个项目的部署方式和上面的一样。
这样部署完成之后,假设我的域名是 javaboy.org ,那么用户通过 http://www.javaboy.org/jinlu-admin/**
格式的请求就可以访问到前端资源了。
此时大家发现,前端的静态资源和后端的接口现在处于同一个域之中了,这样就不存在跨域问题,所以我一开始基说不必用 JSONP 或者 CORS 去解决跨域。特殊情况可能需要在 nginx 中配置跨域,这个松哥以后再和大家细聊~
好了,不知道小伙伴有没有看懂呢?有问题欢迎留言讨论。