mirror of https://github.com/1Panel-dev/1Panel
feat: SSL 配置增加重启选项 (#6792)
parent
e531b509d6
commit
9a79dc4cdd
|
@ -30,6 +30,7 @@ type SettingInfo struct {
|
|||
ServerPort string `json:"serverPort"`
|
||||
SSL string `json:"ssl"`
|
||||
SSLType string `json:"sslType"`
|
||||
AutoRestart string `json:"autoRestart"`
|
||||
BindDomain string `json:"bindDomain"`
|
||||
AllowIPs string `json:"allowIPs"`
|
||||
SecurityEntrance string `json:"securityEntrance"`
|
||||
|
@ -73,12 +74,13 @@ type SettingUpdate struct {
|
|||
}
|
||||
|
||||
type SSLUpdate struct {
|
||||
SSLType string `json:"sslType" validate:"required,oneof=self select import import-paste import-local"`
|
||||
Domain string `json:"domain"`
|
||||
SSL string `json:"ssl" validate:"required,oneof=enable disable"`
|
||||
Cert string `json:"cert"`
|
||||
Key string `json:"key"`
|
||||
SSLID uint `json:"sslID"`
|
||||
SSLType string `json:"sslType" validate:"required,oneof=self select import import-paste import-local"`
|
||||
Domain string `json:"domain"`
|
||||
SSL string `json:"ssl" validate:"required,oneof=enable disable"`
|
||||
Cert string `json:"cert"`
|
||||
Key string `json:"key"`
|
||||
SSLID uint `json:"sslID"`
|
||||
AutoRestart string `json:"autoRestart"`
|
||||
}
|
||||
type SSLInfo struct {
|
||||
Domain string `json:"domain"`
|
||||
|
|
|
@ -322,6 +322,9 @@ func (u *SettingService) UpdateSSL(c *gin.Context, req dto.SSLUpdate) error {
|
|||
if err := settingRepo.Update("SSL", req.SSL); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := settingRepo.Update("AutoRestart", req.AutoRestart); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sID, _ := c.Cookie(constant.SessionName)
|
||||
c.SetCookie(constant.SessionName, sID, 0, "", "", true, true)
|
||||
|
|
|
@ -3,7 +3,6 @@ package service
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/xpack"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
|
@ -13,6 +12,8 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/xpack"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/i18n"
|
||||
|
@ -1001,20 +1002,23 @@ func saveCertificateFile(websiteSSL *model.WebsiteSSL, logger *log.Logger) {
|
|||
}
|
||||
}
|
||||
|
||||
func GetSystemSSL() (bool, uint) {
|
||||
func GetSystemSSL() (bool, bool, uint) {
|
||||
sslSetting, err := settingRepo.Get(settingRepo.WithByKey("SSL"))
|
||||
if err != nil {
|
||||
global.LOG.Errorf("load service ssl from setting failed, err: %v", err)
|
||||
return false, 0
|
||||
return false, false, 0
|
||||
}
|
||||
if sslSetting.Value == "enable" {
|
||||
sslID, _ := settingRepo.Get(settingRepo.WithByKey("SSLID"))
|
||||
idValue, _ := strconv.Atoi(sslID.Value)
|
||||
if idValue > 0 {
|
||||
return true, uint(idValue)
|
||||
if idValue <= 0 {
|
||||
return false, false, 0
|
||||
}
|
||||
|
||||
auto, _ := settingRepo.Get(settingRepo.WithByKey("AutoRestart"))
|
||||
return true, auto.Value == "enable", uint(idValue)
|
||||
}
|
||||
return false, 0
|
||||
return false, false, 0
|
||||
}
|
||||
|
||||
func UpdateSSLConfig(websiteSSL model.WebsiteSSL) error {
|
||||
|
@ -1033,7 +1037,7 @@ func UpdateSSLConfig(websiteSSL model.WebsiteSSL) error {
|
|||
return buserr.WithErr(constant.ErrSSLApply, err)
|
||||
}
|
||||
}
|
||||
enable, sslID := GetSystemSSL()
|
||||
enable, auto, sslID := GetSystemSSL()
|
||||
if enable && sslID == websiteSSL.ID {
|
||||
fileOp := files.NewFileOp()
|
||||
secretDir := path.Join(global.CONF.System.BaseDir, "1panel/secret")
|
||||
|
@ -1045,6 +1049,9 @@ func UpdateSSLConfig(websiteSSL model.WebsiteSSL) error {
|
|||
global.LOG.Errorf("Failed to update the SSL certificate for 1Panel System domain [%s] , err:%s", websiteSSL.PrimaryDomain, err.Error())
|
||||
return err
|
||||
}
|
||||
if auto {
|
||||
_, _ = cmd.Exec("systemctl restart 1panel.service")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"github.com/1Panel-dev/1Panel/backend/app/service"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
)
|
||||
|
@ -22,7 +23,7 @@ func NewSSLJob() *ssl {
|
|||
}
|
||||
|
||||
func (ssl *ssl) Run() {
|
||||
systemSSLEnable, sslID := service.GetSystemSSL()
|
||||
systemSSLEnable, auto, sslID := service.GetSystemSSL()
|
||||
sslRepo := repo.NewISSLRepo()
|
||||
sslService := service.NewIWebsiteSSLService()
|
||||
sslList, _ := sslRepo.List()
|
||||
|
@ -70,6 +71,9 @@ func (ssl *ssl) Run() {
|
|||
global.LOG.Errorf("Failed to update the SSL certificate for 1Panel System domain [%s] , err:%s", s.PrimaryDomain, err.Error())
|
||||
continue
|
||||
}
|
||||
if auto {
|
||||
_, _ = cmd.Exec("systemctl restart 1panel.service")
|
||||
}
|
||||
}
|
||||
global.LOG.Infof("The SSL certificate for the [%s] domain has been successfully updated", s.PrimaryDomain)
|
||||
}
|
||||
|
|
|
@ -95,6 +95,8 @@ func Init() {
|
|||
migrations.AddClamStatus,
|
||||
migrations.AddAlertMenu,
|
||||
migrations.AddComposeColumn,
|
||||
|
||||
migrations.AddAutoRestart,
|
||||
})
|
||||
if err := m.Migrate(); err != nil {
|
||||
global.LOG.Error(err)
|
||||
|
|
|
@ -324,3 +324,13 @@ var AddComposeColumn = &gormigrate.Migration{
|
|||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var AddAutoRestart = &gormigrate.Migration{
|
||||
ID: "20241021-add-auto-restart",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
if err := tx.Create(&model.Setting{Key: "AutoRestart", Value: "enable"}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ export namespace Setting {
|
|||
bindAddress: string;
|
||||
ssl: string;
|
||||
sslType: string;
|
||||
autoRestart: string;
|
||||
allowIPs: string;
|
||||
bindDomain: string;
|
||||
securityEntrance: string;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
:destroy-on-close="true"
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="false"
|
||||
:before-close="handleClose"
|
||||
:size="globalStore.isFullScreen ? '100%' : '50%'"
|
||||
>
|
||||
<template #header>
|
||||
|
@ -21,10 +22,10 @@
|
|||
</el-drawer>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref } from 'vue';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import LogFile from '@/components/log-file/index.vue';
|
||||
import { GlobalStore } from '@/store';
|
||||
import screenfull from 'screenfull';
|
||||
import { GlobalStore } from '@/store';
|
||||
import i18n from '@/lang';
|
||||
|
||||
const globalStore = GlobalStore();
|
||||
|
@ -45,19 +46,22 @@ const open = ref(false);
|
|||
const config = ref();
|
||||
const em = defineEmits(['close']);
|
||||
|
||||
const handleClose = (search: boolean) => {
|
||||
const handleClose = () => {
|
||||
open.value = false;
|
||||
em('close', search);
|
||||
em('close', false);
|
||||
globalStore.isFullScreen = false;
|
||||
};
|
||||
|
||||
watch(open, (val) => {
|
||||
if (screenfull.isEnabled && !val && !mobile.value) screenfull.exit();
|
||||
});
|
||||
|
||||
function toggleFullscreen() {
|
||||
if (screenfull.isEnabled) {
|
||||
screenfull.toggle();
|
||||
}
|
||||
globalStore.isFullScreen = !globalStore.isFullScreen;
|
||||
}
|
||||
|
||||
const loadTooltip = () => {
|
||||
return i18n.global.t('commons.button.' + (screenfull.isFullscreen ? 'quitFullscreen' : 'fullscreen'));
|
||||
return i18n.global.t('commons.button.' + (globalStore.isFullScreen ? 'quitFullscreen' : 'fullscreen'));
|
||||
};
|
||||
|
||||
const acceptParams = (props: LogProps) => {
|
||||
|
|
|
@ -1518,8 +1518,11 @@ const message = {
|
|||
bindDomain: 'Bind Domain',
|
||||
unBindDomain: 'Unbind domain',
|
||||
panelSSL: 'Panel SSL',
|
||||
panelSSLHelper:
|
||||
'After the automatic renewal of the panel SSL, you need to manually restart the 1Panel service for the changes to take effect.',
|
||||
sslAutoRestart: 'Restart 1Panel service after certificate auto-renewal',
|
||||
sslChangeHelper1:
|
||||
'Currently, automatic restart of 1Panel service is not selected. The certificate auto-renewal will not take effect immediately and will still require a manual restart of 1Panel.',
|
||||
sslChangeHelper2:
|
||||
'The 1Panel service will automatically restart after setting the panel SSL. Do you want to continue?',
|
||||
unBindDomainHelper:
|
||||
'The action of unbinding a domain name may cause system insecurity. Do you want to continue?',
|
||||
bindDomainHelper:
|
||||
|
|
|
@ -1468,7 +1468,9 @@ const message = {
|
|||
bindDomain: '域名綁定',
|
||||
unBindDomain: '域名解綁',
|
||||
panelSSL: '面板 SSL',
|
||||
panelSSLHelper: '面板 SSL 自动续期后需要手动重启 1Panel 服务才可生效',
|
||||
sslAutoRestart: '證書自動續期後重啟 1Panel 服務',
|
||||
sslChangeHelper1: '當前未勾選自動重啟 1Panel 服務,證書自動續期後不會立即生效,仍需手動重啟 1Panel。',
|
||||
sslChangeHelper2: '設置面板 SSL 後將自動重啟 1Panel 服務,是否繼續?',
|
||||
unBindDomainHelper: '解除域名綁定可能造成系統不安全,是否繼續?',
|
||||
bindDomainHelper: '設置域名綁定後,僅能通過設置中域名訪問 1Panel 服務',
|
||||
bindDomainHelper1: '綁定域名為空時,則取消域名綁定',
|
||||
|
|
|
@ -1470,7 +1470,9 @@ const message = {
|
|||
bindDomain: '域名绑定',
|
||||
unBindDomain: '域名解绑',
|
||||
panelSSL: '面板 SSL',
|
||||
panelSSLHelper: '面板 SSL 自动续期后需要手动重启 1Panel 服务才可生效',
|
||||
sslAutoRestart: '证书自动续期后重启 1Panel 服务',
|
||||
sslChangeHelper1: '当前未勾选自动重启 1Panel 服务,证书自动续期后不会立即生效,仍需手动重启 1Panel。',
|
||||
sslChangeHelper2: '设置面板 SSL 后将自动重启 1Panel 服务,是否继续?',
|
||||
unBindDomainHelper: '解除域名绑定可能造成系统不安全,是否继续?',
|
||||
bindDomainHelper: '设置域名绑定后,仅能通过设置中域名访问 1Panel 服务',
|
||||
bindDomainHelper1: '绑定域名为空时,则取消域名绑定',
|
||||
|
@ -1494,7 +1496,6 @@ const message = {
|
|||
mfaInterval: '刷新时间(秒)',
|
||||
mfaTitleHelper: '用于区分不同 1Panel 主机,修改后请重新扫描或手动添加密钥信息!',
|
||||
mfaIntervalHelper: '修改刷新时间后,请重新扫描或手动添加密钥信息!',
|
||||
sslChangeHelper: 'https 设置修改需要重启服务,是否继续?',
|
||||
sslDisable: '禁用',
|
||||
sslDisableHelper: '禁用 https 服务,需要重启面板才能生效,是否继续?',
|
||||
noAuthSetting: '未认证设置',
|
||||
|
|
|
@ -114,7 +114,7 @@
|
|||
<div v-if="form.ssl === 'enable' && sslInfo">
|
||||
<el-tag>{{ $t('setting.domainOrIP') }} {{ sslInfo.domain }}</el-tag>
|
||||
<el-tag style="margin-left: 5px">
|
||||
{{ $t('setting.timeOut') }} {{ sslInfo.timeout }}
|
||||
{{ $t('setting.timeOut') }} {{ dateFormat('', '', sslInfo.timeout) }}
|
||||
</el-tag>
|
||||
<div>
|
||||
<el-button link type="primary" @click="handleSSL">
|
||||
|
@ -194,6 +194,7 @@ import TimeoutSetting from '@/views/setting/safe/timeout/index.vue';
|
|||
import EntranceSetting from '@/views/setting/safe/entrance/index.vue';
|
||||
import DomainSetting from '@/views/setting/safe/domain/index.vue';
|
||||
import AllowIPsSetting from '@/views/setting/safe/allowips/index.vue';
|
||||
import { dateFormat } from '@/utils/util';
|
||||
import { updateSetting, getSettingInfo, getSystemAvailable, updateSSL, loadSSLInfo } from '@/api/modules/setting';
|
||||
import i18n from '@/lang';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
|
@ -224,6 +225,7 @@ const form = reactive({
|
|||
bindAddress: '',
|
||||
ssl: 'disable',
|
||||
sslType: 'self',
|
||||
autoRestart: 'disable',
|
||||
securityEntrance: '',
|
||||
expirationDays: 0,
|
||||
expirationTime: '',
|
||||
|
@ -248,6 +250,7 @@ const search = async () => {
|
|||
if (form.ssl === 'enable') {
|
||||
loadInfo();
|
||||
}
|
||||
form.autoRestart = res.data.autoRestart;
|
||||
form.securityEntrance = res.data.securityEntrance;
|
||||
form.expirationDays = Number(res.data.expirationDays);
|
||||
form.expirationTime = res.data.expirationTime;
|
||||
|
@ -327,6 +330,7 @@ const handleSSL = async () => {
|
|||
ssl: form.ssl,
|
||||
sslType: form.sslType,
|
||||
sslInfo: sslInfo.value,
|
||||
autoRestart: form.autoRestart,
|
||||
};
|
||||
sslRef.value!.acceptParams(params);
|
||||
return;
|
||||
|
|
|
@ -11,13 +11,6 @@
|
|||
<template #header>
|
||||
<DrawerHeader :header="$t('setting.panelSSL')" :back="handleClose" />
|
||||
</template>
|
||||
<el-alert class="common-prompt" :closable="false" type="error">
|
||||
<template #default>
|
||||
<span>
|
||||
<span>{{ $t('setting.panelSSLHelper') }}</span>
|
||||
</span>
|
||||
</template>
|
||||
</el-alert>
|
||||
<el-form ref="formRef" label-position="top" :model="form" :rules="rules" v-loading="loading">
|
||||
<el-row type="flex" justify="center">
|
||||
<el-col :span="22">
|
||||
|
@ -40,7 +33,9 @@
|
|||
|
||||
<el-form-item v-if="form.timeout">
|
||||
<el-tag>{{ $t('setting.domainOrIP') }} {{ form.domain }}</el-tag>
|
||||
<el-tag style="margin-left: 5px">{{ $t('setting.timeOut') }} {{ form.timeout }}</el-tag>
|
||||
<el-tag style="margin-left: 5px">
|
||||
{{ $t('setting.timeOut') }} {{ dateFormat('', '', form.timeout) }}
|
||||
</el-tag>
|
||||
<el-button
|
||||
@click="onDownload"
|
||||
style="margin-left: 5px"
|
||||
|
@ -117,6 +112,14 @@
|
|||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
<el-form-item v-if="form.sslType !== 'import'">
|
||||
<el-checkbox true-value="enable" false-value="disable" v-model="form.autoRestart">
|
||||
{{ $t('setting.sslAutoRestart') }}
|
||||
</el-checkbox>
|
||||
<span v-if="form.autoRestart === 'disable'" class="input-help">
|
||||
{{ $t('setting.sslChangeHelper1') }}
|
||||
</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
|
@ -133,7 +136,7 @@
|
|||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { Website } from '@/api/interface/website';
|
||||
import { dateFormatSimple, getProvider } from '@/utils/util';
|
||||
import { dateFormatSimple, dateFormat, getProvider } from '@/utils/util';
|
||||
import { ListSSL } from '@/api/modules/website';
|
||||
import { reactive, ref } from 'vue';
|
||||
import i18n from '@/lang';
|
||||
|
@ -159,6 +162,7 @@ const form = reactive({
|
|||
key: '',
|
||||
rootPath: '',
|
||||
timeout: '',
|
||||
autoRestart: 'disable',
|
||||
});
|
||||
|
||||
const rules = reactive({
|
||||
|
@ -175,6 +179,7 @@ const itemSSL = ref();
|
|||
interface DialogProps {
|
||||
sslType: string;
|
||||
sslInfo?: Setting.SSLInfo;
|
||||
autoRestart: string;
|
||||
}
|
||||
const acceptParams = async (params: DialogProps): Promise<void> => {
|
||||
if (params.sslType.indexOf('-') !== -1) {
|
||||
|
@ -197,6 +202,7 @@ const acceptParams = async (params: DialogProps): Promise<void> => {
|
|||
} else {
|
||||
loadSSLs();
|
||||
}
|
||||
form.autoRestart = params.autoRestart;
|
||||
drawerVisible.value = true;
|
||||
};
|
||||
const emit = defineEmits<{ (e: 'search'): void }>();
|
||||
|
@ -237,7 +243,10 @@ const onSaveSSL = async (formEl: FormInstance | undefined) => {
|
|||
if (!formEl) return;
|
||||
formEl.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
ElMessageBox.confirm(i18n.global.t('setting.sslChangeHelper'), 'https', {
|
||||
let msg = !form.autoRestart
|
||||
? i18n.global.t('setting.sslChangeHelper1') + '\n\n\n' + 'qwdqwdqwd'
|
||||
: i18n.global.t('setting.sslChangeHelper2');
|
||||
ElMessageBox.confirm(msg, i18n.global.t('setting.panelSSL'), {
|
||||
confirmButtonText: i18n.global.t('commons.button.confirm'),
|
||||
cancelButtonText: i18n.global.t('commons.button.cancel'),
|
||||
type: 'info',
|
||||
|
@ -253,6 +262,7 @@ const onSaveSSL = async (formEl: FormInstance | undefined) => {
|
|||
sslID: form.sslID,
|
||||
cert: form.cert,
|
||||
key: form.key,
|
||||
autoRestart: form.autoRestart,
|
||||
};
|
||||
let href = window.location.href;
|
||||
param.domain = href.split('//')[1].split(':')[0];
|
||||
|
|
|
@ -92,6 +92,10 @@ let timer: NodeJS.Timer | null = null;
|
|||
|
||||
const em = defineEmits(['search']);
|
||||
|
||||
watch(open, (val) => {
|
||||
if (screenfull.isEnabled && !val && !mobile.value) screenfull.exit();
|
||||
});
|
||||
|
||||
const mobile = computed(() => {
|
||||
return globalStore.isMobile();
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue