diff --git a/server/db/schemas/schema.ts b/server/db/schemas/schema.ts index ecb5cd35..1c594545 100644 --- a/server/db/schemas/schema.ts +++ b/server/db/schemas/schema.ts @@ -78,6 +78,9 @@ export const resources = sqliteTable("resources", { .notNull() .default(false), enabled: integer("enabled", { mode: "boolean" }).notNull().default(true), + stickySession: integer("stickySession", { mode: "boolean" }) + .notNull() + .default(false), tlsServerName: text("tlsServerName"), setHostHeader: text("setHostHeader") }); diff --git a/server/routers/resource/updateResource.ts b/server/routers/resource/updateResource.ts index dbf96fea..d17ad499 100644 --- a/server/routers/resource/updateResource.ts +++ b/server/routers/resource/updateResource.ts @@ -44,6 +44,7 @@ const updateHttpResourceBodySchema = z applyRules: z.boolean().optional(), domainId: z.string().optional(), enabled: z.boolean().optional(), + stickySession: z.boolean().optional(), tlsServerName: z.string().optional(), setHostHeader: z.string().optional() }) diff --git a/server/routers/traefik/getTraefikConfig.ts b/server/routers/traefik/getTraefikConfig.ts index d6053430..e6488b9f 100644 --- a/server/routers/traefik/getTraefikConfig.ts +++ b/server/routers/traefik/getTraefikConfig.ts @@ -41,6 +41,7 @@ export async function traefikConfigProvider( orgId: orgs.orgId }, enabled: resources.enabled, + stickySession: resources.stickySessionk, tlsServerName: resources.tlsServerName, setHostHeader: resources.setHostHeader }) @@ -104,7 +105,10 @@ export async function traefikConfigProvider( [badgerMiddlewareName]: { apiBaseUrl: new URL( "/api/v1", - `http://${config.getRawConfig().server.internal_hostname}:${ + `http://${ + config.getRawConfig().server + .internal_hostname + }:${ config.getRawConfig().server .internal_port }` @@ -279,7 +283,18 @@ export async function traefikConfigProvider( url: `${target.method}://${ip}:${target.internalPort}` }; } - }) + }), + ...(resource.stickySession + ? { + sticky: { + cookie: { + name: "pangolin_sticky", + secure: resource.ssl, + httpOnly: true + } + } + } + : {}) } }; @@ -376,7 +391,17 @@ export async function traefikConfigProvider( address: `${ip}:${target.internalPort}` }; } - }) + }), + ...(resource.stickySession + ? { + sticky: { + ipStrategy: { + depth: 0, + sourcePort: true + } + } + } + : {}) } }; } diff --git a/server/setup/scripts/1.3.0.ts b/server/setup/scripts/1.3.0.ts index 692dacb4..f837deb7 100644 --- a/server/setup/scripts/1.3.0.ts +++ b/server/setup/scripts/1.3.0.ts @@ -9,10 +9,13 @@ export default async function migration() { try { db.transaction((trx) => { trx.run( - sql`ALTER TABLE 'resources' ADD 'tlsServerName' text DEFAULT '' NOT NULL;` + sql`ALTER TABLE resources ADD stickySession integer DEFAULT false NOT NULL;` ); trx.run( - sql`ALTER TABLE 'resources' ADD 'setHostHeader' text DEFAULT '' NOT NULL;` + sql`ALTER TABLE 'resources' ADD 'tlsServerName' text;` + ); + trx.run( + sql`ALTER TABLE 'resources' ADD 'setHostHeader' text;` ); }); diff --git a/src/app/[orgId]/settings/resources/[resourceId]/connectivity/page.tsx b/src/app/[orgId]/settings/resources/[resourceId]/connectivity/page.tsx index f0dd8978..18bb8f34 100644 --- a/src/app/[orgId]/settings/resources/[resourceId]/connectivity/page.tsx +++ b/src/app/[orgId]/settings/resources/[resourceId]/connectivity/page.tsx @@ -94,6 +94,7 @@ export default function ReverseProxyTargets(props: { const [site, setSite] = useState(); const [targetsToRemove, setTargetsToRemove] = useState([]); const [sslEnabled, setSslEnabled] = useState(resource.ssl); + const [stickySession, setStickySession] = useState(resource.stickySession); const [loading, setLoading] = useState(false); @@ -317,6 +318,35 @@ export default function ReverseProxyTargets(props: { } } + async function saveStickySession(val: boolean) { + const res = await api + .post(`/resource/${params.resourceId}`, { + stickySession: val + }) + .catch((err) => { + console.error(err); + toast({ + variant: "destructive", + title: "Failed to update sticky session configuration", + description: formatAxiosError( + err, + "An error occurred while updating the sticky session configuration" + ) + }); + }); + + if (res && res.status === 200) { + setStickySession(val); + updateResource({ stickySession: val }); + + toast({ + title: "Sticky Session Configuration", + description: "Sticky session configuration updated successfully" + }); + router.refresh(); + } + } + const columns: ColumnDef[] = [ { accessorKey: "ip", @@ -456,13 +486,24 @@ export default function ReverseProxyTargets(props: { - SSL Configuration + Advanced Configuration - Set up SSL to secure your connections with certificates + Configure advanced settings for your resource + {targets.length >= 2 && ( + { + await saveStickySession(val); + }} + /> + )}