Merge pull request #367 from Dokploy/canary

v0.7.1
This commit is contained in:
Mauricio Siu
2024-08-19 16:03:39 -06:00
committed by GitHub
70 changed files with 673 additions and 578 deletions

View File

@@ -166,20 +166,26 @@ import {
generateRandomDomain, generateRandomDomain,
type Template, type Template,
type Schema, type Schema,
type DomainSchema,
} from "../utils"; } from "../utils";
export function generate(schema: Schema): Template { export function generate(schema: Schema): Template {
// do your stuff here, like create a new domain, generate random passwords, mounts. // do your stuff here, like create a new domain, generate random passwords, mounts.
const mainServiceHash = generateHash(schema.projectName); const mainServiceHash = generateHash(schema.projectName);
const randomDomain = generateRandomDomain(schema); const mainDomain = generateRandomDomain(schema);
const secretBase = generateBase64(64); const secretBase = generateBase64(64);
const toptKeyBase = generateBase64(32); const toptKeyBase = generateBase64(32);
const domains: DomainSchema[] = [
{
host: mainDomain,
port: 8000,
serviceName: "plausible",
},
];
const envs = [ const envs = [
// If you want to show a domain in the UI, please add the prefix _HOST at the end of the variable name. `BASE_URL=http://${mainDomain}`,
`PLAUSIBLE_HOST=${randomDomain}`,
"PLAUSIBLE_PORT=8000",
`BASE_URL=http://${randomDomain}`,
`SECRET_KEY_BASE=${secretBase}`, `SECRET_KEY_BASE=${secretBase}`,
`TOTP_VAULT_KEY=${toptKeyBase}`, `TOTP_VAULT_KEY=${toptKeyBase}`,
`HASH=${mainServiceHash}`, `HASH=${mainServiceHash}`,
@@ -195,6 +201,7 @@ export function generate(schema: Schema): Template {
return { return {
envs, envs,
mounts, mounts,
domains,
}; };
} }
``` ```

26
LICENSE.MD Normal file
View File

@@ -0,0 +1,26 @@
# License
## Core License (Apache License 2.0)
Copyright 2024 Mauricio Siu.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
## Additional Terms for Specific Features
The following additional terms apply to the multi-node support and Docker Compose file support features of Dokploy. In the event of a conflict, these provisions shall take precedence over those in the Apache License:
- **Self-Hosted Version Free**: All features of Dokploy, including multi-node support and Docker Compose file support, will always be free to use in the self-hosted version.
- **Restriction on Resale**: The multi-node support and Docker Compose file support features cannot be sold or offered as a service by any party other than the copyright holder without prior written consent.
- **Modification Distribution**: Any modifications to the multi-node support and Docker Compose file support features must be distributed freely and cannot be sold or offered as a service.
For further inquiries or permissions, please contact us directly.

View File

@@ -23,12 +23,14 @@ export const AddManager = () => {
<div className="flex flex-col gap-2.5 text-sm"> <div className="flex flex-col gap-2.5 text-sm">
<span>1. Go to your new server and run the following command</span> <span>1. Go to your new server and run the following command</span>
<span className="bg-muted rounded-lg p-2 flex justify-between"> <span className="bg-muted rounded-lg p-2 flex justify-between">
curl https://get.docker.com | sh -s -- --version 24.0 curl https://get.docker.com | sh -s -- --version {data?.version}
<button <button
type="button" type="button"
className="self-center" className="self-center"
onClick={() => { onClick={() => {
copy("curl https://get.docker.com | sh -s -- --version 24.0"); copy(
`curl https://get.docker.com | sh -s -- --version ${data?.version}`,
);
toast.success("Copied to clipboard"); toast.success("Copied to clipboard");
}} }}
> >
@@ -43,12 +45,12 @@ export const AddManager = () => {
cluster cluster
</span> </span>
<span className="bg-muted rounded-lg p-2 flex"> <span className="bg-muted rounded-lg p-2 flex">
{data} {data?.command}
<button <button
type="button" type="button"
className="self-start" className="self-start"
onClick={() => { onClick={() => {
copy(data || ""); copy(data?.command || "");
toast.success("Copied to clipboard"); toast.success("Copied to clipboard");
}} }}
> >

View File

@@ -22,12 +22,14 @@ export const AddWorker = () => {
<div className="flex flex-col gap-2.5 text-sm"> <div className="flex flex-col gap-2.5 text-sm">
<span>1. Go to your new server and run the following command</span> <span>1. Go to your new server and run the following command</span>
<span className="bg-muted rounded-lg p-2 flex justify-between"> <span className="bg-muted rounded-lg p-2 flex justify-between">
curl https://get.docker.com | sh -s -- --version 24.0 curl https://get.docker.com | sh -s -- --version {data?.version}
<button <button
type="button" type="button"
className="self-center" className="self-center"
onClick={() => { onClick={() => {
copy("curl https://get.docker.com | sh -s -- --version 24.0"); copy(
`curl https://get.docker.com | sh -s -- --version ${data?.version}`,
);
toast.success("Copied to clipboard"); toast.success("Copied to clipboard");
}} }}
> >
@@ -42,12 +44,12 @@ export const AddWorker = () => {
</span> </span>
<span className="bg-muted rounded-lg p-2 flex"> <span className="bg-muted rounded-lg p-2 flex">
{data} {data?.command}
<button <button
type="button" type="button"
className="self-start" className="self-start"
onClick={() => { onClick={() => {
copy(data || ""); copy(data?.command || "");
toast.success("Copied to clipboard"); toast.success("Copied to clipboard");
}} }}
> >

View File

@@ -22,6 +22,7 @@ import {
import { api } from "@/utils/api"; import { api } from "@/utils/api";
import { toast } from "sonner"; import { toast } from "sonner";
import { DockerTerminalModal } from "./web-server/docker-terminal-modal"; import { DockerTerminalModal } from "./web-server/docker-terminal-modal";
import { EditTraefikEnv } from "./web-server/edit-traefik-env";
import { ShowMainTraefikConfig } from "./web-server/show-main-traefik-config"; import { ShowMainTraefikConfig } from "./web-server/show-main-traefik-config";
import { ShowModalLogs } from "./web-server/show-modal-logs"; import { ShowModalLogs } from "./web-server/show-modal-logs";
import { ShowServerMiddlewareConfig } from "./web-server/show-server-middleware-config"; import { ShowServerMiddlewareConfig } from "./web-server/show-server-middleware-config";
@@ -67,6 +68,9 @@ export const WebServer = () => {
const { mutateAsync: updateDockerCleanup } = const { mutateAsync: updateDockerCleanup } =
api.settings.updateDockerCleanup.useMutation(); api.settings.updateDockerCleanup.useMutation();
const { data: haveTraefikDashboardPortEnabled, refetch: refetchDashboard } =
api.settings.haveTraefikDashboardPortEnabled.useQuery();
return ( return (
<Card className="rounded-lg w-full bg-transparent"> <Card className="rounded-lg w-full bg-transparent">
<CardHeader> <CardHeader>
@@ -167,37 +171,38 @@ export const WebServer = () => {
<span>View Traefik config</span> <span>View Traefik config</span>
</DropdownMenuItem> </DropdownMenuItem>
</ShowMainTraefikConfig> </ShowMainTraefikConfig>
<EditTraefikEnv>
<DropdownMenuItem
onSelect={(e) => e.preventDefault()}
className="w-full cursor-pointer space-x-3"
>
<span>Modify Env</span>
</DropdownMenuItem>
</EditTraefikEnv>
<DropdownMenuItem <DropdownMenuItem
onClick={async () => { onClick={async () => {
await toggleDashboard({ await toggleDashboard({
enableDashboard: true, enableDashboard: !haveTraefikDashboardPortEnabled,
}) })
.then(async () => { .then(async () => {
toast.success("Dashboard Enabled"); toast.success(
`${haveTraefikDashboardPortEnabled ? "Disabled" : "Enabled"} Dashboard`,
);
refetchDashboard();
}) })
.catch(() => { .catch(() => {
toast.error("Error to enable Dashboard"); toast.error(
`${haveTraefikDashboardPortEnabled ? "Disabled" : "Enabled"} Dashboard`,
);
}); });
}} }}
className="w-full cursor-pointer space-x-3" className="w-full cursor-pointer space-x-3"
> >
<span>Enable Dashboard</span> <span>
</DropdownMenuItem> {haveTraefikDashboardPortEnabled ? "Disable" : "Enable"}{" "}
<DropdownMenuItem Dashboard
onClick={async () => { </span>
await toggleDashboard({
enableDashboard: false,
})
.then(async () => {
toast.success("Dashboard Disabled");
})
.catch(() => {
toast.error("Error to disable Dashboard");
});
}}
className="w-full cursor-pointer space-x-3"
>
<span>Disable Dashboard</span>
</DropdownMenuItem> </DropdownMenuItem>
<DockerTerminalModal appName="dokploy-traefik"> <DockerTerminalModal appName="dokploy-traefik">

View File

@@ -0,0 +1,146 @@
import { AlertBlock } from "@/components/shared/alert-block";
import { CodeEditor } from "@/components/shared/code-editor";
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { api } from "@/utils/api";
import { zodResolver } from "@hookform/resolvers/zod";
import { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import { toast } from "sonner";
import { z } from "zod";
const schema = z.object({
env: z.string(),
});
type Schema = z.infer<typeof schema>;
interface Props {
children?: React.ReactNode;
}
export const EditTraefikEnv = ({ children }: Props) => {
const [canEdit, setCanEdit] = useState(true);
const { data } = api.settings.readTraefikEnv.useQuery();
const { mutateAsync, isLoading, error, isError } =
api.settings.writeTraefikEnv.useMutation();
const form = useForm<Schema>({
defaultValues: {
env: data || "",
},
disabled: canEdit,
resolver: zodResolver(schema),
});
useEffect(() => {
if (data) {
form.reset({
env: data || "",
});
}
}, [form, form.reset, data]);
const onSubmit = async (data: Schema) => {
await mutateAsync(data.env)
.then(async () => {
toast.success("Traefik Env Updated");
})
.catch(() => {
toast.error("Error to update the traefik env");
});
};
return (
<Dialog>
<DialogTrigger asChild>{children}</DialogTrigger>
<DialogContent className="max-h-screen overflow-y-auto sm:max-w-4xl">
<DialogHeader>
<DialogTitle>Update Traefik Env</DialogTitle>
<DialogDescription>Update the traefik env</DialogDescription>
</DialogHeader>
{isError && <AlertBlock type="error">{error?.message}</AlertBlock>}
<Form {...form}>
<form
id="hook-form-update-server-traefik-config"
onSubmit={form.handleSubmit(onSubmit)}
className="w-full space-y-4 relative overflow-auto"
>
<div className="flex flex-col">
<FormField
control={form.control}
name="env"
render={({ field }) => (
<FormItem className="relative">
<FormLabel>Env</FormLabel>
<FormControl>
<CodeEditor
language="properties"
wrapperClassName="h-[35rem] font-mono"
placeholder={`TRAEFIK_CERTIFICATESRESOLVERS_LETSENCRYPT_ACME_EMAIL=test@localhost.com
TRAEFIK_CERTIFICATESRESOLVERS_LETSENCRYPT_STORAGE=/etc/dokploy/traefik/dynamic/acme.json
TRAEFIK_CERTIFICATESRESOLVERS_LETSENCRYPT_HTTP_CHALLENGE=true
TRAEFIK_CERTIFICATESRESOLVERS_LETSENCRYPT_HTTP_CHALLENGE_PRETTY=true
TRAEFIK_CERTIFICATESRESOLVERS_LETSENCRYPT_HTTP_CHALLENGE_ENTRYPOINT=web
TRAEFIK_CERTIFICATESRESOLVERS_LETSENCRYPT_HTTP_CHALLENGE_DNS_CHALLENGE=true
TRAEFIK_CERTIFICATESRESOLVERS_LETSENCRYPT_HTTP_CHALLENGE_DNS_PROVIDER=cloudflare
`}
{...field}
/>
</FormControl>
<pre>
<FormMessage />
</pre>
<div className="flex justify-end absolute z-50 right-6 top-0">
<Button
className="shadow-sm"
variant="secondary"
type="button"
onClick={async () => {
setCanEdit(!canEdit);
}}
>
{canEdit ? "Unlock" : "Lock"}
</Button>
</div>
</FormItem>
)}
/>
</div>
</form>
<DialogFooter>
<Button
isLoading={isLoading}
disabled={canEdit}
form="hook-form-update-server-traefik-config"
type="submit"
>
Update
</Button>
</DialogFooter>
</Form>
</DialogContent>
</Dialog>
);
};

View File

@@ -1,6 +1,6 @@
{ {
"name": "dokploy", "name": "dokploy",
"version": "v0.7.0", "version": "v0.7.1",
"private": true, "private": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"type": "module", "type": "module",

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -35,14 +35,23 @@ export const clusterRouter = createTRPCRouter({
}), }),
addWorker: protectedProcedure.query(async ({ input }) => { addWorker: protectedProcedure.query(async ({ input }) => {
const result = await docker.swarmInspect(); const result = await docker.swarmInspect();
return `docker swarm join --token ${ const docker_version = await docker.version();
result.JoinTokens.Worker
} ${await getPublicIpWithFallback()}:2377`; return {
command: `docker swarm join --token ${
result.JoinTokens.Worker
} ${await getPublicIpWithFallback()}:2377`,
version: docker_version.Version,
};
}), }),
addManager: protectedProcedure.query(async ({ input }) => { addManager: protectedProcedure.query(async ({ input }) => {
const result = await docker.swarmInspect(); const result = await docker.swarmInspect();
return `docker swarm join --token ${ const docker_version = await docker.version();
result.JoinTokens.Manager return {
} ${await getPublicIpWithFallback()}:2377`; command: `docker swarm join --token ${
result.JoinTokens.Manager
} ${await getPublicIpWithFallback()}:2377`,
version: docker_version.Version,
};
}), }),
}); });

View File

@@ -41,7 +41,7 @@ import {
updateCompose, updateCompose,
} from "../services/compose"; } from "../services/compose";
import { removeDeploymentsByComposeId } from "../services/deployment"; import { removeDeploymentsByComposeId } from "../services/deployment";
import { findDomainsByComposeId } from "../services/domain"; import { createDomain, findDomainsByComposeId } from "../services/domain";
import { createMount } from "../services/mount"; import { createMount } from "../services/mount";
import { findProjectById } from "../services/project"; import { findProjectById } from "../services/project";
import { addNewService, checkServiceAccess } from "../services/user"; import { addNewService, checkServiceAccess } from "../services/user";
@@ -236,7 +236,7 @@ export const composeRouter = createTRPCRouter({
const project = await findProjectById(input.projectId); const project = await findProjectById(input.projectId);
const projectName = slugify(`${project.name} ${input.id}`); const projectName = slugify(`${project.name} ${input.id}`);
const { envs, mounts } = generate({ const { envs, mounts, domains } = generate({
serverIp: admin.serverIp, serverIp: admin.serverIp,
projectName: projectName, projectName: projectName,
}); });
@@ -244,7 +244,7 @@ export const composeRouter = createTRPCRouter({
const compose = await createComposeByTemplate({ const compose = await createComposeByTemplate({
...input, ...input,
composeFile: composeFile, composeFile: composeFile,
env: envs.join("\n"), env: envs?.join("\n"),
name: input.id, name: input.id,
sourceType: "raw", sourceType: "raw",
appName: `${projectName}-${generatePassword(6)}`, appName: `${projectName}-${generatePassword(6)}`,
@@ -267,6 +267,17 @@ export const composeRouter = createTRPCRouter({
} }
} }
if (domains && domains?.length > 0) {
for (const domain of domains) {
await createDomain({
...domain,
domainType: "compose",
certificateType: "none",
composeId: compose.composeId,
});
}
}
return null; return null;
}), }),

View File

@@ -15,6 +15,7 @@ import {
cleanUpSystemPrune, cleanUpSystemPrune,
cleanUpUnusedImages, cleanUpUnusedImages,
cleanUpUnusedVolumes, cleanUpUnusedVolumes,
prepareEnvironmentVariables,
startService, startService,
stopService, stopService,
} from "@/server/utils/docker/utils"; } from "@/server/utils/docker/utils";
@@ -37,6 +38,7 @@ import {
import { generateOpenApiDocument } from "@dokploy/trpc-openapi"; import { generateOpenApiDocument } from "@dokploy/trpc-openapi";
import { TRPCError } from "@trpc/server"; import { TRPCError } from "@trpc/server";
import { scheduleJob, scheduledJobs } from "node-schedule"; import { scheduleJob, scheduledJobs } from "node-schedule";
import { z } from "zod";
import { appRouter } from "../root"; import { appRouter } from "../root";
import { findAdmin, updateAdmin } from "../services/admin"; import { findAdmin, updateAdmin } from "../services/admin";
import { import {
@@ -69,7 +71,9 @@ export const settingsRouter = createTRPCRouter({
toggleDashboard: adminProcedure toggleDashboard: adminProcedure
.input(apiEnableDashboard) .input(apiEnableDashboard)
.mutation(async ({ input }) => { .mutation(async ({ input }) => {
await initializeTraefik(input.enableDashboard); await initializeTraefik({
enableDashboard: input.enableDashboard,
});
return true; return true;
}), }),
@@ -309,4 +313,37 @@ export const settingsRouter = createTRPCRouter({
return openApiDocument; return openApiDocument;
}, },
), ),
readTraefikEnv: adminProcedure.query(async () => {
const { stdout } = await execAsync(
"docker service inspect --format='{{range .Spec.TaskTemplate.ContainerSpec.Env}}{{println .}}{{end}}' dokploy-traefik",
);
return stdout.trim();
}),
writeTraefikEnv: adminProcedure
.input(z.string())
.mutation(async ({ input }) => {
const envs = prepareEnvironmentVariables(input);
await initializeTraefik({
env: envs,
});
return true;
}),
haveTraefikDashboardPortEnabled: adminProcedure.query(async () => {
const { stdout } = await execAsync(
"docker service inspect --format='{{json .Endpoint.Ports}}' dokploy-traefik",
);
const parsed: any[] = JSON.parse(stdout.trim());
for (const port of parsed) {
if (port.PublishedPort === 8080) {
return true;
}
}
return false;
}),
}); });

View File

@@ -11,7 +11,15 @@ const TRAEFIK_SSL_PORT =
Number.parseInt(process.env.TRAEFIK_SSL_PORT ?? "", 10) || 443; Number.parseInt(process.env.TRAEFIK_SSL_PORT ?? "", 10) || 443;
const TRAEFIK_PORT = Number.parseInt(process.env.TRAEFIK_PORT ?? "", 10) || 80; const TRAEFIK_PORT = Number.parseInt(process.env.TRAEFIK_PORT ?? "", 10) || 80;
export const initializeTraefik = async (enableDashboard = false) => { interface TraefikOptions {
enableDashboard?: boolean;
env?: string[];
}
export const initializeTraefik = async ({
enableDashboard = false,
env = [],
}: TraefikOptions = {}) => {
const imageName = "traefik:v2.5"; const imageName = "traefik:v2.5";
const containerName = "dokploy-traefik"; const containerName = "dokploy-traefik";
const settings: CreateServiceOptions = { const settings: CreateServiceOptions = {
@@ -19,6 +27,7 @@ export const initializeTraefik = async (enableDashboard = false) => {
TaskTemplate: { TaskTemplate: {
ContainerSpec: { ContainerSpec: {
Image: imageName, Image: imageName,
Env: env,
Mounts: [ Mounts: [
{ {
Type: "bind", Type: "bind",

View File

@@ -2,17 +2,5 @@ version: "3.8"
services: services:
appsmith: appsmith:
image: index.docker.io/appsmith/appsmith-ee:v1.29 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: volumes:
- ../files/stacks:/appsmith-stacks - ../files/stacks:/appsmith-stacks
networks:
dokploy-network:
external: true

View File

@@ -1,4 +1,5 @@
import { import {
type DomainSchema,
type Schema, type Schema,
type Template, type Template,
generateHash, generateHash,
@@ -7,14 +8,16 @@ import {
export function generate(schema: Schema): Template { export function generate(schema: Schema): Template {
const mainServiceHash = generateHash(schema.projectName); const mainServiceHash = generateHash(schema.projectName);
const randomDomain = generateRandomDomain(schema);
const envs = [ const domains: DomainSchema[] = [
`APP_SMITH_HOST=${randomDomain}`, {
"APP_SMITH_PORT=80", host: generateRandomDomain(schema),
`HASH=${mainServiceHash}`, port: 80,
serviceName: "appsmith",
},
]; ];
return { return {
envs, domains,
}; };
} }

View File

@@ -2,21 +2,9 @@ version: "3.8"
services: services:
baserow: baserow:
image: baserow/baserow:1.25.2 image: baserow/baserow:1.25.2
networks:
- dokploy-network
environment: environment:
BASEROW_PUBLIC_URL: "http://${BASEROW_HOST}" 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: volumes:
- baserow_data:/baserow/data - baserow_data:/baserow/data
volumes: volumes:
baserow_data: baserow_data:
networks:
dokploy-network:
external: true

View File

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

View File

@@ -21,16 +21,6 @@ services:
- DATABASE_URL=postgres://postgres:password@postgres:5432/db - DATABASE_URL=postgres://postgres:password@postgres:5432/db
- NEXT_PUBLIC_WEBAPP_URL=http://${CALCOM_HOST} - NEXT_PUBLIC_WEBAPP_URL=http://${CALCOM_HOST}
- NEXTAUTH_URL=http://${CALCOM_HOST}/api/auth - NEXTAUTH_URL=http://${CALCOM_HOST}/api/auth
networks:
- dokploy-network
labels:
- "traefik.enable=true"
- "traefik.http.routers.${HASH}.rule=Host(`${CALCOM_HOST}`)"
- "traefik.http.services.${HASH}.loadbalancer.server.port=${CALCOM_PORT}"
networks:
dokploy-network:
external: true
volumes: volumes:
calcom-data: calcom-data:

View File

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

View File

@@ -18,8 +18,6 @@ services:
directus: directus:
image: directus/directus:10.12.1 image: directus/directus:10.12.1
networks:
- dokploy-network
ports: ports:
- 8055 - 8055
volumes: volumes:
@@ -28,10 +26,6 @@ services:
depends_on: depends_on:
- cache - cache
- database - database
labels:
- traefik.enable=true
- traefik.http.routers.${HASH}.rule=Host(`${DIRECTUS_HOST}`)
- traefik.http.services.${HASH}.loadbalancer.server.port=${DIRECTUS_PORT}
environment: environment:
SECRET: "replace-with-secure-random-value" SECRET: "replace-with-secure-random-value"
@@ -49,8 +43,5 @@ services:
ADMIN_EMAIL: "admin@example.com" ADMIN_EMAIL: "admin@example.com"
ADMIN_PASSWORD: "d1r3ctu5" ADMIN_PASSWORD: "d1r3ctu5"
networks:
dokploy-network:
external: true
volumes: volumes:
directus: directus:

View File

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

View File

@@ -19,8 +19,6 @@ services:
documenso: documenso:
image: documenso/documenso:1.5.6-rc.2 image: documenso/documenso:1.5.6-rc.2
networks:
- dokploy-network
depends_on: depends_on:
postgres: postgres:
condition: service_healthy condition: service_healthy
@@ -38,16 +36,8 @@ services:
- NEXT_PRIVATE_SIGNING_LOCAL_FILE_PATH=/opt/documenso/cert.p12 - NEXT_PRIVATE_SIGNING_LOCAL_FILE_PATH=/opt/documenso/cert.p12
ports: ports:
- ${DOCUMENSO_PORT} - ${DOCUMENSO_PORT}
labels:
- "traefik.enable=true"
- "traefik.http.routers.${HASH}.rule=Host(`${DOCUMENSO_HOST}`)"
- "traefik.http.services.${HASH}.loadbalancer.server.port=${DOCUMENSO_PORT}"
volumes: volumes:
- /opt/documenso/cert.p12:/opt/documenso/cert.p12 - /opt/documenso/cert.p12:/opt/documenso/cert.p12
networks:
dokploy-network:
external: true
volumes: volumes:
documenso-data: documenso-data:

View File

@@ -1,24 +1,29 @@
import { import {
type DomainSchema,
type Schema, type Schema,
type Template, type Template,
generateBase64, generateBase64,
generateHash,
generatePassword, generatePassword,
generateRandomDomain, generateRandomDomain,
} from "../utils"; } from "../utils";
export function generate(schema: Schema): Template { export function generate(schema: Schema): Template {
const mainServiceHash = generateHash(schema.projectName); const mainDomain = generateRandomDomain(schema);
const randomDomain = generateRandomDomain(schema);
const nextAuthSecret = generateBase64(32); const nextAuthSecret = generateBase64(32);
const documensoEncryptionKey = generatePassword(32); const documensoEncryptionKey = generatePassword(32);
const documensoSecondaryEncryptionKey = generatePassword(64); const documensoSecondaryEncryptionKey = generatePassword(64);
const domains: DomainSchema[] = [
{
host: mainDomain,
port: 3000,
serviceName: "documenso",
},
];
const envs = [ const envs = [
`DOCUMENSO_HOST=${randomDomain}`, `DOCUMENSO_HOST=${mainDomain}`,
"DOCUMENSO_PORT=3000", "DOCUMENSO_PORT=3000",
`HASH=${mainServiceHash}`,
`NEXTAUTH_SECRET=${nextAuthSecret}`, `NEXTAUTH_SECRET=${nextAuthSecret}`,
`NEXT_PRIVATE_ENCRYPTION_KEY=${documensoEncryptionKey}`, `NEXT_PRIVATE_ENCRYPTION_KEY=${documensoEncryptionKey}`,
`NEXT_PRIVATE_ENCRYPTION_SECONDARY_KEY=${documensoSecondaryEncryptionKey}`, `NEXT_PRIVATE_ENCRYPTION_SECONDARY_KEY=${documensoSecondaryEncryptionKey}`,
@@ -26,5 +31,6 @@ export function generate(schema: Schema): Template {
return { return {
envs, envs,
domains,
}; };
} }

View File

@@ -2,10 +2,6 @@ services:
doublezero: doublezero:
restart: always restart: always
image: liltechnomancer/double-zero:0.2.1 image: liltechnomancer/double-zero:0.2.1
ports:
- ${DOUBLEZERO_PORT}
networks:
- dokploy-network
volumes: volumes:
- db-data:/var/lib/doublezero/data - db-data:/var/lib/doublezero/data
environment: environment:
@@ -17,15 +13,7 @@ services:
SECRET_KEY_BASE: ${SECRET_KEY_BASE} SECRET_KEY_BASE: ${SECRET_KEY_BASE}
PHX_HOST: ${DOUBLEZERO_HOST} PHX_HOST: ${DOUBLEZERO_HOST}
DATABASE_PATH: ./00.db DATABASE_PATH: ./00.db
labels:
- "traefik.enable=true"
- "traefik.http.routers.${HASH}.rule=Host(`${DOUBLEZERO_HOST}`)"
- "traefik.http.services.${HASH}.loadbalancer.server.port=${DOUBLEZERO_PORT}"
volumes: volumes:
db-data: db-data:
driver: local driver: local
networks:
dokploy-network:
external: true

View File

@@ -1,20 +1,26 @@
import { import {
type DomainSchema,
type Schema, type Schema,
type Template, type Template,
generateBase64, generateBase64,
generateHash,
generateRandomDomain, generateRandomDomain,
} from "../utils"; } from "../utils";
export function generate(schema: Schema): Template { export function generate(schema: Schema): Template {
const mainServiceHash = generateHash(schema.projectName); const mainDomain = generateRandomDomain(schema);
const randomDomain = generateRandomDomain(schema);
const secretKeyBase = generateBase64(64); const secretKeyBase = generateBase64(64);
const domains: DomainSchema[] = [
{
host: mainDomain,
port: 4000,
serviceName: "doublezero",
},
];
const envs = [ const envs = [
`DOUBLEZERO_HOST=${randomDomain}`, `DOUBLEZERO_HOST=${mainDomain}`,
"DOUBLEZERO_PORT=4000", "DOUBLEZERO_PORT=4000",
`HASH=${mainServiceHash}`,
`SECRET_KEY_BASE=${secretKeyBase}`, `SECRET_KEY_BASE=${secretKeyBase}`,
"AWS_ACCESS_KEY_ID=your-aws-access-key", "AWS_ACCESS_KEY_ID=your-aws-access-key",
"AWS_SECRET_ACCESS_KEY=your-aws-secret-key", "AWS_SECRET_ACCESS_KEY=your-aws-secret-key",
@@ -25,5 +31,6 @@ export function generate(schema: Schema): Template {
return { return {
envs, envs,
domains,
}; };
} }

View File

@@ -1,17 +1,7 @@
version: '3.8' version: "3.8"
services: services:
excalidraw: excalidraw:
networks: networks:
- dokploy-network - dokploy-network
image: excalidraw/excalidraw:latest 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

@@ -1,4 +1,5 @@
import { import {
type DomainSchema,
type Schema, type Schema,
type Template, type Template,
generateHash, generateHash,
@@ -6,15 +7,17 @@ import {
} from "../utils"; } from "../utils";
export function generate(schema: Schema): Template { export function generate(schema: Schema): Template {
const mainServiceHash = generateHash(schema.projectName); const mainDomain = generateRandomDomain(schema);
const randomDomain = generateRandomDomain(schema);
const envs = [ const domains: DomainSchema[] = [
`EXCALIDRAW_HOST=${randomDomain}`, {
"EXCALIDRAW_PORT=80", host: mainDomain,
`HASH=${mainServiceHash}`, port: 80,
serviceName: "excalidraw",
},
]; ];
return { return {
envs, domains,
}; };
} }

View File

@@ -1,13 +1,8 @@
version: "3.8" version: "3.8"
services: services:
ghost: ghost:
image: ghost:5-alpine image: ghost:5-alpine
restart: always restart: always
networks:
- dokploy-network
ports:
- ${GHOST_PORT}
environment: environment:
database__client: mysql database__client: mysql
database__connection__host: db database__connection__host: db
@@ -15,10 +10,7 @@ services:
database__connection__password: example database__connection__password: example
database__connection__database: ghost database__connection__database: ghost
url: http://${GHOST_HOST} 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: volumes:
- ghost:/var/lib/ghost/content - ghost:/var/lib/ghost/content
@@ -35,7 +27,3 @@ services:
volumes: volumes:
ghost: ghost:
db: db:
networks:
dokploy-network:
external: true

View File

@@ -1,4 +1,5 @@
import { import {
type DomainSchema,
type Schema, type Schema,
type Template, type Template,
generateHash, generateHash,
@@ -6,15 +7,19 @@ import {
} from "../utils"; } from "../utils";
export function generate(schema: Schema): Template { export function generate(schema: Schema): Template {
const mainServiceHash = generateHash(schema.projectName); const mainDomain = generateRandomDomain(schema);
const randomDomain = generateRandomDomain(schema);
const envs = [ const domains: DomainSchema[] = [
`GHOST_HOST=${randomDomain}`, {
"GHOST_PORT=2368", host: mainDomain,
`HASH=${mainServiceHash}`, port: 2368,
serviceName: "ghost",
},
]; ];
const envs = [`GHOST_HOST=${mainDomain}`];
return { return {
envs, envs,
domains,
}; };
} }

View File

@@ -1,16 +1,14 @@
x-environment: x-environment: &default-environment
&default-environment
DATABASE_URL: postgres://postgres:postgres@postgres:5432/postgres DATABASE_URL: postgres://postgres:postgres@postgres:5432/postgres
SECRET_KEY: ${SECRET_KEY} SECRET_KEY: ${SECRET_KEY}
PORT: ${GLITCHTIP_PORT} PORT: ${GLITCHTIP_PORT}
EMAIL_URL: consolemail:// EMAIL_URL: consolemail://
GLITCHTIP_DOMAIN: http://${GLITCHTIP_HOST} GLITCHTIP_DOMAIN: http://${GLITCHTIP_HOST}
DEFAULT_FROM_EMAIL: email@glitchtip.com DEFAULT_FROM_EMAIL: email@glitchtip.com
CELERY_WORKER_AUTOSCALE: "1,3" CELERY_WORKER_AUTOSCALE: "1,3"
CELERY_WORKER_MAX_TASKS_PER_CHILD: "10000" CELERY_WORKER_MAX_TASKS_PER_CHILD: "10000"
x-depends_on: x-depends_on: &default-depends_on
&default-depends_on
- postgres - postgres
- redis - redis
@@ -18,7 +16,7 @@ services:
postgres: postgres:
image: postgres:16 image: postgres:16
environment: environment:
POSTGRES_HOST_AUTH_METHOD: "trust" POSTGRES_HOST_AUTH_METHOD: "trust"
restart: unless-stopped restart: unless-stopped
volumes: volumes:
- pg-data:/var/lib/postgresql/data - pg-data:/var/lib/postgresql/data
@@ -36,21 +34,15 @@ services:
- ${GLITCHTIP_PORT} - ${GLITCHTIP_PORT}
environment: *default-environment environment: *default-environment
restart: unless-stopped restart: unless-stopped
volumes: volumes:
- uploads:/code/uploads - 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: worker:
image: glitchtip/glitchtip:v4.0 image: glitchtip/glitchtip:v4.0
command: ./bin/run-celery-with-beat.sh command: ./bin/run-celery-with-beat.sh
depends_on: *default-depends_on depends_on: *default-depends_on
environment: *default-environment environment: *default-environment
restart: unless-stopped restart: unless-stopped
volumes: volumes:
- uploads:/code/uploads - uploads:/code/uploads
networks: networks:
- dokploy-network - dokploy-network
@@ -65,7 +57,3 @@ services:
volumes: volumes:
pg-data: pg-data:
uploads: uploads:
networks:
dokploy-network:
external: true

View File

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

View File

@@ -1,20 +1,9 @@
version: "3.8" version: "3.8"
services: services:
grafana: grafana:
networks:
- dokploy-network
image: grafana/grafana-enterprise:9.5.20 image: grafana/grafana-enterprise:9.5.20
restart: unless-stopped 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: volumes:
- grafana-storage:/var/lib/grafana - grafana-storage:/var/lib/grafana
networks:
dokploy-network:
external: true
volumes: volumes:
grafana-storage: {} grafana-storage: {}

View File

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

View File

@@ -1,30 +1,19 @@
version: '3.8' version: "3.8"
services: services:
jellyfin: jellyfin:
image: jellyfin/jellyfin:10 image: jellyfin/jellyfin:10
networks:
- dokploy-network
ports:
- ${JELLYFIN_PORT}
labels:
- "traefik.enable=true"
- "traefik.http.routers.${HASH}.rule=Host(`${JELLYFIN_HOST}`)"
- "traefik.http.services.${HASH}.loadbalancer.server.port=${JELLYFIN_PORT}"
volumes: volumes:
- config:/config - config:/config
- cache:/cache - cache:/cache
- media:/media - media:/media
restart: 'unless-stopped' restart: "unless-stopped"
# Optional - alternative address used for autodiscovery # Optional - alternative address used for autodiscovery
environment: environment:
- JELLYFIN_PublishedServerUrl=http://${JELLYFIN_HOST} - JELLYFIN_PublishedServerUrl=http://${JELLYFIN_HOST}
# Optional - may be necessary for docker healthcheck to pass if running in host network mode # Optional - may be necessary for docker healthcheck to pass if running in host network mode
extra_hosts: extra_hosts:
- 'host.docker.internal:host-gateway' - "host.docker.internal:host-gateway"
volumes: volumes:
config: config:
cache: cache:
media: media:
networks:
dokploy-network:
external: true

View File

@@ -1,22 +1,25 @@
// EXAMPLE // EXAMPLE
import { import {
type DomainSchema,
type Schema, type Schema,
type Template, type Template,
generateHash,
generateRandomDomain, generateRandomDomain,
} from "../utils"; } from "../utils";
export function generate(schema: Schema): Template { export function generate(schema: Schema): Template {
const mainServiceHash = generateHash(schema.projectName); const domain = generateRandomDomain(schema);
const randomDomain = generateRandomDomain(schema); const domains: DomainSchema[] = [
const port = 8096; {
const envs = [ host: domain,
`JELLYFIN_HOST=${randomDomain}`, port: 8096,
`HASH=${mainServiceHash}`, serviceName: "jellyfin",
`JELLYFIN_PORT=${port}`, },
]; ];
const envs = [`JELLYFIN_HOST=${domain}`];
return { return {
envs, envs,
domains,
}; };
} }

View File

@@ -36,10 +36,6 @@ services:
app: app:
restart: unless-stopped restart: unless-stopped
image: listmonk/listmonk:v3.0.0 image: listmonk/listmonk:v3.0.0
ports:
- "${LISTMONK_PORT}"
networks:
- dokploy-network
environment: environment:
- TZ=Etc/UTC - TZ=Etc/UTC
depends_on: depends_on:
@@ -47,15 +43,7 @@ services:
- setup - setup
volumes: volumes:
- ../files/config.toml:/listmonk/config.toml - ../files/config.toml:/listmonk/config.toml
labels:
- "traefik.enable=true"
- "traefik.http.routers.${HASH}.rule=Host(`${LISTMONK_HOST}`)"
- "traefik.http.services.${HASH}.loadbalancer.server.port=${LISTMONK_PORT}"
volumes: volumes:
listmonk-data: listmonk-data:
driver: local driver: local
networks:
dokploy-network:
external: true

View File

@@ -1,20 +1,24 @@
import { import {
type DomainSchema,
type Schema, type Schema,
type Template, type Template,
generateHash,
generatePassword, generatePassword,
generateRandomDomain, generateRandomDomain,
} from "../utils"; } from "../utils";
export function generate(schema: Schema): Template { export function generate(schema: Schema): Template {
const mainServiceHash = generateHash(schema.projectName);
const randomDomain = generateRandomDomain(schema); const randomDomain = generateRandomDomain(schema);
const adminPassword = generatePassword(32); const adminPassword = generatePassword(32);
const domains: DomainSchema[] = [
{
host: randomDomain,
port: 9000,
serviceName: "app",
},
];
const envs = [ const envs = [
`LISTMONK_HOST=${randomDomain}`,
"LISTMONK_PORT=9000",
`HASH=${mainServiceHash}`,
`# login with admin:${adminPassword}`, `# login with admin:${adminPassword}`,
"# check config.toml in Advanced / Volumes for more options", "# check config.toml in Advanced / Volumes for more options",
]; ];
@@ -48,5 +52,6 @@ params = ""
return { return {
envs, envs,
mounts, mounts,
domains,
}; };
} }

View File

@@ -1,25 +1,14 @@
version: '3.8' version: "3.8"
services: services:
meilisearch: meilisearch:
networks:
- dokploy-network
image: getmeili/meilisearch:v1.8.3 image: getmeili/meilisearch:v1.8.3
ports:
- ${MEILISEARCH_PORT}
volumes: volumes:
- meili_data:/meili_data - meili_data:/meili_data
environment: environment:
MEILI_MASTER_KEY: ${MEILI_MASTER_KEY} MEILI_MASTER_KEY: ${MEILI_MASTER_KEY}
MEILI_ENV: ${MEILI_ENV} 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: volumes:
meili_data: meili_data:
driver: local driver: local
networks:
dokploy-network:
external: true

View File

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

View File

@@ -4,8 +4,6 @@ services:
image: metabase/metabase:v0.50.8 image: metabase/metabase:v0.50.8
volumes: volumes:
- /dev/urandom:/dev/random:ro - /dev/urandom:/dev/random:ro
ports:
- ${METABASE_PORT}
environment: environment:
MB_DB_TYPE: postgres MB_DB_TYPE: postgres
MB_DB_DBNAME: metabaseappdb MB_DB_DBNAME: metabaseappdb
@@ -13,17 +11,11 @@ services:
MB_DB_USER: metabase MB_DB_USER: metabase
MB_DB_PASS: mysecretpassword MB_DB_PASS: mysecretpassword
MB_DB_HOST: postgres MB_DB_HOST: postgres
networks:
- dokploy-network
healthcheck: healthcheck:
test: curl --fail -I http://localhost:3000/api/health || exit 1 test: curl --fail -I http://localhost:3000/api/health || exit 1
interval: 15s interval: 15s
timeout: 5s timeout: 5s
retries: 5 retries: 5
labels:
- traefik.enable=true
- traefik.http.routers.${HASH}.rule=Host(`${METABASE_HOST}`)
- traefik.http.services.${HASH}.loadbalancer.server.port=${METABASE_PORT}
postgres: postgres:
image: postgres:14 image: postgres:14
environment: environment:
@@ -32,7 +24,3 @@ services:
POSTGRES_PASSWORD: mysecretpassword POSTGRES_PASSWORD: mysecretpassword
networks: networks:
- dokploy-network - dokploy-network
networks:
dokploy-network:
external: true

View File

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

View File

@@ -1,31 +1,13 @@
version: '3.8' version: "3.8"
services: services:
minio: minio:
image: minio/minio image: minio/minio
ports:
- ${MINIO_API_PORT}
- ${MINIO_DASHBOARD_PORT}
volumes: volumes:
- minio-data:/data - minio-data:/data
environment: environment:
- MINIO_ROOT_USER=minioadmin - MINIO_ROOT_USER=minioadmin
- MINIO_ROOT_PASSWORD=minioadmin123 - MINIO_ROOT_PASSWORD=minioadmin123
command: server /data --console-address ":9001" 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: volumes:
minio-data: minio-data:
networks:
dokploy-network:
external: true

View File

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

View File

@@ -3,17 +3,9 @@ services:
n8n: n8n:
image: docker.n8n.io/n8nio/n8n:1.48.1 image: docker.n8n.io/n8nio/n8n:1.48.1
restart: always 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: environment:
- N8N_HOST=${N8N_HOST} - N8N_HOST=${N8N_HOST}
- N8N_PORT=5678 - N8N_PORT=${N8N_PORT}
- N8N_PROTOCOL=http - N8N_PROTOCOL=http
- NODE_ENV=production - NODE_ENV=production
- WEBHOOK_URL=https://${N8N_HOST}/ - WEBHOOK_URL=https://${N8N_HOST}/
@@ -23,7 +15,4 @@ services:
- n8n_data:/home/node/.n8n - n8n_data:/home/node/.n8n
volumes: volumes:
n8n_data: n8n_data:
networks:
dokploy-network:
external: true

View File

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

View File

@@ -3,18 +3,10 @@ services:
nocodb: nocodb:
image: nocodb/nocodb:0.251.1 image: nocodb/nocodb:0.251.1
restart: always restart: always
networks:
- dokploy-network
ports:
- ${NOCODB_PORT}
environment: environment:
NC_DB : "pg://root_db?u=postgres&p=password&d=root_db" NC_DB: "pg://root_db?u=postgres&p=password&d=root_db"
PORT : ${NOCODB_PORT} PORT: ${NOCODB_PORT}
NC_REDIS_URL: ${NC_REDIS_URL} 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: volumes:
- nc_data:/usr/app/data - nc_data:/usr/app/data
@@ -30,15 +22,11 @@ services:
healthcheck: healthcheck:
interval: 10s interval: 10s
retries: 10 retries: 10
test: "pg_isready -U \"$$POSTGRES_USER\" -d \"$$POSTGRES_DB\"" test: 'pg_isready -U "$$POSTGRES_USER" -d "$$POSTGRES_DB"'
timeout: 2s timeout: 2s
volumes: volumes:
- "db_data:/var/lib/postgresql/data" - "db_data:/var/lib/postgresql/data"
networks:
dokploy-network:
external: true
volumes: volumes:
db_data: {} db_data: {}
nc_data: {} nc_data: {}

View File

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

View File

@@ -2,20 +2,12 @@ version: "3.8"
services: services:
web: web:
image: odoo:16.0 image: odoo:16.0
networks:
- dokploy-network
depends_on: depends_on:
- db - db
ports:
- ${ODOO_PORT}
environment: environment:
- HOST=db - HOST=db
- USER=odoo - USER=odoo
- PASSWORD=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: volumes:
- odoo-web-data:/var/lib/odoo - odoo-web-data:/var/lib/odoo
- ../files/config:/etc/odoo - ../files/config:/etc/odoo
@@ -35,7 +27,3 @@ services:
volumes: volumes:
odoo-web-data: odoo-web-data:
odoo-db-data: odoo-db-data:
networks:
dokploy-network:
external: true

View File

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

View File

@@ -1,6 +1,5 @@
version: '3.8' version: "3.8"
services: services:
ollama: ollama:
volumes: volumes:
- ollama:/root/.ollama - ollama:/root/.ollama
@@ -13,24 +12,14 @@ services:
open-webui: open-webui:
image: ghcr.io/open-webui/open-webui:${WEBUI_DOCKER_TAG-main} image: ghcr.io/open-webui/open-webui:${WEBUI_DOCKER_TAG-main}
networks:
- dokploy-network
volumes: volumes:
- open-webui:/app/backend/data - open-webui:/app/backend/data
depends_on: depends_on:
- ollama - ollama
environment: environment:
- 'OLLAMA_BASE_URL=http://ollama:11434' - "OLLAMA_BASE_URL=http://ollama:11434"
- 'WEBUI_SECRET_KEY=' - "WEBUI_SECRET_KEY="
restart: unless-stopped 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: volumes:
ollama: {} ollama: {}

View File

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

View File

@@ -1,4 +1,4 @@
version: '3.8' version: "3.8"
services: services:
db: db:
@@ -20,21 +20,9 @@ services:
PMA_USER: ${MYSQL_USER} PMA_USER: ${MYSQL_USER}
PMA_PASSWORD: ${MYSQL_PASSWORD} PMA_PASSWORD: ${MYSQL_PASSWORD}
PMA_ARBITRARY: 1 PMA_ARBITRARY: 1
ports:
- ${PHPMYADMIN_PORT}
depends_on: depends_on:
- db - 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: volumes:
db_data: db_data:
driver: local driver: local
networks:
dokploy-network:
external: true

View File

@@ -1,20 +1,24 @@
import { import {
type DomainSchema,
type Schema, type Schema,
type Template, type Template,
generateHash,
generatePassword, generatePassword,
generateRandomDomain, generateRandomDomain,
} from "../utils"; } from "../utils";
export function generate(schema: Schema): Template { export function generate(schema: Schema): Template {
const mainServiceHash = generateHash(schema.projectName); const mainDomain = generateRandomDomain(schema);
const randomDomain = generateRandomDomain(schema);
const rootPassword = generatePassword(32); const rootPassword = generatePassword(32);
const password = generatePassword(32); const password = generatePassword(32);
const domains: DomainSchema[] = [
{
host: mainDomain,
port: 80,
serviceName: "phpmyadmin",
},
];
const envs = [ const envs = [
`PHPMYADMIN_HOST=${randomDomain}`,
"PHPMYADMIN_PORT=80",
`HASH=${mainServiceHash}`,
`MYSQL_ROOT_PASSWORD=${rootPassword}`, `MYSQL_ROOT_PASSWORD=${rootPassword}`,
"MYSQL_DATABASE=mysql", "MYSQL_DATABASE=mysql",
"MYSQL_USER=phpmyadmin", "MYSQL_USER=phpmyadmin",
@@ -23,5 +27,6 @@ export function generate(schema: Schema): Template {
return { return {
envs, envs,
domains,
}; };
} }

View File

@@ -32,17 +32,9 @@ services:
depends_on: depends_on:
- plausible_db - plausible_db
- plausible_events_db - plausible_events_db
ports:
- ${PLAUSIBLE_PORT}
networks:
- dokploy-network
env_file: env_file:
- .env - .env
labels:
- "traefik.enable=true"
- "traefik.http.routers.${HASH}.rule=Host(`${PLAUSIBLE_HOST}`)"
- "traefik.http.services.${HASH}.loadbalancer.server.port=${PLAUSIBLE_PORT}"
volumes: volumes:
db-data: db-data:
driver: local driver: local
@@ -50,7 +42,3 @@ volumes:
driver: local driver: local
event-logs: event-logs:
driver: local driver: local
networks:
dokploy-network:
external: true

View File

@@ -1,24 +1,28 @@
import { import {
type DomainSchema,
type Schema, type Schema,
type Template, type Template,
generateBase64, generateBase64,
generateHash,
generateRandomDomain, generateRandomDomain,
} from "../utils"; } from "../utils";
export function generate(schema: Schema): Template { export function generate(schema: Schema): Template {
const mainServiceHash = generateHash(schema.projectName); const mainDomain = generateRandomDomain(schema);
const randomDomain = generateRandomDomain(schema);
const secretBase = generateBase64(64); const secretBase = generateBase64(64);
const toptKeyBase = generateBase64(32); const toptKeyBase = generateBase64(32);
const domains: DomainSchema[] = [
{
host: mainDomain,
port: 8000,
serviceName: "plausible",
},
];
const envs = [ const envs = [
`PLAUSIBLE_HOST=${randomDomain}`, `BASE_URL=http://${mainDomain}`,
"PLAUSIBLE_PORT=8000",
`BASE_URL=http://${randomDomain}`,
`SECRET_KEY_BASE=${secretBase}`, `SECRET_KEY_BASE=${secretBase}`,
`TOTP_VAULT_KEY=${toptKeyBase}`, `TOTP_VAULT_KEY=${toptKeyBase}`,
`HASH=${mainServiceHash}`,
]; ];
const mounts: Template["mounts"] = [ const mounts: Template["mounts"] = [
@@ -62,5 +66,6 @@ export function generate(schema: Schema): Template {
return { return {
envs, envs,
mounts, mounts,
domains,
}; };
} }

View File

@@ -3,19 +3,7 @@ services:
pocketbase: pocketbase:
image: spectado/pocketbase:0.22.12 image: spectado/pocketbase:0.22.12
restart: unless-stopped restart: unless-stopped
ports:
- ${POCKETBASE_PORT}
networks:
- dokploy-network
labels:
- traefik.enable=true
- traefik.http.routers.${HASH}.rule=Host(`${POCKETBASE_HOST}`)
- traefik.http.services.${HASH}.loadbalancer.server.port=${POCKETBASE_PORT}
volumes: volumes:
- /etc/dokploy/templates/${HASH}/data:/pb_data - /etc/dokploy/templates/${HASH}/data:/pb_data
- /etc/dokploy/templates/${HASH}/public:/pb_public - /etc/dokploy/templates/${HASH}/public:/pb_public
- /etc/dokploy/templates/${HASH}/migrations:/pb_migrations - /etc/dokploy/templates/${HASH}/migrations:/pb_migrations
networks:
dokploy-network:
external: true

View File

@@ -1,21 +1,22 @@
import { import {
type DomainSchema,
type Schema, type Schema,
type Template, type Template,
generateHash,
generateRandomDomain, generateRandomDomain,
} from "../utils"; } from "../utils";
export function generate(schema: Schema): Template { export function generate(schema: Schema): Template {
const mainServiceHash = generateHash(schema.projectName); const mainDomain = generateRandomDomain(schema);
const randomDomain = generateRandomDomain(schema);
const envs = [ const domains: DomainSchema[] = [
`POCKETBASE_HOST=${randomDomain}`, {
"POCKETBASE_PORT=80", host: mainDomain,
`HASH=${mainServiceHash}`, port: 80,
serviceName: "pocketbase",
},
]; ];
return { return {
envs, domains,
}; };
} }

View File

@@ -9,18 +9,10 @@ services:
ROOT_URL: ${ROOT_URL:-http://${ROCKETCHAT_HOST}:${ROCKETCHAT_PORT}} ROOT_URL: ${ROOT_URL:-http://${ROCKETCHAT_HOST}:${ROCKETCHAT_PORT}}
PORT: ${ROCKETCHAT_PORT} PORT: ${ROCKETCHAT_PORT}
DEPLOY_METHOD: docker DEPLOY_METHOD: docker
DEPLOY_PLATFORM: DEPLOY_PLATFORM:
REG_TOKEN: REG_TOKEN:
depends_on: depends_on:
- mongodb - 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: mongodb:
image: docker.io/bitnami/mongodb:5.0 image: docker.io/bitnami/mongodb:5.0
@@ -41,8 +33,3 @@ services:
volumes: volumes:
mongodb_data: { driver: local } mongodb_data: { driver: local }
networks:
dokploy-network:
external: true

View File

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

View File

@@ -0,0 +1,12 @@
version: "3"
services:
soketi:
image: quay.io/soketi/soketi:1.4-16-debian
container_name: soketi
environment:
SOKETI_DEBUG: "1"
SOKETI_HOST: "0.0.0.0"
SOKETI_PORT: "6001"
SOKETI_METRICS_SERVER_PORT: "9601"
restart: unless-stopped

View File

@@ -0,0 +1,28 @@
import {
type DomainSchema,
type Schema,
type Template,
generateRandomDomain,
} from "../utils";
export function generate(schema: Schema): Template {
const mainDomain = generateRandomDomain(schema);
const metricsDomain = generateRandomDomain(schema);
const domains: DomainSchema[] = [
{
host: mainDomain,
port: 6001,
serviceName: "soketi",
},
{
host: metricsDomain,
port: 9601,
serviceName: "soketi",
},
];
return {
domains,
};
}

View File

@@ -4,8 +4,6 @@ services:
teable: teable:
image: ghcr.io/teableio/teable:1.3.1-alpha-build.460 image: ghcr.io/teableio/teable:1.3.1-alpha-build.460
restart: always restart: always
ports:
- ${TEABLE_PORT}
volumes: volumes:
- teable-data:/app/.assets - teable-data:/app/.assets
# you may use a bind-mounted host directory instead, # you may use a bind-mounted host directory instead,
@@ -24,12 +22,6 @@ services:
- BACKEND_MAIL_SENDER_NAME=${BACKEND_MAIL_SENDER_NAME} - BACKEND_MAIL_SENDER_NAME=${BACKEND_MAIL_SENDER_NAME}
- BACKEND_MAIL_AUTH_USER=${BACKEND_MAIL_AUTH_USER} - BACKEND_MAIL_AUTH_USER=${BACKEND_MAIL_AUTH_USER}
- BACKEND_MAIL_AUTH_PASS=${BACKEND_MAIL_AUTH_PASS} - BACKEND_MAIL_AUTH_PASS=${BACKEND_MAIL_AUTH_PASS}
networks:
- dokploy-network
labels:
- "traefik.enable=true"
- "traefik.http.routers.${HASH}.rule=Host(`${TEABLE_HOST}`)"
- "traefik.http.services.${HASH}.loadbalancer.server.port=${TEABLE_PORT}"
depends_on: depends_on:
teable-db-migrate: teable-db-migrate:
condition: service_completed_successfully condition: service_completed_successfully
@@ -72,10 +64,6 @@ services:
teable-db: teable-db:
condition: service_healthy condition: service_healthy
networks:
dokploy-network:
external: true
volumes: volumes:
teable-data: {} teable-data: {}
teable-db: {} teable-db: {}

View File

@@ -1,25 +1,30 @@
import { import {
type DomainSchema,
type Schema, type Schema,
type Template, type Template,
generateHash,
generatePassword, generatePassword,
generateRandomDomain, generateRandomDomain,
} from "../utils"; } from "../utils";
export function generate(schema: Schema): Template { export function generate(schema: Schema): Template {
const mainServiceHash = generateHash(schema.projectName);
const password = generatePassword(); const password = generatePassword();
const randomDomain = generateRandomDomain(schema); const mainDomain = generateRandomDomain(schema);
const publicDbPort = ((min: number, max: number) => { const publicDbPort = ((min: number, max: number) => {
return Math.round(Math.random() * (max - min) + min); return Math.round(Math.random() * (max - min) + min);
})(32769, 65534); })(32769, 65534);
const domains: DomainSchema[] = [
{
host: mainDomain,
port: 3000,
serviceName: "teable",
},
];
const envs = [ const envs = [
`TEABLE_HOST=${randomDomain}`, `TEABLE_HOST=${mainDomain}`,
"TEABLE_PORT=3000",
`TEABLE_DB_PORT=${publicDbPort}`, `TEABLE_DB_PORT=${publicDbPort}`,
`HASH=${mainServiceHash}`,
"TIMEZONE=UTC", "TIMEZONE=UTC",
"# Postgres", "# Postgres",
"POSTGRES_HOST=teable-db", "POSTGRES_HOST=teable-db",
@@ -44,5 +49,6 @@ export function generate(schema: Schema): Template {
return { return {
envs, envs,
domains,
}; };
} }

View File

@@ -408,4 +408,19 @@ export const templates: TemplateData[] = [
tags: ["database", "spreadsheet", "low-code", "nocode"], tags: ["database", "spreadsheet", "low-code", "nocode"],
load: () => import("./teable/index").then((m) => m.generate), load: () => import("./teable/index").then((m) => m.generate),
}, },
{
id: "soketi",
name: "Soketi",
version: "v1.4-16",
description:
"Soketi is your simple, fast, and resilient open-source WebSockets server.",
logo: "soketi.png",
links: {
github: "https://github.com/soketi/soketi",
website: "https://soketi.app/",
docs: "https://docs.soketi.app/",
},
tags: ["chat"],
load: () => import("./soketi/index").then((m) => m.generate),
},
]; ];

View File

@@ -10,18 +10,10 @@ services:
depends_on: depends_on:
db: db:
condition: service_healthy condition: service_healthy
ports:
- ${UMAMI_PORT}
networks:
- dokploy-network
environment: environment:
DATABASE_URL: postgresql://umami:umami@db:5432/umami DATABASE_URL: postgresql://umami:umami@db:5432/umami
DATABASE_TYPE: postgresql DATABASE_TYPE: postgresql
APP_SECRET: ${APP_SECRET} APP_SECRET: ${APP_SECRET}
labels:
- "traefik.enable=true"
- "traefik.http.routers.${HASH}.rule=Host(`${UMAMI_HOST}`)"
- "traefik.http.services.${HASH}.loadbalancer.server.port=${UMAMI_PORT}"
db: db:
image: postgres:15-alpine image: postgres:15-alpine
restart: always restart: always
@@ -39,8 +31,5 @@ services:
POSTGRES_USER: umami POSTGRES_USER: umami
POSTGRES_PASSWORD: umami POSTGRES_PASSWORD: umami
networks:
dokploy-network:
external: true
volumes: volumes:
db-data: db-data:

View File

@@ -1,24 +1,27 @@
import { import {
type DomainSchema,
type Schema, type Schema,
type Template, type Template,
generateBase64, generateBase64,
generateHash,
generateRandomDomain, generateRandomDomain,
} from "../utils"; } from "../utils";
export function generate(schema: Schema): Template { export function generate(schema: Schema): Template {
const mainServiceHash = generateHash(schema.projectName);
const randomDomain = generateRandomDomain(schema); const randomDomain = generateRandomDomain(schema);
const randomSecret = generateBase64(); const randomSecret = generateBase64();
const envs = [ const domains: DomainSchema[] = [
`UMAMI_HOST=${randomDomain}`, {
"UMAMI_PORT=3000", host: randomDomain,
`APP_SECRET=${randomSecret}`, port: 3000,
`HASH=${mainServiceHash}`, serviceName: "umami",
},
]; ];
const envs = [`APP_SECRET=${randomSecret}`];
return { return {
envs, envs,
domains,
}; };
} }

View File

@@ -1,21 +1,10 @@
version: "3.8" version: "3.8"
services: services:
uptime-kuma: uptime-kuma:
networks:
- dokploy-network
image: louislam/uptime-kuma:1 image: louislam/uptime-kuma:1
restart: always restart: always
ports:
- ${UPTIME_KUMA_PORT}
volumes: volumes:
- uptime-kuma-data:/app/data - 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: volumes:
uptime-kuma-data: uptime-kuma-data:
networks:
dokploy-network:
external: true

View File

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

View File

@@ -1,6 +1,7 @@
import { randomBytes } from "node:crypto"; import { randomBytes } from "node:crypto";
import { readFile } from "node:fs/promises"; import { readFile } from "node:fs/promises";
import { join } from "node:path"; import { join } from "node:path";
import type { Domain } from "@/server/api/services/domain";
import { TRPCError } from "@trpc/server"; import { TRPCError } from "@trpc/server";
import { templates } from "../templates"; import { templates } from "../templates";
import type { TemplatesKeys } from "../types/templates-data.type"; import type { TemplatesKeys } from "../types/templates-data.type";
@@ -10,12 +11,15 @@ export interface Schema {
projectName: string; projectName: string;
} }
export type DomainSchema = Pick<Domain, "host" | "port" | "serviceName">;
export interface Template { export interface Template {
envs: string[]; envs?: string[];
mounts?: { mounts?: {
filePath: string; filePath: string;
content?: string; content?: string;
}[]; }[];
domains?: DomainSchema[];
} }
export const generateRandomDomain = ({ export const generateRandomDomain = ({

View File

@@ -1,20 +1,12 @@
version: '3.8' version: "3.8"
services: services:
wordpress: wordpress:
image: wordpress:5.8.3 image: wordpress:5.8.3
networks:
- dokploy-network
ports:
- ${WORDPRESS_PORT}
environment: environment:
WORDPRESS_DB_HOST: db WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: exampleuser WORDPRESS_DB_USER: exampleuser
WORDPRESS_DB_PASSWORD: examplepass WORDPRESS_DB_PASSWORD: examplepass
WORDPRESS_DB_NAME: exampledb 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: volumes:
- wordpress_data:/var/www/html - wordpress_data:/var/www/html
@@ -33,7 +25,3 @@ services:
volumes: volumes:
wordpress_data: wordpress_data:
db_data: db_data:
networks:
dokploy-network:
external: true

View File

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