Nginx 虚拟主机:在单个服务器上托管多个网站
现代的 Web 基础设施通常需要能够在单个服务器实例上提供多个网站或 Web 应用程序。这不仅优化了资源利用率,还简化了管理并降低了运营成本。Nginx 以其高性能、稳定性、丰富的功能集和低资源消耗而闻名,它通过其所谓的 服务器块 (server blocks) 来实现这一目标,这在 Apache 世界中通常被称为 虚拟主机 (virtual hosts)。
本综合指南将引导您完成设置 Nginx 虚拟主机的过程,以有效地从单个 Nginx 服务器管理和提供多个不同的域名或子域名。无论您是托管 example.com 和 anothersite.org,还是一个主站点带有 blog.example.com 和 shop.example.com 等子域名,掌握 Nginx 服务器块都是任何系统管理员或开发人员的基本技能。在本文结束时,您将对如何配置 Nginx 服务器进行多站点托管有清晰的理解和实际示例。
理解 Nginx 服务器块(虚拟主机)
核心上,Nginx 的 服务器块 (server block) 是 Nginx 配置文件(nginx.conf 或包含的文件)中定义的一个配置指令。每个 server 块定义了一个特定虚拟主机的配置,指示 Nginx 如何响应对特定域或一组域的请求。Nginx 使用 listen 指令指定它应该监听的 IP 地址和端口,并使用 server_name 指令识别此服务器块应该响应的域名或主机名。
当请求到来时,Nginx 检查 HTTP 请求的 Host 头,并将其与配置的服务器块的 server_name 指令进行比较。然后,它提供匹配的服务器块中定义的内容。如果没有 server_name 匹配,Nginx 通常会回退到 默认服务器块 (default server block)(第一个 server 块或明确标记为 default_server 的块)。
先决条件
在开始之前,请确保您具备以下条件:
- Nginx 已安装:Nginx 应该已安装并在您的服务器上运行。如果尚未安装,您通常可以通过系统的包管理器进行安装(例如,在 Ubuntu/Debian 上使用
sudo apt update && sudo apt install nginx,在 CentOS/RHEL 上使用sudo yum install nginx)。 - 域名:您需要至少两个要托管的域名(例如
example1.com和example2.com)或子域名(例如blog.example.com和app.example.com)。这些域名的 DNS A/AAAA 记录必须指向您服务器的公共 IP 地址。 - 基本目录结构:您的网站文件将存放在何处。常见的做法是
/var/www/yourdomain.com/html。 - Sudo 权限:您将需要
sudo访问权限来修改 Nginx 配置文件。
分步设置指南
让我们设置两个虚拟主机:example1.com 和 example2.com。
1. 为网站创建目录结构
首先,为您的每个网站创建根目录。HTML、CSS、JavaScript 和其他静态文件将存储在此处。一个常见的存放位置是 /var/www/。
sudo mkdir -p /var/www/example1.com/html
sudo mkdir -p /var/www/example2.com/html
# 设置文件所有权给你的用户(将 $USER 替换为你的用户名),以便允许编辑
sudo chown -R $USER:$USER /var/www/example1.com/html
sudo chown -R $USER:$USER /var/www/example2.com/html
# 为 Web 服务器设置读取权限
sudo chmod -R 755 /var/www
接下来,在每个目录中创建一个简单的 index.html 文件来测试设置:
对于 /var/www/example1.com/html/index.html:
<!-- /var/www/example1.com/html/index.html -->
<!DOCTYPE html>
<html>
<head>
<title>欢迎访问 Example1.com!</title>
</head>
<body>
<h1>成功!这是 Example1.com。</h1>
<p>此虚拟主机正常工作。</p>
</body>
</html>
对于 /var/www/example2.com/html/index.html:
<!-- /var/www/example2.com/html/index.html -->
<!DOCTYPE html>
<html>
<head>
<title>欢迎访问 Example2.com!</title>
</head>
<body>
<h1>成功!这是 Example2.com。</h1>
<p>此虚拟主机也正常工作!</p>
</body>
</html>
2. 创建 Nginx 服务器块配置文件
Nginx 通常从 /etc/nginx/sites-enabled/ 目录中的文件加载服务器块配置。这些文件通常是 /etc/nginx/sites-available/ 中存储的配置的符号链接。这种分离允许您存储尚未激活的配置,或轻松启用/禁用站点。
为 example1.com 创建一个新的配置文件:
sudo nano /etc/nginx/sites-available/example1.com.conf
添加以下内容:
# /etc/nginx/sites-available/example1.com.conf
server {
listen 80;
listen [::]:80;
root /var/www/example1.com/html;
index index.html index.htm index.nginx-debian.html;
server_name example1.com www.example1.com;
location / {
try_files $uri $uri/ =404;
}
access_log /var/log/nginx/example1.com_access.log;
error_log /var/log/nginx/example1.com_error.log;
}
指令说明:
listen 80;:Nginx 监听端口 80(标准 HTTP)。listen [::]:80;用于 IPv6。root /var/www/example1.com/html;:指定此服务器块的文档根目录。Nginx 将在此目录中查找文件。index index.html ...;:定义当请求目录时(例如,当有人访问example1.com/时)Nginx 应该提供的默认文件。server_name example1.com www.example1.com;:这至关重要。它告诉 Nginx 使用此服务器块的配置来响应对example1.com或www.example1.com的请求。location / { ... }:一个定义如何处理特定 URI 请求的块。try_files尝试直接提供文件($uri),然后是目录($uri/),最后返回404 Not Found错误。access_log和error_log:为此特定站点指定单独的日志文件,这是为了更轻松地调试和分析的良好实践。
现在,为 example2.com 创建一个类似的配置文件:
sudo nano /etc/nginx/sites-available/example2.com.conf
添加以下内容:
# /etc/nginx/sites-available/example2.com.conf
server {
listen 80;
listen [::]:80;
root /var/www/example2.com/html;
index index.html index.htm index.nginx-debian.html;
server_name example2.com www.example2.com;
location / {
try_files $uri $uri/ =404;
}
access_log /var/log/nginx/example2.com_access.log;
error_log /var/log/nginx/example2.com_error.log;
}
3. 启用服务器块
要启用这些配置,请从 sites-available 目录创建到 sites-enabled 目录的符号链接。这会告诉 Nginx 在启动时包含这些文件。
sudo ln -s /etc/nginx/sites-available/example1.com.conf /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/example2.com.conf /etc/nginx/sites-enabled/
4. 测试 Nginx 配置
在重新加载之前测试 Nginx 配置是否存在语法错误至关重要。这可以防止 Nginx 因拼写错误而无法重新启动。
sudo nginx -t
您应该会看到类似以下的输出,表示成功:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
如果看到任何错误,请在相应的配置文件中修复它们,并重新运行 sudo nginx -t,直到通过。
5. 重启 Nginx
通过重新启动或重新加载 Nginx 来应用新配置。通常更推荐使用 reload,因为它允许 Nginx 在不中断活动连接的情况下加载新配置。
sudo systemctl reload nginx
# 或者,如果 reload 不起作用或对于全新安装:
sudo systemctl restart nginx
6. 更新 DNS 记录
确保 example1.com、www.example1.com、example2.com 和 www.example2.com 的 DNS A 记录都指向您的 Nginx 服务器的 IP 地址。如果没有正确的 DNS 条目,您的浏览器将不知道在哪里找到您的网站。
一旦 DNS 传播完成(可能需要几分钟到几个小时),您应该能够在 Web 浏览器中访问 http://example1.com 和 http://example2.com,并看到各自的 index.html 页面。
高级场景和最佳实践
托管子域名
托管子域名(例如 blog.example.com、shop.example.com)的工作方式与托管单独的域名完全相同。您只需使用子域名作为 server_name 定义一个新的服务器块。
blog.example.com 的示例:
# /etc/nginx/sites-available/blog.example.com.conf
server {
listen 80;
listen [::]:80;
root /var/www/blog.example.com/html;
index index.html;
server_name blog.example.com;
location / {
try_files $uri $uri/ =404;
}
}
请记住创建目录(/var/www/blog.example.com/html)、创建 index.html、创建符号链接并重新加载 Nginx。
默认服务器块
最好有一个默认服务器块,用于捕获服务器上与任何其他 server_name 指令不匹配的域名请求。这可以防止未知请求被 Nginx 找到的“第一个”虚拟主机服务,或者允许您提供一个通用的“找不到站点”页面。
通常,nginx.conf 或 sites-enabled 中的第一个 server 块隐式地是默认块。您可以使用 default_server 明确设置一个:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
# 下划线 `_` 是一个不存在的域名,永远不会匹配真实的请求。
# 您也可以使用 localhost。
root /var/www/default_site/html;
index index.html;
location / {
return 444; # 对未知主机返回 Nginx 特定的 444 错误(无响应)
# 或者,提供一个通用的着陆页:
# try_files $uri $uri/ =404;
}
}
警告:如果您定义了 default_server 块,请确保给定 listen 端口上只有一个 server 块带有 default_server 标志,否则 Nginx 将记录警告。
使用 HTTPS (SSL/TLS) 保护虚拟主机
对于生产网站,启用 HTTPS 是必不可少的。这涉及到获取 SSL/TLS 证书(例如,通过使用 Certbot 的 Let's Encrypt)并配置 Nginx 在端口 443 上监听并使用该证书。
一个典型的 HTTPS 服务器块看起来像这样(在获取证书后):
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example1.com www.example1.com;
root /var/www/example1.com/html;
index index.html;
ssl_certificate /etc/letsencrypt/live/example1.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example1.com/privkey.pem;
# 包含其他 SSL 配置(密码、协议等)
include /etc/nginx/snippets/ssl-params.conf;
include /etc/nginx/snippets/force-ssl.conf; # 可选:将 HTTP 重定向到 HTTPS
location / {
try_files $uri $uri/ =404;
}
}
# 可选:将此域的 HTTP 重定向到 HTTPS
server {
listen 80;
listen [::]:80;
server_name example1.com www.example1.com;
return 301 https://$host$request_uri;
}
通常会有一个单独的 HTTP 服务器块,其唯一目的是将所有流量重定向到其 HTTPS 对应项。
每个站点的日志记录
如示例所示,为每个虚拟主机分配单独的 access_log 和 error_log 文件是最佳实践。这使得调试问题和分析各个网站的流量变得更容易,而无需筛选组合日志。
配置文件结构
对于大型部署,请考虑按以下方式组织 Nginx 配置文件:
nginx.conf:主配置,包含conf.d/*.conf和sites-enabled/*。conf.d/:通用服务器范围设置(例如 Gzip、缓存)。snippets/:可重用的 Nginx 配置片段(例如 SSL 参数、通用location块)。sites-available/:每个网站的独立server块。sites-enabled/:指向sites-available/中活动配置的符号链接。
常见问题排查
- 403 Forbidden 错误:这通常意味着 Nginx 没有您网站文件或目录的读取权限。请仔细检查文件和目录权限(例如,
sudo chmod -R 755 /var/www/yourdomain.com/html并确保 Nginx 用户,通常是www-data或nginx,可以读取它们)。 - 404 Not Found 错误:验证服务器块中的
root指令是否指向正确的目录,以及您的index.html文件是否存在于该位置。另外,请确保try_files配置正确。 - 加载了错误的网站:这通常表示
server_name指令存在问题。确保server_name与您尝试访问的域名(包括www.或子域名)完全匹配。另外,请检查您的 DNS 记录。 - Nginx 无法启动/重新加载:在尝试重新加载或重新启动 Nginx 之前,请始终使用
sudo nginx -t测试您的配置。错误消息将指出发生语法错误的行和文件。 - DNS 问题:如果您可以通过 IP 地址访问您的网站,但不能通过域名访问,那几乎肯定是 DNS 问题。使用
dig或nslookup验证您的域名的 A 记录是否指向正确的服务器 IP。
结论
Nginx 虚拟主机(服务器块)提供了一种强大而灵活的方式,可以在单个服务器上托管多个网站。通过使用适当的 listen、server_name、root 和 location 指令正确配置 server 块,您可以有效地管理各种 Web 资产。这种方法不仅节省了资源,还集中了服务器管理。
凭借本指南中概述的基础知识和实践步骤,您现在已能够设置和管理 Nginx 服务器上的多个域。请记住,始终测试您的配置,使用 HTTPS 保护您的站点,并遵循日志记录和目录结构的最佳实践,以构建健壮且可维护的 Web 环境。从这里开始,您可以进一步探索 Nginx 的功能,如反向代理、负载均衡和缓存,以增强您的 Web 服务器的性能和可靠性。