mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
* feat(WIP): compose implementation * feat: add volumes, networks, services name hash generate * feat: add compose config test unique * feat: add tests for each unique config * feat: implement lodash for docker compose parsing * feat: add tests for generating compose file * refactor: implement logs docker compose * refactor: composeFile set not empty * feat: implement providers for compose deployments * feat: add Files volumes to compose * feat: add stop compose button * refactor: change strategie of building compose * feat: create .env file in composepath * refactor: simplify git and github function * chore: update deps * refactor: update migrations and add badge to recognize compose type * chore: update lock yaml * refactor: use code editor * feat: add monitoring for app types * refactor: reset stats on change appName * refactor: add option to clean monitoring folder * feat: show current command that will run * feat: add prefix * fix: add missing types * refactor: add docker provider and expose by default as false * refactor: customize error page * refactor: unified deployments to be a single one * feat: add vitest to ci/cd * revert: back to initial version * refactor: add maxconcurrency vitest * refactor: add pool forks to vitest * feat: add pocketbase template * fix: update path resolution compose * removed * feat: add template pocketbase * feat: add pocketbase template * feat: add support button * feat: add plausible template * feat: add calcom template * feat: add version to each template * feat: add code editor to enviroment variables and swarm settings json * refactor: add loader when download the image * fix: use base64 to generate keys plausible * feat: add recognized domain names by enviroment compose * refactor: show alert to redeploy in each card advanced tab * refactor: add validation to prevent create compose if not have permissions * chore: add templates section to contributing * chore: add example contributing
247 lines
6.3 KiB
TypeScript
247 lines
6.3 KiB
TypeScript
import { docker, MAIN_TRAEFIK_PATH, MONITORING_PATH } from "@/server/constants";
|
|
import { adminProcedure, createTRPCRouter, protectedProcedure } from "../trpc";
|
|
import {
|
|
cleanStoppedContainers,
|
|
cleanUpDockerBuilder,
|
|
cleanUpSystemPrune,
|
|
cleanUpUnusedImages,
|
|
cleanUpUnusedVolumes,
|
|
startService,
|
|
stopService,
|
|
} from "@/server/utils/docker/utils";
|
|
import {
|
|
apiAssignDomain,
|
|
apiModifyTraefikConfig,
|
|
apiReadTraefikConfig,
|
|
apiSaveSSHKey,
|
|
apiTraefikConfig,
|
|
apiUpdateDockerCleanup,
|
|
} from "@/server/db/schema";
|
|
import { scheduledJobs, scheduleJob } from "node-schedule";
|
|
import {
|
|
readMainConfig,
|
|
updateLetsEncryptEmail,
|
|
updateServerTraefik,
|
|
writeMainConfig,
|
|
} from "@/server/utils/traefik/web-server";
|
|
import {
|
|
readConfig,
|
|
readConfigInPath,
|
|
writeConfig,
|
|
writeTraefikConfigInPath,
|
|
} from "@/server/utils/traefik/application";
|
|
import { spawnAsync } from "@/server/utils/process/spawnAsync";
|
|
import { findAdmin, updateAdmin } from "../services/admin";
|
|
import { TRPCError } from "@trpc/server";
|
|
import {
|
|
getDokployVersion,
|
|
getDokployImage,
|
|
pullLatestRelease,
|
|
readDirectory,
|
|
} from "../services/settings";
|
|
import { canAccessToTraefikFiles } from "../services/user";
|
|
import { recreateDirectory } from "@/server/utils/filesystem/directory";
|
|
|
|
export const settingsRouter = createTRPCRouter({
|
|
reloadServer: adminProcedure.mutation(async () => {
|
|
await spawnAsync("docker", [
|
|
"service",
|
|
"update",
|
|
"--force",
|
|
"--image",
|
|
getDokployImage(),
|
|
"dokploy",
|
|
]);
|
|
return true;
|
|
}),
|
|
reloadTraefik: adminProcedure.mutation(async () => {
|
|
await stopService("dokploy-traefik");
|
|
await startService("dokploy-traefik");
|
|
return true;
|
|
}),
|
|
cleanUnusedImages: adminProcedure.mutation(async () => {
|
|
await cleanUpUnusedImages();
|
|
return true;
|
|
}),
|
|
cleanUnusedVolumes: adminProcedure.mutation(async () => {
|
|
await cleanUpUnusedVolumes();
|
|
return true;
|
|
}),
|
|
cleanStoppedContainers: adminProcedure.mutation(async () => {
|
|
await cleanStoppedContainers();
|
|
return true;
|
|
}),
|
|
cleanDockerBuilder: adminProcedure.mutation(async () => {
|
|
await cleanUpDockerBuilder();
|
|
}),
|
|
cleanDockerPrune: adminProcedure.mutation(async () => {
|
|
await cleanUpSystemPrune();
|
|
await cleanUpDockerBuilder();
|
|
|
|
return true;
|
|
}),
|
|
cleanAll: adminProcedure.mutation(async () => {
|
|
await cleanUpUnusedImages();
|
|
await cleanUpDockerBuilder();
|
|
await cleanUpSystemPrune();
|
|
return true;
|
|
}),
|
|
cleanMonitoring: adminProcedure.mutation(async () => {
|
|
await recreateDirectory(MONITORING_PATH);
|
|
return true;
|
|
}),
|
|
saveSSHPrivateKey: adminProcedure
|
|
.input(apiSaveSSHKey)
|
|
.mutation(async ({ input, ctx }) => {
|
|
await updateAdmin(ctx.user.authId, {
|
|
sshPrivateKey: input.sshPrivateKey,
|
|
});
|
|
|
|
return true;
|
|
}),
|
|
assignDomainServer: adminProcedure
|
|
.input(apiAssignDomain)
|
|
.mutation(async ({ ctx, input }) => {
|
|
const admin = await updateAdmin(ctx.user.authId, {
|
|
host: input.host,
|
|
letsEncryptEmail: input.letsEncryptEmail,
|
|
certificateType: input.certificateType,
|
|
});
|
|
|
|
if (!admin) {
|
|
throw new TRPCError({
|
|
code: "NOT_FOUND",
|
|
message: "Admin not found",
|
|
});
|
|
}
|
|
|
|
updateServerTraefik(admin, input.host);
|
|
updateLetsEncryptEmail(admin.letsEncryptEmail);
|
|
return admin;
|
|
}),
|
|
cleanSSHPrivateKey: adminProcedure.mutation(async ({ ctx }) => {
|
|
await updateAdmin(ctx.user.authId, {
|
|
sshPrivateKey: null,
|
|
});
|
|
return true;
|
|
}),
|
|
updateDockerCleanup: adminProcedure
|
|
.input(apiUpdateDockerCleanup)
|
|
.mutation(async ({ input, ctx }) => {
|
|
await updateAdmin(ctx.user.authId, {
|
|
enableDockerCleanup: input.enableDockerCleanup,
|
|
});
|
|
|
|
const admin = await findAdmin();
|
|
|
|
if (admin.enableDockerCleanup) {
|
|
scheduleJob("docker-cleanup", "0 0 * * *", async () => {
|
|
console.log(
|
|
`Docker Cleanup ${new Date().toLocaleString()}] Running...`,
|
|
);
|
|
await cleanUpUnusedImages();
|
|
await cleanUpDockerBuilder();
|
|
await cleanUpSystemPrune();
|
|
});
|
|
} else {
|
|
const currentJob = scheduledJobs["docker-cleanup"];
|
|
currentJob?.cancel();
|
|
}
|
|
|
|
return true;
|
|
}),
|
|
|
|
readTraefikConfig: adminProcedure.query(() => {
|
|
const traefikConfig = readMainConfig();
|
|
return traefikConfig;
|
|
}),
|
|
|
|
updateTraefikConfig: adminProcedure
|
|
.input(apiTraefikConfig)
|
|
.mutation(async ({ input }) => {
|
|
writeMainConfig(input.traefikConfig);
|
|
return true;
|
|
}),
|
|
|
|
readWebServerTraefikConfig: adminProcedure.query(() => {
|
|
const traefikConfig = readConfig("dokploy");
|
|
return traefikConfig;
|
|
}),
|
|
updateWebServerTraefikConfig: adminProcedure
|
|
.input(apiTraefikConfig)
|
|
.mutation(async ({ input }) => {
|
|
writeConfig("dokploy", input.traefikConfig);
|
|
return true;
|
|
}),
|
|
|
|
readMiddlewareTraefikConfig: adminProcedure.query(() => {
|
|
const traefikConfig = readConfig("middlewares");
|
|
return traefikConfig;
|
|
}),
|
|
|
|
updateMiddlewareTraefikConfig: adminProcedure
|
|
.input(apiTraefikConfig)
|
|
.mutation(async ({ input }) => {
|
|
writeConfig("middlewares", input.traefikConfig);
|
|
return true;
|
|
}),
|
|
|
|
checkAndUpdateImage: adminProcedure.mutation(async () => {
|
|
return await pullLatestRelease();
|
|
}),
|
|
updateServer: adminProcedure.mutation(async () => {
|
|
await spawnAsync("docker", [
|
|
"service",
|
|
"update",
|
|
"--force",
|
|
"--image",
|
|
getDokployImage(),
|
|
"dokploy",
|
|
]);
|
|
return true;
|
|
}),
|
|
|
|
getDokployVersion: adminProcedure.query(() => {
|
|
return getDokployVersion();
|
|
}),
|
|
readDirectories: protectedProcedure.query(async ({ ctx }) => {
|
|
if (ctx.user.rol === "user") {
|
|
const canAccess = await canAccessToTraefikFiles(ctx.user.authId);
|
|
|
|
if (!canAccess) {
|
|
throw new TRPCError({ code: "UNAUTHORIZED" });
|
|
}
|
|
}
|
|
const result = readDirectory(MAIN_TRAEFIK_PATH);
|
|
return result || [];
|
|
}),
|
|
|
|
updateTraefikFile: protectedProcedure
|
|
.input(apiModifyTraefikConfig)
|
|
.mutation(async ({ input, ctx }) => {
|
|
if (ctx.user.rol === "user") {
|
|
const canAccess = await canAccessToTraefikFiles(ctx.user.authId);
|
|
|
|
if (!canAccess) {
|
|
throw new TRPCError({ code: "UNAUTHORIZED" });
|
|
}
|
|
}
|
|
writeTraefikConfigInPath(input.path, input.traefikConfig);
|
|
return true;
|
|
}),
|
|
|
|
readTraefikFile: protectedProcedure
|
|
.input(apiReadTraefikConfig)
|
|
.query(async ({ input, ctx }) => {
|
|
if (ctx.user.rol === "user") {
|
|
const canAccess = await canAccessToTraefikFiles(ctx.user.authId);
|
|
|
|
if (!canAccess) {
|
|
throw new TRPCError({ code: "UNAUTHORIZED" });
|
|
}
|
|
}
|
|
return readConfigInPath(input.path);
|
|
}),
|
|
});
|
|
// apt-get install apache2-utils
|