UI and backend update to add proxy protocol support

This commit is contained in:
Pallavi Kumari
2025-10-23 23:07:26 +05:30
parent c1bb029a1c
commit b5a931c96e
3 changed files with 147 additions and 27 deletions

View File

@@ -114,7 +114,10 @@ export const resources = sqliteTable("resources", {
skipToIdpId: integer("skipToIdpId").references(() => idp.idpId, {
onDelete: "cascade"
}),
headers: text("headers") // comma-separated list of headers to add to the request
headers: text("headers"), // comma-separated list of headers to add to the request
proxyProtocol: integer("proxyProtocol", { mode: "boolean" }).notNull().default(false),
proxyProtocolVersion: integer("proxyProtocolVersion").default(1)
});
export const targets = sqliteTable("targets", {

View File

@@ -99,8 +99,9 @@ const updateRawResourceBodySchema = z
name: z.string().min(1).max(255).optional(),
proxyPort: z.number().int().min(1).max(65535).optional(),
stickySession: z.boolean().optional(),
enabled: z.boolean().optional()
// enableProxy: z.boolean().optional() // always true now
enabled: z.boolean().optional(),
proxyProtocol: z.boolean().optional(),
proxyProtocolVersion: z.number().int().min(1).optional()
})
.strict()
.refine((data) => Object.keys(data).length > 0, {

View File

@@ -77,7 +77,8 @@ import {
MoveRight,
ArrowUp,
Info,
ArrowDown
ArrowDown,
AlertTriangle
} from "lucide-react";
import { ContainersSelector } from "@app/components/ContainersSelector";
import { useTranslations } from "next-intl";
@@ -115,6 +116,7 @@ import {
TooltipProvider,
TooltipTrigger
} from "@app/components/ui/tooltip";
import { Alert, AlertDescription } from "@app/components/ui/alert";
const addTargetSchema = z
.object({
@@ -288,7 +290,9 @@ export default function ReverseProxyTargets(props: {
),
headers: z
.array(z.object({ name: z.string(), value: z.string() }))
.nullable()
.nullable(),
proxyProtocol: z.boolean().optional(),
proxyProtocolVersion: z.number().int().min(1).max(2).optional()
});
const tlsSettingsSchema = z.object({
@@ -325,7 +329,9 @@ export default function ReverseProxyTargets(props: {
resolver: zodResolver(proxySettingsSchema),
defaultValues: {
setHostHeader: resource.setHostHeader || "",
headers: resource.headers
headers: resource.headers,
proxyProtocol: resource.proxyProtocol || false,
proxyProtocolVersion: resource.proxyProtocolVersion || 1
}
});
@@ -800,6 +806,22 @@ export default function ReverseProxyTargets(props: {
setHostHeader: proxyData.setHostHeader || null,
headers: proxyData.headers || null
});
} else {
// For TCP/UDP resources, save proxy protocol settings
const proxyData = proxySettingsForm.getValues();
const payload = {
proxyProtocol: proxyData.proxyProtocol || false,
proxyProtocolVersion: proxyData.proxyProtocolVersion || 1
};
await api.post(`/resource/${resource.resourceId}`, payload);
updateResource({
...resource,
proxyProtocol: proxyData.proxyProtocol || false,
proxyProtocolVersion: proxyData.proxyProtocolVersion || 1
});
}
toast({
@@ -1675,6 +1697,100 @@ export default function ReverseProxyTargets(props: {
</SettingsSection>
)}
{!resource.http && resource.protocol && (
<SettingsSection>
<SettingsSectionHeader>
<SettingsSectionTitle>
Proxy Protocol Settings
</SettingsSectionTitle>
<SettingsSectionDescription>
Configure Proxy Protocol to preserve client IP addresses for TCP/UDP services.
</SettingsSectionDescription>
</SettingsSectionHeader>
<SettingsSectionBody>
<SettingsSectionForm>
<Form {...proxySettingsForm}>
<form
onSubmit={proxySettingsForm.handleSubmit(
saveAllSettings
)}
className="space-y-4"
id="proxy-protocol-settings-form"
>
<FormField
control={proxySettingsForm.control}
name="proxyProtocol"
render={({ field }) => (
<FormItem>
<FormControl>
<SwitchInput
id="proxy-protocol-toggle"
label="Enable Proxy Protocol"
description="Preserve client IP addresses for TCP/UDP backends"
defaultChecked={
field.value || false
}
onCheckedChange={(val) => {
field.onChange(val);
}}
/>
</FormControl>
</FormItem>
)}
/>
{proxySettingsForm.watch("proxyProtocol") && (
<>
<FormField
control={proxySettingsForm.control}
name="proxyProtocolVersion"
render={({ field }) => (
<FormItem>
<FormLabel>Proxy Protocol Version</FormLabel>
<FormControl>
<Select
value={String(field.value || 1)}
onValueChange={(value) =>
field.onChange(parseInt(value, 10))
}
>
<SelectTrigger>
<SelectValue placeholder="Select version" />
</SelectTrigger>
<SelectContent>
<SelectItem value="1">
Version 1 (Recommended)
</SelectItem>
<SelectItem value="2">
Version 2
</SelectItem>
</SelectContent>
</Select>
</FormControl>
<FormDescription>
Version 1 is text-based and widely supported. Version 2 is binary and more efficient but less compatible.
</FormDescription>
</FormItem>
)}
/>
<Alert>
<AlertTriangle className="h-4 w-4" />
<AlertDescription>
<strong>Warning:</strong> Your backend application must be configured to accept Proxy Protocol connections.
If your backend doesn't support Proxy Protocol, enabling this will break all connections.
Make sure to configure your backend to trust Proxy Protocol headers from Traefik.
</AlertDescription>
</Alert>
</>
)}
</form>
</Form>
</SettingsSectionForm>
</SettingsSectionBody>
</SettingsSection>
)}
<div className="flex justify-end mt-6">
<Button
onClick={saveAllSettings}