From 0a930f227b87d24829c7cffb12b141e853dd5dec Mon Sep 17 00:00:00 2001 From: Codex Bot Date: Fri, 18 Sep 2026 22:52:25 +0800 Subject: [PATCH] Keep API private on shared Docker network --- .env.example | 5 ++--- .gitea/workflows/docker-deploy.yml | 5 ++--- README.md | 2 +- compose.yml | 16 +++++++++++++--- docs/architecture.md | 15 ++++++++------- scripts/deploy.sh | 1 + src/pk_lab_server/config.py | 2 +- 7 files changed, 28 insertions(+), 18 deletions(-) diff --git a/.env.example b/.env.example index 878730a..4c80048 100644 --- a/.env.example +++ b/.env.example @@ -1,8 +1,7 @@ DEPLOY_IMAGE=pk-lab-server:local -DEPLOY_PORT=18082 POSTGRES_PASSWORD=replace-with-a-long-random-value -PUBLIC_BASE_URL=https://api.example.com -CORS_ORIGINS=https://pk.example.com,https://rice.example.com +PUBLIC_BASE_URL= +CORS_ORIGINS=http://localhost:3000,http://localhost:3002 TEST_AUTH_ENABLED=false XHS_HUB_APP_ID= XHS_HUB_APP_SECRET= diff --git a/.gitea/workflows/docker-deploy.yml b/.gitea/workflows/docker-deploy.yml index 7564069..caeb5e3 100644 --- a/.gitea/workflows/docker-deploy.yml +++ b/.gitea/workflows/docker-deploy.yml @@ -20,9 +20,8 @@ jobs: SOURCE_SERVER: ${{ gitea.server_url }} SOURCE_REPOSITORY: ${{ gitea.repository }} SOURCE_REVISION: ${{ gitea.sha }} - DEPLOY_PORT: ${{ vars.DEPLOY_PORT || '18082' }} PUBLIC_BASE_URL: ${{ vars.PUBLIC_BASE_URL || '' }} - CORS_ORIGINS: ${{ vars.CORS_ORIGINS || 'http://47.83.180.156:3000,http://47.83.180.156:3002,http://localhost:3000,http://localhost:3002' }} + CORS_ORIGINS: ${{ vars.CORS_ORIGINS || 'http://localhost:3000,http://localhost:3002' }} TEST_AUTH_ENABLED: ${{ vars.TEST_AUTH_ENABLED || 'true' }} POSTGRES_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }} XHS_HUB_APP_ID: ${{ secrets.XHS_HUB_APP_ID }} @@ -64,7 +63,7 @@ jobs: test -n "$POSTGRES_PASSWORD" export DEPLOY_IMAGE="pk-lab-server:$SOURCE_REVISION" sh scripts/deploy.sh - curl --fail --silent --show-error "http://127.0.0.1:$DEPLOY_PORT/health" + docker compose -p pk-lab-production exec -T api python -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/health', timeout=3)" - name: Probe public endpoint if: gitea.event_name == 'push' && gitea.ref == 'refs/heads/main' && env.PUBLIC_BASE_URL != '' run: curl --fail --silent --show-error --connect-timeout 10 --max-time 20 "${PUBLIC_BASE_URL%/}/health" diff --git a/README.md b/README.md index 5312d99..dbe50ca 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ ## CI 所需配置 -部署前只需由仓库所有者配置 Secret `POSTGRES_PASSWORD`。用户登录采用 PostgreSQL 持久化 session,服务端只保存随机 token 的 SHA-256 哈希,不需要全局 token 签名密钥。上线真实登录前再配置两套 `XHS_*_APP_ID/SECRET`。拉取源码默认使用 Gitea 工作流自带令牌,也可用 `GITEA_TOKEN` 覆盖。Variables:`DEPLOY_PORT`(默认 `18082`)、`PUBLIC_BASE_URL`、`CORS_ORIGINS`、`TEST_AUTH_ENABLED`。默认允许 `3000`(综合版)和 `3002`(饭类独立版)访问。 +部署前只需由仓库所有者配置 Secret `POSTGRES_PASSWORD`。用户登录采用 PostgreSQL 持久化 session,服务端只保存随机 token 的 SHA-256 哈希,不需要全局 token 签名密钥。上线真实登录前再配置两套 `XHS_*_APP_ID/SECRET`。拉取源码默认使用 Gitea 工作流自带令牌,也可用 `GITEA_TOKEN` 覆盖。后端只在 `pk-lab-public` Docker 网络内以别名 `pk-lab-api:8000` 提供服务,不映射宿主机端口;两个预览站通过同源 `/api` 反向代理访问。可选 Variables:`PUBLIC_BASE_URL`、`CORS_ORIGINS`、`TEST_AUTH_ENABLED`。 当前流水线默认 `TEST_AUTH_ENABLED=true`,让两个公网预览可以创建明确隔离的测试身份。接入真实小红书 App ID/Secret 后,必须把该变量改成 `false`,关闭 `dev:` 登录路径。 diff --git a/compose.yml b/compose.yml index 3d97889..6e71339 100644 --- a/compose.yml +++ b/compose.yml @@ -25,11 +25,11 @@ services: tmpfs: [/tmp:rw,noexec,nosuid,size=64m] mem_limit: 512m pids_limit: 128 - ports: - - "${DEPLOY_BIND_IP:-0.0.0.0}:${DEPLOY_PORT:-18082}:8000" + expose: + - "8000" environment: DATABASE_URL: postgresql+psycopg://pk_lab:${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD}@postgres:5432/pk_lab - PUBLIC_BASE_URL: ${PUBLIC_BASE_URL:-http://localhost:18082} + PUBLIC_BASE_URL: ${PUBLIC_BASE_URL:-} CORS_ORIGINS: ${CORS_ORIGINS:-http://localhost:3000,http://localhost:3002} TEST_AUTH_ENABLED: ${TEST_AUTH_ENABLED:-false} XHS_HUB_APP_ID: ${XHS_HUB_APP_ID:-} @@ -39,7 +39,17 @@ services: depends_on: postgres: condition: service_healthy + networks: + default: + public: + aliases: + - pk-lab-api volumes: postgres-data: name: pk-lab-postgres-data + +networks: + public: + name: pk-lab-public + external: true diff --git a/docs/architecture.md b/docs/architecture.md index 11c5e80..c997c52 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -3,9 +3,9 @@ ## 三仓关系 ```text -pk-lab-xhs (综合小程序 + :3000 公网预览) ─┐ - ├─ HTTPS ─ pk-lab-server (:18082) ─ PostgreSQL 16 -rice-pk-xhs (饭类小程序 + :3002 公网预览) ───┘ +pk-lab-xhs (:3000 公网预览 + Nginx /api 代理) ─┐ + ├─ pk-lab-public Docker 网络 ─ pk-lab-api:8000 ─ PostgreSQL 16 +rice-pk-xhs (:3002 公网预览 + Nginx /api 代理) ──┘ ``` 小程序源码不是由 Nginx 托管的 H5。两个前端容器是功能一致的浏览器验收入口;正式小程序仍由小红书开发者工具或后续接入 `xhs-mp-cli` 上传。 @@ -40,20 +40,21 @@ Secrets: Variables: -- `DEPLOY_PORT=18082` -- `PUBLIC_BASE_URL=https://你的-api-域名` -- `CORS_ORIGINS=https://综合预览域名,https://饭类预览域名` +- `PUBLIC_BASE_URL`:可选,配置未来的正式 API 域名。 +- `CORS_ORIGINS`:可选,仅跨域访问 API 时配置。 - `TEST_AUTH_ENABLED=true`(公网预览阶段);小程序真实登录验收后改为 `false`。 ### 两个前端 -每个仓库可配置 `API_BASE_URL` Variable;综合版默认 `DEPLOY_PORT=3000`,独立版默认 `DEPLOY_PORT=3002`。 +综合版默认 `DEPLOY_PORT=3000`,独立版默认 `DEPLOY_PORT=3002`。预览默认使用同源 `/api`,无需配置 `API_BASE_URL`;仅跨域部署时覆盖该变量。 ## 永久运行保证 - API 与 PostgreSQL 均为 `restart: unless-stopped`。 - PostgreSQL 使用固定具名卷 `pk-lab-postgres-data`。 - 后端部署固定 Compose project 为 `pk-lab-production`,只执行 `docker compose up -d --wait`。 +- 三个服务共享外部 Docker 网络 `pk-lab-public`;后端使用固定网络别名 `pk-lab-api`,前端 Nginx 通过容器 DNS 发现后端。 +- 后端 API 不映射宿主机端口,公网只开放两个前端入口。 - 前端以固定容器名更新并设置重启策略;CI 结束不会删除新容器。 - PostgreSQL 不映射公网端口,只有 API 容器能访问。 diff --git a/scripts/deploy.sh b/scripts/deploy.sh index 38082d5..b6a99d3 100644 --- a/scripts/deploy.sh +++ b/scripts/deploy.sh @@ -3,5 +3,6 @@ set -eu : "${DEPLOY_IMAGE:?Set DEPLOY_IMAGE}" : "${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD}" +docker network inspect pk-lab-public >/dev/null 2>&1 || docker network create pk-lab-public docker compose -p pk-lab-production up -d --remove-orphans --wait docker compose -p pk-lab-production ps diff --git a/src/pk_lab_server/config.py b/src/pk_lab_server/config.py index f01ba3b..8bc4e9c 100644 --- a/src/pk_lab_server/config.py +++ b/src/pk_lab_server/config.py @@ -10,7 +10,7 @@ class Settings(BaseSettings): database_url: str = "sqlite:///./pk-lab.db" session_ttl_seconds: int = 60 * 60 * 24 * 30 cors_origins: str = "http://localhost:3000,http://localhost:3002" - public_base_url: str = "http://localhost:18082" + public_base_url: str = "" test_auth_enabled: bool = False xhs_token_url: str = "https://miniapp.xiaohongshu.com/api/rmp/token" xhs_session_url: str = "https://miniapp.xiaohongshu.com/api/rmp/session"