Docker Nginx HTTPS二级域名无端口部署多Web项目全攻略

一、技术背景与核心价值

在现代化Web开发中,企业常面临多项目并行部署的挑战:如何通过单一服务器实现不同二级域名(如project1.example.comproject2.example.com)的HTTPS无端口访问?传统方案需为每个项目配置独立IP或端口,导致资源浪费和管理复杂。Docker与Nginx的组合提供了轻量级、高可用的解决方案:

  • Docker容器化:每个Web项目独立运行于容器中,隔离环境依赖。
  • Nginx反向代理:通过配置server_namelocation实现域名级路由。
  • HTTPS自动化:利用Let’s Encrypt免费证书实现全站加密。
  • 无端口访问:通过Nginx监听443端口并转发请求,用户无需输入:443

二、环境准备与前置条件

1. 服务器要求

  • 操作系统:Ubuntu 20.04 LTS(推荐)或CentOS 8
  • 硬件配置:至少2核CPU、4GB内存(支持多容器并发)
  • 域名准备:已解析的顶级域名(如example.com)及二级域名(如project1.example.com

2. 软件安装

  1. # 安装Docker
  2. curl -fsSL https://get.docker.com | sh
  3. systemctl enable --now docker
  4. # 安装Nginx
  5. apt install nginx -y # Ubuntu
  6. yum install nginx -y # CentOS
  7. # 安装Certbot(Let's Encrypt客户端)
  8. apt install certbot python3-certbot-nginx -y

3. 防火墙配置

  1. ufw allow 80/tcp # HTTP
  2. ufw allow 443/tcp # HTTPS
  3. ufw enable

三、Docker容器化Web项目

1. 创建Docker网络

  1. docker network create web_network

此网络用于容器间通信,确保Nginx与后端服务在同一子网。

2. 部署示例项目

以Node.js和Python Flask为例:

  1. # Node.js项目Dockerfile
  2. FROM node:14
  3. WORKDIR /app
  4. COPY package*.json ./
  5. RUN npm install
  6. COPY . .
  7. EXPOSE 3000
  8. CMD ["npm", "start"]
  9. # Flask项目Dockerfile
  10. FROM python:3.8
  11. WORKDIR /app
  12. COPY requirements.txt ./
  13. RUN pip install -r requirements.txt
  14. COPY . .
  15. EXPOSE 5000
  16. CMD ["python", "app.py"]

构建并运行容器:

  1. docker build -t node-app .
  2. docker run -d --name node-service --network web_network -p 3000:3000 node-app
  3. docker build -t flask-app .
  4. docker run -d --name flask-service --network web_network -p 5000:5000 flask-app

四、Nginx配置HTTPS与反向代理

1. 获取SSL证书

  1. certbot --nginx -d project1.example.com -d project2.example.com

此命令自动申请证书并修改Nginx配置,生成/etc/letsencrypt/live/下的证书文件。

2. 配置多域名代理

编辑/etc/nginx/conf.d/multi_projects.conf

  1. upstream node_backend {
  2. server node-service:3000; # 使用容器名而非IP
  3. }
  4. upstream flask_backend {
  5. server flask-service:5000;
  6. }
  7. server {
  8. listen 443 ssl;
  9. server_name project1.example.com;
  10. ssl_certificate /etc/letsencrypt/live/project1.example.com/fullchain.pem;
  11. ssl_certificate_key /etc/letsencrypt/live/project1.example.com/privkey.pem;
  12. location / {
  13. proxy_pass http://node_backend;
  14. proxy_set_header Host $host;
  15. proxy_set_header X-Real-IP $remote_addr;
  16. }
  17. }
  18. server {
  19. listen 443 ssl;
  20. server_name project2.example.com;
  21. ssl_certificate /etc/letsencrypt/live/project2.example.com/fullchain.pem;
  22. ssl_certificate_key /etc/letsencrypt/live/project2.example.com/privkey.pem;
  23. location / {
  24. proxy_pass http://flask_backend;
  25. proxy_set_header Host $host;
  26. proxy_set_header X-Real-IP $remote_addr;
  27. }
  28. }

关键点:

  • upstream定义后端服务地址,使用容器名实现DNS解析。
  • 每个server块监听443端口,通过server_name区分域名。
  • SSL证书路径需与域名匹配。

3. 强制HTTPS重定向

/etc/nginx/sites-available/default中添加:

  1. server {
  2. listen 80;
  3. server_name project1.example.com project2.example.com;
  4. return 301 https://$host$request_uri;
  5. }

五、自动化与维护

1. 证书自动续期

  1. crontab -e
  2. # 添加以下行(每月1日凌晨3点执行)
  3. 0 3 1 * * /usr/bin/certbot renew --quiet --nginx

2. Docker日志管理

  1. # 查看容器日志
  2. docker logs -f node-service
  3. # 配置日志轮转(/etc/logrotate.d/docker)
  4. /var/lib/docker/containers/*/*.log {
  5. daily
  6. missingok
  7. rotate 7
  8. compress
  9. delaycompress
  10. notifempty
  11. copytruncate
  12. }

3. 性能优化建议

  • 启用HTTP/2:在Nginx配置中添加listen 443 ssl http2;
  • 缓存静态资源
    1. location ~* \.(jpg|jpeg|png|css|js)$ {
    2. expires 30d;
    3. add_header Cache-Control "public";
    4. }
  • Gzip压缩
    1. gzip on;
    2. 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. 诊断命令

  1. # 检查Nginx配置语法
  2. nginx -t
  3. # 查看SSL证书信息
  4. openssl x509 -in /etc/letsencrypt/live/project1.example.com/fullchain.pem -noout -text
  5. # 监控容器资源
  6. docker stats

七、扩展场景

1. 动态域名路由

结合Lua脚本实现基于路径的路由:

  1. location /api {
  2. set $backend "";
  3. if ($host ~* "project1.example.com") {
  4. set $backend "node_backend";
  5. }
  6. if ($host ~* "project2.example.com") {
  7. set $backend "flask_backend";
  8. }
  9. proxy_pass http://$backend;
  10. }

2. 多级子域名

配置*.example.com通配符证书,通过正则表达式匹配:

  1. server {
  2. listen 443 ssl;
  3. server_name ~^(?<subdomain>.+)\.example\.com$;
  4. location / {
  5. proxy_pass http://${subdomain}_backend;
  6. }
  7. }

八、总结与最佳实践

  1. 容器化原则:每个项目独立容器,共享网络但隔离存储。
  2. Nginx配置:优先使用upstream定义后端,避免硬编码IP。
  3. 证书管理:定期检查证书有效期,启用自动续期。
  4. 监控告警:集成Prometheus+Grafana监控容器指标。

通过此方案,企业可在单台服务器上高效部署多个Web项目,实现域名级隔离、全站HTTPS加密及零端口暴露,显著降低运维成本与安全风险。