mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
feat(domains): add custom certificate resolver support
- Extend domain configuration to support custom certificate resolvers - Add new "custom" certificate type option in domain forms - Update database schema and validation to include custom certificate resolver - Implement custom certificate resolver handling in Traefik and Docker domain configurations - Enhance domain management with more flexible SSL/TLS certificate options
This commit is contained in:
@@ -85,8 +85,20 @@ export const AddDomain = ({
|
|||||||
|
|
||||||
const form = useForm<Domain>({
|
const form = useForm<Domain>({
|
||||||
resolver: zodResolver(domain),
|
resolver: zodResolver(domain),
|
||||||
|
defaultValues: {
|
||||||
|
host: "",
|
||||||
|
path: undefined,
|
||||||
|
port: undefined,
|
||||||
|
https: false,
|
||||||
|
certificateType: undefined,
|
||||||
|
customCertResolver: undefined,
|
||||||
|
},
|
||||||
|
mode: "onChange",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const certificateType = form.watch("certificateType");
|
||||||
|
const https = form.watch("https");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (data) {
|
if (data) {
|
||||||
form.reset({
|
form.reset({
|
||||||
@@ -94,13 +106,29 @@ export const AddDomain = ({
|
|||||||
/* Convert null to undefined */
|
/* Convert null to undefined */
|
||||||
path: data?.path || undefined,
|
path: data?.path || undefined,
|
||||||
port: data?.port || undefined,
|
port: data?.port || undefined,
|
||||||
|
certificateType: data?.certificateType || undefined,
|
||||||
|
customCertResolver: data?.customCertResolver || undefined,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!domainId) {
|
if (!domainId) {
|
||||||
form.reset({});
|
form.reset({
|
||||||
|
host: "",
|
||||||
|
path: undefined,
|
||||||
|
port: undefined,
|
||||||
|
https: false,
|
||||||
|
certificateType: undefined,
|
||||||
|
customCertResolver: undefined,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}, [form, form.reset, data, isLoading]);
|
}, [form, data, isLoading, domainId]);
|
||||||
|
|
||||||
|
// Separate effect for handling custom cert resolver validation
|
||||||
|
useEffect(() => {
|
||||||
|
if (certificateType === "custom") {
|
||||||
|
form.trigger("customCertResolver");
|
||||||
|
}
|
||||||
|
}, [certificateType, form]);
|
||||||
|
|
||||||
const dictionary = {
|
const dictionary = {
|
||||||
success: domainId ? "Domain Updated" : "Domain Created",
|
success: domainId ? "Domain Updated" : "Domain Created",
|
||||||
@@ -256,34 +284,73 @@ export const AddDomain = ({
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{form.getValues().https && (
|
{https && (
|
||||||
<FormField
|
<>
|
||||||
control={form.control}
|
<FormField
|
||||||
name="certificateType"
|
control={form.control}
|
||||||
render={({ field }) => (
|
name="certificateType"
|
||||||
<FormItem className="col-span-2">
|
render={({ field }) => {
|
||||||
<FormLabel>Certificate Provider</FormLabel>
|
return (
|
||||||
<Select
|
<FormItem>
|
||||||
onValueChange={field.onChange}
|
<FormLabel>Certificate Provider</FormLabel>
|
||||||
defaultValue={field.value || ""}
|
<Select
|
||||||
>
|
onValueChange={(value) => {
|
||||||
<FormControl>
|
field.onChange(value);
|
||||||
<SelectTrigger>
|
if (value !== "custom") {
|
||||||
<SelectValue placeholder="Select a certificate provider" />
|
form.setValue(
|
||||||
</SelectTrigger>
|
"customCertResolver",
|
||||||
</FormControl>
|
undefined,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
value={field.value}
|
||||||
|
>
|
||||||
|
<FormControl>
|
||||||
|
<SelectTrigger>
|
||||||
|
<SelectValue placeholder="Select a certificate provider" />
|
||||||
|
</SelectTrigger>
|
||||||
|
</FormControl>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value={"none"}>None</SelectItem>
|
||||||
|
<SelectItem value={"letsencrypt"}>
|
||||||
|
Let's Encrypt
|
||||||
|
</SelectItem>
|
||||||
|
<SelectItem value={"custom"}>Custom</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
<SelectContent>
|
{certificateType === "custom" && (
|
||||||
<SelectItem value="none">None</SelectItem>
|
<FormField
|
||||||
<SelectItem value={"letsencrypt"}>
|
control={form.control}
|
||||||
Let's Encrypt
|
name="customCertResolver"
|
||||||
</SelectItem>
|
render={({ field }) => {
|
||||||
</SelectContent>
|
return (
|
||||||
</Select>
|
<FormItem>
|
||||||
<FormMessage />
|
<FormLabel>Custom Certificate Resolver</FormLabel>
|
||||||
</FormItem>
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
className="w-full"
|
||||||
|
placeholder="Enter your custom certificate resolver"
|
||||||
|
{...field}
|
||||||
|
value={field.value || ""}
|
||||||
|
onChange={(e) => {
|
||||||
|
field.onChange(e);
|
||||||
|
form.trigger("customCertResolver");
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -104,6 +104,15 @@ export const AddDomainCompose = ({
|
|||||||
|
|
||||||
const form = useForm<Domain>({
|
const form = useForm<Domain>({
|
||||||
resolver: zodResolver(domainCompose),
|
resolver: zodResolver(domainCompose),
|
||||||
|
defaultValues: {
|
||||||
|
host: "",
|
||||||
|
path: undefined,
|
||||||
|
port: undefined,
|
||||||
|
https: false,
|
||||||
|
certificateType: undefined,
|
||||||
|
customCertResolver: undefined,
|
||||||
|
serviceName: "",
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const https = form.watch("https");
|
const https = form.watch("https");
|
||||||
@@ -116,11 +125,21 @@ export const AddDomainCompose = ({
|
|||||||
path: data?.path || undefined,
|
path: data?.path || undefined,
|
||||||
port: data?.port || undefined,
|
port: data?.port || undefined,
|
||||||
serviceName: data?.serviceName || undefined,
|
serviceName: data?.serviceName || undefined,
|
||||||
|
certificateType: data?.certificateType || undefined,
|
||||||
|
customCertResolver: data?.customCertResolver || undefined,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!domainId) {
|
if (!domainId) {
|
||||||
form.reset({});
|
form.reset({
|
||||||
|
host: "",
|
||||||
|
path: undefined,
|
||||||
|
port: undefined,
|
||||||
|
https: false,
|
||||||
|
certificateType: undefined,
|
||||||
|
customCertResolver: undefined,
|
||||||
|
serviceName: "",
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}, [form, form.reset, data, isLoading]);
|
}, [form, form.reset, data, isLoading]);
|
||||||
|
|
||||||
@@ -393,33 +412,55 @@ export const AddDomainCompose = ({
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{https && (
|
{https && (
|
||||||
<FormField
|
<>
|
||||||
control={form.control}
|
<FormField
|
||||||
name="certificateType"
|
control={form.control}
|
||||||
render={({ field }) => (
|
name="certificateType"
|
||||||
<FormItem className="col-span-2">
|
render={({ field }) => (
|
||||||
<FormLabel>Certificate Provider</FormLabel>
|
<FormItem className="col-span-2">
|
||||||
<Select
|
<FormLabel>Certificate Provider</FormLabel>
|
||||||
onValueChange={field.onChange}
|
<Select
|
||||||
defaultValue={field.value || ""}
|
onValueChange={field.onChange}
|
||||||
>
|
defaultValue={field.value || ""}
|
||||||
<FormControl>
|
>
|
||||||
<SelectTrigger>
|
<FormControl>
|
||||||
<SelectValue placeholder="Select a certificate provider" />
|
<SelectTrigger>
|
||||||
</SelectTrigger>
|
<SelectValue placeholder="Select a certificate provider" />
|
||||||
</FormControl>
|
</SelectTrigger>
|
||||||
|
</FormControl>
|
||||||
|
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectItem value="none">None</SelectItem>
|
<SelectItem value="none">None</SelectItem>
|
||||||
<SelectItem value={"letsencrypt"}>
|
<SelectItem value={"letsencrypt"}>
|
||||||
Let's Encrypt
|
Let's Encrypt
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
</SelectContent>
|
<SelectItem value={"custom"}>Custom</SelectItem>
|
||||||
</Select>
|
</SelectContent>
|
||||||
<FormMessage />
|
</Select>
|
||||||
</FormItem>
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{form.getValues().certificateType === "custom" && (
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="customCertResolver"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem className="col-span-2">
|
||||||
|
<FormLabel>Custom Certificate Resolver</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
placeholder="Enter your custom certificate resolver"
|
||||||
|
{...field}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ const addServerDomain = z
|
|||||||
.object({
|
.object({
|
||||||
domain: z.string().min(1, { message: "URL is required" }),
|
domain: z.string().min(1, { message: "URL is required" }),
|
||||||
letsEncryptEmail: z.string(),
|
letsEncryptEmail: z.string(),
|
||||||
certificateType: z.enum(["letsencrypt", "none"]),
|
certificateType: z.enum(["letsencrypt", "none", "custom"]),
|
||||||
})
|
})
|
||||||
.superRefine((data, ctx) => {
|
.superRefine((data, ctx) => {
|
||||||
if (data.certificateType === "letsencrypt" && !data.letsEncryptEmail) {
|
if (data.certificateType === "letsencrypt" && !data.letsEncryptEmail) {
|
||||||
@@ -193,6 +193,7 @@ export const WebDomain = () => {
|
|||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="flex w-full justify-end col-span-2">
|
<div className="flex w-full justify-end col-span-2">
|
||||||
<Button isLoading={isLoading} type="submit">
|
<Button isLoading={isLoading} type="submit">
|
||||||
{t("settings.common.save")}
|
{t("settings.common.save")}
|
||||||
|
|||||||
2
apps/dokploy/drizzle/0072_green_susan_delgado.sql
Normal file
2
apps/dokploy/drizzle/0072_green_susan_delgado.sql
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ALTER TYPE "public"."certificateType" ADD VALUE 'custom';--> statement-breakpoint
|
||||||
|
ALTER TABLE "domain" ADD COLUMN "customCertResolver" text;--> statement-breakpoint
|
||||||
5132
apps/dokploy/drizzle/meta/0072_snapshot.json
Normal file
5132
apps/dokploy/drizzle/meta/0072_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -505,6 +505,13 @@
|
|||||||
"when": 1741460060541,
|
"when": 1741460060541,
|
||||||
"tag": "0071_flaky_black_queen",
|
"tag": "0071_flaky_black_queen",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 72,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1741487009559,
|
||||||
|
"tag": "0072_green_susan_delgado",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -10,7 +10,8 @@ export const domain = z
|
|||||||
.max(65535, { message: "Port must be 65535 or below" })
|
.max(65535, { message: "Port must be 65535 or below" })
|
||||||
.optional(),
|
.optional(),
|
||||||
https: z.boolean().optional(),
|
https: z.boolean().optional(),
|
||||||
certificateType: z.enum(["letsencrypt", "none"]).optional(),
|
certificateType: z.enum(["letsencrypt", "none", "custom"]).optional(),
|
||||||
|
customCertResolver: z.string().optional(),
|
||||||
})
|
})
|
||||||
.superRefine((input, ctx) => {
|
.superRefine((input, ctx) => {
|
||||||
if (input.https && !input.certificateType) {
|
if (input.https && !input.certificateType) {
|
||||||
@@ -20,6 +21,14 @@ export const domain = z
|
|||||||
message: "Required",
|
message: "Required",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (input.certificateType === "custom" && !input.customCertResolver) {
|
||||||
|
ctx.addIssue({
|
||||||
|
code: z.ZodIssueCode.custom,
|
||||||
|
path: ["customCertResolver"],
|
||||||
|
message: "Required",
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export const domainCompose = z
|
export const domainCompose = z
|
||||||
@@ -32,7 +41,8 @@ export const domainCompose = z
|
|||||||
.max(65535, { message: "Port must be 65535 or below" })
|
.max(65535, { message: "Port must be 65535 or below" })
|
||||||
.optional(),
|
.optional(),
|
||||||
https: z.boolean().optional(),
|
https: z.boolean().optional(),
|
||||||
certificateType: z.enum(["letsencrypt", "none"]).optional(),
|
certificateType: z.enum(["letsencrypt", "none", "custom"]).optional(),
|
||||||
|
customCertResolver: z.string().optional(),
|
||||||
serviceName: z.string().min(1, { message: "Service name is required" }),
|
serviceName: z.string().min(1, { message: "Service name is required" }),
|
||||||
})
|
})
|
||||||
.superRefine((input, ctx) => {
|
.superRefine((input, ctx) => {
|
||||||
@@ -43,4 +53,12 @@ export const domainCompose = z
|
|||||||
message: "Required",
|
message: "Required",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (input.certificateType === "custom" && !input.customCertResolver) {
|
||||||
|
ctx.addIssue({
|
||||||
|
code: z.ZodIssueCode.custom,
|
||||||
|
path: ["customCertResolver"],
|
||||||
|
message: "Required",
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ export const domains = pgTable("domain", {
|
|||||||
composeId: text("composeId").references(() => compose.composeId, {
|
composeId: text("composeId").references(() => compose.composeId, {
|
||||||
onDelete: "cascade",
|
onDelete: "cascade",
|
||||||
}),
|
}),
|
||||||
|
customCertResolver: text("customCertResolver"),
|
||||||
applicationId: text("applicationId").references(
|
applicationId: text("applicationId").references(
|
||||||
() => applications.applicationId,
|
() => applications.applicationId,
|
||||||
{ onDelete: "cascade" },
|
{ onDelete: "cascade" },
|
||||||
@@ -76,6 +77,7 @@ export const apiCreateDomain = createSchema.pick({
|
|||||||
https: true,
|
https: true,
|
||||||
applicationId: true,
|
applicationId: true,
|
||||||
certificateType: true,
|
certificateType: true,
|
||||||
|
customCertResolver: true,
|
||||||
composeId: true,
|
composeId: true,
|
||||||
serviceName: true,
|
serviceName: true,
|
||||||
domainType: true,
|
domainType: true,
|
||||||
@@ -107,6 +109,7 @@ export const apiUpdateDomain = createSchema
|
|||||||
port: true,
|
port: true,
|
||||||
https: true,
|
https: true,
|
||||||
certificateType: true,
|
certificateType: true,
|
||||||
|
customCertResolver: true,
|
||||||
serviceName: true,
|
serviceName: true,
|
||||||
domainType: true,
|
domainType: true,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -10,4 +10,5 @@ export const applicationStatus = pgEnum("applicationStatus", [
|
|||||||
export const certificateType = pgEnum("certificateType", [
|
export const certificateType = pgEnum("certificateType", [
|
||||||
"letsencrypt",
|
"letsencrypt",
|
||||||
"none",
|
"none",
|
||||||
|
"custom",
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ export const domain = z
|
|||||||
.max(65535, { message: "Port must be 65535 or below" })
|
.max(65535, { message: "Port must be 65535 or below" })
|
||||||
.optional(),
|
.optional(),
|
||||||
https: z.boolean().optional(),
|
https: z.boolean().optional(),
|
||||||
certificateType: z.enum(["letsencrypt", "none"]).optional(),
|
certificateType: z.enum(["letsencrypt", "none", "custom"]).optional(),
|
||||||
|
customCertResolver: z.string(),
|
||||||
})
|
})
|
||||||
.superRefine((input, ctx) => {
|
.superRefine((input, ctx) => {
|
||||||
if (input.https && !input.certificateType) {
|
if (input.https && !input.certificateType) {
|
||||||
@@ -20,6 +21,14 @@ export const domain = z
|
|||||||
message: "Required",
|
message: "Required",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (input.certificateType === "custom" && !input.customCertResolver) {
|
||||||
|
ctx.addIssue({
|
||||||
|
code: z.ZodIssueCode.custom,
|
||||||
|
path: ["customCertResolver"],
|
||||||
|
message: "Required when certificate type is custom",
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export const domainCompose = z
|
export const domainCompose = z
|
||||||
@@ -32,7 +41,8 @@ export const domainCompose = z
|
|||||||
.max(65535, { message: "Port must be 65535 or below" })
|
.max(65535, { message: "Port must be 65535 or below" })
|
||||||
.optional(),
|
.optional(),
|
||||||
https: z.boolean().optional(),
|
https: z.boolean().optional(),
|
||||||
certificateType: z.enum(["letsencrypt", "none"]).optional(),
|
certificateType: z.enum(["letsencrypt", "none", "custom"]).optional(),
|
||||||
|
customCertResolver: z.string(),
|
||||||
serviceName: z.string().min(1, { message: "Service name is required" }),
|
serviceName: z.string().min(1, { message: "Service name is required" }),
|
||||||
})
|
})
|
||||||
.superRefine((input, ctx) => {
|
.superRefine((input, ctx) => {
|
||||||
@@ -43,4 +53,12 @@ export const domainCompose = z
|
|||||||
message: "Required",
|
message: "Required",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (input.certificateType === "custom" && !input.customCertResolver) {
|
||||||
|
ctx.addIssue({
|
||||||
|
code: z.ZodIssueCode.custom,
|
||||||
|
path: ["customCertResolver"],
|
||||||
|
message: "Required when certificate type is custom",
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -211,13 +211,9 @@ export const addDomainToCompose = async (
|
|||||||
throw new Error(`The service ${serviceName} not found in the compose`);
|
throw new Error(`The service ${serviceName} not found in the compose`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const httpLabels = await createDomainLabels(appName, domain, "web");
|
const httpLabels = createDomainLabels(appName, domain, "web");
|
||||||
if (https) {
|
if (https) {
|
||||||
const httpsLabels = await createDomainLabels(
|
const httpsLabels = createDomainLabels(appName, domain, "websecure");
|
||||||
appName,
|
|
||||||
domain,
|
|
||||||
"websecure",
|
|
||||||
);
|
|
||||||
httpLabels.push(...httpsLabels);
|
httpLabels.push(...httpsLabels);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,12 +275,20 @@ export const writeComposeFile = async (
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createDomainLabels = async (
|
export const createDomainLabels = (
|
||||||
appName: string,
|
appName: string,
|
||||||
domain: Domain,
|
domain: Domain,
|
||||||
entrypoint: "web" | "websecure",
|
entrypoint: "web" | "websecure",
|
||||||
) => {
|
) => {
|
||||||
const { host, port, https, uniqueConfigKey, certificateType, path } = domain;
|
const {
|
||||||
|
host,
|
||||||
|
port,
|
||||||
|
https,
|
||||||
|
uniqueConfigKey,
|
||||||
|
certificateType,
|
||||||
|
path,
|
||||||
|
customCertResolver,
|
||||||
|
} = domain;
|
||||||
const routerName = `${appName}-${uniqueConfigKey}-${entrypoint}`;
|
const routerName = `${appName}-${uniqueConfigKey}-${entrypoint}`;
|
||||||
const labels = [
|
const labels = [
|
||||||
`traefik.http.routers.${routerName}.rule=Host(\`${host}\`)${path && path !== "/" ? ` && PathPrefix(\`${path}\`)` : ""}`,
|
`traefik.http.routers.${routerName}.rule=Host(\`${host}\`)${path && path !== "/" ? ` && PathPrefix(\`${path}\`)` : ""}`,
|
||||||
@@ -304,6 +308,10 @@ export const createDomainLabels = async (
|
|||||||
labels.push(
|
labels.push(
|
||||||
`traefik.http.routers.${routerName}.tls.certresolver=letsencrypt`,
|
`traefik.http.routers.${routerName}.tls.certresolver=letsencrypt`,
|
||||||
);
|
);
|
||||||
|
} else if (certificateType === "custom" && customCertResolver) {
|
||||||
|
labels.push(
|
||||||
|
`traefik.http.routers.${routerName}.tls.certresolver=${customCertResolver}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -148,6 +148,8 @@ export const createRouterConfig = async (
|
|||||||
if (entryPoint === "websecure") {
|
if (entryPoint === "websecure") {
|
||||||
if (certificateType === "letsencrypt") {
|
if (certificateType === "letsencrypt") {
|
||||||
routerConfig.tls = { certResolver: "letsencrypt" };
|
routerConfig.tls = { certResolver: "letsencrypt" };
|
||||||
|
} else if (certificateType === "custom" && domain.customCertResolver) {
|
||||||
|
routerConfig.tls = { certResolver: domain.customCertResolver };
|
||||||
} else if (certificateType === "none") {
|
} else if (certificateType === "none") {
|
||||||
routerConfig.tls = undefined;
|
routerConfig.tls = undefined;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user