Skip to content

Commit fb4e92d

Browse files
committed
fix(traefik): restrict default Dokploy route
1 parent f12ecc3 commit fb4e92d

3 files changed

Lines changed: 397 additions & 19 deletions

File tree

apps/dokploy/__test__/traefik/server/update-server-config.test.ts

Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,257 @@ test("Should read the configuration file", () => {
8282
expect(config.http?.routers?.["dokploy-router-app"]?.service).toBe(
8383
"dokploy-service-app",
8484
);
85+
expect(config.http?.routers?.["dokploy-router-app"]?.middlewares).toEqual([
86+
"dokploy-local-access",
87+
]);
88+
expect(config.http?.middlewares?.["dokploy-local-access"]).toEqual({
89+
ipAllowList: {
90+
sourceRange: [
91+
"127.0.0.1/32",
92+
"10.0.0.0/8",
93+
"172.16.0.0/12",
94+
"192.168.0.0/16",
95+
],
96+
},
97+
});
98+
});
99+
100+
test("Should migrate existing configuration with the local-access allowlist", () => {
101+
vol.reset();
102+
fs.mkdirSync(".docker/traefik/dynamic", { recursive: true });
103+
fs.writeFileSync(
104+
".docker/traefik/dynamic/dokploy.yml",
105+
`http:
106+
routers:
107+
dokploy-router-app:
108+
rule: Host(\`dokploy.docker.localhost\`) && PathPrefix(\`/\`)
109+
service: dokploy-service-app
110+
entryPoints:
111+
- web
112+
custom-router:
113+
rule: Host(\`custom.example.com\`)
114+
service: custom-service
115+
middlewares:
116+
custom-middleware:
117+
headers:
118+
customRequestHeaders:
119+
X-Test: preserved
120+
services:
121+
dokploy-service-app:
122+
loadBalancer:
123+
servers:
124+
- url: http://dokploy:3000
125+
custom-service:
126+
loadBalancer:
127+
servers:
128+
- url: http://custom:3000
129+
`,
130+
);
131+
132+
createDefaultServerTraefikConfig();
133+
134+
const config: FileConfig = loadOrCreateConfig("dokploy");
135+
expect(config.http?.routers?.["dokploy-router-app"]?.middlewares).toEqual([
136+
"dokploy-local-access",
137+
]);
138+
expect(config.http?.middlewares?.["dokploy-local-access"]).toEqual({
139+
ipAllowList: {
140+
sourceRange: [
141+
"127.0.0.1/32",
142+
"10.0.0.0/8",
143+
"172.16.0.0/12",
144+
"192.168.0.0/16",
145+
],
146+
},
147+
});
148+
expect(config.http?.routers?.["custom-router"]?.service).toBe(
149+
"custom-service",
150+
);
151+
expect(config.http?.middlewares?.["custom-middleware"]).toBeDefined();
152+
});
153+
154+
test("Should reconcile an ineffective local-access middleware", () => {
155+
vol.reset();
156+
fs.mkdirSync(".docker/traefik/dynamic", { recursive: true });
157+
fs.writeFileSync(
158+
".docker/traefik/dynamic/dokploy.yml",
159+
`http:
160+
routers:
161+
dokploy-router-app:
162+
rule: Host(\`dokploy.docker.localhost\`) && PathPrefix(\`/\`)
163+
service: dokploy-service-app
164+
entryPoints:
165+
- web
166+
middlewares:
167+
- dokploy-local-access
168+
middlewares:
169+
dokploy-local-access:
170+
headers:
171+
customRequestHeaders:
172+
X-Test: ineffective
173+
`,
174+
);
175+
176+
createDefaultServerTraefikConfig();
177+
178+
const config: FileConfig = loadOrCreateConfig("dokploy");
179+
expect(config.http?.routers?.["dokploy-router-app"]?.middlewares).toEqual([
180+
"dokploy-local-access",
181+
]);
182+
expect(config.http?.middlewares?.["dokploy-local-access"]).toEqual({
183+
ipAllowList: {
184+
sourceRange: [
185+
"127.0.0.1/32",
186+
"10.0.0.0/8",
187+
"172.16.0.0/12",
188+
"192.168.0.0/16",
189+
],
190+
},
191+
});
192+
});
193+
194+
test("Should not migrate the local-access allowlist for a custom domain", () => {
195+
vol.reset();
196+
fs.mkdirSync(".docker/traefik/dynamic", { recursive: true });
197+
fs.writeFileSync(
198+
".docker/traefik/dynamic/dokploy.yml",
199+
`http:
200+
routers:
201+
dokploy-router-app:
202+
rule: Host(\`dash.example.com\`)
203+
service: dokploy-service-app
204+
entryPoints:
205+
- web
206+
middlewares:
207+
- redirect-to-https
208+
services:
209+
dokploy-service-app:
210+
loadBalancer:
211+
servers:
212+
- url: http://dokploy:3000
213+
`,
214+
);
215+
216+
createDefaultServerTraefikConfig();
217+
218+
const config: FileConfig = loadOrCreateConfig("dokploy");
219+
expect(config.http?.routers?.["dokploy-router-app"]).toEqual({
220+
rule: "Host(`dash.example.com`)",
221+
service: "dokploy-service-app",
222+
entryPoints: ["web"],
223+
middlewares: ["redirect-to-https"],
224+
});
225+
expect(config.http?.middlewares?.["dokploy-local-access"]).toBeUndefined();
226+
});
227+
228+
test("Should skip malformed default traefik configuration", () => {
229+
vol.reset();
230+
fs.mkdirSync(".docker/traefik/dynamic", { recursive: true });
231+
const malformedConfig = "http:\n routers: [\n";
232+
fs.writeFileSync(".docker/traefik/dynamic/dokploy.yml", malformedConfig);
233+
234+
expect(() => createDefaultServerTraefikConfig()).not.toThrow();
235+
expect(fs.readFileSync(".docker/traefik/dynamic/dokploy.yml", "utf8")).toBe(
236+
malformedConfig,
237+
);
238+
});
239+
240+
test("Should skip a configuration without HTTP routers", () => {
241+
vol.reset();
242+
fs.mkdirSync(".docker/traefik/dynamic", { recursive: true });
243+
const configWithoutHttp = "tcp:\n routers: {}\n";
244+
fs.writeFileSync(".docker/traefik/dynamic/dokploy.yml", configWithoutHttp);
245+
246+
expect(() => createDefaultServerTraefikConfig()).not.toThrow();
247+
expect(fs.readFileSync(".docker/traefik/dynamic/dokploy.yml", "utf8")).toBe(
248+
configWithoutHttp,
249+
);
250+
});
251+
252+
test("Should skip a configuration with HTTP but no routers", () => {
253+
vol.reset();
254+
fs.mkdirSync(".docker/traefik/dynamic", { recursive: true });
255+
const configWithoutRouters = "http:\n services: {}\n";
256+
fs.writeFileSync(".docker/traefik/dynamic/dokploy.yml", configWithoutRouters);
257+
258+
expect(() => createDefaultServerTraefikConfig()).not.toThrow();
259+
expect(fs.readFileSync(".docker/traefik/dynamic/dokploy.yml", "utf8")).toBe(
260+
configWithoutRouters,
261+
);
262+
});
263+
264+
test("Should migrate a default router without an HTTP middleware map", () => {
265+
vol.reset();
266+
fs.mkdirSync(".docker/traefik/dynamic", { recursive: true });
267+
fs.writeFileSync(
268+
".docker/traefik/dynamic/dokploy.yml",
269+
`http:
270+
routers:
271+
dokploy-router-app:
272+
rule: Host(\`dokploy.docker.localhost\`) && PathPrefix(\`/\`)
273+
service: dokploy-service-app
274+
entryPoints:
275+
- web
276+
`,
277+
);
278+
279+
createDefaultServerTraefikConfig();
280+
281+
const config: FileConfig = loadOrCreateConfig("dokploy");
282+
expect(config.http?.routers?.["dokploy-router-app"]?.middlewares).toEqual([
283+
"dokploy-local-access",
284+
]);
285+
expect(config.http?.middlewares?.["dokploy-local-access"]).toBeDefined();
286+
});
287+
288+
test("Should skip a configuration with a malformed HTTP middleware map", () => {
289+
vol.reset();
290+
fs.mkdirSync(".docker/traefik/dynamic", { recursive: true });
291+
const malformedMiddlewares = `http:
292+
routers:
293+
dokploy-router-app:
294+
rule: Host(\`dokploy.docker.localhost\`) && PathPrefix(\`/\`)
295+
service: dokploy-service-app
296+
entryPoints:
297+
- web
298+
middlewares: redirect-to-https
299+
`;
300+
fs.writeFileSync(".docker/traefik/dynamic/dokploy.yml", malformedMiddlewares);
301+
302+
expect(() => createDefaultServerTraefikConfig()).not.toThrow();
303+
expect(fs.readFileSync(".docker/traefik/dynamic/dokploy.yml", "utf8")).toBe(
304+
malformedMiddlewares,
305+
);
306+
});
307+
308+
test("Should skip a default router with malformed middlewares", () => {
309+
vol.reset();
310+
fs.mkdirSync(".docker/traefik/dynamic", { recursive: true });
311+
const malformedMiddlewares = `http:
312+
routers:
313+
dokploy-router-app:
314+
rule: Host(\`dokploy.docker.localhost\`) && PathPrefix(\`/\`)
315+
service: dokploy-service-app
316+
entryPoints:
317+
- web
318+
middlewares: redirect-to-https
319+
`;
320+
fs.writeFileSync(".docker/traefik/dynamic/dokploy.yml", malformedMiddlewares);
321+
322+
expect(() => createDefaultServerTraefikConfig()).not.toThrow();
323+
expect(fs.readFileSync(".docker/traefik/dynamic/dokploy.yml", "utf8")).toBe(
324+
malformedMiddlewares,
325+
);
326+
});
327+
328+
test("Should skip a default traefik configuration path that is a directory", () => {
329+
vol.reset();
330+
fs.mkdirSync(".docker/traefik/dynamic/dokploy.yml", { recursive: true });
331+
332+
expect(() => createDefaultServerTraefikConfig()).not.toThrow();
333+
expect(fs.statSync(".docker/traefik/dynamic/dokploy.yml").isDirectory()).toBe(
334+
true,
335+
);
85336
});
86337

87338
test("Should apply redirect-to-https", () => {

0 commit comments

Comments
 (0)