5.8 KiB
V2 production backend deployment
The production backend runs on 192.168.3.90; Contract Web is deployed separately to Alibaba Cloud. The production compose override therefore disables Contract Web by default and exposes only the HTTPS edge service publicly.
Files
../compose/docker-compose.yml: shared service definitions used by local and smoke environments.../compose/docker-compose.production.yml: backend-only production image, volume, TLS edge, and backup-helper overrides.../compose/docker-compose.production.smtp.yml: optional SMTP password secret mount; include only when email delivery mode issmtp.../compose/.env.production.example: reviewed variable inventory. The real file belongs at/etc/yuqei/production.env, mode0600, outside the repository.preflight-production.py: read-only production configuration gate.
Prepare without changing traffic
- Create an immutable RC commit and publish the three application images by digest. Pin PostgreSQL/pgvector, Redis, MinIO, mc, Nginx, and the backup helper by digest as well.
- Create a new production PostgreSQL/volume set. Do not reuse or rename the smoke database or volumes.
- Mount an off-host backup filesystem at
BACKUP_HOST_DIR. - Place
tls.crt,tls.key, and the AI provider key in protected host directories. When enabling SMTP, also create the file named byCONTRACT_API_IDENTITY_SMTP_PASSWORD_FILE_HOST, mode0600. - Copy
.env.production.exampleto/etc/yuqei/production.env, replace every placeholder, and keep mode0600. Create the file named byPRODUCTION_ALERT_WEBHOOK_URL_FILE, containing only the approved HTTPS alert receiver URL. Keep it owner-only and readable by thenobodyaccount used by the production health unit (for example, ownernobody:nobody, mode0600). - Run the read-only gate:
python3 yuqei-infra/deploy/preflight-production.py \
--env-file /etc/yuqei/production.env \
--artifact-dir /var/lib/yuqei/preflight
- Validate and pull images without starting services:
docker compose \
--project-name yuqei-v2-production \
--env-file /etc/yuqei/production.env \
-f yuqei-infra/compose/docker-compose.yml \
-f yuqei-infra/compose/docker-compose.production.yml \
config --quiet
docker compose \
--project-name yuqei-v2-production \
--env-file /etc/yuqei/production.env \
-f yuqei-infra/compose/docker-compose.yml \
-f yuqei-infra/compose/docker-compose.production.yml \
pull
These commands do not start containers and do not switch traffic.
Optional SMTP secret
The default production example keeps identity email delivery disabled; it does not require an SMTP password file or the SMTP compose overlay. To enable SMTP, set the SMTP mode and related transport fields in the protected production env file, set manual invitations to false, then append the opt-in override to every production Compose command:
docker compose \
--project-name yuqei-v2-production \
--env-file /etc/yuqei/production.env \
-f yuqei-infra/compose/docker-compose.yml \
-f yuqei-infra/compose/docker-compose.production.yml \
-f yuqei-infra/compose/docker-compose.production.smtp.yml \
config --quiet
The override mounts CONTRACT_API_IDENTITY_SMTP_PASSWORD_FILE_HOST as /run/secrets/contract_smtp_password and clears the direct password environment variable. Do not include this override in disabled-mode deployments. The preflight gate checks that an authenticated SMTP configuration uses an absolute, non-empty, owner-only host secret file and an encrypted transport mode.
Provider secret and model config
The provider key file is mounted at /run/secrets/ai_provider_api_key. The enabled default model config must use:
api_key_secret_ref=file:///run/secrets/ai_provider_api_key
Do not send the key in the model-config API payload. Run the Provider acceptance gate before any production start approval.
The production Provider canary is read-only. Run the protected
provider-promotion-canary.yml workflow against at least two distinct HTTPS nodes after
the signed receipt, public keyring, immutable release and image digest are pinned. The
gate sends Cache-Control: no-cache, no-store and fails closed unless every response:
- declares
environment=productionandverification_mode=offline_read_only; - is fresh within
max_observation_age_seconds(120 seconds by default); - reports consistent top-level, check-detail, and promotion-diagnostic state; and
- matches the expected release, receipt, signing key and image digest.
Revocation and kill-switch modes apply the same provenance and freshness checks after all nodes report the blocking control. The workflow performs GET requests only; it does not change a keyring, toggle the kill switch, import a receipt, or invoke any identity write/execute API. Make control changes through the independently approved operations procedure, then use this workflow only to observe their propagation.
Alibaba Cloud frontend variables
The frontend deployment must use server-only values:
CONTRACT_API_BASE_URL=https://<backend-domain>/contract
AI_PLATFORM_API_BASE_URL=https://<backend-domain>/ai
CONTRACT_API_PROXY_SECRET=<same protected proxy secret as Contract API>
AI_PLATFORM_PROXY_SECRET=<same protected AI service secret as AI Platform>
CONTRACT_WEB_SESSION_SECRET=<independent protected session secret>
CONTRACT_WEB_SESSION_SECURE=true
Do not expose any of these secrets through NEXT_PUBLIC_* variables. The browser should call only same-origin Contract Web API routes.
Traffic boundary
Starting postgres, redis, minio, migrations, APIs, and workers is a backend deployment. Starting edge or changing Alibaba Cloud frontend variables/DNS is a separate traffic-change approval. This repository intentionally does not provide an automatic production cutover command.