深入理解 Nginx server_name
:原理、配置与最佳实践
Nginx 是当今互联网上最流行的高性能 Web 服务器之一。它以其高并发处理能力、低内存占用和丰富的功能模块而闻名。在 Nginx 的众多配置指令中,server_name
是一个核心且至关重要的指令,尤其在使用 Nginx 进行虚拟主机托管时。理解 server_name
的工作原理和正确配置方法,对于构建高效、灵活的网站服务架构至关重要。
本文将详细探讨 server_name
的方方面面,从其基本概念、不同匹配类型、优先级规则,到默认服务器的处理,以及如何结合实际场景进行配置。
1. server_name
的基本概念:为什么需要它?
想象一下,你有一台服务器,它有一个公网 IP 地址(例如 203.0.113.10
)。你希望在这台服务器上同时托管多个不同的网站,比如 www.example.com
、blog.mydomain.org
和 app.anothersite.net
。当用户在浏览器中输入 www.example.com
并按下回车时,浏览器会首先将域名解析为对应的 IP 地址 (203.0.113.10
),然后向这个 IP 地址的默认 HTTP 端口(通常是 80 或 443)发送一个 HTTP 请求。
服务器收到了这个请求,但它怎么知道这个请求是给 www.example.com
的,而不是给 blog.mydomain.org
或 app.anothersite.net
的呢?这就是 server_name
指令发挥作用的地方。
HTTP/1.1 协议引入了一个重要的请求头叫做 Host
。当浏览器发送 HTTP 请求时,它会在请求头中包含 Host
字段,指明用户尝试访问的域名。例如:
GET /index.html HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0 (...)
...
Nginx 服务器在接收到来自 203.0.113.10:80
的连接后,会读取请求中的 Host
头字段的值。然后,它会查找其配置中所有监听在 203.0.113.10:80
端口的 server
块。对于每个这样的 server
块,Nginx 会检查其 server_name
指令中配置的名称列表,看是否有任何一个名称与请求的 Host
头完全匹配、部分匹配(通配符)或通过正则表达式匹配。
server_name
指令的作用就是为 server
块定义一个或多个域名或 IP 地址,告诉 Nginx:如果收到的请求的 Host
头是这些名称之一,那么就由这个 server
块来处理这个请求。
简单来说,server_name
是 Nginx 用于区分同一 IP 地址和端口上不同虚拟主机的“门牌号”。
一个 server
块是 Nginx 配置中用于定义一个虚拟主机的上下文。它通常包含 listen
指令(指定监听的 IP 和端口)、server_name
指令(指定该虚拟主机响应的域名)、root
指令(指定网站根目录)、location
指令(定义如何处理不同 URL 路径的请求)等等。
典型的 server
块结构如下:
“`nginx
server {
listen 80; # 监听在所有接口的80端口
server_name example.com www.example.com; # 定义该server块响应的域名
root /var/www/example.com; # 网站根目录
location / {
index index.html index.htm;
try_files $uri $uri/ =404;
}
# ... 其他配置
}
“`
在这个例子中,当 Nginx 收到一个指向服务器 80 端口,且 Host
头是 example.com
或 www.example.com
的请求时,它会选择这个 server
块来处理。
2. server_name
的匹配类型
server_name
指令支持三种主要的名称匹配类型:
- 精确名称 (Exact Names)
- 通配符名称 (Wildcard Names)
- 正则表达式 (Regular Expressions)
理解这三种类型的语法和用途是正确配置 server_name
的基础。
2.1 精确名称 (Exact Names)
这是最简单也是最常用的类型。你直接指定一个或多个完整的域名或 IP 地址。
语法:
nginx
server_name name1 name2 ...;
示例:
“`nginx
server {
listen 80;
server_name www.example.com example.com; # 精确匹配 www.example.com 或 example.com
# …
}
server {
listen 80;
server_name blog.mydomain.org; # 精确匹配 blog.mydomain.org
# …
}
server {
listen 80;
server_name 192.168.1.10; # 精确匹配 IP 地址 (如果用户直接通过IP访问)
# …
}
“`
在 server_name
中列出多个名称是非常常见的,因为一个网站可能通过多个域名访问(例如带 www
和不带 www
的域名)。
2.2 通配符名称 (Wildcard Names)
通配符允许匹配一系列相似的域名。通配符 *
可以出现在域名的开头或结尾,但不能出现在中间。
2.2.1 开头通配符 (Leading Wildcard)
语法:*.example.com
这会匹配 a.example.com
、b.example.com
、foo.example.com
等,但不会匹配 example.com
本身(即不包含子域名的裸域名)。
示例:
nginx
server {
listen 80;
server_name *.example.com; # 匹配所有 example.com 的二级子域名
# ...
}
如果你想同时匹配裸域名和所有二级子域名,你需要同时指定:
nginx
server {
listen 80;
server_name example.com *.example.com; # 同时匹配 example.com 和它的所有二级子域名
# ...
}
2.2.2 结尾通配符 (Trailing Wildcard)
语法:mail.*
这会匹配 mail.example.com
、mail.mydomain.org
等。
示例:
nginx
server {
listen 80;
server_name mail.*; # 匹配所有以 mail. 开头的域名
# ...
}
2.2.3 通配符的限制
- 通配符
*
只能代表一个或多个字符,且不能跨越点(.
)。例如,*.example.com
不会匹配a.b.example.com
。 *
不能出现在域名的中间,例如www.*.com
是无效的(虽然在某些特殊情况下可能被解释,但不推荐且不如正则灵活)。*
也不能代表空字符串。*.example.com
不会匹配example.com
。
2.3 正则表达式 (Regular Expressions)
对于更复杂的匹配模式,可以使用正则表达式。正则表达式匹配的 server_name
必须以波浪号 ~
开头。
语法:~ regex;
示例:
“`nginx
server {
listen 80;
server_name ~^www\d+.example.com$; # 匹配 www1.example.com, www2.example.com 等
# …
}
server {
listen 80;
server_name ~^(?
# …
# 在location块中使用捕获的变量,例如:
# location / {
# root /var/www/example.com/sites/$subdomain;
# }
}
“`
正则表达式注意事项:
- 正则表达式需要以
~
开头。 - 如果需要在正则表达式中使用特殊字符(如
.
,*
,?
,+
,^
,$
,|
,(
,)
,[
,]
,{
,}
,\
),需要使用反斜杠\
进行转义。例如,要匹配字面意义的点,需要写\.
。 ^
匹配字符串的开始,$
匹配字符串的结束。使用^
和$
可以确保正则表达式匹配整个Host
字符串,避免意外的部分匹配。- 可以使用命名捕获组
(?<name>...)
或数字捕获组(...)
将匹配的部分存储到变量中(例如$name
或$1
,$2
等),以便在其他指令中使用(如root
,proxy_pass
,rewrite
)。 - 正则表达式匹配的优先级比精确名称和通配符名称低(详见下一节)。
- 大量的正则表达式匹配可能会对性能产生轻微影响,但在大多数情况下可以忽略不计。
3. server_name
的匹配顺序和优先级
当一个请求到达 Nginx 并且 Host
头与多个 server
块的 server_name
指令都可能匹配时,Nginx 会按照一个严格的优先级顺序来选择最终由哪个 server
块来处理请求。这个顺序是固定的:
-
精确名称匹配 (Exact Name): Nginx 会首先尝试找到与
Host
头完全一致的server_name
。如果找到一个或多个精确匹配的server
块(例如,如果同一个名称意外地出现在了多个server
块中,但这通常应避免),Nginx 会选择第一个匹配的server
块。这是最高优先级的匹配。 -
最长的开头通配符匹配 (Longest Wildcard Starting with
*
): 如果没有找到精确匹配,Nginx 会查找以*
开头、且匹配Host
头的通配符名称中,最长的那一个。例如,对于Host: a.b.example.com
,*.example.com
和*.b.example.com
都可能匹配。Nginx 会选择*.b.example.com
,因为它更长(更具体)。 -
最长的结尾通配符匹配 (Longest Wildcard Ending with
*
): 如果没有找到精确匹配或开头通配符匹配,Nginx 会查找以*
结尾、且匹配Host
头的通配符名称中,最长的那一个。例如,对于Host: www.example.com
,www.*
可能匹配。 -
第一个正则表达式匹配 (First Matching Regular Expression): 如果以上所有类型都没有找到匹配项,Nginx 会按照配置文件中
server
块出现的顺序,尝试匹配使用正则表达式定义的server_name
。它会使用第一个找到的匹配项。
重要规则:
- Nginx 只会执行一次匹配过程。一旦找到一个匹配项(无论是精确、通配符还是正则),它就会停止搜索,并使用找到的第一个
server
块来处理请求。 - 这个匹配顺序是硬编码在 Nginx 中的,不受配置中
server
块出现顺序的影响(除了正则表达式匹配,它按照配置文件中的顺序)。 - 优先级从高到低是:精确名称 > 最长开头通配符 > 最长结尾通配符 > 第一个正则表达式。
示例说明优先级:
假设你有以下配置片段(为了简化,省略了 location 等内部配置):
“`nginx
server_config.conf
server {
listen 80;
server_name example.com; # 精确名称 (P1)
# … A
}
server {
listen 80;
server_name *.example.com; # 开头通配符 (P2)
# … B
}
server {
listen 80;
server_name mail.*; # 结尾通配符 (P3)
# … C
}
server {
listen 80;
server_name ~^www\d+.example.com$; # 正则表达式 (P4)
# … D
}
server {
listen 80;
server_name sub.example.com; # 精确名称 (P5)
# … E
}
server {
listen 80;
server_name *.sub.example.com; # 开头通配符 (P6)
# … F
}
server {
listen 80;
server_name ~^test.example.com$; # 正则表达式 (P7)
# … G
}
“`
现在看看不同的 Host
头会匹配哪个 server
块:
Host: example.com
: 精确匹配到server_name example.com;
的块 A。这是最高优先级。Host: sub.example.com
: 精确匹配到server_name sub.example.com;
的块 E。这是最高优先级。Host: www.example.com
: 没有精确匹配。查找开头通配符:*.example.com
(块 B) 匹配。它是最长的开头通配符(只有一个)。匹配块 B。Host: a.b.example.com
: 没有精确匹配。查找开头通配符:*.example.com
(块 B) 匹配。*.sub.example.com
(块 F) 不匹配a.b.example.com
。所以匹配块 B。Host: test.sub.example.com
: 没有精确匹配。查找开头通配符:*.example.com
(块 B) 匹配。*.sub.example.com
(块 F) 也匹配。*.sub.example.com
(块 F) 比*.example.com
(块 B) 长。所以匹配块 F。Host: mail.example.com
: 没有精确匹配。没有开头通配符匹配。查找结尾通配符:mail.*
(块 C) 匹配。匹配块 C。Host: www1.example.com
: 没有精确匹配,没有通配符匹配。查找正则表达式:~^www\d+\.example\.com$;
(块 D) 匹配。匹配块 D。Host: test.example.com
: 没有精确匹配,没有通配符匹配。查找正则表达式:~^www\d+\.example\.com$;
(块 D) 不匹配。~^test\.example\.com$;
(块 G) 匹配。匹配块 G。注意,虽然块 D在配置文件中先出现,但只有匹配了的正则表达式才参与考虑。如果有多个正则表达式都匹配,才会选择第一个出现的。
理解这个优先级顺序对于避免配置错误和确保请求被正确路由至关重要。
4. 默认服务器 (Default Server)
当一个请求到达 Nginx,但其 Host
头与所有监听在相同 IP 和端口的 server
块的 server_name
都不匹配时,Nginx 需要一个“兜底”的 server
块来处理这个请求。这个“兜底”的 server
块就被称为该 IP/端口对的默认服务器 (Default Server)。
以下情况可能会导致请求被默认服务器处理:
- 客户端使用 IP 地址直接访问服务器(例如
http://203.0.113.10/
),并且Host
头是 IP 地址,而你的server_name
配置的都是域名。 - 请求的
Host
头是一个你没有在任何server_name
中配置的域名。 - 客户端发送的请求不包含
Host
头(这种情况很少见,通常是恶意或非标准客户端)。 - 对于 HTTPS 请求,如果客户端不支持 SNI(Server Name Indication),Nginx 在 SSL 握手阶段无法确定要访问的域名,可能会将请求路由到默认服务器(通常是该端口配置的第一个支持 SSL 的
server
块)。
如何指定默认服务器?
对于每个 listen
指令监听的 IP/端口对,Nginx 都会有一个默认服务器。指定默认服务器有两种方式:
- 隐式默认服务器: 如果你没有显式指定哪个
server
块是默认服务器,Nginx 会将监听在该 IP/端口对的配置中第一个出现的server
块视为默认服务器。这个“第一个”是指在 Nginx 加载配置文件时遇到的第一个server
块。 - 显式默认服务器: 你可以在
listen
指令后面加上default_server
参数来明确指定某个server
块作为默认服务器。
“`nginx
server {
listen 80 default_server; # 将此server块设为默认服务器
server_name ; # 通常使用一个不可能的域名,如 ‘‘,作为默认服务器的server_name
# … 此处配置处理所有不匹配其他server_name的请求
return 444; # 例如,返回444连接关闭(Nginx特有)或403禁止访问
}
server {
listen 80;
server_name example.com www.example.com; # 正常网站
# …
}
server {
listen 80;
server_name blog.mydomain.org; # 另一个网站
# …
}
“`
在这个例子中,第一个 server
块通过 default_server
参数被明确指定为监听 80 端口的默认服务器。任何到达 80 端口但 Host
头既不是 example.com
或 www.example.com
,也不是 blog.mydomain.org
的请求,都将被第一个 server
块处理。这里 server_name _;
的用法很常见,_
是一个无效的域名,永远不会与实际的 Host
头匹配,所以它确保这个 server
块只会被作为默认服务器选中(在 server_name
匹配阶段永远不会成功),而不会意外地通过 server_name
匹配到某些奇怪的 Host
头。
显式指定默认服务器的好处:
- 清晰性: 配置意图明确,易于理解和维护。
- 可控性: 你可以精确控制不匹配的请求如何处理,例如直接拒绝、重定向到主站、显示错误页面等。
- 安全性: 防止未知域名或直接 IP 访问暴露你的正常网站内容。
强烈建议总是显式地为一个 listen
IP/端口对配置一个默认服务器。
5. server_name
配置示例
下面提供一些更全面的配置示例,展示不同场景下 server_name
的用法。
示例 1:两个不同的网站在同一个 IP 和端口
“`nginx
/etc/nginx/sites-available/example.conf
server {
listen 80;
listen [::]:80; # 同时监听IPv4和IPv6
server_name example.com www.example.com;
root /var/www/example.com/html;
index index.html index.htm;
location / {
try_files $uri $uri/ =404;
}
error_page 404 /404.html;
location = /404.html {
internal;
}
access_log /var/log/nginx/example.access.log;
error_log /var/log/nginx/example.error.log;
}
/etc/nginx/sites-available/mydomain.conf
server {
listen 80;
listen [::]:80;
server_name mydomain.org www.mydomain.org;
root /var/www/mydomain.org/html;
index index.html index.htm;
location / {
try_files $uri $uri/ =404;
}
access_log /var/log/nginx/mydomain.access.log;
error_log /var/log/nginx/mydomain.error.log;
}
/etc/nginx/sites-available/default.conf (作为默认服务器处理未知请求)
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
# 直接返回444,关闭连接,不发送任何响应
return 444;
# 或者返回一个简单的错误页面
# root /var/www/default/html;
# index index.html;
# location / {
# # 可以在这里放一个简单的 index.html 说明“未知站点”
# try_files $uri $uri/ =404; # 或者直接 return 403;
# }
access_log /var/log/nginx/default.access.log;
error_log /var/log/nginx/default.error.log;
}
``
include /etc/nginx/sites-enabled/*;
确保这些配置文件通过等方式被 Nginx 主配置文件包含。通过符号链接将文件从
sites-available链接到
sites-enabled` 是标准做法。
sudo ln -s /etc/nginx/sites-available/example.conf /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/mydomain.conf /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/default.conf /etc/nginx/sites-enabled/
sudo nginx -t
sudo nginx -s reload
示例 2:使用通配符处理所有二级子域名
假设你想让所有 *.sub.example.com
的请求都指向同一个应用,但 example.com
和 www.example.com
指向主站。
“`nginx
server {
listen 80;
server_name example.com www.example.com; # 精确匹配主站
root /var/www/example.com/html;
# … 主站配置
}
server {
listen 80;
server_name *.sub.example.com; # 匹配所有 sub.example.com 的二级子域名
root /var/www/sub.example.com/html; # 或者根据子域名动态调整 root
# … 子域名站配置
}
别忘了默认服务器
server {
listen 80 default_server;
server_name _;
return 444;
}
“`
示例 3:使用正则表达式捕获子域名并动态处理
假设你想让所有 *.users.example.com
的请求都指向 /var/www/users/
目录下以子域名命名的文件夹。
“`nginx
server {
listen 80;
server_name ~^(?
# 动态设置根目录
root /var/www/users/$username;
index index.html;
location / {
try_files $uri $uri/ =404;
}
access_log /var/log/nginx/users_$username.access.log; # 日志文件也可以动态命名
error_log /var/log/nginx/users_$username.error.log;
}
别忘了其他 server 块,比如主站和默认服务器
server {
listen 80;
server_name example.com www.example.com;
root /var/www/example.com/html;
# … 主站配置
}
server {
listen 80 default_server;
server_name _;
return 444;
}
``
server
通过正则表达式捕获变量,可以在块内部的
location、
root、
proxy_pass` 等指令中引用这些变量,实现非常灵活的配置。
6. server_name
与 listen
的交互
server_name
的匹配过程总是发生在 Nginx 已经确定了请求是到达了哪个 listen
地址和端口之后。
一个 listen
指令可以定义一个或多个 IP 地址和端口组合。例如:
* listen 80;
:监听所有可用网络接口的 80 端口。
* listen 192.168.1.10:80;
:只监听特定 IP 地址的 80 端口。
* listen [::]:80;
:监听所有可用 IPv6 接口的 80 端口。
* listen 80 ssl;
:监听 80 端口并启用 SSL/TLS (虽然标准 HTTPS 端口是 443,但这语法是有效的)。
* listen 443 ssl;
:监听 443 端口并启用 SSL/TLS。
当一个请求到达服务器的某个 IP 地址和端口时,Nginx 会查看所有配置中包含该 IP 和端口组合的 listen
指令的 server
块。然后,它会在这些 server
块中,根据请求的 Host
头和 server_name
的匹配规则及优先级,选择一个最终的 server
块来处理请求。
特别注意 HTTPS (SSL/TLS) 和 SNI:
对于 HTTPS 请求,情况稍微复杂一些。SSL/TLS 握手发生在 HTTP 请求(包括 Host
头)发送之前。在传统的 HTTPS 设置中,一个 IP 地址/端口对只能绑定一个 SSL 证书,这意味着如果你的多个网站都使用 HTTPS,并且你需要不同的证书(这是常见的,因为证书通常与域名绑定),你就需要为每个 HTTPS 网站分配一个独立的 IP 地址。
然而,SNI (Server Name Indication) 扩展解决了这个问题。SNI 允许浏览器在 SSL 握手过程中告知服务器它尝试访问的域名。Nginx 支持 SNI。当收到支持 SNI 的客户端的 HTTPS 请求时,Nginx 在进行 SSL 握手时就可以获取到客户端想要访问的域名,并据此选择正确的 server
块,从而提供正确的 SSL 证书。这样,你就可以在同一个 IP 地址和 443 端口上托管多个使用不同证书的 HTTPS 网站了。
在这种情况下,Nginx 首先使用 SNI 提供的域名来选择 server
块,以便完成 SSL 握手并提供正确的证书。然后,在接收到加密后的 HTTP 请求后,它会再次使用 Host
头(通常与 SNI 提供的域名相同)来确认选择哪个 server
块(如果 SNI 匹配到了多个 server 块,或者 SNI 不可用/与 Host 不符,会回退到 server_name
匹配逻辑,或使用默认服务器)。
配置 HTTPS 虚拟主机:
“`nginx
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name example.com www.example.com;
ssl_certificate /etc/nginx/ssl/example.com.crt;
ssl_certificate_key /etc/nginx/ssl/example.com.key;
# ... 其他 SSL/TLS 配置
# ... 网站配置
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name mydomain.org www.mydomain.org;
ssl_certificate /etc/nginx/ssl/mydomain.org.crt;
ssl_certificate_key /etc/nginx/ssl/mydomain.org.key;
# ... 其他 SSL/TLS 配置
# ... 网站配置
}
HTTPS 默认服务器
server {
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
server_name _;
# 通常需要为默认服务器配置一个 SSL 证书,否则不支持 SNI 的客户端无法连接
ssl_certificate /etc/nginx/ssl/default.crt; # 可以是一个通用证书或自签名证书
ssl_certificate_key /etc/nginx/ssl/default.key;
return 444; # 或者返回一个错误页面
}
``
default_server
注意,即使对于,如果它监听的是带有
ssl参数的端口,通常也需要配置
ssl_certificate和
ssl_certificate_key。这是因为在某些情况下(如不支持 SNI 的客户端),Nginx 必须在知道
Host` 头之前就完成 SSL 握手,此时它会使用默认服务器配置的证书。
7. 常见问题与故障排除
理解 server_name
的工作原理有助于解决许多常见的 Nginx 配置问题。
- 请求总是被默认服务器处理: 这意味着请求的
Host
头没有匹配到任何一个非默认server
块的server_name
。检查以下几点:- 客户端发送的
Host
头是否正确?使用curl -v http://your_domain.com/
命令查看请求头。 server_name
配置是否有拼写错误?- 如果使用了通配符或正则表达式,语法是否正确?它们是否真的匹配了预期的
Host
头? - 请求是否到达了 Nginx 正在监听的正确 IP 和端口?
- 客户端发送的
- 请求被错误的
server
块处理: 这通常是因为对server_name
的匹配优先级理解有误。回顾优先级顺序:精确 > 最长开头通配符 > 最长结尾通配符 > 第一个正则表达式。检查是否存在优先级更高的server_name
无意中匹配了请求。 - 直接 IP 访问暴露了敏感网站内容: 这是因为默认服务器没有得到妥善处理。确保为每个
listen
IP/端口对配置了明确的default_server
,并且该默认服务器的server_name
使用_
或其他不可能的名称,同时配置了适当的响应(如返回 403 或 444)。 - 修改配置后不生效: 每次修改 Nginx 配置文件后,都需要先通过
sudo nginx -t
检查语法错误,然后使用sudo nginx -s reload
安全地重新加载配置,或者使用sudo systemctl reload nginx
(systemd 系统)。 - 日志分析: Nginx 的访问日志 (
access_log
) 和错误日志 (error_log
) 是非常有用的诊断工具。配置不同的server
块使用不同的访问日志文件,可以清楚地看到哪些请求被哪个server
块处理了。检查错误日志,看是否有关于server_name
解析或其他配置问题的警告或错误信息。
8. server_name
中的特殊值
""
(空字符串):server_name "";
可以用于匹配不带Host
头的请求。然而,大多数现代客户端都会发送Host
头,即使是直接通过 IP 访问,某些客户端也会将 IP 地址作为Host
头的值。这个用法不如default_server
和server_name _;
常见或灵活,且有兼容性问题。通常不推荐使用。_
(下划线):server_name _;
是一个非常常用的技巧。因为它是一个无效的域名,永远不会与实际的域名匹配(除非客户端发送了字面意义的Host: _
头,这极不可能)。因此,它常用于默认服务器,确保该server
块只有在没有其他server_name
匹配时才会被选中。结合listen ... default_server;
是最佳实践。
9. 结论
server_name
指令是 Nginx 实现虚拟主机功能的基石。通过精确名称、通配符和正则表达式,Nginx 能够灵活地根据客户端请求的 Host
头将流量路由到不同的 server
块,从而在同一台服务器上托管多个网站。
深入理解 server_name
的匹配优先级是避免配置错误的关键所在:精确名称 > 最长开头通配符 > 最长结尾通配符 > 第一个正则表达式。
同时,为每个监听的 IP/端口对配置一个明确的 default_server
是一个重要的最佳实践,它能够确保所有未匹配的请求都能得到预期的处理,提高服务器的安全性和可维护性。通常结合 server_name _;
使用,并配置合适的返回码(如 403 或 444)。
掌握 server_name
的原理和配置技巧,对于任何希望充分利用 Nginx 强大功能的系统管理员或开发者来说,都是必不可少的技能。通过精心设计 server_name
和 listen
配置,你可以构建出稳定、高效且易于管理的 Web 服务架构。