mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
Merge branch 'canary' of github.com:Dokploy/dokploy into feat/condition-certificate
This commit is contained in:
187
__test__/traefik/traefik.test.ts
Normal file
187
__test__/traefik/traefik.test.ts
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
import type { Domain } from "@/server/api/services/domain";
|
||||||
|
import type { Redirect } from "@/server/api/services/redirect";
|
||||||
|
import type { ApplicationNested } from "@/server/utils/builders";
|
||||||
|
import { createRouterConfig } from "@/server/utils/traefik/domain";
|
||||||
|
import { expect, test } from "vitest";
|
||||||
|
|
||||||
|
const baseApp: ApplicationNested = {
|
||||||
|
applicationId: "",
|
||||||
|
applicationStatus: "done",
|
||||||
|
appName: "",
|
||||||
|
autoDeploy: true,
|
||||||
|
branch: null,
|
||||||
|
buildArgs: null,
|
||||||
|
buildPath: "/",
|
||||||
|
buildType: "nixpacks",
|
||||||
|
command: null,
|
||||||
|
cpuLimit: null,
|
||||||
|
cpuReservation: null,
|
||||||
|
createdAt: "",
|
||||||
|
customGitBranch: "",
|
||||||
|
customGitBuildPath: "",
|
||||||
|
customGitSSHKey: "",
|
||||||
|
customGitUrl: "",
|
||||||
|
description: "",
|
||||||
|
dockerfile: null,
|
||||||
|
dockerImage: null,
|
||||||
|
dropBuildPath: null,
|
||||||
|
enabled: null,
|
||||||
|
env: null,
|
||||||
|
healthCheckSwarm: null,
|
||||||
|
labelsSwarm: null,
|
||||||
|
memoryLimit: null,
|
||||||
|
memoryReservation: null,
|
||||||
|
modeSwarm: null,
|
||||||
|
mounts: [],
|
||||||
|
name: "",
|
||||||
|
networkSwarm: null,
|
||||||
|
owner: null,
|
||||||
|
password: null,
|
||||||
|
placementSwarm: null,
|
||||||
|
ports: [],
|
||||||
|
projectId: "",
|
||||||
|
redirects: [],
|
||||||
|
refreshToken: "",
|
||||||
|
registry: null,
|
||||||
|
registryId: null,
|
||||||
|
replicas: 1,
|
||||||
|
repository: null,
|
||||||
|
restartPolicySwarm: null,
|
||||||
|
rollbackConfigSwarm: null,
|
||||||
|
security: [],
|
||||||
|
sourceType: "git",
|
||||||
|
subtitle: null,
|
||||||
|
title: null,
|
||||||
|
updateConfigSwarm: null,
|
||||||
|
username: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
const baseDomain: Domain = {
|
||||||
|
applicationId: "",
|
||||||
|
certificateType: "none",
|
||||||
|
createdAt: "",
|
||||||
|
domainId: "",
|
||||||
|
host: "",
|
||||||
|
https: false,
|
||||||
|
path: null,
|
||||||
|
port: null,
|
||||||
|
uniqueConfigKey: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
const baseRedirect: Redirect = {
|
||||||
|
redirectId: "",
|
||||||
|
regex: "",
|
||||||
|
replacement: "",
|
||||||
|
permanent: false,
|
||||||
|
uniqueConfigKey: 1,
|
||||||
|
createdAt: "",
|
||||||
|
applicationId: "",
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Middlewares */
|
||||||
|
|
||||||
|
test("Web entrypoint on http domain", async () => {
|
||||||
|
const router = await createRouterConfig(
|
||||||
|
baseApp,
|
||||||
|
{ ...baseDomain, https: false },
|
||||||
|
"web",
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(router.middlewares).not.toContain("redirect-to-https");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Web entrypoint on http domain with redirect", async () => {
|
||||||
|
const router = await createRouterConfig(
|
||||||
|
{
|
||||||
|
...baseApp,
|
||||||
|
appName: "test",
|
||||||
|
redirects: [{ ...baseRedirect, uniqueConfigKey: 1 }],
|
||||||
|
},
|
||||||
|
{ ...baseDomain, https: false },
|
||||||
|
"web",
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(router.middlewares).not.toContain("redirect-to-https");
|
||||||
|
expect(router.middlewares).toContain("redirect-test-1");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Web entrypoint on http domain with multiple redirect", async () => {
|
||||||
|
const router = await createRouterConfig(
|
||||||
|
{
|
||||||
|
...baseApp,
|
||||||
|
appName: "test",
|
||||||
|
redirects: [
|
||||||
|
{ ...baseRedirect, uniqueConfigKey: 1 },
|
||||||
|
{ ...baseRedirect, uniqueConfigKey: 2 },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ ...baseDomain, https: false },
|
||||||
|
"web",
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(router.middlewares).not.toContain("redirect-to-https");
|
||||||
|
expect(router.middlewares).toContain("redirect-test-1");
|
||||||
|
expect(router.middlewares).toContain("redirect-test-2");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Web entrypoint on https domain", async () => {
|
||||||
|
const router = await createRouterConfig(
|
||||||
|
baseApp,
|
||||||
|
{ ...baseDomain, https: true },
|
||||||
|
"web",
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(router.middlewares).toContain("redirect-to-https");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Web entrypoint on https domain with redirect", async () => {
|
||||||
|
const router = await createRouterConfig(
|
||||||
|
{
|
||||||
|
...baseApp,
|
||||||
|
appName: "test",
|
||||||
|
redirects: [{ ...baseRedirect, uniqueConfigKey: 1 }],
|
||||||
|
},
|
||||||
|
{ ...baseDomain, https: true },
|
||||||
|
"web",
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(router.middlewares).toContain("redirect-to-https");
|
||||||
|
expect(router.middlewares).not.toContain("redirect-test-1");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Websecure entrypoint on https domain", async () => {
|
||||||
|
const router = await createRouterConfig(
|
||||||
|
baseApp,
|
||||||
|
{ ...baseDomain, https: true },
|
||||||
|
"websecure",
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(router.middlewares).not.toContain("redirect-to-https");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Websecure entrypoint on https domain with redirect", async () => {
|
||||||
|
const router = await createRouterConfig(
|
||||||
|
{
|
||||||
|
...baseApp,
|
||||||
|
appName: "test",
|
||||||
|
redirects: [{ ...baseRedirect, uniqueConfigKey: 1 }],
|
||||||
|
},
|
||||||
|
{ ...baseDomain, https: true },
|
||||||
|
"websecure",
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(router.middlewares).not.toContain("redirect-to-https");
|
||||||
|
expect(router.middlewares).toContain("redirect-test-1");
|
||||||
|
});
|
||||||
|
|
||||||
|
/** Certificates */
|
||||||
|
|
||||||
|
test("CertificateType on websecure entrypoint", async () => {
|
||||||
|
const router = await createRouterConfig(
|
||||||
|
baseApp,
|
||||||
|
{ ...baseDomain, certificateType: "letsencrypt" },
|
||||||
|
"websecure",
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(router.tls?.certResolver).toBe("letsencrypt");
|
||||||
|
});
|
||||||
@@ -13,12 +13,27 @@ export const manageDomain = async (app: ApplicationNested, domain: Domain) => {
|
|||||||
const config: FileConfig = loadOrCreateConfig(appName);
|
const config: FileConfig = loadOrCreateConfig(appName);
|
||||||
const serviceName = `${appName}-service-${domain.uniqueConfigKey}`;
|
const serviceName = `${appName}-service-${domain.uniqueConfigKey}`;
|
||||||
const routerName = `${appName}-router-${domain.uniqueConfigKey}`;
|
const routerName = `${appName}-router-${domain.uniqueConfigKey}`;
|
||||||
|
const routerNameSecure = `${appName}-router-websecure-${domain.uniqueConfigKey}`;
|
||||||
|
|
||||||
config.http = config.http || { routers: {}, services: {} };
|
config.http = config.http || { routers: {}, services: {} };
|
||||||
config.http.routers = config.http.routers || {};
|
config.http.routers = config.http.routers || {};
|
||||||
config.http.services = config.http.services || {};
|
config.http.services = config.http.services || {};
|
||||||
|
|
||||||
config.http.routers[routerName] = await createRouterConfig(app, domain);
|
config.http.routers[routerName] = await createRouterConfig(
|
||||||
|
app,
|
||||||
|
domain,
|
||||||
|
"web",
|
||||||
|
);
|
||||||
|
|
||||||
|
if (domain.https) {
|
||||||
|
config.http.routers[routerNameSecure] = await createRouterConfig(
|
||||||
|
app,
|
||||||
|
domain,
|
||||||
|
"websecure",
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
delete config.http.routers[routerNameSecure];
|
||||||
|
}
|
||||||
|
|
||||||
config.http.services[serviceName] = createServiceConfig(appName, domain);
|
config.http.services[serviceName] = createServiceConfig(appName, domain);
|
||||||
writeTraefikConfig(config, appName);
|
writeTraefikConfig(config, appName);
|
||||||
@@ -28,10 +43,15 @@ export const removeDomain = async (appName: string, uniqueKey: number) => {
|
|||||||
const config: FileConfig = loadOrCreateConfig(appName);
|
const config: FileConfig = loadOrCreateConfig(appName);
|
||||||
|
|
||||||
const routerKey = `${appName}-router-${uniqueKey}`;
|
const routerKey = `${appName}-router-${uniqueKey}`;
|
||||||
|
const routerSecureKey = `${appName}-router-websecure-${uniqueKey}`;
|
||||||
|
|
||||||
const serviceKey = `${appName}-service-${uniqueKey}`;
|
const serviceKey = `${appName}-service-${uniqueKey}`;
|
||||||
if (config.http?.routers?.[routerKey]) {
|
if (config.http?.routers?.[routerKey]) {
|
||||||
delete config.http.routers[routerKey];
|
delete config.http.routers[routerKey];
|
||||||
}
|
}
|
||||||
|
if (config.http?.routers?.[routerSecureKey]) {
|
||||||
|
delete config.http.routers[routerSecureKey];
|
||||||
|
}
|
||||||
if (config.http?.services?.[serviceKey]) {
|
if (config.http?.services?.[serviceKey]) {
|
||||||
delete config.http.services[serviceKey];
|
delete config.http.services[serviceKey];
|
||||||
}
|
}
|
||||||
@@ -47,7 +67,11 @@ export const removeDomain = async (appName: string, uniqueKey: number) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const createRouterConfig = async (app: ApplicationNested, domain: Domain) => {
|
export const createRouterConfig = async (
|
||||||
|
app: ApplicationNested,
|
||||||
|
domain: Domain,
|
||||||
|
entryPoint: "web" | "websecure",
|
||||||
|
) => {
|
||||||
const { appName, redirects, security } = app;
|
const { appName, redirects, security } = app;
|
||||||
const { certificateType } = domain;
|
const { certificateType } = domain;
|
||||||
|
|
||||||
@@ -56,32 +80,33 @@ const createRouterConfig = async (app: ApplicationNested, domain: Domain) => {
|
|||||||
rule: `Host(\`${host}\`)${path ? ` && PathPrefix(\`${path}\`)` : ""}`,
|
rule: `Host(\`${host}\`)${path ? ` && PathPrefix(\`${path}\`)` : ""}`,
|
||||||
service: `${appName}-service-${uniqueConfigKey}`,
|
service: `${appName}-service-${uniqueConfigKey}`,
|
||||||
middlewares: [],
|
middlewares: [],
|
||||||
entryPoints: https
|
entryPoints: [entryPoint],
|
||||||
? ["web", ...(process.env.NODE_ENV === "production" ? ["websecure"] : [])]
|
|
||||||
: ["web"],
|
|
||||||
tls: {},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (https) {
|
if (entryPoint === "web" && https) {
|
||||||
routerConfig.middlewares = ["redirect-to-https"];
|
routerConfig.middlewares = ["redirect-to-https"];
|
||||||
}
|
}
|
||||||
|
|
||||||
// redirects
|
if ((entryPoint === "websecure" && https) || !https) {
|
||||||
for (const redirect of redirects) {
|
// redirects
|
||||||
const middlewareName = `redirect-${appName}-${redirect.uniqueConfigKey}`;
|
for (const redirect of redirects) {
|
||||||
routerConfig.middlewares?.push(middlewareName);
|
const middlewareName = `redirect-${appName}-${redirect.uniqueConfigKey}`;
|
||||||
|
routerConfig.middlewares?.push(middlewareName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// security
|
||||||
|
if (security.length > 0) {
|
||||||
|
const middlewareName = `auth-${appName}`;
|
||||||
|
routerConfig.middlewares?.push(middlewareName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// security
|
if (entryPoint === "websecure") {
|
||||||
if (security.length > 0) {
|
if (certificateType === "letsencrypt") {
|
||||||
const middlewareName = `auth-${appName}`;
|
routerConfig.tls = { certResolver: "letsencrypt" };
|
||||||
routerConfig.middlewares?.push(middlewareName);
|
} else if (certificateType === "none") {
|
||||||
}
|
routerConfig.tls = undefined;
|
||||||
|
}
|
||||||
if (certificateType === "letsencrypt") {
|
|
||||||
routerConfig.tls = { certResolver: "letsencrypt" };
|
|
||||||
} else if (certificateType === "none") {
|
|
||||||
routerConfig.tls = undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return routerConfig;
|
return routerConfig;
|
||||||
|
|||||||
Reference in New Issue
Block a user