Files
dokploy/packages/server/src/constants/index.ts
T
2026-08-11 15:06:02 -04:00

143 lines
4.1 KiB
TypeScript

import fs from "node:fs";
import path from "node:path";
import Docker from "dockerode";
export const IS_CLOUD = process.env.IS_CLOUD === "true";
export const DOKPLOY_DOCKER_API_VERSION =
process.env.DOKPLOY_DOCKER_API_VERSION;
export const DOKPLOY_DOCKER_HOST = process.env.DOKPLOY_DOCKER_HOST;
export const DOKPLOY_DOCKER_PORT = process.env.DOKPLOY_DOCKER_PORT
? Number(process.env.DOKPLOY_DOCKER_PORT)
: undefined;
export const CLEANUP_CRON_JOB = "50 23 * * *";
// Body size limits for the OpenAPI catch-all route (pages/api/[...trpc].ts).
const parseByteSize = (envVar: string, fallback: number): number => {
const raw = process.env[envVar];
if (!raw) return fallback;
const parsed = Number(raw);
if (!Number.isInteger(parsed) || parsed <= 0) {
console.warn(`Invalid ${envVar}="${raw}", using default ${fallback}`);
return fallback;
}
return parsed;
};
export const OPENAPI_MAX_JSON_BODY_SIZE = parseByteSize(
"OPENAPI_MAX_JSON_BODY_SIZE",
10 * 1024 * 1024, // 10mb
);
export const OPENAPI_MAX_UPLOAD_SIZE = parseByteSize(
"OPENAPI_MAX_UPLOAD_SIZE",
1024 * 1024 * 1024, // 1gb
);
type DockerSocketCandidate = {
label: string;
path: string;
};
const getDockerConfig = (): Docker => {
const versionOption = DOKPLOY_DOCKER_API_VERSION
? { version: DOKPLOY_DOCKER_API_VERSION }
: {};
// Explicit remote Docker host configuration
if (DOKPLOY_DOCKER_HOST) {
console.info(
`Using remote Docker host: ${DOKPLOY_DOCKER_HOST}${DOKPLOY_DOCKER_PORT ? `:${DOKPLOY_DOCKER_PORT}` : ""}`,
);
return new Docker({
host: DOKPLOY_DOCKER_HOST,
...(DOKPLOY_DOCKER_PORT && { port: DOKPLOY_DOCKER_PORT }),
...versionOption,
});
}
// Local socket auto-detection (Rancher Desktop, Colima, standard Docker)
const dockerSocketCandidates: Array<DockerSocketCandidate> = [];
if (process.env.DOCKER_HOST) {
dockerSocketCandidates.push({
label: "DOCKER_HOST environment variable",
path: process.env.DOCKER_HOST.replace("unix://", ""),
});
}
if (process.env.HOME) {
dockerSocketCandidates.push({
label: "Rancher Desktop socket",
path: `${process.env.HOME}/.rd/docker.sock`,
});
}
dockerSocketCandidates.push({
label: "Standard Docker socket",
path: "/var/run/docker.sock",
});
for (const candidate of dockerSocketCandidates) {
try {
if (candidate.path && fs.existsSync(candidate.path)) {
console.info(
`Using Docker socket (${candidate.label}): ${candidate.path}`,
);
return new Docker({
socketPath: candidate.path,
...versionOption,
});
}
} catch (e) {
console.info(
`Docker socket initialization failed for ${candidate.label} (${candidate.path}): ${e instanceof Error ? e.message : "Unknown error"}`,
);
}
}
console.info(
"Using default Docker configuration. You can set the DOCKER_HOST environment variable to specify a custom Docker socket path.",
);
return new Docker({ ...versionOption });
};
// Igual que db: el módulo se evalúa una vez por copia bundleada, el cache
// evita crear un cliente (y loguear la detección del socket) por cada una.
const globalForDocker = globalThis as unknown as {
docker?: Docker;
};
if (!globalForDocker.docker) {
globalForDocker.docker = getDockerConfig();
}
export const docker = globalForDocker.docker;
export const paths = (isServer = false) => {
const BASE_PATH =
isServer || process.env.NODE_ENV === "production"
? "/etc/dokploy"
: path.join(process.cwd(), ".docker");
const MAIN_TRAEFIK_PATH = `${BASE_PATH}/traefik`;
const DYNAMIC_TRAEFIK_PATH = `${MAIN_TRAEFIK_PATH}/dynamic`;
return {
BASE_PATH,
MAIN_TRAEFIK_PATH,
DYNAMIC_TRAEFIK_PATH,
LOGS_PATH: `${BASE_PATH}/logs`,
APPLICATIONS_PATH: `${BASE_PATH}/applications`,
COMPOSE_PATH: `${BASE_PATH}/compose`,
SSH_PATH: `${BASE_PATH}/ssh`,
CERTIFICATES_PATH: `${DYNAMIC_TRAEFIK_PATH}/certificates`,
MONITORING_PATH: `${BASE_PATH}/monitoring`,
REGISTRY_PATH: `${BASE_PATH}/registry`,
SCHEDULES_PATH: `${BASE_PATH}/schedules`,
VOLUME_BACKUPS_PATH: `${BASE_PATH}/volume-backups`,
VOLUME_BACKUP_LOCK_PATH: `${BASE_PATH}/volume-backup-lock`,
PATCH_REPOS_PATH: `${BASE_PATH}/patch-repos`,
};
};