From 9065385b87f1ccca449cf4bf1b3849a1f00c6e7f Mon Sep 17 00:00:00 2001 From: Varun Narravula Date: Wed, 3 Dec 2025 15:40:55 -0800 Subject: [PATCH] feat(healthcheck): add SNI input field to target healthcheck config --- messages/en-US.json | 2 + server/routers/newt/targets.ts | 3 +- server/routers/target/createTarget.ts | 4 +- server/routers/target/listTargets.ts | 1 + server/routers/target/updateTarget.ts | 4 +- .../resources/[niceId]/proxy/page.tsx | 11 ++++-- .../settings/resources/create/page.tsx | 12 ++++-- src/components/HealthCheckDialog.tsx | 38 ++++++++++++++++++- 8 files changed, 64 insertions(+), 11 deletions(-) diff --git a/messages/en-US.json b/messages/en-US.json index cf066c3d..0a78ccfe 100644 --- a/messages/en-US.json +++ b/messages/en-US.json @@ -516,6 +516,8 @@ "targetCreatedDescription": "Target has been created successfully", "targetErrorCreate": "Failed to create target", "targetErrorCreateDescription": "An error occurred while creating the target", + "tlsServerName": "TLS Server Name", + "tlsServerNameDescription": "The TLS server name to use for SNI", "save": "Save", "proxyAdditional": "Additional Proxy Settings", "proxyAdditionalDescription": "Configure how your resource handles proxy settings", diff --git a/server/routers/newt/targets.ts b/server/routers/newt/targets.ts index 97e4030d..32145fcb 100644 --- a/server/routers/newt/targets.ts +++ b/server/routers/newt/targets.ts @@ -66,7 +66,8 @@ export async function addTargets( hcUnhealthyInterval: hc.hcUnhealthyInterval, // in seconds hcTimeout: hc.hcTimeout, // in seconds hcHeaders: hcHeadersSend, - hcMethod: hc.hcMethod + hcMethod: hc.hcMethod, + hcTlsServerName: hc.hcTlsServerName, }; }); diff --git a/server/routers/target/createTarget.ts b/server/routers/target/createTarget.ts index 6cf29da3..2c09b5a6 100644 --- a/server/routers/target/createTarget.ts +++ b/server/routers/target/createTarget.ts @@ -48,6 +48,7 @@ const createTargetSchema = z.strictObject({ hcFollowRedirects: z.boolean().optional().nullable(), hcMethod: z.string().min(1).optional().nullable(), hcStatus: z.int().optional().nullable(), + hcTlsServerName: z.string().optional().nullable(), path: z.string().optional().nullable(), pathMatchType: z .enum(["exact", "prefix", "regex"]) @@ -247,7 +248,8 @@ export async function createTarget( hcFollowRedirects: targetData.hcFollowRedirects ?? null, hcMethod: targetData.hcMethod ?? null, hcStatus: targetData.hcStatus ?? null, - hcHealth: "unknown" + hcHealth: "unknown", + hcTlsServerName: targetData.hcTlsServerName ?? null }) .returning(); diff --git a/server/routers/target/listTargets.ts b/server/routers/target/listTargets.ts index e97d577d..356276cb 100644 --- a/server/routers/target/listTargets.ts +++ b/server/routers/target/listTargets.ts @@ -57,6 +57,7 @@ function queryTargets(resourceId: number) { hcMethod: targetHealthCheck.hcMethod, hcStatus: targetHealthCheck.hcStatus, hcHealth: targetHealthCheck.hcHealth, + hcTlsServerName: targetHealthCheck.hcTlsServerName, path: targets.path, pathMatchType: targets.pathMatchType, rewritePath: targets.rewritePath, diff --git a/server/routers/target/updateTarget.ts b/server/routers/target/updateTarget.ts index 1889154c..4a60e6cf 100644 --- a/server/routers/target/updateTarget.ts +++ b/server/routers/target/updateTarget.ts @@ -42,6 +42,7 @@ const updateTargetBodySchema = z.strictObject({ hcFollowRedirects: z.boolean().optional().nullable(), hcMethod: z.string().min(1).optional().nullable(), hcStatus: z.int().optional().nullable(), + hcTlsServerName: z.string().optional().nullable(), path: z.string().optional().nullable(), pathMatchType: z.enum(["exact", "prefix", "regex"]).optional().nullable(), rewritePath: z.string().optional().nullable(), @@ -217,7 +218,8 @@ export async function updateTarget( hcHeaders: hcHeaders, hcFollowRedirects: parsedBody.data.hcFollowRedirects, hcMethod: parsedBody.data.hcMethod, - hcStatus: parsedBody.data.hcStatus + hcStatus: parsedBody.data.hcStatus, + hcTlsServerName: parsedBody.data.hcTlsServerName, }) .where(eq(targetHealthCheck.targetId, targetId)) .returning(); diff --git a/src/app/[orgId]/settings/resources/[niceId]/proxy/page.tsx b/src/app/[orgId]/settings/resources/[niceId]/proxy/page.tsx index f7a5a559..c7faed5f 100644 --- a/src/app/[orgId]/settings/resources/[niceId]/proxy/page.tsx +++ b/src/app/[orgId]/settings/resources/[niceId]/proxy/page.tsx @@ -464,6 +464,7 @@ export default function ReverseProxyTargets(props: { hcStatus: null, hcMode: null, hcUnhealthyInterval: null, + hcTlsServerName: null, siteType: sites.length > 0 ? sites[0].type : null, new: true, updated: false @@ -629,7 +630,8 @@ export default function ReverseProxyTargets(props: { hcHealth: "unknown", hcStatus: null, hcMode: null, - hcUnhealthyInterval: null + hcUnhealthyInterval: null, + hcTlsServerName: null, }; setTargets([...targets, newTarget]); @@ -729,7 +731,8 @@ export default function ReverseProxyTargets(props: { hcMethod: target.hcMethod || null, hcStatus: target.hcStatus || null, hcUnhealthyInterval: target.hcUnhealthyInterval || null, - hcMode: target.hcMode || null + hcMode: target.hcMode || null, + hcTlsServerName: target.hcTlsServerName, }; // Only include path-related fields for HTTP resources @@ -1822,7 +1825,9 @@ export default function ReverseProxyTargets(props: { hcMode: selectedTargetForHealthCheck.hcMode || "http", hcUnhealthyInterval: selectedTargetForHealthCheck.hcUnhealthyInterval || - 30 + 30, + hcTlsServerName: selectedTargetForHealthCheck.hcTlsServerName || + undefined, }} onChanges={async (config) => { console.log("here"); diff --git a/src/app/[orgId]/settings/resources/create/page.tsx b/src/app/[orgId]/settings/resources/create/page.tsx index c3655239..2cbeaf34 100644 --- a/src/app/[orgId]/settings/resources/create/page.tsx +++ b/src/app/[orgId]/settings/resources/create/page.tsx @@ -297,6 +297,7 @@ export default function Page() { hcStatus: null, hcMode: null, hcUnhealthyInterval: null, + hcTlsServerName: null, siteType: sites.length > 0 ? sites[0].type : null, new: true, updated: false @@ -454,7 +455,8 @@ export default function Page() { hcHealth: "unknown", hcStatus: null, hcMode: null, - hcUnhealthyInterval: null + hcUnhealthyInterval: null, + hcTlsServerName: null }; setTargets([...targets, newTarget]); @@ -576,7 +578,8 @@ export default function Page() { target.hcFollowRedirects || null, hcStatus: target.hcStatus || null, hcUnhealthyInterval: target.hcUnhealthyInterval || null, - hcMode: target.hcMode || null + hcMode: target.hcMode || null, + hcTlsServerName: target.hcTlsServerName }; // Only include path-related fields for HTTP resources @@ -1800,7 +1803,10 @@ export default function Page() { "http", hcUnhealthyInterval: selectedTargetForHealthCheck.hcUnhealthyInterval || - 30 + 30, + hcTlsServerName: + selectedTargetForHealthCheck.hcTlsServerName || + undefined }} onChanges={async (config) => { if (selectedTargetForHealthCheck) { diff --git a/src/components/HealthCheckDialog.tsx b/src/components/HealthCheckDialog.tsx index be5e5d45..2784aa23 100644 --- a/src/components/HealthCheckDialog.tsx +++ b/src/components/HealthCheckDialog.tsx @@ -51,6 +51,7 @@ type HealthCheckConfig = { hcFollowRedirects: boolean; hcMode: string; hcUnhealthyInterval: number; + hcTlsServerName: string; }; type HealthCheckDialogProps = { @@ -93,7 +94,8 @@ export default function HealthCheckDialog({ hcPort: z.number().positive().gt(0).lte(65535), hcFollowRedirects: z.boolean(), hcMode: z.string(), - hcUnhealthyInterval: z.int().positive().min(5) + hcUnhealthyInterval: z.int().positive().min(5), + hcTlsServerName: z.string() }); const form = useForm>({ @@ -129,7 +131,8 @@ export default function HealthCheckDialog({ hcPort: initialConfig?.hcPort, hcFollowRedirects: initialConfig?.hcFollowRedirects, hcMode: initialConfig?.hcMode, - hcUnhealthyInterval: initialConfig?.hcUnhealthyInterval + hcUnhealthyInterval: initialConfig?.hcUnhealthyInterval, + hcTlsServerName: initialConfig?.hcTlsServerName ?? "" }); }, [open]); @@ -531,6 +534,37 @@ export default function HealthCheckDialog({ )} /> + {/*TLS Server Name (SNI)*/} + ( + + + {t("tlsServerName")} + + + { + field.onChange(e); + handleFieldChange( + "hcTlsServerName", + e.target.value + ); + }} + /> + + + {t( + "tlsServerNameDescription" + )} + + + + )} + /> + {/* Custom Headers */}