本文记录一套只作用于单个站点的 Nginx 访问限制配置。
目标如下:
- 允许指定 CDN 域名访问
- 允许指定 IP 访问
- 其他请求直接返回
403 - 不影响
Let's Encrypt自动续期
一、http 块新增映射
先在 nginx.conf 的 http 块加入域名和 IP 的白名单映射。
....
http {
# 取 CDN 回源时的原始 Host
map $http_x_forwarded_host $original_host {
default $http_x_forwarded_host;
'' $host;
}
# 域名白名单
map $original_host $allowed_domain {
default 0;
include /www/wwwroot/limit/domain_map.conf;
}
# IP 白名单
geo $remote_addr $allowed_ip {
default 0;
include /www/wwwroot/limit/allow_ips_geo.conf;
}
....
}这样后续增删域名和 IP 时,只需要改独立文件,不用反复修改主配置。
二、站点配置中的修改位置
把这段加在目标站点 server 块里,建议放在 root 后面、其他访问规则之前:
....
server {
index index.php index.html index.htm;
root /www/wwwroot/example-site/public;
# 证书验证路径 - 必须在访问控制之前,允许所有访问
location ~ \.well-known/acme-challenge {
allow all;
default_type "text/plain";
}
#访问控制-START
set $access_allowed 0;
# 检查域名白名单
if ($allowed_domain = 1) {
set $access_allowed 1;
}
# 检查IP白名单
if ($allowed_ip = 1) {
set $access_allowed 1;
}
# 证书验证路径豁免
if ($uri ~* "^/\.well-known/acme-challenge/") {
set $access_allowed 1;
}
if ($access_allowed = 0) {
return 403;
}
#访问控制-END
include /www/server/panel/vhost/nginx/extension/www.example.com/*.conf;
....
}三、domain_map.conf 的匹配方式
这里用的是 map 的匹配方式,常用写法有两类:
- 精确匹配
- 正则匹配
实际使用中,最常见的一类写法是:
^(([a-zA-Z0-9-]+\.)*)?example\.com$ 1;属于正则匹配,含义是:
- 匹配任意一级子域名和根域名
另外几种常见用法示例如下:
# 匹配所有子域名,不匹配根域名
~*\.example\.com$ 1;
# 匹配根域名
example.com 1;
# 匹配固定子域名
cdn.example.com 1;
# 匹配带前缀的子域名
~*^img-[a-z0-9]+\.example\.com$ 1;
# 只匹配任意一级子域名
~*^[^.]+\.example\.com$ 1;一个更完整的 domain_map.conf 示例:
~*\.example\.com$ 1;
example.com 1;
cdn.example.com 1;
~*^img-[a-z0-9]+\.example\.com$ 1;
~*^[^.]+\.static\.example\.com$ 1;如果回源域名不止一个,继续往这个文件追加即可。
四、allow_ips_geo.conf 示例
格式:
# 单个 IP
198.51.100.21 1;
198.51.100.34 1;
# 一个网段
203.0.113.0/24 1;如果只需要放行少量固定 IP,直接一行一个即可;如果是一整段出口地址,直接写 CIDR 会更方便。
五、应用配置
修改完成后执行:
nginx -t
nginx -s reload如果 nginx -t 没通过,先修正报错,再 reload。
六、关键点
这套写法的重点有两个:
- 域名和 IP 白名单拆到独立文件中维护
/.well-known/acme-challenge/必须在访问控制之前放行,否则证书自动续期会失败