mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-10-15 13:21:11 +00:00
06a349152f
- Modified the `writeConfigRemote` function to encode the Traefik configuration in base64 before saving it to the remote YAML file. - This change ensures that the configuration is correctly handled and prevents potential issues with special characters in the config.
292 lines
7.7 KiB
TypeScript
292 lines
7.7 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 { execAsync, 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`);
|
|
const command = `rm -f ${configPath}`;
|
|
|
|
if (serverId) {
|
|
await execAsyncRemote(serverId, command);
|
|
} else {
|
|
await execAsync(command);
|
|
}
|
|
} catch (error) {
|
|
console.error(`Error removing traefik config for ${appName}:`, error);
|
|
}
|
|
};
|
|
|
|
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 -f ${configPath}`);
|
|
} catch (error) {
|
|
console.error(
|
|
`Error removing remote traefik config for ${appName}:`,
|
|
error,
|
|
);
|
|
}
|
|
};
|
|
|
|
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`);
|
|
const encoded = encodeBase64(traefikConfig);
|
|
await execAsyncRemote(
|
|
serverId,
|
|
`echo "${encoded}" | base64 -d > "${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,
|
|
},
|
|
});
|