服务器 | 基于 Docker 的 Nginx 多服务器部署与域名互联访问实战指南 文章目录概要一、环境配置1、软件资源2、Docker安装二、后端服务器1、针对MySQL 和 Redis2、Docker Compose编排3、Nginx配置文件三、门户服务器1、nginx.conf四、访问流程图常见问题1、问题1数据库连接地址2、问题2请求重定向总结概要在构建现代化的分布式系统或微服务架构时如何在多台服务器之间高效地管理流量入口并实现基于域名的灵活访问传统的 Nginx 部署方式往往伴随着繁琐的环境配置和迁移成本而 Docker 的引入则为这一过程带来了标准化的解决方案。本文将深入探讨如何利用 Docker 容器化技术在多台服务器上部署 Nginx 实例并通过反向代理与 DNS 解析策略构建一个高可用、易扩展的域名互联访问体系。一、环境配置1、软件资源名称型号数量Linux服务器Alibaba Cloud Linux 3.2104 LTS 64位2Web 服务器jonasal/nginx-certbot:2.4.1-nginx1.21.0-alpine2SpringBoot项目SpringBoot 3.x1数据库mysql-81缓存数据库redis:6.0.201分布式对象存储系统rustfs:latest1域名阿里云域名22、Docker安装# 添加 Docker-ce 软件包源sudoyum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo# 修正仓库配置中的版本号Alibaba Cloud Linux 4 对应 RHEL 8因此使用 8sudosed-is/$releasever/8/g/etc/yum.repos.d/docker-ce.repo# 清理并刷新缓存sudoyum clean allsudoyum makecachesudoyum update# 安装 Docker 社区版及相关组件sudoyuminstall-ydocker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin二、后端服务器该服务器作为后端服务器用于部署后端项目、数据库、缓存、对象存储等。域名myserver2.comDocker统一网络:pic-net在 Linux 服务器上使用 Nginx 作为网关来统一管理 Docker 部署的 Spring Boot、 RustFS 项目是一个非常经典的架构。Nginx 可以通过路径前缀 或 域名将请求精准路由到不同的后端服务。1、针对MySQL 和 Redis极致的安全性零公网暴露数据库和缓存属于核心内部服务绝对不应该将端口映射到宿主机暴露给公网。加入 pic-net 后可以去掉 -p 端口映射Spring Boot 项目可以通过容器名如 容器名称:3306完美连接它们。高效的内部通信容器之间通过 Docker 内置的 DNS 服务进行通信应用只需将数据库主机名配置为容器名无需硬编码不固定的内部 IP 地址。配置与代码分离使用 Docker Compose 编排时可以将数据库密码、用户名等敏感信息抽取到 .env 文件中避免硬编码在代码或镜像里。2、Docker Compose编排使用docker-comose.yml统一编排以上文件services:# Nginx nginx-c:container_name:nginx-crestart:unless-stoppedimage:jonasal/nginx-certbot:2.4.1-nginx1.21.0-alpine# network_mode: hostports:-80:80-443:443environment:CERTBOT_EMAIL:f15176258474163.comvolumes:-/root/dcs/nginx/nginx:/etc/nginx/user_conf.d-/root/dcs/nginx/letsencrypt:/etc/letsencrypt-/root/apps/frontend:/appsnetworks:-pic-net# Bao-Admin bao-admin:image:openjdk:17-jdkworking_dir:/appvolumes:-/root/apps/backend/bao-admin.jar:/app/app.jarcontainer_name:bao-admindepends_on:mysql:condition:service_healthy# 等待 MySQL 健康redis:condition:service_healthy# 等待 Redis 健康restart:alwaysnetworks:-pic-netcommand:java -Xms256m -Xmx512m -XX:MaxMetaspaceSize256m -Xss512k -XX:UseSerialGC -Dspring.profiles.activedruid-prod -Djava.security.egdfile:/dev/./urandom -Duser.timezoneAsia/Shanghai -jar /app/app.jar# Docker 资源限制deploy:resources:limits:cpus:1.0memory:768Mulimits:nofile:soft:65536hard:65536# RustFS rustfs:image:rustfs/rustfs:latestcontainer_name:rustfsuser:1000:1000restart:alwaysnetworks:-pic-netports:-9000:9000-9001:9001volumes:-/root/dcs/rustfs/data:/data-/root/dcs/rustfs/logs:/var/log/rustfsenvironment:-TZAsia/Shanghai-RUSTFS_ADDRESS0.0.0.0:9000-RUSTFS_CONSOLE_ENABLEtrue-RUSTFS_CONSOLE_ADDRESS0.0.0.0:9001-RUSTFS_ACCESS_KEYusername-RUSTFS_SECRET_KEYpassword-RUSTFS_VOLUMES/datadeploy:resources:limits:memory:2Gcpus:1.0reservations:memory:1Gcpus:0.5healthcheck:# 使用 curl 检查根路径如果返回 403 则视为健康exit 0否则视为不健康exit 1test:[CMD-SHELL,curl -sf -o /dev/null -w %{http_code} http://localhost:9000/ | grep -q 403 || exit 1]interval:30s# 检查间隔timeout:10s# 超时时间retries:3# 失败重试次数start_period:10s# 容器启动后的宽限期# Redis redis:image:redis:6.0.20container_name:redis-servernetworks:-pic-netports:-63790:6379volumes:-/root/dcs/redis/redis.conf:/usr/local/redis/redis.conf-/root/dcs/redis/redis-data:/datacommand:redis-server /usr/local/redis/redis.confdeploy:resources:limits:cpus:0.5memory:256Mreservations:cpus:0.1memory:64Mhealthcheck:# 在 docker-compose 中使用双 $$ 来转义环境变量让容器内部能正确解析test:[CMD,redis-cli,-a,password,ping]interval:5s# 每 5 秒检查一次timeout:3s# 超时时间retries:5# 最多重试 5 次start_period:5s# 启动后预留 5 秒的初始化时间# MySQL mysql:image:mysql:8.0.28container_name:mysql8restart:alwaysnetworks:-pic-netports:-33060:3306environment:TZ:Asia/ShanghaiMYSQL_ROOT_PASSWORD:passwordvolumes:-/root/dcs/mysql/data:/var/lib/mysql-/root/dcs/mysql/conf:/etc/mysql/conf.d-/root/dcs/mysql/logs:/var/log/mysqlcommand:---character-set-serverutf8mb4---collation-serverutf8mb4_unicode_cihealthcheck:test:[CMD,mysqladmin,ping,-h,localhost]interval:10stimeout:5sretries:5start_period:30sdeploy:resources:limits:cpus:1.0memory:768Mulimits:nofile:soft:65535hard:65535# Networks networks:pic-net:driver:bridge后端基础设施就形成了一个高内聚、高安全的内网闭环。外部流量只能通过 Nginx 网关安全地进入。3、Nginx配置文件# # 1. 定义上游服务使用 Docker 容器名# upstream springboot_backend{server bao-admin:8080;# 对应你之前配置的 Spring Boot 容器}upstream rustfs_api{server rustfs:9000;# RustFS S3 API 端口 (请根据实际端口修改)}upstream rustfs_console{server rustfs:9001;# RustFS 控制台端口}server{listen 80; server_name myserver2.com;# 替换为你的实际域名或公网IP# # 2. Spring Boot 业务接口# location /api/{proxy_redirect off; proxy_pass http://springboot_backend/; proxy_http_version 1.1; 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; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; proxy_set_header Host $http_host;}# 5. RustFS 对象存储 APIlocation /rustfs-api/{proxy_pass http://rustfs_api/; proxy_buffering off; proxy_request_buffering off; client_max_body_size 10240M; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header Origin ;}# 6. RustFS Web 控制台location /rustfs-console/{proxy_pass http://rustfs_console/; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; proxy_set_header Host $host; proxy_set_header Origin ; proxy_buffering off;}}三、门户服务器该服务器用于部署前端项目用于部署前端项目用于反向代理域名myserver1.com1、nginx.conf# 1. 将所有 HTTP 请求重定向到 HTTPSserver{listen 80; listen[::]:80; server_name myserver1.com;# 将所有请求永久重定向到 HTTPSreturn 301 https://$host$request_uri;}# 2. 配置 HTTPS 服务 (合并了所有 location)server{listen 443 ssl http2; listen[::]:443 ssl http2; server_name alxuan.fun;# --- SSL 证书配置 ---ssl_certificate /etc/letsencrypt/live/myserver1.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/myserver1.com/privkey.pem;# --- 推荐的 SSL 安全配置 ---ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; ssl_prefer_server_ciphers off; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; add_header Strict-Transport-Security max-age31536000 always; client_max_body_size 500m;# --- 2. 前端静态资源配置 ---location /{alias /apps/media_bao/; index index.html; try_files $uri $uri/ /index.html;}# --- 3. API 接口代理 --location /rustfs/{proxy_pass http://myserver2.com/rustfs-api/; proxy_buffering off; proxy_request_buffering off; client_max_body_size 10240M;# 必须传递 Host 头否则服务器 2 的 Nginx 可能因为 server_name 不匹配而拒绝请求proxy_set_header Host myserver2.com; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Origin ;}location /prod-api/{proxy_pass http://myserver2.com/api/; proxy_set_header Host myserver2.com; 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;}}四、访问流程图常见问题1、问题1数据库连接地址在 Docker 网络中Spring Boot 的数据库连接 URL 绝对不能使用 localhost。localhost 会指向 Spring Boot 容器自身导致连接失败Communications link failure。解决方法使用 MySQL 的容器名如 mysql_server作为主机名。SpringBoot项目配置文件改为spring:datasource:type:com.alibaba.druid.pool.DruidDataSourcedriverClassName:com.mysql.cj.jdbc.Driverdruid:# 主库数据源master:url:jdbc:mysql://mysql8:3306/database-name?useUnicodetruecharacterEncodingutf8zeroDateTimeBehaviorconvertToNulluseSSLfalseserverTimezoneAsia/Shanghaiusername:usernamepassword:password2、问题2请求重定向location /prod-api/{proxy_pass http://myserver2.com/api/; proxy_set_header Host myserver2.com; 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;}proxy_set_header Host myserver2.com; 这行配置的作用是确保了后端服务器能正确地识别出请求的目标是它托管的 myserver2.com 这个站点从而返回正确的数据。总结为了确保多服务器间的域名能够顺利解析和互联配置域名解析到对应 IP 地址需要检查云服务商的安全组规则以及服务器内部的防火墙设置确保 Nginx 容器暴露的端口80 和 443对外部流量开放同时内部服务端口仅对受信任的内网 IP 开放。通过这种分层网络策略既实现了基于域名的公网访问又保障了后端服务集群的私密性与安全性。各位再见这里是鳄鱼杆的空间钓……鳄鱼的杆儿期待下次再会愿你的每一次垂钓之旅都能满载而归。