ServBay 与 Docker 协同工作常见问题解答 (FAQ) 
在使用 ServBay 进行本地 Web 开发时,您可能希望结合 Docker 使用容器化环境。本 FAQ 旨在解答在 ServBay 与 Docker 协同工作时可能遇到的一些常见问题,支持 macOS 和 Windows 环境,包括从 Docker 访问 ServBay 服务以及使用 ServBay 反向代理 Docker 容器内的应用。
Q1: 为什么 ServBay 会修改我系统的 hosts 文件?我能阻止吗? 
ServBay 通过在系统的 hosts 文件中添加条目(例如 mysite.servbay.demo 127.0.0.1),使您能够使用自定义的本地域名(如 mysite.servbay.demo)访问本地开发网站。这些网站实际运行在您本机的 127.0.0.1 地址上。
但是因为Docker的机制,会从主机系统(macOS 或 Windows)中读取hosts文件,造成mysite.servbay.demo会被解析至127.0.0.1,导致Docker访问了错误的(Docker容器自身)服务。
核心机制:
- 当您在 ServBay 中创建一个新的网站并指定一个域名(如 example.servbay.demo)时,ServBay 会自动将该域名指向127.0.0.1。
- 这是实现本地友好域名访问的标准做法。若不修改 hosts文件,您将只能通过http://127.0.0.1:PORT这样的方式访问,无法使用自定义域名。
可以阻止吗?
理论上,您可以手动移除 ServBay 添加的条目,但这会使您无法通过 ServBay 设置的域名访问您的本地网站,这违背了 ServBay 提供便捷本地开发体验的初衷。ServBay 的核心功能之一就是简化本地网站的创建和访问。如果您不希望 ServBay 管理特定域名的 hosts 条目,建议不要在 ServBay 中为该域名创建网站。
对于大多数本地开发场景,ServBay 自动管理 hosts 文件是期望的行为,能极大简化开发流程。
Q2: 我的 Docker 容器如何通过域名正确访问由 ServBay 在主机上管理的网站 (例如 mysite.servbay.demo)? 
这是一个常见的需求,但需要正确处理以避免问题。当 ServBay 在您的主机系统(macOS 或 Windows)上运行一个网站(例如 mysite.servbay.demo,它在主机上解析到 127.0.0.1)时,Docker 容器内的 127.0.0.1 指向的是容器自身,而不是主机系统。
错误的方法:直接使用 host.docker.internal 作为 URL 的主机名访问 ServBay 网站
虽然 Docker Desktop for Mac (和 Windows) 提供了特殊的 DNS 名称 host.docker.internal 来从容器内部解析到主机的 IP 地址,但强烈不推荐直接在 URL 中使用它来访问 ServBay 托管的网站 (例如,访问 http://host.docker.internal/ 并期望它能解析到 mysite.servbay.demo)。
这是因为当您这样做时,发送到 ServBay Web 服务器 (如 Caddy 或 Nginx) 的 HTTP 请求头中的 Host 字段会是 host.docker.internal。ServBay 的 Web 服务器依赖这个 Host 头来确定请求的是哪个网站。如果 Host 头是 host.docker.internal 而不是 mysite.servbay.demo,Web 服务器将无法正确路由请求到目标网站,或者在 HTTPS 情况下,会导致 SNI (Server Name Indication) 错误,因为提供的 SSL 证书是为 mysite.servbay.demo 颁发的,而不是为 host.docker.internal。
正确的解决方案:在 Docker 容器启动时添加 extra_hosts
为了让 Docker 容器内的应用能够使用 ServBay 网站的原始域名(如 mysite.servbay.demo)并正确发送 Host 头,您应该在容器的 /etc/hosts 文件中添加一个条目,将该域名指向主机的 IP 地址。这可以通过 extra_hosts (在 docker-compose.yml 中) 或 --add-host (在使用 docker run 时) 实现,并将域名指向 host.docker.internal 或更推荐的 host-gateway。
- 使用 - docker run:bash- docker run --add-host=mysite.servbay.demo:host-gateway ... your_image1- ( - host-gateway是一个特殊值,Docker 会将其替换为宿主机的内部 IP 地址。对于 Docker 20.10+ 版本,这通常是- host.docker.internal的一个更底层的别名。)
- 使用 - docker-compose.yml:yaml- version: '3.8' # 或更高版本 services: myapp: image: your_image extra_hosts: - "mysite.servbay.demo:host-gateway" # 或者 "mysite.servbay.demo:host.docker.internal" # ... 其他配置1
 2
 3
 4
 5
 6
 7
配置后,在您的 Docker 容器内:
- 当应用尝试访问 http://mysite.servbay.demo或https://mysite.servbay.demo时,容器的/etc/hosts文件会将mysite.servbay.demo解析到 macOS 主机的 IP 地址。
- 请求将被发送到主机上运行的 ServBay Web 服务器。
- HTTP Host头将正确地为mysite.servbay.demo,允许 ServBay 正确路由请求并提供正确的 SSL 证书(如果使用 HTTPS)。
Q3: 我的 Docker 容器如何连接到由 ServBay 管理的数据库(如 MySQL, PostgreSQL)或其他非 HTTP 服务? 
与访问基于域名的 Web 服务不同,连接数据库或其他不依赖 SNI 的 TCP 服务时,使用 host.docker.internal 作为服务器的主机名是推荐且有效的方法。
步骤:
- 确保 ServBay 中的数据库软件包(或其他服务)已启动 并且配置为允许来自主机的连接(通常默认配置即可用于本地开发)。
- 在您的 Docker 容器中,配置数据库连接(或服务连接)时: - 主机名 (Hostname/Server): 使用 host.docker.internal。
- 端口 (Port): 使用 ServBay 中为该数据库软件包(或服务)配置的端口(例如,MySQL 默认是 3306,PostgreSQL 默认是5432)。
- 用户名/密码: 使用您在 ServBay 数据库(或服务)中设置的凭据。
 
- 主机名 (Hostname/Server): 使用 
示例 (连接到 ServBay 管理的 MySQL): 假设 ServBay 上的 MySQL 运行在默认端口 3306。在 Docker 容器的应用中,连接字符串或配置可能如下:
- 主机: host.docker.internal
- 端口: 3306
- 用户: your_db_user
- 密码: your_db_password
Q4: 当 Docker 容器通过域名 (使用 extra_hosts 配置) 访问 ServBay 上的 HTTPS 网站 (使用 ServBay User CA 证书) 时,如何让容器信任该 CA? 
假设您已按照 Q2 的建议,使用 extra_hosts 或 --add-host 将 secure.servbay.demo 指向 host-gateway。如果 secure.servbay.demo 使用的是由 ServBay User CA 颁发的 SSL 证书,您的 Docker 容器默认不信任此 CA,会导致 SSL 握手失败。
ServBay CA 文件路径:
- ServBay User CA 根证书:- macOS: /Applications/ServBay/ssl/private/ServBay-Private-CA-ECC-Root.crt
- Windows: C:\ServBay\ssl\private\ServBay-Private-CA-ECC-Root.crt
 
- macOS: 
- 包含 ServBay User CA 和 Public CA 及 Mozilla 根证书的 PEM 文件:- macOS (ARM 架构): /Applications/ServBay/package/common/openssl/3.2/cacert.pem
- macOS (Intel 架构): /Applications/ServBay/package/common/openssl/1.1.1u/cacert.pem
- Windows: C:\ServBay\package\common\openssl\3.3\cacert.pem
 
- macOS (ARM 架构): 
解决方案概述:
有几种方法可以让 Docker 容器信任 ServBay User CA:
- 方法 1: 构建时系统级信任 (通过 Dockerfile) - 推荐用于需要广泛信任CA且镜像可自定义的场景。
- 方法 2: 运行时应用级信任 (通过卷挂载和环境变量) - 适用于特定应用信任CA或不想修改镜像的场景。
- 方法 3: 运行时系统级信任 (通过卷挂载和自定义启动命令) - 适用于需要在运行时让整个容器系统信任CA,但不想构建自定义镜像的场景。
方法 1: 构建时系统级信任 (通过 Dockerfile) 
这种方法在构建 Docker 镜像时将 CA 证书集成到系统信任库中。
- 准备 CA 文件: 将 ServBay User CA 根证书复制到您的 Docker 构建上下文目录 (例如,与 Dockerfile 同级): - macOS: /Applications/ServBay/ssl/private/ServBay-Private-CA-ECC-Root.crt
- Windows: C:\ServBay\ssl\private\ServBay-Private-CA-ECC-Root.crt
 
- macOS: 
- Dockerfile 示例 (Debian/Ubuntu):dockerfile# Dockerfile FROM ubuntu:latest COPY ServBay-Private-CA-ECC-Root.crt /usr/local/share/ca-certificates/ServBay-User-CA.crt RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates && \ update-ca-certificates && \ rm -rf /var/lib/apt/lists/*1
 2
 3
 4
 5
 6
- Dockerfile 示例 (Alpine):dockerfile# Dockerfile FROM alpine:latest COPY ServBay-Private-CA-ECC-Root.crt /usr/local/share/ca-certificates/ServBay-User-CA.crt RUN apk add --no-cache ca-certificates && update-ca-certificates1
 2
 3
 4
- Docker Compose 构建:yaml# docker-compose.yml version: '3.8' services: myapp: build: context: ./app_service # 目录包含 Dockerfile 和 ServBay-Private-CA-ECC-Root.crt dockerfile: Dockerfile extra_hosts: ["secure.servbay.demo:host-gateway"]1
 2
 3
 4
 5
 6
 7
 8
方法 2: 运行时应用级信任 (通过卷挂载和环境变量) 
这种方法将 CA 证书文件挂载到容器中,并配置特定应用程序通过环境变量来使用它。
- docker-compose.yml示例:yaml您需要查阅应用的文档来确定正确的环境变量。- version: '3.8' services: myapp: image: some-base-image volumes: # macOS 路径示例 - /Applications/ServBay/ssl/private/ServBay-Private-CA-ECC-Root.crt:/etc/ssl/certs/MyCustomCA.crt:ro # Windows 路径示例 (请根据实际操作系统调整) # - C:\ServBay\ssl\private\ServBay-Private-CA-ECC-Root.crt:/etc/ssl/certs/MyCustomCA.crt:ro environment: # 示例 for Node.js: - NODE_EXTRA_CA_CERTS=/etc/ssl/certs/MyCustomCA.crt # 示例 for Python (requests): # - REQUESTS_CA_BUNDLE=/etc/ssl/certs/MyCustomCA.crt # 示例 for generic SSL_CERT_FILE: # - SSL_CERT_FILE=/etc/ssl/certs/MyCustomCA.crt extra_hosts: ["secure.servbay.demo:host-gateway"]1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
方法 3: 运行时系统级信任 (通过卷挂载和自定义启动命令) 
这种方法结合了卷挂载和在容器启动时执行命令来更新系统 CA 存储。这避免了构建自定义镜像,但可能使启动命令更复杂。
- docker-compose.yml示例 (基于 Debian/Ubuntu 的镜像):yaml注意事项:- version: '3.8' services: myapp: image: ubuntu:latest # 或其他兼容 update-ca-certificates 的镜像 volumes: # 将主机上的 CA 证书直接挂载到系统期望的目录 # macOS 路径示例 - /Applications/ServBay/ssl/private/ServBay-Private-CA-ECC-Root.crt:/usr/local/share/ca-certificates/ServBay-User-CA.crt:ro # Windows 路径示例 (请根据实际操作系统调整) # - C:\ServBay\ssl\private\ServBay-Private-CA-ECC-Root.crt:/usr/local/share/ca-certificates/ServBay-User-CA.crt:ro # 覆盖 command 以在启动时更新证书并运行原命令 # 确保容器以 root 或有权限执行 update-ca-certificates 的用户运行 command: > sh -c " echo 'Attempting to update CA certificates...' && if command -v update-ca-certificates > /dev/null; then if [ ! -f /usr/bin/update-ca-certificates ]; then apt-get update && apt-get install -y --no-install-recommends ca-certificates; fi && update-ca-certificates && echo 'CA certificates updated.' else echo 'update-ca-certificates command not found, skipping CA update.' fi && echo 'Starting application...' && exec your_original_application_command_here # 替换为镜像的原始 CMD 或您的应用启动命令 " extra_hosts: ["secure.servbay.demo:host-gateway"] # 如果需要以 root 身份运行更新命令但应用以非 root 运行,可能需要更复杂的 entrypoint 脚本 # user: root # 临时切换到 root,或者通过 entrypoint 脚本处理权限1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28- 复杂性: 修改 command或entrypoint可能会很复杂,特别是对于有复杂启动逻辑的官方镜像。您需要确保正确地执行原始的应用程序启动命令。
- 权限: update-ca-certificates通常需要 root 权限。如果容器默认以非 root 用户运行,此方法可能失败或需要提权。
- 包依赖: 容器内必须有 ca-certificates包和update-ca-certificates命令。示例脚本尝试安装它(如果不存在且是基于 apt 的系统)。
- 启动时间: 每次容器启动时都执行这些检查和命令会增加启动时间。
- Alpine Linux: 对于 Alpine,命令将是 apk add --no-cache ca-certificates && update-ca-certificates。
 
- 复杂性: 修改 
选择哪种方法?
- 如果可以构建自定义镜像且希望CA被广泛信任,方法 1 通常是最佳选择。
- 如果不想修改镜像,且只需要特定应用信任 CA,方法 2 很方便。
- 如果不想构建镜像,对系统的改动更小,并且需要系统级信任,方法 3 是最合适的选择。
对于公共 CA 颁发的证书 (如 Let's Encrypt): 如果您的 ServBay 网站使用的是通过 ACME 协议从公共 CA(如 Let's Encrypt)获取的证书,那么大多数基础 Docker 镜像默认已信任这些公共 CA,通常不需要额外操作。
Q5: 如何使用 ServBay 为运行在 Docker 容器内的应用设置域名并进行反向代理? 
您可能在 Docker 容器中运行了一个应用(例如,一个 Node.js 服务监听容器内的 3000 端口),并希望通过 ServBay 为其分配一个友好的域名(如 myapp.servbay.demo)从主机浏览器访问,同时利用 ServBay 管理 SSL 证书。
步骤:
- 运行 Docker 容器并映射端口到主机的 - 127.0.0.1: 确保您的 Docker 容器将其应用端口映射到主机系统(macOS 或 Windows)上的一个端口,并且绑定到- 127.0.0.1以确保该端口仅在主机本地可访问,防止外部网络直接访问。bash- # 示例:容器内应用监听 3000 端口,映射到主机的 127.0.0.1:3001 docker run -d -p 127.0.0.1:3001:3000 your-docker-app-image1
 2- 在这个例子中,容器内的应用监听 - 3000端口,现在可以通过主机的- http://127.0.0.1:3001访问。
- 在 ServBay 中添加新网站并配置反向代理: - 打开 ServBay 管理界面。
- 点击“添加网站”。
- 域名: 输入您希望使用的域名,例如 myapp.servbay.demo。
- 网站类型: 从下拉菜单中选择 “反向代理”。
- IP 地址: 在右侧出现的输入框中,输入 127.0.0.1。
- 端口: 输入您在步骤 1 中 Docker 容器映射到主机的端口号,例如 3001。
- 点击“保存”或“添加”。
 
- (可选) 配置 SSL: 网站添加后,您可以进入该网站的设置,为其启用 SSL。ServBay 支持通过 ACME 协议自动申请 Let's Encrypt 等公共 CA 的证书,或者您也可以选择使用 ServBay User CA 或 ServBay Public CA。ServBay 将处理 SSL 终止,而 ServBay 到 Docker 容器的连接可以是普通的 HTTP (即 - http://127.0.0.1:3001)。
- 测试访问: 保存 ServBay 中的配置后,您应该能够通过浏览器访问 - http://myapp.servbay.demo或- https://myapp.servbay.demo(如果配置了 SSL)。ServBay 会将请求代理到运行在 Docker 容器内的应用。
工作流程: 用户浏览器 -> https://myapp.servbay.demo -> ServBay (处理 SSL, 查找反向代理规则) -> http://127.0.0.1:3001 (主机上的端口) -> Docker 容器内的应用。
总结 
ServBay 极大地简化了在 macOS 和 Windows 上的本地 Web 开发。当与 Docker 结合使用时:
- 要从 Docker 容器访问 ServBay 托管的网站,请使用 extra_hosts或--add-host将网站域名指向host-gateway,以确保Host头正确传递并避免 SNI 问题。
- 要从 Docker 容器访问 ServBay 托管的数据库或其他非 HTTP 服务,使用 host.docker.internal作为服务器主机名通常是简单有效的。
- 要让 Docker 容器信任 ServBay User CA 颁发的 SSL 证书,需将 CA 证书复制到 Docker 镜像中并更新其信任存储。
- 要使用 ServBay 反向代理 Docker 容器内的应用,在 ServBay 中选择“反向代理”网站类型,并指向 Docker 容器映射到主机 127.0.0.1的端口。
始终确保 ServBay 中的相关软件包(Web 服务器、数据库等)以及您的 Docker 容器都已正确配置并正在运行。
