mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
Merge branch 'Dokploy:canary' into feat/copy-ip
This commit is contained in:
@@ -219,21 +219,17 @@ const Service = (
|
||||
<TabsList
|
||||
className={cn(
|
||||
"md:grid md:w-fit max-md:overflow-y-scroll justify-start",
|
||||
data?.serverId ? "md:grid-cols-6" : "md:grid-cols-7",
|
||||
data?.serverId ? "md:grid-cols-7" : "md:grid-cols-7",
|
||||
data?.composeType === "docker-compose"
|
||||
? ""
|
||||
: "md:grid-cols-6",
|
||||
: "md:grid-cols-7",
|
||||
data?.serverId && data?.composeType === "stack"
|
||||
? "md:grid-cols-5"
|
||||
? "md:grid-cols-6"
|
||||
: "",
|
||||
)}
|
||||
>
|
||||
<TabsTrigger value="general">General</TabsTrigger>
|
||||
{data?.composeType === "docker-compose" && (
|
||||
<TabsTrigger value="environment">
|
||||
Environment
|
||||
</TabsTrigger>
|
||||
)}
|
||||
<TabsTrigger value="environment">Environment</TabsTrigger>
|
||||
{!data?.serverId && (
|
||||
<TabsTrigger value="monitoring">Monitoring</TabsTrigger>
|
||||
)}
|
||||
|
||||
BIN
apps/dokploy/public/templates/evolutionapi.png
Normal file
BIN
apps/dokploy/public/templates/evolutionapi.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
BIN
apps/dokploy/public/templates/formbricks.png
Normal file
BIN
apps/dokploy/public/templates/formbricks.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 73 KiB |
61
apps/dokploy/templates/evolutionapi/docker-compose.yml
Normal file
61
apps/dokploy/templates/evolutionapi/docker-compose.yml
Normal file
@@ -0,0 +1,61 @@
|
||||
services:
|
||||
evolution-api:
|
||||
image: atendai/evolution-api:v2.1.2
|
||||
restart: always
|
||||
volumes:
|
||||
- evolution-instances:/evolution/instances
|
||||
networks:
|
||||
- dokploy-network
|
||||
environment:
|
||||
- SERVER_URL=${SERVER_URL}
|
||||
- AUTHENTICATION_TYPE=${AUTHENTICATION_TYPE}
|
||||
- AUTHENTICATION_API_KEY=${AUTHENTICATION_API_KEY}
|
||||
- AUTHENTICATION_EXPOSE_IN_FETCH_INSTANCES=${AUTHENTICATION_EXPOSE_IN_FETCH_INSTANCES}
|
||||
- LANGUAGE=${LANGUAGE}
|
||||
- CONFIG_SESSION_PHONE_CLIENT=${CONFIG_SESSION_PHONE_CLIENT}
|
||||
- CONFIG_SESSION_PHONE_NAME=${CONFIG_SESSION_PHONE_NAME}
|
||||
- TELEMETRY=${TELEMETRY}
|
||||
- TELEMETRY_URL=${TELEMETRY_URL}
|
||||
- DATABASE_ENABLED=${DATABASE_ENABLED}
|
||||
- DATABASE_PROVIDER=${DATABASE_PROVIDER}
|
||||
- DATABASE_CONNECTION_URI=${DATABASE_CONNECTION_URI}
|
||||
- DATABASE_SAVE_DATA_INSTANCE=${DATABASE_SAVE_DATA_INSTANCE}
|
||||
- DATABASE_SAVE_DATA_NEW_MESSAGE=${DATABASE_SAVE_DATA_NEW_MESSAGE}
|
||||
- DATABASE_SAVE_MESSAGE_UPDATE=${DATABASE_SAVE_MESSAGE_UPDATE}
|
||||
- DATABASE_SAVE_DATA_CONTACTS=${DATABASE_SAVE_DATA_CONTACTS}
|
||||
- DATABASE_SAVE_DATA_CHATS=${DATABASE_SAVE_DATA_CHATS}
|
||||
- DATABASE_SAVE_DATA_LABELS=${DATABASE_SAVE_DATA_LABELS}
|
||||
- DATABASE_SAVE_DATA_HISTORIC=${DATABASE_SAVE_DATA_HISTORIC}
|
||||
- CACHE_REDIS_ENABLED=${CACHE_REDIS_ENABLED}
|
||||
- CACHE_REDIS_URI=${CACHE_REDIS_URI}
|
||||
- CACHE_REDIS_PREFIX_KEY=${CACHE_REDIS_PREFIX_KEY}
|
||||
- CACHE_REDIS_SAVE_INSTANCES=${CACHE_REDIS_SAVE_INSTANCES}
|
||||
|
||||
evolution-postgres:
|
||||
image: postgres:16-alpine
|
||||
restart: always
|
||||
volumes:
|
||||
- evolution-postgres-data:/var/lib/postgresql/data
|
||||
networks:
|
||||
- dokploy-network
|
||||
environment:
|
||||
- POSTGRES_DB=${POSTGRES_DATABASE}
|
||||
- POSTGRES_USER=${POSTGRES_USERNAME}
|
||||
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
|
||||
|
||||
evolution-redis:
|
||||
image: redis:alpine
|
||||
restart: always
|
||||
volumes:
|
||||
- evolution-redis-data:/data
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
networks:
|
||||
dokploy-network:
|
||||
external: true
|
||||
|
||||
volumes:
|
||||
evolution-instances:
|
||||
evolution-postgres-data:
|
||||
evolution-redis-data:
|
||||
59
apps/dokploy/templates/evolutionapi/index.ts
Normal file
59
apps/dokploy/templates/evolutionapi/index.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import {
|
||||
type DomainSchema,
|
||||
type Schema,
|
||||
type Template,
|
||||
generateBase64,
|
||||
generatePassword,
|
||||
generateRandomDomain,
|
||||
} from "../utils";
|
||||
|
||||
export function generate(schema: Schema): Template {
|
||||
const mainDomain = generateRandomDomain(schema);
|
||||
const apiKey = generateBase64(64);
|
||||
const postgresPassword = generatePassword();
|
||||
|
||||
const domains: DomainSchema[] = [
|
||||
{
|
||||
host: mainDomain,
|
||||
port: 8080,
|
||||
serviceName: "evolution-api",
|
||||
},
|
||||
];
|
||||
|
||||
const envs = [
|
||||
`SERVER_URL=https://${mainDomain}`,
|
||||
"AUTHENTICATION_TYPE=apikey",
|
||||
`AUTHENTICATION_API_KEY=${apiKey}`,
|
||||
"AUTHENTICATION_EXPOSE_IN_FETCH_INSTANCES=true",
|
||||
|
||||
"LANGUAGE=en",
|
||||
"CONFIG_SESSION_PHONE_CLIENT=Evolution API",
|
||||
"CONFIG_SESSION_PHONE_NAME=Chrome",
|
||||
"TELEMETRY=false",
|
||||
"TELEMETRY_URL=",
|
||||
|
||||
"POSTGRES_DATABASE=evolution",
|
||||
"POSTGRES_USERNAME=postgresql",
|
||||
`POSTGRES_PASSWORD=${postgresPassword}`,
|
||||
"DATABASE_ENABLED=true",
|
||||
"DATABASE_PROVIDER=postgresql",
|
||||
`DATABASE_CONNECTION_URI=postgres://postgresql:${postgresPassword}@evolution-postgres:5432/evolution`,
|
||||
"DATABASE_SAVE_DATA_INSTANCE=true",
|
||||
"DATABASE_SAVE_DATA_NEW_MESSAGE=true",
|
||||
"DATABASE_SAVE_MESSAGE_UPDATE=true",
|
||||
"DATABASE_SAVE_DATA_CONTACTS=true",
|
||||
"DATABASE_SAVE_DATA_CHATS=true",
|
||||
"DATABASE_SAVE_DATA_LABELS=true",
|
||||
"DATABASE_SAVE_DATA_HISTORIC=true",
|
||||
|
||||
"CACHE_REDIS_ENABLED=true",
|
||||
"CACHE_REDIS_URI=redis://evolution-redis:6379",
|
||||
"CACHE_REDIS_PREFIX_KEY=evolution",
|
||||
"CACHE_REDIS_SAVE_INSTANCES=true",
|
||||
];
|
||||
|
||||
return {
|
||||
domains,
|
||||
envs,
|
||||
};
|
||||
}
|
||||
38
apps/dokploy/templates/formbricks/docker-compose.yml
Normal file
38
apps/dokploy/templates/formbricks/docker-compose.yml
Normal file
@@ -0,0 +1,38 @@
|
||||
x-environment: &environment
|
||||
environment:
|
||||
WEBAPP_URL: ${WEBAPP_URL}
|
||||
NEXTAUTH_URL: ${NEXTAUTH_URL}
|
||||
DATABASE_URL: "postgresql://postgres:postgres@postgres:5432/formbricks?schema=public"
|
||||
NEXTAUTH_SECRET: ${NEXTAUTH_SECRET}
|
||||
ENCRYPTION_KEY: ${ENCRYPTION_KEY}
|
||||
CRON_SECRET: ${CRON_SECRET}
|
||||
EMAIL_VERIFICATION_DISABLED: 1
|
||||
PASSWORD_RESET_DISABLED: 1
|
||||
S3_FORCE_PATH_STYLE: 0
|
||||
|
||||
services:
|
||||
postgres:
|
||||
restart: always
|
||||
image: pgvector/pgvector:pg17
|
||||
volumes:
|
||||
- postgres:/var/lib/postgresql/data
|
||||
environment:
|
||||
- POSTGRES_PASSWORD=postgres
|
||||
networks:
|
||||
- dokploy-network
|
||||
|
||||
formbricks:
|
||||
restart: always
|
||||
image: ghcr.io/formbricks/formbricks:v3.1.3
|
||||
depends_on:
|
||||
- postgres
|
||||
ports:
|
||||
- 3000
|
||||
volumes:
|
||||
- ../files/uploads:/home/nextjs/apps/web/uploads/
|
||||
<<: *environment
|
||||
|
||||
volumes:
|
||||
postgres:
|
||||
driver: local
|
||||
uploads:
|
||||
38
apps/dokploy/templates/formbricks/index.ts
Normal file
38
apps/dokploy/templates/formbricks/index.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import {
|
||||
type DomainSchema,
|
||||
type Schema,
|
||||
type Template,
|
||||
generateBase64,
|
||||
generateRandomDomain,
|
||||
} from "../utils";
|
||||
|
||||
export function generate(schema: Schema): Template {
|
||||
const mainDomain = generateRandomDomain(schema);
|
||||
const secretBase = generateBase64(64);
|
||||
const encryptionKey = generateBase64(48);
|
||||
const cronSecret = generateBase64(32);
|
||||
|
||||
const domains: DomainSchema[] = [
|
||||
{
|
||||
host: mainDomain,
|
||||
port: 3000,
|
||||
serviceName: "formbricks",
|
||||
},
|
||||
];
|
||||
|
||||
const envs = [
|
||||
`WEBAPP_URL=http://${mainDomain}`,
|
||||
`NEXTAUTH_URL=http://${mainDomain}`,
|
||||
`NEXTAUTH_SECRET=${secretBase}`,
|
||||
`ENCRYPTION_KEY=${encryptionKey}`,
|
||||
`CRON_SECRET=${cronSecret}`,
|
||||
];
|
||||
|
||||
const mounts: Template["mounts"] = [];
|
||||
|
||||
return {
|
||||
envs,
|
||||
mounts,
|
||||
domains,
|
||||
};
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
services:
|
||||
db:
|
||||
image: postgres:13
|
||||
image: postgres:17-alpine
|
||||
ports:
|
||||
- 5432
|
||||
networks:
|
||||
@@ -19,7 +19,7 @@ services:
|
||||
- listmonk-data:/var/lib/postgresql/data
|
||||
|
||||
setup:
|
||||
image: listmonk/listmonk:v3.0.0
|
||||
image: listmonk/listmonk:v4.1.0
|
||||
networks:
|
||||
- dokploy-network
|
||||
volumes:
|
||||
@@ -35,7 +35,7 @@ services:
|
||||
|
||||
app:
|
||||
restart: unless-stopped
|
||||
image: listmonk/listmonk:v3.0.0
|
||||
image: listmonk/listmonk:v4.1.0
|
||||
environment:
|
||||
- TZ=Etc/UTC
|
||||
depends_on:
|
||||
|
||||
@@ -2,13 +2,11 @@ import {
|
||||
type DomainSchema,
|
||||
type Schema,
|
||||
type Template,
|
||||
generatePassword,
|
||||
generateRandomDomain,
|
||||
} from "../utils";
|
||||
|
||||
export function generate(schema: Schema): Template {
|
||||
const randomDomain = generateRandomDomain(schema);
|
||||
const adminPassword = generatePassword(32);
|
||||
|
||||
const domains: DomainSchema[] = [
|
||||
{
|
||||
@@ -19,7 +17,7 @@ export function generate(schema: Schema): Template {
|
||||
];
|
||||
|
||||
const envs = [
|
||||
`# login with admin:${adminPassword}`,
|
||||
"# visit the page to setup your super admin user",
|
||||
"# check config.toml in Advanced / Volumes for more options",
|
||||
];
|
||||
|
||||
@@ -29,9 +27,6 @@ export function generate(schema: Schema): Template {
|
||||
content: `[app]
|
||||
address = "0.0.0.0:9000"
|
||||
|
||||
admin_username = "admin"
|
||||
admin_password = "${adminPassword}"
|
||||
|
||||
[db]
|
||||
host = "db"
|
||||
port = 5432
|
||||
|
||||
@@ -2,7 +2,7 @@ version: "3.9"
|
||||
|
||||
services:
|
||||
teable:
|
||||
image: ghcr.io/teableio/teable:1.3.1-alpha-build.460
|
||||
image: ghcr.io/teableio/teable:latest
|
||||
restart: always
|
||||
volumes:
|
||||
- teable-data:/app/.assets
|
||||
|
||||
@@ -1239,6 +1239,21 @@ export const templates: TemplateData[] = [
|
||||
tags: ["matrix", "communication"],
|
||||
load: () => import("./conduit/index").then((m) => m.generate),
|
||||
},
|
||||
{
|
||||
id: "evolutionapi",
|
||||
name: "Evolution API",
|
||||
version: "v2.1.2",
|
||||
description:
|
||||
"Evolution API is a robust platform dedicated to empowering small businesses with limited resources, going beyond a simple messaging solution via WhatsApp.",
|
||||
logo: "evolutionapi.png",
|
||||
links: {
|
||||
github: "https://github.com/EvolutionAPI/evolution-api",
|
||||
docs: "https://doc.evolution-api.com/v2/en/get-started/introduction",
|
||||
website: "https://evolution-api.com/opensource-whatsapp-api/",
|
||||
},
|
||||
tags: ["api", "whatsapp", "messaging"],
|
||||
load: () => import("./evolutionapi/index").then((m) => m.generate),
|
||||
},
|
||||
{
|
||||
id: "conduwuit",
|
||||
name: "Conduwuit",
|
||||
@@ -1438,4 +1453,19 @@ export const templates: TemplateData[] = [
|
||||
tags: ["sharing", "shortener", "url"],
|
||||
load: () => import("./shlink/index").then((m) => m.generate),
|
||||
},
|
||||
{
|
||||
id: "formbricks",
|
||||
name: "Formbricks",
|
||||
version: "v3.1.3",
|
||||
description:
|
||||
"Formbricks is an open-source survey and form platform for collecting user data.",
|
||||
logo: "formbricks.png",
|
||||
links: {
|
||||
github: "https://github.com/formbricks/formbricks",
|
||||
website: "https://formbricks.com/",
|
||||
docs: "https://formbricks.com/docs",
|
||||
},
|
||||
tags: ["forms", "analytics"],
|
||||
load: () => import("./formbricks/index").then((m) => m.generate),
|
||||
},
|
||||
];
|
||||
|
||||
@@ -558,6 +558,17 @@ export const stopCompose = async (composeId: string) => {
|
||||
}
|
||||
}
|
||||
|
||||
if (compose.composeType === "stack") {
|
||||
if (compose.serverId) {
|
||||
await execAsyncRemote(
|
||||
compose.serverId,
|
||||
`docker stack rm ${compose.appName}`,
|
||||
);
|
||||
} else {
|
||||
await execAsync(`docker stack rm ${compose.appName}`);
|
||||
}
|
||||
}
|
||||
|
||||
await updateCompose(composeId, {
|
||||
composeStatus: "idle",
|
||||
});
|
||||
|
||||
@@ -2,6 +2,7 @@ import {
|
||||
createWriteStream,
|
||||
existsSync,
|
||||
mkdirSync,
|
||||
readFileSync,
|
||||
writeFileSync,
|
||||
} from "node:fs";
|
||||
import { dirname, join } from "node:path";
|
||||
@@ -12,8 +13,12 @@ import {
|
||||
writeDomainsToCompose,
|
||||
writeDomainsToComposeRemote,
|
||||
} from "../docker/domain";
|
||||
import { encodeBase64, prepareEnvironmentVariables } from "../docker/utils";
|
||||
import { execAsyncRemote } from "../process/execAsync";
|
||||
import {
|
||||
encodeBase64,
|
||||
getEnviromentVariablesObject,
|
||||
prepareEnvironmentVariables,
|
||||
} from "../docker/utils";
|
||||
import { execAsync, execAsyncRemote } from "../process/execAsync";
|
||||
import { spawnAsync } from "../process/spawnAsync";
|
||||
|
||||
export type ComposeNested = InferResultType<
|
||||
@@ -30,12 +35,12 @@ export const buildCompose = async (compose: ComposeNested, logPath: string) => {
|
||||
createEnvFile(compose);
|
||||
|
||||
const logContent = `
|
||||
App Name: ${appName}
|
||||
Build Compose 🐳
|
||||
Detected: ${mounts.length} mounts 📂
|
||||
Command: docker ${command}
|
||||
Source Type: docker ${sourceType} ✅
|
||||
Compose Type: ${composeType} ✅`;
|
||||
App Name: ${appName}
|
||||
Build Compose 🐳
|
||||
Detected: ${mounts.length} mounts 📂
|
||||
Command: docker ${command}
|
||||
Source Type: docker ${sourceType} ✅
|
||||
Compose Type: ${composeType} ✅`;
|
||||
const logBox = boxen(logContent, {
|
||||
padding: {
|
||||
left: 1,
|
||||
@@ -46,7 +51,6 @@ Compose Type: ${composeType} ✅`;
|
||||
borderStyle: "double",
|
||||
});
|
||||
writeStream.write(`\n${logBox}\n`);
|
||||
|
||||
const projectPath = join(COMPOSE_PATH, compose.appName, "code");
|
||||
|
||||
await spawnAsync(
|
||||
@@ -62,6 +66,9 @@ Compose Type: ${composeType} ✅`;
|
||||
env: {
|
||||
NODE_ENV: process.env.NODE_ENV,
|
||||
PATH: process.env.PATH,
|
||||
...(composeType === "stack" && {
|
||||
...getEnviromentVariablesObject(compose.env, compose.project.env),
|
||||
}),
|
||||
},
|
||||
},
|
||||
);
|
||||
@@ -85,6 +92,7 @@ export const getBuildComposeCommand = async (
|
||||
const command = createCommand(compose);
|
||||
const envCommand = getCreateEnvFileCommand(compose);
|
||||
const projectPath = join(COMPOSE_PATH, compose.appName, "code");
|
||||
const exportEnvCommand = getExportEnvCommand(compose);
|
||||
|
||||
const newCompose = await writeDomainsToComposeRemote(
|
||||
compose,
|
||||
@@ -120,6 +128,8 @@ Compose Type: ${composeType} ✅`;
|
||||
|
||||
cd "${projectPath}";
|
||||
|
||||
${exportEnvCommand}
|
||||
|
||||
docker ${command.split(" ").join(" ")} >> "${logPath}" 2>&1 || { echo "Error: ❌ Docker command failed" >> "${logPath}"; exit 1; }
|
||||
|
||||
echo "Docker Compose Deployed: ✅" >> "${logPath}"
|
||||
@@ -153,9 +163,7 @@ export const createCommand = (compose: ComposeNested) => {
|
||||
sourceType === "raw" ? "docker-compose.yml" : compose.composePath;
|
||||
let command = "";
|
||||
|
||||
if (composeType === "docker-compose") {
|
||||
command = `compose -p ${appName} -f ${path} up -d --build --remove-orphans`;
|
||||
} else if (composeType === "stack") {
|
||||
if (composeType === "stack") {
|
||||
command = `stack deploy -c ${path} ${appName} --prune`;
|
||||
}
|
||||
|
||||
@@ -219,3 +227,17 @@ touch ${envFilePath};
|
||||
echo "${encodedContent}" | base64 -d > "${envFilePath}";
|
||||
`;
|
||||
};
|
||||
|
||||
const getExportEnvCommand = (compose: ComposeNested) => {
|
||||
if (compose.composeType !== "stack") return "";
|
||||
|
||||
const envVars = getEnviromentVariablesObject(
|
||||
compose.env,
|
||||
compose.project.env,
|
||||
);
|
||||
const exports = Object.entries(envVars)
|
||||
.map(([key, value]) => `export ${key}=${JSON.stringify(value)}`)
|
||||
.join("\n");
|
||||
|
||||
return exports ? `\n# Export environment variables\n${exports}\n` : "";
|
||||
};
|
||||
|
||||
@@ -278,12 +278,15 @@ export const prepareEnvironmentVariables = (
|
||||
return resolvedVars;
|
||||
};
|
||||
|
||||
export const prepareBuildArgs = (input: string | null) => {
|
||||
const pairs = (input ?? "").split("\n");
|
||||
export const getEnviromentVariablesObject = (
|
||||
input: string | null,
|
||||
projectEnv?: string | null,
|
||||
) => {
|
||||
const envs = prepareEnvironmentVariables(input, projectEnv);
|
||||
|
||||
const jsonObject: Record<string, string> = {};
|
||||
|
||||
for (const pair of pairs) {
|
||||
for (const pair of envs) {
|
||||
const [key, value] = pair.split("=");
|
||||
if (key && value) {
|
||||
jsonObject[key] = value;
|
||||
|
||||
Reference in New Issue
Block a user