Merge branch 'canary' into feat/requests

This commit is contained in:
Mauricio Siu
2024-08-30 11:16:03 -06:00
20 changed files with 249 additions and 15 deletions

BIN
.github/sponsors/hostinger.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 KiB

View File

@@ -9,7 +9,7 @@
<div align="center">
<div>Join us on Discord for help, feedback, and discussions!</div>
</br>
<a href="https://discord.gg/ZXwG32bw">
<a href="https://discord.gg/2tBnJ3jDJc">
<img src="https://discordapp.com/api/guilds/1234073262418563112/widget.png?style=banner2" alt="Discord Shield"/>
</a>
</div>
@@ -56,6 +56,10 @@ For detailed documentation, visit [docs.dokploy.com](https://docs.dokploy.com).
<!-- Add Hero Sponsors here -->
### Hero Sponsors 🎖
<a href="https://www.hostinger.com/?ref=dokploy" target="_blank" ><img src=".github/sponsors/hostinger.jpg" alt="Hostinger" width="200"/></a>
### Premium Supporters 🥇
<div style="display: flex; gap: 30px; flex-wrap: wrap;">

View File

@@ -69,4 +69,4 @@ Open your web browser and navigate to `http://your-ip-from-your-vps:3000`. You w
1. **Create an Admin Account:** Fill in the necessary details to set up your administrator account. This account will be the admin account for Dokploy.
<ImageZoom src="/assets/images/setup.png" width={1300} height={630} alt='home og image' className="rounded-lg" />
<ImageZoom src="/assets/images/setup.png" width={1300} height={650} alt='home og image' className="rounded-lg" />

View File

@@ -32,22 +32,22 @@ Please go to get started.
<Cards>
<Card
href="/get-started/installation"
href="/docs/core/get-started/installation"
title="Installation"
description="Learn how to install Dokploy."
/>
<Card
href="/application/overview"
href="/docs/core/application/overview"
title="Applications"
description="Learn how to deploy applications."
/>
<Card
href="/databases/overview"
href="/docs/core/databases/overview"
title="Databases"
description="Learn how to deploy databases."
/>
<Card
href="/traefik/overview"
href="/docs/core/traefik/overview"
title="Traefik"
description="Learn how to deploy Traefik."
/>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 101 KiB

View File

@@ -71,7 +71,10 @@ export const ShowDomains = ({ applicationId }: Props) => {
key={item.domainId}
className="flex w-full items-center gap-4 max-sm:flex-wrap border p-4 rounded-lg"
>
<Link target="_blank" href={`http://${item.host}`}>
<Link
target="_blank"
href={`${item.https ? "https" : "http"}://${item.host}${item.path}`}
>
<ExternalLink className="size-5" />
</Link>

View File

@@ -132,7 +132,7 @@ TRAEFIK_CERTIFICATESRESOLVERS_LETSENCRYPT_HTTP_CHALLENGE_DNS_PROVIDER=cloudflare
<DialogFooter>
<Button
isLoading={isLoading}
disabled={canEdit}
disabled={canEdit || isLoading}
form="hook-form-update-server-traefik-config"
type="submit"
>

View File

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

View File

@@ -0,0 +1,13 @@
<svg viewBox="0 0 800 800" xmlns="http://www.w3.org/2000/svg">
<rect width="800" height="800" rx="80" fill="#0042DA" style="--darkreader-inline-fill:#0035ae" />
<rect x="650" y="293" width="85.47" height="384.617" rx="20" transform="rotate(90 650 293)" fill="#FF8E20"
style="--darkreader-inline-fill:#ff9630" />
<path fill-rule="evenodd" clip-rule="evenodd"
d="M192.735 378.47c23.602 0 42.735-19.133 42.735-42.735S216.337 293 192.735 293 150 312.133 150 335.735s19.133 42.735 42.735 42.735Z"
fill="#FF8E20" style="--darkreader-inline-fill:#ff9630" />
<rect x="150" y="506.677" width="85.47" height="384.617" rx="20" transform="rotate(-90 150 506.677)" fill="#fff"
style="--darkreader-inline-fill:#e8e6e3" />
<path fill-rule="evenodd" clip-rule="evenodd"
d="M607.265 421.206c-23.602 0-42.735 19.134-42.735 42.736 0 23.602 19.133 42.735 42.735 42.735S650 487.544 650 463.942s-19.133-42.736-42.735-42.736Z"
fill="#fff" style="--darkreader-inline-fill:#e8e6e3" />
</svg>

After

Width:  |  Height:  |  Size: 1000 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

View File

@@ -12,6 +12,7 @@ import {
} from "@/server/db/schema";
import { TRPCError } from "@trpc/server";
import * as bcrypt from "bcrypt";
import { db } from "../../db";
import {
createAdmin,
createUser,
@@ -33,6 +34,14 @@ export const authRouter = createTRPCRouter({
.input(apiCreateAdmin)
.mutation(async ({ ctx, input }) => {
try {
const admin = await db.query.admins.findFirst({});
if (admin) {
throw new TRPCError({
code: "BAD_REQUEST",
message: "Admin already exists",
});
}
const newAdmin = await createAdmin(input);
const session = await lucia.createSession(newAdmin.id || "", {});
ctx.res.appendHeader(

View File

@@ -1,6 +1,6 @@
import { chmodSync, existsSync, mkdirSync, writeFileSync } from "node:fs";
import path from "node:path";
import type { CreateServiceOptions } from "dockerode";
import type { ContainerTaskSpec, CreateServiceOptions } from "dockerode";
import { dump } from "js-yaml";
import { DYNAMIC_TRAEFIK_PATH, MAIN_TRAEFIK_PATH, docker } from "../constants";
import { pullImage } from "../utils/docker/utils";
@@ -18,7 +18,7 @@ interface TraefikOptions {
export const initializeTraefik = async ({
enableDashboard = false,
env = [],
env,
}: TraefikOptions = {}) => {
const imageName = "traefik:v2.5";
const containerName = "dokploy-traefik";
@@ -85,9 +85,23 @@ export const initializeTraefik = async ({
const service = docker.getService(containerName);
const inspect = await service.inspect();
const existingEnv = inspect.Spec.TaskTemplate.ContainerSpec.Env || [];
const updatedEnv = !env ? existingEnv : env;
const updatedSettings = {
...settings,
TaskTemplate: {
...settings.TaskTemplate,
ContainerSpec: {
...(settings?.TaskTemplate as ContainerTaskSpec).ContainerSpec,
Env: updatedEnv,
},
},
};
await service.update({
version: Number.parseInt(inspect.Version.Index),
...settings,
...updatedSettings,
});
console.log("Traefik Started ✅");

View File

@@ -109,7 +109,7 @@ export const cleanStoppedContainers = async () => {
export const cleanUpUnusedVolumes = async () => {
try {
await execAsync("docker volume prune --force");
await execAsync("docker volume prune --all --force");
} catch (error) {
console.error(error);
throw error;

View File

@@ -18,7 +18,7 @@ services:
start_period: 10s
documenso:
image: documenso/documenso:1.5.6-rc.2
image: documenso/documenso:v1.5.6-rc.2
depends_on:
postgres:
condition: service_healthy

View File

@@ -423,6 +423,21 @@ export const templates: TemplateData[] = [
tags: ["database", "spreadsheet", "low-code", "nocode"],
load: () => import("./teable/index").then((m) => m.generate),
},
{
id: "zipline",
name: "Zipline",
version: "v3.7.9",
description:
"A ShareX/file upload server that is easy to use, packed with features, and with an easy setup!",
logo: "zipline.png",
links: {
github: "https://github.com/diced/zipline",
website: "https://zipline.diced.sh/",
docs: "https://zipline.diced.sh/docs/",
},
tags: ["media system", "storage"],
load: () => import("./zipline/index").then((m) => m.generate),
},
{
id: "soketi",
name: "Soketi",
@@ -453,4 +468,18 @@ export const templates: TemplateData[] = [
tags: ["analytics", "self-hosted"],
load: () => import("./aptabase/index").then((m) => m.generate),
},
{
id: "typebot",
name: "Typebot",
version: "2.27.0",
description: "Typebot is an open-source chatbot builder platform.",
logo: "typebot.svg",
links: {
github: "https://github.com/baptisteArno/typebot.io",
website: "https://typebot.io/",
docs: "https://docs.typebot.io/get-started/introduction",
},
tags: ["chatbot", "builder", "open-source"],
load: () => import("./typebot/index").then((m) => m.generate),
},
];

View File

@@ -0,0 +1,49 @@
version: '3.3'
volumes:
db-data:
services:
typebot-db:
image: postgres:14-alpine
restart: always
volumes:
- db-data:/var/lib/postgresql/data
environment:
POSTGRES_USER: typebot
POSTGRES_DB: typebot
POSTGRES_PASSWORD: typebot
networks:
- dokploy-network
typebot-builder:
image: baptistearno/typebot-builder:2.27
restart: always
depends_on:
- typebot-db
environment:
ENCRYPTION_SECRET: '${ENCRYPTION_SECRET}'
DATABASE_URL: 'postgresql://typebot:typebot@typebot-db:5432/typebot'
NEXTAUTH_URL: '${NEXTAUTH_URL}'
NEXT_PUBLIC_VIEWER_URL: '${NEXT_PUBLIC_VIEWER_URL}'
ADMIN_EMAIL: '${ADMIN_EMAIL}'
SMTP_HOST: '${SMTP_HOST}'
NEXT_PUBLIC_SMTP_FROM: '${NEXT_PUBLIC_SMTP_FROM}'
SMTP_USERNAME: '${SMTP_USERNAME}'
SMTP_PASSWORD: '${SMTP_PASSWORD}'
DEFAULT_WORKSPACE_PLAN: '${DEFAULT_WORKSPACE_PLAN}'
typebot-viewer:
image: baptistearno/typebot-viewer:2.27.0
restart: always
environment:
ENCRYPTION_SECRET: '${ENCRYPTION_SECRET}'
DATABASE_URL: postgresql://typebot:typebot@typebot-db:5432/typebot
NEXTAUTH_URL: '${NEXTAUTH_URL}'
NEXT_PUBLIC_VIEWER_URL: '${NEXT_PUBLIC_VIEWER_URL}'
ADMIN_EMAIL: '${ADMIN_EMAIL}'
SMTP_HOST: '${SMTP_HOST}'
NEXT_PUBLIC_SMTP_FROM: '${NEXT_PUBLIC_SMTP_FROM}'
SMTP_USERNAME: '${SMTP_USERNAME}'
SMTP_PASSWORD: '${SMTP_PASSWORD}'
DEFAULT_WORKSPACE_PLAN: '${DEFAULT_WORKSPACE_PLAN}'

View File

@@ -0,0 +1,44 @@
import {
type DomainSchema,
type Schema,
type Template,
generateBase64,
generateRandomDomain,
} from "../utils";
export function generate(schema: Schema): Template {
const builderDomain = generateRandomDomain(schema);
const viewerDomain = generateRandomDomain(schema);
const encryptionSecret = generateBase64(24);
const domains: DomainSchema[] = [
{
host: builderDomain,
port: 3000,
serviceName: "typebot-builder",
},
{
host: viewerDomain,
port: 3000,
serviceName: "typebot-viewer",
},
];
const envs = [
`ENCRYPTION_SECRET=${encryptionSecret}`,
`NEXTAUTH_URL=http://${builderDomain}`,
`NEXT_PUBLIC_VIEWER_URL=http://${viewerDomain}`,
"ADMIN_EMAIL=typebot@example.com",
"SMTP_HOST='Fill'",
"SMTP_PORT=25",
"SMTP_USERNAME='Fill'",
"SMTP_PASSWORD='Fill'",
"NEXT_PUBLIC_SMTP_FROM=typebot@example.com",
"DEFAULT_WORKSPACE_PLAN=UNLIMITED",
];
return {
envs,
domains,
};
}

View File

@@ -1,6 +1,6 @@
services:
umami:
image: ghcr.io/umami-software/umami:postgresql-v2.12.1
image: ghcr.io/umami-software/umami:postgresql-v2.13.2
restart: always
healthcheck:
test: ["CMD-SHELL", "curl http://localhost:3000/api/heartbeat"]

View File

@@ -0,0 +1,37 @@
version: "3"
services:
postgres:
image: postgres:15
networks:
- dokploy-network
restart: unless-stopped
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
- POSTGRES_DATABASE=postgres
volumes:
- pg_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
zipline:
image: ghcr.io/diced/zipline:3.7.9
restart: unless-stopped
environment:
- CORE_RETURN_HTTPS=${ZIPLINE_RETURN_HTTPS}
- CORE_SECRET=${ZIPLINE_SECRET}
- CORE_HOST=0.0.0.0
- CORE_PORT=${ZIPLINE_PORT}
- CORE_DATABASE_URL=postgres://postgres:postgres@postgres/postgres
- CORE_LOGGER=${ZIPLINE_LOGGER}
volumes:
- "../files/uploads:/zipline/uploads"
- "../files/public:/zipline/public"
depends_on:
- "postgres"
volumes:
pg_data:

View File

@@ -0,0 +1,32 @@
import {
type DomainSchema,
type Schema,
type Template,
generateBase64,
generateRandomDomain,
} from "@/templates/utils";
export function generate(schema: Schema): Template {
const randomDomain = generateRandomDomain(schema);
const secretBase = generateBase64(64);
const domains: DomainSchema[] = [
{
host: randomDomain,
port: 3000,
serviceName: "zipline",
},
];
const envs = [
"ZIPLINE_PORT=3000",
`ZIPLINE_SECRET=${secretBase}`,
"ZIPLINE_RETURN_HTTPS=false",
"ZIPLINE_LOGGER=true",
];
return {
envs,
domains,
};
}