♻️ Force disable redirects when domain is missing attached resource domain

This commit is contained in:
Fred KISSIE
2026-09-23 20:49:45 +02:00
parent ca18320ca3
commit 14fda9cec0
4 changed files with 74 additions and 62 deletions
+1
View File
@@ -2580,6 +2580,7 @@
"billingModifyLicenses": "Modify License Subscription", "billingModifyLicenses": "Modify License Subscription",
"domainNotFound": "Domain Not Found", "domainNotFound": "Domain Not Found",
"domainNotFoundDescription": "This resource is disabled because the domain no longer exists our system. Please set a new domain for this resource.", "domainNotFoundDescription": "This resource is disabled because the domain no longer exists our system. Please set a new domain for this resource.",
"rdirectDomainNotFoundDescription": "This redirect is disabled because the domain no longer exists our system. Please set a new domain for this redirect or its attached resource domain.",
"failed": "Failed", "failed": "Failed",
"createNewOrgDescription": "Create a new organization", "createNewOrgDescription": "Create a new organization",
"organization": "Organization", "organization": "Organization",
+8 -2
View File
@@ -40,7 +40,7 @@ import {
domains domains
} from "@server/db"; } from "@server/db";
import { alias } from "@server/db"; import { alias } from "@server/db";
import { and, desc, eq, inArray, isNull, or, sql } from "drizzle-orm"; import { and, desc, eq, inArray, isNull, not, or, sql } from "drizzle-orm";
import logger from "@server/logger"; import logger from "@server/logger";
export type ResourceWithAuth = { export type ResourceWithAuth = {
@@ -116,7 +116,13 @@ export async function getRedirectsByHost(
eq(redirects.enabled, true), eq(redirects.enabled, true),
// Traefik drops resource-attached redirects along with a // Traefik drops resource-attached redirects along with a
// disabled resource; do the same here. // disabled resource; do the same here.
or(isNull(redirects.resourceId), eq(resources.enabled, true)), or(
isNull(redirects.resourceId),
and(
eq(resources.enabled, true),
not(isNull(resources.domainId))
)
),
inArray(redirectHost, candidates) inArray(redirectHost, candidates)
) )
) )
+8 -1
View File
@@ -20,6 +20,7 @@ import {
inArray, inArray,
isNotNull, isNotNull,
isNull, isNull,
not,
or, or,
sql sql
} from "drizzle-orm"; } from "drizzle-orm";
@@ -367,7 +368,13 @@ export async function getTraefikConfig(
.where( .where(
and( and(
eq(redirects.enabled, true), eq(redirects.enabled, true),
or(isNull(redirects.resourceId), eq(resources.enabled, true)) or(
isNull(redirects.resourceId),
and(
eq(resources.enabled, true),
not(isNull(resources.domainId))
)
)
) )
) )
.orderBy(desc(redirects.priority), redirects.redirectId); // stable ordering .orderBy(desc(redirects.priority), redirects.redirectId); // stable ordering
+57 -59
View File
@@ -11,6 +11,10 @@
* This file is not licensed under the AGPLv3. * This file is not licensed under the AGPLv3.
*/ */
import regionalCache from "#private/lib/cache";
import privateConfig from "#private/lib/config";
import license from "#private/license/license";
import { build } from "@server/build";
import { import {
certificates, certificates,
db, db,
@@ -19,77 +23,70 @@ import {
exitNodes, exitNodes,
loginPage, loginPage,
redirects, redirects,
SiteResource,
targetHealthCheck
} from "@server/db";
import {
and,
eq,
inArray,
or,
isNull,
ne,
isNotNull,
desc,
sql
} from "drizzle-orm";
import logger from "@server/logger";
import config from "@server/lib/config";
import {
orgs,
resources, resources,
sites,
siteNetworks, siteNetworks,
SiteResource,
siteResources, siteResources,
sites,
targetHealthCheck,
targets targets
} from "@server/db"; } from "@server/db";
import {
sanitize,
encodePath,
validatePathRewriteConfig
} from "@server/lib/traefik/utils";
import privateConfig from "#private/lib/config";
import { applyPathRewriteMiddleware } from "@server/lib/traefik/middleware";
import { import {
CertificateResult, CertificateResult,
getValidCertificatesForDomains getValidCertificatesForDomains
} from "@server/lib/certificates"; } from "@server/lib/certificates";
import { build } from "@server/build"; import config from "@server/lib/config";
import license from "#private/license/license";
import regionalCache from "#private/lib/cache";
import { ResourceWithTargets } from "@server/lib/traefik/types";
import { buildWildcardTls } from "@server/lib/traefik/certResolver";
import { import {
buildHostRule, AI_GATEWAY_CLIENT_IP_MIDDLEWARE_NAME,
appendPathMatch, AI_GATEWAY_TRUST_MIDDLEWARE_RESOURCE,
computeRoutePriority AI_GATEWAY_TRUST_MIDDLEWARE_SITE_RESOURCE,
} from "@server/lib/traefik/rule"; buildAiGatewayClientIpMiddleware,
buildAiGatewayHostHeaderMiddleware,
buildAiGatewayRouterAndService,
buildAiGatewayTrustMiddlewares,
getAiGatewayHost
} from "@server/lib/traefik/aiGatewayMiddlewares";
import {
buildBrowserGatewayConfig,
buildBrowserGatewayResourcesMap
} from "@server/lib/traefik/browserGateway";
import { buildWildcardTls } from "@server/lib/traefik/certResolver";
import { buildCustomHeadersMiddleware } from "@server/lib/traefik/headersMiddleware";
import { import {
buildHttpLoadBalancerServers, buildHttpLoadBalancerServers,
buildStickySessionCookie, buildStickySessionCookie,
buildTcpUdpLoadBalancerServers, buildStickySessionIp,
buildStickySessionIp buildTcpUdpLoadBalancerServers
} from "@server/lib/traefik/loadBalancer"; } from "@server/lib/traefik/loadBalancer";
import { buildCustomHeadersMiddleware } from "@server/lib/traefik/headersMiddleware"; import { applyPathRewriteMiddleware } from "@server/lib/traefik/middleware";
import {
AI_GATEWAY_TRUST_MIDDLEWARE_RESOURCE,
AI_GATEWAY_TRUST_MIDDLEWARE_SITE_RESOURCE,
AI_GATEWAY_CLIENT_IP_MIDDLEWARE_NAME,
getAiGatewayHost,
buildAiGatewayTrustMiddlewares,
buildAiGatewayClientIpMiddleware,
buildAiGatewayHostHeaderMiddleware,
buildAiGatewayRouterAndService
} from "@server/lib/traefik/aiGatewayMiddlewares";
import {
buildBrowserGatewayResourcesMap,
buildBrowserGatewayConfig
} from "@server/lib/traefik/browserGateway";
import { buildSiteResourceAliasCertPlaceholders } from "@server/lib/traefik/siteResourceAlias";
import { import {
buildRedirectConfig, buildRedirectConfig,
RedirectRouteRow RedirectRouteRow
} from "@server/lib/traefik/redirect"; } from "@server/lib/traefik/redirect";
import {
appendPathMatch,
buildHostRule,
computeRoutePriority
} from "@server/lib/traefik/rule";
import { buildSiteResourceAliasCertPlaceholders } from "@server/lib/traefik/siteResourceAlias";
import { ResourceWithTargets } from "@server/lib/traefik/types";
import {
encodePath,
sanitize,
validatePathRewriteConfig
} from "@server/lib/traefik/utils";
import logger from "@server/logger";
import {
and,
desc,
eq,
inArray,
isNotNull,
isNull,
not,
or,
sql
} from "drizzle-orm";
const redirectHttpsMiddlewareName = "redirect-to-https"; const redirectHttpsMiddlewareName = "redirect-to-https";
const redirectToRootMiddlewareName = "redirect-to-root"; const redirectToRootMiddlewareName = "redirect-to-root";
@@ -445,7 +442,13 @@ export async function getTraefikConfig(
.where( .where(
and( and(
eq(redirects.enabled, true), eq(redirects.enabled, true),
or(isNull(redirects.resourceId), eq(resources.enabled, true)) or(
isNull(redirects.resourceId),
and(
eq(resources.enabled, true),
not(isNull(resources.domainId))
)
)
) )
) )
.orderBy(desc(redirects.priority), redirects.redirectId); // stable ordering .orderBy(desc(redirects.priority), redirects.redirectId); // stable ordering
@@ -563,11 +566,6 @@ export async function getTraefikConfig(
} }
}; };
console.dir(
{ resourcesMap, resourcesWithTargetsAndSites },
{ depth: null }
);
// get the key and the resource // get the key and the resource
for (const [, resource] of resourcesMap.entries()) { for (const [, resource] of resourcesMap.entries()) {
const targets = resource.targets; const targets = resource.targets;