2
0
mirror of https://github.com/acepanel/panel.git synced 2026-02-04 10:17:17 +08:00

fix: 使用短期证书配置

This commit is contained in:
2026-01-08 19:28:06 +08:00
parent 5e3ec29076
commit 2099d2ca57
6 changed files with 63 additions and 11 deletions

View File

@@ -241,7 +241,7 @@ func (r *certRepo) ObtainPanel(account *biz.CertAccount, ips []string) ([]byte,
} }
client.UsePanel(ips, filepath.Join(app.Root, "server/nginx/conf/acme.conf")) client.UsePanel(ips, filepath.Join(app.Root, "server/nginx/conf/acme.conf"))
ssl, err := client.ObtainCertificate(context.Background(), ips, acme.KeyEC256) ssl, err := client.ObtainShortCertificate(context.Background(), ips, acme.KeyEC256)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }

View File

@@ -15,7 +15,7 @@ func MustInstall(t *gotext.Locale, app biz.AppRepo) func(next http.Handler) http
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var slugs []string var slugs []string
if strings.HasPrefix(r.URL.Path, "/api/website") { if strings.HasPrefix(r.URL.Path, "/api/website") {
slugs = append(slugs, "nginx") slugs = append(slugs, "nginx", "openresty", "apache", "openlitespeed", "caddy")
} else if strings.HasPrefix(r.URL.Path, "/api/container") { } else if strings.HasPrefix(r.URL.Path, "/api/container") {
slugs = append(slugs, "podman", "docker") slugs = append(slugs, "podman", "docker")
} else if strings.HasPrefix(r.URL.Path, "/api/apps/") { } else if strings.HasPrefix(r.URL.Path, "/api/apps/") {

View File

@@ -73,7 +73,7 @@ func (c *Client) UsePanel(ip []string, conf string) {
} }
// ObtainCertificate 签发 SSL 证书 // ObtainCertificate 签发 SSL 证书
func (c *Client) ObtainCertificate(ctx context.Context, domains []string, keyType KeyType) (Certificate, error) { func (c *Client) ObtainCertificate(ctx context.Context, sans []string, keyType KeyType) (Certificate, error) {
certPrivateKey, err := generatePrivateKey(keyType) certPrivateKey, err := generatePrivateKey(keyType)
if err != nil { if err != nil {
return Certificate{}, err return Certificate{}, err
@@ -83,7 +83,38 @@ func (c *Client) ObtainCertificate(ctx context.Context, domains []string, keyTyp
return Certificate{}, err return Certificate{}, err
} }
certs, err := c.zClient.ObtainCertificateForSANs(ctx, c.Account, certPrivateKey, domains) certs, err := c.zClient.ObtainCertificateForSANs(ctx, c.Account, certPrivateKey, sans)
if err != nil {
return Certificate{}, err
}
crt := c.selectPreferredChain(certs)
return Certificate{PrivateKey: pemPrivateKey, Certificate: crt}, nil
}
// ObtainShortCertificate 签发短期 SSL 证书
func (c *Client) ObtainShortCertificate(ctx context.Context, sans []string, keyType KeyType) (Certificate, error) {
certPrivateKey, err := generatePrivateKey(keyType)
if err != nil {
return Certificate{}, err
}
pemPrivateKey, err := cert.EncodeKey(certPrivateKey)
if err != nil {
return Certificate{}, err
}
csr, err := acmez.NewCSR(certPrivateKey, sans)
if err != nil {
return Certificate{}, err
}
params, err := acmez.OrderParametersFromCSR(c.Account, csr)
if err != nil {
return Certificate{}, err
}
params.Profile = "shortlived"
certs, err := c.zClient.ObtainCertificate(ctx, params)
if err != nil { if err != nil {
return Certificate{}, err return Certificate{}, err
} }

View File

@@ -29,12 +29,14 @@ export function createAppInstallGuard(router: Router) {
// 网站 // 网站
if (to.path.startsWith('/website')) { if (to.path.startsWith('/website')) {
await useRequest(app.isInstalled('nginx')).onSuccess(({ data }) => { await useRequest(app.isInstalled('nginx,openresty,apache,openlitespeed,caddy')).onSuccess(
if (!data) { ({ data }) => {
showErrorMessage(`Web 服务器未安装`) if (!data) {
return router.push({ name: 'app-index' }) showErrorMessage(`Web 服务器未安装`)
return router.push({ name: 'app-index' })
}
} }
}) )
} }
// 容器 // 容器

View File

@@ -35,6 +35,7 @@ const { data: model } = useRequest(setting.list, {
website_path: '', website_path: '',
backup_path: '', backup_path: '',
https: false, https: false,
acme: false,
cert: '', cert: '',
key: '' key: ''
} }

View File

@@ -189,14 +189,32 @@ const model = defineModel<any>('model', { type: Object, required: true })
</template> </template>
<n-switch v-model:value="model.https" /> <n-switch v-model:value="model.https" />
</n-form-item> </n-form-item>
<n-form-item v-if="model.https" :label="$gettext('Certificate')"> <n-form-item>
<template #label>
<n-tooltip>
<template #trigger>
<div class="flex items-center">
{{ $gettext('ACME') }}
<the-icon :size="16" icon="mdi:help-circle-outline" class="ml-1" />
</div>
</template>
{{
$gettext(
'Use ACME protocol to automatically obtain and renew SSL certificates for the panel. Make sure your panel is accessible via the ip you provide'
)
}}
</n-tooltip>
</template>
<n-switch v-model:value="model.acme" />
</n-form-item>
<n-form-item v-if="model.https && !model.acme" :label="$gettext('Certificate')">
<n-input <n-input
v-model:value="model.cert" v-model:value="model.cert"
type="textarea" type="textarea"
:autosize="{ minRows: 10, maxRows: 15 }" :autosize="{ minRows: 10, maxRows: 15 }"
/> />
</n-form-item> </n-form-item>
<n-form-item v-if="model.https" :label="$gettext('Private Key')"> <n-form-item v-if="model.https && !model.acme" :label="$gettext('Private Key')">
<n-input <n-input
v-model:value="model.key" v-model:value="model.key"
type="textarea" type="textarea"