perf: 调整全部静态资源到static目录

pull/213/head
xiaojunnuo 2024-10-03 23:11:50 +08:00
parent a4e2cc54e6
commit a21889080d
58 changed files with 104 additions and 148 deletions

View File

@ -29,11 +29,11 @@ https://certd.handsfree.work/
## 三、使用教程
本案例演示如何配置自动申请证书并部署到阿里云CDN然后快要到期前自动更新证书并重新部署
![演示](./packages/ui/certd-client/public/doc/images/5-view.png)
![演示](./packages/ui/certd-client/public/doc/images/9-start.png)
![演示](./packages/ui/certd-client/public/doc/images/10-1-log.png)
![演示](./packages/ui/certd-client/public/doc/images/13-3-download.png)
![演示](./packages/ui/certd-client/public/doc/images/13-1-result.png)
![演示](./packages/ui/certd-client/src/assets/doc/images/5-view.png)
![演示](./packages/ui/certd-client/src/assets/doc/images/9-start.png)
![演示](./packages/ui/certd-client/src/assets/doc/images/10-1-log.png)
![演示](./packages/ui/certd-client/src/assets/doc/images/13-3-download.png)
![演示](./packages/ui/certd-client/src/assets/doc/images/13-1-result.png)
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
-------> [点我查看详细使用步骤演示](./step.md) <--------

View File

@ -1,5 +1,5 @@
import { logger } from "../utils/index.js";
import { setLogger, isPlus } from "@certd/plus-core";
import { setLogger, isPlus, isComm } from "@certd/plus-core";
setLogger(logger);
export * from "@certd/plus-core";
@ -8,3 +8,9 @@ export function checkPlus() {
throw new Error("此为专业版功能,请升级到专业版");
}
}
export function checkComm() {
if (!isComm()) {
throw new Error("此为商业版功能,请升级到商业版");
}
}

View File

@ -1 +1,2 @@
export * from './settings/index.js';
export * from './plus/index.js';

View File

@ -0,0 +1 @@
export * from './service/plus-service.js';

View File

