介绍
在为网站配置服务器时,您可能需要实施一些常见的条件操作。 例如,也许某些文件应该由用户的浏览器缓存比其他文件更长的时间,或者网站的某些部分应该只允许通过安全连接(如任何需要用户密码的东西),而网站的其他部分则不允许吨。
另一个简单、常见的示例是确保在发布新网页代替旧网页时,所有旧地址都将重定向到正确的位置。 这很有用,因为它意味着旧链接和书签不会停止工作,而且它还保留了 Google 的缓存。
Nginx 的 map 模块允许您在 Nginx 的配置文件中创建变量,其值是有条件的——也就是说,它们依赖于其他变量的值。 在本指南中,我们将研究如何使用 Nginx 的地图模块实现两个示例:如何设置从旧网站 URL 到新 URL 的重定向列表以及如何创建国家许可列表来控制您网站的流量。
先决条件
要遵循本教程,您将需要:
- 使用 this initial server setup tutorial 设置的一台 Ubuntu 16.04 服务器,包括 sudo 非 root 用户。
- 按照 如何在 Ubuntu 16.04 上安装 Nginx 教程 在您的服务器上安装 Nginx。
第 1 步 - 创建和测试示例网页
首先,我们将创建一个代表新发布网站的测试文件。 我们将使用这个文件来测试我们的配置。
让我们在默认的 Nginx 网站目录中创建一个简单的页面 index.html
。 该文件将仅包含描述内部内容的纯文本:Home。
sudo sh -c 'echo "Home" > /var/www/html/index.html'
有了这个测试文件,接下来我们将使用 curl
检查它是否被正确提供。 我们不需要为此命令指定 index.html
,因为如果没有提供确切的文件名,则默认提供该文件。
curl http://localhost/
作为响应,您应该会看到一个单词 Home,如下所示:
Nginx 响应
Home
现在让我们尝试访问 /var/www/html/
中不存在的文件,例如 old.html
。
curl -L http://localhost/old.html
响应将是一条系统错误消息,404 Not Found,表示该页面不存在。
Nginx 响应
<html> <head><title>404 Not Found</title></head> <body bgcolor="white"> <center><h1>404 Not Found</h1></center> <hr><center>nginx/1.10.0 (Ubuntu)</center> </body> </html>
在本教程中,我们只是使用了一个虚拟网站,但如果 old.html
是真实网站上曾经存在并被删除的页面,则返回 404 将意味着指向该页面的所有链接都已损坏。 这不太理想,因为这些链接可能已被 Google 索引、打印出来或写下来,或以任何其他方式共享。
在下一步中,我们将利用地图模块通过自动将查看者重定向到新的替代地址来确保这个旧地址能够再次工作。
第 2 步 — 配置重定向
对于只有几页的小型网站,简单的 if
条件语句可以用于重定向和类似的事情。 但是,从长远来看,随着条件列表的增长,这样的配置并不容易维护或扩展。
map 模块是一个更优雅、更简洁的解决方案。 它允许您将 Nginx 变量值与条件列表进行比较,然后根据匹配将新值与变量关联。 在此示例中,我们将请求的 URL 与我们希望重定向到新页面的旧页面列表进行比较。 对于每个旧地址,我们将关联新地址。
map 模块是一个核心的 Nginx 模块,这意味着它不需要单独安装即可使用。 要创建必要的映射和重定向配置,请在 nano
或您喜欢的文本编辑器中打开默认的服务器块 Nginx 配置文件。
sudo nano /etc/nginx/sites-available/default
找到 server
配置块,如下所示:
/etc/nginx/sites-available/default
. . . # Default server configuration # server { listen 80 default_server; listen [::]:80 default_server; . . .
我们将添加两个新部分:一个在 server
块之前,一个在它里面。
server
块之前的部分是一个新的 map
块,它使用 map 模块定义旧 URL 和新 URL 之间的映射。 server
块内的部分是重定向本身。
修改 /etc/nginx/sites-available/default
. . . # Default server configuration # # Old website redirect map # map $uri $new_uri { /old.html /index.html; } server { listen 80 default_server; listen [::]:80 default_server; # Old website redirect if ($new_uri) { rewrite ^ $new_uri permanent; } . . .
map $uri $new_uri
指令获取系统 $uri
变量的内容,该变量包含所请求页面的 URL 地址,然后将其与大括号中的条件列表进行比较。 条件列表中的每个项目都有两个部分:要匹配的值,以及如果匹配则分配给变量的新值。
map
块内的 /old.html /index.html
行表示如果 $uri
的值为 /old.html
,则 $new_uri
将更改为 /index.html
。 如果不匹配,则不会更改。 在这里,我们只定义一个条件,但您可以在地图中定义任意数量的条件。
然后,使用 server
块内的条件 if
语句,我们检查是否设置了 $new_uri
变量的值。 如果是,则说明地图中的条件已经满足,我们应该使用 rewrite
命令重定向到新网站。 permanent
关键字确保重定向将是 301 Moved Permanently HTTP 重定向,这意味着旧地址不再有效并且不会重新上线。
保存并关闭文件以退出。
要启用新配置,请重新启动 Nginx。
sudo systemctl restart nginx
要测试新配置,请执行与之前相同的请求:
curl -L http://localhost/old.html
这次输出中不会出现 404 Not Found 错误。 相反,您将看到我们在第 1 步中创建的简单主页。
Nginx 响应
Home
这意味着地图已正确配置,您可以通过向地图添加更多条目来使用它来重定向 URL。
重定向 URL 是 map 模块的一个有用的应用。 我们将在下一步中探讨的另一个是根据访问者的地理位置过滤流量。
第 3 步 — 限制对某些国家/地区的网站访问
有时,服务器可能会收到过多的自动恶意请求。 这可能是 DDoS 攻击、试图暴力破解网站管理面板的密码,或试图利用软件中的已知漏洞来攻击网站并使用它来发送垃圾邮件或修改网站内容。
这种自动攻击可能来自许多不同国家的许多不同的分布式服务器,因此难以阻止。 减轻此类攻击影响的一种解决方案是创建可以访问该网站的国家/地区的许可名单。
这不是一个完美的解决方案,但在基于访问者的地理位置限制对网站的访问是明智的选择并且不会限制网站的访问者的情况下,此解决方案的优点是速度快且不易出错。
服务器级别的过滤比网站级别的过滤要快,并且还涵盖了所有请求(包括静态文件,如图像)。 这种过滤还可以完全阻止请求到达网站软件,这使得漏洞更难被利用。
为了使用地理过滤,我们首先创建一个新的配置文件。
sudo nano /etc/nginx/conf.d/geoip.conf
将以下内容粘贴到文件中。 这告诉 Nginx 在哪里可以找到包含访问者 IP 地址与其各自国家/地区之间的映射的 GeoIP 数据库。 该数据库预装了 Ubuntu 16.04。
/etc/nginx/conf.d/geoip.conf
. . . # GeoIP database path # geoip_country /usr/share/GeoIP/GeoIP.dat;
下一步是创建必要的地图和限制配置。 打开默认的服务器块 Nginx 配置。
sudo nano /etc/nginx/sites-available/default
找到 server
配置块,在步骤 1 和 2 中修改后,如下所示:
/etc/nginx/sites-available/default
. . . # Default server configuration # # Old website redirect map # map $uri $new_uri { /old.html /index.html; } server { listen 80 default_server; listen [::]:80 default_server; # Old website redirect if ($new_uri) { rewrite ^ $new_uri permanent; } . . .
我们将添加两个新部分:一个在 server
块之前,一个在其中。
server
块之前的部分是一个新的 map
块,它定义了默认操作(不允许访问)以及允许访问网站的国家代码列表。 如果 map
结果表明,server
块内的部分拒绝访问网站。
修改 /etc/nginx/sites-available/default
. . . # Default server configuration # # Allowed countries # map $geoip_country_code $allowed_country { default no; country_code_1 yes; country_code_2 yes; } # Old website redirect map # map $uri $new_uri { /old.html /index.html; } server { listen 80 default_server; listen [::]:80 default_server; # Disallow access based on GeoIP if ($allowed_country = no) { return 444; } # Old website redirect if ($new_uri) { rewrite ^ $new_uri permanent; } . . .
保存并关闭文件以退出。
在这里,我们使用 country_code_1
和 country_code_2
作为占位符。 将这些变量替换为您希望加入白名单的国家/地区的两个字符国家/地区代码。 您可以使用 ISO 的所有国家代码的完整、可搜索列表 来查找。 例如,美国的两个字符代码是 US
。
与第一个示例不同,在此 map
块中,$allowed_country
变量将始终设置为某个值。 默认设置为no
; 如果 $geoip_country_code
变量与块中的国家代码之一匹配,则将其设置为 yes
。 如果 $allowed_country
变量是 no
,我们将返回 444 Connection Closed without Response,而不是为实际网站提供服务。
要启用新配置,请重新启动 Nginx。
sudo systemctl restart nginx
如果您没有将您的国家/地区添加到允许列表中,当您尝试访问 http://your_server_ip
时,您会看到类似 The page is not working 或 The page没有发送任何数据。 如果您确实将您的国家/地区添加到允许列表中,您会像以前一样看到 Home。
结论
虽然它可能是一个关于如何使用 map 模块的非常简单的示例,但它显示了可以以许多其他不同方式使用的机制。 map 模块不仅允许简单的比较,还支持正则表达式,允许更复杂的匹配。 如果必须评估多个条件,这是使配置文件更整洁的好方法。
地图模块的另一个非常流行的用例是在其他非 SSL 环境中对网站的安全部分进行条件重定向。 仅为需要密码输入的表单设置强制 SSL 连接是如何在现实世界场景中应用地图模块的一个很好的示例,我鼓励尝试这种设置。
更详细的信息可以在 Nginx 的官方地图模块文档中找到。