1. 多域名服务架构的现实需求
现代Web服务部署中,单台服务器承载多个独立域名的业务场景越来越普遍。我最近接手的一个企业级项目就需要在同一组Nginx服务器上部署7个业务域名,每个域名都有独立的SSL证书,并且需要根据访问路径分发到不同的后端服务。这种架构不仅能节省服务器成本,还能简化运维管理,但配置过程确实存在不少技术细节需要注意。
在实际操作中,我发现很多教程只讲基础配置,却忽略了生产环境中的关键细节。比如证书自动续期时的服务重启策略、不同域名间的资源隔离、日志文件管理等问题。本文将基于我处理过的真实案例,分享一套经过实战检验的Nginx多域名配置方案。
2. 基础环境准备与规划
2.1 服务器基础配置
建议使用Linux发行版作为操作系统(我常用Ubuntu 20.04 LTS),确保已安装:
- Nginx 1.18+(支持TLS 1.3)
- OpenSSL 1.1.1+
- 系统防火墙配置放行80/443端口
重要提示:生产环境务必禁用HTTP/1.0,建议在nginx.conf的http块中添加:
code复制http { ... server_tokens off; chunked_transfer_encoding on; keepalive_timeout 75s; keepalive_requests 100; }
2.2 域名与证书规划
假设我们需要配置以下三个域名:
- www.example.com - 主站(使用ECC证书)
- api.example.com - 接口服务(使用RSA证书)
- static.example.com - 静态资源(使用通配符证书)
证书存放路径建议采用结构化目录:
code复制/etc/nginx/ssl/
├── example.com/
│ ├── ecc/
│ │ ├── fullchain.pem
│ │ └── privkey.pem
│ └── rsa/
│ ├── fullchain.pem
│ └── privkey.pem
└── wildcard/
├── fullchain.pem
└── privkey.pem
3. 核心配置实现
3.1 主配置文件拆分
最佳实践是将配置拆分为多个文件:
code复制/etc/nginx/
├── nginx.conf
├── conf.d/
│ ├── 00-basic.conf
│ ├── 10-example.com.conf
│ ├── 20-api.example.com.conf
│ └── 30-static.example.com.conf
└── snippets/
├── ssl-params.conf
└── proxy-headers.conf
nginx.conf中需要包含:
nginx复制http {
...
include /etc/nginx/conf.d/*.conf;
}
3.2 SSL配置模板
创建/etc/nginx/snippets/ssl-params.conf:
nginx复制ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_ecdh_curve secp384r1;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 valid=300s;
resolver_timeout 5s;
3.3 典型域名配置示例
以api.example.com为例:
nginx复制server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name api.example.com;
# RSA证书配置
ssl_certificate /etc/nginx/ssl/example.com/rsa/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/example.com/rsa/privkey.pem;
include snippets/ssl-params.conf;
# 日志分离
access_log /var/log/nginx/api.access.log main buffer=32k flush=5m;
error_log /var/log/nginx/api.error.log warn;
# 后端服务配置
location /v1/ {
proxy_pass http://backend-api:8000;
include snippets/proxy-headers.conf;
# 连接池优化
proxy_http_version 1.1;
proxy_set_header Connection "";
}
# 健康检查端点
location = /healthz {
access_log off;
return 200 "OK";
}
}
4. 高级优化技巧
4.1 OCSP Stapling配置
在证书配置块中添加:
nginx复制ssl_trusted_certificate /etc/nginx/ssl/example.com/rsa/chain.pem;
ssl_stapling on;
ssl_stapling_verify on;
验证命令:
bash复制openssl s_client -connect api.example.com:443 -status -servername api.example.com < /dev/null 2>&1 | grep -i "OCSP response"
4.2 证书自动更新方案
使用Certbot的hook脚本:
bash复制#!/bin/bash
# /etc/letsencrypt/renewal-hooks/post/nginx-reload.sh
if [[ "$RENEWED_DOMAINS" == *"example.com"* ]]; then
systemctl reload nginx
logger "Nginx reloaded for $RENEWED_DOMAINS"
fi
设置权限:
bash复制chmod +x /etc/letsencrypt/renewal-hooks/post/nginx-reload.sh
4.3 性能调优参数
在http块中添加:
nginx复制# 连接优化
keepalive_requests 1000;
keepalive_timeout 30s;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
# 静态资源缓存
open_file_cache max=10000 inactive=30s;
open_file_cache_valid 60s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
5. 常见问题排查
5.1 证书不生效检查清单
-
检查证书路径权限:
bash复制ls -l /etc/nginx/ssl/example.com/rsa/确保Nginx用户(通常是www-data或nginx)有读取权限
-
验证证书链完整性:
bash复制
openssl verify -CAfile /etc/nginx/ssl/example.com/rsa/fullchain.pem \ /etc/nginx/ssl/example.com/rsa/cert.pem -
检查SSL协议支持:
bash复制
nginx -T | grep ssl_protocols
5.2 配置调试技巧
-
测试配置语法:
bash复制
nginx -t -
查看加载的完整配置:
bash复制
nginx -T -
实时监控错误日志:
bash复制tail -f /var/log/nginx/error.log
5.3 多域名下的资源隔离
-
限制每个域名的连接数:
nginx复制limit_conn_zone $server_name zone=perdomain:10m; server { ... limit_conn perdomain 100; } -
独立进程池配置(Nginx Plus功能):
nginx复制# 在main上下文 zone "api" 32k; # 在server块 status_zone "api.example.com";
6. 安全加固措施
6.1 访问控制策略
-
管理接口IP白名单:
nginx复制location /admin/ { allow 192.168.1.0/24; allow 203.0.113.45; deny all; proxy_pass http://backend-admin; } -
基于地理位置的访问限制:
nginx复制geo $blocked_country { default 0; include /etc/nginx/geo-block.conf; } server { if ($blocked_country) { return 403; } }
6.2 请求过滤规则
-
防恶意扫描配置:
nginx复制# 在http块 map $uri $bad_uri { default 0; ~*"(phpmyadmin|wp-admin)" 1; } # 在server块 if ($bad_uri) { return 444; } -
User-Agent过滤:
nginx复制map $http_user_agent $badagent { default 0; ~*(nmap|nikto|sqlmap) 1; } server { if ($badagent) { return 403; } }
7. 监控与维护
7.1 关键指标监控
-
配置Nginx状态页(需要stub_status模块):
nginx复制server { listen 127.0.0.1:8080; location /nginx_status { stub_status; access_log off; allow 127.0.0.1; deny all; } } -
Prometheus监控配置:
nginx复制location /metrics { access_log off; allow 192.168.1.100; deny all; content_by_lua_block { ngx.print(require("nginx-prometheus").collect()) } }
7.2 日志分析策略
-
日志格式优化:
nginx复制log_format main_ext '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for" ' '"$host" $request_time $upstream_response_time'; -
使用GoAccess实时分析:
bash复制
zcat -f /var/log/nginx/*.access.log | \ goaccess --log-format=COMBINED --real-time-html --output=report.html
在实际运维中,我发现将不同域名的错误日志分离特别重要。曾经因为所有域名共享error.log,导致排查API域名的502错误时花费了大量时间筛选日志。现在每个域名有独立的错误日志文件后,问题定位效率提升了70%以上。