nginx配置技巧汇总
本文记录了一些nginx作为反向代理和文件服务器的配置技巧和解决方案,原文会持续更新
Nginx作为文件服务
避免浏览器自动播放文件
有时对于图片、视频,浏览器会视能力,自动为用户显示或播放。这主要是由于Web服务器在返回文件本身数据的同时,返回了一些特殊的MIME类型,比如:image/jpeg
(JPEG图像),application/pdf
(PDF文档),video/mpeg
(MPEG动画)。这些MIMIE类型实际上是告诉浏览器,文件数据到底是什么,这样浏览器就能更好的为用户展示数据。现在像图片、pdf、甚至是视频基本都是可以直接在浏览器中展示和播放的。但是有时,我们需要浏览器为用户下载文件而不是直接播放,而Nginx在默认配置下,会根据文件的后缀来匹配相应的MIME类型,并写入Response header,导致浏览器播放文件而不是下载,这时需要通过配置让Nginx返回的MIME类型为下面这个类型:
application/octet-stream
这个类型会让浏览器认为响应是普通的文件流,并提示用户下载文件。可以通过在Nginx的配置文件中做如下配置达到这样的目的:
location /download/ {
types { }
default_type application/octet-stream;
}
这样当Url路径中包含/download/
时,MIME类型会被重置为application/octet-stream
。另外,nginx自带的MIME类型映射表保存在conf/mime.types
中。
文件上传大小限制放开
有的时候后端的Web-Server提供文件上传的服务,但是如果前端使用Nginx做反向代理时,会出现文件无法上传的问题,这可能是由于Ngxin默认对客户端请求的body的限制。因为,默认情况下Nginx对客户端请求的大小限制是1m,而上传的文件往往超过1m。可以通过修改如下配置项,来放宽这个限制:
client_max_body_size 10m;
将这个值设置为0,可以取消这个限制。这个配置项可以用在http
, server
, location
配置节中。详见client_max_body_size
下载文件重命名
通常情况下,为了保证用户上传的文件在服务器的文件系统中不至于重名,一般会将文件名修改成guid后保存,并在数据库中保持guid与文件名的映射。此时,如果使用Nginx来提供对这些用户文件的下载功能的话,文件下载到用户浏览器,会以文件的guid名作为文件名,这显然是用户不想看到的。可以考虑用这个方案。
假设我们有一个文件的原始文件名为test.txt
,对应的guid文件名是21EC2020-3AEA-1069-A2DD-08002B30309D.txt
,文件的虚拟路径是/download/
使用服务器端编程语言,在输出的html中使用如下链接提供文件的下载:
<a href="/download/21EC2020-3AEA-1069-A2DD-08002B30309D.txt?n=test.txt" target='_blank'>下载test.txt</a>
可以看到,将原始文件名以QueryString的方式带在请求中,这样可以在Nginx端,利用$arg_name
变量来取到这个QueryString的值,从而重写response header:
add_header Content-Disposition "attachment; filename=$arg_n";
这会在response header中加入如下键值:
Content-Disposition: "attachment; filename=test.txt";
经测试,无论是IE还是Chrome都可以支持这个header。
关于Content-Disposition,详见这里
关于Nginx的标准http模块的嵌入变量,详见这里
Nginx作为反向代理
一个IP多个域名
如果只有一个公网IP,但是网站功能需要划分为多个不同的子网站或者子域名,可以用Nginx来搭建反向代理来“复用”IP资源。假设有如下几个域名都是abc.com这个主域的:
www.abc.com
image.abc.com
video.abc.com
1. 首先在DNS出注册这3个域名同时指向同一个IP,Nginx作为前端的web服务器,让所有访问这个IP地址80端口的请求全部指向Nginx
2. 然后,配置Nginx,根据域名将请求转发转发给内网的上游服务器,例如下面的配置:
server {
listen 80;
server_name www.abc.com;
location / {
proxy_pass http://192.168.1.100;
}
}
server {
listen 80;
server_name image.abc.com;
location / {
alias /var/www/image;
}
}
server {
listen 80;
server_name video.abc.com;
location / {
proxy_pass http://192.168.1.100:8081/video;
}
}
在上述配置中,将三个域名分发给了不同的模块处理:
www.abc.com
分发给上游的http://192.168.1.100服务器处理image.abc.com
则直接映射到了Nginx本机的一个目录video.abc.com
分发给上游的http://192.168.1.100:8081/video服务器处理(video是上游web-server的某虚拟目录)
上游服务器超时
Nginx作为反向代理的时候,如果上游服务器处理时间过长的话,有时会返回504网关超时,从nginx的错误日志看出如果是upstream timed out,就表示是上游服务器处理时间过长,Nginx认为服务超时。Nginx在请求上游服务器时默认的超时时间为1分钟,可以通过调整proxy_read_timeout
属性增加这个超时时间
proxy_read_timeout 180s;
解决liunx的Slab占用比较高的有关问题
liunx的Slab占用比较高的问题
最近经常报内存超过80%的阀值.
统计了下内存实际使用只有1.6G,希望能帮我们分析下为什么内存的使用率显示使用了3178M.

