一、技术背景与核心价值
在现代化Web开发中,企业常面临多项目并行部署的挑战:如何通过单一服务器实现不同二级域名(如project1.example.com、project2.example.com)的HTTPS无端口访问?传统方案需为每个项目配置独立IP或端口,导致资源浪费和管理复杂。Docker与Nginx的组合提供了轻量级、高可用的解决方案:
- Docker容器化:每个Web项目独立运行于容器中,隔离环境依赖。
- Nginx反向代理:通过配置
server_name和location实现域名级路由。 - HTTPS自动化:利用Let’s Encrypt免费证书实现全站加密。
- 无端口访问:通过Nginx监听443端口并转发请求,用户无需输入
:443。
二、环境准备与前置条件
1. 服务器要求
- 操作系统:Ubuntu 20.04 LTS(推荐)或CentOS 8
- 硬件配置:至少2核CPU、4GB内存(支持多容器并发)
- 域名准备:已解析的顶级域名(如
example.com)及二级域名(如project1.example.com)
2. 软件安装
# 安装Dockercurl -fsSL https://get.docker.com | shsystemctl enable --now docker# 安装Nginxapt install nginx -y # Ubuntuyum install nginx -y # CentOS# 安装Certbot(Let's Encrypt客户端)apt install certbot python3-certbot-nginx -y
3. 防火墙配置
ufw allow 80/tcp # HTTPufw allow 443/tcp # HTTPSufw enable
三、Docker容器化Web项目
1. 创建Docker网络
docker network create web_network
此网络用于容器间通信,确保Nginx与后端服务在同一子网。
2. 部署示例项目
以Node.js和Python Flask为例:
# Node.js项目DockerfileFROM node:14WORKDIR /appCOPY package*.json ./RUN npm installCOPY . .EXPOSE 3000CMD ["npm", "start"]# Flask项目DockerfileFROM python:3.8WORKDIR /appCOPY requirements.txt ./RUN pip install -r requirements.txtCOPY . .EXPOSE 5000CMD ["python", "app.py"]
构建并运行容器:
docker build -t node-app .docker run -d --name node-service --network web_network -p 3000:3000 node-appdocker build -t flask-app .docker run -d --name flask-service --network web_network -p 5000:5000 flask-app
四、Nginx配置HTTPS与反向代理
1. 获取SSL证书
certbot --nginx -d project1.example.com -d project2.example.com
此命令自动申请证书并修改Nginx配置,生成/etc/letsencrypt/live/下的证书文件。
2. 配置多域名代理
编辑/etc/nginx/conf.d/multi_projects.conf:
upstream node_backend {server node-service:3000; # 使用容器名而非IP}upstream flask_backend {server flask-service:5000;}server {listen 443 ssl;server_name project1.example.com;ssl_certificate /etc/letsencrypt/live/project1.example.com/fullchain.pem;ssl_certificate_key /etc/letsencrypt/live/project1.example.com/privkey.pem;location / {proxy_pass http://node_backend;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;}}server {listen 443 ssl;server_name project2.example.com;ssl_certificate /etc/letsencrypt/live/project2.example.com/fullchain.pem;ssl_certificate_key /etc/letsencrypt/live/project2.example.com/privkey.pem;location / {proxy_pass http://flask_backend;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;}}
关键点:
upstream定义后端服务地址,使用容器名实现DNS解析。- 每个
server块监听443端口,通过server_name区分域名。 - SSL证书路径需与域名匹配。
3. 强制HTTPS重定向
在/etc/nginx/sites-available/default中添加:
server {listen 80;server_name project1.example.com project2.example.com;return 301 https://$host$request_uri;}
五、自动化与维护
1. 证书自动续期
crontab -e# 添加以下行(每月1日凌晨3点执行)0 3 1 * * /usr/bin/certbot renew --quiet --nginx
2. Docker日志管理
# 查看容器日志docker logs -f node-service# 配置日志轮转(/etc/logrotate.d/docker)/var/lib/docker/containers/*/*.log {dailymissingokrotate 7compressdelaycompressnotifemptycopytruncate}
3. 性能优化建议
- 启用HTTP/2:在Nginx配置中添加
listen 443 ssl http2; - 缓存静态资源:
location ~* \.(jpg|jpeg|png|css|js)$ {expires 30d;add_header Cache-Control "public";}
- Gzip压缩:
gzip on;gzip_types text/plain text/css application/json application/javascript text/xml;
六、故障排查指南
1. 常见问题
- 502 Bad Gateway:检查后端容器是否运行(
docker ps),网络是否连通(docker exec -it nginx-container ping node-service)。 - 证书错误:验证证书路径是否正确,域名是否与证书匹配。
- 端口冲突:确保Nginx未监听其他容器的端口。
2. 诊断命令
# 检查Nginx配置语法nginx -t# 查看SSL证书信息openssl x509 -in /etc/letsencrypt/live/project1.example.com/fullchain.pem -noout -text# 监控容器资源docker stats
七、扩展场景
1. 动态域名路由
结合Lua脚本实现基于路径的路由:
location /api {set $backend "";if ($host ~* "project1.example.com") {set $backend "node_backend";}if ($host ~* "project2.example.com") {set $backend "flask_backend";}proxy_pass http://$backend;}
2. 多级子域名
配置*.example.com通配符证书,通过正则表达式匹配:
server {listen 443 ssl;server_name ~^(?<subdomain>.+)\.example\.com$;location / {proxy_pass http://${subdomain}_backend;}}
八、总结与最佳实践
- 容器化原则:每个项目独立容器,共享网络但隔离存储。
- Nginx配置:优先使用
upstream定义后端,避免硬编码IP。 - 证书管理:定期检查证书有效期,启用自动续期。
- 监控告警:集成Prometheus+Grafana监控容器指标。
通过此方案,企业可在单台服务器上高效部署多个Web项目,实现域名级隔离、全站HTTPS加密及零端口暴露,显著降低运维成本与安全风险。