在Web服务部署中,经常需要同时管理多个环境(如测试环境和生产环境)的域名和证书配置。作为一名有多年运维经验的工程师,我经常遇到需要在单台服务器上通过Nginx配置多域名、多证书的场景。这种配置不仅能节省服务器资源,还能简化运维管理流程。
本次要解决的问题是:在同一台Nginx服务器上,为测试环境(test-xxx.com)和正式环境(xxx.com)配置独立的域名和SSL证书,并实现HTTP到HTTPS的自动跳转。这种配置方式特别适合中小型项目或创业团队,可以在保证环境隔离的同时,降低服务器成本。
在开始配置前,我们需要确认服务器环境已经满足以下条件:
nginx -V查看是否包含--with-http_ssl_module)/usr/local/nginx)建议通过以下命令验证Nginx的SSL支持:
bash复制nginx -V 2>&1 | grep -o with-http_ssl_module
如果输出with-http_ssl_module则表示支持SSL。
证书文件的安全存放至关重要。我建议采用以下目录结构:
code复制/usr/local/nginx/
├── ssl/
│ ├── prod/
│ │ ├── xxx.com_bundle.pem
│ │ └── xxx.com.key
│ └── test/
│ ├── test-xxx.com_bundle.pem
│ └── test-xxx.com.key
这种按环境分类存放的方式有三大优势:
重要提示:证书.key文件应设置为600权限,仅允许root用户读写:
bash复制chmod 600 /usr/local/nginx/ssl/*/*.key
以下是经过生产验证的Nginx主配置文件(nginx.conf)优化方案:
nginx复制user www-data;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /run/nginx.pid;
events {
worker_connections 2048;
multi_accept on;
use epoll;
}
http {
include 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" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
client_max_body_size 20M;
# 启用Gzip压缩
gzip on;
gzip_min_length 1k;
gzip_comp_level 4;
gzip_types text/plain text/css application/json application/javascript text/xml;
# 引入各环境配置
include /usr/local/nginx/conf/conf.d/*.conf;
}
关键优化点说明:
worker_connections 2048 - 根据服务器内存调整(每个连接约占用256KB内存)multi_accept on - 提高并发处理能力client_max_body_size 20M - 调整上传文件大小限制conf.d目录存放各环境配置,保持主配置简洁实现全站HTTPS是安全最佳实践。我们通过单独的server块处理HTTP到HTTPS的重定向:
nginx复制server {
listen 80;
server_name xxx.com www.xxx.com test-xxx.com www.test-xxx.com;
# 301永久重定向
return 301 https://$host$request_uri;
# 防止恶意扫描
location ~ /\.(?!well-known).* {
deny all;
access_log off;
log_not_found off;
}
}
注意事项:
$host而非$server_name可以保留原始请求的域名创建/usr/local/nginx/conf/conf.d/prod.conf:
nginx复制server {
listen 443 ssl http2;
server_name xxx.com www.xxx.com;
# SSL证书配置
ssl_certificate /usr/local/nginx/ssl/prod/xxx.com_bundle.pem;
ssl_certificate_key /usr/local/nginx/ssl/prod/xxx.com.key;
# SSL性能优化
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;
# 现代加密套件
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers on;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
# HSTS (慎重开启)
# add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
# 静态资源缓存
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
expires 30d;
add_header Cache-Control "public, no-transform";
}
# 主应用配置
location / {
root /var/www/prod/html;
index index.html;
try_files $uri $uri/ /index.html;
# 安全头
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options "nosniff";
add_header X-XSS-Protection "1; mode=block";
}
# 错误页面
error_page 404 /404.html;
location = /404.html {
root /usr/share/nginx/html;
internal;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
internal;
}
# 禁止访问敏感文件
location ~ /\. {
deny all;
}
location ~* (\.env|\.git) {
deny all;
}
}
创建/usr/local/nginx/conf/conf.d/test.conf:
nginx复制server {
listen 443 ssl;
server_name test-xxx.com www.test-xxx.com;
# SSL证书配置
ssl_certificate /usr/local/nginx/ssl/test/test-xxx.com_bundle.pem;
ssl_certificate_key /usr/local/nginx/ssl/test/test-xxx.com.key;
# 简化SSL配置
ssl_protocols TLSv1.2;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';
ssl_prefer_server_ciphers on;
# 主应用配置
location / {
root /var/www/test/html;
index index.html;
# 开发环境禁用缓存
add_header Cache-Control "no-cache, no-store, must-revalidate";
add_header Pragma "no-cache";
add_header Expires 0;
}
# API代理示例
location /api/ {
proxy_pass http://localhost:3000/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# 错误页面
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
internal;
}
}
测试环境与生产环境的主要差异:
完成配置后,按步骤执行:
bash复制# 检查配置语法
nginx -t
# 如果报错,根据提示修正后再次检查
# 确认无误后重载配置
nginx -s reload
常见错误及解决方案:
SSL_CTX_use_PrivateKey_file错误 - 证书与私钥不匹配,检查文件内容netstat -tulnp | grep 443确认443端口未被占用部署完成后,建议使用以下工具验证配置:
长期运行建议配置监控:
bash复制# 实时监控连接数
watch -n 1 "netstat -an | grep 443 | wc -l"
# Nginx状态监控
location /nginx_status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}
使用Certbot实现Let's Encrypt证书自动续期:
bash复制# 安装Certbot
sudo apt install certbot python3-certbot-nginx
# 为生产环境申请证书
sudo certbot --nginx -d xxx.com -d www.xxx.com
# 设置自动续期
sudo certbot renew --dry-run
使用rsync保持多台服务器配置一致:
bash复制rsync -avz /usr/local/nginx/conf/ user@backup-server:/usr/local/nginx/conf/
创建/etc/logrotate.d/nginx:
code复制/var/log/nginx/*.log {
daily
missingok
rotate 30
compress
delaycompress
notifempty
create 0640 www-data adm
sharedscripts
postrotate
[ -f /run/nginx.pid ] && kill -USR1 `cat /run/nginx.pid`
endscript
}
在实际运维中,我发现将测试环境和生产环境的配置完全分离(使用不同的conf文件)能大大降低人为错误的风险。每次修改配置前,务必先在测试环境验证,并通过nginx -t检查语法。证书更新时,建议先保留旧证书,等新证书确认无误后再删除旧文件。