Nginx 虚拟主机配置

Virtual Host Configuration

概述

虚拟主机允许在单个服务器上托管多个网站或应用程序。Nginx提供了灵活强大的虚拟主机配置功能,支持基于域名、IP地址和端口的虚拟主机。本文将详细介绍各种虚拟主机配置方法。

1. 虚拟主机基础概念

1.1 虚拟主机类型

虚拟主机类型:
├── 基于域名 (Name-based)
│   ├── 单域名
│   ├── 多域名
│   └── 通配符域名
├── 基于IP (IP-based)
├── 基于端口 (Port-based)
└── 混合模式

1.2 配置文件组织结构

/etc/nginx/
├── nginx.conf                    # 主配置文件
├── sites-available/              # 可用站点配置
│   ├── default
│   ├── example.com
│   ├── blog.example.com
│   └── api.example.com
├── sites-enabled/                # 启用站点配置(符号链接)
│   ├── default -> ../sites-available/default
│   └── example.com -> ../sites-available/example.com
└── conf.d/                       # 其他配置文件
    └── ssl-params.conf

2. 基于域名的虚拟主机

2.1 单域名配置

# /etc/nginx/sites-available/example.com
server {
    listen 80;
    listen [::]:80;

    server_name example.com;

    root /var/www/example.com;
    index index.html index.htm index.php;

    # 日志配置
    access_log /var/log/nginx/example.com.access.log;
    error_log /var/log/nginx/example.com.error.log;

    location / {
        try_files $uri $uri/ =404;
    }

    # PHP支持
    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }

    # 静态文件缓存
    location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    # 安全配置
    location ~ /\.ht {
        deny all;
    }
}

2.2 多域名配置

# 主域名和www域名
server {
    listen 80;
    listen [::]:80;

    server_name example.com www.example.com;

    root /var/www/example.com;
    index index.html index.htm;

    location / {
        try_files $uri $uri/ =404;
    }
}

# 多个不同域名指向同一内容
server {
    listen 80;

    server_name example.com example.net example.org;

    root /var/www/shared;

    location / {
        try_files $uri $uri/ =404;
    }
}

2.3 子域名配置