问题描述
Linux服务器内存使用量超过阈值,触发报警。
问题排查
首先,通过free命令观察系统的内存使用情况,显示如下:
- total used free shared buffers cached
- Mem: 24675796 24587144 88652 0 357012 1612488
- -/+ buffers/cache: 22617644 2058152
- Swap: 2096472 108224 1988248
其中,可以看出内存总量为24675796KB,已使用22617644KB,只剩余2058152KB。
然后,接着通过top命令,shift + M按内存排序后,观察系统中使用内存最大的进程情况,发现只占用了18GB内存,其他进程均很小,可忽略。
因此,还有将近4GB内存(22617644KB-18GB,约4GB)用到什么地方了呢?
进一步,通过cat /proc/meminfo发现,其中有将近4GB(3688732 KB)的Slab内存:
- ……
- Mapped: 25212 kB
- Slab: 3688732 kB
- PageTables: 43524 kB
- ……
Slab是用于存放内核数据结构缓存,再通过slabtop命令查看这部分内存的使用情况:
- OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
- 13926348 13926348 100% 0.21K 773686 18 3494744K dentry_cache
- 334040 262056 78% 0.09K 8351 40 33404K buffer_head
- 151040 150537 99% 0.74K 30208 5 120832K ext3_inode_cache
发现其中大部分(大约3.5GB)都是用于了dentry_cache。
问题解决
1. 修改/proc/sys/vm/drop_caches,释放Slab占用的cache内存空间(参考drop_caches的官方文档):
- Writing to this will cause the kernel to drop clean caches, dentries and inodes from memory, causing that memory to become free.
- To free pagecache:
- * echo 1 > /proc/sys/vm/drop_caches
- To free dentries and inodes:
- * echo 2 > /proc/sys/vm/drop_caches
- To free pagecache, dentries and inodes:
- * echo 3 > /proc/sys/vm/drop_caches
- As this is a non-destructive operation, and dirty objects are notfreeable, the user should run “sync” first in order to make sure allcached objects are freed.
- This tunable was added in 2.6.16.
2. 方法1需要用户具有root权限,如果不是root,但有sudo权限,可以通过sysctl命令进行设置:
- $sync
- $sudo sysctl -w vm.drop_caches=3
- $sudo sysctl -w vm.drop_caches=0 #recovery drop_caches
操作后可以通过sudo sysctl -a | grep drop_caches查看是否生效。
3. 修改/proc/sys/vm/vfs_cache_pressure,调整清理inode/dentry caches的优先级(默认为100),LinuxInsight中有相关的解释:
- At the default value of vfs_cache_pressure = 100 the kernel will attempt to reclaim dentries and inodes at a “fair” rate with respect to pagecache and swapcache reclaim. Decreasing vfs_cache_pressure causes the kernel to prefer to retain dentry and inode caches. Increasing vfs_cache_pressure beyond 100 causes the kernel to prefer to reclaim dentries and inodes.
具体的设置方法,可以参考方法1或者方法2均可。
参考资料
- https://www.kernel.org/doc/Documentation/sysctl/vm.txt
- http://major.io/2008/12/03/reducing-inode-and-dentry-caches-to-keep-oom-killer-at-bay/
- http://linux-mm.org/Drop_Caches
以下记录的是进一步排查的进展情况。
更深层次的原因
上文排查到Linux系统中有大量的dentry_cache占用内存,为什么会有如此多的dentry_cache呢?
1. 首先,弄清楚dentry_cache的概念及作用:目录项高速缓存,是Linux为了提高目录项对象的处理效率而设计的;它记录了目录项到inode的映射关系。因此,当应用程序发起stat系统调用时,就会创建对应的dentry_cache项(更进一步,如果每次stat的文件都是不存在的文件,那么总是会有大量新的dentry_cache项被创建)。
2. 当前服务器是storm集群的节点,首先想到了storm相关的工作进程,strace一下storm的worker进程发现其中有非常频繁的stat系统调用发生,而且stat的文件总是新的文件名:
sudo strace -fp <pid> -e trace=stat
3. 进一步观察到storm的worker进程会在本地目录下频繁的创建、打开、关闭、删除心跳文件,每秒钟一个新的文件名:
sudo strace -fp <pid> -e trace=open,stat,close,unlink
以上就是系统中为何有如此多的dentry_cache的原因所在。
一个奇怪的现象
通过观察/proc/meminfo发现,slab内存分为两部分:
SReclaimable // 可回收的slab SUnreclaim // 不可回收的slab
当时服务器的现状是:slab部分占用的内存,大部分显示的都是SReclaimable,也就是说可以被回收的。
但是通过slabtop观察到slab内存中最主要的部分(dentry_cache)的OBJS几乎都是ACTIVE的,显示100%处于被使用状态。
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME 13926348 13926348 100% 0.21K 773686 18 3494744K dentry_cache 334040 262056 78% 0.09K 8351 40 33404K buffer_head 151040 150537 99% 0.74K 30208 5 120832K ext3_inode_cache
为什么显示可回收的,但是又处于ACTIVE状态呢?求Linux内核达人看到后热心解释下:(
会不会由于是ACTIVE状态,导致dcache没有被自动回收释放掉呢?
让系统自动回收dcache
上一小节,我们已经提到,服务器上大部分的slab内存是SReclaimable可回收状态的,那么,我们能不能交给操作系统让他在某个时机自动触发回收操作呢?答案是肯定的。
查了一些关于Linux dcache的相关资料,发现操作系统会在到了内存临界阈值后,触发kswapd内核进程工作才进行释放,这个阈值的计算方法如下:
1. 首先,grep low /proc/zoneinfo,得到如下结果:
low 1 low 380 low 12067
2. 将以上3列加起来,乘以4KB,就是这个阈值,通过这个方法计算后发现当前服务器的回收阈值只有48MB,因此很难看到这一现象,实际中可能等不到回收,操作系统就会hang住没响应了。
3. 可以通过以下方法调大这个阈值:将vm.extra_free_kbytes设置为vm.min_free_kbytes和一样大,则/proc/zoneinfo中对应的low阈值就会增大一倍,同时high阈值也会随之增长,以此类推。
$ sudo sysctl -a | grep free_kbytes vm.min_free_kbytes = 39847 vm.extra_free_kbytes = 0 $ sudo sysctl -w vm.extra_free_kbytes=836787 ######1GB
4. 举个例子,当low阈值被设置为1GB的时候,当系统free的内存小于1GB时,观察到kswapd进程开始工作(进程状态从Sleeping变为Running),同时dcache开始被系统回收,直到系统free的内存介于low阈值和high阈值之间,停止回收。
原文链接:http://www.cnblogs.com/panfeng412/p/drop-caches-under-linux-system.html
find -mtime -newermt 使用心得
最近需要在linux下,某目录中筛出所有mtime < 今天的文件。于是有了这篇博文。
find {path} -mtime {days}
本能地使用find -mtime +1 命令。使用后发现,筛出的一直是修改时间为48小时以外的文件。经过研究man find,亲自试验,得到了如下结论。
find -mtime -1
find -mtime 1
find -mtime +1
find在修改时间处使用的是排除法,上述三个出现的文件不会有交集。
-1是24小时之内操作过的;1是24小时之外,48小时之内操作过的;+1是48小时之外操作过的.
如果有文件同时符合两个或三个,优先出现在第一个,不会出现在第二个或第三个。比如有文件从三天前到今天一直在append,那么只会出现在find -mtime -1里。
基于此,find -mtime +1只能得到48小时之外的文件,不符合我的要求。
find {path} -newermt {time}
其实find -newermt的真正形式是find -newerXY {variable},旨在找到一些X属性比variable的Y属性更早的文件。其中X指代find的目标文件属性,Y代表参照属性。X可选a,c,m;Y可选a,c,m,t。acm意义分别为atime(访问时间),ctime(改变时间),mtime(修改时间)。t代表客观绝对时间,只作为参照属性存在,格式为yyyy-MM-dd hh:mm:ss。
由于我想要找到除了今天修改的文件之外的文件,只需要
1. 筛出mtime为今天的文件:find {path} -newermt `date +%F` -type f
2. 进行反选,在find中加入 !
所以得到的最终命令为
find {path} ! -newermt \`date +%F\` -exec {order} {} \;
最后一组{}表示exec之前筛到的文件。
结论:find -mtime更适合筛选以小时为单位(相对时间)的时间区间。对于以绝对时间(如自然日)为单位的时间区间,更适合使用find {path} (!) -newermt -type f
———————
作者:ligeforrent
来源:CSDN
原文:https://blog.csdn.net/ligeforrent/article/details/75352245
版权声明:本文为博主原创文章,转载请附上博文链接!
SSL3_GET_SERVER_CERTIFICATE 错误解决办法(SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed)
requests模块之前一直正常的,某一天开始对https的请求都抛错误了:
requests.exceptions.SSLError: [Errno 1] _ssl.c:504: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
完整的:
/usr/local/lib/python2.7/dist-packages/requests/packages/urllib3/util/ssl_.py:79: InsecurePlatformWarning: A true SSLContext object is not available. This prevents urllib3 from configuring SSL appropriately and may cause certain SSL connections to fail. For more information, see https://urllib3.readthedocs.org/en/latest/security.html#insecureplatformwarning.
InsecurePlatformWarning
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/usr/local/lib/python2.7/dist-packages/requests/api.py", line 68, in get
return request('get', url, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/requests/api.py", line 50, in request
response = session.request(method=method, url=url, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 464, in request
resp = self.send(prep, **send_kwargs)
File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 576, in send
r = adapter.send(request, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/requests/adapters.py", line 431, in send
raise SSLError(e, request=request)
requests.exceptions.SSLError: [Errno 1] _ssl.c:504: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
试过:
sudo apt-get install ca-certificates
sudo update-ca-certificates
没效果,
最后试了下面的起效的:
sudo pip uninstall -y certifi
sudo pip install certifi==2015.04.28
当然,还是有警告:
/usr/local/lib/python2.7/dist-packages/requests/packages/urllib3/util/ssl_.py:79: InsecurePlatformWarning: A true SSLContext object is not available. This prevents urllib3 from configuring SSL appropriately and may cause certain SSL connections to fail. For more information, see https://urllib3.readthedocs.org/en/latest/security.html#insecureplatformwarning.
InsecurePlatformWarning
不够,至少可以先用着了。原因估计就是高版本(2016.2.8)的certifi对证书验证更为严格了。
为什么nohup在终端退出之后进程会退出
因为在nohup执行之后,该终端必须以exit方式正常退出,若直接退出,则有些主机会认为你异常退出而关闭你的进程。
进程与终端–终端关闭后,后台进程也终止
问题:
ssh登录服务器,并开启一个后台进程,然后自己去做其他事情了。等过了一会儿,当再来查看时,发现开启的后台进程莫名其妙的挂掉了。
原因:
无论进程是在后台还是在前台,它都与启动它的终端实例紧密绑定。当终端关闭时,它通常向绑定到终端的所有进程(前台、后台进程)发送SIGHUP信号。 这表示进程终止,因为它们的控制终端将很快不可用。
本例中,ssh登录终端,超过一定时间没有操作后,连接断开,终端关闭,与终端相关的所有进程(包括前台和后台进程)都将终止。
验证:
开启一个后台进程
代码如下:
terminal_process.c
#include <unistd.h>
int main()
{
while(1)
{
sleep(10);
}
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
编译、后台运行
$ gcc terminal_process.c -o terminal_process
$ ./terminal_process &
1
2
3
查看前后台进程、终端
$ ps -o pid,ppid,pgrp,session,tpgid,comm,tty
PID PPID PGRP SESS TPGID COMMAND TT
15907 15906 15907 15907 16145 bash pts/1
15946 15907 15946 15907 16145 terminal_proces pts/1
16145 15907 16145 15907 16145 ps pts/1
1
2
3
4
5
其中,
pgrp 进程组ID
tpgid 控制进程组ID
tty 控制终端号
15097是会话首进程,会话ID为其ID,此时会话首进程属于后台进程组。
terminal_proces进程是15946,其父进程为bash(会话首进程15907)。
16145拥有控制终端,所以是前台进程组。
15907、15946都是后台进程组。
过一段时间,没有操作终端,ssh登录终端自动断开。
再查看进程,可以看到刚才开启的进程已经终止。
另外,本地终端强制关闭,也有类似的问题。
解决办法:
终端开启一个后台进程后,例如termal_process,然后终端下输入命令exit正常退出.
$ ./terminal_process &
$ ps -ef | grep terminal_process
lanyang 16946 16907 0 10:18 pts/1 00:00:00 ./terminal_process
$ exit
1
2
3
4
5
登录另一个终端查看
$ ps -ef | grep terminal_process
lanyang 16946 1 0 10:18 ? 00:00:00 ./terminal_process
1
2
terminal_process的父进程已经变成了init进程,不会出现刚才的问题。
除了这个方法,还有nohup,disown等其他,有兴趣可以自行搜索查看。
[FTP] Pure-FTPd SSL/TLS 配置方法
一、准备 & 安装
启用 Pure-FTPd SSL/TLS 连接方式在安装时需要检查以下两项:
1、系统中是否已经安装了 openssl 和 openssl-devel 包?
2、在编译 Pure-FTPd 的时候需要加载 –with-tls
二、证书制作
在成功安装好 Pure-FTPd 后,我们需要制作一张 SSL 证书供 Pure-FTPd 使用。
编译安装后的 Pure-FTPd 默认的证书存储位置为:/etc/ssl/private/pure-ftpd.pem,该文件会在 Pure-FTPd 启动时自动加载,若证书不存在或路径错误则 Pure-FTPd 启动失败。可以检查 /var/log/message 日志,其中记录了 Pure-FTPd 启动时的报错信息。
下面,我们开始制作证书:(以下操作需要 root 权限)
# mkdir -p /etc/ssl/private
# openssl req -x509 -nodes -newkey rsa:1024 -keyout /etc/ssl/private/pure-ftpd.pem -out /etc/ssl/private/pure-ftpd.pem
(按照提示输入证书的相关信息)
# chmod 600 /etc/ssl/private/*.pem
至此,证书就制作完成了。
三、配置 Pure-FTPd
在 Pure-FTPd 配置文件 pure-ftpd.conf 中配置所需使用的登录方式。
TLS 0|1|2
其中:
0:禁用 SSL/TLS 登录模式;
1:同时支持普通模式登录和 SSL/TLS 模式登录;
2:仅支持有效的 SSL/TLS 登录模式(推荐!)。
Jenkins 为每个job配置相应的jdk版本
在使用jenkins构建项目时会遇到不同的job需要配置不同版本的jdk。例如job1里构建project A 时需要的jdk版本是1.7的,但是在job2里面构建project B时,却需要的jdk版本是1.8的。或者是同一个job需要在构建时根据情况指定不同的jdk版本等情况。此时就需要为job指定使用的jdk版本,这个需求可以通过配置jenkins Global Tool Configuration 和JDK Parameter Plugin实现。
方法如下说明:
先在jenkins 上的manage Jenkins ——->Manage Plugins—–>Available里面搜索JDK Parameter Plugin安装。
在Manage Jenkins——->Global Tool Configuration——>JDK部分,点击Add JDK:
配置不同版本的jdk:
填写name(可以随便取名,主要用来标识,会出现在后续job中jdk的版本选择中),然后勾选I agree to the Java SE Development Kit Licence Agreement。
这里是通过jenkins每次去网站上自动下载,此时若是第一次配置jdk,还会要求你输入java.sun.com网站上的账号。根据提示填写就好(没有就注册一个)。
新建一个job,此时在job 的config界面会有jdk选项,供你选择jdk的版本。下拉框中的选项是之前在Global Tool Configuration中配置的jdk name
若是需要把设置jdk 版本作为参数化构建的参数,此时可以在job 的config 界面中添加参数:
填写参数的名称,选择默认的jdk版本,selectable jdks 是在参数化构建时的可选项,下拉菜单中是之前Global Tool Configuration中配置的jdk name。
该配置完成后,参数化构建job时会是下图所示的样子:
ok~为不同的job指定不同版本的jdk完成构建就完成啦,不得不感慨jenkins 的强大之处,可以集成各种各样的插件~
———————
作者:MaggieTian77
来源:CSDN
原文:https://blog.csdn.net/maggietian77/article/details/80831259
版权声明:本文为博主原创文章,转载请附上博文链接!
-bash: locate: command not found
部分版本的linux系统使用locate快速查找某文件路径会报以下错误:
-bash: locate: command not found
其原因是没有安装mlocate这个包
安装:yum -y install mlocate
安装完再尝试用locate定位内容,发现依然不好使,报了新的错误:
locate: can not stat () `/var/lib/mlocate/mlocate.db’: No such file or directory
原因是安装完后没有更新库
更新库:updatedb
———————
作者:搁浅记忆
来源:CSDN
原文:https://blog.csdn.net/huangyuhuangyu/article/details/80347250
版权声明:本文为博主原创文章,转载请附上博文链接!
解决zabbix可用性为灰色状态
zabbix添加主机后,获取不到zabbix agent状态,并且图标为灰色,而在zabbix-server端使用zabbix_get可以正常获取到数据。在正常情况下应为绿色或红色。
问题原因,添加主机时没有添加监控项,或链接至模板,后触发zabbix可用性。
原因为:在添加zabbix主机时,虽然通过agent获取到监控对应主机信息,但是,由于并没有配置监控主机的任何指标(item),所以,ZBX仍然是灰色的,也就是说,此时只是将被监控的agent端加入了zabbix的监控范围,但是并没有对它进行任何实际的监控。需要配置任意监控项才可激活zabbix支持的监控方式。