traefik config update for custom Cert Resolver

This commit is contained in:
Pallavi Kumari
2025-10-07 00:37:54 +05:30
parent d30e0a3c51
commit 2f1aec02f0
4 changed files with 77 additions and 13 deletions

View File

@@ -19,7 +19,7 @@ export const domains = pgTable("domains", {
verified: boolean("verified").notNull().default(false),
failed: boolean("failed").notNull().default(false),
tries: integer("tries").notNull().default(0),
certResolver: varchar("certResolver").default("letsencrypt"),
certResolver: varchar("certResolver"),
customCertResolver: varchar("customCertResolver")
});

View File

@@ -12,7 +12,7 @@ export const domains = sqliteTable("domains", {
verified: integer("verified", { mode: "boolean" }).notNull().default(false),
failed: integer("failed", { mode: "boolean" }).notNull().default(false),
tries: integer("tries").notNull().default(0),
certResolver: text("certResolver").default("letsencrypt"),
certResolver: text("certResolver"),
customCertResolver: text("customCertResolver")
});

View File

@@ -51,6 +51,7 @@ export const configSchema = z
.nonempty("base_domain must not be empty")
.transform((url) => url.toLowerCase()),
cert_resolver: z.string().optional().default("letsencrypt"),
custom_cert_resolver: z.string().optional(),
prefer_wildcard_cert: z.boolean().optional().default(false)
})
)
@@ -187,6 +188,7 @@ export const configSchema = z
https_entrypoint: z.string().optional().default("websecure"),
additional_middlewares: z.array(z.string()).optional(),
cert_resolver: z.string().optional().default("letsencrypt"),
custom_cert_resolver: z.string().optional(),
prefer_wildcard_cert: z.boolean().optional().default(false),
certificates_path: z.string().default("/var/certificates"),
monitor_interval: z.number().default(5000),

View File

@@ -1,4 +1,4 @@
import { db, targetHealthCheck } from "@server/db";
import { db, targetHealthCheck, domains } from "@server/db";
import {
and,
eq,
@@ -75,11 +75,15 @@ export async function getTraefikConfig(
siteType: sites.type,
siteOnline: sites.online,
subnet: sites.subnet,
exitNodeId: sites.exitNodeId
exitNodeId: sites.exitNodeId,
// Domain cert resolver fields
domainCertResolver: domains.certResolver,
domainCustomCertResolver: domains.customCertResolver
})
.from(sites)
.innerJoin(targets, eq(targets.siteId, sites.siteId))
.innerJoin(resources, eq(resources.resourceId, targets.resourceId))
.leftJoin(domains, eq(domains.domainId, resources.domainId))
.leftJoin(
targetHealthCheck,
eq(targetHealthCheck.targetId, targets.targetId)
@@ -161,7 +165,10 @@ export async function getTraefikConfig(
pathMatchType: row.pathMatchType, // the targets will all have the same pathMatchType
rewritePath: row.rewritePath,
rewritePathType: row.rewritePathType,
priority: priority // may be null, we fallback later
priority: priority,
// Store domain cert resolver fields
domainCertResolver: row.domainCertResolver,
domainCustomCertResolver: row.domainCustomCertResolver
});
}
@@ -242,18 +249,73 @@ export async function getTraefikConfig(
const configDomain = config.getDomain(resource.domainId);
let certResolver: string, preferWildcardCert: boolean;
if (!configDomain) {
certResolver = config.getRawConfig().traefik.cert_resolver;
preferWildcardCert =
config.getRawConfig().traefik.prefer_wildcard_cert;
let certResolverFromConfig: string | undefined;
let preferWildcardCert = false;
const rawTraefikCfg = config.getRawConfig().traefik || {};
const globalDefaultResolver: string | undefined = rawTraefikCfg.cert_resolver;
const availableResolvers = rawTraefikCfg.custom_cert_resolver
? Object.keys(rawTraefikCfg.custom_cert_resolver)
: [];
// Priority 1: Read from YAML config (if exists)
if (configDomain) {
certResolverFromConfig =
configDomain.cert_resolver ??
configDomain.custom_cert_resolver;
preferWildcardCert = !!(configDomain.prefer_wildcard_cert);
}
// Priority 2: Override with database domain settings (if exists)
let finalCertResolver: string | undefined;
let finalCustomCertResolver: string | undefined;
if (resource.domainCertResolver) {
finalCertResolver = resource.domainCertResolver;
if (resource.domainCertResolver === "custom" && resource.domainCustomCertResolver) {
finalCustomCertResolver = resource.domainCustomCertResolver;
}
} else {
certResolver = configDomain.cert_resolver;
preferWildcardCert = configDomain.prefer_wildcard_cert;
// Fall back to config
finalCertResolver = certResolverFromConfig;
}
// Resolve the final resolver name
let resolverName: string | undefined;
if (finalCertResolver) {
if (finalCertResolver === "custom") {
// Check database custom resolver first, then config
const customResolver = finalCustomCertResolver || configDomain?.custom_cert_resolver;
if (customResolver && typeof customResolver === "string" && customResolver.trim()) {
resolverName = customResolver.trim();
} else {
resolverName = globalDefaultResolver;
logger.warn(
`Domain ${resource.domainId} requested custom cert resolver but none set; falling back to global resolver ${resolverName}`
);
}
} else {
// Validate against available resolvers
if (
availableResolvers.length === 0 ||
availableResolvers.includes(finalCertResolver)
) {
resolverName = finalCertResolver;
} else {
logger.warn(
`Unknown cert resolver "${finalCertResolver}" for domain ${resource.domainId}; falling back to global resolver.`
);
resolverName = globalDefaultResolver;
}
}
} else {
resolverName = globalDefaultResolver;
}
const tls = {
certResolver: certResolver,
certResolver: resolverName,
...(preferWildcardCert
? {
domains: [