mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
BIN
.github/sponsors/openalternative.png
vendored
Normal file
BIN
.github/sponsors/openalternative.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.1 KiB |
@@ -93,6 +93,7 @@ For detailed documentation, visit [docs.dokploy.com](https://docs.dokploy.com).
|
||||
<a href="https://cloudblast.io/?ref=dokploy "><img src="https://cloudblast.io/img/logo-icon.193cf13e.svg" width="250px" alt="Cloudblast.io"/></a>
|
||||
<a href="https://startupfa.me/?ref=dokploy "><img src=".github/sponsors/startupfame.png" width="65px" alt="Startupfame"/></a>
|
||||
<a href="https://itsdb-center.com?ref=dokploy "><img src=".github/sponsors/its.png" width="65px" alt="Itsdb-center"/></a>
|
||||
<a href="https://openalternative.co/?ref=dokploy "><img src=".github/sponsors/openalternative.png" width="65px" alt="Openalternative"/></a>
|
||||
</div>
|
||||
|
||||
### Community Backers 🤝
|
||||
|
||||
@@ -14,7 +14,7 @@ import { useForm } from "react-hook-form";
|
||||
import { toast } from "sonner";
|
||||
import { z } from "zod";
|
||||
import { validateAndFormatYAML } from "../../application/advanced/traefik/update-traefik-config";
|
||||
import { RandomizeCompose } from "./randomize-compose";
|
||||
import { ShowUtilities } from "./show-utilities";
|
||||
|
||||
interface Props {
|
||||
composeId: string;
|
||||
@@ -125,7 +125,7 @@ services:
|
||||
</Form>
|
||||
<div className="flex justify-between flex-col lg:flex-row gap-2">
|
||||
<div className="w-full flex flex-col lg:flex-row gap-4 items-end">
|
||||
<RandomizeCompose composeId={composeId} />
|
||||
<ShowUtilities composeId={composeId} />
|
||||
</div>
|
||||
<Button
|
||||
type="submit"
|
||||
|
||||
@@ -0,0 +1,191 @@
|
||||
import { AlertBlock } from "@/components/shared/alert-block";
|
||||
import { CodeEditor } from "@/components/shared/code-editor";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "@/components/ui/dialog";
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormDescription,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
} from "@/components/ui/form";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { api } from "@/utils/api";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { AlertTriangle } from "lucide-react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { toast } from "sonner";
|
||||
import { z } from "zod";
|
||||
|
||||
interface Props {
|
||||
composeId: string;
|
||||
}
|
||||
|
||||
const schema = z.object({
|
||||
isolatedDeployment: z.boolean().optional(),
|
||||
});
|
||||
|
||||
type Schema = z.infer<typeof schema>;
|
||||
|
||||
export const IsolatedDeployment = ({ composeId }: Props) => {
|
||||
const utils = api.useUtils();
|
||||
const [compose, setCompose] = useState<string>("");
|
||||
const { mutateAsync, error, isError } =
|
||||
api.compose.isolatedDeployment.useMutation();
|
||||
|
||||
const { mutateAsync: updateCompose } = api.compose.update.useMutation();
|
||||
|
||||
const { data, refetch } = api.compose.one.useQuery(
|
||||
{ composeId },
|
||||
{ enabled: !!composeId },
|
||||
);
|
||||
|
||||
console.log(data);
|
||||
|
||||
const form = useForm<Schema>({
|
||||
defaultValues: {
|
||||
isolatedDeployment: false,
|
||||
},
|
||||
resolver: zodResolver(schema),
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
randomizeCompose();
|
||||
if (data) {
|
||||
form.reset({
|
||||
isolatedDeployment: data?.isolatedDeployment || false,
|
||||
});
|
||||
}
|
||||
}, [form, form.reset, form.formState.isSubmitSuccessful, data]);
|
||||
|
||||
const onSubmit = async (formData: Schema) => {
|
||||
await updateCompose({
|
||||
composeId,
|
||||
isolatedDeployment: formData?.isolatedDeployment || false,
|
||||
})
|
||||
.then(async (data) => {
|
||||
randomizeCompose();
|
||||
refetch();
|
||||
toast.success("Compose updated");
|
||||
})
|
||||
.catch(() => {
|
||||
toast.error("Error updating the compose");
|
||||
});
|
||||
};
|
||||
|
||||
const randomizeCompose = async () => {
|
||||
await mutateAsync({
|
||||
composeId,
|
||||
suffix: data?.appName || "",
|
||||
})
|
||||
.then(async (data) => {
|
||||
await utils.project.all.invalidate();
|
||||
setCompose(data);
|
||||
toast.success("Compose Isolated");
|
||||
})
|
||||
.catch(() => {
|
||||
toast.error("Error isolating the compose");
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Isolate Deployment</DialogTitle>
|
||||
<DialogDescription>
|
||||
Use this option to isolate the deployment of this compose file.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="text-sm text-muted-foreground flex flex-col gap-2">
|
||||
<span>
|
||||
This feature creates an isolated environment for your deployment by
|
||||
adding unique prefixes to all resources. It establishes a dedicated
|
||||
network based on your compose file's name, ensuring your services run
|
||||
in isolation. This prevents conflicts when running multiple instances
|
||||
of the same template or services with identical names.
|
||||
</span>
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<h4 className="font-medium mb-2">
|
||||
Resources that will be isolated:
|
||||
</h4>
|
||||
<ul className="list-disc list-inside">
|
||||
<li>Docker volumes</li>
|
||||
<li>Docker networks</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{isError && <AlertBlock type="error">{error?.message}</AlertBlock>}
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(onSubmit)}
|
||||
id="hook-form-add-project"
|
||||
className="grid w-full gap-4"
|
||||
>
|
||||
{isError && (
|
||||
<div className="flex flex-row gap-4 rounded-lg items-center bg-red-50 p-2 dark:bg-red-950">
|
||||
<AlertTriangle className="text-red-600 dark:text-red-400" />
|
||||
<span className="text-sm text-red-600 dark:text-red-400">
|
||||
{error?.message}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="flex flex-col lg:flex-col gap-4 w-full ">
|
||||
<div>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="isolatedDeployment"
|
||||
render={({ field }) => (
|
||||
<FormItem className="mt-4 flex flex-row items-center justify-between rounded-lg border p-3 shadow-sm">
|
||||
<div className="space-y-0.5">
|
||||
<FormLabel>Enable Randomize ({data?.appName})</FormLabel>
|
||||
<FormDescription>
|
||||
Enable randomize to the compose file.
|
||||
</FormDescription>
|
||||
</div>
|
||||
<FormControl>
|
||||
<Switch
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col lg:flex-row gap-4 w-full items-end justify-end">
|
||||
<Button
|
||||
form="hook-form-add-project"
|
||||
type="submit"
|
||||
className="lg:w-fit"
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-4">
|
||||
<Label>Preview</Label>
|
||||
<pre>
|
||||
<CodeEditor
|
||||
value={compose || ""}
|
||||
language="yaml"
|
||||
readOnly
|
||||
height="50rem"
|
||||
/>
|
||||
</pre>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -1,14 +1,10 @@
|
||||
import { AlertBlock } from "@/components/shared/alert-block";
|
||||
import { CodeEditor } from "@/components/shared/code-editor";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { CardTitle } from "@/components/ui/card";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
import {
|
||||
Form,
|
||||
@@ -20,11 +16,6 @@ import {
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import {
|
||||
InputOTP,
|
||||
InputOTPGroup,
|
||||
InputOTPSlot,
|
||||
} from "@/components/ui/input-otp";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { api } from "@/utils/api";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
@@ -70,6 +61,7 @@ export const RandomizeCompose = ({ composeId }: Props) => {
|
||||
const suffix = form.watch("suffix");
|
||||
|
||||
useEffect(() => {
|
||||
randomizeCompose();
|
||||
if (data) {
|
||||
form.reset({
|
||||
suffix: data?.suffix || "",
|
||||
@@ -110,126 +102,117 @@ export const RandomizeCompose = ({ composeId }: Props) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
||||
<DialogTrigger asChild onClick={() => randomizeCompose()}>
|
||||
<Button className="max-lg:w-full" variant="outline">
|
||||
<Dices className="h-4 w-4" />
|
||||
Randomize Compose
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="sm:max-w-6xl max-h-[50rem] overflow-y-auto">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Randomize Compose (Experimental)</DialogTitle>
|
||||
<DialogDescription>
|
||||
Use this in case you want to deploy the same compose file and you
|
||||
have conflicts with some property like volumes, networks, etc.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="text-sm text-muted-foreground flex flex-col gap-2">
|
||||
<span>
|
||||
This will randomize the compose file and will add a suffix to the
|
||||
property to avoid conflicts
|
||||
</span>
|
||||
<ul className="list-disc list-inside">
|
||||
<li>volumes</li>
|
||||
<li>networks</li>
|
||||
<li>services</li>
|
||||
<li>configs</li>
|
||||
<li>secrets</li>
|
||||
</ul>
|
||||
<AlertBlock type="info">
|
||||
When you activate this option, we will include a env
|
||||
`COMPOSE_PREFIX` variable to the compose file so you can use it in
|
||||
your compose file.
|
||||
</AlertBlock>
|
||||
</div>
|
||||
{isError && <AlertBlock type="error">{error?.message}</AlertBlock>}
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(onSubmit)}
|
||||
id="hook-form-add-project"
|
||||
className="grid w-full gap-4"
|
||||
>
|
||||
{isError && (
|
||||
<div className="flex flex-row gap-4 rounded-lg items-center bg-red-50 p-2 dark:bg-red-950">
|
||||
<AlertTriangle className="text-red-600 dark:text-red-400" />
|
||||
<span className="text-sm text-red-600 dark:text-red-400">
|
||||
{error?.message}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="flex flex-col lg:flex-col gap-4 w-full ">
|
||||
<div>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="suffix"
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex flex-col justify-center max-sm:items-center w-full">
|
||||
<FormLabel>Suffix</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder="Enter a suffix (Optional, example: prod)"
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="randomize"
|
||||
render={({ field }) => (
|
||||
<FormItem className="mt-4 flex flex-row items-center justify-between rounded-lg border p-3 shadow-sm">
|
||||
<div className="space-y-0.5">
|
||||
<FormLabel>Apply Randomize</FormLabel>
|
||||
<FormDescription>
|
||||
Apply randomize to the compose file.
|
||||
</FormDescription>
|
||||
</div>
|
||||
<FormControl>
|
||||
<Switch
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col lg:flex-row gap-4 w-full items-end justify-end">
|
||||
<Button
|
||||
form="hook-form-add-project"
|
||||
type="submit"
|
||||
className="lg:w-fit"
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
variant="secondary"
|
||||
onClick={async () => {
|
||||
await randomizeCompose();
|
||||
}}
|
||||
className="lg:w-fit"
|
||||
>
|
||||
Random
|
||||
</Button>
|
||||
</div>
|
||||
<div className="w-full">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Randomize Compose (Experimental)</DialogTitle>
|
||||
<DialogDescription>
|
||||
Use this in case you want to deploy the same compose file and you have
|
||||
conflicts with some property like volumes, networks, etc.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="text-sm text-muted-foreground flex flex-col gap-2">
|
||||
<span>
|
||||
This will randomize the compose file and will add a suffix to the
|
||||
property to avoid conflicts
|
||||
</span>
|
||||
<ul className="list-disc list-inside">
|
||||
<li>volumes</li>
|
||||
<li>networks</li>
|
||||
<li>services</li>
|
||||
<li>configs</li>
|
||||
<li>secrets</li>
|
||||
</ul>
|
||||
<AlertBlock type="info">
|
||||
When you activate this option, we will include a env `COMPOSE_PREFIX`
|
||||
variable to the compose file so you can use it in your compose file.
|
||||
</AlertBlock>
|
||||
</div>
|
||||
{isError && <AlertBlock type="error">{error?.message}</AlertBlock>}
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(onSubmit)}
|
||||
id="hook-form-add-project"
|
||||
className="grid w-full gap-4"
|
||||
>
|
||||
{isError && (
|
||||
<div className="flex flex-row gap-4 rounded-lg items-center bg-red-50 p-2 dark:bg-red-950">
|
||||
<AlertTriangle className="text-red-600 dark:text-red-400" />
|
||||
<span className="text-sm text-red-600 dark:text-red-400">
|
||||
{error?.message}
|
||||
</span>
|
||||
</div>
|
||||
<pre>
|
||||
<CodeEditor
|
||||
value={compose || ""}
|
||||
language="yaml"
|
||||
readOnly
|
||||
height="50rem"
|
||||
)}
|
||||
|
||||
<div className="flex flex-col lg:flex-col gap-4 w-full ">
|
||||
<div>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="suffix"
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex flex-col justify-center max-sm:items-center w-full mt-4">
|
||||
<FormLabel>Suffix</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder="Enter a suffix (Optional, example: prod)"
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</pre>
|
||||
</form>
|
||||
</Form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="randomize"
|
||||
render={({ field }) => (
|
||||
<FormItem className="mt-4 flex flex-row items-center justify-between rounded-lg border p-3 shadow-sm">
|
||||
<div className="space-y-0.5">
|
||||
<FormLabel>Apply Randomize</FormLabel>
|
||||
<FormDescription>
|
||||
Apply randomize to the compose file.
|
||||
</FormDescription>
|
||||
</div>
|
||||
<FormControl>
|
||||
<Switch
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col lg:flex-row gap-4 w-full items-end justify-end">
|
||||
<Button
|
||||
form="hook-form-add-project"
|
||||
type="submit"
|
||||
className="lg:w-fit"
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
variant="secondary"
|
||||
onClick={async () => {
|
||||
await randomizeCompose();
|
||||
}}
|
||||
className="lg:w-fit"
|
||||
>
|
||||
Random
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<pre>
|
||||
<CodeEditor
|
||||
value={compose || ""}
|
||||
language="yaml"
|
||||
readOnly
|
||||
height="50rem"
|
||||
/>
|
||||
</pre>
|
||||
</form>
|
||||
</Form>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
import { useState } from "react";
|
||||
import { IsolatedDeployment } from "./isolated-deployment";
|
||||
import { RandomizeCompose } from "./randomize-compose";
|
||||
|
||||
interface Props {
|
||||
composeId: string;
|
||||
}
|
||||
|
||||
export const ShowUtilities = ({ composeId }: Props) => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
return (
|
||||
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="ghost">Show Utilities</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="max-h-screen overflow-y-auto sm:max-w-5xl">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Utilities </DialogTitle>
|
||||
<DialogDescription>Modify the application data</DialogDescription>
|
||||
</DialogHeader>
|
||||
<Tabs defaultValue="isolated">
|
||||
<TabsList className="grid w-full grid-cols-2">
|
||||
<TabsTrigger value="isolated">Isolated Deployment</TabsTrigger>
|
||||
<TabsTrigger value="randomize">Randomize Compose</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value="randomize" className="pt-5">
|
||||
<RandomizeCompose composeId={composeId} />
|
||||
</TabsContent>
|
||||
<TabsContent value="isolated" className="pt-5">
|
||||
<IsolatedDeployment composeId={composeId} />
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
@@ -1,5 +1,6 @@
|
||||
import { BreadcrumbSidebar } from "@/components/shared/breadcrumb-sidebar";
|
||||
import { DateTooltip } from "@/components/shared/date-tooltip";
|
||||
import { StatusTooltip } from "@/components/shared/status-tooltip";
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogAction,
|
||||
@@ -176,8 +177,11 @@ export const ShowProjects = () => {
|
||||
<div key={app.applicationId}>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel className="font-normal capitalize text-xs">
|
||||
<DropdownMenuLabel className="font-normal capitalize text-xs flex items-center justify-between">
|
||||
{app.name}
|
||||
<StatusTooltip
|
||||
status={app.applicationStatus}
|
||||
/>
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
{app.domains.map((domain) => (
|
||||
@@ -209,8 +213,11 @@ export const ShowProjects = () => {
|
||||
<div key={comp.composeId}>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel className="font-normal capitalize text-xs">
|
||||
<DropdownMenuLabel className="font-normal capitalize text-xs flex items-center justify-between">
|
||||
{comp.name}
|
||||
<StatusTooltip
|
||||
status={comp.composeStatus}
|
||||
/>
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
{comp.domains.map((domain) => (
|
||||
|
||||
1
apps/dokploy/drizzle/0064_previous_agent_brand.sql
Normal file
1
apps/dokploy/drizzle/0064_previous_agent_brand.sql
Normal file
@@ -0,0 +1 @@
|
||||
ALTER TABLE "compose" ADD COLUMN "deployable" boolean DEFAULT false NOT NULL;
|
||||
1
apps/dokploy/drizzle/0065_daily_zaladane.sql
Normal file
1
apps/dokploy/drizzle/0065_daily_zaladane.sql
Normal file
@@ -0,0 +1 @@
|
||||
ALTER TABLE "compose" RENAME COLUMN "deployable" TO "isolatedDeployment";
|
||||
4485
apps/dokploy/drizzle/meta/0064_snapshot.json
Normal file
4485
apps/dokploy/drizzle/meta/0064_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
4485
apps/dokploy/drizzle/meta/0065_snapshot.json
Normal file
4485
apps/dokploy/drizzle/meta/0065_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -449,6 +449,20 @@
|
||||
"when": 1738522845992,
|
||||
"tag": "0063_panoramic_dreadnoughts",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 64,
|
||||
"version": "7",
|
||||
"when": 1738564387043,
|
||||
"tag": "0064_previous_agent_brand",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 65,
|
||||
"version": "7",
|
||||
"when": 1739087857244,
|
||||
"tag": "0065_daily_zaladane",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "dokploy",
|
||||
"version": "v0.18.2",
|
||||
"version": "v0.18.3",
|
||||
"private": true,
|
||||
"license": "Apache-2.0",
|
||||
"type": "module",
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
import { ProjectLayout } from "@/components/layouts/project-layout";
|
||||
import { BreadcrumbSidebar } from "@/components/shared/breadcrumb-sidebar";
|
||||
import { DateTooltip } from "@/components/shared/date-tooltip";
|
||||
import { DialogAction } from "@/components/shared/dialog-action";
|
||||
import { StatusTooltip } from "@/components/shared/status-tooltip";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
@@ -23,6 +24,7 @@ import {
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/components/ui/card";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import {
|
||||
Command,
|
||||
CommandEmpty,
|
||||
@@ -50,22 +52,27 @@ import type { findProjectById } from "@dokploy/server";
|
||||
import { validateRequest } from "@dokploy/server";
|
||||
import { createServerSideHelpers } from "@trpc/react-query/server";
|
||||
import {
|
||||
Ban,
|
||||
Check,
|
||||
CheckCircle2,
|
||||
ChevronsUpDown,
|
||||
CircuitBoard,
|
||||
FolderInput,
|
||||
GlobeIcon,
|
||||
Loader2,
|
||||
PlusIcon,
|
||||
Search,
|
||||
X,
|
||||
} from "lucide-react";
|
||||
import { Check, ChevronsUpDown, X } from "lucide-react";
|
||||
import type {
|
||||
GetServerSidePropsContext,
|
||||
InferGetServerSidePropsType,
|
||||
} from "next";
|
||||
import Head from "next/head";
|
||||
import { useRouter } from "next/router";
|
||||
import React, { useMemo, useState, type ReactElement } from "react";
|
||||
import { useMemo, useState, type ReactElement } from "react";
|
||||
import superjson from "superjson";
|
||||
import { toast } from "sonner";
|
||||
|
||||
export type Services = {
|
||||
appName: string;
|
||||
@@ -191,6 +198,7 @@ export const extractServices = (data: Project | undefined) => {
|
||||
const Project = (
|
||||
props: InferGetServerSidePropsType<typeof getServerSideProps>,
|
||||
) => {
|
||||
const [isBulkActionLoading, setIsBulkActionLoading] = useState(false);
|
||||
const { projectId } = props;
|
||||
const { data: auth } = api.auth.get.useQuery();
|
||||
const { data: user } = api.user.byAuthId.useQuery(
|
||||
@@ -201,7 +209,7 @@ const Project = (
|
||||
enabled: !!auth?.id && auth?.rol === "user",
|
||||
},
|
||||
);
|
||||
const { data, isLoading } = api.project.one.useQuery({ projectId });
|
||||
const { data, isLoading, refetch } = api.project.one.useQuery({ projectId });
|
||||
const router = useRouter();
|
||||
|
||||
const emptyServices =
|
||||
@@ -228,6 +236,70 @@ const Project = (
|
||||
|
||||
const [selectedTypes, setSelectedTypes] = useState<string[]>([]);
|
||||
const [openCombobox, setOpenCombobox] = useState(false);
|
||||
const [selectedServices, setSelectedServices] = useState<string[]>([]);
|
||||
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
|
||||
|
||||
const handleSelectAll = () => {
|
||||
if (selectedServices.length === filteredServices.length) {
|
||||
setSelectedServices([]);
|
||||
} else {
|
||||
setSelectedServices(filteredServices.map((service) => service.id));
|
||||
}
|
||||
};
|
||||
|
||||
const handleServiceSelect = (serviceId: string, event: React.MouseEvent) => {
|
||||
event.stopPropagation();
|
||||
setSelectedServices((prev) =>
|
||||
prev.includes(serviceId)
|
||||
? prev.filter((id) => id !== serviceId)
|
||||
: [...prev, serviceId],
|
||||
);
|
||||
};
|
||||
|
||||
const composeActions = {
|
||||
start: api.compose.start.useMutation(),
|
||||
stop: api.compose.stop.useMutation(),
|
||||
};
|
||||
|
||||
const handleBulkStart = async () => {
|
||||
let success = 0;
|
||||
setIsBulkActionLoading(true);
|
||||
for (const serviceId of selectedServices) {
|
||||
try {
|
||||
await composeActions.start.mutateAsync({ composeId: serviceId });
|
||||
success++;
|
||||
} catch (error) {
|
||||
toast.error(`Error starting service ${serviceId}`);
|
||||
}
|
||||
}
|
||||
if (success > 0) {
|
||||
toast.success(`${success} services started successfully`);
|
||||
refetch();
|
||||
}
|
||||
setIsBulkActionLoading(false);
|
||||
setSelectedServices([]);
|
||||
setIsDropdownOpen(false);
|
||||
};
|
||||
|
||||
const handleBulkStop = async () => {
|
||||
let success = 0;
|
||||
setIsBulkActionLoading(true);
|
||||
for (const serviceId of selectedServices) {
|
||||
try {
|
||||
await composeActions.stop.mutateAsync({ composeId: serviceId });
|
||||
success++;
|
||||
} catch (error) {
|
||||
toast.error(`Error stopping service ${serviceId}`);
|
||||
}
|
||||
}
|
||||
if (success > 0) {
|
||||
toast.success(`${success} services stopped successfully`);
|
||||
refetch();
|
||||
}
|
||||
setSelectedServices([]);
|
||||
setIsDropdownOpen(false);
|
||||
setIsBulkActionLoading(false);
|
||||
};
|
||||
|
||||
const filteredServices = useMemo(() => {
|
||||
if (!applications) return [];
|
||||
@@ -309,78 +381,151 @@ const Project = (
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div className="flex flex-row gap-2 items-center">
|
||||
<div className="w-full relative">
|
||||
<Input
|
||||
placeholder="Filter services..."
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
className="pr-10"
|
||||
/>
|
||||
<Search className="absolute right-3 top-1/2 -translate-y-1/2 size-4 text-muted-foreground" />
|
||||
<div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<Checkbox
|
||||
checked={selectedServices.length > 0}
|
||||
className={cn(
|
||||
"data-[state=checked]:bg-primary",
|
||||
selectedServices.length > 0 &&
|
||||
selectedServices.length <
|
||||
filteredServices.length &&
|
||||
"bg-primary/50",
|
||||
)}
|
||||
onCheckedChange={handleSelectAll}
|
||||
/>
|
||||
<span className="text-sm">
|
||||
Select All{" "}
|
||||
{selectedServices.length > 0 &&
|
||||
`(${selectedServices.length}/${filteredServices.length})`}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<DropdownMenu
|
||||
open={isDropdownOpen}
|
||||
onOpenChange={setIsDropdownOpen}
|
||||
>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
disabled={selectedServices.length === 0}
|
||||
isLoading={isBulkActionLoading}
|
||||
>
|
||||
Bulk Actions
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuLabel>Actions</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
<DialogAction
|
||||
title="Start Services"
|
||||
description={`Are you sure you want to start ${selectedServices.length} services?`}
|
||||
type="default"
|
||||
onClick={handleBulkStart}
|
||||
>
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="w-full justify-start"
|
||||
>
|
||||
<CheckCircle2 className="mr-2 h-4 w-4" />
|
||||
Start
|
||||
</Button>
|
||||
</DialogAction>
|
||||
<DialogAction
|
||||
title="Stop Services"
|
||||
description={`Are you sure you want to stop ${selectedServices.length} services?`}
|
||||
type="destructive"
|
||||
onClick={handleBulkStop}
|
||||
>
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="w-full justify-start text-destructive"
|
||||
>
|
||||
<Ban className="mr-2 h-4 w-4" />
|
||||
Stop
|
||||
</Button>
|
||||
</DialogAction>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
<Popover open={openCombobox} onOpenChange={setOpenCombobox}>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
aria-expanded={openCombobox}
|
||||
className="min-w-[200px] justify-between"
|
||||
>
|
||||
{selectedTypes.length === 0
|
||||
? "Select types..."
|
||||
: `${selectedTypes.length} selected`}
|
||||
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-[200px] p-0">
|
||||
<Command>
|
||||
<CommandInput placeholder="Search type..." />
|
||||
<CommandEmpty>No type found.</CommandEmpty>
|
||||
<CommandGroup>
|
||||
{serviceTypes.map((type) => (
|
||||
|
||||
<div className="flex flex-col gap-2 sm:flex-row sm:gap-4 sm:items-center">
|
||||
<div className="w-full relative">
|
||||
<Input
|
||||
placeholder="Filter services..."
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
className="pr-10"
|
||||
/>
|
||||
<Search className="absolute right-3 top-1/2 -translate-y-1/2 size-4 text-muted-foreground" />
|
||||
</div>
|
||||
<Popover
|
||||
open={openCombobox}
|
||||
onOpenChange={setOpenCombobox}
|
||||
>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
aria-expanded={openCombobox}
|
||||
className="min-w-[200px] justify-between"
|
||||
>
|
||||
{selectedTypes.length === 0
|
||||
? "Select types..."
|
||||
: `${selectedTypes.length} selected`}
|
||||
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-[200px] p-0">
|
||||
<Command>
|
||||
<CommandInput placeholder="Search type..." />
|
||||
<CommandEmpty>No type found.</CommandEmpty>
|
||||
<CommandGroup>
|
||||
{serviceTypes.map((type) => (
|
||||
<CommandItem
|
||||
key={type.value}
|
||||
onSelect={() => {
|
||||
setSelectedTypes((prev) =>
|
||||
prev.includes(type.value)
|
||||
? prev.filter((t) => t !== type.value)
|
||||
: [...prev, type.value],
|
||||
);
|
||||
setOpenCombobox(false);
|
||||
}}
|
||||
>
|
||||
<div className="flex flex-row">
|
||||
<Check
|
||||
className={cn(
|
||||
"mr-2 h-4 w-4",
|
||||
selectedTypes.includes(type.value)
|
||||
? "opacity-100"
|
||||
: "opacity-0",
|
||||
)}
|
||||
/>
|
||||
{type.icon && (
|
||||
<type.icon className="mr-2 h-4 w-4" />
|
||||
)}
|
||||
{type.label}
|
||||
</div>
|
||||
</CommandItem>
|
||||
))}
|
||||
<CommandItem
|
||||
key={type.value}
|
||||
onSelect={() => {
|
||||
setSelectedTypes((prev) =>
|
||||
prev.includes(type.value)
|
||||
? prev.filter((t) => t !== type.value)
|
||||
: [...prev, type.value],
|
||||
);
|
||||
setSelectedTypes([]);
|
||||
setOpenCombobox(false);
|
||||
}}
|
||||
className="border-t"
|
||||
>
|
||||
<div className="flex flex-row">
|
||||
<Check
|
||||
className={cn(
|
||||
"mr-2 h-4 w-4",
|
||||
selectedTypes.includes(type.value)
|
||||
? "opacity-100"
|
||||
: "opacity-0",
|
||||
)}
|
||||
/>
|
||||
{type.icon && (
|
||||
<type.icon className="mr-2 h-4 w-4" />
|
||||
)}
|
||||
{type.label}
|
||||
<div className="flex flex-row items-center">
|
||||
<X className="mr-2 h-4 w-4" />
|
||||
Clear filters
|
||||
</div>
|
||||
</CommandItem>
|
||||
))}
|
||||
<CommandItem
|
||||
onSelect={() => {
|
||||
setSelectedTypes([]);
|
||||
setOpenCombobox(false);
|
||||
}}
|
||||
className="border-t"
|
||||
>
|
||||
<div className="flex flex-row items-center">
|
||||
<X className="mr-2 h-4 w-4" />
|
||||
Clear filters
|
||||
</div>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</CommandGroup>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex w-full gap-8">
|
||||
@@ -418,6 +563,27 @@ const Project = (
|
||||
<StatusTooltip status={service.status} />
|
||||
</div>
|
||||
|
||||
<div
|
||||
className={cn(
|
||||
"absolute -left-3 -bottom-3 size-9 translate-y-1 rounded-full p-0 transition-all duration-200 z-10 bg-background border",
|
||||
selectedServices.includes(service.id)
|
||||
? "opacity-100 translate-y-0"
|
||||
: "opacity-0 group-hover:translate-y-0 group-hover:opacity-100",
|
||||
)}
|
||||
onClick={(e) =>
|
||||
handleServiceSelect(service.id, e)
|
||||
}
|
||||
>
|
||||
<div className="h-full w-full flex items-center justify-center">
|
||||
<Checkbox
|
||||
checked={selectedServices.includes(
|
||||
service.id,
|
||||
)}
|
||||
className="data-[state=checked]:bg-primary"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center justify-between">
|
||||
<div className="flex flex-row items-center gap-2 justify-between w-full">
|
||||
|
||||
5
apps/dokploy/public/templates/frappe-hr.svg
Normal file
5
apps/dokploy/public/templates/frappe-hr.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<svg width="101" height="101" viewBox="0 0 101 101" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M72.2667 0.422852H29.4096C13.63 0.422852 0.838135 13.2147 0.838135 28.9943V71.8514C0.838135 87.631 13.63 100.423 29.4096 100.423H72.2667C88.0463 100.423 100.838 87.631 100.838 71.8514V28.9943C100.838 13.2147 88.0463 0.422852 72.2667 0.422852Z" fill="#06B58B"/>
|
||||
<path d="M31.1592 78.9948L26.3379 73.7091C33.0879 67.602 41.7664 64.209 50.8021 64.209C59.8378 64.209 68.5522 67.5662 75.2665 73.7091L70.4449 78.9948C65.0164 74.0662 58.0521 71.3518 50.8021 71.3518C43.5521 71.3518 36.5523 74.0662 31.1237 78.9948H31.1592Z" fill="white"/>
|
||||
<path d="M54.1236 21.8516H33.1948V28.9944H54.1236C58.0521 28.9944 61.2664 32.2087 61.2664 36.1373V42.7801C61.2664 46.7087 58.0521 49.9229 54.1236 49.9229H47.4805C43.552 49.9229 40.3377 46.7087 40.3377 42.7801V38.28H33.1948V42.7801C33.1948 50.6729 39.5877 57.0658 47.4805 57.0658H54.1236C62.0164 57.0658 68.4093 50.6729 68.4093 42.7801V36.1373C68.4093 28.2444 62.0164 21.8516 54.1236 21.8516Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
@@ -46,6 +46,7 @@ import {
|
||||
findServerById,
|
||||
loadServices,
|
||||
randomizeComposeFile,
|
||||
randomizeIsolatedDeploymentComposeFile,
|
||||
removeCompose,
|
||||
removeComposeDirectory,
|
||||
removeDeploymentsByComposeId,
|
||||
@@ -216,6 +217,21 @@ export const composeRouter = createTRPCRouter({
|
||||
}
|
||||
return await randomizeComposeFile(input.composeId, input.suffix);
|
||||
}),
|
||||
isolatedDeployment: protectedProcedure
|
||||
.input(apiRandomizeCompose)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const compose = await findComposeById(input.composeId);
|
||||
if (compose.project.adminId !== ctx.user.adminId) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to randomize this compose",
|
||||
});
|
||||
}
|
||||
return await randomizeIsolatedDeploymentComposeFile(
|
||||
input.composeId,
|
||||
input.suffix,
|
||||
);
|
||||
}),
|
||||
getConvertedCompose: protectedProcedure
|
||||
.input(apiFindCompose)
|
||||
.query(async ({ input, ctx }) => {
|
||||
@@ -399,6 +415,7 @@ export const composeRouter = createTRPCRouter({
|
||||
name: input.id,
|
||||
sourceType: "raw",
|
||||
appName: `${projectName}-${generatePassword(6)}`,
|
||||
isolatedDeployment: true,
|
||||
});
|
||||
|
||||
if (ctx.user.rol === "user") {
|
||||
|
||||
@@ -4,8 +4,7 @@ services:
|
||||
activepieces:
|
||||
image: activepieces/activepieces:0.35.0
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
@@ -35,8 +34,7 @@ services:
|
||||
postgres:
|
||||
image: postgres:14
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
environment:
|
||||
POSTGRES_DB: activepieces
|
||||
POSTGRES_PASSWORD: ${AP_POSTGRES_PASSWORD}
|
||||
@@ -52,8 +50,7 @@ services:
|
||||
redis:
|
||||
image: redis:7
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
healthcheck:
|
||||
|
||||
@@ -17,8 +17,7 @@ services:
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
volumes:
|
||||
- db-data:/var/lib/postgresql/data
|
||||
environment:
|
||||
|
||||
@@ -7,8 +7,7 @@ services:
|
||||
environment:
|
||||
POSTGRES_USER: aptabase
|
||||
POSTGRES_PASSWORD: sTr0NGp4ssw0rd
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U aptabase"]
|
||||
interval: 10s
|
||||
@@ -27,8 +26,7 @@ services:
|
||||
nofile:
|
||||
soft: 262144
|
||||
hard: 262144
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -f http://localhost:8123 || exit 1"]
|
||||
interval: 10s
|
||||
|
||||
@@ -2,8 +2,7 @@ services:
|
||||
apps:
|
||||
image: budibase.docker.scarf.sh/budibase/apps:3.2.25
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
environment:
|
||||
SELF_HOSTED: 1
|
||||
LOG_LEVEL: info
|
||||
@@ -43,8 +42,7 @@ services:
|
||||
worker:
|
||||
image: budibase.docker.scarf.sh/budibase/worker:3.2.25
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
environment:
|
||||
SELF_HOSTED: 1
|
||||
LOG_LEVEL: info
|
||||
@@ -83,8 +81,7 @@ services:
|
||||
minio:
|
||||
image: minio/minio:RELEASE.2024-11-07T00-52-20Z
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
volumes:
|
||||
- 'minio_data:/data'
|
||||
environment:
|
||||
@@ -104,8 +101,7 @@ services:
|
||||
proxy:
|
||||
image: budibase/proxy:3.2.25
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
environment:
|
||||
PROXY_RATE_LIMIT_WEBHOOKS_PER_SECOND: 10
|
||||
PROXY_RATE_LIMIT_API_PER_SECOND: 20
|
||||
@@ -137,8 +133,7 @@ services:
|
||||
couchdb:
|
||||
image: budibase/couchdb:v3.3.3
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
environment:
|
||||
COUCHDB_USER: budibase
|
||||
COUCHDB_PASSWORD: ${BB_COUCHDB_PASSWORD}
|
||||
@@ -157,8 +152,7 @@ services:
|
||||
- 'couchdb3_data:/opt/couchdb/data'
|
||||
redis:
|
||||
image: redis:7.2-alpine
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
restart: unless-stopped
|
||||
command: 'redis-server --requirepass "${BB_REDIS_PASSWORD}"'
|
||||
volumes:
|
||||
@@ -176,8 +170,7 @@ services:
|
||||
start_period: 10s
|
||||
watchtower:
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
image: containrrr/watchtower:1.7.1
|
||||
volumes:
|
||||
- '/var/run/docker.sock:/var/run/docker.sock'
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
volumes:
|
||||
- calcom-data:/var/lib/postgresql/data
|
||||
environment:
|
||||
|
||||
@@ -51,8 +51,7 @@ services:
|
||||
restart: always
|
||||
volumes:
|
||||
- chatwoot-postgres-data:/var/lib/postgresql/data
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
environment:
|
||||
- POSTGRES_DB=${POSTGRES_DATABASE}
|
||||
- POSTGRES_USER=${POSTGRES_USERNAME}
|
||||
@@ -63,8 +62,7 @@ services:
|
||||
restart: always
|
||||
volumes:
|
||||
- chatwoot-redis-data:/data
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
|
||||
networks:
|
||||
dokploy-network:
|
||||
|
||||
@@ -9,8 +9,7 @@ services:
|
||||
- 443
|
||||
depends_on:
|
||||
- server
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
server:
|
||||
image: bluewaveuptime/uptime_server:latest
|
||||
restart: always
|
||||
@@ -22,8 +21,7 @@ services:
|
||||
environment:
|
||||
- DB_CONNECTION_STRING=mongodb://mongodb:27017/uptime_db
|
||||
- REDIS_HOST=redis
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
# volumes:
|
||||
# - /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
redis:
|
||||
@@ -33,8 +31,7 @@ services:
|
||||
- 6379
|
||||
volumes:
|
||||
- ../files/redis/data:/data
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
mongodb:
|
||||
image: bluewaveuptime/uptime_database_mongo:latest
|
||||
restart: always
|
||||
@@ -43,5 +40,3 @@ services:
|
||||
command: ["mongod", "--quiet"]
|
||||
ports:
|
||||
- 27017
|
||||
networks:
|
||||
- dokploy-network
|
||||
@@ -1,8 +1,7 @@
|
||||
services:
|
||||
coder:
|
||||
image: ghcr.io/coder/coder:v2.15.3
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
group_add:
|
||||
@@ -17,8 +16,7 @@ services:
|
||||
|
||||
db:
|
||||
image: postgres:17
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
environment:
|
||||
- POSTGRES_PASSWORD
|
||||
- POSTGRES_USER
|
||||
|
||||
@@ -3,8 +3,7 @@ services:
|
||||
image: postgis/postgis:13-master
|
||||
volumes:
|
||||
- directus_database:/var/lib/postgresql/data
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
environment:
|
||||
POSTGRES_USER: "directus"
|
||||
POSTGRES_PASSWORD: ${DATABASE_PASSWORD}
|
||||
@@ -26,8 +25,7 @@ services:
|
||||
retries: 5
|
||||
start_interval: 5s
|
||||
start_period: 30s
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
|
||||
directus:
|
||||
image: directus/directus:11.0.2
|
||||
|
||||
@@ -4,8 +4,7 @@ services:
|
||||
tickets-postgres:
|
||||
image: mysql:8
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
volumes:
|
||||
- tickets-mysql-data:/var/lib/mysql
|
||||
environment:
|
||||
@@ -25,8 +24,7 @@ services:
|
||||
tickets-postgres:
|
||||
condition: service_healthy
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
volumes:
|
||||
- tickets-app-data:/home/container/user
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
|
||||
@@ -3,8 +3,7 @@ version: '3.7'
|
||||
services:
|
||||
discourse-db:
|
||||
image: docker.io/bitnami/postgresql:17
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
volumes:
|
||||
- discourse-postgresql-data:/bitnami/postgresql
|
||||
environment:
|
||||
@@ -20,8 +19,7 @@ services:
|
||||
|
||||
discourse-redis:
|
||||
image: docker.io/bitnami/redis:7.4
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
volumes:
|
||||
- discourse-redis-data:/bitnami/redis
|
||||
environment:
|
||||
@@ -35,8 +33,7 @@ services:
|
||||
|
||||
discourse-app:
|
||||
image: docker.io/bitnami/discourse:3.3.2
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
volumes:
|
||||
- discourse-data:/bitnami/discourse
|
||||
depends_on:
|
||||
@@ -63,8 +60,7 @@ services:
|
||||
|
||||
discourse-sidekiq:
|
||||
image: docker.io/bitnami/discourse:3.3.2
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
volumes:
|
||||
- discourse-sidekiq-data:/bitnami/discourse
|
||||
depends_on:
|
||||
|
||||
@@ -12,8 +12,7 @@ services:
|
||||
- DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}?schema=public
|
||||
- REDIS_URL=redis://redis:6379
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
volumes:
|
||||
- docmost:/app/data/storage
|
||||
|
||||
@@ -24,16 +23,14 @@ services:
|
||||
- POSTGRES_USER
|
||||
- POSTGRES_PASSWORD
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
volumes:
|
||||
- db_docmost_data:/var/lib/postgresql/data
|
||||
|
||||
redis:
|
||||
image: redis:7.2-alpine
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
volumes:
|
||||
- redis_docmost_data:/data
|
||||
|
||||
|
||||
@@ -2,8 +2,7 @@ version: "3.8"
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:16
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
volumes:
|
||||
- documenso-data:/var/lib/postgresql/data
|
||||
environment:
|
||||
|
||||
@@ -4,16 +4,14 @@ services:
|
||||
image: plantuml/plantuml-server
|
||||
ports:
|
||||
- "8080"
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
volumes:
|
||||
- fonts_volume:/usr/share/fonts/drawio
|
||||
image-export:
|
||||
image: jgraph/export-server
|
||||
ports:
|
||||
- "8000"
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
volumes:
|
||||
- fonts_volume:/usr/share/fonts/drawio
|
||||
environment:
|
||||
@@ -28,8 +26,7 @@ services:
|
||||
depends_on:
|
||||
- plantuml-server
|
||||
- image-export
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
environment:
|
||||
RAWIO_SELF_CONTAINED: 1
|
||||
DRAWIO_USE_HTTP: 1
|
||||
|
||||
@@ -189,7 +189,7 @@ services:
|
||||
bench set-config -g redis_socketio "redis://$$REDIS_QUEUE";
|
||||
bench set-config -gp socketio_port $$SOCKETIO_PORT;
|
||||
environment:
|
||||
DB_HOST: db
|
||||
DB_HOST: "${DB_HOST:-db}"
|
||||
DB_PORT: "3306"
|
||||
REDIS_CACHE: redis-cache:6379
|
||||
REDIS_QUEUE: redis-queue:6379
|
||||
@@ -210,7 +210,7 @@ services:
|
||||
entrypoint: ["bash", "-c"]
|
||||
command:
|
||||
- >
|
||||
wait-for-it -t 120 db:3306;
|
||||
wait-for-it -t 120 $$DB_HOST:$$DB_PORT;
|
||||
wait-for-it -t 120 redis-cache:6379;
|
||||
wait-for-it -t 120 redis-queue:6379;
|
||||
export start=`date +%s`;
|
||||
@@ -231,10 +231,12 @@ services:
|
||||
volumes:
|
||||
- sites:/home/frappe/frappe-bench/sites
|
||||
environment:
|
||||
SITE_NAME: ${SITE_NAME}
|
||||
ADMIN_PASSWORD: ${ADMIN_PASSWORD}
|
||||
DB_HOST: ${DB_HOST:-db}
|
||||
DB_PORT: "${DB_PORT:-3306}"
|
||||
DB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
|
||||
INSTALL_APP_ARGS: ${INSTALL_APP_ARGS}
|
||||
SITE_NAME: ${SITE_NAME}
|
||||
networks:
|
||||
- bench-network
|
||||
|
||||
@@ -262,6 +264,8 @@ services:
|
||||
db:
|
||||
image: mariadb:10.6
|
||||
deploy:
|
||||
mode: replicated
|
||||
replicas: ${ENABLE_DB:-0}
|
||||
restart_policy:
|
||||
condition: always
|
||||
healthcheck:
|
||||
@@ -341,6 +345,10 @@ volumes:
|
||||
redis-queue-data:
|
||||
redis-socketio-data:
|
||||
sites:
|
||||
driver_opts:
|
||||
type: "${SITE_VOLUME_TYPE}"
|
||||
o: "${SITE_VOLUME_OPTS}"
|
||||
device: "${SITE_VOLUME_DEV}"
|
||||
|
||||
networks:
|
||||
bench-network:
|
||||
@@ -24,6 +24,8 @@ export function generate(schema: Schema): Template {
|
||||
`ADMIN_PASSWORD=${adminPassword}`,
|
||||
`DB_ROOT_PASSWORD=${dbRootPassword}`,
|
||||
"MIGRATE=1",
|
||||
"ENABLE_DB=1",
|
||||
"DB_HOST=db",
|
||||
"CREATE_SITE=1",
|
||||
"CONFIGURE=1",
|
||||
"REGENERATE_APPS_TXT=1",
|
||||
|
||||
@@ -4,8 +4,7 @@ services:
|
||||
restart: always
|
||||
volumes:
|
||||
- evolution-instances:/evolution/instances
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
environment:
|
||||
- SERVER_URL=${SERVER_URL}
|
||||
- AUTHENTICATION_TYPE=${AUTHENTICATION_TYPE}
|
||||
@@ -36,8 +35,7 @@ services:
|
||||
restart: always
|
||||
volumes:
|
||||
- evolution-postgres-data:/var/lib/postgresql/data
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
environment:
|
||||
- POSTGRES_DB=${POSTGRES_DATABASE}
|
||||
- POSTGRES_USER=${POSTGRES_USERNAME}
|
||||
@@ -48,8 +46,7 @@ services:
|
||||
restart: always
|
||||
volumes:
|
||||
- evolution-redis-data:/data
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
|
||||
networks:
|
||||
dokploy-network:
|
||||
|
||||
@@ -2,6 +2,5 @@ version: "3.8"
|
||||
|
||||
services:
|
||||
excalidraw:
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
image: excalidraw/excalidraw:latest
|
||||
|
||||
@@ -18,8 +18,7 @@ services:
|
||||
- postgres:/var/lib/postgresql/data
|
||||
environment:
|
||||
- POSTGRES_PASSWORD=postgres
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
|
||||
formbricks:
|
||||
restart: always
|
||||
|
||||
354
apps/dokploy/templates/frappe-hr/docker-compose.yml
Normal file
354
apps/dokploy/templates/frappe-hr/docker-compose.yml
Normal file
@@ -0,0 +1,354 @@
|
||||
x-custom-image: &custom_image
|
||||
image: ${IMAGE_NAME:-ghcr.io/frappe/hrms}:${VERSION:-version-15}
|
||||
pull_policy: ${PULL_POLICY:-always}
|
||||
deploy:
|
||||
restart_policy:
|
||||
condition: always
|
||||
|
||||
services:
|
||||
backend:
|
||||
<<: *custom_image
|
||||
volumes:
|
||||
- sites:/home/frappe/frappe-bench/sites
|
||||
networks:
|
||||
- bench-network
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD
|
||||
- wait-for-it
|
||||
- '0.0.0.0:8000'
|
||||
interval: 2s
|
||||
timeout: 10s
|
||||
retries: 30
|
||||
|
||||
frontend:
|
||||
<<: *custom_image
|
||||
command:
|
||||
- nginx-entrypoint.sh
|
||||
depends_on:
|
||||
backend:
|
||||
condition: service_started
|
||||
required: true
|
||||
websocket:
|
||||
condition: service_started
|
||||
required: true
|
||||
environment:
|
||||
BACKEND: backend:8000
|
||||
FRAPPE_SITE_NAME_HEADER: ${FRAPPE_SITE_NAME_HEADER:-$$host}
|
||||
SOCKETIO: websocket:9000
|
||||
UPSTREAM_REAL_IP_ADDRESS: 127.0.0.1
|
||||
UPSTREAM_REAL_IP_HEADER: X-Forwarded-For
|
||||
UPSTREAM_REAL_IP_RECURSIVE: "off"
|
||||
volumes:
|
||||
- sites:/home/frappe/frappe-bench/sites
|
||||
|
||||
networks:
|
||||
- bench-network
|
||||
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD
|
||||
- wait-for-it
|
||||
- '0.0.0.0:8080'
|
||||
interval: 2s
|
||||
timeout: 30s
|
||||
retries: 30
|
||||
|
||||
queue-default:
|
||||
<<: *custom_image
|
||||
command:
|
||||
- bench
|
||||
- worker
|
||||
- --queue
|
||||
- default
|
||||
volumes:
|
||||
- sites:/home/frappe/frappe-bench/sites
|
||||
networks:
|
||||
- bench-network
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD
|
||||
- wait-for-it
|
||||
- 'redis-queue:6379'
|
||||
interval: 2s
|
||||
timeout: 10s
|
||||
retries: 30
|
||||
depends_on:
|
||||
configurator:
|
||||
condition: service_completed_successfully
|
||||
required: true
|
||||
|
||||
queue-long:
|
||||
<<: *custom_image
|
||||
command:
|
||||
- bench
|
||||
- worker
|
||||
- --queue
|
||||
- long
|
||||
volumes:
|
||||
- sites:/home/frappe/frappe-bench/sites
|
||||
networks:
|
||||
- bench-network
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD
|
||||
- wait-for-it
|
||||
- 'redis-queue:6379'
|
||||
interval: 2s
|
||||
timeout: 10s
|
||||
retries: 30
|
||||
depends_on:
|
||||
configurator:
|
||||
condition: service_completed_successfully
|
||||
required: true
|
||||
|
||||
queue-short:
|
||||
<<: *custom_image
|
||||
command:
|
||||
- bench
|
||||
- worker
|
||||
- --queue
|
||||
- short
|
||||
volumes:
|
||||
- sites:/home/frappe/frappe-bench/sites
|
||||
networks:
|
||||
- bench-network
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD
|
||||
- wait-for-it
|
||||
- 'redis-queue:6379'
|
||||
interval: 2s
|
||||
timeout: 10s
|
||||
retries: 30
|
||||
depends_on:
|
||||
configurator:
|
||||
condition: service_completed_successfully
|
||||
required: true
|
||||
|
||||
scheduler:
|
||||
<<: *custom_image
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD
|
||||
- wait-for-it
|
||||
- 'redis-queue:6379'
|
||||
interval: 2s
|
||||
timeout: 10s
|
||||
retries: 30
|
||||
command:
|
||||
- bench
|
||||
- schedule
|
||||
depends_on:
|
||||
configurator:
|
||||
condition: service_completed_successfully
|
||||
required: true
|
||||
volumes:
|
||||
- sites:/home/frappe/frappe-bench/sites
|
||||
networks:
|
||||
- bench-network
|
||||
|
||||
websocket:
|
||||
<<: *custom_image
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD
|
||||
- wait-for-it
|
||||
- '0.0.0.0:9000'
|
||||
interval: 2s
|
||||
timeout: 10s
|
||||
retries: 30
|
||||
command:
|
||||
- node
|
||||
- /home/frappe/frappe-bench/apps/frappe/socketio.js
|
||||
depends_on:
|
||||
configurator:
|
||||
condition: service_completed_successfully
|
||||
required: true
|
||||
volumes:
|
||||
- sites:/home/frappe/frappe-bench/sites
|
||||
networks:
|
||||
- bench-network
|
||||
|
||||
configurator:
|
||||
<<: *custom_image
|
||||
deploy:
|
||||
mode: replicated
|
||||
replicas: ${CONFIGURE:-0}
|
||||
restart_policy:
|
||||
condition: none
|
||||
entrypoint: ["bash", "-c"]
|
||||
command:
|
||||
- >
|
||||
[[ $${REGENERATE_APPS_TXT} == "1" ]] && ls -1 apps > sites/apps.txt;
|
||||
[[ -n `grep -hs ^ sites/common_site_config.json | jq -r ".db_host // empty"` ]] && exit 0;
|
||||
bench set-config -g db_host $$DB_HOST;
|
||||
bench set-config -gp db_port $$DB_PORT;
|
||||
bench set-config -g redis_cache "redis://$$REDIS_CACHE";
|
||||
bench set-config -g redis_queue "redis://$$REDIS_QUEUE";
|
||||
bench set-config -g redis_socketio "redis://$$REDIS_QUEUE";
|
||||
bench set-config -gp socketio_port $$SOCKETIO_PORT;
|
||||
environment:
|
||||
DB_HOST: "${DB_HOST:-db}"
|
||||
DB_PORT: "3306"
|
||||
REDIS_CACHE: redis-cache:6379
|
||||
REDIS_QUEUE: redis-queue:6379
|
||||
SOCKETIO_PORT: "9000"
|
||||
REGENERATE_APPS_TXT: "${REGENERATE_APPS_TXT:-0}"
|
||||
volumes:
|
||||
- sites:/home/frappe/frappe-bench/sites
|
||||
networks:
|
||||
- bench-network
|
||||
|
||||
create-site:
|
||||
<<: *custom_image
|
||||
deploy:
|
||||
mode: replicated
|
||||
replicas: ${CREATE_SITE:-0}
|
||||
restart_policy:
|
||||
condition: none
|
||||
entrypoint: ["bash", "-c"]
|
||||
command:
|
||||
- >
|
||||
wait-for-it -t 120 $$DB_HOST:$$DB_PORT;
|
||||
wait-for-it -t 120 redis-cache:6379;
|
||||
wait-for-it -t 120 redis-queue:6379;
|
||||
export start=`date +%s`;
|
||||
until [[ -n `grep -hs ^ sites/common_site_config.json | jq -r ".db_host // empty"` ]] && \
|
||||
[[ -n `grep -hs ^ sites/common_site_config.json | jq -r ".redis_cache // empty"` ]] && \
|
||||
[[ -n `grep -hs ^ sites/common_site_config.json | jq -r ".redis_queue // empty"` ]];
|
||||
do
|
||||
echo "Waiting for sites/common_site_config.json to be created";
|
||||
sleep 5;
|
||||
if (( `date +%s`-start > 120 )); then
|
||||
echo "could not find sites/common_site_config.json with required keys";
|
||||
exit 1
|
||||
fi
|
||||
done;
|
||||
echo "sites/common_site_config.json found";
|
||||
[[ -d "sites/${SITE_NAME}" ]] && echo "${SITE_NAME} already exists" && exit 0;
|
||||
bench new-site --mariadb-user-host-login-scope='%' --admin-password=$${ADMIN_PASSWORD} --db-root-username=root --db-root-password=$${DB_ROOT_PASSWORD} $${INSTALL_APP_ARGS} $${SITE_NAME};
|
||||
volumes:
|
||||
- sites:/home/frappe/frappe-bench/sites
|
||||
environment:
|
||||
SITE_NAME: ${SITE_NAME}
|
||||
ADMIN_PASSWORD: ${ADMIN_PASSWORD}
|
||||
DB_HOST: ${DB_HOST:-db}
|
||||
DB_PORT: "${DB_PORT:-3306}"
|
||||
DB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
|
||||
INSTALL_APP_ARGS: ${INSTALL_APP_ARGS}
|
||||
networks:
|
||||
- bench-network
|
||||
|
||||
migration:
|
||||
<<: *custom_image
|
||||
deploy:
|
||||
mode: replicated
|
||||
replicas: ${MIGRATE:-0}
|
||||
restart_policy:
|
||||
condition: none
|
||||
entrypoint: ["bash", "-c"]
|
||||
command:
|
||||
- >
|
||||
curl -f http://${SITE_NAME}:8080/api/method/ping || echo "Site busy" && exit 0;
|
||||
bench --site all set-config -p maintenance_mode 1;
|
||||
bench --site all set-config -p pause_scheduler 1;
|
||||
bench --site all migrate;
|
||||
bench --site all set-config -p maintenance_mode 0;
|
||||
bench --site all set-config -p pause_scheduler 0;
|
||||
volumes:
|
||||
- sites:/home/frappe/frappe-bench/sites
|
||||
networks:
|
||||
- bench-network
|
||||
|
||||
db:
|
||||
image: mariadb:10.6
|
||||
deploy:
|
||||
mode: replicated
|
||||
replicas: ${ENABLE_DB:-0}
|
||||
restart_policy:
|
||||
condition: always
|
||||
healthcheck:
|
||||
test: mysqladmin ping -h localhost --password=${DB_ROOT_PASSWORD}
|
||||
interval: 1s
|
||||
retries: 20
|
||||
command:
|
||||
- --character-set-server=utf8mb4
|
||||
- --collation-server=utf8mb4_unicode_ci
|
||||
- --skip-character-set-client-handshake
|
||||
- --skip-innodb-read-only-compressed
|
||||
environment:
|
||||
- MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD}
|
||||
- MARIADB_ROOT_PASSWORD=${DB_ROOT_PASSWORD}
|
||||
volumes:
|
||||
- db-data:/var/lib/mysql
|
||||
networks:
|
||||
- bench-network
|
||||
|
||||
redis-cache:
|
||||
deploy:
|
||||
restart_policy:
|
||||
condition: always
|
||||
image: redis:6.2-alpine
|
||||
volumes:
|
||||
- redis-cache-data:/data
|
||||
networks:
|
||||
- bench-network
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD
|
||||
- redis-cli
|
||||
- ping
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
|
||||
redis-queue:
|
||||
deploy:
|
||||
restart_policy:
|
||||
condition: always
|
||||
image: redis:6.2-alpine
|
||||
volumes:
|
||||
- redis-queue-data:/data
|
||||
networks:
|
||||
- bench-network
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD
|
||||
- redis-cli
|
||||
- ping
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
|
||||
redis-socketio:
|
||||
deploy:
|
||||
restart_policy:
|
||||
condition: always
|
||||
image: redis:6.2-alpine
|
||||
volumes:
|
||||
- redis-socketio-data:/data
|
||||
networks:
|
||||
- bench-network
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD
|
||||
- redis-cli
|
||||
- ping
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
|
||||
volumes:
|
||||
db-data:
|
||||
redis-cache-data:
|
||||
redis-queue-data:
|
||||
redis-socketio-data:
|
||||
sites:
|
||||
driver_opts:
|
||||
type: "${SITE_VOLUME_TYPE}"
|
||||
o: "${SITE_VOLUME_OPTS}"
|
||||
device: "${SITE_VOLUME_DEV}"
|
||||
|
||||
networks:
|
||||
bench-network:
|
||||
39
apps/dokploy/templates/frappe-hr/index.ts
Normal file
39
apps/dokploy/templates/frappe-hr/index.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import {
|
||||
type DomainSchema,
|
||||
type Schema,
|
||||
type Template,
|
||||
generatePassword,
|
||||
generateRandomDomain,
|
||||
} from "../utils";
|
||||
|
||||
export function generate(schema: Schema): Template {
|
||||
const dbRootPassword = generatePassword(32);
|
||||
const adminPassword = generatePassword(32);
|
||||
const mainDomain = generateRandomDomain(schema);
|
||||
|
||||
const domains: DomainSchema[] = [
|
||||
{
|
||||
host: mainDomain,
|
||||
port: 8080,
|
||||
serviceName: "frontend",
|
||||
},
|
||||
];
|
||||
|
||||
const envs = [
|
||||
`SITE_NAME=${mainDomain}`,
|
||||
`ADMIN_PASSWORD=${adminPassword}`,
|
||||
`DB_ROOT_PASSWORD=${dbRootPassword}`,
|
||||
"MIGRATE=1",
|
||||
"ENABLE_DB=1",
|
||||
"DB_HOST=db",
|
||||
"CREATE_SITE=1",
|
||||
"CONFIGURE=1",
|
||||
"REGENERATE_APPS_TXT=1",
|
||||
"INSTALL_APP_ARGS=--install-app hrms",
|
||||
"IMAGE_NAME=ghcr.io/frappe/hrms",
|
||||
"VERSION=version-15",
|
||||
"FRAPPE_SITE_NAME_HEADER=",
|
||||
];
|
||||
|
||||
return { envs, domains };
|
||||
}
|
||||
@@ -17,8 +17,7 @@ services:
|
||||
db:
|
||||
image: mysql:8.0
|
||||
restart: always
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: example
|
||||
volumes:
|
||||
|
||||
@@ -11,8 +11,7 @@ services:
|
||||
- GITEA__database__USER=gitea
|
||||
- GITEA__database__PASSWD=gitea
|
||||
restart: always
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
volumes:
|
||||
- gitea_server:/data
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
@@ -27,8 +26,7 @@ services:
|
||||
- POSTGRES_USER=gitea
|
||||
- POSTGRES_PASSWORD=gitea
|
||||
- POSTGRES_DB=gitea
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
volumes:
|
||||
- gitea_db:/var/lib/postgresql/data
|
||||
|
||||
|
||||
@@ -20,13 +20,11 @@ services:
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- pg-data:/var/lib/postgresql/data
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
redis:
|
||||
image: redis
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
web:
|
||||
image: glitchtip/glitchtip:v4.0
|
||||
depends_on: *default-depends_on
|
||||
@@ -44,15 +42,13 @@ services:
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- uploads:/code/uploads
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
migrate:
|
||||
image: glitchtip/glitchtip:v4.0
|
||||
depends_on: *default-depends_on
|
||||
command: "./manage.py migrate"
|
||||
environment: *default-environment
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
|
||||
volumes:
|
||||
pg-data:
|
||||
|
||||
@@ -4,8 +4,7 @@ services:
|
||||
restart: always
|
||||
volumes:
|
||||
- glpi-mysql-data:/var/lib/mysql
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
|
||||
glpi-web:
|
||||
image: elestio/glpi:10.0.16
|
||||
@@ -16,8 +15,7 @@ services:
|
||||
- glpi-www-data:/var/www/html/glpi
|
||||
environment:
|
||||
- TIMEZONE=Europe/Brussels
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
|
||||
volumes:
|
||||
glpi-mysql-data:
|
||||
|
||||
@@ -28,8 +28,7 @@ services:
|
||||
postgres:
|
||||
image: elestio/postgres:16
|
||||
restart: always
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
environment:
|
||||
- POSTGRES_DB
|
||||
- POSTGRES_USER
|
||||
|
||||
@@ -2,8 +2,7 @@ name: ${DOCKER_NAME}
|
||||
version: "3"
|
||||
services:
|
||||
nginx:
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
image: "nginx:1.21.3"
|
||||
ports:
|
||||
- 80
|
||||
@@ -12,8 +11,7 @@ services:
|
||||
restart: unless-stopped
|
||||
|
||||
mongodb:
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
image: "mongo:7-jammy"
|
||||
environment:
|
||||
- PUID=1000
|
||||
@@ -23,8 +21,7 @@ services:
|
||||
restart: unless-stopped
|
||||
|
||||
minio:
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
image: "minio/minio:RELEASE.2024-11-07T00-52-20Z"
|
||||
command: server /data --address ":9000" --console-address ":9001"
|
||||
volumes:
|
||||
@@ -32,8 +29,7 @@ services:
|
||||
restart: unless-stopped
|
||||
|
||||
elastic:
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
image: "elasticsearch:7.14.2"
|
||||
command: |
|
||||
/bin/sh -c "./bin/elasticsearch-plugin list | grep -q ingest-attachment || yes | ./bin/elasticsearch-plugin install --silent ingest-attachment;
|
||||
@@ -54,8 +50,7 @@ services:
|
||||
restart: unless-stopped
|
||||
|
||||
rekoni:
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
image: hardcoreeng/rekoni-service:${HULY_VERSION}
|
||||
environment:
|
||||
- SECRET=${SECRET}
|
||||
@@ -66,8 +61,7 @@ services:
|
||||
restart: unless-stopped
|
||||
|
||||
transactor:
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
image: hardcoreeng/transactor:${HULY_VERSION}
|
||||
environment:
|
||||
- SERVER_PORT=3333
|
||||
@@ -84,8 +78,7 @@ services:
|
||||
restart: unless-stopped
|
||||
|
||||
collaborator:
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
image: hardcoreeng/collaborator:${HULY_VERSION}
|
||||
environment:
|
||||
- COLLABORATOR_PORT=3078
|
||||
@@ -97,8 +90,7 @@ services:
|
||||
restart: unless-stopped
|
||||
|
||||
account:
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
image: hardcoreeng/account:${HULY_VERSION}
|
||||
environment:
|
||||
- SERVER_PORT=3000
|
||||
@@ -115,8 +107,7 @@ services:
|
||||
restart: unless-stopped
|
||||
|
||||
workspace:
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
image: hardcoreeng/workspace:${HULY_VERSION}
|
||||
environment:
|
||||
- SERVER_SECRET=${SECRET}
|
||||
@@ -130,8 +121,7 @@ services:
|
||||
restart: unless-stopped
|
||||
|
||||
front:
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
image: hardcoreeng/front:${HULY_VERSION}
|
||||
environment:
|
||||
- SERVER_PORT=8080
|
||||
@@ -156,8 +146,7 @@ services:
|
||||
restart: unless-stopped
|
||||
|
||||
fulltext:
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
image: hardcoreeng/fulltext:${HULY_VERSION}
|
||||
environment:
|
||||
- SERVER_SECRET=${SECRET}
|
||||
@@ -171,8 +160,7 @@ services:
|
||||
restart: unless-stopped
|
||||
|
||||
stats:
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
image: hardcoreeng/stats:${HULY_VERSION}
|
||||
environment:
|
||||
- PORT=4900
|
||||
|
||||
@@ -3,8 +3,7 @@ version: "3.9"
|
||||
services:
|
||||
immich-server:
|
||||
image: ghcr.io/immich-app/immich-server:v1.121.0
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
volumes:
|
||||
- immich-library:/usr/src/app/upload
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
@@ -38,8 +37,7 @@ services:
|
||||
|
||||
immich-machine-learning:
|
||||
image: ghcr.io/immich-app/immich-machine-learning:v1.121.0
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
volumes:
|
||||
- immich-model-cache:/cache
|
||||
environment:
|
||||
@@ -55,8 +53,7 @@ services:
|
||||
|
||||
immich-redis:
|
||||
image: redis:6.2-alpine
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
volumes:
|
||||
- immich-redis-data:/data
|
||||
healthcheck:
|
||||
@@ -68,8 +65,7 @@ services:
|
||||
|
||||
immich-database:
|
||||
image: tensorchord/pgvecto-rs:pg14-v0.2.0
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
volumes:
|
||||
- immich-postgres:/var/lib/postgresql/data
|
||||
environment:
|
||||
|
||||
@@ -19,8 +19,7 @@ services:
|
||||
- SMTP_SECURE=true
|
||||
command: npm run migration:latest
|
||||
pull_policy: always
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
|
||||
backend:
|
||||
restart: unless-stopped
|
||||
@@ -46,8 +45,7 @@ services:
|
||||
- SMTP_USERNAME
|
||||
- SMTP_PASSWORD
|
||||
- SMTP_SECURE=true
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
|
||||
redis:
|
||||
image: redis:7.4.1
|
||||
@@ -55,8 +53,7 @@ services:
|
||||
restart: always
|
||||
environment:
|
||||
- ALLOW_EMPTY_PASSWORD=yes
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
volumes:
|
||||
- redis_infisical_data:/data
|
||||
|
||||
@@ -69,8 +66,7 @@ services:
|
||||
- POSTGRES_DB
|
||||
volumes:
|
||||
- pg_infisical_data:/var/lib/postgresql/data
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
healthcheck:
|
||||
test: "pg_isready --username=${POSTGRES_USER} && psql --username=${POSTGRES_USER} --list"
|
||||
interval: 5s
|
||||
|
||||
@@ -3,8 +3,7 @@ version: "3.8"
|
||||
services:
|
||||
invoiceshelf-postgres:
|
||||
image: postgres:15
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
volumes:
|
||||
- invoiceshelf-postgres-data:/var/lib/postgresql/data
|
||||
environment:
|
||||
@@ -19,8 +18,7 @@ services:
|
||||
|
||||
invoiceshelf-app:
|
||||
image: invoiceshelf/invoiceshelf:latest
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
volumes:
|
||||
- invoiceshelf-app-data:/data
|
||||
- invoiceshelf-app-conf:/conf
|
||||
|
||||
@@ -16,8 +16,7 @@ services:
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
db:
|
||||
image: mariadb:10.11
|
||||
restart: unless-stopped
|
||||
@@ -39,8 +38,7 @@ services:
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 30s
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
|
||||
networks:
|
||||
dokploy-network:
|
||||
|
||||
@@ -12,8 +12,7 @@ services:
|
||||
# This variable defines where the logs, file storage, monitor data and secret keys are stored.
|
||||
volumes:
|
||||
- langflow-data:/app/langflow
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
|
||||
postgres-langflow:
|
||||
image: postgres:16
|
||||
@@ -25,8 +24,7 @@ services:
|
||||
- 5432
|
||||
volumes:
|
||||
- langflow-postgres:/var/lib/postgresql/data
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
|
||||
volumes:
|
||||
langflow-postgres:
|
||||
|
||||
@@ -3,8 +3,7 @@ services:
|
||||
image: postgres:17-alpine
|
||||
ports:
|
||||
- 5432
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
environment:
|
||||
- POSTGRES_PASSWORD=listmonk
|
||||
- POSTGRES_USER=listmonk
|
||||
@@ -20,8 +19,7 @@ services:
|
||||
|
||||
setup:
|
||||
image: listmonk/listmonk:v4.1.0
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
volumes:
|
||||
- ../files/config.toml:/listmonk/config.toml
|
||||
depends_on:
|
||||
|
||||
@@ -8,8 +8,7 @@ services:
|
||||
ports:
|
||||
- 3001
|
||||
- 3002
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
environment:
|
||||
TRUST_PROXY_HEADER: 1
|
||||
DB_URL: postgres://logto:${LOGTO_POSTGRES_PASSWORD}@postgres:5432/logto
|
||||
@@ -20,8 +19,7 @@ services:
|
||||
postgres:
|
||||
image: postgres:17-alpine
|
||||
user: postgres
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
environment:
|
||||
POSTGRES_USER: logto
|
||||
POSTGRES_PASSWORD: ${LOGTO_POSTGRES_PASSWORD}
|
||||
|
||||
@@ -24,8 +24,7 @@ services:
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
volumes:
|
||||
- db-data:/var/lib/postgresql/data
|
||||
environment:
|
||||
|
||||
@@ -22,5 +22,4 @@ services:
|
||||
POSTGRES_USER: metabase
|
||||
POSTGRES_DB: metabaseappdb
|
||||
POSTGRES_PASSWORD: mysecretpassword
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
|
||||
@@ -2,8 +2,7 @@ services:
|
||||
nextcloud:
|
||||
image: nextcloud:30.0.2
|
||||
restart: always
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
ports:
|
||||
- 80
|
||||
volumes:
|
||||
@@ -19,8 +18,7 @@ services:
|
||||
nextcloud_db:
|
||||
image: mariadb
|
||||
restart: always
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
volumes:
|
||||
- nextcloud_db_data:/var/lib/mysql
|
||||
environment:
|
||||
|
||||
@@ -13,8 +13,7 @@ services:
|
||||
root_db:
|
||||
image: postgres:17
|
||||
restart: always
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
environment:
|
||||
POSTGRES_DB: root_db
|
||||
POSTGRES_PASSWORD: password
|
||||
|
||||
@@ -15,8 +15,7 @@ services:
|
||||
|
||||
db:
|
||||
image: postgres:13
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
environment:
|
||||
- POSTGRES_DB=postgres
|
||||
- POSTGRES_USER=odoo
|
||||
|
||||
@@ -3,8 +3,7 @@ services:
|
||||
ollama:
|
||||
volumes:
|
||||
- ollama:/root/.ollama
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
pull_policy: always
|
||||
tty: true
|
||||
restart: unless-stopped
|
||||
|
||||
@@ -46,8 +46,7 @@ services:
|
||||
- penpot-backend
|
||||
- penpot-exporter
|
||||
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
|
||||
environment:
|
||||
PENPOT_FLAGS: disable-email-verification enable-smtp enable-prepl-server disable-secure-session-cookies
|
||||
@@ -63,8 +62,7 @@ services:
|
||||
- penpot-postgres
|
||||
- penpot-redis
|
||||
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
|
||||
## Configuration envronment variables for the backend
|
||||
## container.
|
||||
@@ -143,8 +141,7 @@ services:
|
||||
penpot-exporter:
|
||||
image: "penpotapp/exporter:2.3.2"
|
||||
restart: always
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
|
||||
environment:
|
||||
# Don't touch it; this uses an internal docker network to
|
||||
@@ -162,8 +159,7 @@ services:
|
||||
volumes:
|
||||
- penpot_postgres_v15:/var/lib/postgresql/data
|
||||
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
|
||||
environment:
|
||||
- POSTGRES_INITDB_ARGS=--data-checksums
|
||||
@@ -174,8 +170,7 @@ services:
|
||||
penpot-redis:
|
||||
image: redis:7.2
|
||||
restart: always
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
|
||||
## A mailcatch service, used as temporal SMTP server. You can access via HTTP to the
|
||||
## port 1080 for read all emails the penpot platform has sent. Should be only used as a
|
||||
@@ -188,8 +183,7 @@ services:
|
||||
- '1025'
|
||||
ports:
|
||||
- 1080
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
|
||||
## Example configuration of MiniIO (S3 compatible object storage service); If you don't
|
||||
## have preference, then just use filesystem, this is here just for the completeness.
|
||||
|
||||
@@ -4,8 +4,7 @@ services:
|
||||
peppermint-postgres:
|
||||
image: postgres:latest
|
||||
restart: always
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
volumes:
|
||||
- peppermint-postgres-data:/var/lib/postgresql/data
|
||||
environment:
|
||||
@@ -21,8 +20,7 @@ services:
|
||||
peppermint-app:
|
||||
image: pepperlabs/peppermint:latest
|
||||
restart: always
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
depends_on:
|
||||
peppermint-postgres:
|
||||
condition: service_healthy
|
||||
|
||||
@@ -7,8 +7,7 @@ services:
|
||||
security_opt:
|
||||
- seccomp:unconfined
|
||||
- apparmor:unconfined
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
environment:
|
||||
PHOTOPRISM_ADMIN_USER: "admin"
|
||||
PHOTOPRISM_ADMIN_PASSWORD: ${ADMIN_PASSWORD}
|
||||
@@ -57,8 +56,7 @@ services:
|
||||
image: mariadb:11
|
||||
restart: unless-stopped
|
||||
stop_grace_period: 5s
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
security_opt:
|
||||
- seccomp:unconfined
|
||||
- apparmor:unconfined
|
||||
|
||||
@@ -10,8 +10,7 @@ services:
|
||||
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
|
||||
volumes:
|
||||
- db_data:/var/lib/mysql
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
|
||||
phpmyadmin:
|
||||
image: phpmyadmin/phpmyadmin:5.2.1
|
||||
|
||||
@@ -3,8 +3,7 @@ services:
|
||||
plausible_db:
|
||||
image: postgres:16-alpine
|
||||
restart: always
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
volumes:
|
||||
- db-data:/var/lib/postgresql/data
|
||||
environment:
|
||||
@@ -13,8 +12,7 @@ services:
|
||||
plausible_events_db:
|
||||
image: clickhouse/clickhouse-server:24.3.3.102-alpine
|
||||
restart: always
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
volumes:
|
||||
- event-data:/var/lib/clickhouse
|
||||
- event-logs:/var/log/clickhouse-server
|
||||
|
||||
@@ -6,8 +6,7 @@ services:
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- /var/lib/docker/volumes:/var/lib/docker/volumes
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
|
||||
deploy:
|
||||
mode: global
|
||||
|
||||
@@ -4,8 +4,7 @@ services:
|
||||
postiz-app:
|
||||
image: ghcr.io/gitroomhq/postiz-app:latest
|
||||
restart: always
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
environment:
|
||||
MAIN_URL: "https://${POSTIZ_HOST}"
|
||||
FRONTEND_URL: "https://${POSTIZ_HOST}"
|
||||
@@ -30,8 +29,7 @@ services:
|
||||
postiz-postgres:
|
||||
image: postgres:17-alpine
|
||||
restart: always
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
environment:
|
||||
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
||||
POSTGRES_USER: ${DB_USER}
|
||||
@@ -47,8 +45,7 @@ services:
|
||||
postiz-redis:
|
||||
image: redis:7.2
|
||||
restart: always
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
healthcheck:
|
||||
test: redis-cli ping
|
||||
interval: 10s
|
||||
|
||||
@@ -28,8 +28,7 @@ services:
|
||||
MONGODB_ADVERTISED_HOSTNAME: mongodb
|
||||
MONGODB_ENABLE_JOURNAL: true
|
||||
ALLOW_EMPTY_PASSWORD: yes
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
|
||||
volumes:
|
||||
mongodb_data: { driver: local }
|
||||
|
||||
@@ -9,8 +9,7 @@ services:
|
||||
- ROUNDCUBEMAIL_SKIN=elastic
|
||||
- ROUNDCUBEMAIL_DEFAULT_HOST=${DEFAULT_HOST}
|
||||
- ROUNDCUBEMAIL_SMTP_SERVER=${SMTP_SERVER}
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
|
||||
networks:
|
||||
dokploy-network:
|
||||
|
||||
@@ -3,8 +3,7 @@ version: '3.7'
|
||||
services:
|
||||
ryot-app:
|
||||
image: ignisda/ryot:v7.10
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
environment:
|
||||
- DATABASE_URL=postgres://postgres:${POSTGRES_PASSWORD}@ryot-db:5432/postgres
|
||||
- SERVER_ADMIN_ACCESS_TOKEN=${ADMIN_ACCESS_TOKEN}
|
||||
@@ -19,8 +18,7 @@ services:
|
||||
|
||||
ryot-db:
|
||||
image: postgres:16-alpine
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
volumes:
|
||||
- ryot-postgres-data:/var/lib/postgresql/data
|
||||
environment:
|
||||
|
||||
@@ -3,8 +3,7 @@ version: "3.8"
|
||||
services:
|
||||
slash-app:
|
||||
image: yourselfhosted/slash:latest
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
volumes:
|
||||
- slash-app-data:/var/opt/slash
|
||||
environment:
|
||||
@@ -17,8 +16,7 @@ services:
|
||||
|
||||
slash-postgres:
|
||||
image: postgres:16-alpine
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
volumes:
|
||||
- slash-postgres-data:/var/lib/postgresql/data
|
||||
environment:
|
||||
|
||||
@@ -11,8 +11,7 @@ services:
|
||||
studio:
|
||||
container_name: supabase-studio
|
||||
image: supabase/studio:20240729-ce42139
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test:
|
||||
@@ -53,8 +52,7 @@ services:
|
||||
container_name: supabase-kong
|
||||
image: kong:2.8.1
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
# https://unix.stackexchange.com/a/294837
|
||||
entrypoint: bash -c 'eval "echo \"$$(cat ~/temp.yml)\"" > ~/kong.yml && /docker-entrypoint.sh kong docker-start'
|
||||
#ports:
|
||||
@@ -85,8 +83,7 @@ services:
|
||||
auth:
|
||||
container_name: supabase-auth
|
||||
image: supabase/gotrue:v2.158.1
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
depends_on:
|
||||
db:
|
||||
# Disable this if you are using an external Postgres database
|
||||
@@ -157,8 +154,7 @@ services:
|
||||
rest:
|
||||
container_name: supabase-rest
|
||||
image: postgrest/postgrest:v12.2.0
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
depends_on:
|
||||
db:
|
||||
# Disable this if you are using an external Postgres database
|
||||
@@ -180,8 +176,7 @@ services:
|
||||
# This container name looks inconsistent but is correct because realtime constructs tenant id by parsing the subdomain
|
||||
container_name: realtime-dev.supabase-realtime
|
||||
image: supabase/realtime:v2.30.23
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
depends_on:
|
||||
db:
|
||||
# Disable this if you are using an external Postgres database
|
||||
@@ -226,8 +221,7 @@ services:
|
||||
storage:
|
||||
container_name: supabase-storage
|
||||
image: supabase/storage-api:v1.0.6
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
depends_on:
|
||||
db:
|
||||
# Disable this if you are using an external Postgres database
|
||||
@@ -271,8 +265,7 @@ services:
|
||||
imgproxy:
|
||||
container_name: supabase-imgproxy
|
||||
image: darthsim/imgproxy:v3.8.0
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
healthcheck:
|
||||
test: ["CMD", "imgproxy", "health"]
|
||||
timeout: 5s
|
||||
@@ -289,8 +282,7 @@ services:
|
||||
meta:
|
||||
container_name: supabase-meta
|
||||
image: supabase/postgres-meta:v0.83.2
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
depends_on:
|
||||
db:
|
||||
# Disable this if you are using an external Postgres database
|
||||
@@ -310,8 +302,7 @@ services:
|
||||
container_name: supabase-edge-functions
|
||||
image: supabase/edge-runtime:v1.56.0
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
depends_on:
|
||||
analytics:
|
||||
condition: service_healthy
|
||||
@@ -333,8 +324,7 @@ services:
|
||||
analytics:
|
||||
container_name: supabase-analytics
|
||||
image: supabase/logflare:1.4.0
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "http://localhost:4000/health"]
|
||||
timeout: 5s
|
||||
@@ -380,8 +370,7 @@ services:
|
||||
db:
|
||||
container_name: supabase-db
|
||||
image: supabase/postgres:15.1.1.78
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
healthcheck:
|
||||
test: pg_isready -U postgres -h localhost
|
||||
interval: 5s
|
||||
@@ -430,8 +419,7 @@ services:
|
||||
vector:
|
||||
container_name: supabase-vector
|
||||
image: timberio/vector:0.28.1-alpine
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
healthcheck:
|
||||
test:
|
||||
[
|
||||
|
||||
@@ -43,8 +43,7 @@ services:
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
|
||||
superset_redis:
|
||||
image: redis
|
||||
@@ -57,8 +56,7 @@ services:
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
|
||||
volumes:
|
||||
superset_postgres_data:
|
||||
|
||||
@@ -41,8 +41,7 @@ services:
|
||||
- POSTGRES_DB=${POSTGRES_DB}
|
||||
- POSTGRES_USER=${POSTGRES_USER}
|
||||
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
healthcheck:
|
||||
test:
|
||||
[
|
||||
@@ -58,8 +57,7 @@ services:
|
||||
environment:
|
||||
- TZ=${TIMEZONE}
|
||||
- PRISMA_DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
depends_on:
|
||||
teable-db:
|
||||
condition: service_healthy
|
||||
|
||||
@@ -1095,7 +1095,7 @@ export const templates: TemplateData[] = [
|
||||
{
|
||||
id: "unsend",
|
||||
name: "Unsend",
|
||||
version: "v1.2.4",
|
||||
version: "v1.3.2",
|
||||
description: "Open source alternative to Resend,Sendgrid, Postmark etc. ",
|
||||
logo: "unsend.png",
|
||||
links: {
|
||||
@@ -1453,6 +1453,21 @@ export const templates: TemplateData[] = [
|
||||
tags: ["sharing", "shortener", "url"],
|
||||
load: () => import("./shlink/index").then((m) => m.generate),
|
||||
},
|
||||
{
|
||||
id: "frappe-hr",
|
||||
name: "Frappe HR",
|
||||
version: "version-15",
|
||||
description:
|
||||
"Feature rich HR & Payroll software. 100% FOSS and customizable.",
|
||||
logo: "frappe-hr.svg",
|
||||
links: {
|
||||
github: "https://github.com/frappe/hrms",
|
||||
docs: "https://docs.frappe.io/hr",
|
||||
website: "https://frappe.io/hr",
|
||||
},
|
||||
tags: ["hrms", "payroll", "leaves", "expenses", "attendance", "performace"],
|
||||
load: () => import("./frappe-hr/index").then((m) => m.generate),
|
||||
},
|
||||
{
|
||||
id: "formbricks",
|
||||
name: "Formbricks",
|
||||
|
||||
@@ -4,8 +4,7 @@ services:
|
||||
twenty-change-vol-ownership:
|
||||
image: ubuntu
|
||||
user: root
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
volumes:
|
||||
- twenty-server-local-data:/tmp/server-local-data
|
||||
- twenty-docker-data:/tmp/docker-data
|
||||
@@ -16,8 +15,7 @@ services:
|
||||
|
||||
twenty-server:
|
||||
image: twentycrm/twenty:latest
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
volumes:
|
||||
- twenty-server-local-data:/app/packages/twenty-server/${STORAGE_LOCAL_PATH:-.local-storage}
|
||||
- twenty-docker-data:/app/docker-data
|
||||
@@ -45,8 +43,7 @@ services:
|
||||
|
||||
twenty-worker:
|
||||
image: twentycrm/twenty:latest
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
command: ["yarn", "worker:prod"]
|
||||
environment:
|
||||
PG_DATABASE_URL: postgres://${DB_USER}:${DB_PASSWORD}@twenty-postgres:5432/twenty
|
||||
@@ -65,8 +62,7 @@ services:
|
||||
|
||||
twenty-postgres:
|
||||
image: postgres:16-alpine
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
volumes:
|
||||
- twenty-postgres-data:/var/lib/postgresql/data
|
||||
environment:
|
||||
@@ -82,8 +78,7 @@ services:
|
||||
|
||||
twenty-redis:
|
||||
image: redis:latest
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
volumes:
|
||||
- twenty-redis-data:/data
|
||||
healthcheck:
|
||||
|
||||
@@ -13,8 +13,7 @@ services:
|
||||
POSTGRES_USER: typebot
|
||||
POSTGRES_DB: typebot
|
||||
POSTGRES_PASSWORD: typebot
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
|
||||
typebot-builder:
|
||||
image: baptistearno/typebot-builder:2.27
|
||||
|
||||
@@ -22,8 +22,7 @@ services:
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
volumes:
|
||||
- db-data:/var/lib/postgresql/data
|
||||
environment:
|
||||
|
||||
@@ -29,8 +29,7 @@ services:
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- unifi-db
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
|
||||
unifi-db:
|
||||
image: mongo:4.4
|
||||
@@ -40,8 +39,7 @@ services:
|
||||
ports:
|
||||
- 27017
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
|
||||
networks:
|
||||
dokploy-network:
|
||||
|
||||
@@ -3,8 +3,7 @@ name: unsend-prod
|
||||
services:
|
||||
unsend-db-prod:
|
||||
image: postgres:16
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
restart: always
|
||||
environment:
|
||||
- POSTGRES_USER=${POSTGRES_USER:?err}
|
||||
@@ -22,8 +21,7 @@ services:
|
||||
|
||||
unsend-redis-prod:
|
||||
image: redis:7
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
restart: always
|
||||
# ports:
|
||||
# - "6379:6379"
|
||||
@@ -33,8 +31,7 @@ services:
|
||||
|
||||
unsend-storage-prod:
|
||||
image: minio/minio:RELEASE.2024-11-07T00-52-20Z
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
ports:
|
||||
- 9002
|
||||
- 9001
|
||||
@@ -47,9 +44,7 @@ services:
|
||||
command: -c 'mkdir -p /data/unsend && minio server /data --console-address ":9001" --address ":9002"'
|
||||
|
||||
unsend:
|
||||
image: unsend/unsend:v1.2.5
|
||||
networks:
|
||||
- dokploy-network
|
||||
image: unsend/unsend:v1.3.2
|
||||
restart: always
|
||||
ports:
|
||||
- ${PORT:-3000}
|
||||
|
||||
@@ -7,8 +7,7 @@ services:
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- windmill-postgres-data:/var/lib/postgresql/data
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
environment:
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||
POSTGRES_DB: windmill
|
||||
@@ -20,8 +19,7 @@ services:
|
||||
|
||||
windmill-server:
|
||||
image: ghcr.io/windmill-labs/windmill:main
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- DATABASE_URL=${DATABASE_URL}
|
||||
@@ -42,8 +40,7 @@ services:
|
||||
cpus: "1"
|
||||
memory: 2048M
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
environment:
|
||||
- DATABASE_URL=${DATABASE_URL}
|
||||
- MODE=worker
|
||||
@@ -65,8 +62,7 @@ services:
|
||||
cpus: "0.1"
|
||||
memory: 128M
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
environment:
|
||||
- DATABASE_URL=${DATABASE_URL}
|
||||
- MODE=worker
|
||||
@@ -82,16 +78,14 @@ services:
|
||||
windmill-lsp:
|
||||
image: ghcr.io/windmill-labs/windmill-lsp:latest
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
volumes:
|
||||
- windmill-lsp-cache:/root/.cache
|
||||
|
||||
windmill-caddy:
|
||||
image: ghcr.io/windmill-labs/caddy-l4:latest
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
volumes:
|
||||
- ../files/Caddyfile:/etc/caddy/Caddyfile
|
||||
environment:
|
||||
|
||||
@@ -12,8 +12,6 @@ services:
|
||||
|
||||
db:
|
||||
image: mysql:5.7.34
|
||||
networks:
|
||||
- dokploy-network
|
||||
environment:
|
||||
MYSQL_DATABASE: exampledb
|
||||
MYSQL_USER: exampleuser
|
||||
|
||||
@@ -3,8 +3,7 @@ version: '3.7'
|
||||
services:
|
||||
yourls-app:
|
||||
image: yourls:1.9.2
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
environment:
|
||||
YOURLS_SITE: https://${YOURLS_HOST}
|
||||
YOURLS_USER: ${YOURLS_ADMIN_USER}
|
||||
@@ -22,8 +21,7 @@ services:
|
||||
|
||||
yourls-mysql:
|
||||
image: mysql:5.7
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
|
||||
MYSQL_DATABASE: yourls
|
||||
|
||||
@@ -2,8 +2,7 @@ version: "3"
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:15
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- POSTGRES_USER=postgres
|
||||
|
||||
@@ -69,6 +69,7 @@ export const compose = pgTable("compose", {
|
||||
composePath: text("composePath").notNull().default("./docker-compose.yml"),
|
||||
suffix: text("suffix").notNull().default(""),
|
||||
randomize: boolean("randomize").notNull().default(false),
|
||||
isolatedDeployment: boolean("isolatedDeployment").notNull().default(false),
|
||||
composeStatus: applicationStatus("composeStatus").notNull().default("idle"),
|
||||
projectId: text("projectId")
|
||||
.notNull()
|
||||
|
||||
@@ -73,6 +73,7 @@ export * from "./utils/builders/utils";
|
||||
export * from "./utils/cluster/upload";
|
||||
|
||||
export * from "./utils/docker/compose";
|
||||
export * from "./utils/docker/collision";
|
||||
export * from "./utils/docker/domain";
|
||||
export * from "./utils/docker/utils";
|
||||
export * from "./utils/docker/types";
|
||||
|
||||
@@ -34,6 +34,12 @@ export const buildCompose = async (compose: ComposeNested, logPath: string) => {
|
||||
await writeDomainsToCompose(compose, domains);
|
||||
createEnvFile(compose);
|
||||
|
||||
if (compose.isolatedDeployment) {
|
||||
await execAsync(
|
||||
`docker network inspect ${compose.appName} >/dev/null 2>&1 || docker network create --attachable ${compose.appName}`,
|
||||
);
|
||||
}
|
||||
|
||||
const logContent = `
|
||||
App Name: ${appName}
|
||||
Build Compose 🐳
|
||||
@@ -73,6 +79,12 @@ export const buildCompose = async (compose: ComposeNested, logPath: string) => {
|
||||
},
|
||||
);
|
||||
|
||||
if (compose.isolatedDeployment) {
|
||||
await execAsync(
|
||||
`docker network connect ${compose.appName} $(docker ps --filter "name=dokploy-traefik" -q) >/dev/null 2>&1`,
|
||||
).catch(() => {});
|
||||
}
|
||||
|
||||
writeStream.write("Docker Compose Deployed: ✅");
|
||||
} catch (error) {
|
||||
writeStream.write(`Error ❌ ${(error as Error).message}`);
|
||||
@@ -128,9 +140,10 @@ Compose Type: ${composeType} ✅`;
|
||||
|
||||
cd "${projectPath}";
|
||||
|
||||
${exportEnvCommand}
|
||||
|
||||
${exportEnvCommand}
|
||||
${compose.isolatedDeployment ? `docker network inspect ${compose.appName} >/dev/null 2>&1 || docker network create --attachable ${compose.appName}` : ""}
|
||||
docker ${command.split(" ").join(" ")} >> "${logPath}" 2>&1 || { echo "Error: ❌ Docker command failed" >> "${logPath}"; exit 1; }
|
||||
${compose.isolatedDeployment ? `docker network connect ${compose.appName} $(docker ps --filter "name=dokploy-traefik" -q) >/dev/null 2>&1` : ""}
|
||||
|
||||
echo "Docker Compose Deployed: ✅" >> "${logPath}"
|
||||
} || {
|
||||
|
||||
46
packages/server/src/utils/docker/collision.ts
Normal file
46
packages/server/src/utils/docker/collision.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { findComposeById } from "@dokploy/server/services/compose";
|
||||
import { dump, load } from "js-yaml";
|
||||
import { addAppNameToAllServiceNames } from "./collision/root-network";
|
||||
import { generateRandomHash } from "./compose";
|
||||
import { addSuffixToAllVolumes } from "./compose/volume";
|
||||
import type { ComposeSpecification } from "./types";
|
||||
|
||||
export const addAppNameToPreventCollision = (
|
||||
composeData: ComposeSpecification,
|
||||
appName: string,
|
||||
): ComposeSpecification => {
|
||||
let updatedComposeData = { ...composeData };
|
||||
|
||||
updatedComposeData = addAppNameToAllServiceNames(updatedComposeData, appName);
|
||||
updatedComposeData = addSuffixToAllVolumes(updatedComposeData, appName);
|
||||
return updatedComposeData;
|
||||
};
|
||||
|
||||
export const randomizeIsolatedDeploymentComposeFile = async (
|
||||
composeId: string,
|
||||
suffix?: string,
|
||||
) => {
|
||||
const compose = await findComposeById(composeId);
|
||||
const composeFile = compose.composeFile;
|
||||
const composeData = load(composeFile) as ComposeSpecification;
|
||||
|
||||
const randomSuffix = suffix || compose.appName || generateRandomHash();
|
||||
|
||||
const newComposeFile = addAppNameToPreventCollision(
|
||||
composeData,
|
||||
randomSuffix,
|
||||
);
|
||||
|
||||
return dump(newComposeFile);
|
||||
};
|
||||
|
||||
export const randomizeDeployableSpecificationFile = (
|
||||
composeSpec: ComposeSpecification,
|
||||
suffix?: string,
|
||||
) => {
|
||||
if (!suffix) {
|
||||
return composeSpec;
|
||||
}
|
||||
const newComposeFile = addAppNameToPreventCollision(composeSpec, suffix);
|
||||
return newComposeFile;
|
||||
};
|
||||
62
packages/server/src/utils/docker/collision/root-network.ts
Normal file
62
packages/server/src/utils/docker/collision/root-network.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import _ from "lodash";
|
||||
import type { ComposeSpecification, DefinitionsService } from "../types";
|
||||
|
||||
export const addAppNameToRootNetwork = (
|
||||
composeData: ComposeSpecification,
|
||||
appName: string,
|
||||
): ComposeSpecification => {
|
||||
const updatedComposeData = { ...composeData };
|
||||
|
||||
// Initialize networks if it doesn't exist
|
||||
if (!updatedComposeData.networks) {
|
||||
updatedComposeData.networks = {};
|
||||
}
|
||||
|
||||
// Add the new network with the app name
|
||||
updatedComposeData.networks[appName] = {
|
||||
name: appName,
|
||||
external: true,
|
||||
};
|
||||
|
||||
return updatedComposeData;
|
||||
};
|
||||
|
||||
export const addAppNameToServiceNetworks = (
|
||||
services: { [key: string]: DefinitionsService },
|
||||
appName: string,
|
||||
): { [key: string]: DefinitionsService } => {
|
||||
return _.mapValues(services, (service) => {
|
||||
if (!service.networks) {
|
||||
service.networks = [appName];
|
||||
return service;
|
||||
}
|
||||
|
||||
if (Array.isArray(service.networks)) {
|
||||
if (!service.networks.includes(appName)) {
|
||||
service.networks.push(appName);
|
||||
}
|
||||
} else {
|
||||
service.networks[appName] = {};
|
||||
}
|
||||
|
||||
return service;
|
||||
});
|
||||
};
|
||||
|
||||
export const addAppNameToAllServiceNames = (
|
||||
composeData: ComposeSpecification,
|
||||
appName: string,
|
||||
): ComposeSpecification => {
|
||||
let updatedComposeData = { ...composeData };
|
||||
|
||||
updatedComposeData = addAppNameToRootNetwork(updatedComposeData, appName);
|
||||
|
||||
if (updatedComposeData.services) {
|
||||
updatedComposeData.services = addAppNameToServiceNetworks(
|
||||
updatedComposeData.services,
|
||||
appName,
|
||||
);
|
||||
}
|
||||
|
||||
return updatedComposeData;
|
||||
};
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
createComposeFileRaw,
|
||||
createComposeFileRawRemote,
|
||||
} from "../providers/raw";
|
||||
import { randomizeDeployableSpecificationFile } from "./collision";
|
||||
import { randomizeSpecificationFile } from "./compose";
|
||||
import type {
|
||||
ComposeSpecification,
|
||||
@@ -190,7 +191,13 @@ export const addDomainToCompose = async (
|
||||
return null;
|
||||
}
|
||||
|
||||
if (compose.randomize) {
|
||||
if (compose.isolatedDeployment) {
|
||||
const randomized = randomizeDeployableSpecificationFile(
|
||||
result,
|
||||
compose.suffix || compose.appName,
|
||||
);
|
||||
result = randomized;
|
||||
} else if (compose.randomize) {
|
||||
const randomized = randomizeSpecificationFile(result, compose.suffix);
|
||||
result = randomized;
|
||||
}
|
||||
@@ -240,14 +247,18 @@ export const addDomainToCompose = async (
|
||||
labels.push(...httpLabels);
|
||||
}
|
||||
|
||||
// Add the dokploy-network to the service
|
||||
result.services[serviceName].networks = addDokployNetworkToService(
|
||||
result.services[serviceName].networks,
|
||||
);
|
||||
if (!compose.isolatedDeployment) {
|
||||
// Add the dokploy-network to the service
|
||||
result.services[serviceName].networks = addDokployNetworkToService(
|
||||
result.services[serviceName].networks,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Add dokploy-network to the root of the compose file
|
||||
result.networks = addDokployNetworkToRoot(result.networks);
|
||||
if (!compose.isolatedDeployment) {
|
||||
result.networks = addDokployNetworkToRoot(result.networks);
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user