mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-06-19 06:05:25 +02:00
- Added a test case to ensure Dokploy dashboard requests are filtered out correctly. - Updated the logs processing logic to exclude both Dokploy service app and dashboard requests, improving log clarity and relevance.
285 lines
7.5 KiB
TypeScript
285 lines
7.5 KiB
TypeScript
import fs, { createReadStream, writeFileSync } from "node:fs";
|
|
import path from "node:path";
|
|
import { createInterface } from "node:readline";
|
|
import { paths } from "@dokploy/server/constants";
|
|
import type { Domain } from "@dokploy/server/services/domain";
|
|
import { parse, stringify } from "yaml";
|
|
import { encodeBase64 } from "../docker/utils";
|
|
import { execAsyncRemote } from "../process/execAsync";
|
|
import type { FileConfig, HttpLoadBalancerService } from "./file-types";
|
|
|
|
export const createTraefikConfig = (appName: string) => {
|
|
const defaultPort = 3000;
|
|
const serviceURLDefault = `http://${appName}:${defaultPort}`;
|
|
const domainDefault = `Host(\`${appName}.docker.localhost\`)`;
|
|
const config: FileConfig = {
|
|
http: {
|
|
routers: {
|
|
...(process.env.NODE_ENV === "production"
|
|
? {}
|
|
: {
|
|
[`${appName}-router-1`]: {
|
|
rule: domainDefault,
|
|
service: `${appName}-service-1`,
|
|
entryPoints: ["web"],
|
|
},
|
|
}),
|
|
},
|
|
|
|
services: {
|
|
...(process.env.NODE_ENV === "production"
|
|
? {}
|
|
: {
|
|
[`${appName}-service-1`]: {
|
|
loadBalancer: {
|
|
servers: [{ url: serviceURLDefault }],
|
|
passHostHeader: true,
|
|
},
|
|
},
|
|
}),
|
|
},
|
|
},
|
|
};
|
|
const yamlStr = stringify(config);
|
|
const { DYNAMIC_TRAEFIK_PATH } = paths();
|
|
fs.mkdirSync(DYNAMIC_TRAEFIK_PATH, { recursive: true });
|
|
writeFileSync(
|
|
path.join(DYNAMIC_TRAEFIK_PATH, `${appName}.yml`),
|
|
yamlStr,
|
|
"utf8",
|
|
);
|
|
};
|
|
|
|
export const removeTraefikConfig = async (
|
|
appName: string,
|
|
serverId?: string | null,
|
|
) => {
|
|
try {
|
|
const { DYNAMIC_TRAEFIK_PATH } = paths(!!serverId);
|
|
const configPath = path.join(DYNAMIC_TRAEFIK_PATH, `${appName}.yml`);
|
|
|
|
if (serverId) {
|
|
await execAsyncRemote(serverId, `rm ${configPath}`);
|
|
} else {
|
|
if (fs.existsSync(configPath)) {
|
|
await fs.promises.unlink(configPath);
|
|
}
|
|
}
|
|
if (fs.existsSync(configPath)) {
|
|
await fs.promises.unlink(configPath);
|
|
}
|
|
} catch {}
|
|
};
|
|
|
|
export const removeTraefikConfigRemote = async (
|
|
appName: string,
|
|
serverId: string,
|
|
) => {
|
|
try {
|
|
const { DYNAMIC_TRAEFIK_PATH } = paths(true);
|
|
const configPath = path.join(DYNAMIC_TRAEFIK_PATH, `${appName}.yml`);
|
|
await execAsyncRemote(serverId, `rm ${configPath}`);
|
|
} catch {}
|
|
};
|
|
|
|
export const loadOrCreateConfig = (appName: string): FileConfig => {
|
|
const { DYNAMIC_TRAEFIK_PATH } = paths();
|
|
const configPath = path.join(DYNAMIC_TRAEFIK_PATH, `${appName}.yml`);
|
|
if (fs.existsSync(configPath)) {
|
|
const yamlStr = fs.readFileSync(configPath, "utf8");
|
|
const parsedConfig = (parse(yamlStr) as FileConfig) || {
|
|
http: { routers: {}, services: {} },
|
|
};
|
|
return parsedConfig;
|
|
}
|
|
return { http: { routers: {}, services: {} } };
|
|
};
|
|
|
|
export const loadOrCreateConfigRemote = async (
|
|
serverId: string,
|
|
appName: string,
|
|
) => {
|
|
const { DYNAMIC_TRAEFIK_PATH } = paths(true);
|
|
const fileConfig: FileConfig = { http: { routers: {}, services: {} } };
|
|
const configPath = path.join(DYNAMIC_TRAEFIK_PATH, `${appName}.yml`);
|
|
try {
|
|
const { stdout } = await execAsyncRemote(serverId, `cat ${configPath}`);
|
|
|
|
if (!stdout) return fileConfig;
|
|
|
|
const parsedConfig = (parse(stdout) as FileConfig) || {
|
|
http: { routers: {}, services: {} },
|
|
};
|
|
return parsedConfig;
|
|
} catch {
|
|
return fileConfig;
|
|
}
|
|
};
|
|
|
|
export const readConfig = (appName: string) => {
|
|
const { DYNAMIC_TRAEFIK_PATH } = paths();
|
|
const configPath = path.join(DYNAMIC_TRAEFIK_PATH, `${appName}.yml`);
|
|
if (fs.existsSync(configPath)) {
|
|
const yamlStr = fs.readFileSync(configPath, "utf8");
|
|
return yamlStr;
|
|
}
|
|
return null;
|
|
};
|
|
|
|
export const readRemoteConfig = async (serverId: string, appName: string) => {
|
|
const { DYNAMIC_TRAEFIK_PATH } = paths(true);
|
|
const configPath = path.join(DYNAMIC_TRAEFIK_PATH, `${appName}.yml`);
|
|
try {
|
|
const { stdout } = await execAsyncRemote(serverId, `cat ${configPath}`);
|
|
if (!stdout) return null;
|
|
return stdout;
|
|
} catch {
|
|
return null;
|
|
}
|
|
};
|
|
|
|
export const readMonitoringConfig = async (readAll = false) => {
|
|
const { DYNAMIC_TRAEFIK_PATH } = paths();
|
|
const configPath = path.join(DYNAMIC_TRAEFIK_PATH, "access.log");
|
|
if (fs.existsSync(configPath)) {
|
|
if (!readAll) {
|
|
// Read first 500 lines using streams
|
|
let content = "";
|
|
let validCount = 0;
|
|
|
|
const fileStream = createReadStream(configPath, { encoding: "utf8" });
|
|
const readline = createInterface({
|
|
input: fileStream,
|
|
crlfDelay: Number.POSITIVE_INFINITY,
|
|
});
|
|
|
|
for await (const line of readline) {
|
|
try {
|
|
const trimmed = line.trim();
|
|
if (
|
|
trimmed !== "" &&
|
|
trimmed.startsWith("{") &&
|
|
trimmed.endsWith("}")
|
|
) {
|
|
const log = JSON.parse(trimmed);
|
|
// Exclude Dokploy service app and Dashboard requests
|
|
if (log.ServiceName !== "dokploy-service-app@file") {
|
|
content += `${line}\n`;
|
|
validCount++;
|
|
if (validCount >= 500) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} catch {
|
|
// Ignore invalid JSON
|
|
}
|
|
}
|
|
return content;
|
|
}
|
|
return fs.readFileSync(configPath, "utf8");
|
|
}
|
|
return null;
|
|
};
|
|
|
|
export const readConfigInPath = async (pathFile: string, serverId?: string) => {
|
|
const configPath = path.join(pathFile);
|
|
|
|
if (serverId) {
|
|
const { stdout } = await execAsyncRemote(serverId, `cat ${configPath}`);
|
|
if (!stdout) return null;
|
|
return stdout;
|
|
}
|
|
if (fs.existsSync(configPath)) {
|
|
const yamlStr = fs.readFileSync(configPath, "utf8");
|
|
return yamlStr;
|
|
}
|
|
return null;
|
|
};
|
|
|
|
export const writeConfig = (appName: string, traefikConfig: string) => {
|
|
try {
|
|
const { DYNAMIC_TRAEFIK_PATH } = paths();
|
|
const configPath = path.join(DYNAMIC_TRAEFIK_PATH, `${appName}.yml`);
|
|
fs.writeFileSync(configPath, traefikConfig, "utf8");
|
|
} catch (e) {
|
|
console.error("Error saving the YAML config file:", e);
|
|
}
|
|
};
|
|
|
|
export const writeConfigRemote = async (
|
|
serverId: string,
|
|
appName: string,
|
|
traefikConfig: string,
|
|
) => {
|
|
try {
|
|
const { DYNAMIC_TRAEFIK_PATH } = paths(true);
|
|
const configPath = path.join(DYNAMIC_TRAEFIK_PATH, `${appName}.yml`);
|
|
await execAsyncRemote(serverId, `echo '${traefikConfig}' > ${configPath}`);
|
|
} catch (e) {
|
|
console.error("Error saving the YAML config file:", e);
|
|
}
|
|
};
|
|
|
|
export const writeTraefikConfigInPath = async (
|
|
pathFile: string,
|
|
traefikConfig: string,
|
|
serverId?: string,
|
|
) => {
|
|
try {
|
|
const configPath = path.join(pathFile);
|
|
if (serverId) {
|
|
const encoded = encodeBase64(traefikConfig);
|
|
await execAsyncRemote(
|
|
serverId,
|
|
`echo "${encoded}" | base64 -d > "${configPath}"`,
|
|
);
|
|
} else {
|
|
fs.writeFileSync(configPath, traefikConfig, "utf8");
|
|
}
|
|
} catch (e) {
|
|
console.error("Error saving the YAML config file:", e);
|
|
}
|
|
};
|
|
|
|
export const writeTraefikConfig = (
|
|
traefikConfig: FileConfig,
|
|
appName: string,
|
|
) => {
|
|
try {
|
|
const { DYNAMIC_TRAEFIK_PATH } = paths();
|
|
const configPath = path.join(DYNAMIC_TRAEFIK_PATH, `${appName}.yml`);
|
|
const yamlStr = stringify(traefikConfig);
|
|
fs.writeFileSync(configPath, yamlStr, "utf8");
|
|
} catch (e) {
|
|
console.error("Error saving the YAML config file:", e);
|
|
}
|
|
};
|
|
|
|
export const writeTraefikConfigRemote = async (
|
|
traefikConfig: FileConfig,
|
|
appName: string,
|
|
serverId: string,
|
|
) => {
|
|
try {
|
|
const { DYNAMIC_TRAEFIK_PATH } = paths(true);
|
|
const configPath = path.join(DYNAMIC_TRAEFIK_PATH, `${appName}.yml`);
|
|
const yamlStr = stringify(traefikConfig);
|
|
await execAsyncRemote(serverId, `echo '${yamlStr}' > ${configPath}`);
|
|
} catch (e) {
|
|
console.error("Error saving the YAML config file:", e);
|
|
}
|
|
};
|
|
|
|
export const createServiceConfig = (
|
|
appName: string,
|
|
domain: Domain,
|
|
): {
|
|
loadBalancer: HttpLoadBalancerService;
|
|
} => ({
|
|
loadBalancer: {
|
|
servers: [{ url: `http://${appName}:${domain.port || 80}` }],
|
|
passHostHeader: true,
|
|
},
|
|
});
|