@ -1,8 +1,7 @@
import { Config, Init, Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
import { SysSettingsService } from '@certd/lib-server';
import { SysInstallInfo, SysLicenseInfo } from '@certd/lib-server';
import { AppKey, http, PlusRequestService, verify } from '@certd/pipeline';
import { logger } from '@certd/pipeline';
import { SysInstallInfo, SysLicenseInfo, SysSettingsService } from '../../settings/index.js';
@Provide()
@Scope(ScopeEnum.Singleton)

View File

@ -14,6 +14,7 @@ export class SysPublicSettings extends BaseSettings {
static __access__ = 'public';
registerEnabled = false;
managerOtherUserPipeline = false;
icpNo?: string;
// triggerOnStartup = false;
}
@ -48,8 +49,7 @@ export class SysSiteInfo extends BaseSettings {
static __title__ = '站点信息';
static __key__ = 'sys.site';
static __access__ = 'public';
TITLE?: string;
SLOGAN?: string;
LOGO?: string;
ICP_NO?: string;
title?: string;
slogan?: string;
logo?: string;
}

View File

@ -6,6 +6,6 @@ VITE_APP_SLOGAN=让你的证书永不过期
VITE_APP_COPYRIGHT_YEAR=2021-2024
VITE_APP_COPYRIGHT_NAME=handsfree.work
VITE_APP_COPYRIGHT_URL=https://certd.handsfree.work
VITE_APP_LOGO=./images/logo/logo.svg
VITE_APP_LOGO=./assets/images/logo/logo.svg
VITE_APP_PROJECT_PATH=https://github.com/certd/certd

View File

@ -5,7 +5,7 @@
<link rel="icon" href="/logo.svg"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Certd-让你的证书永不过期</title>
<script src="/icons/iconfont.js"></script>
<script src="/assets/icons/iconfont.js"></script>
<link rel="stylesheet" type="text/css" href="/index.css"/>
</head>
<body>

View File

@ -3,6 +3,7 @@ import { request } from "../service";
export type SysPublicSetting = {
registerEnabled: boolean;
managerOtherUserPipeline: boolean;
icpNo?: string;
};
export type SysInstallInfo = {

View File

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 68 KiB

View File

Before

Width:  |  Height:  |  Size: 124 KiB

After

Width:  |  Height:  |  Size: 124 KiB

View File

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

View File

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 67 KiB

View File

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View File

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 47 KiB

View File

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 82 KiB

View File

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

View File

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 43 KiB

View File

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 50 KiB

View File

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

View File

Before

Width:  |  Height:  |  Size: 145 KiB

After

Width:  |  Height:  |  Size: 145 KiB

View File

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View File

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

View File

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 50 KiB

View File

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 72 KiB

View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 61 KiB

View File

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 66 KiB

View File

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 76 KiB

View File

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 55 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View File

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 56 KiB

View File

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

View File

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View File

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

Before

Width:  |  Height:  |  Size: 397 B

After

Width:  |  Height:  |  Size: 397 B

View File

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

View File

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

View File

@ -43,27 +43,27 @@ const steps = ref<Step[]>([
description: "演示证书申请任务如何配置",
items: [
{
image: "/doc/images/1-add.png",
image: "/assets/doc/images/1-add.png",
title: "创建证书流水线",
descriptions: ["点击添加流水线,选择证书申请"]
},
{
image: "/doc/images/2-access-provider.png",
image: "/assets/doc/images/2-access-provider.png",
title: "DNS授权",
descriptions: ["证书申请需要给域名添加TXT解析记录来验证域名所有权"]
},
{
image: "/doc/images/3-add-access.png",
image: "/assets/doc/images/3-add-access.png",
title: "第一次使用需要添加DNS授权",
descriptions: ["选择DNS授权确认创建"]
},
// {
// image: "/doc/images/3-add-access.png",
// image: "/assets/doc/images/3-add-access.png",
// title: "线",
// descriptions: ["DNS"]
// },
{
image: "/doc/images/4-add-success.png",
image: "/assets/doc/images/4-add-success.png",
title: "流水线创建成功",
descriptions: ["此时证书申请任务已经建好,点击手动触发即可测试证书申请", "接下来演示如何添加部署任务"]
}
@ -74,52 +74,52 @@ const steps = ref<Step[]>([
description: "演示部署到阿里云CDN和Nginx",
items: [
{
image: "/doc/images/6-1-add-task.png",
image: "/assets/doc/images/6-1-add-task.png",
title: "添加部署任务",
descriptions: ["演示第一个部署任务部署到阿里云CDN"]
},
{
image: "/doc/images/6-2-add-task.png",
image: "/assets/doc/images/6-2-add-task.png",
title: "选择任务插件",
descriptions: ["可以搜索插件这里选择阿里云CDN插件"]
},
{
image: "/doc/images/6-3-add-task.png",
image: "/assets/doc/images/6-3-add-task.png",
title: "配置任务参数",
descriptions: ["填写CDN的域名和证书ID", "任务保存之后阿里云CDN的部署任务就配置好了"]
},
{
image: "/doc/images/7-1-add-host-task.png",
image: "/assets/doc/images/7-1-add-host-task.png",
title: "添加主机部署任务",
descriptions: ["接下来演示配置第二个部署任务,部署到主机", "部署到主机分两步: 1. 上传证书到主机 2. 运行主机命令"]
},
{
image: "/doc/images/7-2-add-host-task.png",
image: "/assets/doc/images/7-2-add-host-task.png",
title: "配置上传到主机任务",
descriptions: ["填写上传到主机任务参数", "比如证书保存路径"]
},
{
image: "/doc/images/7-3-add-host-task.png",
image: "/assets/doc/images/7-3-add-host-task.png",
title: "添加主机ssh登录授权",
descriptions: ["填写主机ip、用户名、密码授权只需添加一次后续其他任务可以复用"]
},
{
image: "/doc/images/8-1-add-host-task.png",
image: "/assets/doc/images/8-1-add-host-task.png",
title: "上传到主机任务配置完成",
descriptions: ["接下来配置主机执行脚本,去部署证书"]
},
{
image: "/doc/images/8-2-add-host-task.png",
image: "/assets/doc/images/8-2-add-host-task.png",
title: "选择添加主机远程命令任务",
descriptions: ["选择主机远程命令任务"]
},
{
image: "/doc/images/8-4-add-host-task.png",
image: "/assets/doc/images/8-4-add-host-task.png",
title: "填写证书部署脚本",
descriptions: ["选择主机授权编写部署脚本这里演示部署到nginx需要重启nginx让证书生效"]
},
{
image: "/doc/images/8-5-add-host-task.png",
image: "/assets/doc/images/8-5-add-host-task.png",
title: "上传到主机任务的两个步骤配置完成",
descriptions: ["接下来测试运行"]
}
@ -130,47 +130,47 @@ const steps = ref<Step[]>([
description: "演示流水线运行,查看日志,成功后跳过等",
items: [
{
image: "/doc/images/9-start.png",
image: "/assets/doc/images/9-start.png",
title: "运行测试一下",
descriptions: ["之前是把证书上传到主机,接下来要运行命令,去部署证书"]
},
{
image: "/doc/images/10-1-log.png",
image: "/assets/doc/images/10-1-log.png",
title: "查看日志",
descriptions: ["点击任务可以查看状态和日志"]
},
{
image: "/doc/images/11-1-error.png",
image: "/assets/doc/images/11-1-error.png",
title: "执行失败如何排查",
descriptions: ["查看错误日志"]
},
{
image: "/doc/images/11-2-error.png",
image: "/assets/doc/images/11-2-error.png",
title: "执行失败如何排查",
descriptions: ["查看错误日志,这里报的是nginx容器不存在修改命令改成正确的nginx容器名称"]
},
{
image: "/doc/images/12-1-log-success.png",
image: "/assets/doc/images/12-1-log-success.png",
title: "执行成功",
descriptions: ["修改正确后,重新点击手动触发,重新运行一次,执行成功"]
},
{
image: "/doc/images/12-2-skip-log.png",
image: "/assets/doc/images/12-2-skip-log.png",
title: "成功后自动跳过",
descriptions: ["可以看到成功过的将会自动跳过,不会重复执行,只有当参数变更或者证书更新了,才会重新运行"]
},
{
image: "/doc/images/13-1-result.png",
image: "/assets/doc/images/13-1-result.png",
title: "查看证书部署成功",
descriptions: ["访问nginx上的网站可以看到证书已经部署成功"]
},
{
image: "/doc/images/13-2-result.png",
image: "/assets/doc/images/13-2-result.png",
title: "阿里云CDN也部署成功",
descriptions: ["阿里云CDN上已经更新证书证书名称已certd开头"]
},
{
image: "/doc/images/13-3-download.png",
image: "/assets/doc/images/13-3-download.png",
title: "还可以下载证书,手动部署",
descriptions: ["如果还没有好用的部署插件,没办法自动部署,你还可以下载证书,手动部署"]
}
@ -181,7 +181,7 @@ const steps = ref<Step[]>([
description: "自动运行",
items: [
{
image: "/doc/images/14-timer.png",
image: "/assets/doc/images/14-timer.png",
title: "设置定时执行",
descriptions: [
"流水线测试成功,接下来配置定时触发,以后每天定时执行就不用管了",
@ -189,7 +189,7 @@ const steps = ref<Step[]>([
]
},
{
image: "/doc/images/15-1-email.png",
image: "/assets/doc/images/15-1-email.png",
title: "设置邮件通知",
descriptions: ["建议选择监听'错误时'和'错误转成功'两种即可,在意外失败时可以尽快去排查问题,(免费版需要配置邮件服务器)"]
}

View File

@ -2,7 +2,7 @@
<a-layout class="fs-framework">
<a-layout-sider v-model:collapsed="asideCollapsed" :trigger="null" collapsible>
<div class="header-logo">
<img src="/images/logo/logo.svg" />
<img src="/assets/images/logo/logo.svg" />
<span v-if="!asideCollapsed" class="title">Certd</span>
</div>
<div class="aside-menu">

View File

@ -4,7 +4,7 @@
<div class="user-layout-content">
<div class="top flex flex-col items-center justify-center">
<div class="header flex flex-row items-center">
<img src="/images/logo/rect-black.svg" class="logo" alt="logo" />
<img src="/assets/images/logo/rect-black.svg" class="logo" alt="logo" />
<span class="title"></span>
</div>
<div class="desc"></div>

View File

@ -32,10 +32,9 @@ export interface SettingState {
appKey?: string;
};
siteInfo?: {
TITLE: string;
SLOGAN: string;
LOGO: string;
ICP_NO: string;
title: string;
slogan: string;
logo: string;
};
}
@ -54,7 +53,8 @@ export const useSettingStore = defineStore({
},
sysPublic: {
registerEnabled: false,
managerOtherUserPipeline: false
managerOtherUserPipeline: false,
icpNo: ""
},
installInfo: {
siteId: "",
@ -64,10 +64,9 @@ export const useSettingStore = defineStore({
appKey: ""
},
siteInfo: {
TITLE: "",
SLOGAN: "",
LOGO: "",
ICP_NO: ""
title: "Certd",
slogan: "让你的证书永不过期",
logo: ""
}
}),
getters: {

View File

@ -18,7 +18,7 @@
</a-alert>
</div>
<div class="content">
<img src="/images/preview.png" class="preview_img" />
<img src="/assets/images/preview.png" class="preview_img" />
</div>
<div class="footer_box">
<div>如果觉得好用请不要吝啬你的star哟</div>

View File

@ -19,6 +19,9 @@
<a-form-item label="管理其他用户流水线" name="managerOtherUserPipeline">
<a-switch v-model:checked="formState.managerOtherUserPipeline" />
</a-form-item>
<a-form-item label="ICP备案号" name="icpNo">
<a-switch v-model:checked="formState.icpNo" />
</a-form-item>
<!-- <a-form-item label="启动后触发流水线" name="triggerOnStartup">-->
<!-- <a-switch v-model:checked="formState.triggerOnStartup" />-->
<!-- <div class="helper">启动后自动触发一次所有已启用的流水线</div>-->

View File

@ -1,9 +1,9 @@
<template>
<fs-page class="page-sys-settings">
<fs-page class="page-sys-site">
<template #header>
<div class="title">站点个性化设置</div>
</template>
<div class="sys-settings-form">
<div class="sys-site-form">
<a-form
:model="formState"
name="basic"
@ -13,16 +13,15 @@
@finish="onFinish"
@finish-failed="onFinishFailed"
>
<a-form-item label="开启自助注册" name="registerEnabled">
<a-switch v-model:checked="formState.registerEnabled" />
<a-form-item label="标题" name="title">
<a-input v-model:checked="formState.title" />
</a-form-item>
<a-form-item label="管理其他用户流水线" name="managerOtherUserPipeline">
<a-switch v-model:checked="formState.managerOtherUserPipeline" />
<a-form-item label="副标题" name="slogan">
<a-input v-model:value="formState.slogan" />
</a-form-item>
<a-form-item label="Logo" name="logo">
<fs-cropper-upload v-model:value="formState.logo" />
</a-form-item>
<!-- <a-form-item label="启动后触发流水线" name="triggerOnStartup">-->
<!-- <a-switch v-model:checked="formState.triggerOnStartup" />-->
<!-- <div class="helper">启动后自动触发一次所有已启用的流水线</div>-->
<!-- </a-form-item>-->
<a-form-item :wrapper-col="{ offset: 8, span: 16 }">
<a-button type="primary" html-type="submit">保存</a-button>
</a-form-item>
@ -46,7 +45,9 @@ import { useSettingStore } from "/src/store/modules/settings";
interface FormState {
title: string;
slogan: string;
logo: string;
icpNo: string;
}
const formState = reactive<Partial<FormState>>({
@ -83,8 +84,8 @@ async function stopOtherUserTimer() {
</script>
<style lang="less">
.page-sys-settings {
.sys-settings-form {
.page-sys-site {
.sys-site-form {
width: 500px;
margin: 20px;
}

View File

@ -5,7 +5,7 @@ import nodemailer from 'nodemailer';
import type SMTPConnection from 'nodemailer/lib/smtp-connection';
import { logger } from '@certd/pipeline';
import { UserSettingsService } from '../../mine/service/user-settings-service.js';
import { PlusService } from './plus-service.js';
import { PlusService } from '@certd/lib-server';
export type EmailConfig = {
host: string;

View File

@ -4,7 +4,7 @@ import { BaseController } from '@certd/lib-server';
import { AppKey } from '@certd/pipeline';
import { SysInstallInfo } from '@certd/lib-server';
import { logger } from '@certd/pipeline';
import { PlusService } from '../../basic/service/plus-service.js';
import { PlusService } from '@certd/lib-server';
/**
*/

View File

@ -1,55 +0,0 @@
import { ALL, Body, Controller, Inject, Post, Provide } from '@midwayjs/core';
import { SysSettingsService } from '@certd/lib-server';
import { BaseController } from '@certd/lib-server';
import { AppKey } from '@certd/pipeline';
import { SysInstallInfo } from '@certd/lib-server';
import { logger } from '@certd/pipeline';
import { PlusService } from '../../basic/service/plus-service.js';
/**
*/
@Provide()
@Controller('/api/sys/site')
export class SysPlusController extends BaseController {
@Inject()
sysSettingsService: SysSettingsService;
@Inject()
plusService: PlusService;
@Post('/active', { summary: 'sys:settings:edit' })
async active(@Body(ALL) body) {
const { code } = body;
const installInfo: SysInstallInfo = await this.sysSettingsService.getSetting(SysInstallInfo);
const siteId = installInfo.siteId;
const formData = {
appKey: AppKey,
code,
subjectId: siteId,
};
const res: any = await this.plusService.active(formData);
if (res.code > 0) {
logger.error('激活失败', res.message);
return this.fail(res.message, 1);
}
const license = res.data.license;
await this.plusService.updateLicense(license);
return this.ok(true);
}
@Post('/bindUrl', { summary: 'sys:settings:edit' })
async bindUrl(@Body(ALL) body: { url: string }) {
const { url } = body;
const installInfo: SysInstallInfo = await this.sysSettingsService.getSetting(SysInstallInfo);
await this.plusService.bindUrl(installInfo.siteId, url);
installInfo.bindUrl = url;
await this.sysSettingsService.saveSetting(installInfo);
return this.ok(true);
}
}

54
step.md
View File

@ -13,19 +13,19 @@
## 自动化流水线创建
### 1. 创建证书申请部署流水线
![创建证书申请任务](./packages/ui/certd-client/public/doc/images/1-add.png)
![创建证书申请任务](./packages/ui/certd-client/src/assets/doc/images/1-add.png)
需要添加域名的DNS解析服务商的授权
![添加域名的DNS解析服务商的授权](./packages/ui/certd-client/public/doc/images/2-access-provider.png)
![添加域名的DNS解析服务商的授权](./packages/ui/certd-client/src/assets/doc/images/2-access-provider.png)
填写accessKey和accessSecret
![](./packages/ui/certd-client/public/doc/images/3-add-access.png)
![](./packages/ui/certd-client/src/assets/doc/images/3-add-access.png)
流水线创建成功
![](./packages/ui/certd-client/public/doc/images/4-add-success.png)
![](./packages/ui/certd-client/src/assets/doc/images/4-add-success.png)
### 2. 任务详情界面
![](./packages/ui/certd-client/public/doc/images/5-view.png)
![](./packages/ui/certd-client/src/assets/doc/images/5-view.png)
到这一步申请证书就已经配置完成了。
点击手动触发,就可以申请证书了。
@ -34,72 +34,72 @@
### 3. 添加部署到阿里云CDN任务
点击添加任务
![](./packages/ui/certd-client/public/doc/images/6-1-add-task.png)
![](./packages/ui/certd-client/src/assets/doc/images/6-1-add-task.png)
选择任务类型
![](./packages/ui/certd-client/public/doc/images/6-2-add-task.png)
![](./packages/ui/certd-client/src/assets/doc/images/6-2-add-task.png)
填写任务参数
![](./packages/ui/certd-client/public/doc/images/6-3-add-task.png)
![](./packages/ui/certd-client/src/assets/doc/images/6-3-add-task.png)
点击确定部署到CDN任务配置成功
### 4. 添加部署到服务器主机任务
点击新任务,弹出添加任务界面
![](./packages/ui/certd-client/public/doc/images/7-1-add-host-task.png)
![](./packages/ui/certd-client/src/assets/doc/images/7-1-add-host-task.png)
先选择上传到主机任务
填写任务参数,比如证书保存路径
![](./packages/ui/certd-client/public/doc/images/7-2-add-host-task.png)
![](./packages/ui/certd-client/src/assets/doc/images/7-2-add-host-task.png)
需要添加主机ip、用户名、密码只需添加一次后续其他任务可以复用
![](./packages/ui/certd-client/public/doc/images/7-3-add-host-task.png)
![](./packages/ui/certd-client/src/assets/doc/images/7-3-add-host-task.png)
然后添加第二个任务,执行主机命令,部署证书
![](./packages/ui/certd-client/public/doc/images/8-1-add-host-task.png)
![](./packages/ui/certd-client/src/assets/doc/images/8-1-add-host-task.png)
选择执行脚本命令任务
![](./packages/ui/certd-client/public/doc/images/8-2-add-host-task.png)
![](./packages/ui/certd-client/src/assets/doc/images/8-2-add-host-task.png)
编写脚本,选择之前添加的主机
![](./packages/ui/certd-client/public/doc/images/8-4-add-host-task.png)
![](./packages/ui/certd-client/src/assets/doc/images/8-4-add-host-task.png)
点击确定,部署到主机任务配置成功
![](./packages/ui/certd-client/public/doc/images/8-5-add-host-task.png)
![](./packages/ui/certd-client/src/assets/doc/images/8-5-add-host-task.png)
### 5. 手动触发执行任务,测试一下
![](./packages/ui/certd-client/public/doc/images/9-start.png)
![](./packages/ui/certd-client/src/assets/doc/images/9-start.png)
点击任务可以查看状态和日志
![](./packages/ui/certd-client/public/doc/images/10-1-log.png)
![](./packages/ui/certd-client/src/assets/doc/images/10-1-log.png)
这里执行失败,可以查看错误日志
![](./packages/ui/certd-client/public/doc/images/11-1-error.png)
![](./packages/ui/certd-client/public/doc/images/11-2-error.png)
![](./packages/ui/certd-client/src/assets/doc/images/11-1-error.png)
![](./packages/ui/certd-client/src/assets/doc/images/11-2-error.png)
修改正确后,重新执行
![](./packages/ui/certd-client/public/doc/images/12-1-log-success.png)
![](./packages/ui/certd-client/src/assets/doc/images/12-1-log-success.png)
可以看到前面执行过的就会跳过,不会重复执行
![](./packages/ui/certd-client/public/doc/images/12-2-skip-log.png)
![](./packages/ui/certd-client/src/assets/doc/images/12-2-skip-log.png)
### 6. 查看证书部署效果
可以看到证书已经部署到CDN成功
![](./packages/ui/certd-client/public/doc/images/13-1-result.png)
![](./packages/ui/certd-client/public/doc/images/13-2-result.png)
![](./packages/ui/certd-client/src/assets/doc/images/13-1-result.png)
![](./packages/ui/certd-client/src/assets/doc/images/13-2-result.png)
也可以手动下载证书
![](./packages/ui/certd-client/public/doc/images/13-3-download.png)
![](./packages/ui/certd-client/src/assets/doc/images/13-3-download.png)
### 7. 定时触发
配置定时触发,以后每天定时执行
cron格式例如 `0 0 3 * * *` 表示每天凌晨3点执行
到期前20天会自动申请新证书并部署没到期前不会重复申请
![](./packages/ui/certd-client/public/doc/images/14-timer.png)
![](./packages/ui/certd-client/src/assets/doc/images/14-timer.png)
### 8. 邮件通知
可以接收邮件通知(支持时机:开始、成功、失败、失败转成功)
![](./packages/ui/certd-client/public/doc/images/15-1-email.png)
![](./packages/ui/certd-client/src/assets/doc/images/15-1-email.png)
需要配置邮件服务器
![](./packages/ui/certd-client/public/doc/images/15-2-email.png)
![](./packages/ui/certd-client/src/assets/doc/images/15-2-email.png)