diff --git a/apps/dokploy/components/dashboard/settings/git/gitea/add-gitea-provider.tsx b/apps/dokploy/components/dashboard/settings/git/gitea/add-gitea-provider.tsx
index 13c65bdf3..fa6e9946a 100644
--- a/apps/dokploy/components/dashboard/settings/git/gitea/add-gitea-provider.tsx
+++ b/apps/dokploy/components/dashboard/settings/git/gitea/add-gitea-provider.tsx
@@ -17,6 +17,12 @@ import {
FormLabel,
FormMessage,
} from "@/components/ui/form";
+import {
+ Accordion,
+ AccordionContent,
+ AccordionItem,
+ AccordionTrigger,
+} from "@/components/ui/accordion";
import { Input } from "@/components/ui/input";
import { api } from "@/utils/api";
import {
@@ -39,6 +45,7 @@ const Schema = z.object({
giteaUrl: z.string().min(1, {
message: "Gitea URL is required",
}),
+ giteaUrlAlt: z.string(),
clientId: z.string().min(1, {
message: "Client ID is required",
}),
@@ -70,6 +77,7 @@ export const AddGiteaProvider = () => {
redirectUri: webhookUrl,
name: "",
giteaUrl: "https://gitea.com",
+ giteaUrlAlt: "",
},
resolver: zodResolver(Schema),
});
@@ -83,6 +91,7 @@ export const AddGiteaProvider = () => {
redirectUri: webhookUrl,
name: "",
giteaUrl: "https://gitea.com",
+ giteaUrlAlt: "",
});
}, [form, webhookUrl, isOpen]);
@@ -95,6 +104,7 @@ export const AddGiteaProvider = () => {
name: data.name,
redirectUri: data.redirectUri,
giteaUrl: data.giteaUrl,
+ giteaUrlAlt: data.giteaUrlAlt,
organizationName: data.organizationName,
})) as unknown as GiteaProviderResponse;
@@ -273,6 +283,36 @@ export const AddGiteaProvider = () => {
)}
/>
+
+
+ Advanced Settings
+
+
+ Gitea Docker Url : useful only when Gitea's front
+ end is not exposed to the internet (i.e. you use remote
+ tunneling) and Dokploy can't access the browser
+ reachable Gitea Url. In most cases, this is unnessesary.
+
+ (
+
+ Gitea Docker URL
+
+
+
+
+
+ )}
+ />
+
+
+
+
Configure Gitea App
diff --git a/apps/dokploy/components/dashboard/settings/git/gitea/edit-gitea-provider.tsx b/apps/dokploy/components/dashboard/settings/git/gitea/edit-gitea-provider.tsx
index 13e43fbf9..a0128cd27 100644
--- a/apps/dokploy/components/dashboard/settings/git/gitea/edit-gitea-provider.tsx
+++ b/apps/dokploy/components/dashboard/settings/git/gitea/edit-gitea-provider.tsx
@@ -15,6 +15,12 @@ import {
FormLabel,
FormMessage,
} from "@/components/ui/form";
+import {
+ Accordion,
+ AccordionContent,
+ AccordionItem,
+ AccordionTrigger,
+} from "@/components/ui/accordion";
import { Input } from "@/components/ui/input";
import { api } from "@/utils/api";
import { getGiteaOAuthUrl } from "@/utils/gitea-utils";
@@ -30,6 +36,7 @@ import { z } from "zod";
const formSchema = z.object({
name: z.string().min(1, "Name is required"),
giteaUrl: z.string().min(1, "Gitea URL is required"),
+ giteaUrlAlt: z.string(),
clientId: z.string().min(1, "Client ID is required"),
clientSecret: z.string().min(1, "Client Secret is required"),
});
@@ -94,6 +101,7 @@ export const EditGiteaProvider = ({ giteaId }: Props) => {
defaultValues: {
name: "",
giteaUrl: "https://gitea.com",
+ giteaUrlAlt: "",
clientId: "",
clientSecret: "",
},
@@ -104,6 +112,7 @@ export const EditGiteaProvider = ({ giteaId }: Props) => {
form.reset({
name: gitea.gitProvider?.name || "",
giteaUrl: gitea.giteaUrl || "https://gitea.com",
+ giteaUrlAlt: gitea.giteaUrlAlt || "",
clientId: gitea.clientId || "",
clientSecret: gitea.clientSecret || "",
});
@@ -116,6 +125,7 @@ export const EditGiteaProvider = ({ giteaId }: Props) => {
gitProviderId: gitea?.gitProvider?.gitProviderId || "",
name: values.name,
giteaUrl: values.giteaUrl,
+ giteaUrlAlt: values.giteaUrlAlt,
clientId: values.clientId,
clientSecret: values.clientSecret,
})
@@ -255,6 +265,33 @@ export const EditGiteaProvider = ({ giteaId }: Props) => {
)}
/>
+
+
+ Advanced Settings
+
+
+ Gitea Docker Url : useful only when Gitea's front end
+ is not exposed to the internet (i.e. you use remote
+ tunneling) and Dokploy can't access the browser reachable
+ Gitea Url. In most cases, this is unnessesary.
+
+ (
+
+ Gitea Docker URL
+
+
+
+
+
+ )}
+ />
+
+
+
+
nanoid()),
giteaUrl: text("giteaUrl").default("https://gitea.com").notNull(),
+ giteaUrlAlt: text("giteaUrlAlt"),
redirectUri: text("redirect_uri"),
clientId: text("client_id"),
clientSecret: text("client_secret"),
@@ -40,6 +41,7 @@ export const apiCreateGitea = createSchema.extend({
redirectUri: z.string().optional(),
name: z.string().min(1),
giteaUrl: z.string().min(1),
+ giteaUrlAlt: z.string().optional(),
giteaUsername: z.string().optional(),
accessToken: z.string().optional(),
refreshToken: z.string().optional(),
@@ -76,6 +78,7 @@ export const apiUpdateGitea = createSchema.extend({
name: z.string().min(1),
giteaId: z.string().min(1),
giteaUrl: z.string().min(1),
+ giteaUrlAlt: z.string().optional(),
giteaUsername: z.string().optional(),
accessToken: z.string().optional(),
refreshToken: z.string().optional(),
diff --git a/packages/server/src/services/gitea.ts b/packages/server/src/services/gitea.ts
index 45447f45e..46d3b5847 100644
--- a/packages/server/src/services/gitea.ts
+++ b/packages/server/src/services/gitea.ts
@@ -51,6 +51,7 @@ export const createGitea = async (
giteaId: giteaProvider.giteaId,
clientId: giteaProvider.clientId,
giteaUrl: giteaProvider.giteaUrl,
+ giteaUrlAlt: giteaProvider.giteaUrlAlt,
};
});
};
diff --git a/packages/server/src/utils/providers/gitea.ts b/packages/server/src/utils/providers/gitea.ts
index 68760559a..2ae095a86 100644
--- a/packages/server/src/utils/providers/gitea.ts
+++ b/packages/server/src/utils/providers/gitea.ts
@@ -28,6 +28,11 @@ export const getErrorCloneRequirements = (entity: {
return reasons;
};
+export const getGiteaCloneUrl = (gitea: Gitea, repo: string) => {
+ const giteaUrl = new URL(gitea.giteaUrl);
+ return `${giteaUrl.protocol}//oauth2:${gitea.accessToken}@${giteaUrl.host}/${repo}`;
+};
+
export const refreshGiteaToken = async (giteaProviderId: string) => {
try {
const giteaProvider = await findGiteaById(giteaProviderId);
@@ -53,8 +58,11 @@ export const refreshGiteaToken = async (giteaProviderId: string) => {
return giteaProvider.accessToken;
}
+ // if user provided giteaUrlAlt, default to it for server fetches
+ const giteaUrl = giteaProvider.giteaUrlAlt || giteaProvider.giteaUrl;
+
// Token is expired or about to expire, refresh it
- const tokenEndpoint = `${giteaProvider.giteaUrl}/login/oauth/access_token`;
+ const tokenEndpoint = `${giteaUrl}/login/oauth/access_token`;
const params = new URLSearchParams({
grant_type: "refresh_token",
refresh_token: giteaProvider.refreshToken,
@@ -128,9 +136,9 @@ export const getGiteaCloneCommand = async (
});
}
- if (!giteaId) {
+ if (!giteaId || !gitea) {
const command = `
- echo "Error: ❌ Gitlab Provider not found" >> ${logPath};
+ echo "Error: ❌ Gitea Provider not found" >> ${logPath};
exit 1;
`;
@@ -147,9 +155,8 @@ export const getGiteaCloneCommand = async (
const basePath = isCompose ? COMPOSE_PATH : APPLICATIONS_PATH;
const outputPath = join(basePath, appName, "code");
- const baseUrl = gitea?.giteaUrl.replace(/^https?:\/\//, "");
const repoClone = `${giteaOwner}/${giteaRepository}.git`;
- const cloneUrl = `https://oauth2:${gitea?.accessToken}@${baseUrl}/${repoClone}`;
+ const cloneUrl = getGiteaCloneUrl(gitea, repoClone);
const cloneCommand = `
rm -rf ${outputPath};
@@ -197,8 +204,7 @@ export const cloneGiteaRepository = async (
await recreateDirectory(outputPath);
const repoClone = `${giteaOwner}/${giteaRepository}.git`;
- const baseUrl = giteaProvider.giteaUrl.replace(/^https?:\/\//, "");
- const cloneUrl = `https://oauth2:${giteaProvider.accessToken}@${baseUrl}/${repoClone}`;
+ const cloneUrl = getGiteaCloneUrl(giteaProvider, repoClone);
writeStream.write(`\nCloning Repo ${repoClone} to ${outputPath}...\n`);
@@ -255,8 +261,7 @@ export const cloneRawGiteaRepository = async (entity: Compose) => {
await recreateDirectory(outputPath);
const repoClone = `${giteaOwner}/${giteaRepository}.git`;
- const baseUrl = giteaProvider.giteaUrl.replace(/^https?:\/\//, "");
- const cloneUrl = `https://oauth2:${giteaProvider.accessToken}@${baseUrl}/${repoClone}`;
+ const cloneUrl = getGiteaCloneUrl(giteaProvider, repoClone);
try {
await spawnAsync("git", [
@@ -302,8 +307,7 @@ export const cloneRawGiteaRepositoryRemote = async (compose: Compose) => {
const basePath = COMPOSE_PATH;
const outputPath = join(basePath, appName, "code");
const repoClone = `${giteaOwner}/${giteaRepository}.git`;
- const baseUrl = giteaProvider.giteaUrl.replace(/^https?:\/\//, "");
- const cloneUrl = `https://oauth2:${giteaProvider.accessToken}@${baseUrl}/${repoClone}`;
+ const cloneUrl = getGiteaCloneUrl(giteaProvider, repoClone);
try {
const command = `
rm -rf ${outputPath};
@@ -345,7 +349,9 @@ export const testGiteaConnection = async (input: { giteaId: string }) => {
});
}
- const baseUrl = provider.giteaUrl.replace(/\/+$/, "");
+ // if user provided giteaUrlAlt, default to it for server fetches
+ const giteaUrl = provider.giteaUrlAlt || provider.giteaUrl;
+ const baseUrl = giteaUrl.replace(/\/+$/, "");
const url = `${baseUrl}/api/v1/user/repos`;
const response = await fetch(url, {
@@ -381,7 +387,9 @@ export const getGiteaRepositories = async (giteaId?: string) => {
const giteaProvider = await findGiteaById(giteaId);
- const baseUrl = giteaProvider.giteaUrl.replace(/\/+$/, "");
+ // if user provided giteaUrlAlt, default to it for server fetches
+ const giteaUrl = giteaProvider.giteaUrlAlt || giteaProvider.giteaUrl;
+ const baseUrl = giteaUrl.replace(/\/+$/, "");
const url = `${baseUrl}/api/v1/user/repos`;
const response = await fetch(url, {
@@ -425,7 +433,9 @@ export const getGiteaBranches = async (input: {
const giteaProvider = await findGiteaById(input.giteaId);
- const baseUrl = giteaProvider.giteaUrl.replace(/\/+$/, "");
+ // if user provided giteaUrlAlt, default to it for server fetches
+ const giteaUrl = giteaProvider.giteaUrlAlt || giteaProvider.giteaUrl;
+ const baseUrl = giteaUrl.replace(/\/+$/, "");
const url = `${baseUrl}/api/v1/repos/${input.owner}/${input.repo}/branches`;
const response = await fetch(url, {