diff --git a/apps/dokploy/components/dashboard/settings/servers/actions/show-traefik-actions.tsx b/apps/dokploy/components/dashboard/settings/servers/actions/show-traefik-actions.tsx
index bd168edc..b43686bd 100644
--- a/apps/dokploy/components/dashboard/settings/servers/actions/show-traefik-actions.tsx
+++ b/apps/dokploy/components/dashboard/settings/servers/actions/show-traefik-actions.tsx
@@ -112,15 +112,6 @@ export const ShowTraefikActions = ({ serverId }: Props) => {
{haveTraefikDashboardPortEnabled ? "Disable" : "Enable"} Dashboard
- {/*
-
- e.preventDefault()}
- >
- Enter the terminal
-
- */}
e.preventDefault()}
diff --git a/apps/dokploy/server/api/routers/settings.ts b/apps/dokploy/server/api/routers/settings.ts
index fc1255fc..03711fe1 100644
--- a/apps/dokploy/server/api/routers/settings.ts
+++ b/apps/dokploy/server/api/routers/settings.ts
@@ -42,10 +42,6 @@ import {
recreateDirectory,
sendDockerCleanupNotifications,
spawnAsync,
- startService,
- startServiceRemote,
- stopService,
- stopServiceRemote,
updateLetsEncryptEmail,
updateServerById,
updateServerTraefik,
@@ -86,11 +82,9 @@ export const settingsRouter = createTRPCRouter({
.mutation(async ({ input }) => {
try {
if (input?.serverId) {
- await stopServiceRemote(input.serverId, "dokploy-traefik");
- await startServiceRemote(input.serverId, "dokploy-traefik");
+ await execAsync("docker restart dokploy-traefik");
} else if (!IS_CLOUD) {
- await stopService("dokploy-traefik");
- await startService("dokploy-traefik");
+ await execAsync("docker restart dokploy-traefik");
}
} catch (err) {
console.error(err);
@@ -104,6 +98,7 @@ export const settingsRouter = createTRPCRouter({
await initializeTraefik({
enableDashboard: input.enableDashboard,
serverId: input.serverId,
+ force: true,
});
return true;
}),
@@ -511,16 +506,18 @@ export const settingsRouter = createTRPCRouter({
.input(apiServerSchema)
.query(async ({ input }) => {
const command =
- "docker service inspect --format='{{range .Spec.TaskTemplate.ContainerSpec.Env}}{{println .}}{{end}}' dokploy-traefik";
+ "docker container inspect dokploy-traefik --format '{{json .Config.Env}}'";
+ let result = "";
if (input?.serverId) {
- const result = await execAsyncRemote(input.serverId, command);
- return result.stdout.trim();
- }
- if (!IS_CLOUD) {
- const result = await execAsync(command);
- return result.stdout.trim();
+ const execResult = await execAsyncRemote(input.serverId, command);
+ result = execResult.stdout;
+ } else {
+ const execResult = await execAsync(command);
+ result = execResult.stdout;
}
+ const envVars = JSON.parse(result.trim());
+ return envVars.join("\n");
}),
writeTraefikEnv: adminProcedure
@@ -530,6 +527,7 @@ export const settingsRouter = createTRPCRouter({
await initializeTraefik({
env: envs,
serverId: input.serverId,
+ force: true,
});
return true;
@@ -537,27 +535,22 @@ export const settingsRouter = createTRPCRouter({
haveTraefikDashboardPortEnabled: adminProcedure
.input(apiServerSchema)
.query(async ({ input }) => {
- const command = `docker service inspect --format='{{json .Endpoint.Ports}}' dokploy-traefik`;
+ const command = `docker container inspect --format='{{json .NetworkSettings.Ports}}' dokploy-traefik`;
let stdout = "";
if (input?.serverId) {
const result = await execAsyncRemote(input.serverId, command);
stdout = result.stdout;
} else if (!IS_CLOUD) {
- const result = await execAsync(
- "docker service inspect --format='{{json .Endpoint.Ports}}' dokploy-traefik",
- );
+ const result = await execAsync(command);
stdout = result.stdout;
}
- const parsed: any[] = JSON.parse(stdout.trim());
- for (const port of parsed) {
- if (port.PublishedPort === 8080) {
- return true;
- }
- }
-
- return false;
+ const ports = JSON.parse(stdout.trim());
+ return Object.entries(ports).some(([containerPort, bindings]) => {
+ const [port] = containerPort.split("/");
+ return port === "8080" && bindings && (bindings as any[]).length > 0;
+ });
}),
readStatsLogs: adminProcedure
@@ -767,6 +760,7 @@ export const settingsRouter = createTRPCRouter({
await initializeTraefik({
serverId: input.serverId,
additionalPorts: input.additionalPorts,
+ force: true,
});
return true;
} catch (error) {
@@ -783,7 +777,7 @@ export const settingsRouter = createTRPCRouter({
getTraefikPorts: adminProcedure
.input(apiServerSchema)
.query(async ({ input }) => {
- const command = `docker service inspect --format='{{json .Endpoint.Ports}}' dokploy-traefik`;
+ const command = `docker container inspect --format='{{json .NetworkSettings.Ports}}' dokploy-traefik`;
try {
let stdout = "";
@@ -795,21 +789,38 @@ export const settingsRouter = createTRPCRouter({
stdout = result.stdout;
}
- const ports: {
- Protocol: string;
- TargetPort: number;
- PublishedPort: number;
- PublishMode: string;
- }[] = JSON.parse(stdout.trim());
+ const portsMap = JSON.parse(stdout.trim());
+ const additionalPorts: Array<{
+ targetPort: number;
+ publishedPort: number;
+ publishMode: "host" | "ingress";
+ }> = [];
- // Filter out the default ports (80, 443, and optionally 8080)
- const additionalPorts = ports
- .filter((port) => ![80, 443, 8080].includes(port.PublishedPort))
- .map((port) => ({
- targetPort: port.TargetPort,
- publishedPort: port.PublishedPort,
- publishMode: port.PublishMode.toLowerCase() as "host" | "ingress",
- }));
+ // Convert the Docker container port format to our expected format
+ for (const [containerPort, bindings] of Object.entries(portsMap)) {
+ if (!bindings) continue;
+
+ const [port = ""] = containerPort.split("/");
+ if (!port) continue;
+
+ const targetPortNum = Number.parseInt(port, 10);
+ if (Number.isNaN(targetPortNum)) continue;
+
+ // Skip default ports
+ if ([80, 443, 8080].includes(targetPortNum)) continue;
+
+ for (const binding of bindings as Array<{ HostPort: string }>) {
+ if (!binding.HostPort) continue;
+ const publishedPort = Number.parseInt(binding.HostPort, 10);
+ if (Number.isNaN(publishedPort)) continue;
+
+ additionalPorts.push({
+ targetPort: targetPortNum,
+ publishedPort,
+ publishMode: "host", // Docker standalone uses host mode by default
+ });
+ }
+ }
return additionalPorts;
} catch (error) {
diff --git a/packages/server/src/setup/server-setup.ts b/packages/server/src/setup/server-setup.ts
index dc760407..0e2a1811 100644
--- a/packages/server/src/setup/server-setup.ts
+++ b/packages/server/src/setup/server-setup.ts
@@ -539,22 +539,21 @@ export const installRClone = () => `
export const createTraefikInstance = () => {
const command = `
# Check if dokpyloy-traefik exists
- if docker service ls | grep -q 'dokploy-traefik'; then
+ if docker ps -a --format '{{.Names}}' | grep -q '^dokploy-traefik$'; then
echo "Traefik already exists ✅"
else
- # Create the dokploy-traefik service
+ # Create the dokploy-traefik container
TRAEFIK_VERSION=${TRAEFIK_VERSION}
- docker service create \
+ docker run -d \
--name dokploy-traefik \
- --replicas 1 \
- --constraint 'node.role==manager' \
--network dokploy-network \
- --mount type=bind,src=/etc/dokploy/traefik/traefik.yml,dst=/etc/traefik/traefik.yml \
- --mount type=bind,src=/etc/dokploy/traefik/dynamic,dst=/etc/dokploy/traefik/dynamic \
- --mount type=bind,src=/var/run/docker.sock,dst=/var/run/docker.sock \
+ --restart unless-stopped \
+ -v /etc/dokploy/traefik/traefik.yml:/etc/traefik/traefik.yml \
+ -v /etc/dokploy/traefik/dynamic:/etc/dokploy/traefik/dynamic \
+ -v /var/run/docker.sock:/var/run/docker.sock \
--label traefik.enable=true \
- --publish mode=host,target=${TRAEFIK_SSL_PORT},published=${TRAEFIK_SSL_PORT} \
- --publish mode=host,target=${TRAEFIK_PORT},published=${TRAEFIK_PORT} \
+ -p ${TRAEFIK_SSL_PORT}:${TRAEFIK_SSL_PORT} \
+ -p ${TRAEFIK_PORT}:${TRAEFIK_PORT} \
traefik:v$TRAEFIK_VERSION
echo "Traefik version $TRAEFIK_VERSION installed ✅"
fi
diff --git a/packages/server/src/setup/traefik-setup.ts b/packages/server/src/setup/traefik-setup.ts
index 5a904eb8..73ebaa75 100644
--- a/packages/server/src/setup/traefik-setup.ts
+++ b/packages/server/src/setup/traefik-setup.ts
@@ -23,6 +23,7 @@ interface TraefikOptions {
publishedPort: number;
publishMode?: "ingress" | "host";
}[];
+ force?: boolean;
}
export const initializeTraefik = async ({
@@ -30,10 +31,33 @@ export const initializeTraefik = async ({
env,
serverId,
additionalPorts = [],
+ force = false,
}: TraefikOptions = {}) => {
const { MAIN_TRAEFIK_PATH, DYNAMIC_TRAEFIK_PATH } = paths(!!serverId);
const imageName = `traefik:v${TRAEFIK_VERSION}`;
const containerName = "dokploy-traefik";
+
+ const exposedPorts: Record = {
+ [`${TRAEFIK_PORT}/tcp`]: {},
+ [`${TRAEFIK_SSL_PORT}/tcp`]: {},
+ };
+
+ const portBindings: Record> = {
+ [`${TRAEFIK_PORT}/tcp`]: [{ HostPort: TRAEFIK_PORT.toString() }],
+ [`${TRAEFIK_SSL_PORT}/tcp`]: [{ HostPort: TRAEFIK_SSL_PORT.toString() }],
+ };
+
+ if (enableDashboard) {
+ exposedPorts["8080/tcp"] = {};
+ portBindings["8080/tcp"] = [{ HostPort: "8080" }];
+ }
+
+ for (const port of additionalPorts) {
+ const portKey = `${port.targetPort}/tcp`;
+ exposedPorts[portKey] = {};
+ portBindings[portKey] = [{ HostPort: port.publishedPort.toString() }];
+ }
+
const settings: ContainerCreateOptions = {
name: containerName,
Image: imageName,
@@ -42,6 +66,7 @@ export const initializeTraefik = async ({
"dokploy-network": {},
},
},
+ ExposedPorts: exposedPorts,
HostConfig: {
RestartPolicy: {
Name: "always",
@@ -51,37 +76,11 @@ export const initializeTraefik = async ({
`${DYNAMIC_TRAEFIK_PATH}:/etc/dokploy/traefik/dynamic`,
"/var/run/docker.sock:/var/run/docker.sock",
],
- PortBindings: {
- [`${TRAEFIK_SSL_PORT}/tcp`]: [
- {
- HostPort: TRAEFIK_SSL_PORT.toString(),
- },
- ],
- [`${TRAEFIK_PORT}/tcp`]: [
- {
- HostPort: TRAEFIK_PORT.toString(),
- },
- ],
- ...(enableDashboard && {
- [`${8080}/tcp`]: [
- {
- HostPort: "8080",
- },
- ],
- }),
- ...additionalPorts.map((port) => {
- return {
- [`${port.targetPort}/tcp`]: [
- {
- HostPort: port.publishedPort.toString(),
- },
- ],
- };
- }),
- },
+ PortBindings: portBindings,
},
Env: env,
};
+
const docker = await getRemoteDocker(serverId);
try {
if (serverId) {
@@ -93,7 +92,7 @@ export const initializeTraefik = async ({
const container = docker.getContainer(containerName);
try {
const inspect = await container.inspect();
- if (inspect.State.Status === "running") {
+ if (inspect.State.Status === "running" && !force) {
console.log("Traefik already running");
return;
}
@@ -112,6 +111,7 @@ export const initializeTraefik = async ({
console.log("Traefik Started ✅");
} catch (error) {
console.log("Traefik Not Found: Starting2 ✅", error);
+ throw error;
}
};