diff --git a/agent/app/api/v2/website_ssl.go b/agent/app/api/v2/website_ssl.go
index 6a546cc10..c46b0b1e5 100644
--- a/agent/app/api/v2/website_ssl.go
+++ b/agent/app/api/v2/website_ssl.go
@@ -1,6 +1,7 @@
package v2
import (
+ "github.com/1Panel-dev/1Panel/agent/app/model"
"net/http"
"net/url"
"reflect"
@@ -245,3 +246,15 @@ func (b *BaseApi) DownloadWebsiteSSL(c *gin.Context) {
c.Header("Content-Disposition", "attachment; filename*=utf-8''"+url.PathEscape(info.Name()))
http.ServeContent(c.Writer, c.Request, info.Name(), info.ModTime(), file)
}
+
+func (b *BaseApi) ImportMasterSSL(c *gin.Context) {
+ var req model.WebsiteSSL
+ if err := helper.CheckBindAndValidate(&req, c); err != nil {
+ return
+ }
+ if err := websiteSSLService.ImportMasterSSL(req); err != nil {
+ helper.InternalServer(c, err)
+ return
+ }
+ helper.Success(c)
+}
diff --git a/agent/app/dto/request/website_ssl.go b/agent/app/dto/request/website_ssl.go
index 06a662607..a08b5ea9c 100644
--- a/agent/app/dto/request/website_ssl.go
+++ b/agent/app/dto/request/website_ssl.go
@@ -9,24 +9,26 @@ type WebsiteSSLSearch struct {
}
type WebsiteSSLCreate struct {
- PrimaryDomain string `json:"primaryDomain" validate:"required"`
- OtherDomains string `json:"otherDomains"`
- Provider string `json:"provider" validate:"required"`
- AcmeAccountID uint `json:"acmeAccountId" validate:"required"`
- DnsAccountID uint `json:"dnsAccountId"`
- AutoRenew bool `json:"autoRenew"`
- KeyType string `json:"keyType"`
- Apply bool `json:"apply"`
- PushDir bool `json:"pushDir"`
- Dir string `json:"dir"`
- ID uint `json:"id"`
- Description string `json:"description"`
- DisableCNAME bool `json:"disableCNAME"`
- SkipDNS bool `json:"skipDNS"`
- Nameserver1 string `json:"nameserver1"`
- Nameserver2 string `json:"nameserver2"`
- ExecShell bool `json:"execShell"`
- Shell string `json:"shell"`
+ PrimaryDomain string `json:"primaryDomain" validate:"required"`
+ OtherDomains string `json:"otherDomains"`
+ Provider string `json:"provider" validate:"required"`
+ AcmeAccountID uint `json:"acmeAccountId" validate:"required"`
+ DnsAccountID uint `json:"dnsAccountId"`
+ AutoRenew bool `json:"autoRenew"`
+ KeyType string `json:"keyType"`
+ Apply bool `json:"apply"`
+ PushDir bool `json:"pushDir"`
+ Dir string `json:"dir"`
+ ID uint `json:"id"`
+ Description string `json:"description"`
+ DisableCNAME bool `json:"disableCNAME"`
+ SkipDNS bool `json:"skipDNS"`
+ Nameserver1 string `json:"nameserver1"`
+ Nameserver2 string `json:"nameserver2"`
+ ExecShell bool `json:"execShell"`
+ Shell string `json:"shell"`
+ PushNode bool `json:"pushNode"`
+ Nodes []string `json:"nodes"`
}
type WebsiteDNSReq struct {
diff --git a/agent/app/model/website_ssl.go b/agent/app/model/website_ssl.go
index a3c6591a2..99a0d201e 100644
--- a/agent/app/model/website_ssl.go
+++ b/agent/app/model/website_ssl.go
@@ -36,6 +36,9 @@ type WebsiteSSL struct {
DisableCNAME bool `json:"disableCNAME"`
ExecShell bool `json:"execShell"`
Shell string `json:"shell"`
+ MasterSSLID uint `json:"masterSslId"`
+ Nodes string `json:"nodes"`
+ PushNode bool `json:"pushNode"`
AcmeAccount WebsiteAcmeAccount `json:"acmeAccount" gorm:"-:migration"`
DnsAccount WebsiteDnsAccount `json:"dnsAccount" gorm:"-:migration"`
diff --git a/agent/app/repo/website_ssl.go b/agent/app/repo/website_ssl.go
index fbb4e3ebd..63fe27ac8 100644
--- a/agent/app/repo/website_ssl.go
+++ b/agent/app/repo/website_ssl.go
@@ -17,6 +17,7 @@ type ISSLRepo interface {
WithByDnsAccountId(dnsAccountId uint) DBOption
WithByCAID(caID uint) DBOption
WithByDomain(domain string) DBOption
+ WithByMasterSSLID(sslID uint) DBOption
Page(page, size int, opts ...DBOption) (int64, []model.WebsiteSSL, error)
GetFirst(opts ...DBOption) (*model.WebsiteSSL, error)
List(opts ...DBOption) ([]model.WebsiteSSL, error)
@@ -52,12 +53,19 @@ func (w WebsiteSSLRepo) WithByCAID(caID uint) DBOption {
return db.Where("ca_id = ?", caID)
}
}
+
func (w WebsiteSSLRepo) WithByDomain(domain string) DBOption {
return func(db *gorm.DB) *gorm.DB {
return db.Where("primary_domain Like ? or domains Like ?", "%"+domain+"%", "%"+domain+"%")
}
}
+func (w WebsiteSSLRepo) WithByMasterSSLID(sslID uint) DBOption {
+ return func(db *gorm.DB) *gorm.DB {
+ return db.Where("master_ssl_id = ?", sslID)
+ }
+}
+
func (w WebsiteSSLRepo) Page(page, size int, opts ...DBOption) (int64, []model.WebsiteSSL, error) {
var sslList []model.WebsiteSSL
db := getDb(opts...).Model(&model.WebsiteSSL{})
diff --git a/agent/app/service/website_ssl.go b/agent/app/service/website_ssl.go
index 0266f1aa4..4bfee04ea 100644
--- a/agent/app/service/website_ssl.go
+++ b/agent/app/service/website_ssl.go
@@ -5,6 +5,7 @@ import (
"crypto/x509"
"encoding/pem"
"fmt"
+ "github.com/1Panel-dev/1Panel/agent/utils/xpack"
"github.com/go-acme/lego/v4/certificate"
"log"
"os"
@@ -46,6 +47,7 @@ type IWebsiteSSLService interface {
ObtainSSL(apply request.WebsiteSSLApply) error
SyncForRestart() error
DownloadFile(id uint) (*os.File, error)
+ ImportMasterSSL(create model.WebsiteSSL) error
}
func NewIWebsiteSSLService() IWebsiteSSLService {
@@ -146,6 +148,10 @@ func (w WebsiteSSLService) Create(create request.WebsiteSSLCreate) (request.Webs
}
websiteSSL.Dir = create.Dir
}
+ if create.PushNode && global.IsMaster && len(create.Nodes) > 0 {
+ websiteSSL.PushNode = true
+ websiteSSL.Nodes = strings.Join(create.Nodes, ",")
+ }
var domains []string
if create.OtherDomains != "" {
@@ -207,7 +213,7 @@ func printSSLLog(logger *log.Logger, msgKey string, params map[string]interface{
}
func reloadSystemSSL(websiteSSL *model.WebsiteSSL, logger *log.Logger) {
- if global.CoreDB == nil {
+ if !global.IsMaster {
return
}
systemSSLEnable, sslID := GetSystemSSL()
@@ -387,6 +393,14 @@ func (w WebsiteSSLService) ObtainSSL(apply request.WebsiteSSLApply) error {
printSSLLog(logger, "ApplyWebSiteSSLSuccess", nil, apply.DisableLog)
}
reloadSystemSSL(websiteSSL, logger)
+ if websiteSSL.PushNode {
+ printSSLLog(logger, "StartPushSSLToNode", nil, apply.DisableLog)
+ if err = xpack.PushSSLToNode(websiteSSL); err != nil {
+ printSSLLog(logger, "PushSSLToNodeFailed", map[string]interface{}{"err": err.Error()}, apply.DisableLog)
+ return
+ }
+ printSSLLog(logger, "PushSSLToNodeSuccess", nil, apply.DisableLog)
+ }
}()
return nil
@@ -712,3 +726,55 @@ func (w WebsiteSSLService) SyncForRestart() error {
}
return nil
}
+
+func (w WebsiteSSLService) ImportMasterSSL(create model.WebsiteSSL) error {
+ websiteSSL, _ := websiteSSLRepo.GetFirst(websiteSSLRepo.WithByMasterSSLID(create.ID))
+ if websiteSSL == nil {
+ websiteSSL = &model.WebsiteSSL{
+ Status: constant.SSLReady,
+ Provider: constant.FromMaster,
+ PrimaryDomain: create.PrimaryDomain,
+ StartDate: create.StartDate,
+ ExpireDate: create.ExpireDate,
+ KeyType: create.KeyType,
+ Description: create.Description,
+ MasterSSLID: create.ID,
+ PrivateKey: create.PrivateKey,
+ Pem: create.Pem,
+ Type: create.Type,
+ Organization: create.Organization,
+ }
+ if err := websiteSSLRepo.Create(context.TODO(), websiteSSL); err != nil {
+ return err
+ }
+ } else {
+ websiteSSL.PrimaryDomain = create.PrimaryDomain
+ websiteSSL.StartDate = create.StartDate
+ websiteSSL.ExpireDate = create.ExpireDate
+ websiteSSL.KeyType = create.KeyType
+ websiteSSL.Description = create.Description
+ websiteSSL.PrivateKey = create.PrivateKey
+ websiteSSL.Pem = create.Pem
+ websiteSSL.Type = create.Type
+ websiteSSL.Organization = create.Organization
+ if err := websiteSSLRepo.Save(websiteSSL); err != nil {
+ return err
+ }
+ }
+ websites, _ := websiteRepo.GetBy(websiteRepo.WithWebsiteSSLID(websiteSSL.ID))
+ if len(websites) == 0 {
+ return nil
+ }
+ for _, website := range websites {
+ if err := createPemFile(website, *websiteSSL); err != nil {
+ continue
+ }
+ }
+ nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
+ if err == nil {
+ if err := opNginx(nginxInstall.ContainerName, constant.NginxReload); err != nil {
+ return err
+ }
+ }
+ return nil
+}
diff --git a/agent/constant/website.go b/agent/constant/website.go
index 7e96e16af..e4a3d059d 100644
--- a/agent/constant/website.go
+++ b/agent/constant/website.go
@@ -25,6 +25,7 @@ const (
Http = "http"
Manual = "manual"
SelfSigned = "selfSigned"
+ FromMaster = "fromMaster"
StartWeb = "start"
StopWeb = "stop"
diff --git a/agent/i18n/lang/en.yaml b/agent/i18n/lang/en.yaml
index 58b0fe4bf..e820a677c 100644
--- a/agent/i18n/lang/en.yaml
+++ b/agent/i18n/lang/en.yaml
@@ -162,6 +162,9 @@ StartUpdateSystemSSL: 'Start updating system certificate'
UpdateSystemSSLSuccess: 'Update system certificate successfully'
ErrWildcardDomain: 'Unable to apply for wildcard domain name certificate in HTTP mode'
ErrApplySSLCanNotDelete: "The certificate {{.name}} being applied for cannot be deleted, please try again later."
+StartPushSSLToNode: "Starting to push certificate to node"
+PushSSLToNodeFailed: "Failed to push certificate to node: {{ .err }}"
+PushSSLToNodeSuccess: "Successfully pushed certificate to node"
#mysql
ErrUserIsExist: 'The current user already exists, please re-enter'
diff --git a/agent/i18n/lang/ja.yaml b/agent/i18n/lang/ja.yaml
index a2d31519e..73ff924aa 100644
--- a/agent/i18n/lang/ja.yaml
+++ b/agent/i18n/lang/ja.yaml
@@ -162,6 +162,9 @@ StartUpdateSystemSSL: 'システム証明書の更新を開始します'
UpdateSystemSSLSuccess: 'システム証明書を正常に更新しました'
ErrWildcardDomain: 'HTTP モードでワイルドカード ドメイン名証明書を申請できません'
ErrApplySSLCanNotDelete: "申請中の証明書 {{.name}} は削除できません。しばらくしてからもう一度お試しください。"
+StartPushSSLToNode: "証明書をノードにプッシュ開始"
+PushSSLToNodeFailed: "ノードに証明書をプッシュ失敗: {{ .err }}"
+PushSSLToNodeSuccess: "ノードに証明書をプッシュ成功"
#mysql
ErrUserIsExist: '現在のユーザーは既に存在します。再入力してください'
diff --git a/agent/i18n/lang/ko.yaml b/agent/i18n/lang/ko.yaml
index a07e2fc85..109cbb4c6 100644
--- a/agent/i18n/lang/ko.yaml
+++ b/agent/i18n/lang/ko.yaml
@@ -162,6 +162,9 @@ StartUpdateSystemSSL: '시스템 인증서 업데이트 시작'
UpdateSystemSSLSuccess: '시스템 인증서 업데이트가 성공적으로 완료되었습니다.'
ErrWildcardDomain: 'HTTP 모드에서 와일드카드 도메인 이름 인증서를 신청할 수 없습니다'
ErrApplySSLCanNotDelete: "신청 중인 인증서 {{.name}}는 삭제할 수 없습니다. 나중에 다시 시도해 주세요."
+StartPushSSLToNode: "인증서를 노드로 푸시 시작"
+PushSSLToNodeFailed: "노드로 인증서 푸시 실패: {{ .err }}"
+PushSSLToNodeSuccess: "노드로 인증서 푸시 성공"
#마이SQL
ErrUserIsExist: '현재 사용자가 이미 존재합니다. 다시 입력하세요'
diff --git a/agent/i18n/lang/ms.yaml b/agent/i18n/lang/ms.yaml
index 5e7a2b573..45a95acf8 100644
--- a/agent/i18n/lang/ms.yaml
+++ b/agent/i18n/lang/ms.yaml
@@ -14,6 +14,9 @@ ErrApiConfigKeyInvalid: 'Ralat kunci antara muka API: {{ .detail }}'
ErrApiConfigIPInvalid: 'IP yang digunakan untuk memanggil antara muka API tiada dalam senarai putih: {{ .detail }}'
ErrApiConfigDisable: 'Antara muka ini melarang penggunaan panggilan antara muka API: {{ .detail }}'
ErrApiConfigKeyTimeInvalid: 'Ralat cap masa antara muka API: {{ .detail }}'
+StartPushSSLToNode: "Mula menolak sijil ke nod"
+PushSSLToNodeFailed: "Gagal menolak sijil ke nod: {{ .err }}"
+PushSSLToNodeSuccess: "Berjaya menolak sijil ke nod"
#biasa
ErrUsernameIsExist: 'Nama pengguna sudah wujud'
diff --git a/agent/i18n/lang/pt-BR.yaml b/agent/i18n/lang/pt-BR.yaml
index 345eb762f..23464540a 100644
--- a/agent/i18n/lang/pt-BR.yaml
+++ b/agent/i18n/lang/pt-BR.yaml
@@ -14,6 +14,9 @@ ErrApiConfigKeyInvalid: 'Erro de chave da interface da API: {{ .detail }}'
ErrApiConfigIPInvalid: 'O IP usado para chamar a interface da API não está na lista de permissões: {{ .detail }}'
ErrApiConfigDisable: 'Esta interface proíbe o uso de chamadas de interface de API: {{ .detail }}'
ErrApiConfigKeyTimeInvalid: 'Erro de registro de data e hora da interface da API: {{ .detail }}'
+StartPushSSLToNode: "Iniciando o envio do certificado para o nó"
+PushSSLToNodeFailed: "Falha ao enviar o certificado para o nó: {{ .err }}"
+PushSSLToNodeSuccess: "Certificado enviado com sucesso para o nó"
#comum
ErrUsernameIsExist: 'Nome de usuário já existe'
diff --git a/agent/i18n/lang/ru.yaml b/agent/i18n/lang/ru.yaml
index 8ee75aeaa..386704f63 100644
--- a/agent/i18n/lang/ru.yaml
+++ b/agent/i18n/lang/ru.yaml
@@ -14,6 +14,9 @@ ErrApiConfigKeyInvalid: 'Ошибка ключа интерфейса API: {{ .d
ErrApiConfigIPInvalid: 'IP-адрес, используемый для вызова интерфейса API, отсутствует в белом списке: {{ .detail }}'
ErrApiConfigDisable: 'Этот интерфейс запрещает использование вызовов интерфейса API: {{ .detail }}'
ErrApiConfigKeyTimeInvalid: 'Ошибка временной метки интерфейса API: {{ .detail }}'
+StartPushSSLToNode: "Начало отправки сертификата на узел"
+PushSSLToNodeFailed: "Не удалось отправить сертификат на узел: {{ .err }}"
+PushSSLToNodeSuccess: "Сертификат успешно отправлен на узел"
#общий
ErrUsernameIsExist: 'Имя пользователя уже существует'
diff --git a/agent/i18n/lang/tr.yaml b/agent/i18n/lang/tr.yaml
index 1d9949b37..6d0fcaf24 100644
--- a/agent/i18n/lang/tr.yaml
+++ b/agent/i18n/lang/tr.yaml
@@ -14,6 +14,9 @@ ErrApiConfigKeyInvalid: 'API arayüz anahtarı hatası: {{ .detail }}'
ErrApiConfigIPInvalid: 'API arayüzünü çağırmak için kullanılan IP beyaz listede değil: {{ .detail }}'
ErrApiConfigDisable: 'Bu arayüz API arayüz çağrılarının kullanımını yasaklıyor: {{ .detail }}'
ErrApiConfigKeyTimeInvalid: 'API arayüz zaman damgası hatası: {{ .detail }}'
+StartPushSSLToNode: "Sertifika düğüme gönderilmeye başlandı"
+PushSSLToNodeFailed: "Sertifika düğüme gönderilemedi: {{ .err }}"
+PushSSLToNodeSuccess: "Sertifika düğüme başarıyla gönderildi"
#common
ErrUsernameIsExist: 'Kullanıcı adı zaten mevcut'
diff --git a/agent/i18n/lang/zh-Hant.yaml b/agent/i18n/lang/zh-Hant.yaml
index edd4498a3..a336c9f1c 100644
--- a/agent/i18n/lang/zh-Hant.yaml
+++ b/agent/i18n/lang/zh-Hant.yaml
@@ -161,6 +161,9 @@ StartUpdateSystemSSL: '開始更新系統憑證'
UpdateSystemSSLSuccess: '更新系統憑證成功'
ErrWildcardDomain: 'HTTP 模式無法申請泛網域憑證'
ErrApplySSLCanNotDelete: "正在申請的證書 {{.name}} 無法刪除,請稍後再試"
+StartPushSSLToNode: "開始推送證書到節點"
+PushSSLToNodeFailed: "推送證書到節點失敗: {{ .err }}"
+PushSSLToNodeSuccess: "推送證書到節點成功"
#mysql
ErrUserIsExist: '目前使用者已存在,請重新輸入'
diff --git a/agent/i18n/lang/zh.yaml b/agent/i18n/lang/zh.yaml
index c3aa9923d..7b4992c9b 100644
--- a/agent/i18n/lang/zh.yaml
+++ b/agent/i18n/lang/zh.yaml
@@ -161,6 +161,9 @@ StartUpdateSystemSSL: "开始更新系统证书"
UpdateSystemSSLSuccess: "更新系统证书成功"
ErrWildcardDomain: "HTTP 模式无法申请泛域名证书"
ErrApplySSLCanNotDelete: "正在申请的证书{{.name}}无法删除,请稍后再试"
+StartPushSSLToNode: "开始推送证书到节点"
+PushSSLToNodeFailed: "推送证书到节点失败: {{ .err }}"
+PushSSLToNodeSuccess: "推送证书到节点成功"
#mysql
ErrUserIsExist: "当前用户已存在,请重新输入"
diff --git a/agent/init/migration/migrate.go b/agent/init/migration/migrate.go
index 306bee2ed..dceebff39 100644
--- a/agent/init/migration/migrate.go
+++ b/agent/init/migration/migrate.go
@@ -36,6 +36,7 @@ func InitAgentDB() {
migrations.UpdateMcpServer,
migrations.InitCronjobGroup,
migrations.AddColumnToAlert,
+ migrations.UpdateWebsiteSSL,
})
if err := m.Migrate(); err != nil {
global.LOG.Error(err)
diff --git a/agent/init/migration/migrations/init.go b/agent/init/migration/migrations/init.go
index f07adb005..4b6e9764b 100644
--- a/agent/init/migration/migrations/init.go
+++ b/agent/init/migration/migrations/init.go
@@ -461,3 +461,13 @@ var AddColumnToAlert = &gormigrate.Migration{
return nil
},
}
+
+var UpdateWebsiteSSL = &gormigrate.Migration{
+ ID: "20250819-update-website-ssl",
+ Migrate: func(tx *gorm.DB) error {
+ if err := tx.AutoMigrate(&model.WebsiteSSL{}); err != nil {
+ return err
+ }
+ return nil
+ },
+}
diff --git a/agent/router/ro_website_ssl.go b/agent/router/ro_website_ssl.go
index beb7d3b69..fcb194063 100644
--- a/agent/router/ro_website_ssl.go
+++ b/agent/router/ro_website_ssl.go
@@ -23,5 +23,6 @@ func (a *WebsiteSSLRouter) InitRouter(Router *gin.RouterGroup) {
groupRouter.POST("/upload", baseApi.UploadWebsiteSSL)
groupRouter.POST("/obtain", baseApi.ApplyWebsiteSSL)
groupRouter.POST("/download", baseApi.DownloadWebsiteSSL)
+ groupRouter.POST("/import", baseApi.ImportMasterSSL)
}
}
diff --git a/agent/utils/ssl/acme.go b/agent/utils/ssl/acme.go
index aec5ebc97..b4d25db1a 100644
--- a/agent/utils/ssl/acme.go
+++ b/agent/utils/ssl/acme.go
@@ -181,7 +181,8 @@ func getCaDirURL(accountType, customCaURL string) string {
var caDirURL string
switch accountType {
case "letsencrypt":
- caDirURL = "https://acme-v02.api.letsencrypt.org/directory"
+ //caDirURL = "https://acme-v02.api.letsencrypt.org/directory"
+ caDirURL = "https://acme-staging-v02.api.letsencrypt.org/directory"
case "zerossl":
caDirURL = "https://acme.zerossl.com/v2/DV90"
case "buypass":
diff --git a/agent/utils/xpack/xpack.go b/agent/utils/xpack/xpack.go
index efee272ec..6ba1c2520 100644
--- a/agent/utils/xpack/xpack.go
+++ b/agent/utils/xpack/xpack.go
@@ -85,3 +85,7 @@ func LoadRequestTransport() *http.Transport {
func ValidateCertificate(c *gin.Context) bool {
return true
}
+
+func PushSSLToNode(websiteSSL *model.WebsiteSSL) error {
+ return nil
+}
diff --git a/core/i18n/lang/en.yaml b/core/i18n/lang/en.yaml
index e40bcbe87..12f8c4ef4 100644
--- a/core/i18n/lang/en.yaml
+++ b/core/i18n/lang/en.yaml
@@ -227,4 +227,7 @@ ErrMasterDelete: "Unable to delete the master node, please delete the slave node
ClusterNameIsExist: "Cluster name already exists."
AppStatusUnHealthy: "Application status acquisition is abnormal, please check the installation node status in the node list."
MasterNodePortNotAvailable: "Node {{ .name }} port {{ .port }} connectivity verification failed, please check firewall/security group settings and master node status."
-ClusterMasterNotExist: "The master node of the cluster is disconnected, please delete the child nodes."
\ No newline at end of file
+ClusterMasterNotExist: "The master node of the cluster is disconnected, please delete the child nodes."
+
+#ssl
+ErrReqFailed: "{{.name}} request failed: {{ .err }}"
\ No newline at end of file
diff --git a/core/i18n/lang/ja.yaml b/core/i18n/lang/ja.yaml
index 67a6c9f56..c8c744f39 100644
--- a/core/i18n/lang/ja.yaml
+++ b/core/i18n/lang/ja.yaml
@@ -228,4 +228,7 @@ ErrMasterDelete: "マスターノードを削除できません。スレーブ
ClusterNameIsExist: "クラスタ名は既に存在します。"
AppStatusUnHealthy: "アプリケーションのステータス取得が異常です。ノードリストでインストールノードのステータスを確認してください。"
MasterNodePortNotAvailable: "ノード {{ .name }} のポート {{ .port }} の接続性検証が失敗しました。ファイアウォール/セキュリティグループの設定とマスターノードのステータスを確認してください。"
-ClusterMasterNotExist: "クラスタのマスターノードが切断されています。子ノードを削除してください。"
\ No newline at end of file
+ClusterMasterNotExist: "クラスタのマスターノードが切断されています。子ノードを削除してください。"
+
+#ssl
+ErrReqFailed: "{{.name}} リクエスト失敗: {{ .err }}"
\ No newline at end of file
diff --git a/core/i18n/lang/ko.yaml b/core/i18n/lang/ko.yaml
index bad73bdd6..d9053e45c 100644
--- a/core/i18n/lang/ko.yaml
+++ b/core/i18n/lang/ko.yaml
@@ -227,4 +227,7 @@ ErrMasterDelete: "마스터 노드를 삭제할 수 없습니다. 슬레이브
ClusterNameIsExist: "클러스터 이름이 이미 존재합니다."
AppStatusUnHealthy: "애플리케이션 상태 획득이 비정상입니다. 노드 목록에서 설치 노드 상태를 확인하세요."
MasterNodePortNotAvailable: "노드 {{ .name }} 포트 {{ .port }} 연결성 검증에 실패했습니다. 방화벽/보안 그룹 설정 및 마스터 노드 상태를 확인하세요."
-ClusterMasterNotExist: "클러스터의 마스터 노드가 연결이 끊어졌습니다. 자식 노드를 삭제하세요."
\ No newline at end of file
+ClusterMasterNotExist: "클러스터의 마스터 노드가 연결이 끊어졌습니다. 자식 노드를 삭제하세요."
+
+#ssl
+ErrReqFailed: "{{.name}} 요청 실패: {{ .err }}"
\ No newline at end of file
diff --git a/core/i18n/lang/ms.yml b/core/i18n/lang/ms.yml
index 49fa2d14e..cee732e03 100644
--- a/core/i18n/lang/ms.yml
+++ b/core/i18n/lang/ms.yml
@@ -222,4 +222,7 @@ ErrMasterDelete: "Tidak dapat menghapus nod utama, sila hapuskan nod perantara d
ClusterNameIsExist: "Nama kluster sudah wujud."
AppStatusUnHealthy: "Pengambilan status aplikasi tidak normal, sila periksa status nod pemasangan dalam senarai nod."
MasterNodePortNotAvailable: "Pengesahan kesambungan pelabuhan {{ .name }} nod {{ .port }} gagal, sila periksa tetapan firewall/kumpulan keselamatan dan status nod utama."
-ClusterMasterNotExist: "Node utama kluster terputus, sila padamkan nod anak."
\ No newline at end of file
+ClusterMasterNotExist: "Node utama kluster terputus, sila padamkan nod anak."
+
+#ssl
+ErrReqFailed: "{{.name}} permintaan gagal: {{ .err }}"
\ No newline at end of file
diff --git a/core/i18n/lang/pt-BR.yaml b/core/i18n/lang/pt-BR.yaml
index 1500f54b8..ee5dd6d94 100644
--- a/core/i18n/lang/pt-BR.yaml
+++ b/core/i18n/lang/pt-BR.yaml
@@ -227,4 +227,7 @@ ErrMasterDelete: "Não é possível excluir o nó mestre, exclua os nós escravo
ClusterNameIsExist: "O nome do cluster já existe."
AppStatusUnHealthy: "A aquisição do status do aplicativo está anormal, verifique o status dos nós de instalação na lista de nós."
MasterNodePortNotAvailable: "A verificação de conectividade da porta {{ .port }} do nó {{ .name }} falhou, verifique as configurações de firewall/grupo de segurança e o status do nó mestre."
-ClusterMasterNotExist: "O nó mestre do cluster está desconectado, por favor, exclua os nós filhos."
\ No newline at end of file
+ClusterMasterNotExist: "O nó mestre do cluster está desconectado, por favor, exclua os nós filhos."
+
+#ssl
+ErrReqFailed: "{{.name}} solicitação falhou: {{ .err }}
\ No newline at end of file
diff --git a/core/i18n/lang/ru.yaml b/core/i18n/lang/ru.yaml
index 426ffac9f..ae43df935 100644
--- a/core/i18n/lang/ru.yaml
+++ b/core/i18n/lang/ru.yaml
@@ -227,4 +227,7 @@ ErrMasterDelete: "Невозможно удалить основной узел,
ClusterNameIsExist: "Имя кластера уже существует."
AppStatusUnHealthy: "Получение статуса приложения аномально, пожалуйста, проверьте статус узлов установки в списке узлов."
MasterNodePortNotAvailable: "Проверка подключения порта {{ .port }} узла {{ .name }} не удалась, пожалуйста, проверьте настройки брандмауэра/группы безопасности и статус главного узла."
-ClusterMasterNotExist: "Основной узел кластера отключен, пожалуйста, удалите дочерние узлы."
\ No newline at end of file
+ClusterMasterNotExist: "Основной узел кластера отключен, пожалуйста, удалите дочерние узлы."
+
+#ssl
+ErrReqFailed: "{{.name}} запрос не удался: {{ .err }}"
\ No newline at end of file
diff --git a/core/i18n/lang/tr.yaml b/core/i18n/lang/tr.yaml
index 0d64d3881..cdc140645 100644
--- a/core/i18n/lang/tr.yaml
+++ b/core/i18n/lang/tr.yaml
@@ -226,4 +226,7 @@ ErrMasterDelete: "Ana düğümü silinemiyor, lütfen önce alt düğümleri sil
ClusterNameIsExist: "Küme adı zaten var."
AppStatusUnHealthy: "Uygulama durumu alımı anormal, lütfen düğüm listesindeki yükleme düğümü durumunu kontrol edin."
MasterNodePortNotAvailable: "Düğüm {{ .name }} portu {{ .port }} bağlantı doğrulaması başarısız oldu, lütfen güvenlik duvarı/güvenlik grubu ayarlarını ve ana düğüm durumunu kontrol edin."
-ClusterMasterNotExist: "Küme ana düğümü bağlantısı kesildi, lütfen alt düğümleri silin."
\ No newline at end of file
+ClusterMasterNotExist: "Küme ana düğümü bağlantısı kesildi, lütfen alt düğümleri silin."
+
+#ssl
+ErrReqFailed: "{{.name}} istek başarısız: {{ .err }}"
\ No newline at end of file
diff --git a/core/i18n/lang/zh-Hant.yaml b/core/i18n/lang/zh-Hant.yaml
index ef75db1aa..a665ccd98 100644
--- a/core/i18n/lang/zh-Hant.yaml
+++ b/core/i18n/lang/zh-Hant.yaml
@@ -236,4 +236,7 @@ ErrMasterDelete: "無法刪除主節點,請先刪除從節點。"
ClusterNameIsExist: "集群名稱已存在。"
AppStatusUnHealthy: "應用獲取狀態異常,請在節點列表檢查安裝節點狀態。"
MasterNodePortNotAvailable: "節點 {{ .name }} 端口 {{ .port }} 連通性校驗失敗,請檢查防火牆/安全組設置和主節點狀態。"
-ClusterMasterNotExist: "集群主節點失聯,請刪除子節點。"
\ No newline at end of file
+ClusterMasterNotExist: "集群主節點失聯,請刪除子節點。"
+
+#ssl
+ErrReqFailed: "{{.name}} 請求失敗: {{ .err }}"
\ No newline at end of file
diff --git a/core/i18n/lang/zh.yaml b/core/i18n/lang/zh.yaml
index cb5f97eb2..a35aff9b8 100644
--- a/core/i18n/lang/zh.yaml
+++ b/core/i18n/lang/zh.yaml
@@ -236,4 +236,7 @@ ErrMasterDelete: "无法删除主节点,请先删除从节点"
ClusterNameIsExist: "集群名称已存在"
AppStatusUnHealthy: "应用获取状态异常,请在节点列表检查安装节点状态"
MasterNodePortNotAvailable: "节点 {{ .name }} 端口 {{ .port }} 连通性校验失败,请检查防火墙/安全组设置和主节点状态"
-ClusterMasterNotExist: "集群主节点失联,请删除子节点"
\ No newline at end of file
+ClusterMasterNotExist: "集群主节点失联,请删除子节点"
+
+#ssl
+ErrReqFailed: "{{.name}} 请求失败: {{ .err }}"
\ No newline at end of file
diff --git a/core/init/router/proxy.go b/core/init/router/proxy.go
index a05fada8a..c122f62ee 100644
--- a/core/init/router/proxy.go
+++ b/core/init/router/proxy.go
@@ -44,7 +44,7 @@ func Proxy() gin.HandlerFunc {
apiReq := c.GetBool("API_AUTH")
- if !apiReq && strings.HasPrefix(c.Request.URL.Path, "/api/v2/") && !checkSession(c) {
+ if !apiReq && strings.HasPrefix(c.Request.URL.Path, "/api/v2/") && !isLocalAPI(c.Request.URL.Path) && !checkSession(c) {
data, _ := res.ErrorMsg.ReadFile("html/401.html")
c.Data(401, "text/html; charset=utf-8", data)
c.Abort()
@@ -89,3 +89,7 @@ func checkSession(c *gin.Context) bool {
_ = global.SESSION.Set(c, psession, httpsSetting.Value == constant.StatusEnable, lifeTime)
return true
}
+
+func isLocalAPI(urlPath string) bool {
+ return urlPath == "/api/v2/core/xpack/sync/ssl"
+}
diff --git a/frontend/src/components/drawer-pro/index.vue b/frontend/src/components/drawer-pro/index.vue
index 07705d6c5..0a3138596 100644
--- a/frontend/src/components/drawer-pro/index.vue
+++ b/frontend/src/components/drawer-pro/index.vue
@@ -146,7 +146,11 @@ const handleClose = () => {
};
const beforeClose = (done: () => void) => {
- emit('beforeClose', done);
+ if (!props.confirmBeforeClose) {
+ done();
+ } else {
+ emit('beforeClose', done);
+ }
};
function toggleFullscreen() {
diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts
index 717ad3d55..02bcbdef1 100644
--- a/frontend/src/lang/modules/en.ts
+++ b/frontend/src/lang/modules/en.ts
@@ -2669,6 +2669,9 @@ const message = {
customAcme: 'Custom ACME Service',
customAcmeURL: 'ACME Service URL',
baiduCloud: 'Baidu Cloud',
+ pushNode: 'Sync to Other Nodes',
+ pushNodeHelper: 'Push to selected nodes after application/renewal',
+ fromMaster: 'Master Node Push',
},
firewall: {
create: 'Create rule',
diff --git a/frontend/src/lang/modules/ja.ts b/frontend/src/lang/modules/ja.ts
index f713cb1fd..e79d32c03 100644
--- a/frontend/src/lang/modules/ja.ts
+++ b/frontend/src/lang/modules/ja.ts
@@ -2582,6 +2582,9 @@ const message = {
customAcme: 'カスタム ACME サービス',
customAcmeURL: 'ACME サービス URL',
baiduCloud: '百度クラウド',
+ pushNode: '他のノードに同期',
+ pushNodeHelper: '申請/更新後に選択したノードにプッシュ',
+ fromMaster: 'マスターノードからのプッシュ',
},
firewall: {
create: 'ルールを作成します',
diff --git a/frontend/src/lang/modules/ko.ts b/frontend/src/lang/modules/ko.ts
index 1c46fd8d3..f25b31baf 100644
--- a/frontend/src/lang/modules/ko.ts
+++ b/frontend/src/lang/modules/ko.ts
@@ -2535,6 +2535,9 @@ const message = {
customAcme: '사용자 정의 ACME 서비스',
customAcmeURL: 'ACME 서비스 URL',
baiduCloud: '바이두 클라우드',
+ pushNode: '다른 노드에 동기화',
+ pushNodeHelper: '신청/갱신 후 선택한 노드로 푸시',
+ fromMaster: '마스터 노드에서 푸시',
},
firewall: {
create: '규칙 만들기',
diff --git a/frontend/src/lang/modules/ms.ts b/frontend/src/lang/modules/ms.ts
index ef446f853..574951767 100644
--- a/frontend/src/lang/modules/ms.ts
+++ b/frontend/src/lang/modules/ms.ts
@@ -2642,6 +2642,9 @@ const message = {
customAcme: 'Perkhidmatan ACME Tersuai',
customAcmeURL: 'URL Perkhidmatan ACME',
baiduCloud: 'Baidu Cloud',
+ pushNode: 'Segerakan ke Nod Lain',
+ pushNodeHelper: 'Tolak ke nod terpilih selepas permohonan/pembaharuan',
+ fromMaster: 'Tolak dari Nod Utama',
},
firewall: {
create: 'Buat peraturan',
diff --git a/frontend/src/lang/modules/pt-br.ts b/frontend/src/lang/modules/pt-br.ts
index 45951ed0f..14807b088 100644
--- a/frontend/src/lang/modules/pt-br.ts
+++ b/frontend/src/lang/modules/pt-br.ts
@@ -2643,6 +2643,9 @@ const message = {
customAcme: 'Serviço ACME Personalizado',
customAcmeURL: 'URL do Serviço ACME',
baiduCloud: 'Baidu Cloud',
+ pushNode: 'Sincronizar com Outros Nós',
+ pushNodeHelper: 'Enviar para os nós selecionados após a aplicação/renovação',
+ fromMaster: 'Envio do Nó Mestre',
},
firewall: {
create: 'Criar regra',
diff --git a/frontend/src/lang/modules/ru.ts b/frontend/src/lang/modules/ru.ts
index dbee0e4f5..c5171cb42 100644
--- a/frontend/src/lang/modules/ru.ts
+++ b/frontend/src/lang/modules/ru.ts
@@ -2638,6 +2638,9 @@ const message = {
customAcme: 'Пользовательская служба ACME',
customAcmeURL: 'URL службы ACME',
baiduCloud: 'Baidu Cloud',
+ pushNode: 'Синхронизация с другими узлами',
+ pushNodeHelper: 'Отправить на выбранные узлы после заявки/продления',
+ fromMaster: 'Отправка с главного узла',
},
firewall: {
create: 'Создать правило',
diff --git a/frontend/src/lang/modules/tr.ts b/frontend/src/lang/modules/tr.ts
index 1f6f33f6a..aea9a25bc 100644
--- a/frontend/src/lang/modules/tr.ts
+++ b/frontend/src/lang/modules/tr.ts
@@ -2702,6 +2702,9 @@ const message = {
customAcme: 'Özel ACME Servisi',
customAcmeURL: 'ACME Servis URL’si',
baiduCloud: 'Baidu Cloud',
+ pushNode: 'Diğer Düğümlere Senkronize Et',
+ pushNodeHelper: 'Başvuru/yenilemeden sonra seçilen düğümlere gönder',
+ fromMaster: 'Ana Düğümden Gönder',
},
firewall: {
create: 'Kural oluştur',
diff --git a/frontend/src/lang/modules/zh-Hant.ts b/frontend/src/lang/modules/zh-Hant.ts
index 96a79504f..4176d12f9 100644
--- a/frontend/src/lang/modules/zh-Hant.ts
+++ b/frontend/src/lang/modules/zh-Hant.ts
@@ -2489,6 +2489,9 @@ const message = {
customAcme: '自訂 ACME 服務',
customAcmeURL: 'ACME 服務 URL',
baiduCloud: '百度雲',
+ pushNode: '同步到其他節點',
+ pushNodeHelper: '申請/續期之後推送到選擇的節點',
+ fromMaster: '主節點推送',
},
firewall: {
create: '創建規則',
diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts
index 314111e59..1bb0da1f1 100644
--- a/frontend/src/lang/modules/zh.ts
+++ b/frontend/src/lang/modules/zh.ts
@@ -2479,6 +2479,9 @@ const message = {
customAcme: '自定义 ACME 服务',
customAcmeURL: 'ACME 服务 URL',
baiduCloud: '百度云',
+ pushNode: '同步到其他节点',
+ pushNodeHelper: '申请/续期之后推送到选择的节点',
+ fromMaster: '主节点推送',
},
firewall: {
create: '创建规则',
diff --git a/frontend/src/utils/util.ts b/frontend/src/utils/util.ts
index 97dddea2f..70cf13dbe 100644
--- a/frontend/src/utils/util.ts
+++ b/frontend/src/utils/util.ts
@@ -440,6 +440,8 @@ export function getProvider(provider: string): string {
return 'HTTP';
case 'selfSigned':
return i18n.global.t('ssl.selfSigned');
+ case 'fromMaster':
+ return i18n.global.t('ssl.fromMaster');
default:
return i18n.global.t('ssl.manualCreate');
}
diff --git a/frontend/src/views/ai/model/del/index.vue b/frontend/src/views/ai/model/del/index.vue
index d50157857..bd2e5e2e8 100644
--- a/frontend/src/views/ai/model/del/index.vue
+++ b/frontend/src/views/ai/model/del/index.vue
@@ -39,7 +39,7 @@ import { deleteOllamaModel } from '@/api/modules/ai';
import i18n from '@/lang';
import { MsgSuccess } from '@/utils/message';
import { CheckboxValueType } from 'element-plus';
-import { onMounted, ref } from 'vue';
+import { ref } from 'vue';
defineOptions({ name: 'OpDialog' });
@@ -97,8 +97,6 @@ const handleClose = () => {
open.value = false;
};
-onMounted(() => {});
-
defineExpose({
acceptParams,
});
diff --git a/frontend/src/views/app-store/apps/index.vue b/frontend/src/views/app-store/apps/index.vue
index 001b6509f..f8bb83f71 100644
--- a/frontend/src/views/app-store/apps/index.vue
+++ b/frontend/src/views/app-store/apps/index.vue
@@ -258,14 +258,6 @@ onMounted(async () => {
padding-bottom: 10px;
}
-// .tag-button {
-// margin-right: 10px;
-// &.no-active {
-// background: none;
-// border: none;
-// }
-// }
-
@media only screen and (min-width: 768px) and (max-width: 1200px) {
.app-col-12 {
max-width: 50%;
diff --git a/frontend/src/views/website/ssl/create/index.vue b/frontend/src/views/website/ssl/create/index.vue
index e97cd5ff5..4f8dd96db 100644
--- a/frontend/src/views/website/ssl/create/index.vue
+++ b/frontend/src/views/website/ssl/create/index.vue
@@ -94,28 +94,6 @@