diff --git a/GUIDES.md b/GUIDES.md index cfb7cd81..90fba522 100644 --- a/GUIDES.md +++ b/GUIDES.md @@ -16,28 +16,29 @@ Here's how to install docker on different operating systems: ### Ubuntu ```bash +# Uninstall old versions +for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done + # Update package index sudo apt-get update # Install prerequisites -sudo apt-get install \ - apt-transport-https \ - ca-certificates \ - curl \ - gnupg \ - lsb-release +sudo apt-get install ca-certificates curl +sudo install -m 0755 -d /etc/apt/keyrings # Add Docker's official GPG key -curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg +sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc +sudo chmod a+r /etc/apt/keyrings/docker.asc -# Set up stable repository +# Add the repository to Apt sources echo \ - "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \ - $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null + "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \ + $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | \ + sudo tee /etc/apt/sources.list.d/docker.list > /dev/null # Install Docker Engine sudo apt-get update -sudo apt-get install docker-ce docker-ce-cli containerd.io +sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin ``` ## Windows diff --git a/LICENSE.MD b/LICENSE.MD index 7e49a35b..6cbef2c6 100644 --- a/LICENSE.MD +++ b/LICENSE.MD @@ -2,7 +2,7 @@ ## Core License (Apache License 2.0) -Copyright 2024 Mauricio Siu. +Copyright 2025 Mauricio Siu. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index e2969f76..f156d318 100644 --- a/README.md +++ b/README.md @@ -62,46 +62,26 @@ For detailed documentation, visit [docs.dokploy.com](https://docs.dokploy.com). ### Hero Sponsors 🎖
- - Hostinger - - - LX Aer - - - Mandarin - - - Lightnode - + Hostinger + LX Aer + Mandarin + Lightnode -
### Premium Supporters 🥇
- - Supafort.com - - - - agentdock.ai - + Supafort.com + agentdock.ai
### Elite Contributors 🥈
- - - AmericanCloud - - - - Tolgee - + AmericanCloud + Tolgee
diff --git a/apps/dokploy/LICENSE.MD b/apps/dokploy/LICENSE.MD deleted file mode 100644 index 8a508efb..00000000 --- a/apps/dokploy/LICENSE.MD +++ /dev/null @@ -1,26 +0,0 @@ -# License - -## Core License (Apache License 2.0) - -Copyright 2024 Mauricio Siu. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and limitations under the License. - -## Additional Terms for Specific Features - -The following additional terms apply to the multi-node support, Docker Compose file, Preview Deployments and Multi Server features of Dokploy. In the event of a conflict, these provisions shall take precedence over those in the Apache License: - -- **Self-Hosted Version Free**: All features of Dokploy, including multi-node support, Docker Compose file support, Preview Deployments and Multi Server, will always be free to use in the self-hosted version. -- **Restriction on Resale**: The multi-node support, Docker Compose file support, Preview Deployments and Multi Server features cannot be sold or offered as a service by any party other than the copyright holder without prior written consent. -- **Modification Distribution**: Any modifications to the multi-node support, Docker Compose file support, Preview Deployments and Multi Server features must be distributed freely and cannot be sold or offered as a service. - -For further inquiries or permissions, please contact us directly. diff --git a/apps/dokploy/components/dashboard/application/advanced/cluster/modify-swarm-settings.tsx b/apps/dokploy/components/dashboard/application/advanced/cluster/modify-swarm-settings.tsx index 95a559f6..ae30a799 100644 --- a/apps/dokploy/components/dashboard/application/advanced/cluster/modify-swarm-settings.tsx +++ b/apps/dokploy/components/dashboard/application/advanced/cluster/modify-swarm-settings.tsx @@ -130,7 +130,7 @@ const createStringToJSONSchema = (schema: z.ZodTypeAny) => { } try { return JSON.parse(str); - } catch (_e) { + } catch { ctx.addIssue({ code: "custom", message: "Invalid JSON format" }); return z.NEVER; } diff --git a/apps/dokploy/components/dashboard/application/advanced/import/show-import.tsx b/apps/dokploy/components/dashboard/application/advanced/import/show-import.tsx index aa359d67..d44455b2 100644 --- a/apps/dokploy/components/dashboard/application/advanced/import/show-import.tsx +++ b/apps/dokploy/components/dashboard/application/advanced/import/show-import.tsx @@ -107,7 +107,7 @@ export const ShowImport = ({ composeId }: Props) => { composeId, }); setShowModal(false); - } catch (_error) { + } catch { toast.error("Error importing template"); } }; @@ -126,7 +126,7 @@ export const ShowImport = ({ composeId }: Props) => { }); setTemplateInfo(result); setShowModal(true); - } catch (_error) { + } catch { toast.error("Error processing template"); } }; diff --git a/apps/dokploy/components/dashboard/application/advanced/ports/handle-ports.tsx b/apps/dokploy/components/dashboard/application/advanced/ports/handle-ports.tsx index c9758e37..ad0c0ac3 100644 --- a/apps/dokploy/components/dashboard/application/advanced/ports/handle-ports.tsx +++ b/apps/dokploy/components/dashboard/application/advanced/ports/handle-ports.tsx @@ -35,6 +35,9 @@ import { z } from "zod"; const AddPortSchema = z.object({ publishedPort: z.number().int().min(1).max(65535), + publishMode: z.enum(["ingress", "host"], { + required_error: "Publish mode is required", + }), targetPort: z.number().int().min(1).max(65535), protocol: z.enum(["tcp", "udp"], { required_error: "Protocol is required", @@ -80,6 +83,7 @@ export const HandlePorts = ({ useEffect(() => { form.reset({ publishedPort: data?.publishedPort ?? 0, + publishMode: data?.publishMode ?? "ingress", targetPort: data?.targetPort ?? 0, protocol: data?.protocol ?? "tcp", }); @@ -165,6 +169,32 @@ export const HandlePorts = ({ )} /> + { + return ( + + Published Port Mode + + + + ); + }} + /> { {data?.ports.map((port) => (
-
+
Published Port @@ -68,7 +68,13 @@ export const ShowPorts = ({ applicationId }: Props) => {
- Target Port + Published Port Mode + + {port?.publishMode?.toUpperCase()} + +
+
+ Target Port {port.targetPort} diff --git a/apps/dokploy/components/dashboard/compose/general/compose-file-editor.tsx b/apps/dokploy/components/dashboard/compose/general/compose-file-editor.tsx index 63ff189d..41e40efb 100644 --- a/apps/dokploy/components/dashboard/compose/general/compose-file-editor.tsx +++ b/apps/dokploy/components/dashboard/compose/general/compose-file-editor.tsx @@ -77,7 +77,7 @@ export const ComposeFileEditor = ({ composeId }: Props) => { composeId, }); }) - .catch((_e) => { + .catch(() => { toast.error("Error updating the Compose config"); }); }; diff --git a/apps/dokploy/components/dashboard/compose/general/show-converted-compose.tsx b/apps/dokploy/components/dashboard/compose/general/show-converted-compose.tsx index 77f331bd..4370dcf8 100644 --- a/apps/dokploy/components/dashboard/compose/general/show-converted-compose.tsx +++ b/apps/dokploy/components/dashboard/compose/general/show-converted-compose.tsx @@ -40,7 +40,7 @@ export const ShowConvertedCompose = ({ composeId }: Props) => { .then(() => { refetch(); }) - .catch((_err) => {}); + .catch(() => {}); } }, [isOpen]); diff --git a/apps/dokploy/components/dashboard/project/add-application.tsx b/apps/dokploy/components/dashboard/project/add-application.tsx index c93de251..6b0a690d 100644 --- a/apps/dokploy/components/dashboard/project/add-application.tsx +++ b/apps/dokploy/components/dashboard/project/add-application.tsx @@ -103,7 +103,7 @@ export const AddApplication = ({ projectId, projectName }: Props) => { projectId, }); }) - .catch((_e) => { + .catch(() => { toast.error("Error creating the service"); }); }; diff --git a/apps/dokploy/components/dashboard/settings/notifications/handle-notifications.tsx b/apps/dokploy/components/dashboard/settings/notifications/handle-notifications.tsx index e0476529..cfa0ca83 100644 --- a/apps/dokploy/components/dashboard/settings/notifications/handle-notifications.tsx +++ b/apps/dokploy/components/dashboard/settings/notifications/handle-notifications.tsx @@ -1063,7 +1063,7 @@ export const HandleNotifications = ({ notificationId }: Props) => { }); } toast.success("Connection Success"); - } catch (_err) { + } catch { toast.error("Error testing the provider"); } }} diff --git a/apps/dokploy/components/dashboard/settings/profile/disable-2fa.tsx b/apps/dokploy/components/dashboard/settings/profile/disable-2fa.tsx index 458bf563..11f16435 100644 --- a/apps/dokploy/components/dashboard/settings/profile/disable-2fa.tsx +++ b/apps/dokploy/components/dashboard/settings/profile/disable-2fa.tsx @@ -63,7 +63,7 @@ export const Disable2FA = () => { toast.success("2FA disabled successfully"); utils.user.get.invalidate(); setIsOpen(false); - } catch (_error) { + } catch { form.setError("password", { message: "Connection error. Please try again.", }); diff --git a/apps/dokploy/components/dashboard/settings/servers/actions/toggle-docker-cleanup.tsx b/apps/dokploy/components/dashboard/settings/servers/actions/toggle-docker-cleanup.tsx index 12e27942..604ab6ce 100644 --- a/apps/dokploy/components/dashboard/settings/servers/actions/toggle-docker-cleanup.tsx +++ b/apps/dokploy/components/dashboard/settings/servers/actions/toggle-docker-cleanup.tsx @@ -36,7 +36,7 @@ export const ToggleDockerCleanup = ({ serverId }: Props) => { await refetch(); } toast.success("Docker Cleanup updated"); - } catch (_error) { + } catch { toast.error("Docker Cleanup Error"); } }; diff --git a/apps/dokploy/components/dashboard/settings/servers/gpu-support.tsx b/apps/dokploy/components/dashboard/settings/servers/gpu-support.tsx index c24440a6..fdd57f5b 100644 --- a/apps/dokploy/components/dashboard/settings/servers/gpu-support.tsx +++ b/apps/dokploy/components/dashboard/settings/servers/gpu-support.tsx @@ -56,7 +56,7 @@ export function GPUSupport({ serverId }: GPUSupportProps) { try { await utils.settings.checkGPUStatus.invalidate({ serverId }); await refetch(); - } catch (_error) { + } catch { toast.error("Failed to refresh GPU status"); } finally { setIsRefreshing(false); @@ -74,7 +74,7 @@ export function GPUSupport({ serverId }: GPUSupportProps) { try { await setupGPU.mutateAsync({ serverId }); - } catch (_error) { + } catch { // Error handling is done in mutation's onError } }; diff --git a/apps/dokploy/components/dashboard/settings/users/show-invitations.tsx b/apps/dokploy/components/dashboard/settings/users/show-invitations.tsx index 76d368a3..569b4585 100644 --- a/apps/dokploy/components/dashboard/settings/users/show-invitations.tsx +++ b/apps/dokploy/components/dashboard/settings/users/show-invitations.tsx @@ -146,7 +146,7 @@ export const ShowInvitations = () => { {invitation.status === "pending" && ( { + onSelect={() => { copy( `${origin}/invitation?token=${invitation.id}`, ); @@ -162,7 +162,7 @@ export const ShowInvitations = () => { {invitation.status === "pending" && ( { + onSelect={async () => { const result = await authClient.organization.cancelInvitation( { @@ -189,7 +189,7 @@ export const ShowInvitations = () => { )} { + onSelect={async () => { await removeInvitation({ invitationId: invitation.id, }).then(() => { diff --git a/apps/dokploy/components/dashboard/settings/web-server/manage-traefik-ports.tsx b/apps/dokploy/components/dashboard/settings/web-server/manage-traefik-ports.tsx index dd9839e3..a5cfb630 100644 --- a/apps/dokploy/components/dashboard/settings/web-server/manage-traefik-ports.tsx +++ b/apps/dokploy/components/dashboard/settings/web-server/manage-traefik-ports.tsx @@ -91,7 +91,7 @@ export const ManageTraefikPorts = ({ children, serverId }: Props) => { }); toast.success(t("settings.server.webServer.traefik.portsUpdated")); setOpen(false); - } catch (_error) {} + } catch {} }; return ( diff --git a/apps/dokploy/components/ui/popover.tsx b/apps/dokploy/components/ui/popover.tsx index b4dac1f3..903cd059 100644 --- a/apps/dokploy/components/ui/popover.tsx +++ b/apps/dokploy/components/ui/popover.tsx @@ -17,7 +17,7 @@ const PopoverContent = React.forwardRef< align={align} sideOffset={sideOffset} className={cn( - "z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", + "z-50 w-full rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", className, )} {...props} diff --git a/apps/dokploy/drizzle/0099_wise_golden_guardian.sql b/apps/dokploy/drizzle/0099_wise_golden_guardian.sql new file mode 100644 index 00000000..1dff65a7 --- /dev/null +++ b/apps/dokploy/drizzle/0099_wise_golden_guardian.sql @@ -0,0 +1,2 @@ +CREATE TYPE "public"."publishModeType" AS ENUM('ingress', 'host');--> statement-breakpoint +ALTER TABLE "port" ADD COLUMN "publishMode" "publishModeType" DEFAULT 'host' NOT NULL; \ No newline at end of file diff --git a/apps/dokploy/drizzle/meta/0099_snapshot.json b/apps/dokploy/drizzle/meta/0099_snapshot.json index 07ea32a0..da38d91b 100644 --- a/apps/dokploy/drizzle/meta/0099_snapshot.json +++ b/apps/dokploy/drizzle/meta/0099_snapshot.json @@ -1,5 +1,5 @@ { - "id": "4d928914-5268-4921-aa21-c1b087cc15cc", + "id": "71f68c87-ddb4-4e8c-b9fc-1db7fbcedf56", "prevId": "edde8c54-b715-4db6-bc3a-85d435226083", "version": "7", "dialect": "postgresql", @@ -1209,20 +1209,6 @@ "primaryKey": false, "notNull": true, "default": "'none'" - }, - "internalPath": { - "name": "internalPath", - "type": "text", - "primaryKey": false, - "notNull": false, - "default": "'/'" - }, - "stripPath": { - "name": "stripPath", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false } }, "indexes": {}, @@ -2847,6 +2833,14 @@ "primaryKey": false, "notNull": true }, + "publishMode": { + "name": "publishMode", + "type": "publishModeType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'host'" + }, "targetPort": { "name": "targetPort", "type": "integer", @@ -5730,6 +5724,14 @@ "udp" ] }, + "public.publishModeType": { + "name": "publishModeType", + "schema": "public", + "values": [ + "ingress", + "host" + ] + }, "public.applicationStatus": { "name": "applicationStatus", "schema": "public", diff --git a/apps/dokploy/drizzle/meta/_journal.json b/apps/dokploy/drizzle/meta/_journal.json index 211898fc..f981a42c 100644 --- a/apps/dokploy/drizzle/meta/_journal.json +++ b/apps/dokploy/drizzle/meta/_journal.json @@ -698,8 +698,8 @@ { "idx": 99, "version": "7", - "when": 1751293280505, - "tag": "0099_fast_the_order", + "when": 1751693569786, + "tag": "0099_wise_golden_guardian", "breakpoints": true } ] diff --git a/apps/dokploy/package.json b/apps/dokploy/package.json index 1c54b822..2ec63a78 100644 --- a/apps/dokploy/package.json +++ b/apps/dokploy/package.json @@ -1,6 +1,6 @@ { "name": "dokploy", - "version": "v0.23.6", + "version": "v0.23.7", "private": true, "license": "Apache-2.0", "type": "module", diff --git a/apps/dokploy/pages/dashboard/docker.tsx b/apps/dokploy/pages/dashboard/docker.tsx index e01a763b..56154d10 100644 --- a/apps/dokploy/pages/dashboard/docker.tsx +++ b/apps/dokploy/pages/dashboard/docker.tsx @@ -72,7 +72,7 @@ export async function getServerSideProps( trpcState: helpers.dehydrate(), }, }; - } catch (_error) { + } catch { return { props: {}, }; diff --git a/apps/dokploy/pages/dashboard/project/[projectId].tsx b/apps/dokploy/pages/dashboard/project/[projectId].tsx index 3b2216dd..e189ed5c 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId].tsx @@ -390,7 +390,7 @@ const Project = ( break; } success++; - } catch (_error) { + } catch { toast.error(`Error starting service ${serviceId}`); } } @@ -437,7 +437,7 @@ const Project = ( break; } success++; - } catch (_error) { + } catch { toast.error(`Error stopping service ${serviceId}`); } } @@ -1107,7 +1107,7 @@ export async function getServerSideProps( projectId: params?.projectId, }, }; - } catch (_error) { + } catch { return { redirect: { permanent: false, diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx index f9ab3bcf..c3164e9e 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx @@ -413,7 +413,7 @@ export async function getServerSideProps( activeTab: (activeTab || "general") as TabState, }, }; - } catch (_error) { + } catch { return { redirect: { permanent: false, diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx index 5eebff64..bdef9a85 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx @@ -409,7 +409,7 @@ export async function getServerSideProps( activeTab: (activeTab || "general") as TabState, }, }; - } catch (_error) { + } catch { return { redirect: { permanent: false, diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/mariadb/[mariadbId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/mariadb/[mariadbId].tsx index edfa3a0b..d6745a24 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/mariadb/[mariadbId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/mariadb/[mariadbId].tsx @@ -338,7 +338,7 @@ export async function getServerSideProps( activeTab: (activeTab || "general") as TabState, }, }; - } catch (_error) { + } catch { return { redirect: { permanent: false, diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/mongo/[mongoId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/mongo/[mongoId].tsx index 3d9d53d3..82b60d5e 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/mongo/[mongoId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/mongo/[mongoId].tsx @@ -340,7 +340,7 @@ export async function getServerSideProps( activeTab: (activeTab || "general") as TabState, }, }; - } catch (_error) { + } catch { return { redirect: { permanent: false, diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/mysql/[mysqlId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/mysql/[mysqlId].tsx index 93245f62..11efc652 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/mysql/[mysqlId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/mysql/[mysqlId].tsx @@ -324,7 +324,7 @@ export async function getServerSideProps( activeTab: (activeTab || "general") as TabState, }, }; - } catch (_error) { + } catch { return { redirect: { permanent: false, diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/postgres/[postgresId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/postgres/[postgresId].tsx index cc455224..99e8e478 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/postgres/[postgresId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/postgres/[postgresId].tsx @@ -321,7 +321,7 @@ export async function getServerSideProps( activeTab: (activeTab || "general") as TabState, }, }; - } catch (_error) { + } catch { return { redirect: { permanent: false, diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/redis/[redisId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/redis/[redisId].tsx index 646f8555..cc9a4235 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/redis/[redisId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/redis/[redisId].tsx @@ -328,7 +328,7 @@ export async function getServerSideProps( activeTab: (activeTab || "general") as TabState, }, }; - } catch (_error) { + } catch { return { redirect: { permanent: false, diff --git a/apps/dokploy/pages/dashboard/settings/git-providers.tsx b/apps/dokploy/pages/dashboard/settings/git-providers.tsx index 7a9b08df..fec2a08f 100644 --- a/apps/dokploy/pages/dashboard/settings/git-providers.tsx +++ b/apps/dokploy/pages/dashboard/settings/git-providers.tsx @@ -68,7 +68,7 @@ export async function getServerSideProps( trpcState: helpers.dehydrate(), }, }; - } catch (_error) { + } catch { return { props: {}, }; diff --git a/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx b/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx index 2472feab..6ce2fd57 100644 --- a/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx +++ b/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx @@ -69,7 +69,7 @@ export async function getServerSideProps( trpcState: helpers.dehydrate(), }, }; - } catch (_error) { + } catch { return { props: {}, }; diff --git a/apps/dokploy/pages/dashboard/swarm.tsx b/apps/dokploy/pages/dashboard/swarm.tsx index 15553116..97643614 100644 --- a/apps/dokploy/pages/dashboard/swarm.tsx +++ b/apps/dokploy/pages/dashboard/swarm.tsx @@ -72,7 +72,7 @@ export async function getServerSideProps( trpcState: helpers.dehydrate(), }, }; - } catch (_error) { + } catch { return { props: {}, }; diff --git a/apps/dokploy/pages/dashboard/traefik.tsx b/apps/dokploy/pages/dashboard/traefik.tsx index ce8208be..893b3725 100644 --- a/apps/dokploy/pages/dashboard/traefik.tsx +++ b/apps/dokploy/pages/dashboard/traefik.tsx @@ -72,7 +72,7 @@ export async function getServerSideProps( trpcState: helpers.dehydrate(), }, }; - } catch (_error) { + } catch { return { props: {}, }; diff --git a/apps/dokploy/pages/index.tsx b/apps/dokploy/pages/index.tsx index 200ca8ef..85aaa20c 100644 --- a/apps/dokploy/pages/index.tsx +++ b/apps/dokploy/pages/index.tsx @@ -96,7 +96,7 @@ export default function Home({ IS_CLOUD }: Props) { toast.success("Logged in successfully"); router.push("/dashboard/projects"); - } catch (_error) { + } catch { toast.error("An error occurred while logging in"); } finally { setIsLoginLoading(false); @@ -124,7 +124,7 @@ export default function Home({ IS_CLOUD }: Props) { toast.success("Logged in successfully"); router.push("/dashboard/projects"); - } catch (_error) { + } catch { toast.error("An error occurred while verifying 2FA code"); } finally { setIsTwoFactorLoading(false); @@ -154,7 +154,7 @@ export default function Home({ IS_CLOUD }: Props) { toast.success("Logged in successfully"); router.push("/dashboard/projects"); - } catch (_error) { + } catch { toast.error("An error occurred while verifying backup code"); } finally { setIsBackupCodeLoading(false); @@ -478,7 +478,7 @@ export async function getServerSideProps(context: GetServerSidePropsContext) { }, }; } - } catch (_error) {} + } catch {} return { props: { diff --git a/apps/dokploy/pages/invitation.tsx b/apps/dokploy/pages/invitation.tsx index 32026c0e..c6e598e4 100644 --- a/apps/dokploy/pages/invitation.tsx +++ b/apps/dokploy/pages/invitation.tsx @@ -133,7 +133,7 @@ const Invitation = ({ toast.success("Account created successfully"); router.push("/dashboard/projects"); - } catch (_error) { + } catch { toast.error("An error occurred while creating your account"); } }; diff --git a/apps/dokploy/server/api/routers/docker.ts b/apps/dokploy/server/api/routers/docker.ts index 3de59058..72dbb40a 100644 --- a/apps/dokploy/server/api/routers/docker.ts +++ b/apps/dokploy/server/api/routers/docker.ts @@ -1,5 +1,6 @@ import { containerRestart, + findServerById, getConfig, getContainers, getContainersByAppLabel, @@ -9,6 +10,9 @@ import { } from "@dokploy/server"; import { z } from "zod"; import { createTRPCRouter, protectedProcedure } from "../trpc"; +import { TRPCError } from "@trpc/server"; + +export const containerIdRegex = /^[a-zA-Z0-9.\-_]+$/; export const dockerRouter = createTRPCRouter({ getContainers: protectedProcedure @@ -17,14 +21,23 @@ export const dockerRouter = createTRPCRouter({ serverId: z.string().optional(), }), ) - .query(async ({ input }) => { + .query(async ({ input, ctx }) => { + if (input.serverId) { + const server = await findServerById(input.serverId); + if (server.organizationId !== ctx.session?.activeOrganizationId) { + throw new TRPCError({ code: "UNAUTHORIZED" }); + } + } return await getContainers(input.serverId); }), restartContainer: protectedProcedure .input( z.object({ - containerId: z.string().min(1), + containerId: z + .string() + .min(1) + .regex(containerIdRegex, "Invalid container id."), }), ) .mutation(async ({ input }) => { @@ -34,11 +47,20 @@ export const dockerRouter = createTRPCRouter({ getConfig: protectedProcedure .input( z.object({ - containerId: z.string().min(1), + containerId: z + .string() + .min(1) + .regex(containerIdRegex, "Invalid container id."), serverId: z.string().optional(), }), ) - .query(async ({ input }) => { + .query(async ({ input, ctx }) => { + if (input.serverId) { + const server = await findServerById(input.serverId); + if (server.organizationId !== ctx.session?.activeOrganizationId) { + throw new TRPCError({ code: "UNAUTHORIZED" }); + } + } return await getConfig(input.containerId, input.serverId); }), @@ -48,11 +70,17 @@ export const dockerRouter = createTRPCRouter({ appType: z .union([z.literal("stack"), z.literal("docker-compose")]) .optional(), - appName: z.string().min(1), + appName: z.string().min(1).regex(containerIdRegex, "Invalid app name."), serverId: z.string().optional(), }), ) - .query(async ({ input }) => { + .query(async ({ input, ctx }) => { + if (input.serverId) { + const server = await findServerById(input.serverId); + if (server.organizationId !== ctx.session?.activeOrganizationId) { + throw new TRPCError({ code: "UNAUTHORIZED" }); + } + } return await getContainersByAppNameMatch( input.appName, input.appType, @@ -63,12 +91,18 @@ export const dockerRouter = createTRPCRouter({ getContainersByAppLabel: protectedProcedure .input( z.object({ - appName: z.string().min(1), + appName: z.string().min(1).regex(containerIdRegex, "Invalid app name."), serverId: z.string().optional(), type: z.enum(["standalone", "swarm"]), }), ) - .query(async ({ input }) => { + .query(async ({ input, ctx }) => { + if (input.serverId) { + const server = await findServerById(input.serverId); + if (server.organizationId !== ctx.session?.activeOrganizationId) { + throw new TRPCError({ code: "UNAUTHORIZED" }); + } + } return await getContainersByAppLabel( input.appName, input.type, @@ -79,22 +113,34 @@ export const dockerRouter = createTRPCRouter({ getStackContainersByAppName: protectedProcedure .input( z.object({ - appName: z.string().min(1), + appName: z.string().min(1).regex(containerIdRegex, "Invalid app name."), serverId: z.string().optional(), }), ) - .query(async ({ input }) => { + .query(async ({ input, ctx }) => { + if (input.serverId) { + const server = await findServerById(input.serverId); + if (server.organizationId !== ctx.session?.activeOrganizationId) { + throw new TRPCError({ code: "UNAUTHORIZED" }); + } + } return await getStackContainersByAppName(input.appName, input.serverId); }), getServiceContainersByAppName: protectedProcedure .input( z.object({ - appName: z.string().min(1), + appName: z.string().min(1).regex(containerIdRegex, "Invalid app name."), serverId: z.string().optional(), }), ) - .query(async ({ input }) => { + .query(async ({ input, ctx }) => { + if (input.serverId) { + const server = await findServerById(input.serverId); + if (server.organizationId !== ctx.session?.activeOrganizationId) { + throw new TRPCError({ code: "UNAUTHORIZED" }); + } + } return await getServiceContainersByAppName(input.appName, input.serverId); }), }); diff --git a/apps/dokploy/server/api/routers/settings.ts b/apps/dokploy/server/api/routers/settings.ts index 0d07bbea..9bab0622 100644 --- a/apps/dokploy/server/api/routers/settings.ts +++ b/apps/dokploy/server/api/routers/settings.ts @@ -459,6 +459,15 @@ export const settingsRouter = createTRPCRouter({ throw new TRPCError({ code: "UNAUTHORIZED" }); } } + + if (input.serverId) { + const server = await findServerById(input.serverId); + + if (server.organizationId !== ctx.session?.activeOrganizationId) { + throw new TRPCError({ code: "UNAUTHORIZED" }); + } + } + return readConfigInPath(input.path, input.serverId); }), getIp: protectedProcedure.query(async ({ ctx }) => { diff --git a/apps/dokploy/server/api/routers/swarm.ts b/apps/dokploy/server/api/routers/swarm.ts index c5a2d4c8..735ddf96 100644 --- a/apps/dokploy/server/api/routers/swarm.ts +++ b/apps/dokploy/server/api/routers/swarm.ts @@ -6,6 +6,9 @@ import { } from "@dokploy/server"; import { z } from "zod"; import { createTRPCRouter, protectedProcedure } from "../trpc"; +import { TRPCError } from "@trpc/server"; +import { findServerById } from "@dokploy/server"; +import { containerIdRegex } from "./docker"; export const swarmRouter = createTRPCRouter({ getNodes: protectedProcedure @@ -14,12 +17,24 @@ export const swarmRouter = createTRPCRouter({ serverId: z.string().optional(), }), ) - .query(async ({ input }) => { + .query(async ({ input, ctx }) => { + if (input.serverId) { + const server = await findServerById(input.serverId); + if (server.organizationId !== ctx.session?.activeOrganizationId) { + throw new TRPCError({ code: "UNAUTHORIZED" }); + } + } return await getSwarmNodes(input.serverId); }), getNodeInfo: protectedProcedure .input(z.object({ nodeId: z.string(), serverId: z.string().optional() })) - .query(async ({ input }) => { + .query(async ({ input, ctx }) => { + if (input.serverId) { + const server = await findServerById(input.serverId); + if (server.organizationId !== ctx.session?.activeOrganizationId) { + throw new TRPCError({ code: "UNAUTHORIZED" }); + } + } return await getNodeInfo(input.nodeId, input.serverId); }), getNodeApps: protectedProcedure @@ -28,17 +43,29 @@ export const swarmRouter = createTRPCRouter({ serverId: z.string().optional(), }), ) - .query(async ({ input }) => { + .query(async ({ input, ctx }) => { + if (input.serverId) { + const server = await findServerById(input.serverId); + if (server.organizationId !== ctx.session?.activeOrganizationId) { + throw new TRPCError({ code: "UNAUTHORIZED" }); + } + } return getNodeApplications(input.serverId); }), getAppInfos: protectedProcedure .input( z.object({ - appName: z.string(), + appName: z.string().min(1).regex(containerIdRegex, "Invalid app name."), serverId: z.string().optional(), }), ) - .query(async ({ input }) => { + .query(async ({ input, ctx }) => { + if (input.serverId) { + const server = await findServerById(input.serverId); + if (server.organizationId !== ctx.session?.activeOrganizationId) { + throw new TRPCError({ code: "UNAUTHORIZED" }); + } + } return await getApplicationInfo(input.appName, input.serverId); }), }); diff --git a/apps/dokploy/server/api/routers/user.ts b/apps/dokploy/server/api/routers/user.ts index b2277399..3ac91dc0 100644 --- a/apps/dokploy/server/api/routers/user.ts +++ b/apps/dokploy/server/api/routers/user.ts @@ -75,6 +75,24 @@ export const userRouter = createTRPCRouter({ }, }); + // If user not found in the organization, deny access + if (!memberResult) { + throw new TRPCError({ + code: "NOT_FOUND", + message: "User not found in this organization", + }); + } + + // Allow access if: + // 1. User is requesting their own information + // 2. User has owner role (admin permissions) AND user is in the same organization + if (memberResult.userId !== ctx.user.id && ctx.user.role !== "owner") { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to access this user", + }); + } + return memberResult; }), get: protectedProcedure.query(async ({ ctx }) => { diff --git a/apps/dokploy/server/utils/docker.ts b/apps/dokploy/server/utils/docker.ts index 3314eb62..07e4e26e 100644 --- a/apps/dokploy/server/utils/docker.ts +++ b/apps/dokploy/server/utils/docker.ts @@ -6,7 +6,7 @@ export const isWSL = async () => { const { stdout } = await execAsync("uname -r"); const isWSL = stdout.includes("microsoft"); return isWSL; - } catch (_error) { + } catch { return false; } }; diff --git a/apps/dokploy/server/wss/listen-deployment.ts b/apps/dokploy/server/wss/listen-deployment.ts index 581c04d7..47010a56 100644 --- a/apps/dokploy/server/wss/listen-deployment.ts +++ b/apps/dokploy/server/wss/listen-deployment.ts @@ -101,7 +101,7 @@ export const setupDeploymentLogsWebSocketServer = ( ws.close(); }); } - } catch (_error) { + } catch { // @ts-ignore // const errorMessage = error?.message as unknown as string; // ws.send(errorMessage); diff --git a/apps/dokploy/setup.ts b/apps/dokploy/setup.ts index 5e15db07..f7fe3410 100644 --- a/apps/dokploy/setup.ts +++ b/apps/dokploy/setup.ts @@ -12,6 +12,7 @@ import { initializeNetwork, initializeSwarm, } from "@dokploy/server/setup/setup"; +import { execAsync } from "@dokploy/server"; (async () => { try { setupDirectories(); @@ -20,6 +21,7 @@ import { await initializeNetwork(); createDefaultTraefikConfig(); createDefaultServerTraefikConfig(); + await execAsync("docker pull traefik:v3.1.2"); await initializeTraefik(); await initializeRedis(); await initializePostgres(); diff --git a/apps/dokploy/styles/globals.css b/apps/dokploy/styles/globals.css index 74a1d276..59d10165 100644 --- a/apps/dokploy/styles/globals.css +++ b/apps/dokploy/styles/globals.css @@ -242,3 +242,8 @@ background-color: var(--terminal-paste) !important; color: currentColor !important; } + +.cm-content, +.cm-lineWrapping { + @apply font-mono; +} diff --git a/apps/monitoring/LICENSE.md b/apps/monitoring/LICENSE.md index e69de29b..235ac37e 100644 --- a/apps/monitoring/LICENSE.md +++ b/apps/monitoring/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright 2025 Mauricio Siu. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/packages/server/src/db/schema/port.ts b/packages/server/src/db/schema/port.ts index 47563ae7..30f79cc4 100644 --- a/packages/server/src/db/schema/port.ts +++ b/packages/server/src/db/schema/port.ts @@ -6,6 +6,7 @@ import { z } from "zod"; import { applications } from "./application"; export const protocolType = pgEnum("protocolType", ["tcp", "udp"]); +export const publishModeType = pgEnum("publishModeType", ["ingress", "host"]); export const ports = pgTable("port", { portId: text("portId") @@ -13,6 +14,7 @@ export const ports = pgTable("port", { .primaryKey() .$defaultFn(() => nanoid()), publishedPort: integer("publishedPort").notNull(), + publishMode: publishModeType("publishMode").notNull().default("host"), targetPort: integer("targetPort").notNull(), protocol: protocolType("protocol").notNull(), @@ -32,6 +34,7 @@ const createSchema = createInsertSchema(ports, { portId: z.string().min(1), applicationId: z.string().min(1), publishedPort: z.number(), + publishMode: z.enum(["ingress", "host"]).default("ingress"), targetPort: z.number(), protocol: z.enum(["tcp", "udp"]).default("tcp"), }); @@ -39,6 +42,7 @@ const createSchema = createInsertSchema(ports, { export const apiCreatePort = createSchema .pick({ publishedPort: true, + publishMode: true, targetPort: true, protocol: true, applicationId: true, @@ -55,6 +59,7 @@ export const apiUpdatePort = createSchema .pick({ portId: true, publishedPort: true, + publishMode: true, targetPort: true, protocol: true, }) diff --git a/packages/server/src/db/schema/user.ts b/packages/server/src/db/schema/user.ts index 139daa3c..8f4de12e 100644 --- a/packages/server/src/db/schema/user.ts +++ b/packages/server/src/db/schema/user.ts @@ -15,6 +15,7 @@ import { backups } from "./backups"; import { projects } from "./project"; import { schedules } from "./schedule"; import { certificateType } from "./shared"; +import { paths } from "@dokploy/server/constants"; /** * This is an example of how to use the multi-project schema feature of Drizzle ORM. Use the same * database instance for multiple projects. @@ -236,7 +237,31 @@ export const apiModifyTraefikConfig = z.object({ serverId: z.string().optional(), }); export const apiReadTraefikConfig = z.object({ - path: z.string().min(1), + path: z + .string() + .min(1) + .refine( + (path) => { + // Prevent directory traversal attacks + if (path.includes("../") || path.includes("..\\")) { + return false; + } + + const { MAIN_TRAEFIK_PATH } = paths(); + if (path.startsWith("/") && !path.startsWith(MAIN_TRAEFIK_PATH)) { + return false; + } + // Prevent null bytes and other dangerous characters + if (path.includes("\0") || path.includes("\x00")) { + return false; + } + return true; + }, + { + message: + "Invalid path: path traversal or unauthorized directory access detected", + }, + ), serverId: z.string().optional(), }); diff --git a/packages/server/src/monitoring/utils.ts b/packages/server/src/monitoring/utils.ts index 147ade0a..11ebb616 100644 --- a/packages/server/src/monitoring/utils.ts +++ b/packages/server/src/monitoring/utils.ts @@ -73,7 +73,7 @@ export const readStatsFile = async ( const filePath = `${MONITORING_PATH}/${appName}/${statType}.json`; const data = await promises.readFile(filePath, "utf-8"); return JSON.parse(data); - } catch (_error) { + } catch { return []; } }; @@ -108,7 +108,7 @@ export const readLastValueStatsFile = async ( const data = await promises.readFile(filePath, "utf-8"); const stats = JSON.parse(data); return stats[stats.length - 1] || null; - } catch (_error) { + } catch { return null; } }; diff --git a/packages/server/src/services/docker.ts b/packages/server/src/services/docker.ts index bb70d28f..2e315d00 100644 --- a/packages/server/src/services/docker.ts +++ b/packages/server/src/services/docker.ts @@ -98,7 +98,7 @@ export const getConfig = async ( const config = JSON.parse(stdout); return config; - } catch (_error) {} + } catch {} }; export const getContainersByAppNameMatch = async ( @@ -156,7 +156,7 @@ export const getContainersByAppNameMatch = async ( }); return containers || []; - } catch (_error) {} + } catch {} return []; }; @@ -214,7 +214,7 @@ export const getStackContainersByAppName = async ( }); return containers || []; - } catch (_error) {} + } catch {} return []; }; @@ -274,7 +274,7 @@ export const getServiceContainersByAppName = async ( }); return containers || []; - } catch (_error) {} + } catch {} return []; }; @@ -331,7 +331,7 @@ export const getContainersByAppLabel = async ( }); return containers || []; - } catch (_error) {} + } catch {} return []; }; @@ -350,7 +350,7 @@ export const containerRestart = async (containerId: string) => { const config = JSON.parse(stdout); return config; - } catch (_error) {} + } catch {} }; export const getSwarmNodes = async (serverId?: string) => { @@ -379,7 +379,7 @@ export const getSwarmNodes = async (serverId?: string) => { .split("\n") .map((line) => JSON.parse(line)); return nodesArray; - } catch (_error) {} + } catch {} }; export const getNodeInfo = async (nodeId: string, serverId?: string) => { @@ -405,7 +405,7 @@ export const getNodeInfo = async (nodeId: string, serverId?: string) => { const nodeInfo = JSON.parse(stdout); return nodeInfo; - } catch (_error) {} + } catch {} }; export const getNodeApplications = async (serverId?: string) => { @@ -437,7 +437,7 @@ export const getNodeApplications = async (serverId?: string) => { .filter((service) => !service.Name.startsWith("dokploy-")); return appArray; - } catch (_error) {} + } catch {} }; export const getApplicationInfo = async ( @@ -470,5 +470,5 @@ export const getApplicationInfo = async ( .map((line) => JSON.parse(line)); return appArray; - } catch (_error) {} + } catch {} }; diff --git a/packages/server/src/services/github.ts b/packages/server/src/services/github.ts index 6485d8fb..1520a00a 100644 --- a/packages/server/src/services/github.ts +++ b/packages/server/src/services/github.ts @@ -121,7 +121,7 @@ export const issueCommentExists = async ({ comment_id: comment_id, }); return true; - } catch (_error) { + } catch { return false; } }; diff --git a/packages/server/src/services/mount.ts b/packages/server/src/services/mount.ts index aca0db05..91d67a21 100644 --- a/packages/server/src/services/mount.ts +++ b/packages/server/src/services/mount.ts @@ -212,7 +212,7 @@ export const deleteFileMount = async (mountId: string) => { } else { await removeFileOrDirectory(fullPath); } - } catch (_error) {} + } catch {} }; export const getBaseFilesPath = async (mountId: string) => { diff --git a/packages/server/src/services/preview-deployment.ts b/packages/server/src/services/preview-deployment.ts index b1ce6ca2..1b358946 100644 --- a/packages/server/src/services/preview-deployment.ts +++ b/packages/server/src/services/preview-deployment.ts @@ -104,7 +104,7 @@ export const removePreviewDeployment = async (previewDeploymentId: string) => { for (const operation of cleanupOperations) { try { await operation(); - } catch (_error) {} + } catch {} } return deployment[0]; } catch (error) { diff --git a/packages/server/src/services/rollbacks.ts b/packages/server/src/services/rollbacks.ts index 1c1b5a29..c8e74a16 100644 --- a/packages/server/src/services/rollbacks.ts +++ b/packages/server/src/services/rollbacks.ts @@ -195,7 +195,7 @@ const rollbackApplication = async ( ForceUpdate: inspect.Spec.TaskTemplate.ForceUpdate + 1, }, }); - } catch (_error: unknown) { + } catch { await docker.createService(settings); } }; diff --git a/packages/server/src/setup/monitoring-setup.ts b/packages/server/src/setup/monitoring-setup.ts index 75b9a928..6e56b31c 100644 --- a/packages/server/src/setup/monitoring-setup.ts +++ b/packages/server/src/setup/monitoring-setup.ts @@ -66,7 +66,7 @@ export const setupMonitoring = async (serverId: string) => { await container.inspect(); await container.remove({ force: true }); console.log("Removed existing container"); - } catch (_error) { + } catch { // Container doesn't exist, continue } @@ -135,7 +135,7 @@ export const setupWebMonitoring = async (userId: string) => { await container.inspect(); await container.remove({ force: true }); console.log("Removed existing container"); - } catch (_error) {} + } catch {} await docker.createContainer(settings); const newContainer = docker.getContainer(containerName); diff --git a/packages/server/src/setup/server-setup.ts b/packages/server/src/setup/server-setup.ts index a5c760fb..1a455408 100644 --- a/packages/server/src/setup/server-setup.ts +++ b/packages/server/src/setup/server-setup.ts @@ -419,14 +419,26 @@ if ! [ -x "$(command -v docker)" ]; then systemctl enable docker >/dev/null 2>&1 ;; "opencloudos") - dnf config-manager --add-repo=https://download.docker.com/linux/centos/docker-ce.repo >/dev/null 2>&1 - dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin >/dev/null 2>&1 + # Special handling for OpenCloud OS + echo " - Installing Docker for OpenCloud OS..." + dnf install -y docker >/dev/null 2>&1 if ! [ -x "$(command -v docker)" ]; then echo " - Docker could not be installed automatically. Please visit https://docs.docker.com/engine/install/ and install Docker manually to continue." exit 1 fi - systemctl start docker >/dev/null 2>&1 + + # Remove --live-restore parameter from Docker configuration if it exists + if [ -f "/etc/sysconfig/docker" ]; then + echo " - Removing --live-restore parameter from Docker configuration..." + sed -i 's/--live-restore[^[:space:]]*//' /etc/sysconfig/docker >/dev/null 2>&1 + sed -i 's/--live-restore//' /etc/sysconfig/docker >/dev/null 2>&1 + # Clean up any double spaces that might be left + sed -i 's/ */ /g' /etc/sysconfig/docker >/dev/null 2>&1 + fi + systemctl enable docker >/dev/null 2>&1 + systemctl start docker >/dev/null 2>&1 + echo " - Docker configured for OpenCloud OS" ;; "alpine") apk add docker docker-cli-compose >/dev/null 2>&1 diff --git a/packages/server/src/setup/setup.ts b/packages/server/src/setup/setup.ts index eeef32dd..4c01bf6c 100644 --- a/packages/server/src/setup/setup.ts +++ b/packages/server/src/setup/setup.ts @@ -18,7 +18,7 @@ export const dockerSwarmInitialized = async () => { await docker.swarmInspect(); return true; - } catch (_e) { + } catch { return false; } }; @@ -41,7 +41,7 @@ export const dockerNetworkInitialized = async () => { try { await docker.getNetwork("dokploy-network").inspect(); return true; - } catch (_e) { + } catch { return false; } }; diff --git a/packages/server/src/setup/traefik-setup.ts b/packages/server/src/setup/traefik-setup.ts index 4d26c655..1f8ee666 100644 --- a/packages/server/src/setup/traefik-setup.ts +++ b/packages/server/src/setup/traefik-setup.ts @@ -101,11 +101,11 @@ export const initializeTraefik = async ({ console.log("Waiting for service cleanup..."); await new Promise((resolve) => setTimeout(resolve, 5000)); attempts++; - } catch (_e) { + } catch { break; } } - } catch (_err) { + } catch { console.log("No existing service to remove"); } @@ -120,7 +120,7 @@ export const initializeTraefik = async ({ await container.remove({ force: true }); await new Promise((resolve) => setTimeout(resolve, 5000)); - } catch (_err) { + } catch { console.log("No existing container to remove"); } diff --git a/packages/server/src/utils/builders/index.ts b/packages/server/src/utils/builders/index.ts index 4f8dfa2f..93283f44 100644 --- a/packages/server/src/utils/builders/index.ts +++ b/packages/server/src/utils/builders/index.ts @@ -183,6 +183,7 @@ export const mechanizeDockerContainer = async ( RollbackConfig, EndpointSpec: { Ports: ports.map((port) => ({ + PublishMode: port.publishMode, Protocol: port.protocol, TargetPort: port.targetPort, PublishedPort: port.publishedPort, @@ -203,7 +204,7 @@ export const mechanizeDockerContainer = async ( ForceUpdate: inspect.Spec.TaskTemplate.ForceUpdate + 1, }, }); - } catch (_error: unknown) { + } catch { await docker.createService(settings); } }; diff --git a/packages/server/src/utils/databases/mariadb.ts b/packages/server/src/utils/databases/mariadb.ts index 5f9befe6..be18425a 100644 --- a/packages/server/src/utils/databases/mariadb.ts +++ b/packages/server/src/utils/databases/mariadb.ts @@ -98,7 +98,7 @@ export const buildMariadb = async (mariadb: MariadbNested) => { version: Number.parseInt(inspect.Version.Index), ...settings, }); - } catch (_error) { + } catch { await docker.createService(settings); } }; diff --git a/packages/server/src/utils/databases/mongo.ts b/packages/server/src/utils/databases/mongo.ts index 58f8624a..5330c018 100644 --- a/packages/server/src/utils/databases/mongo.ts +++ b/packages/server/src/utils/databases/mongo.ts @@ -152,7 +152,7 @@ ${command ?? "wait $MONGOD_PID"}`; version: Number.parseInt(inspect.Version.Index), ...settings, }); - } catch (_error) { + } catch { await docker.createService(settings); } }; diff --git a/packages/server/src/utils/databases/mysql.ts b/packages/server/src/utils/databases/mysql.ts index 76f01e5e..fe6a8160 100644 --- a/packages/server/src/utils/databases/mysql.ts +++ b/packages/server/src/utils/databases/mysql.ts @@ -104,7 +104,7 @@ export const buildMysql = async (mysql: MysqlNested) => { version: Number.parseInt(inspect.Version.Index), ...settings, }); - } catch (_error) { + } catch { await docker.createService(settings); } }; diff --git a/packages/server/src/utils/databases/redis.ts b/packages/server/src/utils/databases/redis.ts index 3a8ad086..b2f2ce3c 100644 --- a/packages/server/src/utils/databases/redis.ts +++ b/packages/server/src/utils/databases/redis.ts @@ -95,7 +95,7 @@ export const buildRedis = async (redis: RedisNested) => { version: Number.parseInt(inspect.Version.Index), ...settings, }); - } catch (_error) { + } catch { await docker.createService(settings); } }; diff --git a/packages/server/src/utils/docker/domain.ts b/packages/server/src/utils/docker/domain.ts index 7ed4b438..614ce73b 100644 --- a/packages/server/src/utils/docker/domain.ts +++ b/packages/server/src/utils/docker/domain.ts @@ -117,7 +117,7 @@ export const loadDockerComposeRemote = async ( if (!stdout) return null; const parsedConfig = load(stdout) as ComposeSpecification; return parsedConfig; - } catch (_err) { + } catch { return null; } }; diff --git a/packages/server/src/utils/docker/utils.ts b/packages/server/src/utils/docker/utils.ts index 13626fa3..a9e2f49a 100644 --- a/packages/server/src/utils/docker/utils.ts +++ b/packages/server/src/utils/docker/utils.ts @@ -101,7 +101,7 @@ export const containerExists = async (containerName: string) => { try { await container.inspect(); return true; - } catch (_error) { + } catch { return false; } }; diff --git a/packages/server/src/utils/gpu-setup.ts b/packages/server/src/utils/gpu-setup.ts index a815a00c..ac3cda11 100644 --- a/packages/server/src/utils/gpu-setup.ts +++ b/packages/server/src/utils/gpu-setup.ts @@ -34,7 +34,7 @@ export async function checkGPUStatus(serverId?: string): Promise { ...gpuInfo, ...cudaInfo, }; - } catch (_error) { + } catch { return { driverInstalled: false, driverVersion: undefined, @@ -315,7 +315,7 @@ const setupLocalServer = async (daemonConfig: any) => { try { await execAsync(setupCommands); - } catch (_error) { + } catch { throw new Error( "Failed to configure GPU support. Please ensure you have sudo privileges and try again.", ); diff --git a/packages/server/src/utils/traefik/application.ts b/packages/server/src/utils/traefik/application.ts index 6220d774..773f2bf6 100644 --- a/packages/server/src/utils/traefik/application.ts +++ b/packages/server/src/utils/traefik/application.ts @@ -67,7 +67,7 @@ export const removeTraefikConfig = async ( if (fs.existsSync(configPath)) { await fs.promises.unlink(configPath); } - } catch (_error) {} + } catch {} }; export const removeTraefikConfigRemote = async ( @@ -78,7 +78,7 @@ export const removeTraefikConfigRemote = async ( const { DYNAMIC_TRAEFIK_PATH } = paths(true); const configPath = path.join(DYNAMIC_TRAEFIK_PATH, `${appName}.yml`); await execAsyncRemote(serverId, `rm ${configPath}`); - } catch (_error) {} + } catch {} }; export const loadOrCreateConfig = (appName: string): FileConfig => { @@ -110,7 +110,7 @@ export const loadOrCreateConfigRemote = async ( http: { routers: {}, services: {} }, }; return parsedConfig; - } catch (_err) { + } catch { return fileConfig; } }; @@ -132,7 +132,7 @@ export const readRemoteConfig = async (serverId: string, appName: string) => { const { stdout } = await execAsyncRemote(serverId, `cat ${configPath}`); if (!stdout) return null; return stdout; - } catch (_err) { + } catch { return null; } };