diff --git a/apps/dokploy/components/dashboard/settings/cluster/registry/handle-registry.tsx b/apps/dokploy/components/dashboard/settings/cluster/registry/handle-registry.tsx index 4321088f2..dc4b810dd 100644 --- a/apps/dokploy/components/dashboard/settings/cluster/registry/handle-registry.tsx +++ b/apps/dokploy/components/dashboard/settings/cluster/registry/handle-registry.tsx @@ -45,7 +45,34 @@ const AddRegistrySchema = z.object({ password: z.string().min(1, { message: "Password is required", }), - registryUrl: z.string(), + registryUrl: z + .string() + .optional() + .refine( + (val) => { + // If empty or undefined, skip validation (field is optional) + if (!val || val.trim().length === 0) { + return true; + } + // Validate that it's a valid hostname (no protocol, no path, optional port) + // Valid formats: example.com, registry.example.com, [::1], example.com:5000 + // Invalid: https://example.com, example.com/path + const trimmed = val.trim(); + // Check for protocol or path - these are not allowed + if (/^https?:\/\//i.test(trimmed) || trimmed.includes("/")) { + return false; + } + // Basic hostname validation: allow alphanumeric, dots, hyphens, underscores, and IPv6 in brackets + // Allow optional port at the end + const hostnameRegex = + /^(?:\[[^\]]+\]|[a-zA-Z0-9](?:[a-zA-Z0-9._-]{0,253}[a-zA-Z0-9])?)(?::\d+)?$/; + return hostnameRegex.test(trimmed); + }, + { + message: + "Invalid registry URL. Please enter only the hostname (e.g., example.com or registry.example.com). Do not include protocol (https://) or paths.", + }, + ), imagePrefix: z.string(), serverId: z.string().optional(), }); @@ -125,7 +152,7 @@ export const HandleRegistry = ({ registryId }: Props) => { password: data.password, registryName: data.registryName, username: data.username, - registryUrl: data.registryUrl, + registryUrl: data.registryUrl || "", registryType: "cloud", imagePrefix: data.imagePrefix, serverId: data.serverId, @@ -261,6 +288,10 @@ export const HandleRegistry = ({ registryId }: Props) => { render={({ field }) => ( Registry URL + + Enter only the hostname (e.g., + aws_account_id.dkr.ecr.us-west-2.amazonaws.com). + { await testRegistry({ username: username, password: password, - registryUrl: registryUrl, + registryUrl: registryUrl || "", registryName: registryName, registryType: "cloud", imagePrefix: imagePrefix,