diff --git a/apps/dokploy/components/layouts/dashboard-layout.tsx b/apps/dokploy/components/layouts/dashboard-layout.tsx index 8dd7e599..451ec45d 100644 --- a/apps/dokploy/components/layouts/dashboard-layout.tsx +++ b/apps/dokploy/components/layouts/dashboard-layout.tsx @@ -1,25 +1,34 @@ +import Head from "next/head"; import { Navbar } from "./navbar"; import { NavigationTabs, type TabState } from "./navigation-tabs"; interface Props { children: React.ReactNode; tab: TabState; + metaName?: string; } -export const DashboardLayout = ({ children, tab }: Props) => { +export const DashboardLayout = ({ children, tab, metaName }: Props) => { return ( -
-
- -
-
- {children} -
-
+ <> + + + {metaName ?? tab.charAt(0).toUpperCase() + tab.slice(1)} | Dokploy + + +
+
+ +
+
+ {children} +
+
+
-
+ ); }; diff --git a/apps/dokploy/pages/dashboard/project/[projectId].tsx b/apps/dokploy/pages/dashboard/project/[projectId].tsx index 82b43ae5..5fd8bd62 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId].tsx @@ -39,6 +39,7 @@ import type { GetServerSidePropsContext, InferGetServerSidePropsType, } from "next"; +import Head from "next/head"; import Link from "next/link"; import { useRouter } from "next/router"; import React, { type ReactElement } from "react"; @@ -189,6 +190,9 @@ const Project = ( {data?.name} + + Project {data?.name} | Dokploy +

{data?.name}

diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx index bcbd4b78..1682348c 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx @@ -41,6 +41,7 @@ import type { GetServerSidePropsContext, InferGetServerSidePropsType, } from "next"; +import Head from "next/head"; import Link from "next/link"; import { useRouter } from "next/router"; import React, { useState, type ReactElement } from "react"; @@ -101,6 +102,11 @@ const Service = ( {data?.name} + + + Project {data?.project.name} | {data?.name} | Dokploy + +
diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx index 60ddfeab..6b9cae51 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx @@ -35,6 +35,7 @@ import type { GetServerSidePropsContext, InferGetServerSidePropsType, } from "next"; +import Head from "next/head"; import Link from "next/link"; import { useRouter } from "next/router"; import React, { useState, type ReactElement } from "react"; @@ -94,6 +95,11 @@ const Service = ( {data?.name} + + + Project {data?.project.name} | {data?.name} | Dokploy + +
diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/mariadb/[mariadbId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/mariadb/[mariadbId].tsx index 31e92976..0a5cfed8 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/mariadb/[mariadbId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/mariadb/[mariadbId].tsx @@ -35,6 +35,7 @@ import type { GetServerSidePropsContext, InferGetServerSidePropsType, } from "next"; +import Head from "next/head"; import Link from "next/link"; import { useRouter } from "next/router"; import React, { useState, type ReactElement } from "react"; @@ -82,6 +83,11 @@ const Mariadb = ( {data?.name} + + + Project {data?.project.name} | {data?.name} | Dokploy + +
diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/mongo/[mongoId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/mongo/[mongoId].tsx index 409d9129..fcf39eff 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/mongo/[mongoId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/mongo/[mongoId].tsx @@ -35,6 +35,7 @@ import type { GetServerSidePropsContext, InferGetServerSidePropsType, } from "next"; +import Head from "next/head"; import Link from "next/link"; import { useRouter } from "next/router"; import React, { useState, type ReactElement } from "react"; @@ -83,6 +84,11 @@ const Mongo = ( {data?.name} + + + Project {data?.project.name} | {data?.name} | Dokploy + +
diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/mysql/[mysqlId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/mysql/[mysqlId].tsx index e69c5a35..4d155e64 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/mysql/[mysqlId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/mysql/[mysqlId].tsx @@ -35,6 +35,7 @@ import type { GetServerSidePropsContext, InferGetServerSidePropsType, } from "next"; +import Head from "next/head"; import Link from "next/link"; import { useRouter } from "next/router"; import React, { useState, type ReactElement } from "react"; @@ -81,6 +82,11 @@ const MySql = ( {data?.name} + + + Project {data?.project.name} | {data?.name} | Dokploy + +
diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/postgres/[postgresId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/postgres/[postgresId].tsx index 3e1e3ea8..c7152dd5 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/postgres/[postgresId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/postgres/[postgresId].tsx @@ -35,6 +35,7 @@ import type { GetServerSidePropsContext, InferGetServerSidePropsType, } from "next"; +import Head from "next/head"; import Link from "next/link"; import { useRouter } from "next/router"; import React, { useState, type ReactElement } from "react"; @@ -82,6 +83,11 @@ const Postgresql = ( {data?.name} + + + Project {data?.project.name} | {data?.name} | Dokploy + +
diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/redis/[redisId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/redis/[redisId].tsx index b68baeab..f4bf3743 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/redis/[redisId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/redis/[redisId].tsx @@ -34,6 +34,7 @@ import type { GetServerSidePropsContext, InferGetServerSidePropsType, } from "next"; +import Head from "next/head"; import Link from "next/link"; import { useRouter } from "next/router"; import React, { useState, type ReactElement } from "react"; @@ -81,6 +82,11 @@ const Redis = ( {data?.name} + + + Project {data?.project.name} | {data?.name} | Dokploy + +
diff --git a/apps/dokploy/pages/dashboard/settings/appearance.tsx b/apps/dokploy/pages/dashboard/settings/appearance.tsx index f7f49746..51c61fc7 100644 --- a/apps/dokploy/pages/dashboard/settings/appearance.tsx +++ b/apps/dokploy/pages/dashboard/settings/appearance.tsx @@ -21,7 +21,7 @@ export default Page; Page.getLayout = (page: ReactElement) => { return ( - + {page} ); diff --git a/apps/dokploy/pages/dashboard/settings/billing.tsx b/apps/dokploy/pages/dashboard/settings/billing.tsx index 4aa7682c..191f25e2 100644 --- a/apps/dokploy/pages/dashboard/settings/billing.tsx +++ b/apps/dokploy/pages/dashboard/settings/billing.tsx @@ -16,7 +16,7 @@ export default Page; Page.getLayout = (page: ReactElement) => { return ( - + {page} ); diff --git a/apps/dokploy/pages/dashboard/settings/certificates.tsx b/apps/dokploy/pages/dashboard/settings/certificates.tsx index e64db687..c648ad38 100644 --- a/apps/dokploy/pages/dashboard/settings/certificates.tsx +++ b/apps/dokploy/pages/dashboard/settings/certificates.tsx @@ -19,7 +19,7 @@ export default Page; Page.getLayout = (page: ReactElement) => { return ( - + {page} ); diff --git a/apps/dokploy/pages/dashboard/settings/cluster.tsx b/apps/dokploy/pages/dashboard/settings/cluster.tsx index 3320a9c3..f01294cd 100644 --- a/apps/dokploy/pages/dashboard/settings/cluster.tsx +++ b/apps/dokploy/pages/dashboard/settings/cluster.tsx @@ -20,7 +20,7 @@ export default Page; Page.getLayout = (page: ReactElement) => { return ( - + {page} ); diff --git a/apps/dokploy/pages/dashboard/settings/destinations.tsx b/apps/dokploy/pages/dashboard/settings/destinations.tsx index fdf91ca1..9653d4a1 100644 --- a/apps/dokploy/pages/dashboard/settings/destinations.tsx +++ b/apps/dokploy/pages/dashboard/settings/destinations.tsx @@ -20,7 +20,7 @@ export default Page; Page.getLayout = (page: ReactElement) => { return ( - + {page} ); diff --git a/apps/dokploy/pages/dashboard/settings/git-providers.tsx b/apps/dokploy/pages/dashboard/settings/git-providers.tsx index b5862eb9..cab53928 100644 --- a/apps/dokploy/pages/dashboard/settings/git-providers.tsx +++ b/apps/dokploy/pages/dashboard/settings/git-providers.tsx @@ -20,7 +20,7 @@ export default Page; Page.getLayout = (page: ReactElement) => { return ( - + {page} ); diff --git a/apps/dokploy/pages/dashboard/settings/notifications.tsx b/apps/dokploy/pages/dashboard/settings/notifications.tsx index d783355e..cdc47fc0 100644 --- a/apps/dokploy/pages/dashboard/settings/notifications.tsx +++ b/apps/dokploy/pages/dashboard/settings/notifications.tsx @@ -20,7 +20,7 @@ export default Page; Page.getLayout = (page: ReactElement) => { return ( - + {page} ); diff --git a/apps/dokploy/pages/dashboard/settings/profile.tsx b/apps/dokploy/pages/dashboard/settings/profile.tsx index a645a4af..87a285b1 100644 --- a/apps/dokploy/pages/dashboard/settings/profile.tsx +++ b/apps/dokploy/pages/dashboard/settings/profile.tsx @@ -33,7 +33,7 @@ export default Page; Page.getLayout = (page: ReactElement) => { return ( - + {page} ); diff --git a/apps/dokploy/pages/dashboard/settings/registry.tsx b/apps/dokploy/pages/dashboard/settings/registry.tsx index 16fded94..7cadd495 100644 --- a/apps/dokploy/pages/dashboard/settings/registry.tsx +++ b/apps/dokploy/pages/dashboard/settings/registry.tsx @@ -20,7 +20,7 @@ export default Page; Page.getLayout = (page: ReactElement) => { return ( - + {page} ); diff --git a/apps/dokploy/pages/dashboard/settings/server.tsx b/apps/dokploy/pages/dashboard/settings/server.tsx index c1d3d548..2ea721fc 100644 --- a/apps/dokploy/pages/dashboard/settings/server.tsx +++ b/apps/dokploy/pages/dashboard/settings/server.tsx @@ -23,7 +23,7 @@ export default Page; Page.getLayout = (page: ReactElement) => { return ( - + {page} ); diff --git a/apps/dokploy/pages/dashboard/settings/servers.tsx b/apps/dokploy/pages/dashboard/settings/servers.tsx index a7c104a1..7aea531b 100644 --- a/apps/dokploy/pages/dashboard/settings/servers.tsx +++ b/apps/dokploy/pages/dashboard/settings/servers.tsx @@ -20,7 +20,7 @@ export default Page; Page.getLayout = (page: ReactElement) => { return ( - + {page} ); diff --git a/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx b/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx index 55b97976..808e4e8c 100644 --- a/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx +++ b/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx @@ -20,7 +20,7 @@ export default Page; Page.getLayout = (page: ReactElement) => { return ( - + {page} ); diff --git a/apps/dokploy/pages/dashboard/settings/users.tsx b/apps/dokploy/pages/dashboard/settings/users.tsx index f8628459..d1b598e4 100644 --- a/apps/dokploy/pages/dashboard/settings/users.tsx +++ b/apps/dokploy/pages/dashboard/settings/users.tsx @@ -20,7 +20,7 @@ export default Page; Page.getLayout = (page: ReactElement) => { return ( - + {page} ); diff --git a/apps/dokploy/public/templates/huly.svg b/apps/dokploy/public/templates/huly.svg new file mode 100644 index 00000000..55a98587 --- /dev/null +++ b/apps/dokploy/public/templates/huly.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/dokploy/public/templates/langflow.svg b/apps/dokploy/public/templates/langflow.svg new file mode 100644 index 00000000..3665f824 --- /dev/null +++ b/apps/dokploy/public/templates/langflow.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/apps/dokploy/public/templates/penpot.svg b/apps/dokploy/public/templates/penpot.svg new file mode 100644 index 00000000..05454092 --- /dev/null +++ b/apps/dokploy/public/templates/penpot.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/dokploy/public/templates/unsend.png b/apps/dokploy/public/templates/unsend.png new file mode 100644 index 00000000..0bbe5e0f Binary files /dev/null and b/apps/dokploy/public/templates/unsend.png differ diff --git a/apps/dokploy/templates/huly/docker-compose.yml b/apps/dokploy/templates/huly/docker-compose.yml new file mode 100644 index 00000000..471ee7e9 --- /dev/null +++ b/apps/dokploy/templates/huly/docker-compose.yml @@ -0,0 +1,184 @@ +name: ${DOCKER_NAME} +version: "3" +services: + nginx: + networks: + - dokploy-network + image: "nginx:1.21.3" + ports: + - 80 + volumes: + - ../files/volumes/nginx/.huly.nginx:/etc/nginx/conf.d/default.conf + restart: unless-stopped + + mongodb: + networks: + - dokploy-network + image: "mongo:7-jammy" + environment: + - PUID=1000 + - PGID=1000 + volumes: + - db:/data/db + restart: unless-stopped + + minio: + networks: + - dokploy-network + image: "minio/minio:RELEASE.2024-11-07T00-52-20Z" + command: server /data --address ":9000" --console-address ":9001" + volumes: + - files:/data + restart: unless-stopped + + elastic: + networks: + - dokploy-network + image: "elasticsearch:7.14.2" + command: | + /bin/sh -c "./bin/elasticsearch-plugin list | grep -q ingest-attachment || yes | ./bin/elasticsearch-plugin install --silent ingest-attachment; + /usr/local/bin/docker-entrypoint.sh eswrapper" + volumes: + - elastic:/usr/share/elasticsearch/data + environment: + - ELASTICSEARCH_PORT_NUMBER=9200 + - BITNAMI_DEBUG=true + - discovery.type=single-node + - ES_JAVA_OPTS=-Xms1024m -Xmx1024m + - http.cors.enabled=true + - http.cors.allow-origin=http://localhost:8082 + healthcheck: + interval: 20s + retries: 10 + test: curl -s http://localhost:9200/_cluster/health | grep -vq '"status":"red"' + restart: unless-stopped + + rekoni: + networks: + - dokploy-network + image: hardcoreeng/rekoni-service:${HULY_VERSION} + environment: + - SECRET=${SECRET} + deploy: + resources: + limits: + memory: 500M + restart: unless-stopped + + transactor: + networks: + - dokploy-network + image: hardcoreeng/transactor:${HULY_VERSION} + environment: + - SERVER_PORT=3333 + - SERVER_SECRET=${SECRET} + - SERVER_CURSOR_MAXTIMEMS=30000 + - DB_URL=mongodb://mongodb:27017 + - MONGO_URL=mongodb://mongodb:27017 + - STORAGE_CONFIG=minio|minio?accessKey=minioadmin&secretKey=minioadmin + - FRONT_URL=http://localhost:8087 + - ACCOUNTS_URL=http://account:3000 + - FULLTEXT_URL=http://fulltext:4700 + - STATS_URL=http://stats:4900 + - LAST_NAME_FIRST=${LAST_NAME_FIRST:-true} + restart: unless-stopped + + collaborator: + networks: + - dokploy-network + image: hardcoreeng/collaborator:${HULY_VERSION} + environment: + - COLLABORATOR_PORT=3078 + - SECRET=${SECRET} + - ACCOUNTS_URL=http://account:3000 + - DB_URL=mongodb://mongodb:27017 + - STATS_URL=http://stats:4900 + - STORAGE_CONFIG=minio|minio?accessKey=minioadmin&secretKey=minioadmin + restart: unless-stopped + + account: + networks: + - dokploy-network + image: hardcoreeng/account:${HULY_VERSION} + environment: + - SERVER_PORT=3000 + - SERVER_SECRET=${SECRET} + - DB_URL=mongodb://mongodb:27017 + - MONGO_URL=mongodb://mongodb:27017 + - TRANSACTOR_URL=ws://transactor:3333;ws${SECURE:+s}://${HOST_ADDRESS}/_transactor + - STORAGE_CONFIG=minio|minio?accessKey=minioadmin&secretKey=minioadmin + - FRONT_URL=http://front:8080 + - STATS_URL=http://stats:4900 + - MODEL_ENABLED=* + - ACCOUNTS_URL=http://localhost:3000 + - ACCOUNT_PORT=3000 + restart: unless-stopped + + workspace: + networks: + - dokploy-network + image: hardcoreeng/workspace:${HULY_VERSION} + environment: + - SERVER_SECRET=${SECRET} + - DB_URL=mongodb://mongodb:27017 + - MONGO_URL=mongodb://mongodb:27017 + - TRANSACTOR_URL=ws://transactor:3333;ws${SECURE:+s}://${HOST_ADDRESS}/_transactor + - STORAGE_CONFIG=minio|minio?accessKey=minioadmin&secretKey=minioadmin + - MODEL_ENABLED=* + - ACCOUNTS_URL=http://account:3000 + - STATS_URL=http://stats:4900 + restart: unless-stopped + + front: + networks: + - dokploy-network + image: hardcoreeng/front:${HULY_VERSION} + environment: + - SERVER_PORT=8080 + - SERVER_SECRET=${SECRET} + - LOVE_ENDPOINT=http${SECURE:+s}://${HOST_ADDRESS}/_love + - ACCOUNTS_URL=http${SECURE:+s}://${HOST_ADDRESS}/_accounts + - REKONI_URL=http${SECURE:+s}://${HOST_ADDRESS}/_rekoni + - CALENDAR_URL=http${SECURE:+s}://${HOST_ADDRESS}/_calendar + - GMAIL_URL=http${SECURE:+s}://${HOST_ADDRESS}/_gmail + - TELEGRAM_URL=http${SECURE:+s}://${HOST_ADDRESS}/_telegram + - STATS_URL=http${SECURE:+s}://${HOST_ADDRESS}/_stats + - UPLOAD_URL=/files + - ELASTIC_URL=http://elastic:9200 + - COLLABORATOR_URL=ws${SECURE:+s}://${HOST_ADDRESS}/_collaborator + - STORAGE_CONFIG=minio|minio?accessKey=minioadmin&secretKey=minioadmin + - DB_URL=mongodb://mongodb:27017 + - MONGO_URL=mongodb://mongodb:27017 + - TITLE=${TITLE:-Huly Self Host} + - DEFAULT_LANGUAGE=${DEFAULT_LANGUAGE:-en} + - LAST_NAME_FIRST=${LAST_NAME_FIRST:-true} + - DESKTOP_UPDATES_CHANNEL=selfhost + restart: unless-stopped + + fulltext: + networks: + - dokploy-network + image: hardcoreeng/fulltext:${HULY_VERSION} + environment: + - SERVER_SECRET=${SECRET} + - DB_URL=mongodb://mongodb:27017 + - FULLTEXT_DB_URL=http://elastic:9200 + - ELASTIC_INDEX_NAME=huly_storage_index + - STORAGE_CONFIG=minio|minio?accessKey=minioadmin&secretKey=minioadmin + - REKONI_URL=http://rekoni:4004 + - ACCOUNTS_URL=http://account:3000 + - STATS_URL=http://stats:4900 + restart: unless-stopped + + stats: + networks: + - dokploy-network + image: hardcoreeng/stats:${HULY_VERSION} + environment: + - PORT=4900 + - SERVER_SECRET=${SECRET} + restart: unless-stopped +volumes: + db: + elastic: + files: diff --git a/apps/dokploy/templates/huly/index.ts b/apps/dokploy/templates/huly/index.ts new file mode 100644 index 00000000..deb5c7db --- /dev/null +++ b/apps/dokploy/templates/huly/index.ts @@ -0,0 +1,152 @@ +import { + type DomainSchema, + type Schema, + type Template, + generateBase64, + generateRandomDomain, +} from "../utils"; + +export function generate(schema: Schema): Template { + const mainDomain = generateRandomDomain(schema); + const hulySecret = generateBase64(64); + const domains: DomainSchema[] = [ + { + host: generateRandomDomain(schema), + port: 80, + serviceName: "nginx", + }, + ]; + + const envs = [ + "HULY_VERSION=v0.6.377", + "DOCKER_NAME=huly", + "", + "# The address of the host or server from which you will access your Huly instance.", + "# This can be a domain name (e.g., huly.example.com) or an IP address (e.g., 192.168.1.1).", + `HOST_ADDRESS=${mainDomain}`, + "", + "# Set this variable to 'true' to enable SSL (HTTPS/WSS). ", + "# Leave it empty to use non-SSL (HTTP/WS).", + "SECURE=", + "", + "# Specify the IP address to bind to; leave blank to bind to all interfaces (0.0.0.0).", + "# Do not use IP:PORT format in HTTP_BIND or HTTP_PORT.", + "HTTP_PORT=80", + "HTTP_BIND=", + "", + "# Huly specific variables", + "TITLE=Huly", + "DEFAULT_LANGUAGE=en", + "LAST_NAME_FIRST=true", + "", + "# The following configs are auto-generated by the setup script. ", + "# Please do not manually overwrite.", + "", + "# Run with --secret to regenerate.", + `SECRET=${hulySecret}`, + ]; + + const mounts: Template["mounts"] = [ + { + filePath: "/volumes/nginx/.huly.nginx", + content: `server { + listen 80; + server_name _; + location / { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_pass http://front:8080; + } + + location /_accounts { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + rewrite ^/_accounts(/.*)$ $1 break; + proxy_pass http://account:3000/; + } + + #location /_love { + # proxy_set_header Host $host; + # proxy_set_header X-Real-IP $remote_addr; + # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + # proxy_set_header X-Forwarded-Proto $scheme; + + # proxy_http_version 1.1; + # proxy_set_header Upgrade $http_upgrade; + # proxy_set_header Connection "upgrade"; + # rewrite ^/_love(/.*)$ $1 break; + # proxy_pass http://love:8096/; + #} + + location /_collaborator { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + rewrite ^/_collaborator(/.*)$ $1 break; + proxy_pass http://collaborator:3078/; + } + + location /_transactor { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + rewrite ^/_transactor(/.*)$ $1 break; + proxy_pass http://transactor:3333/; + } + + location ~ ^/eyJ { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_pass http://transactor:3333; + } + + location /_rekoni { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + rewrite ^/_rekoni(/.*)$ $1 break; + proxy_pass http://rekoni:4004/; + } + + location /_stats { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + rewrite ^/_stats(/.*)$ $1 break; + proxy_pass http://stats:4900/; + } +}`, + }, + ]; + + return { + domains, + envs, + mounts, + }; +} diff --git a/apps/dokploy/templates/langflow/docker-compose.yml b/apps/dokploy/templates/langflow/docker-compose.yml new file mode 100644 index 00000000..75bb73dd --- /dev/null +++ b/apps/dokploy/templates/langflow/docker-compose.yml @@ -0,0 +1,33 @@ +version: "3.8" + +services: + langflow: + image: langflowai/langflow:v1.1.1 + ports: + - 7860 + depends_on: + - postgres-langflow + environment: + - LANGFLOW_DATABASE_URL=postgresql://${DB_USERNAME}:${DB_PASSWORD}@postgres-langflow:5432/langflow + # This variable defines where the logs, file storage, monitor data and secret keys are stored. + volumes: + - langflow-data:/app/langflow + networks: + - dokploy-network + + postgres-langflow: + image: postgres:16 + environment: + POSTGRES_USER: ${DB_USERNAME} + POSTGRES_PASSWORD: ${DB_PASSWORD} + POSTGRES_DB: langflow + ports: + - 5432 + volumes: + - langflow-postgres:/var/lib/postgresql/data + networks: + - dokploy-network + +volumes: + langflow-postgres: + langflow-data: \ No newline at end of file diff --git a/apps/dokploy/templates/langflow/index.ts b/apps/dokploy/templates/langflow/index.ts new file mode 100644 index 00000000..75f6db58 --- /dev/null +++ b/apps/dokploy/templates/langflow/index.ts @@ -0,0 +1,28 @@ +import { + type DomainSchema, + type Schema, + type Template, + generatePassword, + generateRandomDomain, +} from "../utils"; + +export function generate(schema: Schema): Template { + const mainDomain = generateRandomDomain(schema); + const dbPassword = generatePassword(); + const dbUsername = "langflow"; + + const domains: DomainSchema[] = [ + { + host: mainDomain, + port: 7860, + serviceName: "langflow", + }, + ]; + + const envs = [`DB_PASSWORD=${dbPassword}`, `DB_USERNAME=${dbUsername}`]; + + return { + domains, + envs, + }; +} diff --git a/apps/dokploy/templates/penpot/docker-compose.yml b/apps/dokploy/templates/penpot/docker-compose.yml new file mode 100644 index 00000000..55abdb53 --- /dev/null +++ b/apps/dokploy/templates/penpot/docker-compose.yml @@ -0,0 +1,213 @@ +## Common flags: +# demo-users +# email-verification +# log-emails +# log-invitation-tokens +# login-with-github +# login-with-gitlab +# login-with-google +# login-with-ldap +# login-with-oidc +# login-with-password +# prepl-server +# registration +# secure-session-cookies +# smtp +# smtp-debug +# telemetry +# webhooks +## +## You can read more about all available flags and other +## environment variables here: +## https://help.penpot.app/technical-guide/configuration/#advanced-configuration +# +# WARNING: if you're exposing Penpot to the internet, you should remove the flags +# 'disable-secure-session-cookies' and 'disable-email-verification' + +volumes: + penpot_postgres_v15: + penpot_assets: + penpot_traefik: + # penpot_minio: + +services: + + penpot-frontend: + image: "penpotapp/frontend:2.3.2" + restart: always + ports: + - 8080 + - 9001 + + volumes: + - penpot_assets:/opt/data/assets + + depends_on: + - penpot-backend + - penpot-exporter + + networks: + - dokploy-network + + environment: + PENPOT_FLAGS: disable-email-verification enable-smtp enable-prepl-server disable-secure-session-cookies + + penpot-backend: + image: "penpotapp/backend:2.3.2" + restart: always + + volumes: + - penpot_assets:/opt/data/assets + + depends_on: + - penpot-postgres + - penpot-redis + + networks: + - dokploy-network + + ## Configuration envronment variables for the backend + ## container. + + environment: + PENPOT_PUBLIC_URI: http://${DOMAIN_NAME} + PENPOT_FLAGS: disable-email-verification enable-smtp enable-prepl-server disable-secure-session-cookies + + ## Penpot SECRET KEY. It serves as a master key from which other keys for subsystems + ## (eg http sessions, or invitations) are derived. + ## + ## If you leave it commented, all created sessions and invitations will + ## become invalid on container restart. + ## + ## If you going to uncomment this, we recommend to use a trully randomly generated + ## 512 bits base64 encoded string here. You can generate one with: + ## + ## python3 -c "import secrets; print(secrets.token_urlsafe(64))" + + # PENPOT_SECRET_KEY: my-insecure-key + + ## The PREPL host. Mainly used for external programatic access to penpot backend + ## (example: admin). By default it will listen on `localhost` but if you are going to use + ## the `admin`, you will need to uncomment this and set the host to `0.0.0.0`. + + # PENPOT_PREPL_HOST: 0.0.0.0 + + ## Database connection parameters. Don't touch them unless you are using custom + ## postgresql connection parameters. + + PENPOT_DATABASE_URI: postgresql://penpot-postgres/penpot + PENPOT_DATABASE_USERNAME: penpot + PENPOT_DATABASE_PASSWORD: penpot + + ## Redis is used for the websockets notifications. Don't touch unless the redis + ## container has different parameters or different name. + + PENPOT_REDIS_URI: redis://penpot-redis/0 + + ## Default configuration for assets storage: using filesystem based with all files + ## stored in a docker volume. + + PENPOT_ASSETS_STORAGE_BACKEND: assets-fs + PENPOT_STORAGE_ASSETS_FS_DIRECTORY: /opt/data/assets + + ## Also can be configured to to use a S3 compatible storage + ## service like MiniIO. Look below for minio service setup. + + # AWS_ACCESS_KEY_ID: + # AWS_SECRET_ACCESS_KEY: + # PENPOT_ASSETS_STORAGE_BACKEND: assets-s3 + # PENPOT_STORAGE_ASSETS_S3_ENDPOINT: http://penpot-minio:9000 + # PENPOT_STORAGE_ASSETS_S3_BUCKET: + + ## Telemetry. When enabled, a periodical process will send anonymous data about this + ## instance. Telemetry data will enable us to learn how the application is used, + ## based on real scenarios. If you want to help us, please leave it enabled. You can + ## audit what data we send with the code available on github. + + PENPOT_TELEMETRY_ENABLED: true + + ## Example SMTP/Email configuration. By default, emails are sent to the mailcatch + ## service, but for production usage it is recommended to setup a real SMTP + ## provider. Emails are used to confirm user registrations & invitations. Look below + ## how the mailcatch service is configured. + + PENPOT_SMTP_DEFAULT_FROM: no-reply@example.com + PENPOT_SMTP_DEFAULT_REPLY_TO: no-reply@example.com + PENPOT_SMTP_HOST: penpot-mailcatch + PENPOT_SMTP_PORT: 1025 + PENPOT_SMTP_USERNAME: + PENPOT_SMTP_PASSWORD: + PENPOT_SMTP_TLS: false + PENPOT_SMTP_SSL: false + + penpot-exporter: + image: "penpotapp/exporter:2.3.2" + restart: always + networks: + - dokploy-network + + environment: + # Don't touch it; this uses an internal docker network to + # communicate with the frontend. + PENPOT_PUBLIC_URI: http://penpot-frontend + + ## Redis is used for the websockets notifications. + PENPOT_REDIS_URI: redis://penpot-redis/0 + + penpot-postgres: + image: "postgres:15" + restart: always + stop_signal: SIGINT + + volumes: + - penpot_postgres_v15:/var/lib/postgresql/data + + networks: + - dokploy-network + + environment: + - POSTGRES_INITDB_ARGS=--data-checksums + - POSTGRES_DB=penpot + - POSTGRES_USER=penpot + - POSTGRES_PASSWORD=penpot + + penpot-redis: + image: redis:7.2 + restart: always + networks: + - dokploy-network + + ## A mailcatch service, used as temporal SMTP server. You can access via HTTP to the + ## port 1080 for read all emails the penpot platform has sent. Should be only used as a + ## temporal solution while no real SMTP provider is configured. + + penpot-mailcatch: + image: sj26/mailcatcher:latest + restart: always + expose: + - '1025' + ports: + - 1080 + networks: + - dokploy-network + + ## Example configuration of MiniIO (S3 compatible object storage service); If you don't + ## have preference, then just use filesystem, this is here just for the completeness. + + # minio: + # image: "minio/minio:latest" + # command: minio server /mnt/data --console-address ":9001" + # restart: always + # + # volumes: + # - "penpot_minio:/mnt/data" + # + # environment: + # - MINIO_ROOT_USER=minioadmin + # - MINIO_ROOT_PASSWORD=minioadmin + # + # ports: + # - 9000:9000 + # - 9001:9001 + + diff --git a/apps/dokploy/templates/penpot/index.ts b/apps/dokploy/templates/penpot/index.ts new file mode 100644 index 00000000..f657c698 --- /dev/null +++ b/apps/dokploy/templates/penpot/index.ts @@ -0,0 +1,27 @@ +import { + type DomainSchema, + type Schema, + type Template, + generateBase64, + generatePassword, + generateRandomDomain, +} from "../utils"; + +export function generate(schema: Schema): Template { + const mainDomain = generateRandomDomain(schema); + + const domains: DomainSchema[] = [ + { + host: mainDomain, + port: 80, + serviceName: "penpot-frontend", + }, + ]; + + const envs = [`DOMAIN_NAME=${mainDomain}`]; + + return { + domains, + envs, + }; +} diff --git a/apps/dokploy/templates/templates.ts b/apps/dokploy/templates/templates.ts index 86aa9ae8..9aaf1ee0 100644 --- a/apps/dokploy/templates/templates.ts +++ b/apps/dokploy/templates/templates.ts @@ -1062,4 +1062,63 @@ export const templates: TemplateData[] = [ tags: ["identity", "auth"], load: () => import("./logto/index").then((m) => m.generate), }, + { + id: "penpot", + name: "Penpot", + version: "2.3.2", + description: + "Penpot is the web-based open-source design tool that bridges the gap between designers and developers.", + logo: "penpot.svg", + links: { + github: "https://github.com/penpot/penpot", + website: "https://penpot.app/", + docs: "https://docs.penpot.app/", + }, + tags: ["desing", "collaboration"], + load: () => import("./penpot/index").then((m) => m.generate), + }, + { + id: "huly", + name: "Huly", + version: "0.6.377", + description: + "Huly — All-in-One Project Management Platform (alternative to Linear, Jira, Slack, Notion, Motion)", + logo: "huly.svg", + links: { + github: "https://github.com/hcengineering/huly-selfhost", + website: "https://huly.io/", + docs: "https://docs.huly.io/", + }, + tags: ["project-management", "community", "discussion"], + load: () => import("./huly/index").then((m) => m.generate), + }, + { + id: "unsend", + name: "Unsend", + version: "v1.2.4", + description: "Open source alternative to Resend,Sendgrid, Postmark etc. ", + logo: "unsend.png", // we defined the name and the extension of the logo + links: { + github: "https://github.com/unsend-dev/unsend", + website: "https://unsend.dev/", + docs: "https://docs.unsend.dev/get-started/", + }, + tags: ["e-mail", "marketing", "business"], + load: () => import("./unsend/index").then((m) => m.generate), + }, + { + id: "langflow", + name: "Langflow", + version: "1.1.1", + description: + "Langflow is a low-code app builder for RAG and multi-agent AI applications. It’s Python-based and agnostic to any model, API, or database. ", + logo: "langflow.svg", + links: { + github: "https://github.com/langflow-ai/langflow/tree/main", + website: "https://www.langflow.org/", + docs: "https://docs.langflow.org/", + }, + tags: ["ai"], + load: () => import("./langflow/index").then((m) => m.generate), + }, ]; diff --git a/apps/dokploy/templates/unsend/docker-compose.yml b/apps/dokploy/templates/unsend/docker-compose.yml new file mode 100644 index 00000000..cdf02de6 --- /dev/null +++ b/apps/dokploy/templates/unsend/docker-compose.yml @@ -0,0 +1,78 @@ +name: unsend-prod + +services: + unsend-db-prod: + image: postgres:16 + networks: + - dokploy-network + restart: always + environment: + - POSTGRES_USER=${POSTGRES_USER:?err} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:?err} + - POSTGRES_DB=${POSTGRES_DB:?err} + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"] + interval: 10s + timeout: 5s + retries: 5 + # ports: + # - "5432:5432" + volumes: + - database:/var/lib/postgresql/data + + unsend-redis-prod: + image: redis:7 + networks: + - dokploy-network + restart: always + # ports: + # - "6379:6379" + volumes: + - cache:/data + command: ["redis-server", "--maxmemory-policy", "noeviction"] + + unsend-storage-prod: + image: minio/minio:RELEASE.2024-11-07T00-52-20Z + networks: + - dokploy-network + ports: + - 9002 + - 9001 + volumes: + - storage:/data + environment: + MINIO_ROOT_USER: unsend + MINIO_ROOT_PASSWORD: password + entrypoint: sh + command: -c 'mkdir -p /data/unsend && minio server /data --console-address ":9001" --address ":9002"' + + unsend: + image: unsend/unsend:v1.2.4 + networks: + - dokploy-network + restart: always + ports: + - ${PORT:-3000} + environment: + - PORT=${PORT:-3000} + - DATABASE_URL=${DATABASE_URL:?err} + - NEXTAUTH_URL=${NEXTAUTH_URL:?err} + - NEXTAUTH_SECRET=${NEXTAUTH_SECRET:?err} + - AWS_ACCESS_KEY=${AWS_ACCESS_KEY:?err} + - AWS_SECRET_KEY=${AWS_SECRET_KEY:?err} + - AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION:?err} + - GITHUB_ID=${GITHUB_ID:?err} + - GITHUB_SECRET=${GITHUB_SECRET:?err} + - REDIS_URL=${REDIS_URL:?err} + - NEXT_PUBLIC_IS_CLOUD=${NEXT_PUBLIC_IS_CLOUD:-false} + - API_RATE_LIMIT=${API_RATE_LIMIT:-1} + depends_on: + unsend-db-prod: + condition: service_healthy + unsend-redis-prod: + condition: service_started + +volumes: + database: + cache: + storage: diff --git a/apps/dokploy/templates/unsend/index.ts b/apps/dokploy/templates/unsend/index.ts new file mode 100644 index 00000000..a383b771 --- /dev/null +++ b/apps/dokploy/templates/unsend/index.ts @@ -0,0 +1,44 @@ +import { + generateHash, + generateRandomDomain, + generateBase64, + type Template, + type Schema, + type DomainSchema, +} from "../utils"; + +export function generate(schema: Schema): Template { + const mainDomain = generateRandomDomain(schema); + const secretBase = generateBase64(64); + + const domains: DomainSchema[] = [ + { + host: mainDomain, + port: 3000, + serviceName: "unsend", + }, + ]; + + const envs = [ + "REDIS_URL=redis://unsend-redis-prod:6379", + "POSTGRES_USER=postgres", + "POSTGRES_PASSWORD=postgres", + "POSTGRES_DB=unsend", + "DATABASE_URL=postgresql://postgres:postgres@unsend-db-prod:5432/unsend", + "NEXTAUTH_URL=http://localhost:3000", + `NEXTAUTH_SECRET=${secretBase}`, + "GITHUB_ID='Fill'", + "GITHUB_SECRET='Fill'", + "AWS_DEFAULT_REGION=us-east-1", + "AWS_SECRET_KEY='Fill'", + "AWS_ACCESS_KEY='Fill'", + "DOCKER_OUTPUT=1", + "API_RATE_LIMIT=1", + "DISCORD_WEBHOOK_URL=", + ]; + + return { + envs, + domains, + }; +}