mirror of
https://github.com/andwati/dokploy.git
synced 2026-10-18 03:02:56 +00:00
Merge branch 'canary' into feat/scaleway-secret-manager
This commit is contained in:
@@ -56,6 +56,7 @@ export const domains = pgTable("domain", {
|
||||
stripPath: boolean("stripPath").notNull().default(false),
|
||||
middlewares: text("middlewares").array().default(sql`ARRAY[]::text[]`),
|
||||
forwardAuthEnabled: boolean("forwardAuthEnabled").notNull().default(false),
|
||||
enabled: boolean("enabled").notNull().default(true),
|
||||
});
|
||||
|
||||
export const domainsRelations = relations(domains, ({ one }) => ({
|
||||
@@ -129,5 +130,6 @@ export const apiUpdateDomain = createSchema
|
||||
stripPath: true,
|
||||
middlewares: true,
|
||||
forwardAuthEnabled: true,
|
||||
enabled: true,
|
||||
})
|
||||
.merge(createSchema.pick({ domainId: true }).required());
|
||||
|
||||
@@ -20,7 +20,7 @@ export const TRAEFIK_PORT =
|
||||
Number.parseInt(process.env.TRAEFIK_PORT!, 10) || 80;
|
||||
export const TRAEFIK_HTTP3_PORT =
|
||||
Number.parseInt(process.env.TRAEFIK_HTTP3_PORT!, 10) || 443;
|
||||
export const TRAEFIK_VERSION = process.env.TRAEFIK_VERSION || "3.6.7";
|
||||
export const TRAEFIK_VERSION = process.env.TRAEFIK_VERSION || "3.6.25";
|
||||
|
||||
export interface TraefikOptions {
|
||||
env?: string[];
|
||||
|
||||
@@ -170,6 +170,32 @@ export const applyComposeFilePatch = async (
|
||||
}
|
||||
};
|
||||
|
||||
const removeDomainLabels = (
|
||||
labels: DefinitionsService["labels"],
|
||||
appName: string,
|
||||
uniqueConfigKey: number,
|
||||
) => {
|
||||
const prefixes = [
|
||||
`traefik.http.routers.${appName}-${uniqueConfigKey}-`,
|
||||
`traefik.http.services.${appName}-${uniqueConfigKey}-`,
|
||||
`traefik.http.middlewares.stripprefix-${appName}-${uniqueConfigKey}.`,
|
||||
`traefik.http.middlewares.addprefix-${appName}-${uniqueConfigKey}.`,
|
||||
];
|
||||
const belongsToDomain = (label: string) =>
|
||||
prefixes.some((prefix) => label.startsWith(prefix));
|
||||
|
||||
if (Array.isArray(labels)) {
|
||||
return labels.filter((label) => !belongsToDomain(label));
|
||||
}
|
||||
if (labels) {
|
||||
return Object.fromEntries(
|
||||
Object.entries(labels).filter(([label]) => !belongsToDomain(label)),
|
||||
);
|
||||
}
|
||||
|
||||
return labels;
|
||||
};
|
||||
|
||||
export const addDomainToCompose = async (
|
||||
compose: Compose,
|
||||
domains: Domain[],
|
||||
@@ -203,6 +229,24 @@ export const addDomainToCompose = async (
|
||||
}
|
||||
|
||||
for (const domain of domains) {
|
||||
for (const service of Object.values(result.services ?? {})) {
|
||||
if (compose.composeType === "docker-compose") {
|
||||
service.labels = removeDomainLabels(
|
||||
service.labels,
|
||||
appName,
|
||||
domain.uniqueConfigKey,
|
||||
);
|
||||
} else if (service.deploy) {
|
||||
service.deploy.labels = removeDomainLabels(
|
||||
service.deploy.labels,
|
||||
appName,
|
||||
domain.uniqueConfigKey,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const domain of domains.filter((d) => d.enabled)) {
|
||||
const { serviceName, https } = domain;
|
||||
if (!serviceName) {
|
||||
throw new Error(`Domain "${domain.host}" is missing a service name`);
|
||||
@@ -242,33 +286,31 @@ export const addDomainToCompose = async (
|
||||
labels = result.services[serviceName].deploy.labels;
|
||||
}
|
||||
|
||||
const networkLabel =
|
||||
compose.composeType === "docker-compose"
|
||||
? "traefik.docker.network"
|
||||
: "traefik.swarm.network";
|
||||
const networkName = compose.isolatedDeployment
|
||||
? compose.suffix || compose.appName
|
||||
: "dokploy-network";
|
||||
|
||||
if (Array.isArray(labels)) {
|
||||
if (!labels.includes("traefik.enable=true")) {
|
||||
labels.unshift("traefik.enable=true");
|
||||
}
|
||||
labels.unshift(...httpLabels);
|
||||
if (!compose.isolatedDeployment) {
|
||||
if (compose.composeType === "docker-compose") {
|
||||
if (!labels.includes("traefik.docker.network=dokploy-network")) {
|
||||
labels.unshift("traefik.docker.network=dokploy-network");
|
||||
}
|
||||
} else {
|
||||
// Stack Case
|
||||
if (!labels.includes("traefik.swarm.network=dokploy-network")) {
|
||||
labels.unshift("traefik.swarm.network=dokploy-network");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const isolatedNetwork = compose.suffix || compose.appName;
|
||||
if (compose.composeType === "docker-compose") {
|
||||
if (!labels.includes(`traefik.docker.network=${isolatedNetwork}`)) {
|
||||
labels.unshift(`traefik.docker.network=${isolatedNetwork}`);
|
||||
}
|
||||
} else {
|
||||
if (!labels.includes(`traefik.swarm.network=${isolatedNetwork}`)) {
|
||||
labels.unshift(`traefik.swarm.network=${isolatedNetwork}`);
|
||||
}
|
||||
}
|
||||
const networkLabelEntry = `${networkLabel}=${networkName}`;
|
||||
if (!labels.includes(networkLabelEntry)) {
|
||||
labels.unshift(networkLabelEntry);
|
||||
}
|
||||
} else if (labels) {
|
||||
labels["traefik.enable"] = "true";
|
||||
labels[networkLabel] = networkName;
|
||||
for (const label of httpLabels) {
|
||||
const separatorIndex = label.indexOf("=");
|
||||
labels[label.slice(0, separatorIndex)] = label.slice(
|
||||
separatorIndex + 1,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,15 @@ import { createPathMiddlewares, removePathMiddlewares } from "./middleware";
|
||||
|
||||
export const manageDomain = async (app: ApplicationNested, domain: Domain) => {
|
||||
const { appName } = app;
|
||||
|
||||
// A disabled domain keeps its configuration in the database but must never
|
||||
// expose a traefik router. Guarding here covers every caller (create, update,
|
||||
// forward-auth, toggle) so a disabled domain can't be revived from any path.
|
||||
if (!domain.enabled) {
|
||||
await removeDomain(app, domain.uniqueConfigKey);
|
||||
return;
|
||||
}
|
||||
|
||||
let config: FileConfig;
|
||||
|
||||
if (app.serverId) {
|
||||
|
||||
Reference in New Issue
Block a user