fix: resolve merge conflicts with upstream/canary

This commit is contained in:
vishalkadam47
2024-11-03 05:16:55 +05:30
535 changed files with 13051 additions and 83679 deletions

View File

@@ -1,7 +1,7 @@
import { webcrypto } from "node:crypto";
import type { IncomingMessage, ServerResponse } from "node:http";
import { findAdminByAuthId } from "@/server/services/admin";
import { findUserByAuthId } from "@/server/services/user";
import { findAdminByAuthId } from "@dokploy/server/services/admin";
import { findUserByAuthId } from "@dokploy/server/services/user";
import { DrizzlePostgreSQLAdapter } from "@lucia-auth/adapter-drizzle";
import { TimeSpan } from "lucia";
import { Lucia } from "lucia/dist/core.js";

View File

@@ -4,7 +4,7 @@ export default defineConfig({
schema: "./server/db/schema/index.ts",
dialect: "postgresql",
dbCredentials: {
url: process.env.DATABASE_URL || "",
url: process.env.DATABASE_URL!,
},
out: "drizzle",
migrations: {

View File

@@ -7,12 +7,12 @@ declare global {
export let db: PostgresJsDatabase<typeof schema>;
if (process.env.NODE_ENV === "production") {
db = drizzle(postgres(process.env.DATABASE_URL || ""), {
db = drizzle(postgres(process.env.DATABASE_URL!), {
schema,
});
} else {
if (!global.db)
global.db = drizzle(postgres(process.env.DATABASE_URL || ""), {
global.db = drizzle(postgres(process.env.DATABASE_URL!), {
schema,
});

View File

@@ -2,7 +2,7 @@
// import { migrate } from "drizzle-orm/postgres-js/migrator";
// import postgres from "postgres";
// const connectionString = process.env.DATABASE_URL || "";
// const connectionString = process.env.DATABASE_URL!;
// const sql = postgres(connectionString, { max: 1 });
// const db = drizzle(sql);

View File

@@ -3,7 +3,7 @@ import { sql } from "drizzle-orm";
import { drizzle } from "drizzle-orm/postgres-js";
import postgres from "postgres";
const connectionString = process.env.DATABASE_URL || "";
const connectionString = process.env.DATABASE_URL!;
const pg = postgres(connectionString, { max: 1 });
const db = drizzle(pg);

View File

@@ -1,5 +1,5 @@
import { relations } from "drizzle-orm";
import { boolean, pgTable, text } from "drizzle-orm/pg-core";
import { boolean, integer, pgTable, text } from "drizzle-orm/pg-core";
import { createInsertSchema } from "drizzle-zod";
import { nanoid } from "nanoid";
import { z } from "zod";
@@ -28,6 +28,9 @@ export const admins = pgTable("admin", {
createdAt: text("createdAt")
.notNull()
.$defaultFn(() => new Date().toISOString()),
stripeCustomerId: text("stripeCustomerId"),
stripeSubscriptionId: text("stripeSubscriptionId"),
serversQuantity: integer("serversQuantity").notNull().default(0),
});
export const adminsRelations = relations(admins, ({ one, many }) => ({

View File

@@ -48,6 +48,10 @@ export const auth = pgTable("auth", {
createdAt: text("createdAt")
.notNull()
.$defaultFn(() => new Date().toISOString()),
resetPasswordToken: text("resetPasswordToken"),
resetPasswordExpiresAt: text("resetPasswordExpiresAt"),
confirmationToken: text("confirmationToken"),
confirmationExpiresAt: text("confirmationExpiresAt"),
});
export const authRelations = relations(auth, ({ many }) => ({

View File

@@ -53,7 +53,10 @@ export const apiCreateDestination = createSchema
endpoint: true,
secretAccessKey: true,
})
.required();
.required()
.extend({
serverId: z.string().optional(),
});
export const apiFindOneDestination = createSchema
.pick({
@@ -77,4 +80,7 @@ export const apiUpdateDestination = createSchema
secretAccessKey: true,
destinationId: true,
})
.required();
.required()
.extend({
serverId: z.string().optional(),
});

View File

@@ -1,11 +1,10 @@
import { relations, sql } from "drizzle-orm";
import { boolean, pgEnum, pgTable, text, timestamp } from "drizzle-orm/pg-core";
import { relations } from "drizzle-orm";
import { pgEnum, pgTable, text } from "drizzle-orm/pg-core";
import { createInsertSchema } from "drizzle-zod";
import { nanoid } from "nanoid";
import { z } from "zod";
import { admins } from "./admin";
import { applications } from "./application";
import { auth } from "./auth";
/**
* This is an example of how to use the multi-project schema feature of Drizzle ORM. Use the same
* database instance for multiple projects.
@@ -48,7 +47,7 @@ const createSchema = createInsertSchema(registry, {
registryUrl: z.string(),
adminId: z.string().min(1),
registryId: z.string().min(1),
registryType: z.enum(["selfHosted", "cloud"]),
registryType: z.enum(["cloud"]),
imagePrefix: z.string().nullable().optional(),
});
@@ -59,7 +58,7 @@ export const apiCreateRegistry = createSchema
username: z.string().min(1),
password: z.string().min(1),
registryUrl: z.string(),
registryType: z.enum(["selfHosted", "cloud"]),
registryType: z.enum(["cloud"]),
imagePrefix: z.string().nullable().optional(),
})
.required()
@@ -72,7 +71,7 @@ export const apiTestRegistry = createSchema.pick({}).extend({
username: z.string().min(1),
password: z.string().min(1),
registryUrl: z.string(),
registryType: z.enum(["selfHosted", "cloud"]),
registryType: z.enum(["cloud"]),
imagePrefix: z.string().nullable().optional(),
serverId: z.string().optional(),
});

View File

@@ -1,5 +1,5 @@
import { relations } from "drizzle-orm";
import { boolean, integer, pgTable, text } from "drizzle-orm/pg-core";
import { boolean, integer, pgEnum, pgTable, text } from "drizzle-orm/pg-core";
import { createInsertSchema } from "drizzle-zod";
import { nanoid } from "nanoid";
import { z } from "zod";
@@ -17,6 +17,8 @@ import { redis } from "./redis";
import { sshKeys } from "./ssh-key";
import { generateAppName } from "./utils";
export const serverStatus = pgEnum("serverStatus", ["active", "inactive"]);
export const server = pgTable("server", {
serverId: text("serverId")
.notNull()
@@ -37,6 +39,8 @@ export const server = pgTable("server", {
adminId: text("adminId")
.notNull()
.references(() => admins.adminId, { onDelete: "cascade" }),
serverStatus: serverStatus("serverStatus").notNull().default("active"),
sshKeyId: text("sshKeyId").references(() => sshKeys.sshKeyId, {
onDelete: "set null",
}),

View File

@@ -3,7 +3,7 @@
// import postgres from "postgres";
// import { users } from "./schema";
// const connectionString = process.env.DATABASE_URL || "";
// const connectionString = process.env.DATABASE_URL!;
// const pg = postgres(connectionString, { max: 1 });
// const db = drizzle(pg);

View File

@@ -15,9 +15,7 @@ interface NotionMagicLinkEmailProps {
loginCode?: string;
}
const baseUrl = process.env.VERCEL_URL
? `https://${process.env.VERCEL_URL}`
: "";
const baseUrl = process.env.VERCEL_URL!;
export const NotionMagicLinkEmail = ({
loginCode,

View File

@@ -15,9 +15,7 @@ interface PlaidVerifyIdentityEmailProps {
validationCode?: string;
}
const baseUrl = process.env.VERCEL_URL
? `https://${process.env.VERCEL_URL}`
: "";
const baseUrl = process.env.VERCEL_URL!;
export const PlaidVerifyIdentityEmail = ({
validationCode,

View File

@@ -13,9 +13,7 @@ import {
} from "@react-email/components";
import * as React from "react";
const baseUrl = process.env.VERCEL_URL
? `https://${process.env.VERCEL_URL}`
: "";
const baseUrl = process.env.VERCEL_URL!;
export const StripeWelcomeEmail = () => (
<Html>

View File

@@ -29,9 +29,7 @@ interface VercelInviteUserEmailProps {
inviteFromLocation?: string;
}
const baseUrl = process.env.VERCEL_URL
? `https://${process.env.VERCEL_URL}`
: "";
const baseUrl = process.env.VERCEL_URL!;
export const VercelInviteUserEmail = ({
username,

View File

@@ -37,7 +37,6 @@ export * from "./services/application";
export * from "./setup/config-paths";
export * from "./setup/postgres-setup";
export * from "./setup/redis-setup";
export * from "./setup/registry-setup";
export * from "./setup/server-setup";
export * from "./setup/setup";
export * from "./setup/traefik-setup";
@@ -97,7 +96,6 @@ export * from "./utils/traefik/domain";
export * from "./utils/traefik/file-types";
export * from "./utils/traefik/middleware";
export * from "./utils/traefik/redirect";
export * from "./utils/traefik/registry";
export * from "./utils/traefik/security";
export * from "./utils/traefik/types";
export * from "./utils/traefik/web-server";

View File

@@ -1,11 +1,11 @@
import { randomBytes } from "node:crypto";
import { db } from "@/server/db";
import { db } from "@dokploy/server/db";
import {
admins,
type apiCreateUserInvitation,
auth,
users,
} from "@/server/db/schema";
} from "@dokploy/server/db/schema";
import { TRPCError } from "@trpc/server";
import * as bcrypt from "bcrypt";
import { eq } from "drizzle-orm";
@@ -20,7 +20,7 @@ export const createInvitation = async (
const result = await tx
.insert(auth)
.values({
email: input.email,
email: input.email.toLowerCase(),
rol: "user",
password: bcrypt.hashSync("01231203012312", 10),
})

View File

@@ -1,38 +1,41 @@
import { docker } from "@/server/constants";
import { db } from "@/server/db";
import { type apiCreateApplication, applications } from "@/server/db/schema";
import { generateAppName } from "@/server/db/schema";
import { getAdvancedStats } from "@/server/monitoring/utilts";
import { generatePassword } from "@/server/templates/utils";
import { docker } from "@dokploy/server/constants";
import { db } from "@dokploy/server/db";
import {
type apiCreateApplication,
applications,
} from "@dokploy/server/db/schema";
import { generateAppName } from "@dokploy/server/db/schema";
import { getAdvancedStats } from "@dokploy/server/monitoring/utilts";
import { generatePassword } from "@dokploy/server/templates/utils";
import {
buildApplication,
getBuildCommand,
mechanizeDockerContainer,
} from "@/server/utils/builders";
import { sendBuildErrorNotifications } from "@/server/utils/notifications/build-error";
import { sendBuildSuccessNotifications } from "@/server/utils/notifications/build-success";
import { execAsyncRemote } from "@/server/utils/process/execAsync";
} from "@dokploy/server/utils/builders";
import { sendBuildErrorNotifications } from "@dokploy/server/utils/notifications/build-error";
import { sendBuildSuccessNotifications } from "@dokploy/server/utils/notifications/build-success";
import { execAsyncRemote } from "@dokploy/server/utils/process/execAsync";
import {
cloneBitbucketRepository,
getBitbucketCloneCommand,
} from "@/server/utils/providers/bitbucket";
} from "@dokploy/server/utils/providers/bitbucket";
import {
buildDocker,
buildRemoteDocker,
} from "@/server/utils/providers/docker";
} from "@dokploy/server/utils/providers/docker";
import {
cloneGitRepository,
getCustomGitCloneCommand,
} from "@/server/utils/providers/git";
} from "@dokploy/server/utils/providers/git";
import {
cloneGithubRepository,
getGithubCloneCommand,
} from "@/server/utils/providers/github";
} from "@dokploy/server/utils/providers/github";
import {
cloneGitlabRepository,
getGitlabCloneCommand,
} from "@/server/utils/providers/gitlab";
import { createTraefikConfig } from "@/server/utils/traefik/application";
} from "@dokploy/server/utils/providers/gitlab";
import { createTraefikConfig } from "@dokploy/server/utils/traefik/application";
import { TRPCError } from "@trpc/server";
import { eq } from "drizzle-orm";
import { encodeBase64 } from "../utils/docker/utils";

View File

@@ -1,13 +1,13 @@
import { randomBytes } from "node:crypto";
import { db } from "@/server/db";
import { db } from "@dokploy/server/db";
import {
admins,
type apiCreateAdmin,
type apiCreateUser,
auth,
users,
} from "@/server/db/schema";
import { getPublicIpWithFallback } from "@/server/wss/terminal";
} from "@dokploy/server/db/schema";
import { getPublicIpWithFallback } from "@dokploy/server/wss/terminal";
import { TRPCError } from "@trpc/server";
import * as bcrypt from "bcrypt";
import { eq } from "drizzle-orm";
@@ -24,7 +24,7 @@ export const createAdmin = async (input: typeof apiCreateAdmin._type) => {
const newAuth = await tx
.insert(auth)
.values({
email: input.email,
email: input.email.toLowerCase(),
password: hashedPassword,
rol: "admin",
})
@@ -43,9 +43,9 @@ export const createAdmin = async (input: typeof apiCreateAdmin._type) => {
.values({
authId: newAuth.id,
...(!IS_CLOUD && {
serverIp: await getPublicIpWithFallback(),
serverIp:
process.env.ADVERTISE_ADDR || (await getPublicIpWithFallback()),
}),
serverIp: await getPublicIpWithFallback(),
})
.returning();
@@ -93,7 +93,7 @@ export const findAuthByEmail = async (email: string) => {
if (!result) {
throw new TRPCError({
code: "NOT_FOUND",
message: "Auth not found",
message: "User not found",
});
}
return result;

View File

@@ -1,5 +1,5 @@
import { db } from "@/server/db";
import { type apiCreateBackup, backups } from "@/server/db/schema";
import { db } from "@dokploy/server/db";
import { type apiCreateBackup, backups } from "@dokploy/server/db/schema";
import { TRPCError } from "@trpc/server";
import { eq } from "drizzle-orm";

View File

@@ -1,10 +1,10 @@
import { db } from "@/server/db";
import { db } from "@dokploy/server/db";
import {
type apiCreateBitbucket,
type apiUpdateBitbucket,
bitbucket,
gitProvider,
} from "@/server/db/schema";
} from "@dokploy/server/db/schema";
import { TRPCError } from "@trpc/server";
import { eq } from "drizzle-orm";

View File

@@ -1,9 +1,12 @@
import fs from "node:fs";
import path from "node:path";
import { paths } from "@/server/constants";
import { db } from "@/server/db";
import { type apiCreateCertificate, certificates } from "@/server/db/schema";
import { removeDirectoryIfExistsContent } from "@/server/utils/filesystem/directory";
import { paths } from "@dokploy/server/constants";
import { db } from "@dokploy/server/db";
import {
type apiCreateCertificate,
certificates,
} from "@dokploy/server/db/schema";
import { removeDirectoryIfExistsContent } from "@dokploy/server/utils/filesystem/directory";
import { TRPCError } from "@trpc/server";
import { eq } from "drizzle-orm";
import { dump } from "js-yaml";

View File

@@ -1,44 +1,47 @@
import { join } from "node:path";
import { paths } from "@/server/constants";
import { db } from "@/server/db";
import { type apiCreateCompose, compose } from "@/server/db/schema";
import { generateAppName } from "@/server/db/schema";
import { generatePassword } from "@/server/templates/utils";
import { paths } from "@dokploy/server/constants";
import { db } from "@dokploy/server/db";
import { type apiCreateCompose, compose } from "@dokploy/server/db/schema";
import { generateAppName } from "@dokploy/server/db/schema";
import { generatePassword } from "@dokploy/server/templates/utils";
import {
buildCompose,
getBuildComposeCommand,
} from "@/server/utils/builders/compose";
import { randomizeSpecificationFile } from "@/server/utils/docker/compose";
} from "@dokploy/server/utils/builders/compose";
import { randomizeSpecificationFile } from "@dokploy/server/utils/docker/compose";
import {
cloneCompose,
cloneComposeRemote,
loadDockerCompose,
loadDockerComposeRemote,
} from "@/server/utils/docker/domain";
import type { ComposeSpecification } from "@/server/utils/docker/types";
import { sendBuildErrorNotifications } from "@/server/utils/notifications/build-error";
import { sendBuildSuccessNotifications } from "@/server/utils/notifications/build-success";
import { execAsync, execAsyncRemote } from "@/server/utils/process/execAsync";
} from "@dokploy/server/utils/docker/domain";
import type { ComposeSpecification } from "@dokploy/server/utils/docker/types";
import { sendBuildErrorNotifications } from "@dokploy/server/utils/notifications/build-error";
import { sendBuildSuccessNotifications } from "@dokploy/server/utils/notifications/build-success";
import {
execAsync,
execAsyncRemote,
} from "@dokploy/server/utils/process/execAsync";
import {
cloneBitbucketRepository,
getBitbucketCloneCommand,
} from "@/server/utils/providers/bitbucket";
} from "@dokploy/server/utils/providers/bitbucket";
import {
cloneGitRepository,
getCustomGitCloneCommand,
} from "@/server/utils/providers/git";
} from "@dokploy/server/utils/providers/git";
import {
cloneGithubRepository,
getGithubCloneCommand,
} from "@/server/utils/providers/github";
} from "@dokploy/server/utils/providers/github";
import {
cloneGitlabRepository,
getGitlabCloneCommand,
} from "@/server/utils/providers/gitlab";
} from "@dokploy/server/utils/providers/gitlab";
import {
createComposeFile,
getCreateComposeFileCommand,
} from "@/server/utils/providers/raw";
} from "@dokploy/server/utils/providers/raw";
import { TRPCError } from "@trpc/server";
import { eq } from "drizzle-orm";
import { encodeBase64 } from "../utils/docker/utils";

View File

@@ -1,14 +1,14 @@
import { existsSync, promises as fsPromises } from "node:fs";
import path from "node:path";
import { paths } from "@/server/constants";
import { db } from "@/server/db";
import { paths } from "@dokploy/server/constants";
import { db } from "@dokploy/server/db";
import {
type apiCreateDeployment,
type apiCreateDeploymentCompose,
type apiCreateDeploymentServer,
deployments,
} from "@/server/db/schema";
import { removeDirectoryIfExistsContent } from "@/server/utils/filesystem/directory";
} from "@dokploy/server/db/schema";
import { removeDirectoryIfExistsContent } from "@dokploy/server/utils/filesystem/directory";
import { TRPCError } from "@trpc/server";
import { format } from "date-fns";
import { desc, eq } from "drizzle-orm";
@@ -20,7 +20,7 @@ import {
import { type Compose, findComposeById, updateCompose } from "./compose";
import { type Server, findServerById } from "./server";
import { execAsyncRemote } from "@/server/utils/process/execAsync";
import { execAsyncRemote } from "@dokploy/server/utils/process/execAsync";
export type Deployment = typeof deployments.$inferSelect;
@@ -49,7 +49,10 @@ export const createDeployment = async (
const application = await findApplicationById(deployment.applicationId);
try {
// await removeLastTenDeployments(deployment.applicationId);
await removeLastTenDeployments(
deployment.applicationId,
application.serverId,
);
const { LOGS_PATH } = paths(!!application.serverId);
const formattedDateTime = format(new Date(), "yyyy-MM-dd:HH:mm:ss");
const fileName = `${application.appName}-${formattedDateTime}.log`;
@@ -106,7 +109,10 @@ export const createDeploymentCompose = async (
) => {
const compose = await findComposeById(deployment.composeId);
try {
// await removeLastTenComposeDeployments(deployment.composeId);
await removeLastTenComposeDeployments(
deployment.composeId,
compose.serverId,
);
const { LOGS_PATH } = paths(!!compose.serverId);
const formattedDateTime = format(new Date(), "yyyy-MM-dd:HH:mm:ss");
const fileName = `${compose.appName}-${formattedDateTime}.log`;
@@ -181,36 +187,72 @@ export const removeDeploymentsByApplicationId = async (
.returning();
};
const removeLastTenDeployments = async (applicationId: string) => {
const removeLastTenDeployments = async (
applicationId: string,
serverId: string | null,
) => {
const deploymentList = await db.query.deployments.findMany({
where: eq(deployments.applicationId, applicationId),
orderBy: desc(deployments.createdAt),
});
if (deploymentList.length > 10) {
const deploymentsToDelete = deploymentList.slice(10);
for (const oldDeployment of deploymentsToDelete) {
const logPath = path.join(oldDeployment.logPath);
if (existsSync(logPath)) {
await fsPromises.unlink(logPath);
if (serverId) {
let command = "";
for (const oldDeployment of deploymentsToDelete) {
const logPath = path.join(oldDeployment.logPath);
command += `
rm -rf ${logPath};
`;
await removeDeployment(oldDeployment.deploymentId);
}
await execAsyncRemote(serverId, command);
} else {
for (const oldDeployment of deploymentsToDelete) {
const logPath = path.join(oldDeployment.logPath);
if (existsSync(logPath)) {
await fsPromises.unlink(logPath);
}
await removeDeployment(oldDeployment.deploymentId);
}
await removeDeployment(oldDeployment.deploymentId);
}
}
};
const removeLastTenComposeDeployments = async (composeId: string) => {
const removeLastTenComposeDeployments = async (
composeId: string,
serverId: string | null,
) => {
const deploymentList = await db.query.deployments.findMany({
where: eq(deployments.composeId, composeId),
orderBy: desc(deployments.createdAt),
});
if (deploymentList.length > 10) {
const deploymentsToDelete = deploymentList.slice(10);
for (const oldDeployment of deploymentsToDelete) {
const logPath = path.join(oldDeployment.logPath);
if (existsSync(logPath)) {
await fsPromises.unlink(logPath);
if (serverId) {
let command = "";
const deploymentsToDelete = deploymentList.slice(10);
for (const oldDeployment of deploymentsToDelete) {
const logPath = path.join(oldDeployment.logPath);
command += `
rm -rf ${logPath};
`;
await removeDeployment(oldDeployment.deploymentId);
}
await execAsyncRemote(serverId, command);
} else {
const deploymentsToDelete = deploymentList.slice(10);
for (const oldDeployment of deploymentsToDelete) {
const logPath = path.join(oldDeployment.logPath);
if (existsSync(logPath)) {
await fsPromises.unlink(logPath);
}
await removeDeployment(oldDeployment.deploymentId);
}
await removeDeployment(oldDeployment.deploymentId);
}
}
};
@@ -327,7 +369,6 @@ export const createServerDeployment = async (
}
return deploymentCreate[0];
} catch (error) {
console.log(error);
throw new TRPCError({
code: "BAD_REQUEST",
message: "Error to create the deployment",

View File

@@ -1,5 +1,8 @@
import { db } from "@/server/db";
import { type apiCreateDestination, destinations } from "@/server/db/schema";
import { db } from "@dokploy/server/db";
import {
type apiCreateDestination,
destinations,
} from "@dokploy/server/db/schema";
import { TRPCError } from "@trpc/server";
import { and, eq } from "drizzle-orm";

View File

@@ -1,4 +1,7 @@
import { execAsync, execAsyncRemote } from "@/server/utils/process/execAsync";
import {
execAsync,
execAsyncRemote,
} from "@dokploy/server/utils/process/execAsync";
export const getContainers = async (serverId?: string | null) => {
try {

View File

@@ -1,6 +1,6 @@
import { db } from "@/server/db";
import { generateRandomDomain } from "@/server/templates/utils";
import { manageDomain } from "@/server/utils/traefik/domain";
import { db } from "@dokploy/server/db";
import { generateRandomDomain } from "@dokploy/server/templates/utils";
import { manageDomain } from "@dokploy/server/utils/traefik/domain";
import { TRPCError } from "@trpc/server";
import { eq } from "drizzle-orm";
import { type apiCreateDomain, domains } from "../db/schema";

View File

@@ -1,5 +1,5 @@
import { db } from "@/server/db";
import { gitProvider } from "@/server/db/schema";
import { db } from "@dokploy/server/db";
import { gitProvider } from "@dokploy/server/db/schema";
import { TRPCError } from "@trpc/server";
import { eq } from "drizzle-orm";

View File

@@ -1,5 +1,9 @@
import { db } from "@/server/db";
import { type apiCreateGithub, gitProvider, github } from "@/server/db/schema";
import { db } from "@dokploy/server/db";
import {
type apiCreateGithub,
gitProvider,
github,
} from "@dokploy/server/db/schema";
import { TRPCError } from "@trpc/server";
import { eq } from "drizzle-orm";

View File

@@ -1,11 +1,11 @@
import { db } from "@/server/db";
import { db } from "@dokploy/server/db";
import {
type apiCreateGitlab,
type bitbucket,
gitProvider,
type github,
gitlab,
} from "@/server/db/schema";
} from "@dokploy/server/db/schema";
import { TRPCError } from "@trpc/server";
import { eq } from "drizzle-orm";

View File

@@ -1,14 +1,18 @@
import { db } from "@/server/db";
import { type apiCreateMariaDB, backups, mariadb } from "@/server/db/schema";
import { generateAppName } from "@/server/db/schema";
import { generatePassword } from "@/server/templates/utils";
import { buildMariadb } from "@/server/utils/databases/mariadb";
import { pullImage } from "@/server/utils/docker/utils";
import { db } from "@dokploy/server/db";
import {
type apiCreateMariaDB,
backups,
mariadb,
} from "@dokploy/server/db/schema";
import { generateAppName } from "@dokploy/server/db/schema";
import { generatePassword } from "@dokploy/server/templates/utils";
import { buildMariadb } from "@dokploy/server/utils/databases/mariadb";
import { pullImage } from "@dokploy/server/utils/docker/utils";
import { TRPCError } from "@trpc/server";
import { eq, getTableColumns } from "drizzle-orm";
import { validUniqueServerAppName } from "./project";
import { execAsyncRemote } from "@/server/utils/process/execAsync";
import { execAsyncRemote } from "@dokploy/server/utils/process/execAsync";
export type Mariadb = typeof mariadb.$inferSelect;

View File

@@ -1,14 +1,14 @@
import { db } from "@/server/db";
import { type apiCreateMongo, backups, mongo } from "@/server/db/schema";
import { generateAppName } from "@/server/db/schema";
import { generatePassword } from "@/server/templates/utils";
import { buildMongo } from "@/server/utils/databases/mongo";
import { pullImage } from "@/server/utils/docker/utils";
import { db } from "@dokploy/server/db";
import { type apiCreateMongo, backups, mongo } from "@dokploy/server/db/schema";
import { generateAppName } from "@dokploy/server/db/schema";
import { generatePassword } from "@dokploy/server/templates/utils";
import { buildMongo } from "@dokploy/server/utils/databases/mongo";
import { pullImage } from "@dokploy/server/utils/docker/utils";
import { TRPCError } from "@trpc/server";
import { eq, getTableColumns } from "drizzle-orm";
import { validUniqueServerAppName } from "./project";
import { execAsyncRemote } from "@/server/utils/process/execAsync";
import { execAsyncRemote } from "@dokploy/server/utils/process/execAsync";
export type Mongo = typeof mongo.$inferSelect;

View File

@@ -1,14 +1,17 @@
import path from "node:path";
import { paths } from "@/server/constants";
import { db } from "@/server/db";
import { paths } from "@dokploy/server/constants";
import { db } from "@dokploy/server/db";
import {
type ServiceType,
type apiCreateMount,
mounts,
} from "@/server/db/schema";
import { createFile, getCreateFileCommand } from "@/server/utils/docker/utils";
import { removeFileOrDirectory } from "@/server/utils/filesystem/directory";
import { execAsyncRemote } from "@/server/utils/process/execAsync";
} from "@dokploy/server/db/schema";
import {
createFile,
getCreateFileCommand,
} from "@dokploy/server/utils/docker/utils";
import { removeFileOrDirectory } from "@dokploy/server/utils/filesystem/directory";
import { execAsyncRemote } from "@dokploy/server/utils/process/execAsync";
import { TRPCError } from "@trpc/server";
import { type SQL, eq, sql } from "drizzle-orm";

View File

@@ -1,14 +1,14 @@
import { db } from "@/server/db";
import { type apiCreateMySql, backups, mysql } from "@/server/db/schema";
import { generateAppName } from "@/server/db/schema";
import { generatePassword } from "@/server/templates/utils";
import { buildMysql } from "@/server/utils/databases/mysql";
import { pullImage } from "@/server/utils/docker/utils";
import { db } from "@dokploy/server/db";
import { type apiCreateMySql, backups, mysql } from "@dokploy/server/db/schema";
import { generateAppName } from "@dokploy/server/db/schema";
import { generatePassword } from "@dokploy/server/templates/utils";
import { buildMysql } from "@dokploy/server/utils/databases/mysql";
import { pullImage } from "@dokploy/server/utils/docker/utils";
import { TRPCError } from "@trpc/server";
import { eq, getTableColumns } from "drizzle-orm";
import { validUniqueServerAppName } from "./project";
import { execAsyncRemote } from "@/server/utils/process/execAsync";
import { execAsyncRemote } from "@dokploy/server/utils/process/execAsync";
export type MySql = typeof mysql.$inferSelect;

View File

@@ -1,4 +1,4 @@
import { db } from "@/server/db";
import { db } from "@dokploy/server/db";
import {
type apiCreateDiscord,
type apiCreateEmail,
@@ -13,7 +13,7 @@ import {
notifications,
slack,
telegram,
} from "@/server/db/schema";
} from "@dokploy/server/db/schema";
import { TRPCError } from "@trpc/server";
import { eq } from "drizzle-orm";

View File

@@ -1,5 +1,5 @@
import { db } from "@/server/db";
import { type apiCreatePort, ports } from "@/server/db/schema";
import { db } from "@dokploy/server/db";
import { type apiCreatePort, ports } from "@dokploy/server/db/schema";
import { TRPCError } from "@trpc/server";
import { eq } from "drizzle-orm";

View File

@@ -1,14 +1,18 @@
import { db } from "@/server/db";
import { type apiCreatePostgres, backups, postgres } from "@/server/db/schema";
import { generateAppName } from "@/server/db/schema";
import { generatePassword } from "@/server/templates/utils";
import { buildPostgres } from "@/server/utils/databases/postgres";
import { pullImage } from "@/server/utils/docker/utils";
import { db } from "@dokploy/server/db";
import {
type apiCreatePostgres,
backups,
postgres,
} from "@dokploy/server/db/schema";
import { generateAppName } from "@dokploy/server/db/schema";
import { generatePassword } from "@dokploy/server/templates/utils";
import { buildPostgres } from "@dokploy/server/utils/databases/postgres";
import { pullImage } from "@dokploy/server/utils/docker/utils";
import { TRPCError } from "@trpc/server";
import { eq, getTableColumns } from "drizzle-orm";
import { validUniqueServerAppName } from "./project";
import { execAsyncRemote } from "@/server/utils/process/execAsync";
import { execAsyncRemote } from "@dokploy/server/utils/process/execAsync";
export type Postgres = typeof postgres.$inferSelect;

View File

@@ -1,4 +1,4 @@
import { db } from "@/server/db";
import { db } from "@dokploy/server/db";
import {
type apiCreateProject,
applications,
@@ -8,7 +8,7 @@ import {
postgres,
projects,
redis,
} from "@/server/db/schema";
} from "@dokploy/server/db/schema";
import { TRPCError } from "@trpc/server";
import { eq } from "drizzle-orm";

View File

@@ -1,10 +1,10 @@
import { db } from "@/server/db";
import { type apiCreateRedirect, redirects } from "@/server/db/schema";
import { db } from "@dokploy/server/db";
import { type apiCreateRedirect, redirects } from "@dokploy/server/db/schema";
import {
createRedirectMiddleware,
removeRedirectMiddleware,
updateRedirectMiddleware,
} from "@/server/utils/traefik/redirect";
} from "@dokploy/server/utils/traefik/redirect";
import { TRPCError } from "@trpc/server";
import { desc, eq } from "drizzle-orm";
import type { z } from "zod";
@@ -51,7 +51,6 @@ export const createRedirect = async (
return true;
} catch (error) {
console.log(error);
throw new TRPCError({
code: "BAD_REQUEST",
message: "Error to create this redirect",

View File

@@ -1,14 +1,14 @@
import { db } from "@/server/db";
import { type apiCreateRedis, redis } from "@/server/db/schema";
import { generateAppName } from "@/server/db/schema";
import { generatePassword } from "@/server/templates/utils";
import { buildRedis } from "@/server/utils/databases/redis";
import { pullImage } from "@/server/utils/docker/utils";
import { db } from "@dokploy/server/db";
import { type apiCreateRedis, redis } from "@dokploy/server/db/schema";
import { generateAppName } from "@dokploy/server/db/schema";
import { generatePassword } from "@dokploy/server/templates/utils";
import { buildRedis } from "@dokploy/server/utils/databases/redis";
import { pullImage } from "@dokploy/server/utils/docker/utils";
import { TRPCError } from "@trpc/server";
import { eq } from "drizzle-orm";
import { validUniqueServerAppName } from "./project";
import { execAsyncRemote } from "@/server/utils/process/execAsync";
import { execAsyncRemote } from "@dokploy/server/utils/process/execAsync";
export type Redis = typeof redis.$inferSelect;

View File

@@ -1,14 +1,12 @@
import { db } from "@/server/db";
import { type apiCreateRegistry, registry } from "@/server/db/schema";
import { initializeRegistry } from "@/server/setup/registry-setup";
import { removeService } from "@/server/utils/docker/utils";
import { execAsync, execAsyncRemote } from "@/server/utils/process/execAsync";
import { db } from "@dokploy/server/db";
import { type apiCreateRegistry, registry } from "@dokploy/server/db/schema";
import {
manageRegistry,
removeSelfHostedRegistry,
} from "@/server/utils/traefik/registry";
execAsync,
execAsyncRemote,
} from "@dokploy/server/utils/process/execAsync";
import { TRPCError } from "@trpc/server";
import { eq } from "drizzle-orm";
import { IS_CLOUD } from "../constants";
export type Registry = typeof registry.$inferSelect;
@@ -32,6 +30,13 @@ export const createRegistry = async (
message: "Error input: Inserting registry",
});
}
if (IS_CLOUD && !input.serverId && input.serverId !== "none") {
throw new TRPCError({
code: "NOT_FOUND",
message: "Select a server to add the registry",
});
}
const loginCommand = `echo ${input.password} | docker login ${input.registryUrl} --username ${input.username} --password-stdin`;
if (input.serverId && input.serverId !== "none") {
await execAsyncRemote(input.serverId, loginCommand);
@@ -58,13 +63,10 @@ export const removeRegistry = async (registryId: string) => {
});
}
if (response.registryType === "selfHosted") {
await removeSelfHostedRegistry();
await removeService("dokploy-registry");
if (!IS_CLOUD) {
await execAsync(`docker logout ${response.registryUrl}`);
}
await execAsync(`docker logout ${response.registryUrl}`);
return response;
} catch (error) {
throw new TRPCError({
@@ -89,12 +91,19 @@ export const updateRegistry = async (
.returning()
.then((res) => res[0]);
if (response?.registryType === "selfHosted") {
await manageRegistry(response);
await initializeRegistry(response.username, response.password);
}
const loginCommand = `echo ${response?.password} | docker login ${response?.registryUrl} --username ${response?.username} --password-stdin`;
if (
IS_CLOUD &&
!registryData?.serverId &&
registryData?.serverId !== "none"
) {
throw new TRPCError({
code: "NOT_FOUND",
message: "Select a server to add the registry",
});
}
if (registryData?.serverId && registryData?.serverId !== "none") {
await execAsyncRemote(registryData.serverId, loginCommand);
} else if (response?.registryType === "cloud") {

View File

@@ -1,9 +1,9 @@
import { db } from "@/server/db";
import { type apiCreateSecurity, security } from "@/server/db/schema";
import { db } from "@dokploy/server/db";
import { type apiCreateSecurity, security } from "@dokploy/server/db/schema";
import {
createSecurityMiddleware,
removeSecurityMiddleware,
} from "@/server/utils/traefik/security";
} from "@dokploy/server/utils/traefik/security";
import { TRPCError } from "@trpc/server";
import { eq } from "drizzle-orm";
import type { z } from "zod";
@@ -48,7 +48,6 @@ export const createSecurity = async (
return true;
});
} catch (error) {
console.log(error);
throw new TRPCError({
code: "BAD_REQUEST",
message: "Error to create this security",

View File

@@ -1,5 +1,5 @@
import { db } from "@/server/db";
import { type apiCreateServer, server } from "@/server/db/schema";
import { db } from "@dokploy/server/db";
import { type apiCreateServer, server } from "@dokploy/server/db/schema";
import { TRPCError } from "@trpc/server";
import { desc, eq } from "drizzle-orm";

View File

@@ -1,8 +1,8 @@
import { readdirSync } from "node:fs";
import { join } from "node:path";
import { docker } from "@/server/constants";
import { getServiceContainer } from "@/server/utils/docker/utils";
import { execAsyncRemote } from "@/server/utils/process/execAsync";
import { docker } from "@dokploy/server/constants";
import { getServiceContainer } from "@dokploy/server/utils/docker/utils";
import { execAsyncRemote } from "@dokploy/server/utils/process/execAsync";
// import packageInfo from "../../../package.json";
const updateIsAvailable = async () => {

View File

@@ -1,11 +1,11 @@
import { db } from "@/server/db";
import { db } from "@dokploy/server/db";
import {
type apiCreateSshKey,
type apiFindOneSshKey,
type apiRemoveSshKey,
type apiUpdateSshKey,
sshKeys,
} from "@/server/db/schema";
} from "@dokploy/server/db/schema";
import { TRPCError } from "@trpc/server";
import { eq } from "drizzle-orm";

View File

@@ -1,5 +1,5 @@
import { db } from "@/server/db";
import { users } from "@/server/db/schema";
import { db } from "@dokploy/server/db";
import { users } from "@dokploy/server/db/schema";
import { TRPCError } from "@trpc/server";
import { eq } from "drizzle-orm";

View File

@@ -32,16 +32,18 @@ export const initializePostgres = async () => {
Replicas: 1,
},
},
EndpointSpec: {
Ports: [
{
TargetPort: 5432,
PublishedPort: process.env.NODE_ENV === "development" ? 5432 : 0,
Protocol: "tcp",
PublishMode: "host",
},
],
},
...(process.env.NODE_ENV === "development" && {
EndpointSpec: {
Ports: [
{
TargetPort: 5432,
PublishedPort: 5432,
Protocol: "tcp",
PublishMode: "host",
},
],
},
}),
};
try {
await pullImage(imageName);

View File

@@ -29,16 +29,18 @@ export const initializeRedis = async () => {
Replicas: 1,
},
},
EndpointSpec: {
Ports: [
{
TargetPort: 6379,
PublishedPort: process.env.NODE_ENV === "development" ? 6379 : 0,
Protocol: "tcp",
PublishMode: "host",
},
],
},
...(process.env.NODE_ENV === "development" && {
EndpointSpec: {
Ports: [
{
TargetPort: 6379,
PublishedPort: 6379,
Protocol: "tcp",
PublishMode: "host",
},
],
},
}),
};
try {
await pullImage(imageName);

View File

@@ -1,91 +0,0 @@
import type { CreateServiceOptions } from "dockerode";
import { docker, paths } from "../constants";
import { generatePassword } from "../templates/utils";
import { pullImage } from "../utils/docker/utils";
import { execAsync } from "../utils/process/execAsync";
export const initializeRegistry = async (
username: string,
password: string,
) => {
const { REGISTRY_PATH } = paths();
const imageName = "registry:2.8.3";
const containerName = "dokploy-registry";
await generateRegistryPassword(username, password);
const randomPass = generatePassword();
const settings: CreateServiceOptions = {
Name: containerName,
TaskTemplate: {
ContainerSpec: {
Image: imageName,
Env: [
"REGISTRY_STORAGE_DELETE_ENABLED=true",
"REGISTRY_AUTH=htpasswd",
"REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm",
"REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd",
`REGISTRY_HTTP_SECRET=${randomPass}`,
],
Mounts: [
{
Type: "bind",
Source: `${REGISTRY_PATH}/htpasswd`,
Target: "/auth/htpasswd",
ReadOnly: true,
},
{
Type: "volume",
Source: "registry-data",
Target: "/var/lib/registry",
ReadOnly: false,
},
],
},
Networks: [{ Target: "dokploy-network" }],
Placement: {
Constraints: ["node.role==manager"],
},
},
Mode: {
Replicated: {
Replicas: 1,
},
},
EndpointSpec: {
Ports: [
{
TargetPort: 5000,
PublishedPort: 5000,
Protocol: "tcp",
PublishMode: "host",
},
],
},
};
try {
await pullImage(imageName);
const service = docker.getService(containerName);
const inspect = await service.inspect();
await service.update({
version: Number.parseInt(inspect.Version.Index),
...settings,
});
console.log("Registry Started ✅");
} catch (error) {
await docker.createService(settings);
console.log("Registry Not Found: Starting ✅");
}
};
const generateRegistryPassword = async (username: string, password: string) => {
try {
const { REGISTRY_PATH } = paths();
const command = `htpasswd -nbB ${username} "${password}" > ${REGISTRY_PATH}/htpasswd`;
const result = await execAsync(command);
console.log("Password generated ✅");
return result.stdout.trim();
} catch (error) {
console.error("Error generating password:", error);
return null;
}
};

View File

@@ -1,15 +1,15 @@
import { createWriteStream } from "node:fs";
import path from "node:path";
import { paths } from "@/server/constants";
import { paths } from "@dokploy/server/constants";
import {
createServerDeployment,
updateDeploymentStatus,
} from "@/server/services/deployment";
import { findServerById } from "@/server/services/server";
} from "@dokploy/server/services/deployment";
import { findServerById } from "@dokploy/server/services/server";
import {
getDefaultMiddlewares,
getDefaultServerTraefikConfig,
} from "@/server/setup/traefik-setup";
} from "@dokploy/server/setup/traefik-setup";
import { Client } from "ssh2";
import { recreateDirectory } from "../utils/filesystem/directory";
@@ -101,7 +101,6 @@ const installRequirements = async (serverId: string, logPath: string) => {
}
stream
.on("close", () => {
writeStream.write("Connection closed ✅");
client.end();
resolve();
})

View File

@@ -9,8 +9,8 @@ import type { FileConfig } from "../utils/traefik/file-types";
import type { MainTraefikConfig } from "../utils/traefik/types";
const TRAEFIK_SSL_PORT =
Number.parseInt(process.env.TRAEFIK_SSL_PORT ?? "", 10) || 443;
const TRAEFIK_PORT = Number.parseInt(process.env.TRAEFIK_PORT ?? "", 10) || 80;
Number.parseInt(process.env.TRAEFIK_SSL_PORT!, 10) || 443;
const TRAEFIK_PORT = Number.parseInt(process.env.TRAEFIK_PORT!, 10) || 80;
interface TraefikOptions {
enableDashboard?: boolean;

View File

@@ -1,7 +1,7 @@
import { randomBytes } from "node:crypto";
import { readFile } from "node:fs/promises";
import { join } from "node:path";
import type { Domain } from "@/server/services/domain";
import type { Domain } from "@dokploy/server/services/domain";
export interface Schema {
serverIp: string;
@@ -35,9 +35,15 @@ export const generateHash = (projectName: string, quantity = 3): string => {
};
export const generatePassword = (quantity = 16): string => {
return randomBytes(Math.ceil(quantity / 2))
.toString("hex")
.slice(0, quantity);
const characters =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
let password = "";
for (let i = 0; i < quantity; i++) {
password += characters.charAt(
Math.floor(Math.random() * characters.length),
);
}
return password.toLowerCase();
};
export const generateBase64 = (bytes = 32): string => {

View File

@@ -1,4 +1,4 @@
import type * as schema from "@/server/db/schema";
import type * as schema from "@dokploy/server/db/schema";
import type {
BuildQueryResult,
DBQueryConfig,

View File

@@ -1,5 +1,5 @@
import { IS_CLOUD, paths } from "@/server/constants";
import { updateAdmin } from "@/server/services/admin";
import { IS_CLOUD, paths } from "@dokploy/server/constants";
import { updateAdmin } from "@dokploy/server/services/admin";
import { type RotatingFileStream, createStream } from "rotating-file-stream";
import { db } from "../../db";
import { execAsync } from "../process/execAsync";

View File

@@ -1,5 +1,5 @@
import { findAdmin } from "@/server/services/admin";
import { getAllServers } from "@/server/services/server";
import { findAdmin } from "@dokploy/server/services/admin";
import { getAllServers } from "@dokploy/server/services/server";
import { scheduleJob } from "node-schedule";
import { db } from "../../db/index";
import {

View File

@@ -1,7 +1,7 @@
import path from "node:path";
import type { BackupSchedule } from "@/server/services/backup";
import type { Mariadb } from "@/server/services/mariadb";
import { findProjectById } from "@/server/services/project";
import type { BackupSchedule } from "@dokploy/server/services/backup";
import type { Mariadb } from "@dokploy/server/services/mariadb";
import { findProjectById } from "@dokploy/server/services/project";
import {
getRemoteServiceContainer,
getServiceContainer,

View File

@@ -1,7 +1,7 @@
import path from "node:path";
import type { BackupSchedule } from "@/server/services/backup";
import type { Mongo } from "@/server/services/mongo";
import { findProjectById } from "@/server/services/project";
import type { BackupSchedule } from "@dokploy/server/services/backup";
import type { Mongo } from "@dokploy/server/services/mongo";
import { findProjectById } from "@dokploy/server/services/project";
import {
getRemoteServiceContainer,
getServiceContainer,

View File

@@ -1,8 +1,8 @@
import { unlink } from "node:fs/promises";
import path from "node:path";
import type { BackupSchedule } from "@/server/services/backup";
import type { MySql } from "@/server/services/mysql";
import { findProjectById } from "@/server/services/project";
import type { BackupSchedule } from "@dokploy/server/services/backup";
import type { MySql } from "@dokploy/server/services/mysql";
import { findProjectById } from "@dokploy/server/services/project";
import {
getRemoteServiceContainer,
getServiceContainer,

View File

@@ -1,7 +1,7 @@
import path from "node:path";
import type { BackupSchedule } from "@/server/services/backup";
import type { Postgres } from "@/server/services/postgres";
import { findProjectById } from "@/server/services/project";
import type { BackupSchedule } from "@dokploy/server/services/backup";
import type { Postgres } from "@dokploy/server/services/postgres";
import { findProjectById } from "@dokploy/server/services/project";
import {
getRemoteServiceContainer,
getServiceContainer,

View File

@@ -1,5 +1,5 @@
import type { BackupSchedule } from "@/server/services/backup";
import type { Destination } from "@/server/services/destination";
import type { BackupSchedule } from "@dokploy/server/services/backup";
import type { Destination } from "@dokploy/server/services/destination";
import { scheduleJob, scheduledJobs } from "node-schedule";
import { runMariadbBackup } from "./mariadb";
import { runMongoBackup } from "./mongo";

View File

@@ -5,8 +5,8 @@ import {
writeFileSync,
} from "node:fs";
import { dirname, join } from "node:path";
import { paths } from "@/server/constants";
import type { InferResultType } from "@/server/types/with";
import { paths } from "@dokploy/server/constants";
import type { InferResultType } from "@dokploy/server/types/with";
import boxen from "boxen";
import {
writeDomainsToCompose,

View File

@@ -1,5 +1,5 @@
import type { WriteStream } from "node:fs";
import { prepareEnvironmentVariables } from "@/server/utils/docker/utils";
import { prepareEnvironmentVariables } from "@dokploy/server/utils/docker/utils";
import type { ApplicationNested } from ".";
import {
getBuildAppDirectory,

View File

@@ -1,8 +1,8 @@
import fs from "node:fs/promises";
import path, { join } from "node:path";
import { paths } from "@/server/constants";
import type { Application } from "@/server/services/application";
import { findServerById } from "@/server/services/server";
import { paths } from "@dokploy/server/constants";
import type { Application } from "@dokploy/server/services/application";
import { findServerById } from "@dokploy/server/services/server";
import AdmZip from "adm-zip";
import { Client, type SFTPWrapper } from "ssh2";
import {

View File

@@ -1,7 +1,8 @@
import { createWriteStream } from "node:fs";
import type { InferResultType } from "@/server/types/with";
import { join } from "node:path";
import type { InferResultType } from "@dokploy/server/types/with";
import type { CreateServiceOptions } from "dockerode";
import { uploadImage } from "../cluster/upload";
import { uploadImage, uploadImageRemoteCommand } from "../cluster/upload";
import {
calculateResources,
generateBindMounts,
@@ -69,19 +70,30 @@ export const getBuildCommand = (
application: ApplicationNested,
logPath: string,
) => {
const { buildType } = application;
let command = "";
const { buildType, registry } = application;
switch (buildType) {
case "nixpacks":
return getNixpacksCommand(application, logPath);
command = getNixpacksCommand(application, logPath);
break;
case "heroku_buildpacks":
return getHerokuCommand(application, logPath);
command = getHerokuCommand(application, logPath);
break;
case "paketo_buildpacks":
return getPaketoCommand(application, logPath);
command = getPaketoCommand(application, logPath);
break;
case "static":
return getStaticCommand(application, logPath);
command = getStaticCommand(application, logPath);
break;
case "dockerfile":
return getDockerCommand(application, logPath);
command = getDockerCommand(application, logPath);
break;
}
if (registry) {
command += uploadImageRemoteCommand(application, logPath);
}
return command;
};
export const mechanizeDockerContainer = async (
@@ -186,11 +198,11 @@ const getImageName = (application: ApplicationNested) => {
return dockerImage || "ERROR-NO-IMAGE-PROVIDED";
}
const registryUrl = registry?.registryUrl || "";
const imagePrefix = registry?.imagePrefix ? `${registry.imagePrefix}/` : "";
return registry
? `${registryUrl}/${imagePrefix}${appName}`
: `${appName}:latest`;
if (registry) {
return join(registry.imagePrefix || "", appName);
}
return `${appName}:latest`;
};
const getAuthConfig = (application: ApplicationNested) => {

View File

@@ -1,6 +1,9 @@
import { type WriteStream, existsSync, mkdirSync } from "node:fs";
import path from "node:path";
import { buildStatic, getStaticCommand } from "@/server/utils/builders/static";
import {
buildStatic,
getStaticCommand,
} from "@dokploy/server/utils/builders/static";
import { nanoid } from "nanoid";
import type { ApplicationNested } from ".";
import { prepareEnvironmentVariables } from "../docker/utils";

View File

@@ -2,7 +2,7 @@ import type { WriteStream } from "node:fs";
import {
buildCustomDocker,
getDockerCommand,
} from "@/server/utils/builders/docker-file";
} from "@dokploy/server/utils/builders/docker-file";
import type { ApplicationNested } from ".";
import { createFile, getCreateFileCommand } from "../docker/utils";
import { getBuildAppDirectory } from "../filesystem/directory";

View File

@@ -1,4 +1,5 @@
import type { WriteStream } from "node:fs";
import { join } from "node:path";
import type { ApplicationNested } from "../builders";
import { spawnAsync } from "../process/spawnAsync";
@@ -16,23 +17,14 @@ export const uploadImage = async (
const { appName } = application;
const imageName = `${appName}:latest`;
const finalURL =
registryType === "selfHosted"
? process.env.NODE_ENV === "development"
? "localhost:5000"
: registryUrl
: registryUrl;
const finalURL = registryUrl;
const registryTag = imagePrefix
? `${finalURL}/${imagePrefix}/${imageName}`
: `${finalURL}/${imageName}`;
const registryTag = join(imagePrefix || "", imageName);
try {
console.log(finalURL, registryTag);
writeStream.write(
`📦 [Enabled Registry] Uploading image to ${registry.registryType} | ${registryTag} | ${finalURL}\n`,
);
await spawnAsync(
"docker",
["login", finalURL, "-u", registry.username, "-p", registry.password],
@@ -59,7 +51,48 @@ export const uploadImage = async (
throw error;
}
};
// docker:
// endpoint: "unix:///var/run/docker.sock"
// exposedByDefault: false
// swarmMode: true
export const uploadImageRemoteCommand = (
application: ApplicationNested,
logPath: string,
) => {
const registry = application.registry;
if (!registry) {
throw new Error("Registry not found");
}
const { registryUrl, imagePrefix } = registry;
const { appName } = application;
const imageName = `${appName}:latest`;
const finalURL = registryUrl;
const registryTag = join(imagePrefix || "", imageName);
try {
const command = `
echo "📦 [Enabled Registry] Uploading image to '${registry.registryType}' | '${registryTag}'" >> ${logPath};
docker login ${finalURL} -u ${registry.username} -p ${registry.password} >> ${logPath} 2>> ${logPath} || {
echo "❌ DockerHub Failed" >> ${logPath};
exit 1;
}
echo "✅ DockerHub Login Success" >> ${logPath};
docker tag ${imageName} ${registryTag} >> ${logPath} 2>> ${logPath} || {
echo "❌ Error tagging image" >> ${logPath};
exit 1;
}
echo "✅ Image Tagged" >> ${logPath};
docker push ${registryTag} 2>> ${logPath} || {
echo "❌ Error pushing image" >> ${logPath};
exit 1;
}
echo "✅ Image Pushed" >> ${logPath};
`;
return command;
} catch (error) {
console.log(error);
throw error;
}
};

View File

@@ -1,4 +1,4 @@
import type { InferResultType } from "@/server/types/with";
import type { InferResultType } from "@dokploy/server/types/with";
import type { CreateServiceOptions } from "dockerode";
import {
calculateResources,

View File

@@ -1,4 +1,4 @@
import type { InferResultType } from "@/server/types/with";
import type { InferResultType } from "@dokploy/server/types/with";
import type { CreateServiceOptions } from "dockerode";
import {
calculateResources,

View File

@@ -1,4 +1,4 @@
import type { InferResultType } from "@/server/types/with";
import type { InferResultType } from "@dokploy/server/types/with";
import type { CreateServiceOptions } from "dockerode";
import {
calculateResources,

View File

@@ -1,4 +1,4 @@
import type { InferResultType } from "@/server/types/with";
import type { InferResultType } from "@dokploy/server/types/with";
import type { CreateServiceOptions } from "dockerode";
import {
calculateResources,

View File

@@ -1,4 +1,4 @@
import type { InferResultType } from "@/server/types/with";
import type { InferResultType } from "@dokploy/server/types/with";
import type { CreateServiceOptions } from "dockerode";
import {
calculateResources,

View File

@@ -1,5 +1,5 @@
import crypto from "node:crypto";
import { findComposeById } from "@/server/services/compose";
import { findComposeById } from "@dokploy/server/services/compose";
import { dump, load } from "js-yaml";
import { addSuffixToAllConfigs } from "./compose/configs";
import { addSuffixToAllNetworks } from "./compose/network";

View File

@@ -1,9 +1,9 @@
import fs, { existsSync, readFileSync } from "node:fs";
import { writeFile } from "node:fs/promises";
import { join } from "node:path";
import { paths } from "@/server/constants";
import type { Compose } from "@/server/services/compose";
import type { Domain } from "@/server/services/domain";
import { paths } from "@dokploy/server/constants";
import type { Compose } from "@dokploy/server/services/compose";
import type { Domain } from "@dokploy/server/services/domain";
import { dump, load } from "js-yaml";
import { execAsyncRemote } from "../process/execAsync";
import {

View File

@@ -1,7 +1,7 @@
import fs from "node:fs";
import path from "node:path";
import type { Readable } from "node:stream";
import { docker, paths } from "@/server/constants";
import { docker, paths } from "@dokploy/server/constants";
import type { ContainerInfo, ResourceRequirements } from "dockerode";
import { parse } from "dotenv";
import type { ApplicationNested } from "../builders";

View File

@@ -1,7 +1,7 @@
import fs, { promises as fsPromises } from "node:fs";
import path from "node:path";
import { paths } from "@/server/constants";
import type { Application } from "@/server/services/application";
import { paths } from "@dokploy/server/constants";
import type { Application } from "@dokploy/server/services/application";
import { execAsync, execAsyncRemote } from "../process/execAsync";
export const recreateDirectory = async (pathFolder: string): Promise<void> => {

View File

@@ -1,6 +1,6 @@
import { db } from "@/server/db";
import { notifications } from "@/server/db/schema";
import BuildFailedEmail from "@/server/emails/emails/build-failed";
import { db } from "@dokploy/server/db";
import { notifications } from "@dokploy/server/db/schema";
import BuildFailedEmail from "@dokploy/server/emails/emails/build-failed";
import { renderAsync } from "@react-email/components";
import { eq } from "drizzle-orm";
import {

View File

@@ -1,6 +1,6 @@
import { db } from "@/server/db";
import { notifications } from "@/server/db/schema";
import BuildSuccessEmail from "@/server/emails/emails/build-success";
import { db } from "@dokploy/server/db";
import { notifications } from "@dokploy/server/db/schema";
import BuildSuccessEmail from "@dokploy/server/emails/emails/build-success";
import { renderAsync } from "@react-email/components";
import { eq } from "drizzle-orm";
import {

View File

@@ -1,6 +1,6 @@
import { db } from "@/server/db";
import { notifications } from "@/server/db/schema";
import DatabaseBackupEmail from "@/server/emails/emails/database-backup";
import { db } from "@dokploy/server/db";
import { notifications } from "@dokploy/server/db/schema";
import DatabaseBackupEmail from "@dokploy/server/emails/emails/database-backup";
import { renderAsync } from "@react-email/components";
import { eq } from "drizzle-orm";
import {

View File

@@ -1,6 +1,6 @@
import { db } from "@/server/db";
import { notifications } from "@/server/db/schema";
import DockerCleanupEmail from "@/server/emails/emails/docker-cleanup";
import { db } from "@dokploy/server/db";
import { notifications } from "@dokploy/server/db/schema";
import DockerCleanupEmail from "@dokploy/server/emails/emails/docker-cleanup";
import { renderAsync } from "@react-email/components";
import { eq } from "drizzle-orm";
import {

View File

@@ -1,6 +1,6 @@
import { db } from "@/server/db";
import { notifications } from "@/server/db/schema";
import DokployRestartEmail from "@/server/emails/emails/dokploy-restart";
import { db } from "@dokploy/server/db";
import { notifications } from "@dokploy/server/db/schema";
import DokployRestartEmail from "@dokploy/server/emails/emails/dokploy-restart";
import { renderAsync } from "@react-email/components";
import { eq } from "drizzle-orm";
import {

View File

@@ -1,4 +1,9 @@
import type { discord, email, slack, telegram } from "@/server/db/schema";
import type {
discord,
email,
slack,
telegram,
} from "@dokploy/server/db/schema";
import nodemailer from "nodemailer";
export const sendEmailNotification = async (

View File

@@ -1,6 +1,6 @@
import { exec } from "node:child_process";
import util from "node:util";
import { findServerById } from "@/server/services/server";
import { findServerById } from "@dokploy/server/services/server";
import { Client } from "ssh2";
export const execAsync = util.promisify(exec);

View File

@@ -1,13 +1,13 @@
import { createWriteStream } from "node:fs";
import { join } from "node:path";
import { paths } from "@/server/constants";
import { paths } from "@dokploy/server/constants";
import type {
apiBitbucketTestConnection,
apiFindBitbucketBranches,
} from "@/server/db/schema";
import { findBitbucketById } from "@/server/services/bitbucket";
import type { Compose } from "@/server/services/compose";
import type { InferResultType } from "@/server/types/with";
} from "@dokploy/server/db/schema";
import { findBitbucketById } from "@dokploy/server/services/bitbucket";
import type { Compose } from "@dokploy/server/services/compose";
import type { InferResultType } from "@dokploy/server/types/with";
import { TRPCError } from "@trpc/server";
import { recreateDirectory } from "../filesystem/directory";
import { execAsyncRemote } from "../process/execAsync";
@@ -227,42 +227,42 @@ export const getBitbucketRepositories = async (bitbucketId?: string) => {
const username =
bitbucketProvider.bitbucketWorkspaceName ||
bitbucketProvider.bitbucketUsername;
const url = `https://api.bitbucket.org/2.0/repositories/${username}?pagelen=100`;
let url = `https://api.bitbucket.org/2.0/repositories/${username}?pagelen=100`;
let repositories: {
name: string;
url: string;
owner: { username: string };
}[] = [];
try {
const response = await fetch(url, {
method: "GET",
headers: {
Authorization: `Basic ${Buffer.from(`${bitbucketProvider.bitbucketUsername}:${bitbucketProvider.appPassword}`).toString("base64")}`,
},
});
if (!response.ok) {
throw new TRPCError({
code: "BAD_REQUEST",
message: `Failed to fetch repositories: ${response.statusText}`,
while (url) {
const response = await fetch(url, {
method: "GET",
headers: {
Authorization: `Basic ${Buffer.from(`${bitbucketProvider.bitbucketUsername}:${bitbucketProvider.appPassword}`).toString("base64")}`,
},
});
}
const data = await response.json();
if (!response.ok) {
throw new TRPCError({
code: "BAD_REQUEST",
message: `Failed to fetch repositories: ${response.statusText}`,
});
}
const mappedData = data.values.map((repo: any) => {
return {
const data = await response.json();
const mappedData = data.values.map((repo: any) => ({
name: repo.name,
url: repo.links.html.href,
owner: {
username: repo.workspace.slug,
},
};
});
return mappedData as {
name: string;
url: string;
owner: {
username: string;
};
}[];
}));
repositories = repositories.concat(mappedData);
url = data.next || null;
}
return repositories;
} catch (error) {
throw error;
}

View File

@@ -1,8 +1,11 @@
import { createWriteStream } from "node:fs";
import path, { join } from "node:path";
import { paths } from "@/server/constants";
import type { Compose } from "@/server/services/compose";
import { findSSHKeyById, updateSSHKeyById } from "@/server/services/ssh-key";
import { paths } from "@dokploy/server/constants";
import type { Compose } from "@dokploy/server/services/compose";
import {
findSSHKeyById,
updateSSHKeyById,
} from "@dokploy/server/services/ssh-key";
import { TRPCError } from "@trpc/server";
import { recreateDirectory } from "../filesystem/directory";
import { execAsync, execAsyncRemote } from "../process/execAsync";
@@ -55,8 +58,6 @@ export const cloneGitRepository = async (
await addHostToKnownHosts(customGitUrl);
}
await recreateDirectory(outputPath);
// const command = `GIT_SSH_COMMAND="ssh -i ${keyPath} -o UserKnownHostsFile=${knownHostsPath}" git clone --branch ${customGitBranch} --depth 1 ${customGitUrl} ${gitCopyPath} --progress`;
// const { stdout, stderr } = await execAsync(command);
writeStream.write(
`\nCloning Repo Custom ${customGitUrl} to ${outputPath}: ✅\n`,
);
@@ -187,7 +188,6 @@ export const getCustomGitCloneCommand = async (
command.push(`echo "Cloned Custom Git ${customGitUrl}: ✅" >> ${logPath};`);
return command.join("\n");
} catch (error) {
console.log(error);
throw error;
}
};

View File

@@ -1,16 +1,16 @@
import { createWriteStream } from "node:fs";
import { join } from "node:path";
import { paths } from "@/server/constants";
import type { InferResultType } from "@/server/types/with";
import { paths } from "@dokploy/server/constants";
import type { InferResultType } from "@dokploy/server/types/with";
import { createAppAuth } from "@octokit/auth-app";
import { TRPCError } from "@trpc/server";
import { Octokit } from "octokit";
import { recreateDirectory } from "../filesystem/directory";
import { spawnAsync } from "../process/spawnAsync";
import type { apiFindGithubBranches } from "@/server/db/schema";
import type { Compose } from "@/server/services/compose";
import { type Github, findGithubById } from "@/server/services/github";
import type { apiFindGithubBranches } from "@dokploy/server/db/schema";
import type { Compose } from "@dokploy/server/services/compose";
import { type Github, findGithubById } from "@dokploy/server/services/github";
import { execAsyncRemote } from "../process/execAsync";
export const authGithub = (githubProvider: Github): Octokit => {

View File

@@ -1,14 +1,14 @@
import { createWriteStream } from "node:fs";
import { join } from "node:path";
import { paths } from "@/server/constants";
import type { apiGitlabTestConnection } from "@/server/db/schema";
import type { Compose } from "@/server/services/compose";
import { paths } from "@dokploy/server/constants";
import type { apiGitlabTestConnection } from "@dokploy/server/db/schema";
import type { Compose } from "@dokploy/server/services/compose";
import {
type Gitlab,
findGitlabById,
updateGitlab,
} from "@/server/services/gitlab";
import type { InferResultType } from "@/server/types/with";
} from "@dokploy/server/services/gitlab";
import type { InferResultType } from "@dokploy/server/types/with";
import { TRPCError } from "@trpc/server";
import { recreateDirectory } from "../filesystem/directory";
import { execAsyncRemote } from "../process/execAsync";
@@ -47,8 +47,6 @@ export const refreshGitlabToken = async (gitlabProviderId: string) => {
const expiresAt = Math.floor(Date.now() / 1000) + data.expires_in;
console.log("Refreshed token");
await updateGitlab(gitlabProviderId, {
accessToken: data.access_token,
refreshToken: data.refresh_token,

View File

@@ -1,8 +1,8 @@
import { createWriteStream } from "node:fs";
import { writeFile } from "node:fs/promises";
import { join } from "node:path";
import { paths } from "@/server/constants";
import type { Compose } from "@/server/services/compose";
import { paths } from "@dokploy/server/constants";
import type { Compose } from "@dokploy/server/services/compose";
import { encodeBase64 } from "../docker/utils";
import { recreateDirectory } from "../filesystem/directory";
import { execAsyncRemote } from "../process/execAsync";

View File

@@ -1,5 +1,5 @@
import { docker } from "@/server/constants";
import { findServerById } from "@/server/services/server";
import { docker } from "@dokploy/server/constants";
import { findServerById } from "@dokploy/server/services/server";
import Dockerode from "dockerode";
export const getRemoteDocker = async (serverId?: string | null) => {

View File

@@ -1,7 +1,7 @@
import fs, { writeFileSync } from "node:fs";
import path from "node:path";
import { paths } from "@/server/constants";
import type { Domain } from "@/server/services/domain";
import { paths } from "@dokploy/server/constants";
import type { Domain } from "@dokploy/server/services/domain";
import { dump, load } from "js-yaml";
import { encodeBase64 } from "../docker/utils";
import { execAsyncRemote } from "../process/execAsync";

View File

@@ -1,4 +1,4 @@
import type { Domain } from "@/server/services/domain";
import type { Domain } from "@dokploy/server/services/domain";
import type { ApplicationNested } from "../builders";
import {
createServiceConfig,

View File

@@ -1,6 +1,6 @@
import { existsSync, readFileSync, writeFileSync } from "node:fs";
import { join } from "node:path";
import { paths } from "@/server/constants";
import { paths } from "@dokploy/server/constants";
import { dump, load } from "js-yaml";
import type { ApplicationNested } from "../builders";
import { execAsyncRemote } from "../process/execAsync";

View File

@@ -1,4 +1,4 @@
import type { Redirect } from "@/server/services/redirect";
import type { Redirect } from "@dokploy/server/services/redirect";
import type { ApplicationNested } from "../builders";
import {
loadOrCreateConfig,

View File

@@ -1,75 +0,0 @@
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { join } from "node:path";
import { paths } from "@/server/constants";
import type { Registry } from "@/server/services/registry";
import { dump, load } from "js-yaml";
import { removeDirectoryIfExistsContent } from "../filesystem/directory";
import type { FileConfig, HttpRouter } from "./file-types";
export const manageRegistry = async (registry: Registry) => {
const { REGISTRY_PATH } = paths();
if (!existsSync(REGISTRY_PATH)) {
mkdirSync(REGISTRY_PATH, { recursive: true });
}
const appName = "dokploy-registry";
const config: FileConfig = loadOrCreateConfig();
const serviceName = `${appName}-service`;
const routerName = `${appName}-router`;
config.http = config.http || { routers: {}, services: {} };
config.http.routers = config.http.routers || {};
config.http.services = config.http.services || {};
config.http.routers[routerName] = await createRegistryRouterConfig(registry);
config.http.services[serviceName] = {
loadBalancer: {
servers: [{ url: `http://${appName}:5000` }],
passHostHeader: true,
},
};
const yamlConfig = dump(config);
const configFile = join(REGISTRY_PATH, "registry.yml");
writeFileSync(configFile, yamlConfig);
};
export const removeSelfHostedRegistry = async () => {
const { REGISTRY_PATH } = paths();
await removeDirectoryIfExistsContent(REGISTRY_PATH);
};
const createRegistryRouterConfig = async (registry: Registry) => {
const { registryUrl } = registry;
const routerConfig: HttpRouter = {
rule: `Host(\`${registryUrl}\`)`,
service: "dokploy-registry-service",
middlewares: ["redirect-to-https"],
entryPoints: [
"web",
...(process.env.NODE_ENV === "production" ? ["websecure"] : []),
],
...(process.env.NODE_ENV === "production"
? {
tls: { certResolver: "letsencrypt" },
}
: {}),
};
return routerConfig;
};
const loadOrCreateConfig = (): FileConfig => {
const { REGISTRY_PATH } = paths();
const configPath = join(REGISTRY_PATH, "registry.yml");
if (existsSync(configPath)) {
const yamlStr = readFileSync(configPath, "utf8");
const parsedConfig = (load(yamlStr) as FileConfig) || {
http: { routers: {}, services: {} },
};
return parsedConfig;
}
return { http: { routers: {}, services: {} } };
};

View File

@@ -1,4 +1,4 @@
import type { Security } from "@/server/services/security";
import type { Security } from "@dokploy/server/services/security";
import * as bcrypt from "bcrypt";
import type { ApplicationNested } from "../builders";
import {

View File

@@ -1,7 +1,7 @@
import { existsSync, readFileSync, writeFileSync } from "node:fs";
import { join } from "node:path";
import { paths } from "@/server/constants";
import type { Admin } from "@/server/services/admin";
import { paths } from "@dokploy/server/constants";
import type { Admin } from "@dokploy/server/services/admin";
import { dump, load } from "js-yaml";
import { loadOrCreateConfig, writeTraefikConfig } from "./application";
import type { FileConfig } from "./file-types";

View File

@@ -1,5 +1,5 @@
import type http from "node:http";
import { findServerById } from "@/server/services/server";
import { findServerById } from "@dokploy/server/services/server";
import { spawn } from "node-pty";
import { Client } from "ssh2";
import { WebSocketServer } from "ws";
@@ -64,7 +64,6 @@ export const setupDockerContainerLogsWebSocketServer = (
}
stream
.on("close", () => {
console.log("Connection closed ✅");
client.end();
resolve();
})

View File

@@ -1,5 +1,5 @@
import type http from "node:http";
import { findServerById } from "@/server/services/server";
import { findServerById } from "@dokploy/server/services/server";
import { spawn } from "node-pty";
import { Client } from "ssh2";
import { WebSocketServer } from "ws";
@@ -63,9 +63,6 @@ export const setupDockerContainerTerminalWebSocketServer = (
stream
.on("close", (code: number, signal: string) => {
console.log(
`Stream :: close :: code: ${code}, signal: ${signal}`,
);
ws.send(`\nContainer closed with code: ${code}\n`);
conn.end();
})

View File

@@ -1,6 +1,6 @@
import { spawn } from "node:child_process";
import type http from "node:http";
import { findServerById } from "@/server/services/server";
import { findServerById } from "@dokploy/server/services/server";
import { Client } from "ssh2";
import { WebSocketServer } from "ws";
import { validateWebSocketRequest } from "../auth/auth";
@@ -33,7 +33,6 @@ export const setupDeploymentLogsWebSocketServer = (
const { user, session } = await validateWebSocketRequest(req);
if (!logPath) {
console.log("logPath no provided");
ws.close(4000, "logPath no provided");
return;
}
@@ -63,7 +62,6 @@ export const setupDeploymentLogsWebSocketServer = (
}
stream
.on("close", () => {
console.log("Connection closed ✅");
client.end();
resolve();
})

View File

@@ -1,6 +1,6 @@
import type http from "node:http";
import path from "node:path";
import { findServerById } from "@/server/services/server";
import { findServerById } from "@dokploy/server/services/server";
import { spawn } from "node-pty";
import { publicIpv4, publicIpv6 } from "public-ip";
import { WebSocketServer } from "ws";