# 博客子域名
server {
    listen 80;
    server_name blog.example.com;

    root /var/www/blog;
    index index.html index.php;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

# API子域名
server {
    listen 80;
    server_name api.example.com;

    # API通常代理到后端服务
    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

2.4 通配符域名配置

# 通配符子域名
server {
    listen 80;
    server_name *.example.com;

    # 使用正则捕获子域名
    if ($host ~* ^([^.]+)\.example\.com$) {
        set $subdomain $1;
    }

    root /var/www/subdomains/$subdomain;

    # 如果目录不存在,重定向到主站
    location / {
        try_files $uri $uri/ @fallback;
    }

    location @fallback {
        return 301 http://example.com$request_uri;
    }
}

# 使用正则表达式的域名匹配
server {
    listen 80;
    server_name ~^(?<user>\w+)\.example\.com$;

    root /var/www/users/$user;

    # 为每个用户创建独立的日志
    access_log /var/log/nginx/users/$user.access.log;
    error_log /var/log/nginx/users/$user.error.log;

    location / {
        try_files $uri $uri/ =404;
    }
}

3. 基于IP的虚拟主机

3.1 多IP配置

# IP 192.168.1.10的虚拟主机
server {
    listen 192.168.1.10:80;
    server_name _;

    root /var/www/site1;

    location / {
        try_files $uri $uri/ =404;
    }
}

# IP 192.168.1.11的虚拟主机
server {
    listen 192.168.1.11:80;
    server_name _;

    root /var/www/site2;

    location / {
        try_files $uri $uri/ =404;
    }
}

3.2 IPv6支持

server {
    # 同时监听IPv4和IPv6
    listen 80;
    listen [::]:80;
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    server_name example.com;

    # IPv6特定配置
    location / {
        # 记录客户端IP类型
        set $ip_version "IPv4";
        if ($remote_addr ~* "^([0-9a-f]*:){2,}") {
            set $ip_version "IPv6";
        }

        add_header X-IP-Version $ip_version;
        try_files $uri $uri/ =404;
    }
}

4. 基于端口的虚拟主机

4.1 不同端口配置

# 端口8080的虚拟主机
server {
    listen 8080;
    server_name example.com;

    root /var/www/app1;

    location / {
        try_files $uri $uri/ =404;
    }
}

# 端口8081的虚拟主机
server {
    listen 8081;
    server_name example.com;

    root /var/www/app2;

    location / {
        try_files $uri $uri/ =404;
    }
}

# 管理接口(非标准端口)
server {
    listen 9000;
    server_name admin.example.com;

    # 限制访问来源
    allow 192.168.1.0/24;
    allow 10.0.0.0/8;
    deny all;

    location / {
        proxy_pass http://127.0.0.1:3001;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

5. HTTPS虚拟主机配置

5.1 SSL证书配置

# HTTPS虚拟主机
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    server_name example.com www.example.com;

    # SSL证书配置
    ssl_certificate /etc/ssl/certs/example.com.crt;
    ssl_certificate_key /etc/ssl/private/example.com.key;

    # SSL参数
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;

    # HSTS
    add_header Strict-Transport-Security "max-age=63072000" always;

    root /var/www/example.com;
    index index.html index.php;

    location / {
        try_files $uri $uri/ =404;
    }
}

# HTTP重定向到HTTPS
server {
    listen 80;
    listen [::]:80;

    server_name example.com www.example.com;

    return 301 https://$server_name$request_uri;
}

5.2 多域名SSL配置

# 使用通配符证书
server {
    listen 443 ssl http2;
    server_name *.example.com;

    ssl_certificate /etc/ssl/certs/wildcard.example.com.crt;
    ssl_certificate_key /etc/ssl/private/wildcard.example.com.key;

    # 根据子域名路由
    set $subdomain "";
    if ($host ~* ^([^.]+)\.example\.com$) {
        set $subdomain $1;
    }

    location / {
        if ($subdomain = "api") {
            proxy_pass http://api-backend;
            break;
        }

        if ($subdomain = "blog") {
            root /var/www/blog;
            try_files $uri $uri/ /index.php?$query_string;
            break;
        }

        # 默认处理
        root /var/www/default;
        try_files $uri $uri/ =404;
    }
}

6. 默认虚拟主机配置

6.1 默认服务器配置

# 默认虚拟主机(捕获所有未匹配的请求)
server {
    listen 80 default_server;
    listen [::]:80 default_server;

    server_name _;

    # 默认拒绝访问或重定向
    return 444;  # 关闭连接

    # 或者返回自定义页面
    # root /var/www/default;
    # location / {
    #     return 200 "Default server";
    #     add_header Content-Type text/plain;
    # }
}

# HTTPS默认服务器
server {
    listen 443 ssl default_server;
    listen [::]:443 ssl default_server;

    server_name _;

    # 使用自签名证书或默认证书
    ssl_certificate /etc/ssl/certs/default.crt;
    ssl_certificate_key /etc/ssl/private/default.key;

    return 444;
}

6.2 错误处理虚拟主机

# 专门处理错误的虚拟主机
server {
    listen 80;
    server_name error.example.com;

    root /var/www/error-pages;

    location / {
        internal;
        try_files $uri /error.html;
    }

    location /error.html {
        internal;
    }
}

# 在其他虚拟主机中使用
server {
    listen 80;
    server_name example.com;

    error_page 404 = @error404;
    error_page 500 502 503 504 = @error50x;

    location @error404 {
        return 302 http://error.example.com/404;
    }

    location @error50x {
        return 302 http://error.example.com/500;
    }
}

7. 动态虚拟主机

7.1 基于目录的动态虚拟主机

server {
    listen 80;
    server_name ~^(?<domain>.+)$;

    set $domain_path "";
    if ($domain ~* ^([^.]+)\.([^.]+)\.([^.]+)$) {
        set $domain_path $2.$3/$1;
    }
    if ($domain ~* ^([^.]+)\.([^.]+)$) {
        set $domain_path $1.$2;
    }

    root /var/www/vhosts/$domain_path;

    # 检查目录是否存在
    location / {
        try_files $uri $uri/ @notfound;
    }

    location @notfound {
        return 301 http://main-site.com;
    }
}

7.2 使用Lua脚本的动态虚拟主机

server {
    listen 80;
    server_name ~.*;

    set_by_lua_block $document_root {
        local host = ngx.var.host
        local domain = string.gsub(host, "^www%.", "")

        -- 检查域名是否在允许列表中
        local allowed_domains = {
            ["example.com"] = "/var/www/example.com",
            ["test.com"] = "/var/www/test.com"
        }

        return allowed_domains[domain] or "/var/www/default"
    }

    root $document_root;

    location / {
        try_files $uri $uri/ =404;
    }
}

8. 虚拟主机管理

8.1 站点启用和禁用

# 创建新的虚拟主机配置
sudo nano /etc/nginx/sites-available/new-site.com

# 启用站点(创建符号链接)
sudo ln -s /etc/nginx/sites-available/new-site.com /etc/nginx/sites-enabled/

# 禁用站点(删除符号链接)
sudo rm /etc/nginx/sites-enabled/new-site.com

# 测试配置
sudo nginx -t

# 重新加载配置
sudo systemctl reload nginx

8.2 批量管理脚本

#!/bin/bash
# 虚拟主机管理脚本

SITES_AVAILABLE="/etc/nginx/sites-available"
SITES_ENABLED="/etc/nginx/sites-enabled"

case "$1" in
    enable)
        if [ -f "$SITES_AVAILABLE/$2" ]; then
            ln -s "$SITES_AVAILABLE/$2" "$SITES_ENABLED/"
            echo "Site $2 enabled"
        else
            echo "Site $2 not found"
        fi
        ;;
    disable)
        if [ -L "$SITES_ENABLED/$2" ]; then
            rm "$SITES_ENABLED/$2"
            echo "Site $2 disabled"
        else
            echo "Site $2 not enabled"
        fi
        ;;
    list)
        echo "Available sites:"
        ls -1 "$SITES_AVAILABLE"
        echo "Enabled sites:"
        ls -1 "$SITES_ENABLED"
        ;;
    *)
        echo "Usage: $0 {enable|disable|list} [site-name]"
        ;;
