From cc8ffca4d48f9ef422a79a7bdf96e01b9a6850ec Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 8 Mar 2025 20:46:31 -0600 Subject: [PATCH] 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 --- .../application/domains/add-domain.tsx | 123 +- .../dashboard/compose/domains/add-domain.tsx | 93 +- .../dashboard/settings/web-domain.tsx | 3 +- .../drizzle/0072_green_susan_delgado.sql | 2 + apps/dokploy/drizzle/meta/0072_snapshot.json | 5132 +++++++++++++++++ apps/dokploy/drizzle/meta/_journal.json | 7 + apps/dokploy/server/db/validations/domain.ts | 22 +- packages/server/src/db/schema/domain.ts | 3 + packages/server/src/db/schema/shared.ts | 1 + packages/server/src/db/validations/domain.ts | 22 +- packages/server/src/utils/docker/domain.ts | 24 +- packages/server/src/utils/traefik/domain.ts | 2 + 12 files changed, 5367 insertions(+), 67 deletions(-) create mode 100644 apps/dokploy/drizzle/0072_green_susan_delgado.sql create mode 100644 apps/dokploy/drizzle/meta/0072_snapshot.json diff --git a/apps/dokploy/components/dashboard/application/domains/add-domain.tsx b/apps/dokploy/components/dashboard/application/domains/add-domain.tsx index 61168943..f91218ce 100644 --- a/apps/dokploy/components/dashboard/application/domains/add-domain.tsx +++ b/apps/dokploy/components/dashboard/application/domains/add-domain.tsx @@ -85,8 +85,20 @@ export const AddDomain = ({ const form = useForm({ 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(() => { if (data) { form.reset({ @@ -94,13 +106,29 @@ export const AddDomain = ({ /* Convert null to undefined */ path: data?.path || undefined, port: data?.port || undefined, + certificateType: data?.certificateType || undefined, + customCertResolver: data?.customCertResolver || undefined, }); } 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 = { success: domainId ? "Domain Updated" : "Domain Created", @@ -256,34 +284,73 @@ export const AddDomain = ({ )} /> - {form.getValues().https && ( - ( - - Certificate Provider - { + field.onChange(value); + if (value !== "custom") { + form.setValue( + "customCertResolver", + undefined, + ); + } + }} + value={field.value} + > + + + + + + + None + + Let's Encrypt + + Custom + + + + + ); + }} + /> - - None - - Let's Encrypt - - - - - + {certificateType === "custom" && ( + { + return ( + + Custom Certificate Resolver + + { + field.onChange(e); + form.trigger("customCertResolver"); + }} + /> + + + + ); + }} + /> )} - /> + )} diff --git a/apps/dokploy/components/dashboard/compose/domains/add-domain.tsx b/apps/dokploy/components/dashboard/compose/domains/add-domain.tsx index e18d40d7..9b412c83 100644 --- a/apps/dokploy/components/dashboard/compose/domains/add-domain.tsx +++ b/apps/dokploy/components/dashboard/compose/domains/add-domain.tsx @@ -104,6 +104,15 @@ export const AddDomainCompose = ({ const form = useForm({ resolver: zodResolver(domainCompose), + defaultValues: { + host: "", + path: undefined, + port: undefined, + https: false, + certificateType: undefined, + customCertResolver: undefined, + serviceName: "", + }, }); const https = form.watch("https"); @@ -116,11 +125,21 @@ export const AddDomainCompose = ({ path: data?.path || undefined, port: data?.port || undefined, serviceName: data?.serviceName || undefined, + certificateType: data?.certificateType || undefined, + customCertResolver: data?.customCertResolver || undefined, }); } if (!domainId) { - form.reset({}); + form.reset({ + host: "", + path: undefined, + port: undefined, + https: false, + certificateType: undefined, + customCertResolver: undefined, + serviceName: "", + }); } }, [form, form.reset, data, isLoading]); @@ -393,33 +412,55 @@ export const AddDomainCompose = ({ /> {https && ( - ( - - Certificate Provider - + + + + + - - None - - Let's Encrypt - - - - - + + None + + Let's Encrypt + + Custom + + + + + )} + /> + + {form.getValues().certificateType === "custom" && ( + ( + + Custom Certificate Resolver + + + + + + )} + /> )} - /> + )} diff --git a/apps/dokploy/components/dashboard/settings/web-domain.tsx b/apps/dokploy/components/dashboard/settings/web-domain.tsx index 3b3f70ba..a579df39 100644 --- a/apps/dokploy/components/dashboard/settings/web-domain.tsx +++ b/apps/dokploy/components/dashboard/settings/web-domain.tsx @@ -35,7 +35,7 @@ const addServerDomain = z .object({ domain: z.string().min(1, { message: "URL is required" }), letsEncryptEmail: z.string(), - certificateType: z.enum(["letsencrypt", "none"]), + certificateType: z.enum(["letsencrypt", "none", "custom"]), }) .superRefine((data, ctx) => { if (data.certificateType === "letsencrypt" && !data.letsEncryptEmail) { @@ -193,6 +193,7 @@ export const WebDomain = () => { ); }} /> +