服务器 | 基于 Docker 的 Nginx 多服务器部署与域名互联访问实战指南
·
文章目录
概要
在构建现代化的分布式系统或微服务架构时,如何在多台服务器之间高效地管理流量入口,并实现基于域名的灵活访问?
传统的 Nginx 部署方式往往伴随着繁琐的环境配置和迁移成本,而 Docker 的引入则为这一过程带来了标准化的解决方案。
本文将深入探讨如何利用 Docker 容器化技术,在多台服务器上部署 Nginx 实例,并通过反向代理与 DNS 解析策略,构建一个高可用、易扩展的域名互联访问体系。
一、环境配置
1、软件资源
| 名称 | 型号 | 数量 |
|---|---|---|
| Linux服务器 | Alibaba Cloud Linux 3.2104 LTS 64位 | 2 |
| Web 服务器 | jonasal/nginx-certbot:2.4.1-nginx1.21.0-alpine | 2 |
| SpringBoot项目 | SpringBoot 3.x | 1 |
| 数据库 | mysql-8 | 1 |
| 缓存数据库 | redis:6.0.20 | 1 |
| 分布式对象存储系统 | rustfs:latest | 1 |
| 域名 | 阿里云域名 | 2 |

2、Docker安装
# 添加 Docker-ce 软件包源
sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# 修正仓库配置中的版本号(Alibaba Cloud Linux 4 对应 RHEL 8,因此使用 8)
sudo sed -i 's/$releasever/8/g' /etc/yum.repos.d/docker-ce.repo
# 清理并刷新缓存
sudo yum clean all
sudo yum makecache
sudo yum update
# 安装 Docker 社区版及相关组件
sudo yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
二、后端服务器
该服务器作为后端服务器:
- 用于部署后端项目、数据库、缓存、对象存储等。
- 域名:myserver2.com
- Docker统一网络: 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-c
restart: unless-stopped
image: jonasal/nginx-certbot:2.4.1-nginx1.21.0-alpine
# network_mode: "host"
ports:
- "80:80"
- "443:443"
environment:
CERTBOT_EMAIL: f15176258474@163.com
volumes:
- /root/dcs/nginx/nginx:/etc/nginx/user_conf.d
- /root/dcs/nginx/letsencrypt:/etc/letsencrypt
- /root/apps/frontend:/apps
networks:
- pic-net
# ==================== Bao-Admin ====================
bao-admin:
image: openjdk:17-jdk
working_dir: /app
volumes:
- /root/apps/backend/bao-admin.jar:/app/app.jar
container_name: bao-admin
depends_on:
mysql:
condition: service_healthy # 等待 MySQL 健康
redis:
condition: service_healthy # 等待 Redis 健康
restart: always
networks:
- pic-net
command: >
java
-Xms256m -Xmx512m
-XX:MaxMetaspaceSize=256m
-Xss512k
-XX:+UseSerialGC
-Dspring.profiles.active=druid-prod
-Djava.security.egd=file:/dev/./urandom
-Duser.timezone=Asia/Shanghai
-jar /app/app.jar
# Docker 资源限制
deploy:
resources:
limits:
cpus: '1.0'
memory: 768M
ulimits:
nofile:
soft: 65536
hard: 65536
# ==================== RustFS ====================
rustfs:
image: rustfs/rustfs:latest
container_name: rustfs
user: "1000:1000"
restart: always
networks:
- pic-net
ports:
- "9000:9000"
- "9001:9001"
volumes:
- /root/dcs/rustfs/data:/data
- /root/dcs/rustfs/logs:/var/log/rustfs
environment:
- TZ=Asia/Shanghai
- RUSTFS_ADDRESS=0.0.0.0:9000
- RUSTFS_CONSOLE_ENABLE=true
- RUSTFS_CONSOLE_ADDRESS=0.0.0.0:9001
- RUSTFS_ACCESS_KEY=username
- RUSTFS_SECRET_KEY=password
- RUSTFS_VOLUMES=/data
deploy:
resources:
limits:
memory: 2G
cpus: '1.0'
reservations:
memory: 1G
cpus: '0.5'
healthcheck:
# 使用 curl 检查根路径,如果返回 403 则视为健康(exit 0),否则视为不健康(exit 1)
test: ["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.20
container_name: redis-server
networks:
- pic-net
ports:
- "63790:6379"
volumes:
- /root/dcs/redis/redis.conf:/usr/local/redis/redis.conf
- /root/dcs/redis/redis-data:/data
command: redis-server /usr/local/redis/redis.conf
deploy:
resources:
limits:
cpus: '0.5'
memory: 256M
reservations:
cpus: '0.1'
memory: 64M
healthcheck:
# 在 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.28
container_name: mysql8
restart: always
networks:
- pic-net
ports:
- "33060:3306"
environment:
TZ: Asia/Shanghai
MYSQL_ROOT_PASSWORD: 'password'
volumes:
- /root/dcs/mysql/data:/var/lib/mysql
- /root/dcs/mysql/conf:/etc/mysql/conf.d
- /root/dcs/mysql/logs:/var/log/mysql
command:
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_unicode_ci
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
deploy:
resources:
limits:
cpus: '1.0'
memory: 768M
ulimits:
nofile:
soft: 65535
hard: 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 对象存储 API
location /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.com
1、nginx.conf
# 1. 将所有 HTTP 请求重定向到 HTTPS
server {
listen 80;
listen [::]:80;
server_name myserver1.com;
# 将所有请求永久重定向到 HTTPS
return 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-age=31536000" 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.DruidDataSource
driverClassName: com.mysql.cj.jdbc.Driver
druid:
# 主库数据源
master:
url: jdbc:mysql://mysql8:3306/database-name?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=Asia/Shanghai
username: username
password: password
2、问题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 开放。

通过这种分层网络策略,既实现了基于域名的公网访问,又保障了后端服务集群的私密性与安全性。
各位再见!这里是 鳄鱼杆的空间,钓……鳄鱼的杆儿!
期待下次再会!
愿你的每一次垂钓之旅都能满载而归。

更多推荐


所有评论(0)