之前写过http下方的server被称作为虚拟主机,当配置文件中只存在一个server时,Nginx会将该server当成默认网站,所有发给Nginx服务器80端口的数据都会默认发送给这个server。
详解server中的配置
charset utf-8;
access_log logs/112.access.log main;
一般日志中access_log就使用全局的日志记录即可,但如果你想做多个子域名(或者二级域名)网站最好还是单独配置一下access_log,这样日志不会混杂在一起,而且我发现之前使用dnf安装的nginx日志信息都做了定时切割,即每日的日志都打成一个单独压缩包,这样可以节省空间,也方便排查问题,非常棒。如果自己是用源码配置的nginx,那么就得手动去写一个sh脚本放在crontab中运行,不过也不麻烦。
例如,我想写一个每日凌晨0点统计网站每个IP访问次数的脚本(管道符的含义是将前一个命令的结果当做后一个命令的对象)
#命名的尾缀并非一定要sh
touch record_uniq_ip.sh
vim record_uniq_ip.sh
# 以下为record_uniq_ip.sh的内容
>#!/bin/bash
>#author:zhangxiaofei
>#record the number of uniq IP visits my web
>awk '{print $1}' /usr/local/nginx/logs/112.access.log | uniq -c > ip.log
脚本写好后使用crontab -e来写定时任务(请注意,这里不需要填写user name)或者直接修改/etc/crontab中的内容,在我的云服务器上,crontab -e的定时任务存放在/var/spool/cron/root文件下(因为我是root用户)。
Nginx目录访问控制
应用环境是网站存在a目录,但是我不想让它被别人访问。
location / {
#定义根目录/usr/local/nginx/html
root html;
index index.html index.htm;
}
#location定义的是相对于根目录的路径
#/a其实表示的是/usr/local/nginx/html/a目录
location /a {
#可以在本机上通过127.0.0.1来访问该目录
allow 127.0.0.1;
#可以通过IP来源为IP112.110.99.241来访问该目录
allow 112.110.99.241;
deny all;
}
上面的allow 112.110.99.241指的不是通过浏览器输入该公网IP可以访问该目录,而是指在服务器上可以使用elinks http://112.126.88.219/a/这种方式访问到a目录,如果不加入这个,那么你在服务器上想通过112.110.99.241的IP来源(即服务器本机的公网IP)访问a目录是无法访问的。
但是这种做法有个问题,通过公网访问该路径,返回的是403禁止页面,对状态码稍微了解一点的都知道,说明该页面存在,但是只是被禁止访问,稍作修改,让其返回404,500错误,亦或者让其重定向至某个页面(非状态码则必须是一个url);
location /a {
...
# return 404;
return https://www.baidu.com
}
首先访问了a页面,返回的Status Code:302 Moved Temporarily,然后跳转至百度首页。
Nginx登录认证
应用于某个页面必须要登录验证才能访问。为了便捷,需要借用到Apache的一个包,因为centos8上面已经预装了htpasswd,假如服务器上面没有安装,使用yum进行安装httpd-tools即可
rpm -qf `which htpasswd`
>httpd-tools-2.4.37-30.module_el8.3.0+561+97fdbbcc.x86_64
在配置文件中加入以下代码
location /b{
#开启密码验证,前端WWW-Authenticate中的Basic realm
#可以是string也可以是off
auth_basic "zhang";
#存放秘钥文件所在
auth_basic_user_file /usr/local/nginx/pwd/htpasswd;
}
再次访问网站b目录下的路径,提示如下,即使我在htpasswd文件中使用vim加入了zhangxiaofei:123账户和密码也还是无法访问,是因为必须要加密的密码才会得到承认,有两种方法,一种是openssl,一种就是htpasswd
htpasswd -b pwd/htpasswd zhangxiaofei 123456
cat pwd/htpasswd
>zhangxiaofei:$apr1$7c07vj9T$qKR8HbLrGkC2XTR2Mwa7g1
重启nginx之后,再次输入账号密码成功访问到该页面。
Nginx日志格式
在http服务器配置中,有一个字段名为log_format,是用来定义记录日志的格式,可以定义多种日志格式,但是需要取不同的名字,如下所示,log_name为main,后接string(字符串,又称nginx变量)字段。
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
知道了原理,我尝试重新定义nginx.conf的日志输出格式,如下:
#每一行必须用单引号包裹
log_format zxf_log '[$time_local] [$remote_addr] ["$request"] [$status]';
access_log logs/112.access.log zxf_log
再次查看访问日志,如下:
排查日志是一件非常费时间和费眼力的事情,在以上的基础上,我们可以优化日志的输出格式,让输出变得更好看一些,那么完全可以尝试将日志输出为简洁和清晰的json格式。
log_format json_log '{"@timestamp":"$time_local",'
'"client_ip":"$remote_addr",'
'"request":"$request",'
'"status":"$status",'
'"bytes":"$body_bytes_sent",'
'"x_forwarded":"$http_x_forwarded_for",'
'"http_referer":"$http_referer",'
'"user_agent":"$http_user_agent"'
'}';
清晰很多!
Nginx防盗链
防盗链的原理是通过Referrer Policy来判断的,只允许自己设置的路径来访问该图片链接。
例如,现在我服务器上有一张图片,我不设置防盗链的话,我通过其它服务器配置img标签的src属性可以直接将图盗走,如
<img src='http://112.***.**.**9/0.png' height='100px' width='50px'>
通过nginx日志可以看到http_referer正是另外一台服务器的IP
配置文件如下:
#~表示匹配,*不区分大小写,以下图片格式结尾的
location ~* \.(png|gif|bmp)$ {
#blocked表示有防火墙标志
valid_referers none blocked *.myweb.com;
if ($invalid_referer){
return 403;
}
}
再次远程调用该图片,提示403禁止访问
虚拟主机的作用
虚拟主机可以使用一个web服务器发布多个网站。一个web分享出去需要IP,Port,domain,因此相同的web服务器发布不同的网站可以基于这三点。
一、基于IP的虚拟主机。描述:每个网站需要一个独立的IP,一个公网IP每年的费用大概在600元,由于没有公网IP,用elinks对两个内网IP来进行测试。
先用ifconfig查看相关网卡信息,获取内网inet的IP,在其基础上建立一个子网卡,这样就有两个IP段可以用于测试
ifconfig eth0:1 172.23.246.187/24 up
在nginx.conf配置文件中,配置如下
server {
listen 80;
server_name 172.23.246.177;
location / {
root html/web1;
index index.html index.htm;
}
}
server {
listen 80;
server_name 172.23.246.187;
location / {
root html/web2;
index index.html index.htm;
}
}
使用elinks测试如下,就我目前的了解而言,内网IP是无法通过公网IP来进行访问的:
测试完成之后,关闭子网卡
ifconfig eth0:1 down
二、基于端口。适合私网用户。原理是一样的,还是配置两个server,这里就可以直接用浏览器对公网IP进行访问测试了,但是前提是该端口(示例为8000端口)在阿里云和防火墙之中放行了
server {
listen 80;
server_name 112.126.88.219;
location / {
root html/web1;
index index.html index.htm;
}
}
server {
listen 8000;
server_name 112.126.88.219;
location / {
root html/web2;
index index.html index.htm;
}
}
三、基于域名。只需要一个IP就可以发布N个网站,测试如下
首先修改云服务器dns解析策略
vim /etc/hosts
# 加入以下内容
112.126.88.219 www.cba.com
112.126.88.219 www.nba.com
nginx.conf配置文件基本与第一种基于IP的相同,将server_name进行替换即可,使用elinks测试如下: