Compare commits

...

59 Commits

Author SHA1 Message Date
Mauricio Siu
bfdc73f8d1 Merge pull request #197 from Dokploy/canary
v0.3.1
2024-07-06 12:01:07 -06:00
Mauricio Siu
525a711c55 refactor(settings): throw error and log the error 2024-07-06 11:55:21 -06:00
Mauricio Siu
e0a0f97f70 refactor(settings): add console logs for errors 2024-07-06 11:34:33 -06:00
Mauricio Siu
45aae520d8 refacto(github): comment github app 2024-07-05 22:48:32 -06:00
Mauricio Siu
c8f14c322e chore(version): bump version 2024-07-05 13:43:56 -06:00
Mauricio Siu
334466f28f Merge pull request #196 from Dokploy/fix/remove-registry-login-on-self-hosted
fix(registry): remove login on self hosted
2024-07-05 12:32:04 -06:00
Mauricio Siu
22328eeb83 fix(registry): remove login on self hosted 2024-07-05 12:24:13 -06:00
Mauricio Siu
c2201a304e Merge pull request #192 from kucherenko/canary
feat(open-webui): add open-webui template
2024-07-04 10:51:16 -06:00
Mauricio Siu
f77de1bc52 Update templates.ts 2024-07-04 10:43:30 -06:00
Andrey Kucherenko
74d6b2d591 Merge branch 'Dokploy:canary' into canary 2024-07-04 14:00:59 +03:00
Andrey Kucherenko
b7cc3283e2 chore(review): update code based on code review 2024-07-04 12:27:45 +03:00
Mauricio Siu
5dfa6c5194 Merge pull request #193 from Dokploy/fix/custom-internal-url-with-port
fix(git): set 22 port in git add host
2024-07-04 00:58:57 -06:00
Mauricio Siu
59d662396e fix(git): set 22 port in git add host 2024-07-04 00:39:11 -06:00
Mauricio Siu
cbfcae4ab6 Merge pull request #191 from DarkPhoenix2704/update-nocodb
chore: bump nocodb template version
2024-07-03 13:19:07 -06:00
Andrey Kucherenko
152a54b251 feat(open-webui): add open-webui template 2024-07-03 18:21:01 +03:00
DarkPhoenix2704
1113669bfd chore: bump version 2024-07-03 17:09:25 +05:30
Mauricio Siu
4d251271b9 refactor(webhook): use findAdmin() fn 2024-07-02 21:46:06 -06:00
Mauricio Siu
21263a217c Merge pull request #188 from Dokploy/feat/enable-autodeploy-github
feat(github-webhooks): #186 implement github autodeployment with zero…
2024-07-02 21:12:35 -06:00
Mauricio Siu
3322fdf937 Merge pull request #189 from slowlydev/feat/enable-autodeploy-github
Add web hook verification to GitHub Autodeploy
2024-07-02 18:02:06 -06:00
Slowlydev
b415e2fba1 feat(deploy-github): add webhook secret verification before deploying 2024-07-02 17:35:33 +02:00
Slowlydev
8888a4ce5c chore(deps): add @octokit/webhooks for verifying 2024-07-02 17:35:01 +02:00
Slowlydev
dd3ba7e836 feat(github-redirect): save webhook secret into database on redirect 2024-07-02 17:33:02 +02:00
Slowlydev
cb6d8fceb4 chore: add drizzle migrations for github webhook secret 2024-07-02 17:32:21 +02:00
Slowlydev
d8641b7b4e feat: add github webhook secret to admin schema 2024-07-02 17:31:38 +02:00
Mauricio Siu
997a8395b1 feat: add button to view github app 2024-07-02 00:11:40 -06:00
Mauricio Siu
d2420ed6e8 feat(github-webhooks): #186 implement github autodeployment with zero configuration 2024-07-01 23:43:08 -06:00
Mauricio Siu
64ada7020a Merge pull request #185 from Dokploy/canary
v0.3.0
2024-07-01 00:01:16 -06:00
Mauricio Siu
faf24dfa25 chore(version): bump version 2024-06-30 23:53:53 -06:00
Mauricio Siu
6f4bf428c7 Merge pull request #184 from Dokploy/feat/glitchtip
feat: add glitchtip template
2024-06-30 23:53:51 -06:00
Mauricio Siu
a43627d869 feat: add glitchtip template 2024-06-30 23:49:29 -06:00
Mauricio Siu
addd102d39 Merge pull request #180 from Dokploy/feat/templates
Feat/templates
2024-06-30 22:36:15 -06:00
Mauricio Siu
0d85fd0e3c feat: add metabase template 2024-06-30 22:31:23 -06:00
Mauricio Siu
86fc59d850 feat: add minio 2024-06-30 22:12:06 -06:00
Mauricio Siu
3cd3db6828 feat(tempaltes): add meilisearch, phpmyadmin and rocketchat 2024-06-30 21:39:24 -06:00
Mauricio Siu
2c6fd0f52b Merge branch 'canary' into feat/templates 2024-06-30 21:00:08 -06:00
Mauricio Siu
5fb682b58d Merge pull request #182 from DarkPhoenix2704/feat/nocodb-template
feat: nocodb template
2024-06-30 12:39:37 -06:00
DarkPhoenix2704
b77f330222 fix: use defined version 2024-07-01 00:01:16 +05:30
DarkPhoenix2704
f0b8f3eaa0 chore: update version 2024-07-01 00:01:16 +05:30
DarkPhoenix2704
36af22630b feat: nocodb template 2024-07-01 00:01:13 +05:30
Mauricio Siu
2d53a700f6 Merge pull request #175 from ephraimduncan/template/documenso
feat: add documenso as template
2024-06-30 01:20:18 -06:00
Mauricio Siu
00eeffee13 Merge pull request #176 from ephraimduncan/fix/calcom-template
fix: avoid using defined secrets in calcom template
2024-06-30 01:05:18 -06:00
Ephraim Atta-Duncan
7a32698031 fix: use version on image 2024-06-30 07:03:11 +00:00
Ephraim Atta-Duncan
9d834e1a79 fix: use hex instead of base64 for encryption variables 2024-06-30 07:00:29 +00:00
Ephraim Atta-Duncan
91819c2488 fix: use correct env var 2024-06-30 06:55:21 +00:00
Mauricio Siu
f64392469d refactor(compose): change error message 2024-06-30 00:42:00 -06:00
Mauricio Siu
889e72d21e refactor(templates): use port from env variable 2024-06-30 00:34:19 -06:00
Mauricio Siu
86165d1104 refactor(templates): remove comments 2024-06-30 00:33:08 -06:00
Mauricio Siu
54adab16cf feat(templates): add excalidraw 2024-06-30 00:32:14 -06:00
Mauricio Siu
2e3b0ddcde feat(templates): add appsmith 2024-06-30 00:24:16 -06:00
Mauricio Siu
ed0f3cadd6 feat(templates): add odoo template 2024-06-29 23:38:47 -06:00
Mauricio Siu
898880634a feat(template): add wordpress 2024-06-29 19:56:59 -06:00
Mauricio Siu
b4e154fb28 Merge pull request #177 from ephraimduncan/fix/template-dialog-background
fix: avoid black background on light theme
2024-06-29 19:39:48 -06:00
Mauricio Siu
2e6489d315 Merge pull request #178 from ephraimduncan/chore/remove-row-selection-count
chore: remove row selection count
2024-06-29 19:38:36 -06:00
Mauricio Siu
210fed30a2 feat(templates): add uptime kuma, directus, baserow, ghost, n8n 2024-06-29 19:14:46 -06:00
Ephraim Atta-Duncan
60521c1025 chore: remove row selection count because row selection has been disabled 2024-06-30 00:49:19 +00:00
Ephraim Atta-Duncan
1a496e35c0 fix: avoid black background on light theme 2024-06-30 00:37:20 +00:00
Ephraim Atta-Duncan
f37f98aade fix: avoid using defined secrets in calcom template 2024-06-30 00:33:49 +00:00
Ephraim Atta-Duncan
0eb7b3ecb1 chore: remove obselete version 2024-06-30 00:30:53 +00:00
Ephraim Atta-Duncan
1a7c602861 feat: add documenso as template 2024-06-30 00:28:53 +00:00
87 changed files with 4394 additions and 120 deletions

View File

@@ -11,7 +11,6 @@ import {
} from "@/components/ui/alert-dialog";
import { Button } from "@/components/ui/button";
import { api } from "@/utils/api";
import { useEffect, useState } from "react";
import { toast } from "sonner";
interface Props {
@@ -26,8 +25,6 @@ export const DeployApplication = ({ applicationId }: Props) => {
{ enabled: !!applicationId },
);
const { mutateAsync: markRunning } =
api.application.markRunning.useMutation();
const { mutateAsync: deploy } = api.application.deploy.useMutation();
return (
@@ -48,24 +45,16 @@ export const DeployApplication = ({ applicationId }: Props) => {
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction
onClick={async () => {
await markRunning({
toast.success("Deploying Application....");
await refetch();
await deploy({
applicationId,
})
.then(async () => {
toast.success("Deploying Application....");
}).catch(() => {
toast.error("Error to deploy Application");
});
await refetch();
await deploy({
applicationId,
}).catch(() => {
toast.error("Error to deploy Application");
});
await refetch();
})
.catch((e) => {
toast.error(e.message || "Error to deploy Application");
});
await refetch();
}}
>
Confirm

View File

@@ -25,8 +25,7 @@ export const RedbuildApplication = ({ applicationId }: Props) => {
},
{ enabled: !!applicationId },
);
const { mutateAsync: markRunning } =
api.application.markRunning.useMutation();
const { mutateAsync } = api.application.redeploy.useMutation();
const utils = api.useUtils();
return (
@@ -54,22 +53,14 @@ export const RedbuildApplication = ({ applicationId }: Props) => {
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction
onClick={async () => {
await markRunning({
toast.success("Redeploying Application....");
await mutateAsync({
applicationId,
})
.then(async () => {
await mutateAsync({
await utils.application.one.invalidate({
applicationId,
})
.then(async () => {
await utils.application.one.invalidate({
applicationId,
});
toast.success("Application rebuild succesfully");
})
.catch(() => {
toast.error("Error to rebuild the application");
});
});
})
.catch(() => {
toast.error("Error to rebuild the application");

View File

@@ -9,14 +9,11 @@ import {
import { api } from "@/utils/api";
import { RocketIcon } from "lucide-react";
import React, { useEffect, useState } from "react";
// import { CancelQueues } from "./cancel-queues";
// import { ShowDeployment } from "./show-deployment-compose";
import { StatusTooltip } from "@/components/shared/status-tooltip";
import { DateTooltip } from "@/components/shared/date-tooltip";
import { ShowDeploymentCompose } from "./show-deployment-compose";
import { RefreshTokenCompose } from "./refresh-token-compose";
import { CancelQueuesCompose } from "./cancel-queues-compose";
// import { RefreshToken } from "./refresh-token";//
interface Props {
composeId: string;
@@ -90,6 +87,11 @@ export const ShowDeploymentsCompose = ({ composeId }: Props) => {
<span className="text-sm text-muted-foreground">
{deployment.title}
</span>
{deployment.description && (
<span className="text-sm text-muted-foreground">
{deployment.description}
</span>
)}
</div>
<div className="flex flex-col items-end gap-2">
<div className="text-sm capitalize text-muted-foreground">

View File

@@ -25,7 +25,6 @@ export const DeployCompose = ({ composeId }: Props) => {
{ enabled: !!composeId },
);
const { mutateAsync: markRunning } = api.compose.update.useMutation();
const { mutateAsync: deploy } = api.compose.deploy.useMutation();
return (
@@ -44,25 +43,16 @@ export const DeployCompose = ({ composeId }: Props) => {
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction
onClick={async () => {
await markRunning({
toast.success("Deploying Compose....");
await refetch();
await deploy({
composeId,
composeStatus: "running",
})
.then(async () => {
toast.success("Deploying Compose....");
}).catch(() => {
toast.error("Error to deploy Compose");
});
await refetch();
await deploy({
composeId,
}).catch(() => {
toast.error("Error to deploy Compose");
});
await refetch();
})
.catch((e) => {
toast.error(e.message || "Error to deploy Compose");
});
await refetch();
}}
>
Confirm

View File

@@ -25,7 +25,6 @@ export const RedbuildCompose = ({ composeId }: Props) => {
},
{ enabled: !!composeId },
);
const { mutateAsync: markRunning } = api.compose.update.useMutation();
const { mutateAsync } = api.compose.redeploy.useMutation();
const utils = api.useUtils();
return (
@@ -53,23 +52,14 @@ export const RedbuildCompose = ({ composeId }: Props) => {
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction
onClick={async () => {
await markRunning({
toast.success("Redeploying Compose....");
await mutateAsync({
composeId,
composeStatus: "running",
})
.then(async () => {
await mutateAsync({
await utils.compose.one.invalidate({
composeId,
})
.then(async () => {
await utils.compose.one.invalidate({
composeId,
});
toast.success("Compose rebuild succesfully");
})
.catch(() => {
toast.error("Error to rebuild the compose");
});
});
})
.catch(() => {
toast.error("Error to rebuild the compose");

View File

@@ -25,7 +25,6 @@ export const StopCompose = ({ composeId }: Props) => {
},
{ enabled: !!composeId },
);
const { mutateAsync: markRunning } = api.compose.update.useMutation();
const { mutateAsync, isLoading } = api.compose.stop.useMutation();
const utils = api.useUtils();
return (
@@ -47,26 +46,17 @@ export const StopCompose = ({ composeId }: Props) => {
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction
onClick={async () => {
await markRunning({
await mutateAsync({
composeId,
composeStatus: "running",
})
.then(async () => {
await mutateAsync({
await utils.compose.one.invalidate({
composeId,
})
.then(async () => {
await utils.compose.one.invalidate({
composeId,
});
toast.success("Compose rebuild succesfully");
})
.catch(() => {
toast.error("Error to rebuild the compose");
});
});
toast.success("Compose stopped succesfully");
})
.catch(() => {
toast.error("Error to rebuild the compose");
toast.error("Error to stop the compose");
});
}}
>

View File

@@ -161,10 +161,6 @@ export const ShowContainers = () => {
</Table>
</div>
<div className="flex items-center justify-end space-x-2 py-4">
<div className="flex-1 text-sm text-muted-foreground">
{table.getFilteredSelectedRowModel().rows.length} of{" "}
{table.getFilteredRowModel().rows.length} row(s) selected.
</div>
<div className="space-x-2 flex flex-wrap">
<Button
variant="outline"

View File

@@ -54,7 +54,7 @@ export const AddTemplate = ({ projectId }: Props) => {
</DropdownMenuItem>
</DialogTrigger>
<DialogContent className="max-h-screen overflow-y-auto sm:max-w-7xl p-0">
<div className="sticky top-0 z-10 flex flex-col gap-4 bg-black p-6 border-b">
<div className="sticky top-0 z-10 flex flex-col gap-4 bg-background p-6 border-b">
<DialogHeader>
<DialogTitle>Create Template</DialogTitle>
<DialogDescription>

View File

@@ -48,6 +48,7 @@ export const GithubSetup = () => {
const [organizationName, setOrganization] = useState<string>("");
const { data } = api.admin.one.useQuery();
useEffect(() => {
const url = document.location.origin;
const manifest = JSON.stringify(
{
redirect_url: `${origin}/api/redirect?authId=${data?.authId}`,
@@ -55,7 +56,7 @@ export const GithubSetup = () => {
url: origin,
hook_attributes: {
// JUST FOR TESTING
url: "https://webhook.site/b6a167c0-ceb5-4f0c-a257-97c0fd163977",
url: `${url}/api/deploy/github`,
// url: `${origin}/api/webhook`, // Aquí especificas la URL del endpoint de tu webhook
},
callback_urls: [`${origin}/api/redirect`], // Los URLs de callback para procesos de autenticación
@@ -92,8 +93,18 @@ export const GithubSetup = () => {
</span>
<BadgeCheck className="size-4 text-green-700" />
</div>
<div className="flex items-end">
<div className="flex items-end gap-4 flex-wrap">
<RemoveGithubApp />
{/* <Link
href={`https://github.com/settings/apps/${data?.githubAppName}`}
target="_blank"
className={buttonVariants({
className: "w-fit",
variant: "secondary",
})}
>
<span className="text-sm">Manage Github App</span>
</Link> */}
</div>
</div>
) : (

View File

@@ -13,6 +13,13 @@ import {
} from "@/components/ui/alert-dialog";
import { Button } from "@/components/ui/button";
import { toast } from "sonner";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
TooltipProvider,
} from "@/components/ui/tooltip";
import { InfoIcon } from "lucide-react";
export const RemoveGithubApp = () => {
const { refetch } = api.auth.get.useQuery();
@@ -22,7 +29,20 @@ export const RemoveGithubApp = () => {
return (
<AlertDialog>
<AlertDialogTrigger asChild>
<Button variant="destructive">Remove Current Github App</Button>
<Button variant="destructive">
Remove Current Github App
<TooltipProvider delayDuration={0}>
<Tooltip>
<TooltipTrigger asChild>
<InfoIcon className="size-4 fill-muted-destructive text-muted-destructive" />
</TooltipTrigger>
<TooltipContent>
We recommend deleting the GitHub app first, and then removing
the current one from here.
</TooltipContent>
</Tooltip>
</TooltipProvider>
</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>

View File

@@ -0,0 +1 @@
ALTER TABLE "admin" ADD COLUMN "githubWebhookSecret" text;

File diff suppressed because it is too large Load Diff

View File

@@ -127,6 +127,13 @@
"when": 1719547174326,
"tag": "0017_minor_post",
"breakpoints": true
},
{
"idx": 18,
"version": "6",
"when": 1719928377858,
"tag": "0018_careful_killmonger",
"breakpoints": true
}
]
}

View File

@@ -1,8 +1,8 @@
{
"name": "dokploy",
"version": "v0.2.5",
"version": "v0.3.1",
"private": true,
"license": "AGPL-3.0-only",
"license": "Apache-2.0",
"type": "module",
"scripts": {
"build": "npm run build-server && npm run build-next",
@@ -19,7 +19,7 @@
"migration:drop": "drizzle-kit drop --config ./server/db/drizzle.config.ts",
"db:push": "drizzle-kit --config ./server/db/drizzle.config.ts",
"db:truncate": "tsx -r dotenv/config ./server/db/reset.ts",
"db:studio": "drizzle-kit studio",
"db:studio": "drizzle-kit studio --config ./server/db/drizzle.config.ts",
"lint": "biome lint",
"db:seed": "tsx -r dotenv/config ./server/db/seed.ts",
"db:clean": "tsx -r dotenv/config ./server/db/reset.ts",
@@ -36,10 +36,12 @@
"@codemirror/lang-yaml": "^6.1.1",
"@codemirror/language": "^6.10.1",
"@codemirror/legacy-modes": "6.4.0",
"@dokploy/trpc-openapi": "0.0.4",
"@faker-js/faker": "^8.4.1",
"@hookform/resolvers": "^3.3.4",
"@lucia-auth/adapter-drizzle": "1.0.7",
"@octokit/auth-app": "^6.0.4",
"@octokit/webhooks": "^13.2.7",
"@radix-ui/react-accordion": "1.1.2",
"@radix-ui/react-alert-dialog": "^1.0.5",
"@radix-ui/react-avatar": "^1.0.4",
@@ -113,7 +115,6 @@
"tailwind-merge": "^2.2.0",
"tailwindcss-animate": "^1.0.7",
"tar-fs": "3.0.5",
"@dokploy/trpc-openapi": "0.0.4",
"use-resize-observer": "9.1.0",
"ws": "8.16.0",
"xterm-addon-fit": "^0.8.0",

View File

@@ -1,4 +1,3 @@
import { updateApplicationStatus } from "@/server/api/services/application";
import { db } from "@/server/db";
import { applications } from "@/server/db/schema";
import type { DeploymentJob } from "@/server/queues/deployments-queue";
@@ -68,11 +67,6 @@ export default async function handler(
}
try {
await updateApplicationStatus(
application.applicationId as string,
"running",
);
const jobData: DeploymentJob = {
applicationId: application.applicationId as string,
titleLog: deploymentTitle,

View File

@@ -9,7 +9,6 @@ import {
extractCommitMessage,
extractHash,
} from "../[refreshToken]";
import { updateCompose } from "@/server/api/services/compose";
export default async function handler(
req: NextApiRequest,
@@ -56,10 +55,6 @@ export default async function handler(
}
try {
await updateCompose(composeResult.composeId, {
composeStatus: "running",
});
const jobData: DeploymentJob = {
composeId: composeResult.composeId as string,
titleLog: deploymentTitle,

126
pages/api/deploy/github.ts Normal file
View File

@@ -0,0 +1,126 @@
import { and, eq } from "drizzle-orm";
import { db } from "@/server/db";
import { Webhooks } from "@octokit/webhooks";
import type { NextApiRequest, NextApiResponse } from "next";
import { applications, compose } from "@/server/db/schema";
import { extractCommitMessage, extractHash } from "./[refreshToken]";
import type { DeploymentJob } from "@/server/queues/deployments-queue";
import { myQueue } from "@/server/queues/queueSetup";
import { findAdmin } from "@/server/api/services/admin";
export default async function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
const admin = await findAdmin();
if (!admin) {
res.status(200).json({ message: "Could not find admin" });
return;
}
if (!admin.githubWebhookSecret) {
res.status(200).json({ message: "Github Webhook Secret not set" });
return;
}
const webhooks = new Webhooks({
secret: admin.githubWebhookSecret,
});
const signature = req.headers["x-hub-signature-256"];
const github = req.body;
const verified = await webhooks.verify(
JSON.stringify(github),
signature as string,
);
if (!verified) {
res.status(401).json({ message: "Unauthorized" });
return;
}
if (req.headers["x-github-event"] === "ping") {
res.status(200).json({ message: "Ping received, webhook is active" });
return;
}
if (req.headers["x-github-event"] !== "push") {
res.status(400).json({ message: "We only accept push events" });
return;
}
try {
const branchName = github?.ref?.replace("refs/heads/", "");
const repository = github?.repository?.name;
const deploymentTitle = extractCommitMessage(req.headers, req.body);
const deploymentHash = extractHash(req.headers, req.body);
const apps = await db.query.applications.findMany({
where: and(
eq(applications.sourceType, "github"),
eq(applications.autoDeploy, true),
eq(applications.branch, branchName),
eq(applications.repository, repository),
),
});
for (const app of apps) {
const jobData: DeploymentJob = {
applicationId: app.applicationId as string,
titleLog: deploymentTitle,
descriptionLog: `Hash: ${deploymentHash}`,
type: "deploy",
applicationType: "application",
};
await myQueue.add(
"deployments",
{ ...jobData },
{
removeOnComplete: true,
removeOnFail: true,
},
);
}
const composeApps = await db.query.compose.findMany({
where: and(
eq(compose.sourceType, "github"),
eq(compose.autoDeploy, true),
eq(compose.branch, branchName),
eq(compose.repository, repository),
),
});
for (const composeApp of composeApps) {
const jobData: DeploymentJob = {
composeId: composeApp.composeId as string,
titleLog: deploymentTitle,
type: "deploy",
applicationType: "compose",
descriptionLog: `Hash: ${deploymentHash}`,
};
await myQueue.add(
"deployments",
{ ...jobData },
{
removeOnComplete: true,
removeOnFail: true,
},
);
}
const totalApps = apps.length + composeApps.length;
const emptyApps = totalApps === 0;
if (emptyApps) {
res.status(200).json({ message: "No apps to deploy" });
return;
}
res.status(200).json({ message: `Deployed ${totalApps} apps` });
} catch (error) {
res.status(400).json({ message: "Error To Deploy Application", error });
}
}

View File

@@ -38,6 +38,7 @@ export default async function handler(
githubAppName: data.name,
githubClientId: data.client_id,
githubClientSecret: data.client_secret,
githubWebhookSecret: data.webhook_secret,
githubPrivateKey: data.pem,
})
.where(eq(admins.authId, authId as string))

54
pnpm-lock.yaml generated
View File

@@ -35,6 +35,9 @@ dependencies:
'@octokit/auth-app':
specifier: ^6.0.4
version: 6.0.4
'@octokit/webhooks':
specifier: ^13.2.7
version: 13.2.7
'@radix-ui/react-accordion':
specifier: 1.1.2
version: 1.1.2(@types/react-dom@18.2.22)(@types/react@18.2.66)(react-dom@18.2.0)(react@18.2.0)
@@ -2604,6 +2607,14 @@ packages:
resolution: {integrity: sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==}
dev: false
/@octokit/openapi-types@22.2.0:
resolution: {integrity: sha512-QBhVjcUa9W7Wwhm6DBFu6ZZ+1/t/oYxqc2tp81Pi41YNuJinbFRx8B133qVOrAaBbF7D/m0Et6f9/pZt9Rc+tg==}
dev: false
/@octokit/openapi-webhooks-types@8.2.1:
resolution: {integrity: sha512-msAU1oTSm0ZmvAE0xDemuF4tVs5i0xNnNGtNmr4EuATi+1Rn8cZDetj6NXioSf5LwnxEc209COa/WOSbjuhLUA==}
dev: false
/@octokit/plugin-paginate-graphql@4.0.1(@octokit/core@5.1.0):
resolution: {integrity: sha512-R8ZQNmrIKKpHWC6V2gum4x9LG2qF1RxRjo27gjQcG3j+vf2tLsEfE7I/wRWEPzYMaenr1M+qDAtNcwZve1ce1A==}
engines: {node: '>= 18'}
@@ -2665,6 +2676,13 @@ packages:
once: 1.4.0
dev: false
/@octokit/request-error@6.1.1:
resolution: {integrity: sha512-1mw1gqT3fR/WFvnoVpY/zUM2o/XkMs/2AszUUG9I69xn0JFLv6PGkPhNk5lbfvROs79wiS0bqiJNxfCZcRJJdg==}
engines: {node: '>= 18'}
dependencies:
'@octokit/types': 13.5.0
dev: false
/@octokit/request@8.2.0:
resolution: {integrity: sha512-exPif6x5uwLqv1N1irkLG1zZNJkOtj8bZxuVHd71U5Ftuxf2wGNvAJyNBcPbPC+EBzwYEbBDdSFb8EPcjpYxPQ==}
engines: {node: '>= 18'}
@@ -2681,11 +2699,22 @@ packages:
'@octokit/openapi-types': 20.0.0
dev: false
/@octokit/types@13.5.0:
resolution: {integrity: sha512-HdqWTf5Z3qwDVlzCrP8UJquMwunpDiMPt5er+QjGzL4hqr/vBVY/MauQgS1xWxCDT1oMx1EULyqxncdCY/NVSQ==}
dependencies:
'@octokit/openapi-types': 22.2.0
dev: false
/@octokit/webhooks-methods@4.1.0:
resolution: {integrity: sha512-zoQyKw8h9STNPqtm28UGOYFE7O6D4Il8VJwhAtMHFt2C4L0VQT1qGKLeefUOqHNs1mNRYSadVv7x0z8U2yyeWQ==}
engines: {node: '>= 18'}
dev: false
/@octokit/webhooks-methods@5.1.0:
resolution: {integrity: sha512-yFZa3UH11VIxYnnoOYCVoJ3q4ChuSOk2IVBBQ0O3xtKX4x9bmKb/1t+Mxixv2iUhzMdOl1qeWJqEhouXXzB3rQ==}
engines: {node: '>= 18'}
dev: false
/@octokit/webhooks-types@7.3.2:
resolution: {integrity: sha512-JWOoOgtWTFnTSAamPXXyjTY5/apttvNxF+vPBnwdSu5cj5snrd7FO0fyw4+wTXy8fHduq626JjhO+TwCyyA6vA==}
dev: false
@@ -2700,6 +2729,16 @@ packages:
aggregate-error: 3.1.0
dev: false
/@octokit/webhooks@13.2.7:
resolution: {integrity: sha512-sPHCyi9uZuCs1gg0yF53FFocM+GsiiBEhQQV/itGzzQ8gjyv2GMJ1YvgdDY4lC0ePZeiV3juEw4GbS6w1VHhRw==}
engines: {node: '>= 18'}
dependencies:
'@octokit/openapi-webhooks-types': 8.2.1
'@octokit/request-error': 6.1.1
'@octokit/webhooks-methods': 5.1.0
aggregate-error: 5.0.0
dev: false
/@pkgjs/parseargs@0.11.0:
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
engines: {node: '>=14'}
@@ -5566,6 +5605,14 @@ packages:
indent-string: 5.0.0
dev: false
/aggregate-error@5.0.0:
resolution: {integrity: sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw==}
engines: {node: '>=18'}
dependencies:
clean-stack: 5.2.0
indent-string: 5.0.0
dev: false
/ajv-formats@2.1.1(ajv@8.14.0):
resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==}
peerDependencies:
@@ -6072,6 +6119,13 @@ packages:
escape-string-regexp: 5.0.0
dev: false
/clean-stack@5.2.0:
resolution: {integrity: sha512-TyUIUJgdFnCISzG5zu3291TAsE77ddchd0bepon1VVQrKLGKFED4iXFEDQ24mIPdPBbyE16PK3F8MYE1CmcBEQ==}
engines: {node: '>=14.16'}
dependencies:
escape-string-regexp: 5.0.0
dev: false
/cli-boxes@3.0.0:
resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==}
engines: {node: '>=10'}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
public/templates/ghost.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 142.5 145.6" style="enable-background:new 0 0 142.5 145.6;" xml:space="preserve">
<style type="text/css">
.st0{fill:#565656;}
.st1{fill:url(#SVGID_1_);}
</style>
<g>
<path class="st0" d="M28.7,131.5c-0.3,7.9-6.6,14.1-14.4,14.1C6.1,145.6,0,139,0,130.9s6.6-14.7,14.7-14.7c3.6,0,7.2,1.6,10.2,4.4
l-2.3,2.9c-2.3-2-5.1-3.4-7.9-3.4c-5.9,0-10.8,4.8-10.8,10.8c0,6.1,4.6,10.8,10.4,10.8c5.2,0,9.3-3.8,10.2-8.8H12.6v-3.5h16.1
V131.5z"/>
<path class="st0" d="M42.3,129.5h-2.2c-2.4,0-4.4,2-4.4,4.4v11.4h-3.9v-19.6H35v1.6c1.1-1.1,2.7-1.6,4.6-1.6h4.2L42.3,129.5z"/>
<path class="st0" d="M63.7,145.3h-3.4v-2.5c-2.6,2.5-6.6,3.7-10.7,1.9c-3-1.3-5.3-4.1-5.9-7.4c-1.2-6.3,3.7-11.9,9.9-11.9
c2.6,0,5,1.1,6.7,2.8v-2.5h3.4V145.3z M59.7,137c0.9-4-2.1-7.6-6-7.6c-3.4,0-6.1,2.8-6.1,6.1c0,3.8,3.3,6.7,7.2,6.1
C57.1,141.2,59.1,139.3,59.7,137z"/>
<path class="st0" d="M71.5,124.7v1.1h6.2v3.4h-6.2v16.1h-3.8v-20.5c0-4.3,3.1-6.8,7-6.8h4.7l-1.6,3.7h-3.1
C72.9,121.6,71.5,123,71.5,124.7z"/>
<path class="st0" d="M98.5,145.3h-3.3v-2.5c-2.6,2.5-6.6,3.7-10.7,1.9c-3-1.3-5.3-4.1-5.9-7.4c-1.2-6.3,3.7-11.9,9.9-11.9
c2.6,0,5,1.1,6.7,2.8v-2.5h3.4v19.6H98.5z M94.5,137c0.9-4-2.1-7.6-6-7.6c-3.4,0-6.1,2.8-6.1,6.1c0,3.8,3.3,6.7,7.2,6.1
C92,141.2,93.9,139.3,94.5,137z"/>
<path class="st0" d="M119.4,133.8v11.5h-3.9v-11.6c0-2.4-2-4.4-4.4-4.4c-2.5,0-4.4,2-4.4,4.4v11.6h-3.9v-19.6h3.2v1.7
c1.4-1.3,3.3-2,5.2-2C115.8,125.5,119.4,129.2,119.4,133.8z"/>
<path class="st0" d="M142.4,145.3h-3.3v-2.5c-2.6,2.5-6.6,3.7-10.7,1.9c-3-1.3-5.3-4.1-5.9-7.4c-1.2-6.3,3.7-11.9,9.9-11.9
c2.6,0,5,1.1,6.7,2.8v-2.5h3.4v19.6H142.4z M138.4,137c0.9-4-2.1-7.6-6-7.6c-3.4,0-6.1,2.8-6.1,6.1c0,3.8,3.3,6.7,7.2,6.1
C135.9,141.2,137.8,139.3,138.4,137z"/>
</g>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="71.25" y1="10.4893" x2="71.25" y2="113.3415" gradientTransform="matrix(1 0 0 -1 0 148.6)">
<stop offset="0" style="stop-color:#FCEE1F"/>
<stop offset="1" style="stop-color:#F15B2A"/>
</linearGradient>
<path class="st1" d="M122.9,49.9c-0.2-1.9-0.5-4.1-1.1-6.5c-0.6-2.4-1.6-5-2.9-7.8c-1.4-2.7-3.1-5.6-5.4-8.3
c-0.9-1.1-1.9-2.1-2.9-3.2c1.6-6.3-1.9-11.8-1.9-11.8c-6.1-0.4-9.9,1.9-11.3,2.9c-0.2-0.1-0.5-0.2-0.7-0.3c-1-0.4-2.1-0.8-3.2-1.2
c-1.1-0.3-2.2-0.7-3.3-0.9c-1.1-0.3-2.3-0.5-3.5-0.7c-0.2,0-0.4-0.1-0.6-0.1C83.5,3.6,75.9,0,75.9,0c-8.7,5.6-10.4,13.1-10.4,13.1
s0,0.2-0.1,0.4c-0.5,0.1-0.9,0.3-1.4,0.4c-0.6,0.2-1.3,0.4-1.9,0.7c-0.6,0.3-1.3,0.5-1.9,0.8c-1.3,0.6-2.5,1.2-3.8,1.9
c-1.2,0.7-2.4,1.4-3.5,2.2c-0.2-0.1-0.3-0.2-0.3-0.2c-11.7-4.5-22.1,0.9-22.1,0.9c-0.9,12.5,4.7,20.3,5.8,21.7
c-0.3,0.8-0.5,1.5-0.8,2.3c-0.9,2.8-1.5,5.7-1.9,8.7c-0.1,0.4-0.1,0.9-0.2,1.3c-10.8,5.3-14,16.3-14,16.3c9,10.4,19.6,11,19.6,11
l0,0c1.3,2.4,2.9,4.7,4.6,6.8c0.7,0.9,1.5,1.7,2.3,2.6c-3.3,9.4,0.5,17.3,0.5,17.3c10.1,0.4,16.7-4.4,18.1-5.5c1,0.3,2,0.6,3,0.9
c3.1,0.8,6.3,1.3,9.4,1.4c0.8,0,1.6,0,2.4,0h0.4H80h0.5H81l0,0c4.7,6.8,13.1,7.7,13.1,7.7c5.9-6.3,6.3-12.4,6.3-13.8l0,0
c0,0,0,0,0-0.1s0-0.2,0-0.2l0,0c0-0.1,0-0.2,0-0.3c1.2-0.9,2.4-1.8,3.6-2.8c2.4-2.1,4.4-4.6,6.2-7.2c0.2-0.2,0.3-0.5,0.5-0.7
c6.7,0.4,11.4-4.2,11.4-4.2c-1.1-7-5.1-10.4-5.9-11l0,0c0,0,0,0-0.1-0.1l-0.1-0.1l0,0l-0.1-0.1c0-0.4,0.1-0.8,0.1-1.3
c0.1-0.8,0.1-1.5,0.1-2.3v-0.6v-0.3v-0.1c0-0.2,0-0.1,0-0.2v-0.5v-0.6c0-0.2,0-0.4,0-0.6s0-0.4-0.1-0.6l-0.1-0.6l-0.1-0.6
c-0.1-0.8-0.3-1.5-0.4-2.3c-0.7-3-1.9-5.9-3.4-8.4c-1.6-2.6-3.5-4.8-5.7-6.8c-2.2-1.9-4.6-3.5-7.2-4.6c-2.6-1.2-5.2-1.9-7.9-2.2
c-1.3-0.2-2.7-0.2-4-0.2h-0.5h-0.1h-0.2h-0.2h-0.5c-0.2,0-0.4,0-0.5,0c-0.7,0.1-1.4,0.2-2,0.3c-2.7,0.5-5.2,1.5-7.4,2.8
c-2.2,1.3-4.1,3-5.7,4.9s-2.8,3.9-3.6,6.1c-0.8,2.1-1.3,4.4-1.4,6.5c0,0.5,0,1.1,0,1.6c0,0.1,0,0.3,0,0.4v0.4c0,0.3,0,0.5,0.1,0.8
c0.1,1.1,0.3,2.1,0.6,3.1c0.6,2,1.5,3.8,2.7,5.4s2.5,2.8,4,3.8s3,1.7,4.6,2.2c1.6,0.5,3.1,0.7,4.5,0.6c0.2,0,0.4,0,0.5,0
c0.1,0,0.2,0,0.3,0s0.2,0,0.3,0c0.2,0,0.3,0,0.5,0h0.1h0.1c0.1,0,0.2,0,0.3,0c0.2,0,0.4-0.1,0.5-0.1c0.2,0,0.3-0.1,0.5-0.1
c0.3-0.1,0.7-0.2,1-0.3c0.6-0.2,1.2-0.5,1.8-0.7c0.6-0.3,1.1-0.6,1.5-0.9c0.1-0.1,0.3-0.2,0.4-0.3c0.5-0.4,0.6-1.1,0.2-1.6
c-0.4-0.4-1-0.5-1.5-0.3C88,74,87.9,74,87.7,74.1c-0.4,0.2-0.9,0.4-1.3,0.5c-0.5,0.1-1,0.3-1.5,0.4c-0.3,0-0.5,0.1-0.8,0.1
c-0.1,0-0.3,0-0.4,0c-0.1,0-0.3,0-0.4,0s-0.3,0-0.4,0c-0.2,0-0.3,0-0.5,0c0,0-0.1,0,0,0h-0.1h-0.1c-0.1,0-0.1,0-0.2,0
s-0.3,0-0.4-0.1c-1.1-0.2-2.3-0.5-3.4-1c-1.1-0.5-2.2-1.2-3.1-2.1c-1-0.9-1.8-1.9-2.5-3.1c-0.7-1.2-1.1-2.5-1.3-3.8
c-0.1-0.7-0.2-1.4-0.1-2.1c0-0.2,0-0.4,0-0.6c0,0.1,0,0,0,0v-0.1v-0.1c0-0.1,0-0.2,0-0.3c0-0.4,0.1-0.7,0.2-1.1c0.5-3,2-5.9,4.3-8.1
c0.6-0.6,1.2-1.1,1.9-1.5c0.7-0.5,1.4-0.9,2.1-1.2c0.7-0.3,1.5-0.6,2.3-0.8s1.6-0.4,2.4-0.4c0.4,0,0.8-0.1,1.2-0.1
c0.1,0,0.2,0,0.3,0h0.3h0.2c0.1,0,0,0,0,0h0.1h0.3c0.9,0.1,1.8,0.2,2.6,0.4c1.7,0.4,3.4,1,5,1.9c3.2,1.8,5.9,4.5,7.5,7.8
c0.8,1.6,1.4,3.4,1.7,5.3c0.1,0.5,0.1,0.9,0.2,1.4v0.3V66c0,0.1,0,0.2,0,0.3c0,0.1,0,0.2,0,0.3v0.3v0.3c0,0.2,0,0.6,0,0.8
c0,0.5-0.1,1-0.1,1.5c-0.1,0.5-0.1,1-0.2,1.5s-0.2,1-0.3,1.5c-0.2,1-0.6,1.9-0.9,2.9c-0.7,1.9-1.7,3.7-2.9,5.3
c-2.4,3.3-5.7,6-9.4,7.7c-1.9,0.8-3.8,1.5-5.8,1.8c-1,0.2-2,0.3-3,0.3H81h-0.2h-0.3H80h-0.3c0.1,0,0,0,0,0h-0.1
c-0.5,0-1.1,0-1.6-0.1c-2.2-0.2-4.3-0.6-6.4-1.2c-2.1-0.6-4.1-1.4-6-2.4c-3.8-2-7.2-4.9-9.9-8.2c-1.3-1.7-2.5-3.5-3.5-5.4
s-1.7-3.9-2.3-5.9c-0.6-2-0.9-4.1-1-6.2v-0.4v-0.1v-0.1v-0.2V60v-0.1v-0.1v-0.2v-0.5V59l0,0v-0.2c0-0.3,0-0.5,0-0.8
c0-1,0.1-2.1,0.3-3.2c0.1-1.1,0.3-2.1,0.5-3.2c0.2-1.1,0.5-2.1,0.8-3.2c0.6-2.1,1.3-4.1,2.2-6c1.8-3.8,4.1-7.2,6.8-9.9
c0.7-0.7,1.4-1.3,2.2-1.9c0.3-0.3,1-0.9,1.8-1.4c0.8-0.5,1.6-1,2.5-1.4c0.4-0.2,0.8-0.4,1.3-0.6c0.2-0.1,0.4-0.2,0.7-0.3
c0.2-0.1,0.4-0.2,0.7-0.3c0.9-0.4,1.8-0.7,2.7-1c0.2-0.1,0.5-0.1,0.7-0.2c0.2-0.1,0.5-0.1,0.7-0.2c0.5-0.1,0.9-0.2,1.4-0.4
c0.2-0.1,0.5-0.1,0.7-0.2c0.2,0,0.5-0.1,0.7-0.1c0.2,0,0.5-0.1,0.7-0.1l0.4-0.1l0.4-0.1c0.2,0,0.5-0.1,0.7-0.1
c0.3,0,0.5-0.1,0.8-0.1c0.2,0,0.6-0.1,0.8-0.1c0.2,0,0.3,0,0.5-0.1h0.3h0.2h0.2c0.3,0,0.5,0,0.8-0.1h0.4c0,0,0.1,0,0,0h0.1h0.2
c0.2,0,0.5,0,0.7,0c0.9,0,1.8,0,2.7,0c1.8,0.1,3.6,0.3,5.3,0.6c3.4,0.6,6.7,1.7,9.6,3.2c2.9,1.4,5.6,3.2,7.8,5.1
c0.1,0.1,0.3,0.2,0.4,0.4c0.1,0.1,0.3,0.2,0.4,0.4c0.3,0.2,0.5,0.5,0.8,0.7c0.3,0.2,0.5,0.5,0.8,0.7c0.2,0.3,0.5,0.5,0.7,0.8
c1,1,1.9,2.1,2.7,3.1c1.6,2.1,2.9,4.2,3.9,6.2c0.1,0.1,0.1,0.2,0.2,0.4c0.1,0.1,0.1,0.2,0.2,0.4s0.2,0.5,0.4,0.7
c0.1,0.2,0.2,0.5,0.3,0.7c0.1,0.2,0.2,0.5,0.3,0.7c0.4,0.9,0.7,1.8,1,2.7c0.5,1.4,0.8,2.6,1.1,3.6c0.1,0.4,0.5,0.7,0.9,0.7
c0.5,0,0.8-0.4,0.8-0.9C123,52.7,123,51.4,122.9,49.9z"/>
</svg>

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
public/templates/minio.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
public/templates/n8n.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

BIN
public/templates/nocodb.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

BIN
public/templates/odoo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

View File

@@ -33,8 +33,10 @@ export const createRegistry = async (input: typeof apiCreateRegistry._type) => {
});
}
const loginCommand = `echo ${input.password} | docker login ${input.registryUrl} --username ${input.username} --password-stdin`;
await execAsync(loginCommand);
if (newRegistry.registryType === "cloud") {
const loginCommand = `echo ${input.password} | docker login ${input.registryUrl} --username ${input.username} --password-stdin`;
await execAsync(loginCommand);
}
return newRegistry;
});

View File

@@ -23,6 +23,7 @@ export const admins = pgTable("admin", {
githubClientSecret: text("githubClientSecret"),
githubInstallationId: text("githubInstallationId"),
githubPrivateKey: text("githubPrivateKey"),
githubWebhookSecret: text("githubWebhookSecret"),
letsEncryptEmail: text("letsEncryptEmail"),
sshPrivateKey: text("sshPrivateKey"),
enableDockerCleanup: boolean("enableDockerCleanup").notNull().default(false),

View File

@@ -2,9 +2,14 @@ import { type Job, Worker } from "bullmq";
import {
deployApplication,
rebuildApplication,
updateApplicationStatus,
} from "../api/services/application";
import { myQueue, redisConfig } from "./queueSetup";
import { deployCompose, rebuildCompose } from "../api/services/compose";
import {
deployCompose,
rebuildCompose,
updateCompose,
} from "../api/services/compose";
type DeployJob =
| {
@@ -29,6 +34,7 @@ export const deploymentWorker = new Worker(
async (job: Job<DeploymentJob>) => {
try {
if (job.data.applicationType === "application") {
await updateApplicationStatus(job.data.applicationId, "running");
if (job.data.type === "redeploy") {
await rebuildApplication({
applicationId: job.data.applicationId,
@@ -43,6 +49,9 @@ export const deploymentWorker = new Worker(
});
}
} else if (job.data.applicationType === "compose") {
await updateCompose(job.data.composeId, {
composeStatus: "running",
});
if (job.data.type === "deploy") {
await deployCompose({
composeId: job.data.composeId,

View File

@@ -64,8 +64,8 @@ export const containerExists = async (containerName: string) => {
export const stopService = async (appName: string) => {
try {
await execAsync(`docker service scale ${appName}=0 `);
console.log("Service stopped ✅");
} catch (error) {
console.error(error);
return error;
}
};
@@ -93,6 +93,7 @@ export const cleanUpUnusedImages = async () => {
try {
await execAsync("docker image prune --all --force");
} catch (error) {
console.error(error);
throw error;
}
};
@@ -101,6 +102,7 @@ export const cleanStoppedContainers = async () => {
try {
await execAsync("docker container prune --force");
} catch (error) {
console.error(error);
throw error;
}
};
@@ -109,6 +111,7 @@ export const cleanUpUnusedVolumes = async () => {
try {
await execAsync("docker volume prune --force");
} catch (error) {
console.error(error);
throw error;
}
};
@@ -142,6 +145,7 @@ export const startService = async (appName: string) => {
try {
await execAsync(`docker service scale ${appName}=1 `);
} catch (error) {
console.error(error);
throw error;
}
};

View File

@@ -87,7 +87,6 @@ const addHostToKnownHosts = async (repositoryURL: string) => {
throw error;
}
};
const sanitizeRepoPathSSH = (input: string) => {
const SSH_PATH_RE = new RegExp(
[
@@ -113,7 +112,7 @@ const sanitizeRepoPathSSH = (input: string) => {
return {
user: found.groups?.user ?? "git",
domain: found.groups?.domain,
port: Number(found.groups?.port ?? 22),
port: 22,
owner: found.groups?.owner ?? "",
repo: found.groups?.repo,
get repoPath() {

View File

@@ -0,0 +1,18 @@
version: "3.8"
services:
appsmith:
image: index.docker.io/appsmith/appsmith-ee:v1.29
networks:
- dokploy-network
ports:
- ${APP_SMITH_PORT}
labels:
- "traefik.enable=true"
- "traefik.http.routers.${HASH}.rule=Host(`${APP_SMITH_HOST}`)"
- "traefik.http.services.${HASH}.loadbalancer.server.port=${APP_SMITH_PORT}"
volumes:
- ./stacks:/appsmith-stacks
networks:
dokploy-network:
external: true

View File

@@ -0,0 +1,20 @@
import {
generateHash,
generateRandomDomain,
type Template,
type Schema,
} from "../utils";
export function generate(schema: Schema): Template {
const mainServiceHash = generateHash(schema.projectName);
const randomDomain = generateRandomDomain(schema);
const envs = [
`APP_SMITH_HOST=${randomDomain}`,
"APP_SMITH_PORT=80",
`HASH=${mainServiceHash}`,
];
return {
envs,
};
}

View File

@@ -0,0 +1,22 @@
version: "3.8"
services:
baserow:
image: baserow/baserow:1.25.2
networks:
- dokploy-network
environment:
BASEROW_PUBLIC_URL: "http://${BASEROW_HOST}"
ports:
- ${BASEROW_PORT}
labels:
- traefik.enable=true
- traefik.http.routers.${HASH}.rule=Host(`${BASEROW_HOST}`)
- traefik.http.services.${HASH}.loadbalancer.server.port=${BASEROW_PORT}
volumes:
- baserow_data:/baserow/data
volumes:
baserow_data:
networks:
dokploy-network:
external: true

View File

@@ -0,0 +1,20 @@
import {
generateHash,
generateRandomDomain,
type Template,
type Schema,
} from "../utils";
export function generate(schema: Schema): Template {
const mainServiceHash = generateHash(schema.projectName);
const randomDomain = generateRandomDomain(schema);
const envs = [
`BASEROW_HOST=${randomDomain}`,
"BASEROW_PORT=80",
`HASH=${mainServiceHash}`,
];
return {
envs,
};
}

View File

@@ -1,4 +1,3 @@
version: '3.8'
services:
postgres:
image: postgres:16-alpine
@@ -17,8 +16,8 @@ services:
depends_on:
- postgres
environment:
- NEXTAUTH_SECRET=asklmdaklsmdklasmdklasd
- CALENDSO_ENCRYPTION_KEY=asklmdaklsmdklasmdklasd
- NEXTAUTH_SECRET=${NEXTAUTH_SECRET}
- CALENDSO_ENCRYPTION_KEY=${CALENDSO_ENCRYPTION_KEY}
- DATABASE_URL=postgres://postgres:password@postgres:5432/db
- NEXT_PUBLIC_WEBAPP_URL=http://${CALCOM_HOST}
- NEXTAUTH_URL=http://${CALCOM_HOST}/api/auth

View File

@@ -3,16 +3,22 @@ import {
generateRandomDomain,
type Template,
type Schema,
generateBase64,
} from "../utils";
// https://cal.com/
export function generate(schema: Schema): Template {
const mainServiceHash = generateHash(schema.projectName);
const randomDomain = generateRandomDomain(schema);
const calcomEncryptionKey = generateBase64(32);
const nextAuthSecret = generateBase64(32);
const envs = [
`CALCOM_HOST=${randomDomain}`,
"CALCOM_PORT=3000",
`HASH=${mainServiceHash}`,
`NEXTAUTH_SECRET=${nextAuthSecret}`,
`CALENDSO_ENCRYPTION_KEY=${calcomEncryptionKey}`,
];
return {

View File

@@ -0,0 +1,56 @@
version: "3.8"
services:
database:
image: postgis/postgis:13-master
volumes:
- directus:/var/lib/postgresql/data
networks:
- dokploy-network
environment:
POSTGRES_USER: "directus"
POSTGRES_PASSWORD: "directus"
POSTGRES_DB: "directus"
cache:
image: redis:6
networks:
- dokploy-network
directus:
image: directus/directus:10.12.1
networks:
- dokploy-network
ports:
- 8055
volumes:
- ./uploads:/directus/uploads
- ./extensions:/directus/extensions
depends_on:
- cache
- database
labels:
- traefik.enable=true
- traefik.http.routers.${HASH}.rule=Host(`${DIRECTUS_HOST}`)
- traefik.http.services.${HASH}.loadbalancer.server.port=${DIRECTUS_PORT}
environment:
SECRET: "replace-with-secure-random-value"
DB_CLIENT: "pg"
DB_HOST: "database"
DB_PORT: "5432"
DB_DATABASE: "directus"
DB_USER: "directus"
DB_PASSWORD: "directus"
CACHE_ENABLED: "true"
CACHE_AUTO_PURGE: "true"
CACHE_STORE: "redis"
REDIS: "redis://cache:6379"
ADMIN_EMAIL: "admin@example.com"
ADMIN_PASSWORD: "d1r3ctu5"
networks:
dokploy-network:
external: true
volumes:
directus:

View File

@@ -0,0 +1,20 @@
import {
generateHash,
generateRandomDomain,
type Template,
type Schema,
} from "../utils";
export function generate(schema: Schema): Template {
const mainServiceHash = generateHash(schema.projectName);
const randomDomain = generateRandomDomain(schema);
const envs = [
`DIRECTUS_HOST=${randomDomain}`,
"DIRECTUS_PORT=8055",
`HASH=${mainServiceHash}`,
];
return {
envs,
};
}

View File

@@ -0,0 +1,53 @@
version: "3.8"
services:
postgres:
image: postgres:16
networks:
- dokploy-network
volumes:
- documenso-data:/var/lib/postgresql/data
environment:
- POSTGRES_USER=documenso
- POSTGRES_PASSWORD=password
- POSTGRES_DB=documenso
healthcheck:
test: ["CMD-SHELL", "pg_isready -U documenso"]
interval: 10s
timeout: 5s
retries: 5
start_period: 10s
documenso:
image: documenso/documenso:1.5.6-rc.2
networks:
- dokploy-network
depends_on:
postgres:
condition: service_healthy
environment:
- PORT=${DOCUMENSO_PORT}
- NEXTAUTH_URL=http://${DOCUMENSO_HOST}
- NEXTAUTH_SECRET=${NEXTAUTH_SECRET}
- NEXT_PRIVATE_ENCRYPTION_KEY=${NEXT_PRIVATE_ENCRYPTION_KEY}
- NEXT_PRIVATE_ENCRYPTION_SECONDARY_KEY=${NEXT_PRIVATE_ENCRYPTION_SECONDARY_KEY}
- NEXT_PUBLIC_WEBAPP_URL=http://${DOCUMENSO_HOST}
- NEXT_PRIVATE_DATABASE_URL=postgres://documenso:password@postgres:5432/documenso
- NEXT_PRIVATE_DIRECT_DATABASE_URL=postgres://documenso:password@postgres:5432/documenso
- NEXT_PUBLIC_UPLOAD_TRANSPORT=database
- NEXT_PRIVATE_SMTP_TRANSPORT=smtp-auth
- NEXT_PRIVATE_SIGNING_LOCAL_FILE_PATH=/opt/documenso/cert.p12
ports:
- ${DOCUMENSO_PORT}
labels:
- "traefik.enable=true"
- "traefik.http.routers.${HASH}.rule=Host(`${DOCUMENSO_HOST}`)"
- "traefik.http.services.${HASH}.loadbalancer.server.port=${DOCUMENSO_PORT}"
volumes:
- /opt/documenso/cert.p12:/opt/documenso/cert.p12
networks:
dokploy-network:
external: true
volumes:
documenso-data:

View File

@@ -0,0 +1,30 @@
import {
generateHash,
generateRandomDomain,
type Template,
type Schema,
generateBase64,
generatePassword,
} from "../utils";
export function generate(schema: Schema): Template {
const mainServiceHash = generateHash(schema.projectName);
const randomDomain = generateRandomDomain(schema);
const nextAuthSecret = generateBase64(32);
const documensoEncryptionKey = generatePassword(32);
const documensoSecondaryEncryptionKey = generatePassword(64);
const envs = [
`DOCUMENSO_HOST=${randomDomain}`,
"DOCUMENSO_PORT=3000",
`HASH=${mainServiceHash}`,
`NEXTAUTH_SECRET=${nextAuthSecret}`,
`NEXT_PRIVATE_ENCRYPTION_KEY=${documensoEncryptionKey}`,
`NEXT_PRIVATE_ENCRYPTION_SECONDARY_KEY=${documensoSecondaryEncryptionKey}`,
];
return {
envs,
};
}

View File

@@ -0,0 +1,17 @@
version: '3.8'
services:
excalidraw:
networks:
- dokploy-network
image: excalidraw/excalidraw:latest
ports:
- ${EXCALIDRAW_PORT}
labels:
- traefik.enable=true
- traefik.http.routers.${HASH}.rule=Host(`${EXCALIDRAW_HOST}`)
- traefik.http.services.${HASH}.loadbalancer.server.port=${EXCALIDRAW_PORT}
networks:
dokploy-network:
external: true

View File

@@ -0,0 +1,20 @@
import {
generateHash,
generateRandomDomain,
type Template,
type Schema,
} from "../utils";
export function generate(schema: Schema): Template {
const mainServiceHash = generateHash(schema.projectName);
const randomDomain = generateRandomDomain(schema);
const envs = [
`EXCALIDRAW_HOST=${randomDomain}`,
"EXCALIDRAW_PORT=80",
`HASH=${mainServiceHash}`,
];
return {
envs,
};
}

View File

@@ -0,0 +1,41 @@
version: "3.8"
services:
ghost:
image: ghost:5-alpine
restart: always
networks:
- dokploy-network
ports:
- ${GHOST_PORT}
environment:
database__client: mysql
database__connection__host: db
database__connection__user: root
database__connection__password: example
database__connection__database: ghost
url: http://${GHOST_HOST}
labels:
- traefik.enable=true
- traefik.http.routers.${HASH}.rule=Host(`${GHOST_HOST}`)
- traefik.http.services.${HASH}.loadbalancer.server.port=${GHOST_PORT}
volumes:
- ghost:/var/lib/ghost/content
db:
image: mysql:8.0
restart: always
networks:
- dokploy-network
environment:
MYSQL_ROOT_PASSWORD: example
volumes:
- db:/var/lib/mysql
volumes:
ghost:
db:
networks:
dokploy-network:
external: true

20
templates/ghost/index.ts Normal file
View File

@@ -0,0 +1,20 @@
import {
generateHash,
generateRandomDomain,
type Template,
type Schema,
} from "../utils";
export function generate(schema: Schema): Template {
const mainServiceHash = generateHash(schema.projectName);
const randomDomain = generateRandomDomain(schema);
const envs = [
`GHOST_HOST=${randomDomain}`,
"GHOST_PORT=2368",
`HASH=${mainServiceHash}`,
];
return {
envs,
};
}

View File

@@ -0,0 +1,71 @@
x-environment:
&default-environment
DATABASE_URL: postgres://postgres:postgres@postgres:5432/postgres
SECRET_KEY: ${SECRET_KEY}
PORT: ${GLITCHTIP_PORT}
EMAIL_URL: consolemail://
GLITCHTIP_DOMAIN: http://${GLITCHTIP_HOST}
DEFAULT_FROM_EMAIL: email@glitchtip.com
CELERY_WORKER_AUTOSCALE: "1,3"
CELERY_WORKER_MAX_TASKS_PER_CHILD: "10000"
x-depends_on:
&default-depends_on
- postgres
- redis
services:
postgres:
image: postgres:16
environment:
POSTGRES_HOST_AUTH_METHOD: "trust"
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
ports:
- ${GLITCHTIP_PORT}
environment: *default-environment
restart: unless-stopped
volumes:
- uploads:/code/uploads
networks:
- dokploy-network
labels:
- traefik.enable=true
- traefik.http.routers.${HASH}.rule=Host(`${GLITCHTIP_HOST}`)
- traefik.http.services.${HASH}.loadbalancer.server.port=${GLITCHTIP_PORT}
worker:
image: glitchtip/glitchtip:v4.0
command: ./bin/run-celery-with-beat.sh
depends_on: *default-depends_on
environment: *default-environment
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:
uploads:
networks:
dokploy-network:
external: true

View File

@@ -0,0 +1,23 @@
import {
generateHash,
generateRandomDomain,
type Template,
type Schema,
generateBase64,
} from "../utils";
export function generate(schema: Schema): Template {
const mainServiceHash = generateHash(schema.projectName);
const randomDomain = generateRandomDomain(schema);
const secretKey = generateBase64(32);
const envs = [
`GLITCHTIP_HOST=${randomDomain}`,
"GLITCHTIP_PORT=8000",
`SECRET_KEY=${secretKey}`,
`HASH=${mainServiceHash}`,
];
return {
envs,
};
}

View File

@@ -0,0 +1,20 @@
version: "3.8"
services:
grafana:
networks:
- dokploy-network
image: grafana/grafana-enterprise:9.5.20
restart: unless-stopped
ports:
- ${GRAFANA_PORT}
labels:
- traefik.enable=true
- traefik.http.routers.${HASH}.rule=Host(`${GRAFANA_HOST}`)
- traefik.http.services.${HASH}.loadbalancer.server.port=${GRAFANA_PORT}
volumes:
- grafana-storage:/var/lib/grafana
networks:
dokploy-network:
external: true
volumes:
grafana-storage: {}

View File

@@ -0,0 +1,20 @@
import {
generateHash,
generateRandomDomain,
type Template,
type Schema,
} from "../utils";
export function generate(schema: Schema): Template {
const mainServiceHash = generateHash(schema.projectName);
const randomDomain = generateRandomDomain(schema);
const envs = [
`GRAFANA_HOST=${randomDomain}`,
"GRAFANA_PORT=3000",
`HASH=${mainServiceHash}`,
];
return {
envs,
};
}

View File

@@ -0,0 +1,25 @@
version: '3.8'
services:
meilisearch:
networks:
- dokploy-network
image: getmeili/meilisearch:v1.8.3
ports:
- ${MEILISEARCH_PORT}
volumes:
- meili_data:/meili_data
environment:
MEILI_MASTER_KEY: ${MEILI_MASTER_KEY}
MEILI_ENV: ${MEILI_ENV}
labels:
- traefik.enable=true
- traefik.http.routers.${HASH}.rule=Host(`${MEILISEARCH_HOST}`)
- traefik.http.services.${HASH}.loadbalancer.server.port=${MEILISEARCH_PORT}
volumes:
meili_data:
driver: local
networks:
dokploy-network:
external: true

View File

@@ -0,0 +1,24 @@
import {
generateHash,
generateRandomDomain,
type Template,
type Schema,
generateBase64,
} from "../utils";
export function generate(schema: Schema): Template {
const mainServiceHash = generateHash(schema.projectName);
const randomDomain = generateRandomDomain(schema);
const masterKey = generateBase64(32);
const envs = [
`MEILISEARCH_HOST=${randomDomain}`,
"MEILISEARCH_PORT=7700",
"MEILI_ENV=development",
`MEILI_MASTER_KEY=${masterKey}`,
`HASH=${mainServiceHash}`,
];
return {
envs,
};
}

View File

@@ -0,0 +1,38 @@
version: "3.8"
services:
metabase:
image: metabase/metabase:v0.50.8
volumes:
- /dev/urandom:/dev/random:ro
ports:
- ${METABASE_PORT}
environment:
MB_DB_TYPE: postgres
MB_DB_DBNAME: metabaseappdb
MB_DB_PORT: 5432
MB_DB_USER: metabase
MB_DB_PASS: mysecretpassword
MB_DB_HOST: postgres
networks:
- dokploy-network
healthcheck:
test: curl --fail -I http://localhost:3000/api/health || exit 1
interval: 15s
timeout: 5s
retries: 5
labels:
- traefik.enable=true
- traefik.http.routers.${HASH}.rule=Host(`${METABASE_HOST}`)
- traefik.http.services.${HASH}.loadbalancer.server.port=${METABASE_PORT}
postgres:
image: postgres:14
environment:
POSTGRES_USER: metabase
POSTGRES_DB: metabaseappdb
POSTGRES_PASSWORD: mysecretpassword
networks:
- dokploy-network
networks:
dokploy-network:
external: true

View File

@@ -0,0 +1,20 @@
import {
generateHash,
generateRandomDomain,
type Template,
type Schema,
} from "../utils";
export function generate(schema: Schema): Template {
const mainServiceHash = generateHash(schema.projectName);
const randomDomain = generateRandomDomain(schema);
const envs = [
`METABASE_HOST=${randomDomain}`,
"METABASE_PORT=3000",
`HASH=${mainServiceHash}`,
];
return {
envs,
};
}

View File

@@ -0,0 +1,31 @@
version: '3.8'
services:
minio:
image: minio/minio
ports:
- ${MINIO_API_PORT}
- ${MINIO_DASHBOARD_PORT}
volumes:
- minio-data:/data
environment:
- MINIO_ROOT_USER=minioadmin
- MINIO_ROOT_PASSWORD=minioadmin123
command: server /data --console-address ":9001"
networks:
- dokploy-network
labels:
- traefik.enable=true
- traefik.http.routers.${HASH}.service=${HASH}
- traefik.http.routers.${HASH}.rule=Host(`${MINIO_DASHBOARD_HOST}`)
- traefik.http.services.${HASH}.loadbalancer.server.port=${MINIO_DASHBOARD_PORT}
# API router and service
- traefik.http.routers.${HASH}-api.service=${HASH}-api
- traefik.http.routers.${HASH}-api.rule=Host(`${MINIO_API_HOST}`)
- traefik.http.services.${HASH}-api.loadbalancer.server.port=${MINIO_API_PORT}
volumes:
minio-data:
networks:
dokploy-network:
external: true

23
templates/minio/index.ts Normal file
View File

@@ -0,0 +1,23 @@
import {
generateHash,
generateRandomDomain,
type Template,
type Schema,
} from "../utils";
export function generate(schema: Schema): Template {
const mainServiceHash = generateHash(schema.projectName);
const randomDomain = generateRandomDomain(schema);
const apiDomain = generateRandomDomain(schema);
const envs = [
`MINIO_DASHBOARD_HOST=${randomDomain}`,
"MINIO_DASHBOARD_PORT=9001",
`MINIO_API_HOST=${apiDomain}`,
"MINIO_API_PORT=9000",
`HASH=${mainServiceHash}`,
];
return {
envs,
};
}

View File

@@ -0,0 +1,29 @@
version: "3.8"
services:
n8n:
image: docker.n8n.io/n8nio/n8n:1.48.1
restart: always
networks:
- dokploy-network
ports:
- ${N8N_PORT}
labels:
- traefik.enable=true
- traefik.http.routers.${HASH}.rule=Host(`${N8N_HOST}`)
- traefik.http.services.${HASH}.loadbalancer.server.port=${N8N_PORT}
environment:
- N8N_HOST=${N8N_HOST}
- N8N_PORT=5678
- N8N_PROTOCOL=http
- NODE_ENV=production
- WEBHOOK_URL=https://${N8N_HOST}/
- GENERIC_TIMEZONE=${GENERIC_TIMEZONE}
- N8N_SECURE_COOKIE=false
volumes:
- n8n_data:/home/node/.n8n
volumes:
n8n_data:
networks:
dokploy-network:
external: true

21
templates/n8n/index.ts Normal file
View File

@@ -0,0 +1,21 @@
import {
generateHash,
generateRandomDomain,
type Template,
type Schema,
} from "../utils";
export function generate(schema: Schema): Template {
const mainServiceHash = generateHash(schema.projectName);
const randomDomain = generateRandomDomain(schema);
const envs = [
`N8N_HOST=${randomDomain}`,
"N8N_PORT=5678",
`HASH=${mainServiceHash}`,
"GENERIC_TIMEZONE=Europe/Berlin",
];
return {
envs,
};
}

View File

@@ -0,0 +1,44 @@
version: "3.8"
services:
nocodb:
image: nocodb/nocodb:0.251.1
restart: always
networks:
- dokploy-network
ports:
- ${NOCODB_PORT}
environment:
NC_DB : "pg://root_db?u=postgres&p=password&d=root_db"
PORT : ${NOCODB_PORT}
NC_REDIS_URL: ${NC_REDIS_URL}
labels:
- traefik.enable=true
- traefik.http.routers.${HASH}.rule=Host(`${NOCODB_HOST}`)
- traefik.http.services.${HASH}.loadbalancer.server.port=${NOCODB_PORT}
volumes:
- nc_data:/usr/app/data
root_db:
image: postgres:14.7
restart: always
networks:
- dokploy-network
environment:
POSTGRES_DB: root_db
POSTGRES_PASSWORD: password
POSTGRES_USER: postgres
healthcheck:
interval: 10s
retries: 10
test: "pg_isready -U \"$$POSTGRES_USER\" -d \"$$POSTGRES_DB\""
timeout: 2s
volumes:
- "db_data:/var/lib/postgresql/data"
networks:
dokploy-network:
external: true
volumes:
db_data: {}
nc_data: {}

28
templates/nocodb/index.ts Normal file
View File

@@ -0,0 +1,28 @@
// EXAMPLE
import {
generateHash,
generateRandomDomain,
generateBase64,
type Template,
type Schema,
} from "../utils";
export function generate(schema: Schema): Template {
const mainServiceHash = generateHash(schema.projectName);
const randomDomain = generateRandomDomain(schema);
const secretBase = generateBase64(64);
const toptKeyBase = generateBase64(32);
const envs = [
`NOCODB_HOST=${randomDomain}`,
"NOCODB_PORT=8000",
`NC_AUTH_JWT_SECRET=${secretBase}`,
`HASH=${mainServiceHash}`,
];
return {
envs,
};
}

View File

@@ -0,0 +1,42 @@
version: '3.8'
services:
web:
image: odoo:16.0
networks:
- dokploy-network
depends_on:
- db
ports:
- ${ODOO_PORT}
environment:
- HOST=db
- USER=odoo
- PASSWORD=odoo
labels:
- "traefik.enable=true"
- "traefik.http.routers.${HASH}.rule=Host(`${ODOO_HOST}`)"
- "traefik.http.services.${HASH}.loadbalancer.server.port=${ODOO_PORT}"
volumes:
- odoo-web-data:/var/lib/odoo
- ./config:/etc/odoo
- ./addons:/mnt/extra-addons
db:
image: postgres:13
networks:
- dokploy-network
environment:
- POSTGRES_DB=postgres
- POSTGRES_USER=odoo
- POSTGRES_PASSWORD=odoo
volumes:
- odoo-db-data:/var/lib/postgresql/data
volumes:
odoo-web-data:
odoo-db-data:
networks:
dokploy-network:
external: true

20
templates/odoo/index.ts Normal file
View File

@@ -0,0 +1,20 @@
import {
generateHash,
generateRandomDomain,
type Template,
type Schema,
} from "../utils";
export function generate(schema: Schema): Template {
const mainServiceHash = generateHash(schema.projectName);
const randomDomain = generateRandomDomain(schema);
const envs = [
`ODOO_HOST=${randomDomain}`,
"ODOO_PORT=8069",
`HASH=${mainServiceHash}`,
];
return {
envs,
};
}

View File

@@ -0,0 +1,37 @@
version: '3.8'
services:
ollama:
volumes:
- ollama:/root/.ollama
networks:
- dokploy-network
pull_policy: always
tty: true
restart: unless-stopped
image: ollama/ollama:${OLLAMA_DOCKER_TAG-latest}
open-webui:
image: ghcr.io/open-webui/open-webui:${WEBUI_DOCKER_TAG-main}
networks:
- dokploy-network
volumes:
- open-webui:/app/backend/data
depends_on:
- ollama
environment:
- 'OLLAMA_BASE_URL=http://ollama:11434'
- 'WEBUI_SECRET_KEY='
restart: unless-stopped
labels:
- "traefik.enable=true"
- "traefik.http.routers.${HASH}.rule=Host(`${OPEN_WEBUI_HOST}`)"
- "traefik.http.services.${HASH}.loadbalancer.server.port=${OPEN_WEBUI_PORT}"
networks:
dokploy-network:
external: true
volumes:
ollama: {}
open-webui: {}

View File

@@ -0,0 +1,22 @@
import {
generateHash,
generateRandomDomain,
type Template,
type Schema,
} from "../utils";
export function generate(schema: Schema): Template {
const mainServiceHash = generateHash(schema.projectName);
const randomDomain = generateRandomDomain(schema);
const envs = [
`OPEN_WEBUI_HOST=${randomDomain}`,
"OPEN_WEBUI_PORT=8080",
`HASH=${mainServiceHash}`,
'OLLAMA_DOCKER_TAG=0.1.47',
'WEBUI_DOCKER_TAG=0.3.7'
];
return {
envs,
};
}

View File

@@ -0,0 +1,40 @@
version: '3.8'
services:
db:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: tu_base_de_datos
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
volumes:
- db_data:/var/lib/mysql
networks:
- dokploy-network
phpmyadmin:
image: phpmyadmin/phpmyadmin:5.2.1
environment:
PMA_HOST: db
PMA_USER: ${MYSQL_USER}
PMA_PASSWORD: ${MYSQL_PASSWORD}
PMA_ARBITRARY: 1
ports:
- ${PHPMYADMIN_PORT}
depends_on:
- db
labels:
- traefik.enable=true
- traefik.http.routers.${HASH}.rule=Host(`${PHPMYADMIN_HOST}`)
- traefik.http.services.${HASH}.loadbalancer.server.port=${PHPMYADMIN_PORT}
networks:
- dokploy-network
volumes:
db_data:
driver: local
networks:
dokploy-network:
external: true

View File

@@ -0,0 +1,27 @@
import {
generateHash,
generateRandomDomain,
type Template,
type Schema,
generatePassword,
} from "../utils";
export function generate(schema: Schema): Template {
const mainServiceHash = generateHash(schema.projectName);
const randomDomain = generateRandomDomain(schema);
const rootPassword = generatePassword(32);
const password = generatePassword(32);
const envs = [
`PHPMYADMIN_HOST=${randomDomain}`,
"PHPMYADMIN_PORT=80",
`HASH=${mainServiceHash}`,
`MYSQL_ROOT_PASSWORD=${rootPassword}`,
"MYSQL_DATABASE=mysql",
"MYSQL_USER=phpmyadmin",
`MYSQL_PASSWORD=${password}`,
];
return {
envs,
};
}

View File

@@ -1,7 +1,6 @@
version: "3.8"
services:
plausible_db:
# Plausible v2.1.0 was tested against PostgreSQL versions 15 and 16
# https://github.com/plausible/analytics/blob/v2.1.0/.github/workflows/elixir.yml#L21-L32
image: postgres:16-alpine
restart: always
networks:

View File

@@ -1,4 +1,4 @@
version: "3.7"
version: "3.8"
services:
pocketbase:
image: spectado/pocketbase:0.22.12

View File

@@ -5,7 +5,6 @@ import {
type Schema,
} from "../utils";
// https://pocketbase.io/docs/
export function generate(schema: Schema): Template {
const mainServiceHash = generateHash(schema.projectName);
const randomDomain = generateRandomDomain(schema);

View File

@@ -0,0 +1,48 @@
version: "3.8"
services:
rocketchat:
image: registry.rocket.chat/rocketchat/rocket.chat:6.9.2
restart: always
environment:
MONGO_URL: "mongodb://mongodb:27017/rocketchat?replicaSet=rs0"
MONGO_OPLOG_URL: "mongodb://mongodb:27017/local?replicaSet=rs0"
ROOT_URL: ${ROOT_URL:-http://${ROCKETCHAT_HOST}:${ROCKETCHAT_PORT}}
PORT: ${ROCKETCHAT_PORT}
DEPLOY_METHOD: docker
DEPLOY_PLATFORM:
REG_TOKEN:
depends_on:
- mongodb
ports:
- ${ROCKETCHAT_PORT}
networks:
- dokploy-network
labels:
- traefik.enable=true
- traefik.http.routers.${HASH}.rule=Host(`${ROCKETCHAT_HOST}`)
- traefik.http.services.${HASH}.loadbalancer.server.port=${ROCKETCHAT_PORT}
mongodb:
image: docker.io/bitnami/mongodb:5.0
restart: always
volumes:
- mongodb_data:/bitnami/mongodb
environment:
MONGODB_REPLICA_SET_MODE: primary
MONGODB_REPLICA_SET_NAME: rs0
MONGODB_PORT_NUMBER: 27017
MONGODB_INITIAL_PRIMARY_HOST: mongodb
MONGODB_INITIAL_PRIMARY_PORT_NUMBER: 27017
MONGODB_ADVERTISED_HOSTNAME: mongodb
MONGODB_ENABLE_JOURNAL: true
ALLOW_EMPTY_PASSWORD: yes
networks:
- dokploy-network
volumes:
mongodb_data: { driver: local }
networks:
dokploy-network:
external: true

View File

@@ -0,0 +1,21 @@
import {
generateHash,
generateRandomDomain,
type Template,
type Schema,
} from "../utils";
export function generate(schema: Schema): Template {
const mainServiceHash = generateHash(schema.projectName);
const randomDomain = generateRandomDomain(schema);
const envs = [
`ROCKETCHAT_HOST=${randomDomain}`,
"ROCKETCHAT_PORT=3000",
`HASH=${mainServiceHash}`,
];
return {
envs,
};
}

View File

@@ -34,7 +34,7 @@ export const templates: TemplateData[] = [
{
id: "calcom",
name: "Calcom",
version: "2.7.6",
version: "v2.7.6",
description:
"Calcom is a open source alternative to Calendly that allows to create scheduling and booking services.",
@@ -47,4 +47,289 @@ export const templates: TemplateData[] = [
tags: ["scheduling", "booking"],
load: () => import("./calcom/index").then((m) => m.generate),
},
{
id: "grafana",
name: "Grafana",
version: "9.5.20",
description:
"Grafana is an open source platform for data visualization and monitoring.",
logo: "grafana.svg",
links: {
github: "https://github.com/grafana/grafana",
website: "https://grafana.com/",
docs: "https://grafana.com/docs/",
},
tags: ["monitoring"],
load: () => import("./grafana/index").then((m) => m.generate),
},
{
id: "directus",
name: "Directus",
version: "10.12.1",
description:
"Directus is an open source headless CMS that provides an API-first solution for building custom backends.",
logo: "directus.jpg",
links: {
github: "https://github.com/directus/directus",
website: "https://directus.io/",
docs: "https://docs.directus.io/",
},
tags: ["cms"],
load: () => import("./directus/index").then((m) => m.generate),
},
{
id: "baserow",
name: "Baserow",
version: "1.25.2",
description:
"Baserow is an open source database management tool that allows you to create and manage databases.",
logo: "baserow.webp",
links: {
github: "https://github.com/Baserow/baserow",
website: "https://baserow.io/",
docs: "https://baserow.io/docs/index",
},
tags: ["database"],
load: () => import("./baserow/index").then((m) => m.generate),
},
{
id: "ghost",
name: "Ghost",
version: "5.0.0",
description:
"Ghost is a free and open source, professional publishing platform built on a modern Node.js technology stack.",
logo: "ghost.jpeg",
links: {
github: "https://github.com/TryGhost/Ghost",
website: "https://ghost.org/",
docs: "https://ghost.org/docs/",
},
tags: ["cms"],
load: () => import("./ghost/index").then((m) => m.generate),
},
{
id: "uptime-kuma",
name: "Uptime Kuma",
version: "1.21.4",
description:
"Uptime Kuma is a free and open source monitoring tool that allows you to monitor your websites and applications.",
logo: "uptime-kuma.png",
links: {
github: "https://github.com/louislam/uptime-kuma",
website: "https://uptime.kuma.pet/",
docs: "https://github.com/louislam/uptime-kuma/wiki",
},
tags: ["monitoring"],
load: () => import("./uptime-kuma/index").then((m) => m.generate),
},
{
id: "n8n",
name: "n8n",
version: "1.48.1",
description:
"n8n is an open source low-code platform for automating workflows and integrations.",
logo: "n8n.png",
links: {
github: "https://github.com/n8n-io/n8n",
website: "https://n8n.io/",
docs: "https://docs.n8n.io/",
},
tags: ["automation"],
load: () => import("./n8n/index").then((m) => m.generate),
},
{
id: "wordpress",
name: "Wordpress",
version: "5.8.3",
description:
"Wordpress is a free and open source content management system (CMS) for publishing and managing websites.",
logo: "wordpress.png",
links: {
github: "https://github.com/WordPress/WordPress",
website: "https://wordpress.org/",
docs: "https://wordpress.org/documentation/",
},
tags: ["cms"],
load: () => import("./wordpress/index").then((m) => m.generate),
},
{
id: "odoo",
name: "Odoo",
version: "16.0",
description:
"Odoo is a free and open source business management software that helps you manage your company's operations.",
logo: "odoo.png",
links: {
github: "https://github.com/odoo/odoo",
website: "https://odoo.com/",
docs: "https://www.odoo.com/documentation/",
},
tags: ["cms"],
load: () => import("./odoo/index").then((m) => m.generate),
},
{
id: "appsmith",
name: "Appsmith",
version: "v1.29",
description:
"Appsmith is a free and open source platform for building internal tools and applications.",
logo: "appsmith.png",
links: {
github: "https://github.com/appsmithorg/appsmith",
website: "https://appsmith.com/",
docs: "https://docs.appsmith.com/",
},
tags: ["cms"],
load: () => import("./appsmith/index").then((m) => m.generate),
},
{
id: "excalidraw",
name: "Excalidraw",
version: "latest",
description:
"Excalidraw is a free and open source online diagramming tool that lets you easily create and share beautiful diagrams.",
logo: "excalidraw.jpg",
links: {
github: "https://github.com/excalidraw/excalidraw",
website: "https://excalidraw.com/",
docs: "https://docs.excalidraw.com/",
},
tags: ["drawing"],
load: () => import("./excalidraw/index").then((m) => m.generate),
},
{
id: "documenso",
name: "Documenso",
version: "v1.5.6",
description:
"Documenso is the open source alternative to DocuSign for signing documents digitally",
links: {
github: "https://github.com/documenso/documenso",
website: "https://documenso.com/",
docs: "https://documenso.com/docs",
},
logo: "documenso.png",
tags: ["document-signing"],
load: () => import("./documenso/index").then((m) => m.generate),
},
{
id: "nocodb",
name: "NocoDB",
version: "0.251.1",
description:
"NocoDB is an opensource Airtable alternative that turns any MySQL, PostgreSQL, SQL Server, SQLite & MariaDB into a smart spreadsheet.",
links: {
github: "https://github.com/nocodb/nocodb",
website: "https://nocodb.com/",
docs: "https://docs.nocodb.com/",
},
logo: "nocodb.png",
tags: ["database", "spreadsheet", "low-code", "nocode"],
load: () => import("./nocodb/index").then((m) => m.generate),
},
{
id: "meilisearch",
name: "Meilisearch",
version: "v1.8.3",
description:
"Meilisearch is a free and open-source search engine that allows you to easily add search functionality to your web applications.",
logo: "meilisearch.png",
links: {
github: "https://github.com/meilisearch/meilisearch",
website: "https://www.meilisearch.com/",
docs: "https://docs.meilisearch.com/",
},
tags: ["search"],
load: () => import("./meilisearch/index").then((m) => m.generate),
},
{
id: "phpmyadmin",
name: "Phpmyadmin",
version: "5.2.1",
description:
"Phpmyadmin is a free and open-source web interface for MySQL and MariaDB that allows you to manage your databases.",
logo: "phpmyadmin.png",
links: {
github: "https://github.com/phpmyadmin/phpmyadmin",
website: "https://www.phpmyadmin.net/",
docs: "https://www.phpmyadmin.net/docs/",
},
tags: ["database"],
load: () => import("./phpmyadmin/index").then((m) => m.generate),
},
{
id: "rocketchat",
name: "Rocketchat",
version: "6.9.2",
description:
"Rocket.Chat is a free and open-source web chat platform that allows you to build and manage your own chat applications.",
logo: "rocketchat.png",
links: {
github: "https://github.com/RocketChat/Rocket.Chat",
website: "https://rocket.chat/",
docs: "https://rocket.chat/docs/",
},
tags: ["chat"],
load: () => import("./rocketchat/index").then((m) => m.generate),
},
{
id: "minio",
name: "Minio",
description:
"Minio is an open source object storage server compatible with Amazon S3 cloud storage service.",
logo: "minio.png",
version: "latest",
links: {
github: "https://github.com/minio/minio",
website: "https://minio.io/",
docs: "https://docs.minio.io/",
},
tags: ["storage"],
load: () => import("./minio/index").then((m) => m.generate),
},
{
id: "metabase",
name: "Metabase",
version: "v0.50.8",
description:
"Metabase is an open source business intelligence tool that allows you to ask questions and visualize data.",
logo: "metabase.png",
links: {
github: "https://github.com/metabase/metabase",
website: "https://www.metabase.com/",
docs: "https://www.metabase.com/docs/",
},
tags: ["database", "dashboard"],
load: () => import("./metabase/index").then((m) => m.generate),
},
{
id: "glitchtip",
name: "Glitchtip",
version: "v4.0",
description: "Glitchtip is simple, open source error tracking",
logo: "glitchtip.png",
links: {
github: "https://github.com/glitchtip/glitchtip",
website: "https://glitchtip.com/",
docs: "https://glitchtip.com/documentation",
},
tags: ["hosting"],
load: () => import("./glitchtip/index").then((m) => m.generate),
},
{
id: 'open-webui',
name: 'Open WebUI',
version: 'v0.3.7',
description: 'Open WebUI is a free and open source chatgpt alternative. Open WebUI is an extensible, feature-rich, and user-friendly self-hosted WebUI designed to operate entirely offline. It supports various LLM runners, including Ollama and OpenAI-compatible APIs. The template include ollama and webui services.',
logo: 'open-webui.png',
links: {
github: 'https://github.com/open-webui/open-webui',
website: 'https://openwebui.com/',
docs: 'https://docs.openwebui.com/',
},
tags: ['chat'],
load: () => import('./open-webui/index').then((m) => m.generate),
}
];

View File

@@ -0,0 +1,21 @@
version: "3.8"
services:
uptime-kuma:
networks:
- dokploy-network
image: louislam/uptime-kuma:1
restart: always
ports:
- ${UPTIME_KUMA_PORT}
volumes:
- uptime-kuma-data:/app/data
labels:
- traefik.enable=true
- traefik.http.routers.${HASH}.rule=Host(`${UPTIME_KUMA_HOST}`)
- traefik.http.services.${HASH}.loadbalancer.server.port=${UPTIME_KUMA_PORT}
volumes:
uptime-kuma-data:
networks:
dokploy-network:
external: true

View File

@@ -0,0 +1,20 @@
import {
generateHash,
generateRandomDomain,
type Template,
type Schema,
} from "../utils";
export function generate(schema: Schema): Template {
const mainServiceHash = generateHash(schema.projectName);
const randomDomain = generateRandomDomain(schema);
const envs = [
`UPTIME_KUMA_HOST=${randomDomain}`,
"UPTIME_KUMA_PORT=3001",
`HASH=${mainServiceHash}`,
];
return {
envs,
};
}

View File

@@ -0,0 +1,39 @@
version: '3.8'
services:
wordpress:
image: wordpress:5.8.3
networks:
- dokploy-network
ports:
- ${WORDPRESS_PORT}
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: exampleuser
WORDPRESS_DB_PASSWORD: examplepass
WORDPRESS_DB_NAME: exampledb
labels:
- "traefik.enable=true"
- "traefik.http.routers.${HASH}.rule=Host(`${WORDPRESS_HOST}`)"
- "traefik.http.services.${HASH}.loadbalancer.server.port=${WORDPRESS_PORT}"
volumes:
- wordpress_data:/var/www/html
db:
image: mysql:5.7.34
networks:
- dokploy-network
environment:
MYSQL_DATABASE: exampledb
MYSQL_USER: exampleuser
MYSQL_PASSWORD: examplepass
MYSQL_ROOT_PASSWORD: rootpass
volumes:
- db_data:/var/lib/mysql
volumes:
wordpress_data:
db_data:
networks:
dokploy-network:
external: true

View File

@@ -0,0 +1,20 @@
import {
generateHash,
generateRandomDomain,
type Template,
type Schema,
} from "../utils";
export function generate(schema: Schema): Template {
const mainServiceHash = generateHash(schema.projectName);
const randomDomain = generateRandomDomain(schema);
const envs = [
`WORDPRESS_HOST=${randomDomain}`,
"WORDPRESS_PORT=80",
`HASH=${mainServiceHash}`,
];
return {
envs,
};
}