diff --git a/app/(dashboard)/proxy-hosts/ProxyHostsClient.tsx b/app/(dashboard)/proxy-hosts/ProxyHostsClient.tsx index 83a13b26..be9ef1a4 100644 --- a/app/(dashboard)/proxy-hosts/ProxyHostsClient.tsx +++ b/app/(dashboard)/proxy-hosts/ProxyHostsClient.tsx @@ -84,16 +84,10 @@ export default function ProxyHostsClient({ hosts, certificates, accessLists, aut id: "upstreams", label: "Target", render: (host: ProxyHost) => ( - host.response_mode === "static" ? ( - - Static Response ({host.static_status_code ?? 503}) - - ) : ( - - {host.upstreams[0]} - {host.upstreams.length > 1 && ` +${host.upstreams.length - 1} more`} - - ) + + {host.upstreams[0]} + {host.upstreams.length > 1 && ` +${host.upstreams.length - 1} more`} + ) }, { diff --git a/app/(dashboard)/proxy-hosts/actions.ts b/app/(dashboard)/proxy-hosts/actions.ts index 921b6f4c..1ec3e10d 100644 --- a/app/(dashboard)/proxy-hosts/actions.ts +++ b/app/(dashboard)/proxy-hosts/actions.ts @@ -3,7 +3,7 @@ import { revalidatePath } from "next/cache"; import { requireAdmin } from "@/src/lib/auth"; import { actionError, actionSuccess, INITIAL_ACTION_STATE, type ActionState } from "@/src/lib/actions"; -import { createProxyHost, deleteProxyHost, updateProxyHost, type ProxyHostAuthentikInput, type LoadBalancerInput, type LoadBalancingPolicy, type DnsResolverInput, type ResponseMode } from "@/src/lib/models/proxy-hosts"; +import { createProxyHost, deleteProxyHost, updateProxyHost, type ProxyHostAuthentikInput, type LoadBalancerInput, type LoadBalancingPolicy, type DnsResolverInput } from "@/src/lib/models/proxy-hosts"; import { getCertificate } from "@/src/lib/models/certificates"; import { getCloudflareSettings } from "@/src/lib/settings"; @@ -270,28 +270,6 @@ function parseLoadBalancerConfig(formData: FormData): LoadBalancerInput | undefi return Object.keys(result).length > 0 ? result : undefined; } -function parseResponseMode(value: FormDataEntryValue | null): ResponseMode { - if (!value || typeof value !== "string") { - return "proxy"; - } - return value === "static" ? "static" : "proxy"; -} - -function parseStatusCode(value: FormDataEntryValue | null): number | null { - if (!value || typeof value !== "string") { - return null; - } - const trimmed = value.trim(); - if (trimmed === "") { - return null; - } - const num = parseInt(trimmed, 10); - if (!Number.isFinite(num) || num < 100 || num > 599) { - return 200; - } - return num; -} - function parseDnsResolverConfig(formData: FormData): DnsResolverInput | undefined { if (!formData.has("dns_present")) { return undefined; @@ -370,8 +348,6 @@ export async function createProxyHostAction( console.warn(`[createProxyHostAction] ${warning}`); } - const responseMode = parseResponseMode(formData.get("response_mode")); - await createProxyHost( { name: String(formData.get("name") ?? "Untitled"), @@ -386,10 +362,7 @@ export async function createProxyHostAction( custom_reverse_proxy_json: parseOptionalText(formData.get("custom_reverse_proxy_json")), authentik: parseAuthentikConfig(formData), load_balancer: parseLoadBalancerConfig(formData), - dns_resolver: parseDnsResolverConfig(formData), - response_mode: responseMode, - static_status_code: parseStatusCode(formData.get("static_status_code")), - static_response_body: parseOptionalText(formData.get("static_response_body")) + dns_resolver: parseDnsResolverConfig(formData) }, userId ); @@ -437,8 +410,6 @@ export async function updateProxyHostAction( } } - const responseMode = formData.has("response_mode") ? parseResponseMode(formData.get("response_mode")) : undefined; - await updateProxyHost( id, { @@ -460,10 +431,7 @@ export async function updateProxyHostAction( : undefined, authentik: parseAuthentikConfig(formData), load_balancer: parseLoadBalancerConfig(formData), - dns_resolver: parseDnsResolverConfig(formData), - response_mode: responseMode, - static_status_code: formData.has("static_status_code") ? parseStatusCode(formData.get("static_status_code")) : undefined, - static_response_body: formData.has("static_response_body") ? parseOptionalText(formData.get("static_response_body")) : undefined + dns_resolver: parseDnsResolverConfig(formData) }, userId ); diff --git a/drizzle/0005_remove_static_response.sql b/drizzle/0005_remove_static_response.sql new file mode 100644 index 00000000..1e1892f9 --- /dev/null +++ b/drizzle/0005_remove_static_response.sql @@ -0,0 +1,4 @@ +-- Remove static response feature columns from proxy_hosts +ALTER TABLE `proxy_hosts` DROP COLUMN `response_mode`; +ALTER TABLE `proxy_hosts` DROP COLUMN `static_status_code`; +ALTER TABLE `proxy_hosts` DROP COLUMN `static_response_body`; diff --git a/src/components/proxy-hosts/HostDialogs.tsx b/src/components/proxy-hosts/HostDialogs.tsx index 9df93754..e86db51a 100644 --- a/src/components/proxy-hosts/HostDialogs.tsx +++ b/src/components/proxy-hosts/HostDialogs.tsx @@ -1,7 +1,7 @@ -import { Alert, Box, FormControl, FormControlLabel, FormLabel, MenuItem, Radio, RadioGroup, Stack, TextField, Typography } from "@mui/material"; +import { Alert, Box, MenuItem, Stack, TextField, Typography } from "@mui/material"; import { useFormState } from "react-dom"; -import { useEffect, useState } from "react"; +import { useEffect } from "react"; import { createProxyHostAction, deleteProxyHostAction, @@ -10,7 +10,7 @@ import { import { INITIAL_ACTION_STATE } from "@/src/lib/actions"; import { AccessList } from "@/src/lib/models/access-lists"; import { Certificate } from "@/src/lib/models/certificates"; -import { ProxyHost, ResponseMode } from "@/src/lib/models/proxy-hosts"; +import { ProxyHost } from "@/src/lib/models/proxy-hosts"; import { AuthentikSettings } from "@/src/lib/settings"; import { AppDialog } from "@/src/components/ui/AppDialog"; import { AuthentikFields } from "./AuthentikFields"; @@ -35,7 +35,6 @@ export function CreateHostDialog({ initialData?: ProxyHost | null; }) { const [state, formAction] = useFormState(createProxyHostAction, INITIAL_ACTION_STATE); - const [responseMode, setResponseMode] = useState(initialData?.response_mode ?? "proxy"); useEffect(() => { if (state.status === "success") { @@ -43,13 +42,6 @@ export function CreateHostDialog({ } }, [state.status, onClose]); - // Reset response mode when dialog opens/closes - useEffect(() => { - if (open) { - setResponseMode(initialData?.response_mode ?? "proxy"); - } - }, [open, initialData]); - return ( - - Response Mode - setResponseMode(e.target.value as ResponseMode)} - > - } label="Proxy to Upstream" /> - } label="Static Response" /> - - - {responseMode === "proxy" && ( - - )} - {responseMode === "static" && ( - <> - - - - )} + Managed by Caddy (Auto) {certificates.map((cert) => ( @@ -187,7 +143,6 @@ export function EditHostDialog({ accessLists: AccessList[]; }) { const [state, formAction] = useFormState(updateProxyHostAction.bind(null, host.id), INITIAL_ACTION_STATE); - const [responseMode, setResponseMode] = useState(host.response_mode); useEffect(() => { if (state.status === "success") { @@ -195,11 +150,6 @@ export function EditHostDialog({ } }, [state.status, onClose]); - // Reset response mode when host changes - useEffect(() => { - setResponseMode(host.response_mode); - }, [host]); - return ( - - Response Mode - setResponseMode(e.target.value as ResponseMode)} - > - } label="Proxy to Upstream" /> - } label="Static Response" /> - - - {responseMode === "proxy" && ( - - )} - {responseMode === "static" && ( - <> - - - - )} + Managed by Caddy (Auto) {certificates.map((cert) => ( diff --git a/src/lib/caddy.ts b/src/lib/caddy.ts index 5838fb4b..371e433e 100644 --- a/src/lib/caddy.ts +++ b/src/lib/caddy.ts @@ -47,9 +47,6 @@ type ProxyHostRow = { skip_https_hostname_validation: number; meta: string | null; enabled: number; - response_mode: string; - static_status_code: number | null; - static_response_body: string | null; }; type DnsResolverMeta = { @@ -326,58 +323,7 @@ function buildProxyRoutes( continue; } - // Handle static response mode - if (row.response_mode === "static") { - const staticHandlers: Record[] = []; - - // Build static response handler - const staticResponseHandler: Record = { - handler: "static_response", - status_code: row.static_status_code ?? 200, - body: row.static_response_body ?? "" - }; - - // Add HSTS header if enabled - if (row.hsts_enabled) { - const hstsValue = row.hsts_subdomains ? "max-age=63072000; includeSubDomains" : "max-age=63072000"; - staticResponseHandler.headers = { - "Strict-Transport-Security": [hstsValue] - }; - } - - staticHandlers.push(staticResponseHandler); - - // SSL redirect for static responses - if (row.ssl_forced) { - routes.push({ - match: [ - { - host: domains, - expression: '{http.request.scheme} == "http"' - } - ], - handle: [ - { - handler: "static_response", - status_code: 308, - headers: { - Location: ["https://{http.request.host}{http.request.uri}"] - } - } - ], - terminal: true - }); - } - - routes.push({ - match: [{ host: domains }], - handle: staticHandlers, - terminal: true - }); - continue; - } - - // Proxy mode: require upstreams + // Require upstreams const upstreams = parseJson(row.upstreams, []); if (upstreams.length === 0) { continue; @@ -977,10 +923,7 @@ async function buildCaddyDocument() { preserveHostHeader: proxyHosts.preserveHostHeader, skipHttpsHostnameValidation: proxyHosts.skipHttpsHostnameValidation, meta: proxyHosts.meta, - enabled: proxyHosts.enabled, - responseMode: proxyHosts.responseMode, - staticStatusCode: proxyHosts.staticStatusCode, - staticResponseBody: proxyHosts.staticResponseBody + enabled: proxyHosts.enabled }) .from(proxyHosts), db @@ -1029,10 +972,7 @@ async function buildCaddyDocument() { preserve_host_header: h.preserveHostHeader ? 1 : 0, skip_https_hostname_validation: h.skipHttpsHostnameValidation ? 1 : 0, meta: h.meta, - enabled: h.enabled ? 1 : 0, - response_mode: h.responseMode, - static_status_code: h.staticStatusCode, - static_response_body: h.staticResponseBody + enabled: h.enabled ? 1 : 0 })); const redirectHostRows: RedirectHostRow[] = redirectHostRecords.map((h) => ({ diff --git a/src/lib/db/schema.ts b/src/lib/db/schema.ts index 8036951e..5b200050 100644 --- a/src/lib/db/schema.ts +++ b/src/lib/db/schema.ts @@ -147,12 +147,7 @@ export const proxyHosts = sqliteTable("proxy_hosts", { updatedAt: text("updated_at").notNull(), skipHttpsHostnameValidation: integer("skip_https_hostname_validation", { mode: "boolean" }) .notNull() - .default(false), - // Response mode: 'proxy' (default) or 'static' - responseMode: text("response_mode").notNull().default("proxy"), - // Static response fields (used when responseMode is 'static') - staticStatusCode: integer("static_status_code").default(200), - staticResponseBody: text("static_response_body") + .default(false) }); export const redirectHosts = sqliteTable("redirect_hosts", { diff --git a/src/lib/models/proxy-hosts.ts b/src/lib/models/proxy-hosts.ts index b5bb4f91..2760ece7 100644 --- a/src/lib/models/proxy-hosts.ts +++ b/src/lib/models/proxy-hosts.ts @@ -176,8 +176,6 @@ type ProxyHostMeta = { dns_resolver?: DnsResolverMeta; }; -export type ResponseMode = "proxy" | "static"; - export type ProxyHost = { id: number; name: string; @@ -199,15 +197,12 @@ export type ProxyHost = { authentik: ProxyHostAuthentikConfig | null; load_balancer: LoadBalancerConfig | null; dns_resolver: DnsResolverConfig | null; - response_mode: ResponseMode; - static_status_code: number | null; - static_response_body: string | null; }; export type ProxyHostInput = { name: string; domains: string[]; - upstreams?: string[]; + upstreams: string[]; certificate_id?: number | null; access_list_id?: number | null; ssl_forced?: boolean; @@ -222,9 +217,6 @@ export type ProxyHostInput = { authentik?: ProxyHostAuthentikInput | null; load_balancer?: LoadBalancerInput | null; dns_resolver?: DnsResolverInput | null; - response_mode?: ResponseMode; - static_status_code?: number | null; - static_response_body?: string | null; }; type ProxyHostRow = typeof proxyHosts.$inferSelect; @@ -1141,7 +1133,6 @@ function dehydrateDnsResolver(config: DnsResolverConfig | null): DnsResolverMeta function parseProxyHost(row: ProxyHostRow): ProxyHost { const meta = parseMeta(row.meta ?? null); - const responseMode = row.responseMode === "static" ? "static" : "proxy"; return { id: row.id, name: row.name, @@ -1162,10 +1153,7 @@ function parseProxyHost(row: ProxyHostRow): ProxyHost { custom_pre_handlers_json: meta.custom_pre_handlers_json ?? null, authentik: hydrateAuthentik(meta.authentik), load_balancer: hydrateLoadBalancer(meta.load_balancer), - dns_resolver: hydrateDnsResolver(meta.dns_resolver), - response_mode: responseMode, - static_status_code: row.staticStatusCode ?? null, - static_response_body: row.staticResponseBody ?? null + dns_resolver: hydrateDnsResolver(meta.dns_resolver) }; } @@ -1179,22 +1167,18 @@ export async function createProxyHost(input: ProxyHostInput, actorUserId: number throw new Error("At least one domain must be specified"); } - const responseMode = input.response_mode === "static" ? "static" : "proxy"; - - // Only require upstreams in proxy mode - if (responseMode === "proxy" && (!input.upstreams || input.upstreams.length === 0)) { - throw new Error("At least one upstream must be specified for proxy mode"); + if (!input.upstreams || input.upstreams.length === 0) { + throw new Error("At least one upstream must be specified"); } const now = nowIso(); const meta = buildMeta({}, input); - const upstreams = input.upstreams ?? []; const [record] = await db .insert(proxyHosts) .values({ name: input.name.trim(), domains: JSON.stringify(Array.from(new Set(input.domains.map((d) => d.trim().toLowerCase())))), - upstreams: JSON.stringify(Array.from(new Set(upstreams.map((u) => u.trim())))), + upstreams: JSON.stringify(Array.from(new Set(input.upstreams.map((u) => u.trim())))), certificateId: input.certificate_id ?? null, accessListId: input.access_list_id ?? null, ownerUserId: actorUserId, @@ -1207,10 +1191,7 @@ export async function createProxyHost(input: ProxyHostInput, actorUserId: number skipHttpsHostnameValidation: input.skip_https_hostname_validation ?? false, enabled: input.enabled ?? true, createdAt: now, - updatedAt: now, - responseMode, - staticStatusCode: input.static_status_code ?? 200, - staticResponseBody: input.static_response_body ?? null + updatedAt: now }) .returning(); @@ -1244,10 +1225,6 @@ export async function updateProxyHost(id: number, input: Partial throw new Error("Proxy host not found"); } - const responseMode = input.response_mode !== undefined - ? (input.response_mode === "static" ? "static" : "proxy") - : existing.response_mode; - const domains = input.domains ? JSON.stringify(Array.from(new Set(input.domains))) : JSON.stringify(existing.domains); const upstreams = input.upstreams ? JSON.stringify(Array.from(new Set(input.upstreams))) : JSON.stringify(existing.upstreams); const existingMeta: ProxyHostMeta = { @@ -1276,10 +1253,7 @@ export async function updateProxyHost(id: number, input: Partial meta, skipHttpsHostnameValidation: input.skip_https_hostname_validation ?? existing.skip_https_hostname_validation, enabled: input.enabled ?? existing.enabled, - updatedAt: now, - responseMode, - staticStatusCode: input.static_status_code !== undefined ? input.static_status_code : existing.static_status_code, - staticResponseBody: input.static_response_body !== undefined ? input.static_response_body : existing.static_response_body + updatedAt: now }) .where(eq(proxyHosts.id, id));