diff --git a/apps/dokploy/components/dashboard/application/domains/add-domain.tsx b/apps/dokploy/components/dashboard/application/domains/add-domain.tsx index f91218ce..8b1fa7e1 100644 --- a/apps/dokploy/components/dashboard/application/domains/add-domain.tsx +++ b/apps/dokploy/components/dashboard/application/domains/add-domain.tsx @@ -42,6 +42,7 @@ import { domain } from "@/server/db/validations/domain"; import { zodResolver } from "@hookform/resolvers/zod"; import { Dices } from "lucide-react"; import type z from "zod"; +import Link from "next/link"; type Domain = z.infer; @@ -83,6 +84,13 @@ export const AddDomain = ({ const { mutateAsync: generateDomain, isLoading: isLoadingGenerate } = api.domain.generateDomain.useMutation(); + const { data: canGenerateTraefikMeDomains } = + api.domain.canGenerateTraefikMeDomains.useQuery({ + serverId: application?.serverId || "", + }); + + console.log("canGenerateTraefikMeDomains", canGenerateTraefikMeDomains); + const form = useForm({ resolver: zodResolver(domain), defaultValues: { @@ -186,6 +194,21 @@ export const AddDomain = ({ name="host" render={({ field }) => ( + {!canGenerateTraefikMeDomains && + field.value.includes("traefik.me") && ( + + You need to set an IP address in your{" "} + + {application?.serverId + ? "Remote Servers -> Server -> Edit Server -> Update IP Address" + : "Web Server -> Server -> Update Server IP"} + {" "} + to make your traefik.me domain work. + + )} Host
diff --git a/apps/dokploy/components/dashboard/compose/domains/add-domain.tsx b/apps/dokploy/components/dashboard/compose/domains/add-domain.tsx index 9b412c83..975ce1ff 100644 --- a/apps/dokploy/components/dashboard/compose/domains/add-domain.tsx +++ b/apps/dokploy/components/dashboard/compose/domains/add-domain.tsx @@ -42,6 +42,7 @@ import { domainCompose } from "@/server/db/validations/domain"; import { zodResolver } from "@hookform/resolvers/zod"; import { DatabaseZap, Dices, RefreshCw } from "lucide-react"; import type z from "zod"; +import Link from "next/link"; type Domain = z.infer; @@ -102,6 +103,11 @@ export const AddDomainCompose = ({ ? api.domain.update.useMutation() : api.domain.create.useMutation(); + const { data: canGenerateTraefikMeDomains } = + api.domain.canGenerateTraefikMeDomains.useQuery({ + serverId: compose?.serverId || "", + }); + const form = useForm({ resolver: zodResolver(domainCompose), defaultValues: { @@ -313,6 +319,21 @@ export const AddDomainCompose = ({ name="host" render={({ field }) => ( + {!canGenerateTraefikMeDomains && + field.value.includes("traefik.me") && ( + + You need to set an IP address in your{" "} + + {compose?.serverId + ? "Remote Servers -> Server -> Edit Server -> Update IP Address" + : "Web Server -> Server -> Update Server IP"} + {" "} + to make your traefik.me domain work. + + )} Host
diff --git a/apps/dokploy/server/api/routers/domain.ts b/apps/dokploy/server/api/routers/domain.ts index aac2a016..9e81bee1 100644 --- a/apps/dokploy/server/api/routers/domain.ts +++ b/apps/dokploy/server/api/routers/domain.ts @@ -13,7 +13,9 @@ import { findDomainById, findDomainsByApplicationId, findDomainsByComposeId, + findOrganizationById, findPreviewDeploymentById, + findServerById, generateTraefikMeDomain, manageDomain, removeDomain, @@ -94,6 +96,19 @@ export const domainRouter = createTRPCRouter({ input.serverId, ); }), + canGenerateTraefikMeDomains: protectedProcedure + .input(z.object({ serverId: z.string() })) + .query(async ({ input, ctx }) => { + const organization = await findOrganizationById( + ctx.session.activeOrganizationId, + ); + + if (input.serverId) { + const server = await findServerById(input.serverId); + return server.ipAddress; + } + return organization?.owner.serverIp; + }), update: protectedProcedure .input(apiUpdateDomain) diff --git a/packages/server/src/lib/auth.ts b/packages/server/src/lib/auth.ts index 9043f203..6695756c 100644 --- a/packages/server/src/lib/auth.ts +++ b/packages/server/src/lib/auth.ts @@ -8,6 +8,10 @@ import { db } from "../db"; import * as schema from "../db/schema"; import { sendEmail } from "../verification/send-verification-email"; import { IS_CLOUD } from "../constants"; +import { getPublicIpWithFallback } from "../wss/utils"; +import { updateUser } from "../services/user"; +import { getUserByToken } from "../services/admin"; +import { APIError } from "better-auth/api"; const { handler, api } = betterAuth({ database: drizzleAdapter(db, { @@ -88,11 +92,40 @@ const { handler, api } = betterAuth({ databaseHooks: { user: { create: { + before: async (_user, context) => { + if (!IS_CLOUD) { + const xDokployToken = + context?.request?.headers?.get("x-dokploy-token"); + if (xDokployToken) { + const user = await getUserByToken(xDokployToken); + if (!user) { + throw new APIError("BAD_REQUEST", { + message: "User not found", + }); + } + } else { + const isAdminPresent = await db.query.member.findFirst({ + where: eq(schema.member.role, "owner"), + }); + if (isAdminPresent) { + throw new APIError("BAD_REQUEST", { + message: "Admin is already created", + }); + } + } + } + }, after: async (user) => { const isAdminPresent = await db.query.member.findFirst({ where: eq(schema.member.role, "owner"), }); + if (!IS_CLOUD) { + await updateUser(user.id, { + serverIp: await getPublicIpWithFallback(), + }); + } + if (IS_CLOUD || !isAdminPresent) { await db.transaction(async (tx) => { const organization = await tx