停止配置 Nginx:使用 HTTPS 部署 Go 与 React 的最简方法
Source: Dev.to

“It Works on My Machine” 陷阱
我们都有过这种经历。你花了数周时间构建一个健壮的应用。你的 Go 后端飞快,React 前端流畅,一切在 localhost:8080 上运行得完美无缺。
但随后进入部署阶段。突然之间,你要面对 VPS 配置、SSL 证书、看起来像象形文字的 Nginx 配置文件,以及令人头疼的 CORS 错误。
我最近用 Go 和 PostGIS 构建了 Geo Engine,一个地理空间后端服务。我想把它部署到带有自定义域名和 HTTPS 的 DigitalOcean Droplet 上,但又不想花几个小时去配置 Certbot 或管理复杂的 Nginx 指令。
下面就是我使用 Docker Compose 和 Caddy(拯救你理智的 Web 服务器)解决问题的方式。
架构 🏗️
我的目标是拥有一个专业的生产环境:
- 前端: 一个基于 React Dashboard(Vite)的界面,部署在
app.geoengine.dev。 - 后端: 一个使用 Go(Chi Router + PostGIS)的 API,部署在
api.geoengine.dev。 - 安全: 为两个子域名自动提供 HTTPS。
- 基础设施: 所有内容均使用 Docker 容器化。
与其将端口 8080 和 5173 暴露给外部,我使用 Caddy 作为入口。Caddy 充当反向代理,自动处理 SSL 证书的生成和续订。
“魔法” Caddyfile ✨
如果你曾经为 nginx.conf 文件头疼不已,那么你一定会喜欢这个。这正是我为两个子域名启用 HTTPS 所需的全部配置:
# The Dashboard (Frontend)
app.geoengine.dev {
reverse_proxy dashboard:80
}
# The API (Backend)
api.geoengine.dev {
reverse_proxy api:8080
}
Caddy 会自动检测域名,向 Let’s Encrypt 申请证书,并完成流量路由。无需 cron 任务,也不需要手动续期。
Docker 设置 🐳
这里是我的 docker-compose.yml 中的秘密配方。请注意,服务不向主机机器暴露端口(Caddy 除外);它们只在 geo-net 网络内部通信。
services:
# Caddy: The only service exposed to the world
caddy:
image: caddy:2-alpine
restart: always
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
networks:
- geo-net
depends_on:
- dashboard
- api
# Backend API
api:
build: ./backend
expose:
- "8080" # Only visible to Caddy, not the internet
environment:
- ALLOWED_ORIGINS=https://app.geoengine.dev
networks:
- geo-net
# Database
db:
image: postgres:15-alpine
# ... config ...
networks:
- geo-net
networks:
geo-net:
driver: bridge
挑战(我卡住的地方) 🚧
这并非一路顺风。以下是两个让我花了几个小时调试的“坑”,希望你不必经历同样的痛苦:
1. “孤儿”迁移容器
我使用一个单独的容器来运行数据库迁移(golang-migrate)。它一直因连接错误而崩溃。
解决办法: 即使是工具容器也必须在同一个 Docker 网络中!我忘记在迁移服务里添加 networks: - geo-net,导致它无法“看到”数据库。
2. CORS 恶棍 💀
在本地开发时,允许 *(通配符)进行 CORS 通常可以工作。但一旦我在使用 HTTPS 的生产环境中部署,前端请求就开始失败。浏览器在安全环境下对凭证(cookie/headers)非常严格。我不得不停止懒惰,使用 rs/cors 库在 Go 代码中明确指定确切的来源。
In Go:
// Don't do this in production:
// AllowedOrigins: []string{"*"} // ❌
// Do this instead:
AllowedOrigins: []string{"https://app.geoengine.dev"} // ✅
通过匹配前端的精确来源,浏览器(以及安全协议)才会满意。
结果
在推送更改后,我运行了 docker compose up -d。大约 30 秒后,Caddy 就为我的站点启用了 HTTPS。
您可以在此查看实时演示:https://app.geoengine.dev
或在 GitHub 上浏览代码:Geo Engine Core
如果您正在部署一个副项目,试试 Caddy。它的感觉像是作弊,但却是最好的那种作弊。
祝编码愉快!