本指南用于搭建受控的 Development 预览环境。它复用 1Panel 中已安装的 SQL Server、Redis、RabbitMQ、MinIO 与 AgileConfig,不新建、升级或删除这些基础设施容器。前端由 1Panel/OpenResty 静态托管,Gateway、API、JobHost 由 systemd 管理。
不要当正式生产。 须配合密码访问 / IP 白名单 / VPN。Production 门禁见 生产配置与启动守卫。
访问形态(二选一,配置只差 Origin / Endpoint / OpenResty listen):
| 模式 | 浏览器入口示例 | MinIO 浏览器可达地址示例 |
|---|---|---|
| 域名 + HTTPS | https://app.example.com | https://files.example.com |
| 仅 IP(家宽常见) | http://<公网IP>:8088(80 常被光猫占用) | http://<公网IP>:9000 或反代 |
下文占位符:
<PUBLIC_BASE>:https://app.example.com或http://10.10.10.10:8088<FILES_BASE>:https://files.example.com或http://10.10.10.10:9000- 环境名固定
preview(systemd / 目录后缀)
拓扑
浏览器 → <PUBLIC_BASE> └─ 1Panel OpenResty ├─ / → 静态前端 ├─ /api /hubs /health → 127.0.0.1:8082 └─ Gateway :8082 → API :8080 ├─ SQL / Redis / RabbitMQ(宿主机映射端口) ├─ AgileConfig 客户端 └─ MinIO 预签名 → <FILES_BASE>
systemd: bitzorcas-jobhost-preview :8081 bitzorcas-api-preview :8080 bitzorcas-gateway-preview :8082原则:
- API / JobHost / Gateway 只绑
127.0.0.1,不对公网暴露 8080–8082。 - JobHost 占用 8081;OpenResty 对外入口勿再用 8081(家宽可用 8088)。
- 勿公网暴露 AgileConfig 管理端、MinIO Console、SQL 管理端口。
服务器需要:.NET 10 Runtime、systemd、curl、unzip(前端在开发机构建)。
1. 核对 1Panel 基础设施
在「应用商店 → 已安装」记录 SQL Server、Redis、RabbitMQ、MinIO、AgileConfig 的 宿主机映射端口 与凭据。systemd 不能用 Docker 内部服务名。
sudo docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'sudo ss -lntp | grep -E ':(1433|6379|5672|9000|15000|80|8088)\b' || trueMinIO:Region 与后端一致(示例 cn-east-1);CORS 允许 <PUBLIC_BASE> 的 PUT;改 CORS 只重建容器、不 down -v。
AgileConfig:默认 AppId modern-api-01;管理端仅内网/VPN。
2. 服务器一次性准备
# 安装 aspnetcore-runtime-10.0(以发行版文档为准)dotnet --list-runtimes
sudo mkdir -p /www/apps /www/releases /www/backups /www/scripts \ /www/sites/bitzorcas-preview /etc/bitzorcas /var/lib/bitzorcas/preview开发机上传脚本:
# ① 一次传齐部署脚本、环境模板和 OpenResty 片段,避免服务器端版本错配。scp scripts/deploy/deploy.sh scripts/deploy/deploy-frontend.sh \ scripts/deploy/deploy-blue-green.sh scripts/deploy/deploy-rollback.sh \ scripts/deploy/setup-1panel-openresty.sh \ scripts/deploy/env.example \ deploy/1panel/openresty-app.locations.conf \ deploy/1panel/openresty-app.locations-blue-green.conf \ deploy/1panel/openresty-upstream.conf \ deploy/1panel/openresty-minio.locations.conf \ deploy@server:/tmp/# ② lib/common.sh 必须单独上传,蓝绿脚本会 source 它。scp -r scripts/deploy/lib deploy@server:/tmp/deploy-lib服务器安装:
# ① 可执行脚本、敏感配置和代理片段分别使用受控权限安装。sudo install -m 0755 /tmp/deploy.sh /www/scripts/deploy.shsudo install -m 0755 /tmp/deploy-frontend.sh /www/scripts/deploy-frontend.shsudo install -m 0755 /tmp/deploy-blue-green.sh /www/scripts/deploy-blue-green.shsudo install -m 0755 /tmp/deploy-rollback.sh /www/scripts/deploy-rollback.shsudo install -m 0755 /tmp/setup-1panel-openresty.sh /www/scripts/setup-1panel-openresty.shsudo install -m 0600 /tmp/env.example /etc/bitzorcas/preview.env# ② 蓝绿三件套依赖 /www/scripts/lib/common.sh,漏拷会直接失败。sudo mkdir -p /www/scripts/1panel /www/scripts/libsudo install -m 0644 /tmp/deploy-lib/common.sh /www/scripts/lib/common.shsudo install -m 0644 /tmp/openresty-app.locations.conf /www/scripts/1panel/sudo install -m 0644 /tmp/openresty-app.locations-blue-green.conf /www/scripts/1panel/sudo install -m 0644 /tmp/openresty-upstream.conf /www/scripts/1panel/sudo install -m 0644 /tmp/openresty-minio.locations.conf /www/scripts/1panel/3. /etc/bitzorcas/preview.env
sudo nano /etc/bitzorcas/preview.envsudo chmod 600 /etc/bitzorcas/preview.env骨架(连接目标用 127.0.0.1 + 1Panel 宿主机端口):
ASPNETCORE_ENVIRONMENT=DevelopmentDOTNET_ENVIRONMENT=DevelopmentBITZORCAS_BIND_ADDRESS=127.0.0.1
ConnectionStrings__Default="Server=127.0.0.1,<SQL_PORT>;Database=bitzorcas;User Id=<USER>;Password=<PWD>;TrustServerCertificate=true;Encrypt=false"RabbitMq__Host=127.0.0.1RabbitMq__Port=<MQ_PORT>RabbitMq__User=<USER>RabbitMq__Password=<PWD>RabbitMq__VirtualHost=/Redis__Enabled=trueRedis__ConnectionString="127.0.0.1:<REDIS_PORT>,password=<PWD>"
Jwt__Secret=<openssl rand -base64 48>PiiEncryption__SearchHashKey=<openssl rand -base64 32>DataProtection__ApplicationName=bitzorcas-previewDataProtection__RedisKey=bitzorcas:dataprotection:preview
FileStorage__DefaultProvider=MinioFileStorage__S3__Endpoint=<FILES_BASE>FileStorage__S3__AccessKey=<AK>FileStorage__S3__SecretKey=<SK>FileStorage__S3__BucketName=bitzorcas-filesFileStorage__S3__Region=cn-east-1FileStorage__S3__UseSsl=trueFileStorage__S3__ForcePathStyle=trueFileStorage__S3__CreateBucketIfNotExists=true# 仅 IP 且 http 时:UseSsl=false
# 必须与浏览器地址栏完全一致(含协议与端口),否则登录 Cookie Origin 会 403Frontend__BaseUrl=<PUBLIC_BASE>Cors__AllowAnyOrigin=falseCors__AllowedOrigins__0=<PUBLIC_BASE>Cors__AllowCredentials=true# HTTP 预览建议:# Auth__WebRefreshCookie__Secure=false# Auth__WebRefreshCookie__SameSite=Lax
# 共享预览文档面:产品 Host 要求正式文档会话,外层继续做纵深防御OpenApi__Enabled=trueOpenApi__RequireAuthentication=trueOpenApi__PersistAuthentication=falseOpenApi__Servers__0__Url=<PUBLIC_BASE>OpenApi__Servers__0__Description=1Panel预览入口
ForwardedHeaders__ForwardLimit=2ForwardedHeaders__KnownProxies__0=127.0.0.1Gateway__KnownProxies__0=127.0.0.1/8Gateway__DownstreamHealthCheckUrl=http://127.0.0.1:8080/health/live# 集群 id 禁止连字符(systemd 会忽略 api-cluster);下游也可由 deploy.sh 写 appsettings.Deploy.jsonReverseProxy__Clusters__api__Destinations__d1__Address=http://127.0.0.1:8080/ReverseProxy__Clusters__signalr__Destinations__d1__Address=http://127.0.0.1:8080/ReverseProxy__Clusters__files__Destinations__d1__Address=http://127.0.0.1:8080/
Licensing__Runtime__Enabled=trueLicensing__Runtime__PolicyId=community.small.v1Licensing__Runtime__Environment=developmentLicensing__Runtime__ProductId=bitzorcas-modernLicensing__Runtime__ProductVersion=1.0.0Licensing__Runtime__TenancyMode=multi-tenantLicensing__Runtime__DeploymentIdentityPath=/www/apps/preview/.bitzorcas/license/deployment-idLicensing__Runtime__OfflineLicensePath=/www/apps/preview/.bitzorcas/license/runtime-license.json
BITZORCAS_DISABLE_AGILECONFIG=0AgileConfig__Enabled=trueAgileConfig__AppId=modern-api-01AgileConfig__Secret=<SECRET>AgileConfig__Nodes=http://127.0.0.1:<AGILECONFIG_PORT>AgileConfig__Env=DEVAgileConfig__Tag=DEV
# ── 数据库初始化模式(重要)──# schema-only | platform-seed | full-seed# 开发日常发版推荐:仅建表/补字段,完全不跑种子(含数据字典)BITZORCAS_DEPLOY_DB_MODE=schema-only## 兼容旧开关(未设 DEPLOY_DB_MODE 时生效):# BITZORCAS_INIT_NO_SEED=1 # 等同 schema-only# BITZORCAS_SKIP_DEMO_SEED=1 # 默认推导为 platform-seed(仍跑字典等平台种子)## 首次需要平台字典但不想要演示账号:# BITZORCAS_DEPLOY_DB_MODE=platform-seed## 需要演示账号 admin 登录:# BITZORCAS_DEPLOY_DB_MODE=full-seed# USER__ADMIN__PASSWORD=ChangeMe_Admin_1# USER__OPERATOR__PASSWORD=ChangeMe_Operator_1# USER__SUPPORT__PASSWORD=ChangeMe_Support_1# USER__AUDITOR__PASSWORD=ChangeMe_Auditor_1# USER__DEVELOPER__PASSWORD=ChangeMe_Developer_1# USER__HOST_ADMIN__PASSWORD=ChangeMe_HostAdmin_1# (以及 HOST_PRODUCT / HOST_DEVELOPER / HOST_MARKETING / HOST_OPS)## Schema 强制全量 CodeFirst(默认按目录只补缺表/缺列):# BITZORCAS_SCHEMA_FULL_INIT=1放 preview.env | 放 AgileConfig |
|---|---|
| 连接串、密码、JWT、PII、MinIO 密钥、AgileConfig Secret、Gateway 路由 | 非敏感热配置(限流、审计保留、Clock:Kind 等) |
deployment-id(只生成一次):
# deployment-id 只在首次部署生成,常规发布不得轮换。sudo mkdir -p /www/apps/preview/.bitzorcas/licenseif [[ ! -s /www/apps/preview/.bitzorcas/license/deployment-id ]]; then openssl rand -hex 16 | sudo tee /www/apps/preview/.bitzorcas/license/deployment-id >/dev/nullfisudo chmod 640 /www/apps/preview/.bitzorcas/license/deployment-id4. 开发机打包与上传
4.1 首次:全量
# 前后端产物共用同一个版本号,便于回滚时成对定位。VERSION="$(date +%Y%m%d-%H%M)"./scripts/deploy/pack.sh preview "$VERSION" --full./scripts/deploy/pack-frontend.sh preview "$VERSION"
BACKEND_PACKAGE="$(find ../publish -type f -name "bitzorcas-preview-${VERSION}.zip" -print -quit)"FRONTEND_PACKAGE="$(find ../publish -type f -name "bitzorcas-frontend-preview-${VERSION}.tar.gz" -print -quit)"scp "$BACKEND_PACKAGE" "$FRONTEND_PACKAGE" deploy@server:/www/releases/Windows PowerShell(脚本 UTF-8;控制台已强制 UTF-8):
.\scripts\deploy\pack.ps1 -Env preview -Version $Version.\scripts\deploy\pack-frontend.ps1 -Environment preview -Version $VersionmacOS 上 pack-frontend.sh 会去掉 Apple xattr,Linux 解压不应再刷
LIBARCHIVE.xattr.com.apple.provenance。不要把根目录 deploy/ 或 ci/ 并进 scripts/。
4.2 后续:增量(必须有服务器基线)
增量只信任从服务器下载的 manifest,不信任本机已打过几次包。
# 先拉取线上清单,再让 pack.sh 计算真正的增量差异。# 在开发机 publish 目录(与 pack.sh 输出同级,一般是 Codeup/publish/<分支>/)BRANCH="$(git -C . branch --show-current | tr '/' '_')"PUBLISH_DIR="../publish/${BRANCH}"
scp deploy@server:/www/apps/preview/manifest.txt \ "${PUBLISH_DIR}/manifest-server-preview-$(date +%m%d%H%M).txt"
VERSION="$(date +%Y%m%d-%H%M)"./scripts/deploy/pack.sh preview "$VERSION" # 不要加 --full成功日志应出现:
[INFO] 使用服务器基线: manifest-server-preview-20260923.txt[INFO] 增量结果: 变化 14, 未变 102, 删除 0若出现 [WARN] 无基线,执行全量打包,说明没有匹配的 manifest-server-preview-*.txt,或文件名/环境名写错。
5. 服务器部署命令
5.1 默认 platform-seed(跑字典等平台种子,跳过演示用户)
未设置 BITZORCAS_DEPLOY_DB_MODE 且未设 INIT_NO_SEED=1 时:
sudo /www/scripts/deploy.sh /www/releases/bitzorcas-preview-<VERSION>.zip preview脚本会:停服 → 备份 → 解压 → load_env_file → 推导 platform-seed(等价默认 SKIP_DEMO_SEED=1)→ --init-schema(仍跑平台种子)→ --init-quartz-schema → systemd → health。
注意:这不是「仅建表」;数据字典等种子仍会执行。成功后安装完整 manifest.txt 到 /www/apps/preview/manifest.txt。
5.2 schema-only(完全不跑种子,开发迭代推荐)
表已建好、日常只发应用时:
sudo BITZORCAS_DEPLOY_DB_MODE=schema-only \ /www/scripts/deploy.sh /www/releases/bitzorcas-preview-<VERSION>.zip preview兼容旧写法:BITZORCAS_INIT_NO_SEED=1。也可在 preview.env 写死 BITZORCAS_DEPLOY_DB_MODE=schema-only。
效果:--init-schema --no-seed(建表/补字段 + 审计分表 + CAP;零种子)。Schema 默认按目录只补缺失对象。
5.3 full-seed(需要演示账号 admin)
- 在
preview.env设BITZORCAS_DEPLOY_DB_MODE=full-seed(或SKIP_DEMO_SEED=0且勿INIT_NO_SEED=1),并配置全部USER__*__PASSWORD。 - 重新
deploy.sh。 - 已有用户密码不会被 seed 覆盖,只有新建账号使用初始密码。
5.4 前端
# 显式覆盖站点根目录,确保前端产物进入 preview 虚拟主机。sudo BITZORCAS_SITE_ROOT=/www/sites/bitzorcas-preview \ /www/scripts/deploy-frontend.sh \ /www/releases/bitzorcas-frontend-preview-<VERSION>.tar.gz \ preview6. OpenResty
6.1 宿主机站点目录要对容器可见
deploy-frontend 写宿主机 /www/sites/bitzorcas-preview。OpenResty 容器若看不到该路径,会出现 SPA rewrite 死循环。
推荐挂载后:
root /srv/sites/bitzorcas-preview/current;并保证容器内能 ls 到 index.html。
6.2 反代头(登录 Cookie Origin 依赖)
/api/、/hubs/、/openapi/ 与 /scalar/ 都要转到 Gateway。所有 location 至少使用同一组公开地址转发头:
proxy_set_header Host $http_host;proxy_set_header X-Forwarded-Host $http_host;proxy_set_header X-Forwarded-Proto $scheme;proxy_set_header X-Forwarded-Port $server_port;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;$http_host 会保留 8088 一类非默认端口,$host 不会。除 /openapi/、/scalar/ 与 /api/docs/oauth/token 外,还要把 /api/docs/login、/api/docs/logout 以及兼容别名 /docs/login、/docs/logout 转发到 API。OpenApi__RequireAuthentication=true 提供应用内文档会话;1Panel 访问控制、VPN 或 IP 白名单仍作为外层防线。设置了 BITZORCAS_BIND_ADDRESS 却关闭该访问门时,产品 Host 会拒绝启动。
6.3 仅 IP 模式
- 公网 80 常被光猫占用 →
listen 8088;,路由映射8088→服务器:8088。 - 不要
listen 8081(JobHost)。 Frontend__BaseUrl/Cors__AllowedOrigins__0/ MinIO CORS 必须带端口。
6.4 include 链
官方镜像的 nginx.conf 在 http 里已经 include conf.d。单色发布不需要单独的 upstream {} 文件,也不要手改 OpenResty 应用目录去加 upstreams/。
http { # conf.d 挂的是宿主机 ${WEBSITE_DIR}/conf.d。 include /usr/local/openresty/nginx/conf/conf.d/*.conf;}站点主文件就是 ${WEBSITE_DIR}/conf.d/<站点别名>.conf。1Panel 生成的 proxy / rewrite / ssl / waf 等 include 必须留在 server {} 内;不要删面板已有行。下面是对照用的完整写法:
# 本文件被 nginx.conf 在 http {} 里加载。单色发布不要在顶部 include upstream/。
server { listen 80; listen 443 ssl http2; server_name app.example.com;
ssl_certificate /www/sites/app.example.com/ssl/fullchain.pem; ssl_certificate_key /www/sites/app.example.com/ssl/privkey.pem;
root /www/sites/bitzorcas-preview/current; index index.html;
# 以下都在 server {} 内,只能放 location / 头 / 证书补充。 include /www/sites/app.example.com/proxy/*.conf; include /www/sites/app.example.com/rewrite/*.conf; include /www/sites/app.example.com/ssl/*.conf; include /www/sites/app.example.com/redirect/*.conf; include /www/sites/app.example.com/auth/*.conf; include /www/sites/app.example.com/error_page/*.conf; include /www/sites/app.example.com/waf/*.conf;}用面板「反向代理」时,每个路径会生成 sites/<别名>/proxy/*.conf。那些文件里应是 proxy_pass http://127.0.0.1:8082;(单色)或蓝绿页的 named upstream。不用面板反代时,把下一节完整 server {} 写进站点主文件,或把再下一节 location 贴进「自定义配置」。
6.5 完整 server(站点主文件)
下面两份可直接覆盖/对照站点主文件。把 root、server_name、证书路径改成容器内真实值。不要 listen 8081。
域名 + HTTPS:
# 宿主机: ${WEBSITE_DIR}/conf.d/app.example.com.conf# 单色 deploy.sh:proxy_pass 写死蓝区 Gateway。
server { listen 80; listen 443 ssl http2; server_name app.example.com;
ssl_certificate /www/sites/app.example.com/ssl/fullchain.pem; ssl_certificate_key /www/sites/app.example.com/ssl/privkey.pem;
root /www/sites/bitzorcas-preview/current; index index.html;
access_log /www/sites/app.example.com/log/access.log; error_log /www/sites/app.example.com/log/error.log;
if ($scheme = http) { return 301 https://$host$request_uri; }
location ^~ /.well-known/acme-challenge { allow all; root /usr/share/nginx/html; }
location /api/ { proxy_pass http://127.0.0.1:8082; proxy_http_version 1.1; proxy_set_header Host $http_host; 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 X-Forwarded-Host $http_host; proxy_set_header X-Forwarded-Port $server_port; }
location /hubs/ { proxy_pass http://127.0.0.1:8082; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $http_host; 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 X-Forwarded-Host $http_host; proxy_set_header X-Forwarded-Port $server_port; proxy_read_timeout 3600s; proxy_buffering off; }
location /health/ { proxy_pass http://127.0.0.1:8082; proxy_set_header Host $http_host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Host $http_host; proxy_set_header X-Forwarded-Port $server_port; }
location /openapi/ { proxy_pass http://127.0.0.1:8082; proxy_set_header Host $http_host; proxy_set_header X-Forwarded-Host $http_host; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Port $server_port; }
location /scalar/ { proxy_pass http://127.0.0.1:8082; proxy_set_header Host $http_host; proxy_set_header X-Forwarded-Host $http_host; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Port $server_port; }
location /docs/ { proxy_pass http://127.0.0.1:8082; proxy_set_header Host $http_host; proxy_set_header X-Forwarded-Host $http_host; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Port $server_port; }
location / { try_files $uri $uri/ /index.html =404; }}仅 IP(家宽常见入口 8088):
# 宿主机: ${WEBSITE_DIR}/conf.d/<公网IP>.conf# 公网 80 常被光猫占用时 listen 8088。不要 listen 8081。# CORS / Frontend__BaseUrl 必须带端口,例如 http://10.10.10.10:8088。
server { listen 8088; server_name <公网IP>;
root /www/sites/bitzorcas-preview/current; index index.html;
access_log /www/sites/bitzorcas-preview/log/access.log; error_log /www/sites/bitzorcas-preview/log/error.log;
location /api/ { proxy_pass http://127.0.0.1:8082; proxy_http_version 1.1; proxy_set_header Host $http_host; 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 X-Forwarded-Host $http_host; proxy_set_header X-Forwarded-Port $server_port; }
location /hubs/ { proxy_pass http://127.0.0.1:8082; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $http_host; 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 X-Forwarded-Host $http_host; proxy_set_header X-Forwarded-Port $server_port; proxy_read_timeout 3600s; proxy_buffering off; }
location /health/ { proxy_pass http://127.0.0.1:8082; proxy_set_header Host $http_host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Host $http_host; proxy_set_header X-Forwarded-Port $server_port; }
location /openapi/ { proxy_pass http://127.0.0.1:8082; proxy_set_header Host $http_host; proxy_set_header X-Forwarded-Host $http_host; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Port $server_port; }
location /scalar/ { proxy_pass http://127.0.0.1:8082; proxy_set_header Host $http_host; proxy_set_header X-Forwarded-Host $http_host; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Port $server_port; }
location /docs/ { proxy_pass http://127.0.0.1:8082; proxy_set_header Host $http_host; proxy_set_header X-Forwarded-Host $http_host; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Port $server_port; }
location / { try_files $uri $uri/ /index.html =404; }}6.6 server 级 location(自定义配置)
只改 1Panel「自定义配置」、不整份覆盖站点主文件时,贴下面这一段。对应仓库 deploy/1panel/openresty-app.locations.conf。把 root 改成容器内能看到的前端 current。
# 粘贴到 1Panel 的 app.example.com 网站 server 块中(单色 deploy.sh 原地发布)。# 蓝绿发布请改用 openresty-app.locations-blue-green.conf,不要写死 8082。# 把 root 改成 deploy-frontend.sh 使用的 BITZORCAS_SITE_ROOT/current。root /www/sites/bitzorcas-preview/current;index index.html;
location /api/ { proxy_pass http://127.0.0.1:8082; proxy_http_version 1.1; proxy_set_header Host $http_host; 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 X-Forwarded-Host $http_host; proxy_set_header X-Forwarded-Port $server_port;}
location /hubs/ { proxy_pass http://127.0.0.1:8082; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $http_host; 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 X-Forwarded-Host $http_host; proxy_set_header X-Forwarded-Port $server_port; proxy_read_timeout 3600s; proxy_buffering off;}
location /health/ { proxy_pass http://127.0.0.1:8082; proxy_set_header Host $http_host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Host $http_host; proxy_set_header X-Forwarded-Port $server_port;}
location /openapi/ { proxy_pass http://127.0.0.1:8082; proxy_set_header Host $http_host; proxy_set_header X-Forwarded-Host $http_host; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Port $server_port;}
location /scalar/ { proxy_pass http://127.0.0.1:8082; proxy_set_header Host $http_host; proxy_set_header X-Forwarded-Host $http_host; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Port $server_port;}
location /docs/ { proxy_pass http://127.0.0.1:8082; proxy_set_header Host $http_host; proxy_set_header X-Forwarded-Host $http_host; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Port $server_port;}
location / { try_files $uri $uri/ /index.html =404;}7. 验收
# 先确认三个常驻进程,再检查内部与公网健康端点。systemctl is-active bitzorcas-jobhost-preview bitzorcas-api-preview bitzorcas-gateway-previewcurl -fsS http://127.0.0.1:8080/health/readycurl -fsS http://127.0.0.1:8080/health/licensecurl -fsS http://127.0.0.1:8082/health/readycurl -fsS <PUBLIC_BASE>/health/ready
# 匿名 JSON 应为 401,浏览器式 Scalar 请求应跳到文档登录页。curl -sS -o /dev/null -w '%{http_code}\n' <PUBLIC_BASE>/openapi/v1.jsoncurl -sS -o /dev/null -D - -H 'Accept: text/html' <PUBLIC_BASE>/scalar/v1随后用浏览器打开 <PUBLIC_BASE>/scalar/v1,确认 Server 保留地址栏端口。普通账号可在左侧 Authentication 选择 DocsLogin;需要 MFA、验证码、MFA 登记或强制改密时,先走正式登录页,再把 accessToken 粘贴到 Bearer。
若 <PUBLIC_BASE> 仍是 HTTP,只能在隔离网络使用一次性开发账号;真实账号启用 DocsLogin 前必须先配置 HTTPS。Host 内部的 RSA 密码适配不能替代 TLS。
8. 常见故障
| 现象 | 处理 |
|---|---|
每次 pack.sh 都是全量 | 缺少 manifest-server-preview-*.txt;从服务器拉 manifest.txt 并按 §4.2 命名 |
登录 403 Authentication.Cookie.OriginRejected | Cors__AllowedOrigins__0 / Frontend__BaseUrl 与地址栏不一致;OpenResty 未传 Host/X-Forwarded-Host;HTTP 时检查 cookie Secure |
登录 401 Identity.Login.InvalidCredentials | Demo 种子未跑或密码不对;见 §5.3 |
admin requires PASSWORD_HASH | 保持 platform-seed/SKIP_DEMO_SEED=1,或 full-seed 并配密码;日常发版用 schema-only |
| 误以为默认「仅建表」仍很慢 | 默认是 platform-seed,字典等仍会跑;完全跳过请设 BITZORCAS_DEPLOY_DB_MODE=schema-only |
Gateway Ignoring invalid environment assignment: api-cluster | 集群 id 改为 api/signalr/files;新版本 deploy 会写 appsettings.Deploy.json |
Gateway 启动失败 CookieStickySession / RequestHeader | 更新含修复后的 Gateway appsettings.json 的发布包 |
/openapi 或 /scalar 返回 404 | 确认 OpenApi__Enabled=true,OpenResty 与 Gateway 都转发对应路径 |
| API 启动报“必须设置 RequireAuthentication” | 保留 BITZORCAS_BIND_ADDRESS,增加 OpenApi__RequireAuthentication=true |
| Scalar 跳到登录页后 404 或循环 | 转发 /api/docs/login 与兼容 /docs/login,核对公开协议、可信代理和 bitzorcas.docs Cookie |
| Scalar 请求跑到 80/443 或错误主机 | 把代理头改为 $http_host,补 X-Forwarded-Port $server_port,核对 OpenApi__Servers__0__Url |
| DocsLogin 提示 MFA、验证码或强制改密 | 走正式登录页,再把 accessToken 粘贴到 Bearer;不要关闭登录安全策略 |
| 空库首次 seed 很慢 | 正常;之后用 BITZORCAS_DEPLOY_DB_MODE=schema-only(或 INIT_NO_SEED=1)加速日常发版 |
| 误以为默认「仅建表」仍很慢 | 默认是 platform-seed,字典等仍会跑;完全跳过请设 schema-only |
日志:
journalctl -u 'bitzorcas-*-preview' -f更新与回滚
- 仅前端:
pack-frontend+deploy-frontend。 - 后端原地:
pack(有服务器基线则增量)+deploy.sh。 - 后端蓝绿:先按 1Panel 蓝绿发布 接线 OpenResty,再
deploy-blue-green.sh;回切deploy-rollback.sh preview。 - 后端回滚(原地):
/www/backups/preview/;schema 变更通常前向兼容,发版前备份库。
另见 OpenAPI 与 Scalar 文档面、Aspire 本地编排、1Panel OpenResty 单机蓝绿、部署方式总览、生产配置。