feat: Modify the OpenClaw upgrade logic. (#12175)

This commit is contained in:
CityFun
2026-03-16 04:11:50 +00:00
committed by GitHub
parent 8499c09571
commit 17a486b2c4
14 changed files with 226 additions and 4 deletions
+103 -2
View File
@@ -6,7 +6,6 @@ import (
"encoding/hex"
"encoding/json"
"fmt"
"github.com/1Panel-dev/1Panel/agent/xpack/xglobal"
"net/http"
"net/url"
"path"
@@ -28,6 +27,7 @@ import (
"github.com/1Panel-dev/1Panel/agent/utils/common"
"github.com/1Panel-dev/1Panel/agent/utils/files"
"github.com/1Panel-dev/1Panel/agent/utils/req_helper"
"github.com/1Panel-dev/1Panel/agent/xpack/xglobal"
)
type AgentService struct{}
@@ -80,6 +80,7 @@ const (
openclawCaddyPort = 8443
openclawCaddyDataPerm = 0777
openclawCaddyLoopbackAddress = "https://127.0.0.1:8443"
openclawHTTPSVersion = "2026.3.13"
openclawTrustedProxyLoopback = "127.0.0.1/32"
)
@@ -1576,7 +1577,11 @@ func buildAgentItem(agent *model.Agent, appInstall *model.AppInstall, envMap map
item.Container = appInstall.ContainerName
item.AppVersion = appInstall.Version
if agentType == constant.AppOpenclaw {
item.WebUIPort = appInstall.HttpsPort
if isOpenclawHTTPSVersion(appInstall.Version) {
item.WebUIPort = appInstall.HttpsPort
} else {
item.WebUIPort = appInstall.HttpPort
}
} else {
item.WebUIPort = appInstall.HttpPort
}
@@ -1592,6 +1597,102 @@ func buildAgentItem(agent *model.Agent, appInstall *model.AppInstall, envMap map
return item
}
func isOpenclawHTTPSVersion(version string) bool {
target := strings.TrimSpace(strings.ToLower(version))
if target == "" || target == "latest" {
return true
}
if !strings.ContainsAny(target, "0123456789") {
return true
}
return common.CompareAppVersion(target, openclawHTTPSVersion)
}
func shouldMigrateOpenclawHTTPSUpgrade(install *model.AppInstall, fromVersion, toVersion string) bool {
if install == nil || install.App.Key != constant.AppOpenclaw {
return false
}
return !isOpenclawHTTPSVersion(fromVersion) && isOpenclawHTTPSVersion(toVersion)
}
func migrateOpenclawHTTPSUpgrade(install *model.AppInstall, fromVersion, toVersion string) error {
systemIP, _ := settingRepo.GetValueByKey("SystemIP")
return migrateOpenclawHTTPSUpgradeWithSystemIP(install, fromVersion, toVersion, systemIP)
}
func migrateOpenclawHTTPSUpgradeWithSystemIP(install *model.AppInstall, fromVersion, toVersion, systemIP string) error {
if !shouldMigrateOpenclawHTTPSUpgrade(install, fromVersion, toVersion) {
return nil
}
migrateOpenclawInstallPorts(install)
if err := migrateOpenclawInstallEnv(install); err != nil {
return err
}
systemIP = strings.TrimSpace(systemIP)
if systemIP == "" || install.HttpsPort <= 0 {
return nil
}
allowedOrigin, err := buildOpenclawAllowedOrigin(systemIP, install.HttpsPort)
if err != nil {
return nil
}
configPath := path.Join(install.GetPath(), "data", "conf", "openclaw.json")
conf, err := readOpenclawConfig(configPath)
if err != nil {
return err
}
setSecurityConfig(conf, dto.AgentSecurityConfig{AllowedOrigins: []string{allowedOrigin}})
if err := writeOpenclawConfigRaw(configPath, conf); err != nil {
return err
}
return writeOpenclawCaddyfile(configPath, []string{allowedOrigin})
}
func migrateOpenclawInstallPorts(install *model.AppInstall) {
if install == nil {
return
}
if install.HttpsPort == 0 && install.HttpPort > 0 {
install.HttpsPort = install.HttpPort
}
if install.HttpPort > 0 {
install.HttpPort = 0
}
}
func migrateOpenclawInstallEnv(install *model.AppInstall) error {
if install == nil {
return nil
}
envMap := make(map[string]interface{})
if strings.TrimSpace(install.Env) != "" {
if err := json.Unmarshal([]byte(install.Env), &envMap); err != nil {
return err
}
}
if install.HttpsPort > 0 {
envMap["PANEL_APP_PORT_HTTPS"] = install.HttpsPort
}
delete(envMap, "PANEL_APP_PORT_HTTP")
payload, err := json.Marshal(envMap)
if err != nil {
return err
}
install.Env = string(payload)
return nil
}
func buildOpenclawAllowedOrigin(host string, port int) (string, error) {
host = strings.TrimSpace(host)
if host == "" || port <= 0 {
return "", fmt.Errorf("invalid openclaw allowed origin")
}
if strings.Contains(host, ":") && !strings.HasPrefix(host, "[") && strings.Count(host, ":") > 1 {
host = "[" + host + "]"
}
return normalizeAllowedOrigin(fmt.Sprintf("https://%s:%d", host, port))
}
func writeOpenclawCaddyfile(configPath string, allowedOrigins []string) error {
content, err := buildOpenclawCaddyfile(allowedOrigins)
if err != nil {
+4
View File
@@ -675,6 +675,7 @@ func upgradeInstall(req request.AppInstallUpgrade) error {
if err != nil {
return err
}
oldVersion := install.Version
detail, err := appDetailRepo.GetFirst(repo.WithByID(req.DetailID))
if err != nil {
return err
@@ -801,6 +802,9 @@ func upgradeInstall(req request.AppInstallUpgrade) error {
}
var newCompose string
if err = migrateOpenclawHTTPSUpgrade(&install, oldVersion, detail.Version); err != nil {
return err
}
if req.DockerCompose == "" {
newCompose, err = getUpgradeCompose(install, detail)
if err != nil {
+6
View File
@@ -2419,6 +2419,12 @@ const message = {
reload: 'Reload',
upgradeWarn:
'Upgrading the application will replace the docker-compose.yml file. If there are any changes, you can click to view the file comparison',
openclawHttpsUpgradeNoticeTitle:
'Note: The following instructions only apply to users upgrading OpenClaw from versions earlier than 2026.3.13:',
openclawHttpsUpgradeNoticeItem1:
'After the deployed agent is upgraded, go to Configuration -> Settings -> Security and manually add the access address.',
openclawHttpsUpgradeNoticeItem2:
'The new version now requires HTTPS to access the agent. If you previously used a reverse proxy website, change the proxy target to https://IP:Port.',
newVersion: 'New version',
oldVersion: 'Current version',
composeDiff: 'File comparison',
+6
View File
@@ -2464,6 +2464,12 @@ const message = {
showLocal: 'Mostrar apps locales',
reload: 'Recargar',
upgradeWarn: 'Actualizar reemplazará docker-compose.yml. Si hay cambios, puede ver la comparación.',
openclawHttpsUpgradeNoticeTitle:
'Nota: Las siguientes instrucciones solo se aplican a los usuarios que actualizan OpenClaw desde versiones anteriores a 2026.3.13:',
openclawHttpsUpgradeNoticeItem1:
'Después de actualizar el agente desplegado, vaya a Configuración -> Ajustes -> Seguridad y agregue manualmente la dirección de acceso.',
openclawHttpsUpgradeNoticeItem2:
'La nueva versión exige HTTPS para acceder al agente. Si antes usaba un sitio con proxy inverso, cambie el destino del proxy a https://IP:Port.',
newVersion: 'Nueva versión',
oldVersion: 'Versión actual',
composeDiff: 'Comparación de archivos',
+6
View File
@@ -2439,6 +2439,12 @@ const message = {
reload: 'リロード',
upgradeWarn:
'アプリケーションのアップグレードは、docker-compose.ymlファイルを置き換えます。変更がある場合は、クリックしてファイルの比較を表示できます',
openclawHttpsUpgradeNoticeTitle:
'注意: 以下の説明は、2026.3.13 より前のバージョンから OpenClaw をアップグレードするユーザーにのみ適用されます:',
openclawHttpsUpgradeNoticeItem1:
'デプロイ済みエージェントのアップグレード完了後、設定 -> 設定 -> セキュリティ に入り、アクセスアドレスを手動で追加してください。',
openclawHttpsUpgradeNoticeItem2:
'新バージョンではエージェントへのアクセスに HTTPS が必須です。以前リバースプロキシサイト経由でアクセスしていた場合は、プロキシ先を https://IP:Port に変更してください。',
newVersion: '新しいバージョン',
oldVersion: '現在のバージョン',
composeDiff: 'ファイルの比較',
+6
View File
@@ -2382,6 +2382,12 @@ const message = {
reload: '새로고침',
upgradeWarn:
'애플리케이션 업그레이드는 docker-compose.yml 파일을 교체합니다. 변경 사항이 있으면 파일 비교를 클릭하여 확인할 수 있습니다.',
openclawHttpsUpgradeNoticeTitle:
'주의: 다음 안내는 2026.3.13 이전 버전에서 OpenClaw 를 업그레이드하는 사용자에게만 적용됩니다:',
openclawHttpsUpgradeNoticeItem1:
'배포된 에이전트 업그레이드가 완료되면 구성 -> 설정 -> 보안 페이지로 이동해 접근 주소를 수동으로 추가해야 합니다.',
openclawHttpsUpgradeNoticeItem2:
'새 버전은 에이전트 접근에 HTTPS 를 강제합니다. 이전에 리버스 프록시 사이트로 접근했다면 프록시 대상 주소를 https://IP:Port 로 변경하세요.',
newVersion: '새 버전',
oldVersion: '현재 버전',
composeDiff: '파일 비교',
+6
View File
@@ -2469,6 +2469,12 @@ const message = {
showLocal: 'Papar aplikasi tempatan',
reload: 'Muat Semula',
upgradeWarn: 'Meningkatkan aplikasi akan menggantikan fail docker-compose.yml.',
openclawHttpsUpgradeNoticeTitle:
'Nota: Arahan berikut hanya terpakai kepada pengguna yang menaik taraf OpenClaw daripada versi lebih awal daripada 2026.3.13:',
openclawHttpsUpgradeNoticeItem1:
'Selepas ejen yang telah dipasang selesai dinaik taraf, pergi ke Konfigurasi -> Tetapan -> Keselamatan dan tambah alamat akses secara manual.',
openclawHttpsUpgradeNoticeItem2:
'Versi baharu kini mewajibkan HTTPS untuk mengakses ejen. Jika anda sebelum ini menggunakan laman reverse proxy, tukar alamat sasaran proksi kepada https://IP:Port.',
newVersion: 'Versi baru',
oldVersion: 'Versi semasa',
composeDiff: 'Perbandingan fail',
+6
View File
@@ -2600,6 +2600,12 @@ const message = {
reload: 'Recarregar',
upgradeWarn:
'Atualizar o aplicativo substituirá o arquivo docker-compose.yml. Se houver alterações, você pode clicar para visualizar a comparação do arquivo',
openclawHttpsUpgradeNoticeTitle:
'Nota: As instruções a seguir se aplicam apenas a usuários que estão atualizando o OpenClaw de versões anteriores à 2026.3.13:',
openclawHttpsUpgradeNoticeItem1:
'Depois que o agente implantado for atualizado, vá para Configuração -> Ajustes -> Segurança e adicione manualmente o endereço de acesso.',
openclawHttpsUpgradeNoticeItem2:
'A nova versão agora exige HTTPS para acessar o agente. Se você usava um site com proxy reverso, altere o destino do proxy para https://IP:Port.',
newVersion: 'Nova versão',
oldVersion: 'Versão atual',
composeDiff: 'Comparação de arquivo',
+6
View File
@@ -2464,6 +2464,12 @@ const message = {
reload: 'Перезагрузить',
upgradeWarn:
'Обновление приложения заменит файл docker-compose.yml. Если есть изменения, вы можете нажать для просмотра сравнения файлов',
openclawHttpsUpgradeNoticeTitle:
'Примечание: Следующие инструкции применяются только к пользователям, обновляющим OpenClaw с версий ниже 2026.3.13:',
openclawHttpsUpgradeNoticeItem1:
'После завершения обновления развернутого агента перейдите в Конфигурация -> Настройки -> Безопасность и вручную добавьте адрес доступа.',
openclawHttpsUpgradeNoticeItem2:
'Новая версия теперь требует HTTPS для доступа к агенту. Если раньше использовался сайт с обратным прокси, измените адрес назначения прокси на https://IP:Port.',
newVersion: 'Новая версия',
oldVersion: 'Текущая версия',
composeDiff: 'Сравнение файлов',
+6
View File
@@ -2464,6 +2464,12 @@ const message = {
reload: 'Yeniden yükle',
upgradeWarn:
'Uygulamanın yükseltilmesi docker-compose.yml dosyasını değiştirecektir. Herhangi bir değişiklik varsa, dosya karşılaştırmasını görüntülemek için tıklayabilirsiniz',
openclawHttpsUpgradeNoticeTitle:
"Not: Aşağıdaki talimatlar yalnızca OpenClaw'ı 2026.3.13 öncesi sürümlerden yükselten kullanıcılar için geçerlidir:",
openclawHttpsUpgradeNoticeItem1:
'Dağıtılmış ajan yükseltmesi tamamlandıktan sonra Yapılandırma -> Ayarlar -> Güvenlik sayfasına gidip erişim adresini manuel olarak ekleyin.',
openclawHttpsUpgradeNoticeItem2:
'Yeni sürüm artık ajana erişim için HTTPS zorunlu kılıyor. Daha önce ters proxy sitesi kullanıyorsanız proxy hedef adresini https://IP:Port olarak değiştirin.',
newVersion: 'Yeni sürüm',
oldVersion: 'Mevcut sürüm',
composeDiff: 'Dosya karşılaştırması',
+4
View File
@@ -2246,6 +2246,10 @@ const message = {
showLocal: '顯示本機應用程式',
reload: '重載',
upgradeWarn: '升級應用程式會取代 docker-compose.yml 檔案,如有更改,可以點選檢視檔案對比',
openclawHttpsUpgradeNoticeTitle: '注意:以下說明僅適用於 OpenClaw 從 2026.3.13 之前版本升級的使用者:',
openclawHttpsUpgradeNoticeItem1: '已部署的智慧體升級完成後,需要進入 配置 → 設定 → 安全 頁面手動新增存取地址。',
openclawHttpsUpgradeNoticeItem2:
'新版本已強制使用 HTTPS 存取智慧體。如果之前透過反向代理網站存取,請將代理目標地址修改為 https://IP:Port。',
newVersion: '新版本',
oldVersion: '當前版本',
composeDiff: '檔案對比',
+4
View File
@@ -2250,6 +2250,10 @@ const message = {
showLocal: '本地应用',
reload: '重载',
upgradeWarn: '升级应用会替换 docker-compose.yml 文件,如有更改,可以点击查看文件对比',
openclawHttpsUpgradeNoticeTitle: '注意:以下说明仅适用于 OpenClaw 从 2026.3.13 之前版本升级的用户:',
openclawHttpsUpgradeNoticeItem1: '已部署的智能体升级完成后,需要进入 配置 → 设置 → 安全 页面手动添加访问地址。',
openclawHttpsUpgradeNoticeItem2:
'新版本已强制使用 HTTPS 访问智能体。如果之前通过反向代理网站访问,请将代理目标地址修改为 https://IP:Port。',
newVersion: '新版本',
oldVersion: '当前版本',
composeDiff: '文件对比',
+1 -1
View File
@@ -327,7 +327,7 @@ const isOpenClawHttpsVersion = (version: string) => {
if (!/\d/.test(target)) {
return true;
}
return compareVersion(target, '2026.3.12');
return compareVersion(target, '2026.3.13');
};
const jumpWebUI = (row: AI.AgentItem) => {
@@ -42,6 +42,19 @@
></el-option>
</el-select>
</el-form-item>
<el-alert
v-if="showOpenclawHttpsUpgradeNotice"
type="warning"
:closable="false"
show-icon
class="upgrade-notice"
>
<template #title>{{ $t('app.openclawHttpsUpgradeNoticeTitle') }}</template>
<div class="upgrade-notice-content">
<div>1. {{ $t('app.openclawHttpsUpgradeNoticeItem1') }}</div>
<div>2. {{ $t('app.openclawHttpsUpgradeNoticeItem2') }}</div>
</div>
</el-alert>
<el-form-item prop="backup" v-if="operateReq.operate === 'upgrade'">
<el-checkbox v-model="operateReq.backup" :label="$t('app.backupApp')" />
<span class="input-help">
@@ -86,15 +99,17 @@ import CodemirrorPro from '@/components/codemirror-pro/index.vue';
import { App } from '@/api/interface/app';
import { getAppUpdateVersions, ignoreUpgrade, installedOp } from '@/api/modules/app';
import { getAppStoreConfig } from '@/api/modules/setting';
import { compareVersion } from '@/utils/version';
import i18n from '@/lang';
import { ElMessageBox, FormInstance } from 'element-plus';
import { reactive, ref, onBeforeUnmount } from 'vue';
import { computed, onBeforeUnmount, reactive, ref } from 'vue';
import { MsgSuccess } from '@/utils/message';
import { Rules } from '@/global/form-rules';
import bus from '@/global/bus';
import { v4 as uuidv4 } from 'uuid';
import { useGlobalStore } from '@/composables/useGlobalStore';
const { currentNode } = useGlobalStore();
const openclawHttpsVersion = '2026.3.13';
const composeDiffRef = ref();
const updateRef = ref<FormInstance>();
@@ -135,6 +150,40 @@ const ignoreAppReq = reactive({
});
const isEdit = ref(false);
const node = ref('');
const currentVersion = ref('');
const currentAppKey = ref('');
const isOpenclawHttpsVersion = (version: string) => {
const target = String(version || '')
.trim()
.toLowerCase();
if (!target || target === 'latest') {
return true;
}
if (!/\d/.test(target)) {
return false;
}
return compareVersion(target, openclawHttpsVersion);
};
const isLegacyOpenclawVersion = (version: string) => {
const target = String(version || '')
.trim()
.toLowerCase();
if (!target || target === 'latest' || !/\d/.test(target)) {
return false;
}
return !compareVersion(target, openclawHttpsVersion);
};
const showOpenclawHttpsUpgradeNotice = computed(() => {
return (
operateReq.operate === 'upgrade' &&
currentAppKey.value === 'openclaw' &&
isLegacyOpenclawVersion(currentVersion.value) &&
isOpenclawHttpsVersion(operateReq.version)
);
});
const toLink = (link: string) => {
window.open(link, '_blank');
@@ -174,6 +223,8 @@ const acceptParams = (appInstall: App.AppInstallDto, op: string, opNode?: string
node.value = currentNode.value;
}
isEdit.value = appInstall.isEdit;
currentVersion.value = appInstall.version;
currentAppKey.value = appInstall.appKey;
operateReq.installId = appInstall.id;
operateReq.operate = op;
resourceName.value = appInstall.name;
@@ -268,3 +319,13 @@ defineExpose({
acceptParams,
});
</script>
<style lang="scss" scoped>
.upgrade-notice {
margin-bottom: 16px;
}
.upgrade-notice-content {
line-height: 1.8;
}
</style>