首页/新闻资讯/正文详情

ShipDesk前端Nginx独立发布教程

发布时间:2026/9/23 11:48:51 来源:云帆数科 栏目:资讯中心
ShipDesk前端Nginx独立发布教程
我是如何让 ShipDesk 一键发布前端的从手工上传到 Nginx 自动回滚以前发布前端通常是这样一套流程npm run build 打包 dist 登录服务器 备份旧文件 上传新文件 nginx -t 重载 Nginx 祈祷页面能打开偶尔做一次还可以。如果前端每天都在更新或者项目交给其他人维护问题就会越来越明显上传容易漏文件改配置容易出错发布失败后还要手动恢复旧版本。这篇文章记录我把前端发布集成到 ShipDesk 的过程。最终效果是后端继续按照原来的方式发布 Java JAR前端则单独构建、上传和切换互相不影响。最后我们得到了什么在 ShipDesk 中选择前端项目点击发布后它会自动完成本地构建前端 ↓ 检查 dist 是否完整 ↓ 打包并上传 ↓ 校验文件是否传完整 ↓ 检查 Nginx 配置 ↓ 切换到新版本 ↓ 重载 Nginx ↓ 检查 HTTPS 是否正常如果中途出错ShipDesk 会尽量恢复到上一个可用版本。整个过程中不会停止后端 Java 服务。为什么前端和后端要分开发布前端和后端虽然一起提供一个网站但发布方式完全不同。后端发布的是正在运行的 Java 进程。发布新 JAR 时通常需要停止旧进程、替换文件、启动新进程再检查服务是否正常。前端发布的是一组静态文件。Vue、React 或其他 Vite 项目执行构建后最终就是index.html、JavaScript、CSS 和图片等文件Nginx 直接读取即可。如果把两者绑在一次发布中前端改一行文字也可能导致后端重启。更合理的方式是后端项目构建 JAR → 停止 Java → 发布 JAR → 启动 Java 前端项目构建 dist → 上传静态文件 → 切换 Nginx 目录这样前端发布不会打断后端服务后端发布也不会重复上传前端资源两边还可以分别回滚。先把服务器目录设计好假设前端部署在服务器的/opt/example-frontendNginx 在 Docker 容器中运行并且只把宿主机的html目录挂载进去宿主机/opt/example-frontend/html 容器内/usr/share/nginx/html最终目录应该这样设计/opt/example-frontend/ └── html/ ├── current - releases/release-002/html ├── previous - releases/release-001/html └── releases/ ├── release-001/html/index.html └── release-002/html/index.htmlNginx 永远只指向root /usr/share/nginx/html/current;发布新版本时不覆盖正在使用的文件只切换current。一个很容易踩到的 Docker 软链接问题最初很容易设计成/opt/example-frontend/ ├── html/ └── releases/ html/current - ../releases/release-001/html在宿主机上看这个链接是正常的。但进入 Docker 容器后容器只能看到挂载进来的html看不到旁边的releases。于是宿主机上链接正常容器里却找不到页面文件。正确做法是把版本目录放进html挂载范围内并使用容器能理解的相对链接current - releases/release-002/html不要使用这种宿主机绝对路径current - /opt/example-frontend/html/releases/release-002/html这是本次实现中最重要的架构约束之一。第一次接入时先保护线上文件如果服务器上已经有正在运行的前端第一次接入版本化发布时不能直接删除原来的html目录。先复制一份线上内容作为初始版本BASE/opt/example-frontendmkdir-p$BASE/html/releases/bootstrap/htmlcp-a$BASE/html/.$BASE/html/releases/bootstrap/html/if[-L$BASE/html/current];thenmv$BASE/html/current$BASE/html/current.legacyfiln-sreleases/bootstrap/html$BASE/html/current然后从容器内检查dockerexecfrontend-nginxtest-f/usr/share/nginx/html/current/index.html如果current不存在ShipDesk 应该停止并提示初始化而不是自行移动线上文件。Nginx 配置怎么写Nginx 主要做三件事提供前端静态文件、转发后端接口、处理 HTTPS。核心配置可以简化成下面这样server { listen 443 ssl; server_name example.com; root /usr/share/nginx/html/current; index index.html; ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; location /healthz { access_log off; default_type text/plain; return 200 ok\n; } location ~ ^/(api|ws)(/|$) { proxy_pass http://host.docker.internal:8091; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_buffering off; } location /assets/ { try_files $uri 404; expires 1y; } location / { try_files $uri $uri/ /index.html; } }证书和私钥继续由服务器上的 Certbot 管理。ShipDesk 只上传 Nginx 配置不上传证书也不把证书私钥放进项目仓库。ShipDesk 里新增一个前端项目ShipDesk 原本已经支持后端 JAR 发布所以这次没有另起一套工具而是在项目配置中增加了模板静态文件 · Nginx前端项目需要填写配置示例项目名称knowledge-base-frontend本地工作目录/path/to/knowledge-base-frontend构建命令npm run build产物目录dist远程根目录/opt/example-frontend本地 Nginx 配置/path/to/frontend/deploy/nginx.conf远程 Nginx 配置/opt/example-frontend/nginx.confNginx 校验命令docker exec frontend-nginx nginx -tNginx reload 命令docker exec frontend-nginx nginx -s reload健康检查命令curl -kfsS https://example.com/healthz后端项目仍然使用原来的 JAR 模板。切换项目时ShipDesk 根据template决定走哪条发布流程。静态模板不应该要求填写 Java 停止命令、启动命令或 JVM 参数否则前端发布时容易误调用后端脚本。我们先把发布流程想清楚实现之前先把一次发布拆成几个动作在本地构建前端检查dist/index.html和dist/assets打包并计算 SHA-256获取远程发布锁上传到新的版本目录在服务器上再次校验文件上传 Nginx 候选配置执行nginx -t切换currentreload Nginx检查 HTTPS失败时恢复previous。这里最重要的是顺序Nginx 配置校验要在切换页面之前健康检查要在 reload 之后。ShipDesk 的一次发布过程第一步本地构建发布开始后ShipDesk 进入前端工作目录执行npmrun build构建失败时后面的上传和 Nginx 操作都不会执行。第二步检查产物不能只判断dist目录存在还要检查dist/index.html 必须存在 dist/assets/ 必须存在且非空这样可以避免构建命令虽然退出码为 0但产物目录为空最后把一个空站点发布到线上。第三步打包并校验ShipDesk 把整个dist目录打成临时 tar 包并计算 SHA-256。远程收到文件后再次计算两边不一致就停止发布。版本包会解压到/opt/example-frontend/html/releases/releaseId/html每次发布都有独立目录旧版本不会被新版本覆盖。第四步先检查 Nginx 配置候选配置先上传到临时文件然后备份旧配置安装候选配置执行dockerexecfrontend-nginx nginx-t只有命令成功才允许切换current。如果配置语法错误ShipDesk 恢复旧配置并清理未激活的新版本。第五步原子切换 current切换时不直接复制文件而是使用临时链接rm-fhtml/previousmvhtml/current html/previousln-sreleases/releaseId/html html/current.nextmv-Thtml/current.next html/current这样 Nginx 要么看到旧版本要么看到新版本不会看到一半旧文件、一半新文件。第六步reload 和健康检查dockerexecfrontend-nginx nginx-sreloadcurl-kfsShttps://example.com/healthz只有这两步都成功发布才算完成。发布失败时怎么回滚如果失败发生在切换前例如上传失败、SHA-256 不一致或nginx -t失败线上current还没有变化。这时恢复旧配置、删除新版本目录并释放远程锁即可。如果失败发生在切换后例如 reload 失败、健康检查失败或者容器内无法读取新页面则需要把current切回previous恢复旧 Nginx 配置再次 reload再次执行健康检查把回滚结果写入日志。回滚不能只打印一句“回滚成功”程序应该根据每个恢复动作的真实结果设置状态。我遇到的第一个问题sshpass 退出码 1部署时曾经看到bash: warning: setlocale: LC_ALL: cannot change locale (C.UTF-8) /bin/sh: warning: setlocale: LC_ALL: cannot change locale (C.UTF-8) sshpass 退出码 1第一眼很容易认为是 locale 导致 SSH 失败但继续拆开检查后真正失败的是test-L/opt/example-frontend/html/current服务器还没有完成第一次版本目录初始化因此发布引擎主动停止了流程。排查这类错误时建议把命令单独执行test-L/opt/example-frontend/html/currentechosymlink_exit$?dockerexecfrontend-nginxtest-f/usr/share/nginx/html/current/index.htmlechofile_exit$?dockerexecfrontend-nginx nginx-techonginx_test_exit$?C.UTF-8是服务器 locale 配置警告通常不是 SSH 失败的真正原因。它可以后续通过安装和生成对应 locale 来消除但不能代替对实际退出码的排查。我遇到的第二个问题健康检查通过了页面却可能打不开如果/healthz是 Nginx 直接返回的固定文本即使静态目录软链接断了健康检查仍可能返回 200。所以发布验证最好同时检查dockerexecfrontend-nginx nginx-tdockerexecfrontend-nginxtest-f/usr/share/nginx/html/current/index.htmltest$(curl-kfsShttps://example.com/healthz)ok如果条件允许再请求一次首页和一个静态资源验证用户真正访问的内容。这次实现中保留的安全边界发布工具会执行远程命令所以安全边界不能省略密码通过 ElectronsafeStorage保存使用密码时通过SSHPASS环境变量传递不把密码拼接进命令字符串所有远程路径使用统一的 shell quotingSSL 私钥只存在服务器远程发布使用项目级锁失败时清理临时文件但不删除current或previous正在引用的版本。不要把真实服务器密码、私钥、Token 或证书内容写进博客和 Git 仓库。怎么验证这套流程可靠单元测试中使用 fake runner 捕获 SSH、SCP 和远程命令重点验证命令顺序nginx -t发生在 reload 之前配置校验失败时不能切换current健康检查失败时会尝试恢复previous静态发布不会调用 Java stop/start成功和失败都能释放远程锁密码或私钥不会出现在日志中。本地验证npmtestnpmrun build服务器验证dockerexecfrontend-nginxtest-f/usr/share/nginx/html/current/index.htmldockerexecfrontend-nginx nginx-tcurl-kfsShttps://example.com/healthz最后总结把前端发布集成到 ShipDesk真正重要的不是“增加一个上传文件的按钮”而是把发布过程变成一条有顺序、有校验、能回滚的流水线构建 → 检查产物 → 打包上传 → 校验完整性 → 检查 Nginx 配置 → 切换版本 → reload → 验证页面 → 必要时回滚实现时最值得记住的两个细节是前端和后端应该独立发布前端发布不要顺手重启 Java 服务Docker 场景下版本目录必须位于容器挂载范围内软链接必须使用容器可见的相对路径。做好这两点前端发布就能从一次容易出错的手工操作变成一次可重复、可观察、可恢复的工程流程。

相关推荐

搞定迷宫地图生成与寻路算法入门到精通
搞定迷宫地图生成与寻路算法入门到精通

搞定迷宫地图生成与寻路算法入门到精通 复制来的迷宫代码跑不通,报错满屏飞,调试半天找不到头?别慌,这是很多刚接触算法实战的开发者都会遇到的“拦路虎”。很多人以为迷宫生成就是随机挖墙,寻路就是瞎走,结果一上项目就发现边界溢出、死循环或者性能极… · 2026/9/23 11:48:45

Phoenix 前端开发规范实战:React 组件、Relay 数据流与可访问性的工程化指南
Phoenix 前端开发规范实战:React 组件、Relay 数据流与可访问性的工程化指南

可观测性AI 评测LLMOpsAI 应用人工智能 【免费下载链接】phoenix AI Observability & Evaluation 项目地址: https://gitcode.com/gh_mirrors/phoenix13/phoenix 点击查看 免费下载 Phoenix 是一款 AI 可观测性与评估平台,其前端位于 js/app 目录&a… · 2026/9/23 11:48:33

电机转速计算公式实操指南:告别报错,掌握最佳实践
电机转速计算公式实操指南:告别报错,掌握最佳实践

电机转速计算公式实操指南:告别报错,掌握最佳实践 刚接手产线自动化项目,调试电机时屏幕突然弹出一串红色 StackTrace,看着 IndexOutOfBoundsException 和 NullPointerException… · 2026/9/23 11:48:27

物联网卡多少钱?2026 年 1G/2G/6G/10G/20G/50G/100G/200G 全档位套餐价格
物联网卡多少钱?2026 年 1G/2G/6G/10G/20G/50G/100G/200G 全档位套餐价格

导读与核心结论 物联网卡没有全国统一定价。同样是 10GB 流量,不同渠道的报价能从 100 元到 225 元;同样标着「100GB」,有人卖 60 元一年,有人卖 110 元一个月 —— 差的不是渠道良心,是计费口径。 本文以纯问答&… · 2026/9/23 12:34:23

win10编译Cutelyst动态库集成Grantlee视图实战指南
win10编译Cutelyst动态库集成Grantlee视图实战指南

简介:Win10环境下的Cutelyst动态库编译成果,基于Qt5.15.2并集成Grantlee模板视图,为需要在Windows平台使用Cutelyst框架的Qt/C开发者提供开箱即用的库文件。压缩包共172个文件,含87个头文件、23个dll动态库、14个lib导入库、13个p… · 2026/9/23 12:34:23

3步搞定crescendo性能瓶颈:手写实现提速50%
3步搞定crescendo性能瓶颈:手写实现提速50%

3步搞定crescendo性能瓶颈:手写实现提速50% 版本升级后 API 全变了?别慌,这不是你的错。 老代码跑不动新环境,是性能优化最常见的坑。 今天不聊虚的,直接上干货,用 手写实现 拆解 crescendo… · 2026/9/23 12:34:23

SSM兼职论坛部署调试全指南:从404到事务回滚实战
SSM兼职论坛部署调试全指南:从404到事务回滚实战

简介:本资源是一套面向Java初学者与毕业设计学生的SSM框架实战项目,完整实现了一个功能完备的兼职论坛系统,涵盖用户管理、帖子发布、评论互动、后台管理等典型Web业务场景。资源包含467个文件,总大小19.8MB,以69个Jav… · 2026/9/23 12:34:15

服务器被攻击怎么办:从入门到精通的性能自救指南
服务器被攻击怎么办:从入门到精通的性能自救指南

服务器被攻击怎么办:从入门到精通的性能自救指南 凌晨三点,告警群炸了。CPU 飙到 100%,接口响应慢得像蜗牛,一查监控,发现是典型的 DDoS 攻击或者慢速攻击。很多后端兄弟第一反应是慌,其实这种场景下,版本升级后 API… · 2026/9/23 12:34:09

慢收敛级数怎么算?巴塞尔问题的数值逼近策略与实践
慢收敛级数怎么算?巴塞尔问题的数值逼近策略与实践

1. 巴塞尔问题的数值逼近:从求和到计算思维第一次认真琢磨巴塞尔问题,是在处理一个信号处理项目的时候。当时需要估算一组级数的截断误差,翻到《数学分析》里那个经典结论——全体正整数平方倒数和收敛于π/6,心里想的却是另一回事… · 2026/9/23 12:34:09

3招搞定手机怎么下载微信面试难题实战项目解析
3招搞定手机怎么下载微信面试难题实战项目解析

3招搞定手机怎么下载微信面试难题实战项目解析 面试被问“手机怎么下载微信”背后的原理,90%的人答不上来。别笑,这看似弱智的问题,实则是考察你对移动应用分发机制、安全校验及网络协议理解的试金石。我带过不少校招新人,他们背了八股文,却连一个A… · 2026/9/23 0:00:03

你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型
你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型

你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 面试被问“高并发下如何保证消息不丢失”,你张口就是“用Redis”,结果面试官追问“如果Redis宕机了怎么办”,你瞬间卡壳。这种场景太常见了,很多新手在背八股文时,只记住了技术名词… · 2026/9/23 0:00:29

Win7无线热点配置工具源码解析:解决API失效的3个实战技巧
Win7无线热点配置工具源码解析:解决API失效的3个实战技巧

Win7无线热点配置工具源码解析:解决API失效的3个实战技巧 Win7无线热点配置工具在Win10/11上跑不动?不是你的问题,是版本升级后 API 全变了。很多老项目里的 netsh wlan… · 2026/9/23 0:00:36

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码