Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
9544b2a
fix(backups): optional chaining for logCleanupCron
AbdenourTadjer33 Dec 10, 2025
e7dc05d
Merge pull request #3221 from AbdenourTadjer33/patch-1
Siumauricio Dec 10, 2025
a04a4c0
chore(dependencies): update Next.js to version 16.0.10 and remove tur…
Siumauricio Dec 12, 2025
b499cef
Merge pull request #3250 from Dokploy/3249-cant-enable-volume-backup-…
Siumauricio Dec 12, 2025
b230687
fix(environment): prevent renaming of the default environment
Siumauricio Dec 12, 2025
1c83919
fix(environment): prevent deletion of the default environment
Siumauricio Dec 12, 2025
7cf898d
Merge pull request #3251 from Dokploy/3247-cannot-edit-production-env…
Siumauricio Dec 12, 2025
4f6eb51
fix(environment): clarify .env file creation instructions
Siumauricio Dec 12, 2025
3799aea
Merge pull request #3252 from Dokploy/3231-env-file-is-generated-in-d…
Siumauricio Dec 12, 2025
ee9edd7
chore(version): bump dokploy version to v0.26.2
Siumauricio Dec 12, 2025
a32e7e0
fix(build-server): enforce selection rules for Build Server and Build…
Siumauricio Dec 13, 2025
092afbe
fix(dashboard): update project environment link to use default produc…
Siumauricio Dec 13, 2025
2976bb5
Merge pull request #3257 from Dokploy/fix/add-remove-build-registry
Siumauricio Dec 13, 2025
fea3ec9
feat(cleanup): implement background cleanup functionality
Siumauricio Dec 13, 2025
12b8f8a
fix(storage): update success message for cleaning action
Siumauricio Dec 13, 2025
415327c
fix(storage): enhance success message for cleaning action to include …
Siumauricio Dec 13, 2025
5f13679
Merge pull request #3258 from Dokploy/fix/long-request-on-cleanup
Siumauricio Dec 13, 2025
d187b52
refactor(deploy): execute deployments in background to prevent timeouts
Siumauricio Dec 13, 2025
0b45b79
Merge pull request #3259 from Dokploy/2680-webhook-deployments-do-not…
Siumauricio Dec 13, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .github/sponsors/awesome.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,9 @@ For detailed documentation, visit [docs.dokploy.com](https://docs.dokploy.com).
<a href="https://www.lambdatest.com/?utm_source=dokploy&utm_medium=sponsor" target="_blank">
<img src="https://www.lambdatest.com/blue-logo.png" width="450" height="100" />
</a>

<a href="https://awesome.tools/" target="_blank">
<img src=".github/sponsors/awesome.png" width="200" height="150" />
</a>
</div>

<!-- Premium Supporters πŸ₯‡ -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,31 @@ interface Props {
applicationId: string;
}

const schema = z.object({
buildServerId: z.string().min(1, "Build server is required"),
buildRegistryId: z.string().min(1, "Build registry is required"),
});
const schema = z
.object({
buildServerId: z.string().optional(),
buildRegistryId: z.string().optional(),
})
.refine(
(data) => {
// Both empty/none is valid
const buildServerIsNone =
!data.buildServerId || data.buildServerId === "none";
const buildRegistryIsNone =
!data.buildRegistryId || data.buildRegistryId === "none";

// Both should be either filled or empty
if (buildServerIsNone && buildRegistryIsNone) return true;
if (!buildServerIsNone && !buildRegistryIsNone) return true;

return false;
},
{
message:
"Both Build Server and Build Registry must be selected together, or both set to None",
path: ["buildServerId"], // Show error on buildServerId field
},
);

type Schema = z.infer<typeof schema>;

Expand Down Expand Up @@ -121,6 +142,11 @@ export const ShowBuildServer = ({ applicationId }: Props) => {
container starts running.
</AlertBlock>

<AlertBlock type="info">
<strong>Note:</strong> Build Server and Build Registry must be
configured together. You can either select both or set both to None.
</AlertBlock>

{!registries || registries.length === 0 ? (
<AlertBlock type="warning">
You need to add at least one registry to use build servers. Please
Expand All @@ -147,7 +173,13 @@ export const ShowBuildServer = ({ applicationId }: Props) => {
<FormItem>
<FormLabel>Build Server</FormLabel>
<Select
onValueChange={field.onChange}
onValueChange={(value) => {
field.onChange(value);
// If setting to "none", also reset build registry to "none"
if (value === "none") {
form.setValue("buildRegistryId", "none");
}
}}
value={field.value || "none"}
>
<FormControl>
Expand Down Expand Up @@ -197,7 +229,13 @@ export const ShowBuildServer = ({ applicationId }: Props) => {
<FormItem>
<FormLabel>Build Registry</FormLabel>
<Select
onValueChange={field.onChange}
onValueChange={(value) => {
field.onChange(value);
// If setting to "none", also reset build server to "none"
if (value === "none") {
form.setValue("buildServerId", "none");
}
}}
value={field.value || "none"}
>
<FormControl>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,9 +191,10 @@ export const ShowEnvironment = ({ applicationId }: Props) => {
<div className="space-y-0.5">
<FormLabel>Create Environment File</FormLabel>
<FormDescription>
When enabled, an .env file will be created during the
build process. Disable this if you don't want to generate
an environment file.
When enabled, an .env file will be created in the same
directory as your Dockerfile during the build process.
Disable this if you don't want to generate an environment
file.
</FormDescription>
</div>
<FormControl>
Expand Down
6 changes: 5 additions & 1 deletion apps/dokploy/components/dashboard/projects/show.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -286,13 +286,17 @@ export const ShowProjects = () => {
)
.some(Boolean);

const productionEnvironment = project?.environments.find(
(env) => env.isDefault,
);

return (
<div
key={project.projectId}
className="w-full lg:max-w-md"
>
<Link
href={`/dashboard/project/${project.projectId}/environment/${project?.environments?.[0]?.environmentId}`}
href={`/dashboard/project/${project.projectId}/environment/${productionEnvironment?.environmentId}`}
>
<Card className="group relative w-full h-full bg-transparent transition-colors hover:bg-border">
{haveServicesWithDomains ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,7 @@ export const HandleNotifications = ({ notificationId }: Props) => {
webhookUrl: notification.lark?.webhookUrl,
name: notification.name,
dockerCleanup: notification.dockerCleanup,
volumeBackup: notification.volumeBackup,
serverThreshold: notification.serverThreshold,
});
} else if (notification.notificationType === "custom") {
Expand All @@ -388,6 +389,7 @@ export const HandleNotifications = ({ notificationId }: Props) => {
)
: [],
name: notification.name,
volumeBackup: notification.volumeBackup,
dockerCleanup: notification.dockerCleanup,
serverThreshold: notification.serverThreshold,
});
Expand Down Expand Up @@ -522,6 +524,7 @@ export const HandleNotifications = ({ notificationId }: Props) => {
appDeploy: appDeploy,
dokployRestart: dokployRestart,
databaseBackup: databaseBackup,
volumeBackup: volumeBackup,
webhookUrl: data.webhookUrl,
name: data.name,
dockerCleanup: dockerCleanup,
Expand All @@ -547,6 +550,7 @@ export const HandleNotifications = ({ notificationId }: Props) => {
appDeploy: appDeploy,
dokployRestart: dokployRestart,
databaseBackup: databaseBackup,
volumeBackup: volumeBackup,
endpoint: data.endpoint,
headers: headersRecord,
name: data.name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ export const ShowStorageActions = ({ serverId }: Props) => {
serverId: serverId,
})
.then(async () => {
toast.success("Cleaned all");
toast.success("Cleaning in progress... Please wait");
})
.catch(() => {
toast.error("Error cleaning all");
Expand Down
5 changes: 2 additions & 3 deletions apps/dokploy/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "dokploy",
"version": "v0.26.1",
"version": "v0.26.2",
"private": true,
"license": "Apache-2.0",
"type": "module",
Expand All @@ -13,7 +13,6 @@
"reset-password": "node -r dotenv/config dist/reset-password.mjs",
"reset-2fa": "node -r dotenv/config dist/reset-2fa.mjs",
"dev": "tsx -r dotenv/config ./server/server.ts --project tsconfig.server.json ",
"dev-turbopack": "TURBOPACK=1 tsx -r dotenv/config ./server/server.ts --project tsconfig.server.json",
"studio": "drizzle-kit studio --config ./server/db/drizzle.config.ts",
"migration:generate": "drizzle-kit generate --config ./server/db/drizzle.config.ts",
"migration:run": "tsx -r dotenv/config migration.ts",
Expand Down Expand Up @@ -118,7 +117,7 @@
"lucide-react": "^0.469.0",
"micromatch": "4.0.8",
"nanoid": "3.3.11",
"next": "^16.0.7",
"next": "^16.0.10",
"next-i18next": "^15.4.2",
"next-themes": "^0.2.1",
"nextjs-toploader": "^3.9.17",
Expand Down
22 changes: 12 additions & 10 deletions apps/dokploy/pages/api/deploy/[refreshToken].ts
Original file line number Diff line number Diff line change
Expand Up @@ -242,17 +242,19 @@ export default async function handler(

if (IS_CLOUD && application.serverId) {
jobData.serverId = application.serverId;
await deploy(jobData);
return true;
deploy(jobData).catch((error) => {
console.error("Background deployment failed:", error);
});
} else {
await myQueue.add(
"deployments",
{ ...jobData },
{
removeOnComplete: true,
removeOnFail: true,
},
);
}
await myQueue.add(
"deployments",
{ ...jobData },
{
removeOnComplete: true,
removeOnFail: true,
},
);
} catch (error) {
res.status(400).json({ message: "Error deploying Application", error });
return;
Expand Down
22 changes: 12 additions & 10 deletions apps/dokploy/pages/api/deploy/compose/[refreshToken].ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,17 +179,19 @@ export default async function handler(

if (IS_CLOUD && composeResult.serverId) {
jobData.serverId = composeResult.serverId;
await deploy(jobData);
return true;
deploy(jobData).catch((error) => {
console.error("Background deployment failed:", error);
});
} else {
await myQueue.add(
"deployments",
{ ...jobData },
{
removeOnComplete: true,
removeOnFail: true,
},
);
}
await myQueue.add(
"deployments",
{ ...jobData },
{
removeOnComplete: true,
removeOnFail: true,
},
);
} catch (error) {
res.status(400).json({ message: "Error deploying Compose", error });
return;
Expand Down
20 changes: 15 additions & 5 deletions apps/dokploy/pages/api/deploy/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,9 @@ export default async function handler(

if (IS_CLOUD && app.serverId) {
jobData.serverId = app.serverId;
await deploy(jobData);
deploy(jobData).catch((error) => {
console.error("Background deployment failed:", error);
});
continue;
}
await myQueue.add(
Expand Down Expand Up @@ -165,7 +167,9 @@ export default async function handler(

if (IS_CLOUD && composeApp.serverId) {
jobData.serverId = composeApp.serverId;
await deploy(jobData);
deploy(jobData).catch((error) => {
console.error("Background deployment failed:", error);
});
continue;
}

Expand Down Expand Up @@ -246,7 +250,9 @@ export default async function handler(

if (IS_CLOUD && app.serverId) {
jobData.serverId = app.serverId;
await deploy(jobData);
deploy(jobData).catch((error) => {
console.error("Background deployment failed:", error);
});
continue;
}
await myQueue.add(
Expand Down Expand Up @@ -291,7 +297,9 @@ export default async function handler(
}
if (IS_CLOUD && composeApp.serverId) {
jobData.serverId = composeApp.serverId;
await deploy(jobData);
deploy(jobData).catch((error) => {
console.error("Background deployment failed:", error);
});
continue;
}

Expand Down Expand Up @@ -491,7 +499,9 @@ export default async function handler(

if (IS_CLOUD && app.serverId) {
jobData.serverId = app.serverId;
await deploy(jobData);
deploy(jobData).catch((error) => {
console.error("Background deployment failed:", error);
});
continue;
}
await myQueue.add(
Expand Down
12 changes: 9 additions & 3 deletions apps/dokploy/server/api/routers/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,9 @@ export const applicationRouter = createTRPCRouter({

if (IS_CLOUD && application.serverId) {
jobData.serverId = application.serverId;
await deploy(jobData);
deploy(jobData).catch((error) => {
console.error("Background deployment failed:", error);
});
return true;
}
await myQueue.add(
Expand Down Expand Up @@ -701,7 +703,9 @@ export const applicationRouter = createTRPCRouter({
};
if (IS_CLOUD && application.serverId) {
jobData.serverId = application.serverId;
await deploy(jobData);
deploy(jobData).catch((error) => {
console.error("Background deployment failed:", error);
});

return true;
}
Expand Down Expand Up @@ -813,7 +817,9 @@ export const applicationRouter = createTRPCRouter({
};
if (IS_CLOUD && app.serverId) {
jobData.serverId = app.serverId;
await deploy(jobData);
deploy(jobData).catch((error) => {
console.error("Background deployment failed:", error);
});
return true;
}

Expand Down
8 changes: 6 additions & 2 deletions apps/dokploy/server/api/routers/compose.ts
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,9 @@ export const composeRouter = createTRPCRouter({

if (IS_CLOUD && compose.serverId) {
jobData.serverId = compose.serverId;
await deploy(jobData);
deploy(jobData).catch((error) => {
console.error("Background deployment failed:", error);
});
return true;
}
await myQueue.add(
Expand Down Expand Up @@ -453,7 +455,9 @@ export const composeRouter = createTRPCRouter({
};
if (IS_CLOUD && compose.serverId) {
jobData.serverId = compose.serverId;
await deploy(jobData);
deploy(jobData).catch((error) => {
console.error("Background deployment failed:", error);
});
return true;
}
await myQueue.add(
Expand Down
13 changes: 11 additions & 2 deletions apps/dokploy/server/api/routers/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,14 @@ export const environmentRouter = createTRPCRouter({
});
}

// Prevent deletion of the default environment
if (environment.isDefault) {
throw new TRPCError({
code: "BAD_REQUEST",
message: "You cannot delete the default environment",
});
}

// Check environment deletion permission
await checkEnvironmentDeletionPermission(
ctx.user.id,
Expand Down Expand Up @@ -256,10 +264,11 @@ export const environmentRouter = createTRPCRouter({
}
const currentEnvironment = await findEnvironmentById(environmentId);

if (currentEnvironment.isDefault) {
// Prevent renaming the default environment, but allow updating env and description
if (currentEnvironment.isDefault && updateData.name !== undefined) {
throw new TRPCError({
code: "BAD_REQUEST",
message: "You cannot update the default environment",
message: "You cannot rename the default environment",
});
}
if (
Expand Down
Loading