nginx搭建及加固
系统使用的是centos7
Nginx安装及配置
Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务
安装
我是用的环境是centos 7,系统默认的yum源没有nginx,找到一个使用nginx官方源地址
首先建立nginx的yum仓库,执行下面的命令
sudo rpm -ivh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
可以看到已经添加上了nginx的源,下面就是下载安装了
下载安装命令也很简单
sudo yum install -y nginx
安装成功^_^
查看官方安装文档(https://www.nginx.com/resources/wiki/start/topics/tutorials/install/)上的源不一样,不过都是一样的建立本地yum仓库
启动nginx服务
service nginx start
默认是80端口,但测试访问发现并不能进入欢迎页面,查了一下,centos默认是关闭80端口的,我们设置一下防火墙
开启80端口
sudo firewall-cmd --zone=public --permanent --add-service=http
开启443端口
sudo firewall-cmd --zone=public --permanent --add-service=https
必须要重新加载一下防火墙配置才行哦,下面我们再来访问一下
完美。
配置
默认的网站目录为: /usr/share/nginx/html
全局的配置文件为:/etc/nginx/nginx.conf
默认的配置文件为: /etc/nginx/conf.d/default.conf
日志文件目录为:/var/log/nginx/
我们查看具体的配置文件内容,发现其实nginx.conf是主要的配置文件,新增的都在/etc/nginx/conf.d/,nginx.conf将整个目录的配置文件都include了
配置结构
Nginx配置文件常见结构的从外到内依次是「http」「server」「location」等等,缺省的继承关系是从外到内,也就是说内层块会自动获取外层块的值作为缺省值。
Http
http {
#文件扩展名与文件类型映射表
include /etc/nginx/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 /var/log/nginx/access.log main;
#sendfile指令指定 nginx 是否调用sendfile 函数(zero copy 方式)来输出文件,对于普通应用,必须设为on。如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络IO处理速度,降低系统uptime。
sendfile on;
#此选项允许或禁止使用socket的TCP_CORK的选项,此选项仅在使用sendfile的时候使用
#tcp_nopush on;
#长连接超时时间,单位是秒
keepalive_timeout 65;
#开启gzip压缩输出
#gzip on;
#导入其他配置
include /etc/nginx/conf.d/*.conf;
}
整个配置文件结构其实大概是这样的
http {
#全局的配置
…………
server{
#虚拟主机的配置
…………
location {
#每个请求的处理,如请求转发、静态文件映射、负载均衡等
…………
}
}
}
下面再具体了解一下每一层的配置
Server
接收请求的服务器需要将不同的请求按规则转发到不同的后端服务器上,在 nginx 中我们可以通过构建虚拟主机(server)的概念来将这些不同的服务配置隔离。不同的url会对应不同的server配置,而转发到相应的后端服务器上做处理。
server {
listen 80; #服务监听端口
server_name localhost; #服务的域名或IP
root html; #指定服务的页面根目录
index index.html index.htm; #指定访问的默认首页地址
}
通常我们可以配置多个server,像这样
server {
listen 80;
server_name host1;
root html;
index index.html index.htm;
}
server {
listen 80;
server_name host2;
root /data/www/html;
index index.html index.htm;
}
我们可以将不同的服务在/etc/nginx/conf.d/目录下创建相应的conf以区分,方便管理,而nginx.conf会将这个目录下的conf全部引入的。
Location
每个 url 请求都会对应的一个服务,nginx 进行处理转发或者是本地的一个文件路径,或者是其他服务器的一个服务路径。而这个路径的匹配是通过 location 来进行的。我们可以将 server 当做对应一个域名进行的配置,而 location 是在一个域名下对更精细的路径进行配置。
location [匹配规则] {
#具体处理配置,如转发、反向代理、负载均衡等
}
location 匹配规则:
~ 波浪线表示执行一个正则匹配,区分大小写
~* 表示执行一个正则匹配,不区分大小写
^~ ^~表示普通字符匹配,如果该选项匹配,只匹配该选项,不匹配别的选项,一般用来匹配目录
= 进行普通字符精确匹配
匹配例子:
location = / {
# 只匹配"/".
[ configuration A ]
}
location / {
# 匹配任何请求,因为所有请求都是以"/"开始
# 但是更长字符匹配或者正则表达式匹配会优先匹配
[ configuration B ]
}
location ^~ /images/ {
# 匹配任何以 /images/ 开始的请求,并停止匹配 其它location
[ configuration C ]
}
location ~* \.(gif|jpg|jpeg)$ {
# 匹配以 gif, jpg, or jpeg结尾的请求.
# 但是所有 /images/ 目录的请求将由 [Configuration C]处理.
[ configuration D ]
}
请求:
/ -> 符合configuration A
/documents/document.html -> 符合configuration B
/images/1.gif -> 符合configuration C
/documents/1.jpg ->符合 configuration D
功能配置
主要的功能配置都是在location里面的,下面我们来学习不同功能的配置方法
静态文件映射
访问文件的配置主要有 root 和 alias
alias后跟的指定目录是准确的,并且末尾必须加 /。
location /c/ {
alias /a/;
}
如果访问站点http://location/c访问的就是/a/目录下的站点信息。
root后跟的指定目录是上级目录,并且该上级目录下要含有和location后指定名称的同名目录才行。
location /c/ {
root /a/;
}
这时访问站点http://location/c访问的就是/a/c目录下的站点信息。
配置起来很简单比如我要将所有的请求到转移到真正提供服务的一台机器的 8001 端口,只要这样:
location / { proxy_pass 172.16.1.1:8001; }
这样访问host时,就都被转发到 172.16.1.1的8001端口去了。
负载均衡
#负载均衡服务器列表配置在http下面
upstream myserver {
ip_hash;
server 172.16.1.1:8001;
server 172.16.1.2:8002;
server 172.16.1.3;
server 172.16.1.4;
}
location / {
proxy_pass http://myserver;
}
我们在 upstream 中指定了一组机器,并将这个组命名为 myserver,这样在 proxypass 中只要将请求转移到 myserver 这个 upstream 中我们就实现了在四台机器的反向代理加负载均衡。
负载均衡的模式
轮询:默认模式,每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。
weight:指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。
upstream bakend {
server 192.168.0.14 weight=10;
server 192.168.0.15 weight=10;
}
ip_hash:每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。
upstream bakend {
ip_hash;
server 192.168.0.14:88;
server 192.168.0.15:80;
}
fair:按后端服务器的响应时间来分配请求,响应时间短的优先分配。
upstream backend {
server server1;
server server2;
fair;
}
url_hash:按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效。
#例:在upstream中加入hash语句,server语句中不能写入weight等其他的参数,hash_method是使用的hash算法
upstream backend {
server squid1:3128;
server squid2:3128;
hash $request_uri;
hash_method crc32;
}
负载均衡设备的IP及设备状态
每个设备的状态设置为: 1.down表示单前的server暂时不参与负载 2.weight为weight越大,负载的权重就越大。 3.max_fails:允许请求失败的次数默认为1.当超过最大次数时,返回proxy_next_upstream模块定义的错误 4.fail_timeout:max_fails次失败后,暂停的时间。 5.backup: 其它所有的非back
up机器down或者忙的时候,请求backup机器。所以这台机器压力会最轻。
upstream bakend{#定义负载均衡设备的Ip及设备状态}{
ip_hash;
server 127.0.0.1:9090 down;
server 127.0.0.1:8080 weight=2;
server 127.0.0.1:6060;
server 127.0.0.1:7070 backup;
}
加固
隐藏服务器版本号
默认我们访问不存在的页面时,报错页面上会有nginx的版本信息,这会向黑客提供信息,以方便查找当前版本的漏洞,加以利用
修改ngixn.conf,http层里面添加server_tokens off;
我们访问不存在的页面试一下
这样没有版本信息了
禁止目录浏览
默认是不允许列出整个目录的,如果不是做下载服务器的,就不要打开这个,避免敏感信息暴露给黑客并下载
如果开启了就会是下面这样的效果
配置关闭即可
autoindex off
限制访问敏感资源
有些资源我们可能不想对外开放,比如一些版本控制的备份文件,如.git/.svn等,这些暴露了可能会将整个项目的结构或是源代码都泄露了,
location /my/ { deny all; }
上面我设置了my这个目录下的所有资源都拒绝,效果如下
所以要识别好公开的资源,限制敏感资源的访问
限制HTTP请求方法
关闭没必要的请求方法,一般都是get|post了
下面配置在server里面,预期之外的会返回500状态
if ($request_method !~ ^(GET|HEAD|POST)$ ) { return 500; }
这个要放到最前面
限制IP/域名访问
ngx_http_access_module 模块使有可能对特定IP客户端进行控制. 规则检查按照第一次匹配的顺序
location ~ .*my.html$ {
root /usr/share/nginx/html;
deny 192.168.0.105; #禁止ip
allow 192.168.189.134; #允许ip
deny all; #拒绝其他所有
}
限制访问的ip,即限制了服务的客户,防止不允许的人访问,减少风险
控制超时时间
可以缓解dos攻击,避免黑客伪造用户访问服务,造成服务器压力过大,带宽占满,备份nginx.conf配置文件。
编辑配置文件,具体设置如下:
client_body_timeout 10; #设置客户端请求主体读取超时时间 client_header_timeout 10; #设置客户端请求头读取超时时间 keepalive_timeout 5 5; #第一个参数指定客户端连接保持活动的超时时间,第二个参数是可选的,它指定了消息头保持活动的有效时间 send_timeout10; #指定响应客户端的超时时间
验证一下设置
错误页面重定向
避免错误页面提供敏感信息,一般我们会定制一些通用的错误页面返回给客户端
我们在http段配置
error_page 500 502 503 504 /50x.html;
类似上面这种配置,将状态码500、502、503、504全部重定向到50x.html
nginx降权
如果发生入侵,获取了当前运行nginx的用户,则拥有该用户的全新了,我们应当使用最下权限运行ngixn,绝对禁止root用户运行!!!
备份nginx.conf配置文件。
编辑配置文件,添加如下一行内容:
user nobody;
保存,然后后重启nginx服务。
说明:nobody在linux中是一个不能登陆的帐号,一些服务进程如apache,aquid等都采用一些特殊的帐号来运行,比如nobody,news,games等等,这是就可以防止程序本身有安全问题的时候,不会被黑客获得root权限