Skip to content

Commit 6287f3b

Browse files
authored
Merge pull request #1371 from Dokploy/1345-domain-not-working-after-server-restart-or-traefik-reload
refactor(traefik): migrate from Docker Swarm service to standalone co…
2 parents 978cd61 + b7f63fd commit 6287f3b

File tree

7 files changed

+172
-160
lines changed

7 files changed

+172
-160
lines changed

apps/dokploy/components/dashboard/settings/servers/actions/show-traefik-actions.tsx

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,11 @@ export const ShowTraefikActions = ({ serverId }: Props) => {
6767
>
6868
<span>{t("settings.server.webServer.reload")}</span>
6969
</DropdownMenuItem>
70-
<ShowModalLogs appName="dokploy-traefik" serverId={serverId}>
70+
<ShowModalLogs
71+
appName="dokploy-traefik"
72+
serverId={serverId}
73+
type="standalone"
74+
>
7175
<DropdownMenuItem
7276
onSelect={(e) => e.preventDefault()}
7377
className="cursor-pointer"
@@ -108,15 +112,6 @@ export const ShowTraefikActions = ({ serverId }: Props) => {
108112
{haveTraefikDashboardPortEnabled ? "Disable" : "Enable"} Dashboard
109113
</span>
110114
</DropdownMenuItem>
111-
{/*
112-
<DockerTerminalModal appName="dokploy-traefik">
113-
<DropdownMenuItem
114-
className="w-full cursor-pointer space-x-3"
115-
onSelect={(e) => e.preventDefault()}
116-
>
117-
<span>Enter the terminal</span>
118-
</DropdownMenuItem>
119-
</DockerTerminalModal> */}
120115
<ManageTraefikPorts serverId={serverId}>
121116
<DropdownMenuItem
122117
onSelect={(e) => e.preventDefault()}

apps/dokploy/components/dashboard/settings/web-server/show-modal-logs.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,20 @@ interface Props {
3636
appName: string;
3737
children?: React.ReactNode;
3838
serverId?: string;
39+
type?: "standalone" | "swarm";
3940
}
4041

41-
export const ShowModalLogs = ({ appName, children, serverId }: Props) => {
42+
export const ShowModalLogs = ({
43+
appName,
44+
children,
45+
serverId,
46+
type = "swarm",
47+
}: Props) => {
4248
const { data, isLoading } = api.docker.getContainersByAppLabel.useQuery(
4349
{
4450
appName,
4551
serverId,
52+
type,
4653
},
4754
{
4855
enabled: !!appName,

apps/dokploy/server/api/routers/docker.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,15 @@ export const dockerRouter = createTRPCRouter({
6565
z.object({
6666
appName: z.string().min(1),
6767
serverId: z.string().optional(),
68+
type: z.enum(["standalone", "swarm"]),
6869
}),
6970
)
7071
.query(async ({ input }) => {
71-
return await getContainersByAppLabel(input.appName, input.serverId);
72+
return await getContainersByAppLabel(
73+
input.appName,
74+
input.type,
75+
input.serverId,
76+
);
7277
}),
7378

7479
getStackContainersByAppName: protectedProcedure

apps/dokploy/server/api/routers/settings.ts

Lines changed: 54 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,6 @@ import {
4141
recreateDirectory,
4242
sendDockerCleanupNotifications,
4343
spawnAsync,
44-
startService,
45-
startServiceRemote,
46-
stopService,
47-
stopServiceRemote,
4844
updateLetsEncryptEmail,
4945
updateServerById,
5046
updateServerTraefik,
@@ -88,11 +84,9 @@ export const settingsRouter = createTRPCRouter({
8884
.mutation(async ({ input }) => {
8985
try {
9086
if (input?.serverId) {
91-
await stopServiceRemote(input.serverId, "dokploy-traefik");
92-
await startServiceRemote(input.serverId, "dokploy-traefik");
87+
await execAsync("docker restart dokploy-traefik");
9388
} else if (!IS_CLOUD) {
94-
await stopService("dokploy-traefik");
95-
await startService("dokploy-traefik");
89+
await execAsync("docker restart dokploy-traefik");
9690
}
9791
} catch (err) {
9892
console.error(err);
@@ -106,6 +100,7 @@ export const settingsRouter = createTRPCRouter({
106100
await initializeTraefik({
107101
enableDashboard: input.enableDashboard,
108102
serverId: input.serverId,
103+
force: true,
109104
});
110105
return true;
111106
}),
@@ -513,16 +508,18 @@ export const settingsRouter = createTRPCRouter({
513508
.input(apiServerSchema)
514509
.query(async ({ input }) => {
515510
const command =
516-
"docker service inspect --format='{{range .Spec.TaskTemplate.ContainerSpec.Env}}{{println .}}{{end}}' dokploy-traefik";
511+
"docker container inspect dokploy-traefik --format '{{json .Config.Env}}'";
517512

513+
let result = "";
518514
if (input?.serverId) {
519-
const result = await execAsyncRemote(input.serverId, command);
520-
return result.stdout.trim();
521-
}
522-
if (!IS_CLOUD) {
523-
const result = await execAsync(command);
524-
return result.stdout.trim();
515+
const execResult = await execAsyncRemote(input.serverId, command);
516+
result = execResult.stdout;
517+
} else {
518+
const execResult = await execAsync(command);
519+
result = execResult.stdout;
525520
}
521+
const envVars = JSON.parse(result.trim());
522+
return envVars.join("\n");
526523
}),
527524

528525
writeTraefikEnv: adminProcedure
@@ -532,34 +529,30 @@ export const settingsRouter = createTRPCRouter({
532529
await initializeTraefik({
533530
env: envs,
534531
serverId: input.serverId,
532+
force: true,
535533
});
536534

537535
return true;
538536
}),
539537
haveTraefikDashboardPortEnabled: adminProcedure
540538
.input(apiServerSchema)
541539
.query(async ({ input }) => {
542-
const command = `docker service inspect --format='{{json .Endpoint.Ports}}' dokploy-traefik`;
540+
const command = `docker container inspect --format='{{json .NetworkSettings.Ports}}' dokploy-traefik`;
543541

544542
let stdout = "";
545543
if (input?.serverId) {
546544
const result = await execAsyncRemote(input.serverId, command);
547545
stdout = result.stdout;
548546
} else if (!IS_CLOUD) {
549-
const result = await execAsync(
550-
"docker service inspect --format='{{json .Endpoint.Ports}}' dokploy-traefik",
551-
);
547+
const result = await execAsync(command);
552548
stdout = result.stdout;
553549
}
554550

555-
const parsed: any[] = JSON.parse(stdout.trim());
556-
for (const port of parsed) {
557-
if (port.PublishedPort === 8080) {
558-
return true;
559-
}
560-
}
561-
562-
return false;
551+
const ports = JSON.parse(stdout.trim());
552+
return Object.entries(ports).some(([containerPort, bindings]) => {
553+
const [port] = containerPort.split("/");
554+
return port === "8080" && bindings && (bindings as any[]).length > 0;
555+
});
563556
}),
564557

565558
readStatsLogs: adminProcedure
@@ -772,6 +765,7 @@ export const settingsRouter = createTRPCRouter({
772765
await initializeTraefik({
773766
serverId: input.serverId,
774767
additionalPorts: input.additionalPorts,
768+
force: true,
775769
});
776770
return true;
777771
} catch (error) {
@@ -788,7 +782,7 @@ export const settingsRouter = createTRPCRouter({
788782
getTraefikPorts: adminProcedure
789783
.input(apiServerSchema)
790784
.query(async ({ input }) => {
791-
const command = `docker service inspect --format='{{json .Endpoint.Ports}}' dokploy-traefik`;
785+
const command = `docker container inspect --format='{{json .NetworkSettings.Ports}}' dokploy-traefik`;
792786

793787
try {
794788
let stdout = "";
@@ -800,21 +794,38 @@ export const settingsRouter = createTRPCRouter({
800794
stdout = result.stdout;
801795
}
802796

803-
const ports: {
804-
Protocol: string;
805-
TargetPort: number;
806-
PublishedPort: number;
807-
PublishMode: string;
808-
}[] = JSON.parse(stdout.trim());
809-
810-
// Filter out the default ports (80, 443, and optionally 8080)
811-
const additionalPorts = ports
812-
.filter((port) => ![80, 443, 8080].includes(port.PublishedPort))
813-
.map((port) => ({
814-
targetPort: port.TargetPort,
815-
publishedPort: port.PublishedPort,
816-
publishMode: port.PublishMode.toLowerCase() as "host" | "ingress",
817-
}));
797+
const portsMap = JSON.parse(stdout.trim());
798+
const additionalPorts: Array<{
799+
targetPort: number;
800+
publishedPort: number;
801+
publishMode: "host" | "ingress";
802+
}> = [];
803+
804+
// Convert the Docker container port format to our expected format
805+
for (const [containerPort, bindings] of Object.entries(portsMap)) {
806+
if (!bindings) continue;
807+
808+
const [port = ""] = containerPort.split("/");
809+
if (!port) continue;
810+
811+
const targetPortNum = Number.parseInt(port, 10);
812+
if (Number.isNaN(targetPortNum)) continue;
813+
814+
// Skip default ports
815+
if ([80, 443, 8080].includes(targetPortNum)) continue;
816+
817+
for (const binding of bindings as Array<{ HostPort: string }>) {
818+
if (!binding.HostPort) continue;
819+
const publishedPort = Number.parseInt(binding.HostPort, 10);
820+
if (Number.isNaN(publishedPort)) continue;
821+
822+
additionalPorts.push({
823+
targetPort: targetPortNum,
824+
publishedPort,
825+
publishMode: "host", // Docker standalone uses host mode by default
826+
});
827+
}
828+
}
818829

819830
return additionalPorts;
820831
} catch (error) {

packages/server/src/services/docker.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,13 +287,19 @@ export const getServiceContainersByAppName = async (
287287

288288
export const getContainersByAppLabel = async (
289289
appName: string,
290+
type: "standalone" | "swarm",
290291
serverId?: string,
291292
) => {
292293
try {
293294
let stdout = "";
294295
let stderr = "";
295296

296-
const command = `docker ps --filter "label=com.docker.swarm.service.name=${appName}" --format 'CONTAINER ID : {{.ID}} | Name: {{.Names}} | State: {{.State}}'`;
297+
const command =
298+
type === "swarm"
299+
? `docker ps --filter "label=com.docker.swarm.service.name=${appName}" --format 'CONTAINER ID : {{.ID}} | Name: {{.Names}} | State: {{.State}}'`
300+
: type === "standalone"
301+
? `docker ps --filter "name=${appName}" --format 'CONTAINER ID : {{.ID}} | Name: {{.Names}} | State: {{.State}}'`
302+
: `docker ps --filter "label=com.docker.compose.project=${appName}" --format 'CONTAINER ID : {{.ID}} | Name: {{.Names}} | State: {{.State}}'`;
297303
if (serverId) {
298304
const result = await execAsyncRemote(serverId, command);
299305
stdout = result.stdout;

packages/server/src/setup/server-setup.ts

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
TRAEFIK_PORT,
1010
TRAEFIK_SSL_PORT,
1111
TRAEFIK_VERSION,
12+
TRAEFIK_HTTP3_PORT,
1213
getDefaultMiddlewares,
1314
getDefaultServerTraefikConfig,
1415
} from "@dokploy/server/setup/traefik-setup";
@@ -542,22 +543,28 @@ export const installRClone = () => `
542543
export const createTraefikInstance = () => {
543544
const command = `
544545
# Check if dokpyloy-traefik exists
545-
if docker service ls | grep -q 'dokploy-traefik'; then
546+
if docker service inspect dokploy-traefik > /dev/null 2>&1; then
547+
echo "Migrating Traefik to Standalone..."
548+
docker service rm dokploy-traefik
549+
sleep 7
550+
echo "Traefik migrated to Standalone ✅"
551+
fi
552+
553+
if docker inspect dokploy-traefik > /dev/null 2>&1; then
546554
echo "Traefik already exists ✅"
547555
else
548-
# Create the dokploy-traefik service
556+
# Create the dokploy-traefik container
549557
TRAEFIK_VERSION=${TRAEFIK_VERSION}
550-
docker service create \
558+
docker run -d \
551559
--name dokploy-traefik \
552-
--replicas 1 \
553-
--constraint 'node.role==manager' \
554560
--network dokploy-network \
555-
--mount type=bind,src=/etc/dokploy/traefik/traefik.yml,dst=/etc/traefik/traefik.yml \
556-
--mount type=bind,src=/etc/dokploy/traefik/dynamic,dst=/etc/dokploy/traefik/dynamic \
557-
--mount type=bind,src=/var/run/docker.sock,dst=/var/run/docker.sock \
558-
--label traefik.enable=true \
559-
--publish mode=host,target=${TRAEFIK_SSL_PORT},published=${TRAEFIK_SSL_PORT} \
560-
--publish mode=host,target=${TRAEFIK_PORT},published=${TRAEFIK_PORT} \
561+
--restart unless-stopped \
562+
-v /etc/dokploy/traefik/traefik.yml:/etc/traefik/traefik.yml \
563+
-v /etc/dokploy/traefik/dynamic:/etc/dokploy/traefik/dynamic \
564+
-v /var/run/docker.sock:/var/run/docker.sock \
565+
-p ${TRAEFIK_SSL_PORT}:${TRAEFIK_SSL_PORT} \
566+
-p ${TRAEFIK_PORT}:${TRAEFIK_PORT} \
567+
-p ${TRAEFIK_HTTP3_PORT}:${TRAEFIK_HTTP3_PORT}/udp \
561568
traefik:v$TRAEFIK_VERSION
562569
echo "Traefik version $TRAEFIK_VERSION installed ✅"
563570
fi

0 commit comments

Comments
 (0)