虚拟主机
虚拟主机允许在一台服务器上托管多个网站。本章将介绍如何配置 Nginx 虚拟主机。
什么是虚拟主机?
虚拟主机(Virtual Host)是在一台物理服务器上运行多个网站的技术。Nginx 通过 server 块实现虚拟主机,根据请求的域名或端口将请求路由到不同的网站配置。
虚拟主机类型
- 基于域名:不同域名指向同一 IP
- 基于端口:同一域名,不同端口
- 基于 IP:不同 IP 地址
基于域名的虚拟主机
基本配置
# 网站 1:example.com
server {
listen 80;
server_name example.com www.example.com;
root /var/www/example;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
}
# 网站 2:blog.com
server {
listen 80;
server_name blog.com www.blog.com;
root /var/www/blog;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
}
解释:
- 每个
server块代表一个虚拟主机 server_name指定域名root指定网站根目录- Nginx 根据请求的
Host头选择对应的配置
多域名配置
server {
listen 80;
# 多个域名
server_name example.com
www.example.com
example.net
www.example.net;
root /var/www/example;
location / {
try_files $uri $uri/ /index.html;
}
}
通配符域名
# 匹配所有子域名
server {
listen 80;
server_name *.example.com;
root /var/www/subdomains;
# 根据子域名动态设置目录
location / {
# $1 是正则捕获的子域名部分
root /var/www/$1;
}
}
基于端口的虚拟主机
不同端口配置
# 端口 80
server {
listen 80;
server_name example.com;
root /var/www/main;
location / {
try_files $uri $uri/ /index.html;
}
}
# 端口 8080
server {
listen 8080;
server_name example.com;
root /var/www/admin;
location / {
try_files $uri $uri/ /index.html;
}
}
# 端口 8443
server {
listen 8443 ssl;
server_name example.com;
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
root /var/www/secure;
location / {
try_files $uri $uri/ /index.html;
}
}
基于 IP 的虚拟主机
不同 IP 配置
# IP 192.168.1.101
server {
listen 192.168.1.101:80;
server_name example.com;
root /var/www/example;
}
# IP 192.168.1.102
server {
listen 192.168.1.102:80;
server_name blog.com;
root /var/www/blog;
}
默认服务器配置
设置默认服务器
当请求不匹配任何 server_name 时,使用默认服务器:
# 默认服务器(捕获所有未匹配的请求)
server {
listen 80 default_server;
server_name _;
# 返回 404 或重定向
return 444; # 关闭连接
# 或
return 301 https://example.com$request_uri;
}
# 正常服务器
server {
listen 80;
server_name example.com;
root /var/www/example;
}
解释:
default_server指定默认服务器server_name _是一个无效域名,只匹配默认服务器- 返回 444 会直接关闭连接,不返回任何响应
目录结构组织
推荐的目录结构
/var/www/
├── example.com/
│ ├── public/
│ │ ├── index.html
│ │ ├── css/
│ │ └── js/
│ └── logs/
│ ├── access.log
│ └── error.log
├── blog.com/
│ ├── public/
│ │ ├── index.html
│ │ └── ...
│ └── logs/
└── api.example.com/
├── public/
└── logs/
配置文件组织
/etc/nginx/
├── nginx.conf # 主配置
├── conf.d/
│ ├── example.com.conf # example.com 配置
│ ├── blog.com.conf # blog.com 配置
│ └── api.example.com.conf # API 配置
└── ssl/
├── example.com.pem
└── example.com.key
主配置文件
# /etc/nginx/nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent"';
access_log /var/log/nginx/access.log main;
sendfile on;
keepalive_timeout 65;
gzip on;
# 包含所有虚拟主机配置
include /etc/nginx/conf.d/*.conf;
}
站点配置示例
# /etc/nginx/conf.d/example.com.conf
server {
listen 80;
server_name example.com www.example.com;
# 重定向到 HTTPS
return 301 https://example.com$request_uri;
}
server {
listen 443 ssl http2;
server_name example.com www.example.com;
# SSL 配置
ssl_certificate /etc/nginx/ssl/example.com.pem;
ssl_certificate_key /etc/nginx/ssl/example.com.key;
# 网站根目录
root /var/www/example.com/public;
index index.html index.php;
# 日志
access_log /var/www/example.com/logs/access.log;
error_log /var/www/example.com/logs/error.log;
# 网站配置
location / {
try_files $uri $uri/ /index.html;
}
# 静态资源
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
# 禁止访问隐藏文件
location ~ /\. {
deny all;
}
}
实际场景配置
场景 1:个人博客
server {
listen 80;
server_name blog.example.com;
root /var/www/blog;
index index.html;
# 静态博客(如 Hexo、Hugo)
location / {
try_files $uri $uri/ =404;
}
# 文章页
location /posts/ {
try_files $uri $uri/ /posts/index.html;
}
# 静态资源缓存
location ~* \.(jpg|jpeg|png|gif|css|js|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}
场景 2:前后端分离
# 前端(Vue/React)
server {
listen 80;
server_name example.com;
root /var/www/frontend/dist;
index index.html;
# SPA 路由
location / {
try_files $uri $uri/ /index.html;
}
# API 代理
location /api/ {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# 静态资源
location /assets/ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}
场景 3:WordPress 站点
server {
listen 80;
server_name wordpress.example.com;
root /var/www/wordpress;
index index.php index.html;
# WordPress 固定链接
location / {
try_files $uri $uri/ /index.php?$args;
}
# PHP 处理
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.1-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
# 增加缓冲区
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
}
# 静态资源
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
# 禁止访问敏感文件
location ~* /(?:uploads|files)/.*\.php$ {
deny all;
}
# 禁止访问隐藏文件
location ~ /\. {
deny all;
}
}
场景 4:子目录部署多个应用
server {
listen 80;
server_name example.com;
# 主站点
root /var/www/main;
location / {
try_files $uri $uri/ /index.html;
}
# 博客子目录
location /blog/ {
alias /var/www/blog/;
try_files $uri $uri/ /blog/index.html;
}
# 管理后台
location /admin/ {
alias /var/www/admin/;
try_files $uri $uri/ /admin/index.html;
}
# API 服务
location /api/ {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
}
}
最佳实践
1. 使用配置片段
创建可复用的配置片段:
# /etc/nginx/snippets/ssl-params.conf
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
引用配置片段:
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/nginx/ssl/example.com.pem;
ssl_certificate_key /etc/nginx/ssl/example.com.key;
# 引入 SSL 配置
include /etc/nginx/snippets/ssl-params.conf;
}
2. 日志分离
server {
# 每个站点独立日志
access_log /var/log/nginx/example.com.access.log;
error_log /var/log/nginx/example.com.error.log;
}
3. 错误页面
server {
# 自定义错误页面
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /404.html {
root /var/www/errors;
internal;
}
location = /50x.html {
root /var/www/errors;
internal;
}
}
4. 安全头
server {
# 安全响应头
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self'" always;
}
5. 隐藏版本信息
# 在 http 块中
server_tokens off;
# 或在主配置文件中的 http 块
常见问题
1. 域名解析问题
# 测试域名解析
nslookup example.com
dig example.com
# 检查本地 hosts 文件
cat /etc/hosts
2. 配置冲突
# 检查配置语法
nginx -t
# 检查站点配置
nginx -T | grep server_name
3. 目录权限
# 设置正确权限
sudo chown -R nginx:nginx /var/www/example.com
sudo chmod -R 755 /var/www/example.com
小结
本章我们学习了:
- 虚拟主机的概念和类型
- 基于域名的虚拟主机配置
- 基于端口的虚拟主机配置
- 默认服务器设置
- 配置文件组织方式
- 实际场景配置示例
- 最佳实践和安全建议
练习
- 配置两个基于域名的虚拟主机
- 配置一个前后端分离的站点
- 添加自定义错误页面
- 配置安全响应头