esac

# 测试配置
nginx -t && systemctl reload nginx

9. 性能优化

9.1 虚拟主机级别的优化

server {
    listen 80;
    server_name example.com;

    # 单独的工作进程
    # 注意:这需要在http块中配置

    # 连接保持优化
    keepalive_timeout 65;
    keepalive_requests 1000;

    # 压缩配置
    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_types
        text/plain
        text/css
        text/xml
        text/javascript
        application/javascript
        application/xml+rss
        application/json;

    # 缓冲区优化
    client_body_buffer_size 128k;
    client_max_body_size 50m;

    location / {
        # 开启sendfile
        sendfile on;
        tcp_nopush on;
        tcp_nodelay on;

        try_files $uri $uri/ =404;
    }
}

9.2 资源限制

http {
    # 限制每个IP的连接数
    limit_conn_zone $binary_remote_addr zone=conn_limit_per_ip:10m;

    # 限制每个服务器名的连接数
    limit_conn_zone $server_name zone=conn_limit_per_server:10m;

    server {
        listen 80;
        server_name example.com;

        # 应用连接限制
        limit_conn conn_limit_per_ip 10;
        limit_conn conn_limit_per_server 100;

        # 请求频率限制
        limit_req_zone $binary_remote_addr zone=req_limit:10m rate=5r/s;
        limit_req zone=req_limit burst=10 nodelay;

        location / {
            try_files $uri $uri/ =404;
        }
    }
}

10. 故障排除

10.1 常见问题诊断

# 检查虚拟主机配置
nginx -T | grep -A 20 "server_name example.com"

# 测试域名解析
nslookup example.com
dig example.com

# 检查端口监听
netstat -tulpn | grep :80
ss -tulpn | grep :80

# 测试虚拟主机
curl -H "Host: example.com" http://localhost/
curl -I http://example.com/

10.2 日志分析

# 查看特定虚拟主机的日志
tail -f /var/log/nginx/example.com.access.log

# 分析错误日志
grep "example.com" /var/log/nginx/error.log

# 统计访问量
awk '{print $1}' /var/log/nginx/example.com.access.log | sort | uniq -c | sort -nr

小结

通过本文的学习,你应该掌握:

  1. 不同类型虚拟主机的配置方法
  2. 域名、IP和端口的虚拟主机配置
  3. HTTPS虚拟主机的配置技巧
  4. 动态虚拟主机的实现方法
  5. 虚拟主机的管理和优化
  6. 常见问题的诊断和解决

下一篇文章将介绍Nginx的日志配置与管理。

powered by Gitbook© 2025 编外计划 | 最后修改: 2025-08-29 15:40:15

results matching ""

    No results matching ""