Skip to content

Commit 96fbfa7

Browse files
authored
Merge pull request #847 from Dokploy/feat/improve-server-setup
Feat/improve server setup
2 parents 13e9a50 + 6874ede commit 96fbfa7

File tree

6 files changed

+340
-5
lines changed

6 files changed

+340
-5
lines changed

apps/dokploy/components/dashboard/settings/servers/setup-server.tsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import { useState } from "react";
3333
import { toast } from "sonner";
3434
import { ShowDeployment } from "../../application/deployments/show-deployment";
3535
import { GPUSupport } from "./gpu-support";
36+
import { ValidateServer } from "./validate-server";
3637

3738
interface Props {
3839
serverId: string;
@@ -90,9 +91,10 @@ export const SetupServer = ({ serverId }: Props) => {
9091
) : (
9192
<div id="hook-form-add-gitlab" className="grid w-full gap-1">
9293
<Tabs defaultValue="ssh-keys">
93-
<TabsList className="grid grid-cols-3 w-[400px]">
94+
<TabsList className="grid grid-cols-4 w-[600px]">
9495
<TabsTrigger value="ssh-keys">SSH Keys</TabsTrigger>
9596
<TabsTrigger value="deployments">Deployments</TabsTrigger>
97+
<TabsTrigger value="validate">Validate</TabsTrigger>
9698
<TabsTrigger value="gpu-setup">GPU Setup</TabsTrigger>
9799
</TabsList>
98100
<TabsContent
@@ -203,7 +205,7 @@ export const SetupServer = ({ serverId }: Props) => {
203205
<div className="flex flex-col gap-4">
204206
<Card className="bg-background">
205207
<CardHeader className="flex flex-row items-center justify-between flex-wrap gap-2">
206-
<div className="flex flex-row gap-2 justify-between w-full items-end max-sm:flex-col">
208+
<div className="flex flex-row gap-2 justify-between w-full max-sm:flex-col">
207209
<div className="flex flex-col gap-1">
208210
<CardTitle className="text-xl">
209211
Deployments
@@ -293,6 +295,14 @@ export const SetupServer = ({ serverId }: Props) => {
293295
</div>
294296
</CardContent>
295297
</TabsContent>
298+
<TabsContent
299+
value="validate"
300+
className="outline-none ring-0 focus-visible:ring-0 focus-visible:ring-offset-0"
301+
>
302+
<div className="flex flex-col gap-2 text-sm text-muted-foreground pt-3">
303+
<ValidateServer serverId={serverId} />
304+
</div>
305+
</TabsContent>
296306
<TabsContent
297307
value="gpu-setup"
298308
className="outline-none ring-0 focus-visible:ring-0 focus-visible:ring-offset-0"
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
import { AlertBlock } from "@/components/shared/alert-block";
2+
import {
3+
Card,
4+
CardContent,
5+
CardDescription,
6+
CardHeader,
7+
CardTitle,
8+
} from "@/components/ui/card";
9+
import { api } from "@/utils/api";
10+
import { Loader2, PcCase, RefreshCw } from "lucide-react";
11+
import { StatusRow } from "./gpu-support";
12+
import { Button } from "@/components/ui/button";
13+
import { useState } from "react";
14+
15+
interface Props {
16+
serverId: string;
17+
}
18+
19+
export const ValidateServer = ({ serverId }: Props) => {
20+
const [isRefreshing, setIsRefreshing] = useState(false);
21+
const { data, refetch, error, isLoading, isError } =
22+
api.server.validate.useQuery(
23+
{ serverId },
24+
{
25+
enabled: !!serverId,
26+
},
27+
);
28+
const utils = api.useUtils();
29+
return (
30+
<CardContent className="p-0">
31+
<div className="flex flex-col gap-4">
32+
<Card className="bg-background">
33+
<CardHeader className="flex flex-row items-center justify-between flex-wrap gap-2">
34+
<div className="flex flex-row gap-2 justify-between w-full max-sm:flex-col">
35+
<div className="flex flex-col gap-1">
36+
<div className="flex items-center gap-2">
37+
<PcCase className="size-5" />
38+
<CardTitle className="text-xl">Setup Validation</CardTitle>
39+
</div>
40+
<CardDescription>
41+
Check if your server is ready for deployment
42+
</CardDescription>
43+
</div>
44+
<Button
45+
isLoading={isRefreshing}
46+
onClick={async () => {
47+
setIsRefreshing(true);
48+
await refetch();
49+
setIsRefreshing(false);
50+
}}
51+
>
52+
<RefreshCw className="size-4" />
53+
Refresh
54+
</Button>
55+
</div>
56+
<div className="flex items-center gap-2 w-full">
57+
{isError && (
58+
<AlertBlock type="error" className="w-full">
59+
{error.message}
60+
</AlertBlock>
61+
)}
62+
</div>
63+
</CardHeader>
64+
65+
<CardContent className="flex flex-col gap-4">
66+
{isLoading ? (
67+
<div className="flex items-center justify-center text-muted-foreground py-4">
68+
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
69+
<span>Checking Server Configuration</span>
70+
</div>
71+
) : (
72+
<div className="grid w-full gap-4">
73+
<div className="border rounded-lg p-4">
74+
<h3 className="text-lg font-semibold mb-1">Status</h3>
75+
<p className="text-sm text-muted-foreground mb-4">
76+
Shows the server configuration status
77+
</p>
78+
<div className="grid gap-2.5">
79+
<StatusRow
80+
label="Docker Installed"
81+
isEnabled={data?.docker?.enabled}
82+
description={
83+
data?.docker?.enabled
84+
? `Installed: ${data?.docker?.version}`
85+
: undefined
86+
}
87+
/>
88+
<StatusRow
89+
label="RClone Installed"
90+
isEnabled={data?.rclone?.enabled}
91+
description={
92+
data?.rclone?.enabled
93+
? `Installed: ${data?.rclone?.version}`
94+
: undefined
95+
}
96+
/>
97+
<StatusRow
98+
label="Nixpacks Installed"
99+
isEnabled={data?.nixpacks?.enabled}
100+
description={
101+
data?.nixpacks?.enabled
102+
? `Installed: ${data?.nixpacks?.version}`
103+
: undefined
104+
}
105+
/>
106+
<StatusRow
107+
label="Buildpacks Installed"
108+
isEnabled={data?.buildpacks?.enabled}
109+
description={
110+
data?.buildpacks?.enabled
111+
? `Installed: ${data?.buildpacks?.version}`
112+
: undefined
113+
}
114+
/>
115+
<StatusRow
116+
label="Dokploy Network Installed"
117+
isEnabled={data?.isDokployNetworkInstalled}
118+
/>
119+
<StatusRow
120+
label="Swarm Installed"
121+
isEnabled={data?.isSwarmInstalled}
122+
/>
123+
<StatusRow
124+
label="Main Directory Created"
125+
isEnabled={data?.isMainDirectoryInstalled}
126+
/>
127+
</div>
128+
</div>
129+
</div>
130+
)}
131+
</CardContent>
132+
</Card>
133+
</div>
134+
</CardContent>
135+
);
136+
};

apps/dokploy/server/api/routers/server.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import {
2626
haveActiveServices,
2727
removeDeploymentsByServerId,
2828
serverSetup,
29+
serverValidate,
2930
updateServerById,
3031
} from "@dokploy/server";
3132
import { TRPCError } from "@trpc/server";
@@ -118,6 +119,47 @@ export const serverRouter = createTRPCRouter({
118119
throw error;
119120
}
120121
}),
122+
validate: protectedProcedure
123+
.input(apiFindOneServer)
124+
.query(async ({ input, ctx }) => {
125+
try {
126+
const server = await findServerById(input.serverId);
127+
if (server.adminId !== ctx.user.adminId) {
128+
throw new TRPCError({
129+
code: "UNAUTHORIZED",
130+
message: "You are not authorized to validate this server",
131+
});
132+
}
133+
const response = await serverValidate(input.serverId);
134+
return response as unknown as {
135+
docker: {
136+
enabled: boolean;
137+
version: string;
138+
};
139+
rclone: {
140+
enabled: boolean;
141+
version: string;
142+
};
143+
nixpacks: {
144+
enabled: boolean;
145+
version: string;
146+
};
147+
buildpacks: {
148+
enabled: boolean;
149+
version: string;
150+
};
151+
isDokployNetworkInstalled: boolean;
152+
isSwarmInstalled: boolean;
153+
isMainDirectoryInstalled: boolean;
154+
};
155+
} catch (error) {
156+
throw new TRPCError({
157+
code: "BAD_REQUEST",
158+
message: error instanceof Error ? error?.message : `Error: ${error}`,
159+
cause: error as Error,
160+
});
161+
}
162+
}),
121163
remove: protectedProcedure
122164
.input(apiRemoveServer)
123165
.mutation(async ({ input, ctx }) => {

packages/server/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export * from "./setup/redis-setup";
4141
export * from "./setup/server-setup";
4242
export * from "./setup/setup";
4343
export * from "./setup/traefik-setup";
44+
export * from "./setup/server-validate";
4445

4546
export * from "./utils/backups/index";
4647
export * from "./utils/backups/mariadb";

packages/server/src/setup/server-setup.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,14 +132,16 @@ const installRequirements = async (serverId: string, logPath: string) => {
132132
echo -e "---------------------------------------------\n"
133133
echo -e "1. Installing required packages (curl, wget, git, jq, openssl). "
134134
135+
command_exists() {
136+
command -v "$@" > /dev/null 2>&1
137+
}
138+
135139
${installUtilities()}
136140
137141
echo -e "2. Validating ports. "
138142
${validatePorts()}
139143
140-
command_exists() {
141-
command -v "$@" > /dev/null 2>&1
142-
}
144+
143145
144146
echo -e "3. Installing RClone. "
145147
${installRClone()}

0 commit comments

Comments
 (0)