mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-02-07 17:10:07 +08:00
feat: 增加自动续签设置
This commit is contained in:
parent
c7529469f8
commit
75756e8bb7
@ -12,6 +12,7 @@ type WebsiteSSLCreate struct {
|
|||||||
Provider string `json:"provider" validate:"required"`
|
Provider string `json:"provider" validate:"required"`
|
||||||
AcmeAccountID uint `json:"acmeAccountId" validate:"required"`
|
AcmeAccountID uint `json:"acmeAccountId" validate:"required"`
|
||||||
DnsAccountID uint `json:"dnsAccountId"`
|
DnsAccountID uint `json:"dnsAccountId"`
|
||||||
|
AutoRenew bool `json:"autoRenew" validate:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type WebsiteDNSReq struct {
|
type WebsiteDNSReq struct {
|
||||||
|
@ -4,19 +4,21 @@ import "time"
|
|||||||
|
|
||||||
type WebsiteSSL struct {
|
type WebsiteSSL struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
PrimaryDomain string `gorm:"type:varchar(256);not null" json:"primaryDomain"`
|
PrimaryDomain string `gorm:"type:varchar(256);not null" json:"primaryDomain"`
|
||||||
PrivateKey string `gorm:"type:longtext;not null" json:"privateKey"`
|
PrivateKey string `gorm:"type:longtext;not null" json:"privateKey"`
|
||||||
Pem string `gorm:"type:longtext;not null" json:"pem"`
|
Pem string `gorm:"type:longtext;not null" json:"pem"`
|
||||||
Domains string `gorm:"type:varchar(256);not null" json:"domains"`
|
Domains string `gorm:"type:varchar(256);not null" json:"domains"`
|
||||||
CertURL string `gorm:"type:varchar(256);not null" json:"certURL"`
|
CertURL string `gorm:"type:varchar(256);not null" json:"certURL"`
|
||||||
Type string `gorm:"type:varchar(64);not null" json:"type"`
|
Type string `gorm:"type:varchar(64);not null" json:"type"`
|
||||||
Provider string `gorm:"type:varchar(64);not null" json:"provider"`
|
Provider string `gorm:"type:varchar(64);not null" json:"provider"`
|
||||||
Organization string `gorm:"type:varchar(64);not null" json:"organization"`
|
Organization string `gorm:"type:varchar(64);not null" json:"organization"`
|
||||||
DnsAccountID uint `gorm:"type:integer;not null" json:"dnsAccountId"`
|
DnsAccountID uint `gorm:"type:integer;not null" json:"dnsAccountId"`
|
||||||
AcmeAccountID uint `gorm:"type:integer;not null" json:"acmeAccountId"`
|
AcmeAccountID uint `gorm:"type:integer;not null" json:"acmeAccountId"`
|
||||||
AcmeAccount WebsiteAcmeAccount `json:"acmeAccount"`
|
AutoRenew bool `gorm:"type:varchar(64);not null" json:"autoRenew"`
|
||||||
ExpireDate time.Time `json:"expireDate"`
|
ExpireDate time.Time `json:"expireDate"`
|
||||||
StartDate time.Time `json:"startDate"`
|
StartDate time.Time `json:"startDate"`
|
||||||
|
|
||||||
|
AcmeAccount WebsiteAcmeAccount `json:"acmeAccount"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w WebsiteSSL) TableName() string {
|
func (w WebsiteSSL) TableName() string {
|
||||||
|
@ -205,7 +205,6 @@ func nginxCheckAndReload(oldContent string, filePath string, containerName strin
|
|||||||
_ = files.NewFileOp().WriteFile(filePath, strings.NewReader(oldContent), 0644)
|
_ = files.NewFileOp().WriteFile(filePath, strings.NewReader(oldContent), 0644)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := opNginx(containerName, constant.NginxReload); err != nil {
|
if err := opNginx(containerName, constant.NginxReload); err != nil {
|
||||||
_ = files.NewFileOp().WriteFile(filePath, strings.NewReader(oldContent), 0644)
|
_ = files.NewFileOp().WriteFile(filePath, strings.NewReader(oldContent), 0644)
|
||||||
return err
|
return err
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/global"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/ssl"
|
"github.com/1Panel-dev/1Panel/backend/utils/ssl"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
@ -17,6 +18,21 @@ import (
|
|||||||
type WebsiteSSLService struct {
|
type WebsiteSSLService struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type IWebsiteSSLService interface {
|
||||||
|
Page(search request.WebsiteSSLSearch) (int64, []response.WebsiteSSLDTO, error)
|
||||||
|
GetSSL(id uint) (*response.WebsiteSSLDTO, error)
|
||||||
|
Search() ([]response.WebsiteSSLDTO, error)
|
||||||
|
Create(create request.WebsiteSSLCreate) (request.WebsiteSSLCreate, error)
|
||||||
|
Renew(sslId uint) error
|
||||||
|
GetDNSResolve(req request.WebsiteDNSReq) ([]response.WebsiteDNSRes, error)
|
||||||
|
GetWebsiteSSL(websiteId uint) (response.WebsiteSSLDTO, error)
|
||||||
|
Delete(id uint) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIWebsiteSSLService() IWebsiteSSLService {
|
||||||
|
return &WebsiteSSLService{}
|
||||||
|
}
|
||||||
|
|
||||||
func (w WebsiteSSLService) Page(search request.WebsiteSSLSearch) (int64, []response.WebsiteSSLDTO, error) {
|
func (w WebsiteSSLService) Page(search request.WebsiteSSLSearch) (int64, []response.WebsiteSSLDTO, error) {
|
||||||
total, sslList, err := websiteSSLRepo.Page(search.Page, search.PageSize, commonRepo.WithOrderBy("created_at desc"))
|
total, sslList, err := websiteSSLRepo.Page(search.Page, search.PageSize, commonRepo.WithOrderBy("created_at desc"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -151,8 +167,6 @@ func (w WebsiteSSLService) Renew(sslId uint) error {
|
|||||||
if err := client.UseHTTP(path.Join(constant.AppInstallDir, constant.AppNginx, appInstall.Name, "root")); err != nil {
|
if err := client.UseHTTP(path.Join(constant.AppInstallDir, constant.AppNginx, appInstall.Name, "root")); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case constant.DnsManual:
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resource, err := client.RenewSSL(websiteSSL.CertURL)
|
resource, err := client.RenewSSL(websiteSSL.CertURL)
|
||||||
@ -172,7 +186,26 @@ func (w WebsiteSSLService) Renew(sslId uint) error {
|
|||||||
websiteSSL.Type = cert.Issuer.CommonName
|
websiteSSL.Type = cert.Issuer.CommonName
|
||||||
websiteSSL.Organization = cert.Issuer.Organization[0]
|
websiteSSL.Organization = cert.Issuer.Organization[0]
|
||||||
|
|
||||||
return websiteSSLRepo.Save(websiteSSL)
|
if err := websiteSSLRepo.Save(websiteSSL); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
websites, _ := websiteRepo.GetBy(websiteRepo.WithWebsiteSSLID(sslId))
|
||||||
|
for _, website := range websites {
|
||||||
|
if err := createPemFile(website, websiteSSL); err != nil {
|
||||||
|
global.LOG.Errorf("create website [%s] ssl file failed! err:%s", website.PrimaryDomain, err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(websites) > 0 {
|
||||||
|
nginxInstall, err := getAppInstallByKey(constant.AppNginx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := opNginx(nginxInstall.ContainerName, constant.NginxReload); err != nil {
|
||||||
|
return buserr.New(constant.ErrSSLApply)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w WebsiteSSLService) GetDNSResolve(req request.WebsiteDNSReq) ([]response.WebsiteDNSRes, error) {
|
func (w WebsiteSSLService) GetDNSResolve(req request.WebsiteDNSReq) ([]response.WebsiteDNSRes, error) {
|
||||||
|
@ -66,4 +66,5 @@ var (
|
|||||||
var (
|
var (
|
||||||
ErrSSLCannotDelete = "ErrSSLCannotDelete"
|
ErrSSLCannotDelete = "ErrSSLCannotDelete"
|
||||||
ErrAccountCannotDelete = "ErrAccountCannotDelete"
|
ErrAccountCannotDelete = "ErrAccountCannotDelete"
|
||||||
|
ErrSSLApply = "ErrSSLApply"
|
||||||
)
|
)
|
||||||
|
@ -22,6 +22,10 @@ func Run() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
global.LOG.Errorf("can not add website corn job: %s", err.Error())
|
global.LOG.Errorf("can not add website corn job: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
_, err = Cron.AddJob("@daily", job.NewSSLJob())
|
||||||
|
if err != nil {
|
||||||
|
global.LOG.Errorf("can not add ssl corn job: %s", err.Error())
|
||||||
|
}
|
||||||
Cron.Start()
|
Cron.Start()
|
||||||
|
|
||||||
global.Cron = Cron
|
global.Cron = Cron
|
||||||
|
36
backend/cron/job/ssl.go
Normal file
36
backend/cron/job/ssl.go
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package job
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/repo"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/service"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/global"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ssl struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSSLJob() *ssl {
|
||||||
|
return &ssl{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ssl *ssl) Run() {
|
||||||
|
sslRepo := repo.NewISSLRepo()
|
||||||
|
sslService := service.NewIWebsiteSSLService()
|
||||||
|
sslList, _ := sslRepo.List()
|
||||||
|
global.LOG.Info("ssl renew cron job start...")
|
||||||
|
now := time.Now()
|
||||||
|
for _, s := range sslList {
|
||||||
|
if !s.AutoRenew || s.Provider == "manual" || s.Provider == "dnsManual" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
sum := s.ExpireDate.Sub(now)
|
||||||
|
if sum.Hours() < 168 {
|
||||||
|
if err := sslService.Renew(s.ID); err != nil {
|
||||||
|
global.LOG.Errorf("renew doamin [%s] ssl failed err:%s", s.PrimaryDomain, err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
global.LOG.Info("ssl renew cron job end...")
|
||||||
|
}
|
@ -18,7 +18,7 @@ func NewWebsiteJob() *website {
|
|||||||
|
|
||||||
func (w *website) Run() {
|
func (w *website) Run() {
|
||||||
websites, _ := repo.NewIWebsiteRepo().List()
|
websites, _ := repo.NewIWebsiteRepo().List()
|
||||||
global.LOG.Info("website cron job start....")
|
global.LOG.Info("website cron job start...")
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
if len(websites) > 0 {
|
if len(websites) > 0 {
|
||||||
neverExpireDate, _ := time.Parse(constant.DateLayout, constant.DefaultDate)
|
neverExpireDate, _ := time.Parse(constant.DateLayout, constant.DefaultDate)
|
||||||
@ -36,7 +36,7 @@ func (w *website) Run() {
|
|||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
}
|
}
|
||||||
global.LOG.Info("website cron job end")
|
global.LOG.Info("website cron job end...")
|
||||||
}
|
}
|
||||||
|
|
||||||
func stopWebsite(websiteId uint, wg *sync.WaitGroup) {
|
func stopWebsite(websiteId uint, wg *sync.WaitGroup) {
|
||||||
|
@ -34,4 +34,5 @@ ErrAppDelete: 'Other Website use this App'
|
|||||||
|
|
||||||
#ssl
|
#ssl
|
||||||
ErrSSLCannotDelete: "The certificate is being used by the website and cannot be removed"
|
ErrSSLCannotDelete: "The certificate is being used by the website and cannot be removed"
|
||||||
ErrAccountCannotDelete: "The certificate associated with the account cannot be deleted"
|
ErrAccountCannotDelete: "The certificate associated with the account cannot be deleted"
|
||||||
|
ErrSSLApply: "The certificate continues to be signed successfully, but openresty reload fails, please check the configuration!"
|
@ -33,4 +33,5 @@ ErrAppDelete: '其他网站使用此应用,不能删除'
|
|||||||
|
|
||||||
#ssl
|
#ssl
|
||||||
ErrSSLCannotDelete: "证书正在被网站使用,无法删除"
|
ErrSSLCannotDelete: "证书正在被网站使用,无法删除"
|
||||||
ErrAccountCannotDelete: "账号关联证书,无法删除"
|
ErrAccountCannotDelete: "账号关联证书,无法删除"
|
||||||
|
ErrSSLApply: "证书续签成功,openresty reload失败,请检查配置!"
|
@ -12,6 +12,7 @@ export namespace Website {
|
|||||||
webSiteGroupId: number;
|
webSiteGroupId: number;
|
||||||
otherDomains: string;
|
otherDomains: string;
|
||||||
defaultServer: boolean;
|
defaultServer: boolean;
|
||||||
|
autoRenew: boolean;
|
||||||
appinstall?: NewAppInstall;
|
appinstall?: NewAppInstall;
|
||||||
webSiteSSL: SSL;
|
webSiteSSL: SSL;
|
||||||
}
|
}
|
||||||
|
@ -999,6 +999,9 @@ export default {
|
|||||||
startDate: '生效时间',
|
startDate: '生效时间',
|
||||||
organization: '签发机构',
|
organization: '签发机构',
|
||||||
renewConfirm: '是否确定续签?',
|
renewConfirm: '是否确定续签?',
|
||||||
|
autoRenew: '自动续签',
|
||||||
|
autoRenewHelper: '距离到期时间7天自动续签',
|
||||||
|
renewSuccess: '续签成功',
|
||||||
},
|
},
|
||||||
firewall: {
|
firewall: {
|
||||||
ccDeny: 'CC 防护',
|
ccDeny: 'CC 防护',
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
:title="$t('commons.button.create')"
|
:title="$t('commons.button.create')"
|
||||||
:destroy-on-close="true"
|
:destroy-on-close="true"
|
||||||
:close-on-click-modal="false"
|
:close-on-click-modal="false"
|
||||||
width="60%"
|
width="50%"
|
||||||
:before-close="handleClose"
|
:before-close="handleClose"
|
||||||
>
|
>
|
||||||
<el-form
|
<el-form
|
||||||
@ -66,6 +66,9 @@
|
|||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('ssl.autoRenew')" prop="autoRenew" v-if="ssl.provider !== 'dnsManual'">
|
||||||
|
<el-checkbox v-model="ssl.autoRenew" />
|
||||||
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<span class="dialog-footer">
|
<span class="dialog-footer">
|
||||||
@ -115,6 +118,7 @@ let rules = ref({
|
|||||||
acmeAccountId: [Rules.requiredSelectBusiness],
|
acmeAccountId: [Rules.requiredSelectBusiness],
|
||||||
dnsAccountId: [Rules.requiredSelectBusiness],
|
dnsAccountId: [Rules.requiredSelectBusiness],
|
||||||
provider: [Rules.requiredInput],
|
provider: [Rules.requiredInput],
|
||||||
|
autoRenew: [Rules.requiredInput],
|
||||||
});
|
});
|
||||||
let ssl = ref({
|
let ssl = ref({
|
||||||
primaryDomain: '',
|
primaryDomain: '',
|
||||||
@ -123,6 +127,7 @@ let ssl = ref({
|
|||||||
websiteId: 0,
|
websiteId: 0,
|
||||||
acmeAccountId: undefined,
|
acmeAccountId: undefined,
|
||||||
dnsAccountId: undefined,
|
dnsAccountId: undefined,
|
||||||
|
autoRenew: false,
|
||||||
});
|
});
|
||||||
let dnsResolve = ref<Website.DNSResolve[]>([]);
|
let dnsResolve = ref<Website.DNSResolve[]>([]);
|
||||||
let hasResolve = ref(false);
|
let hasResolve = ref(false);
|
||||||
@ -143,6 +148,7 @@ const resetForm = () => {
|
|||||||
websiteId: 0,
|
websiteId: 0,
|
||||||
acmeAccountId: undefined,
|
acmeAccountId: undefined,
|
||||||
dnsAccountId: undefined,
|
dnsAccountId: undefined,
|
||||||
|
autoRenew: false,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ const submit = () => {
|
|||||||
RenewSSL(renewReq)
|
RenewSSL(renewReq)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
handleClose();
|
handleClose();
|
||||||
ElMessage.success(i18n.global.t('commons.msg.renewSuccess'));
|
ElMessage.success(i18n.global.t('ssl.renewSuccess'));
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user