From 3864c50deb3f4592b3440726c4b5c93eccf4c7fb Mon Sep 17 00:00:00 2001 From: Vyacheslav Scherbinin Date: Wed, 13 Aug 2025 08:23:30 +0700 Subject: [PATCH 1/2] bump: Traefik v3.5.0 --- apps/dokploy/setup.ts | 51 +- packages/server/src/setup/traefik-setup.ts | 696 ++++++++++----------- 2 files changed, 362 insertions(+), 385 deletions(-) diff --git a/apps/dokploy/setup.ts b/apps/dokploy/setup.ts index 7abf9fa2d..22dea48d3 100644 --- a/apps/dokploy/setup.ts +++ b/apps/dokploy/setup.ts @@ -1,31 +1,28 @@ -import { execAsync } from "@dokploy/server"; -import { setupDirectories } from "@dokploy/server/setup/config-paths"; -import { initializePostgres } from "@dokploy/server/setup/postgres-setup"; -import { initializeRedis } from "@dokploy/server/setup/redis-setup"; +import { execAsync } from '@dokploy/server'; +import { setupDirectories } from '@dokploy/server/setup/config-paths'; +import { initializePostgres } from '@dokploy/server/setup/postgres-setup'; +import { initializeRedis } from '@dokploy/server/setup/redis-setup'; +import { initializeNetwork, initializeSwarm } from '@dokploy/server/setup/setup'; import { - initializeNetwork, - initializeSwarm, -} from "@dokploy/server/setup/setup"; -import { - createDefaultMiddlewares, - createDefaultServerTraefikConfig, - createDefaultTraefikConfig, - initializeStandaloneTraefik, -} from "@dokploy/server/setup/traefik-setup"; + createDefaultMiddlewares, + createDefaultServerTraefikConfig, + createDefaultTraefikConfig, + initializeStandaloneTraefik, +} from '@dokploy/server/setup/traefik-setup'; (async () => { - try { - setupDirectories(); - createDefaultMiddlewares(); - await initializeSwarm(); - await initializeNetwork(); - createDefaultTraefikConfig(); - createDefaultServerTraefikConfig(); - await execAsync("docker pull traefik:v3.1.2"); - await initializeStandaloneTraefik(); - await initializeRedis(); - await initializePostgres(); - } catch (e) { - console.error("Error in dokploy setup", e); - } + try { + setupDirectories(); + createDefaultMiddlewares(); + await initializeSwarm(); + await initializeNetwork(); + createDefaultTraefikConfig(); + createDefaultServerTraefikConfig(); + await execAsync('docker pull traefik:v3.5.0'); + await initializeStandaloneTraefik(); + await initializeRedis(); + await initializePostgres(); + } catch (e) { + console.error('Error in dokploy setup', e); + } })(); diff --git a/packages/server/src/setup/traefik-setup.ts b/packages/server/src/setup/traefik-setup.ts index ccdfa30f8..9022aeb12 100644 --- a/packages/server/src/setup/traefik-setup.ts +++ b/packages/server/src/setup/traefik-setup.ts @@ -1,402 +1,382 @@ -import { chmodSync, existsSync, mkdirSync, writeFileSync } from "node:fs"; -import path from "node:path"; -import type { ContainerCreateOptions, CreateServiceOptions } from "dockerode"; -import { dump } from "js-yaml"; -import { paths } from "../constants"; -import { getRemoteDocker } from "../utils/servers/remote-docker"; -import type { FileConfig } from "../utils/traefik/file-types"; -import type { MainTraefikConfig } from "../utils/traefik/types"; +import { chmodSync, existsSync, mkdirSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import type { ContainerCreateOptions, CreateServiceOptions } from 'dockerode'; +import { dump } from 'js-yaml'; +import { paths } from '../constants'; +import { getRemoteDocker } from '../utils/servers/remote-docker'; +import type { FileConfig } from '../utils/traefik/file-types'; +import type { MainTraefikConfig } from '../utils/traefik/types'; -export const TRAEFIK_SSL_PORT = - Number.parseInt(process.env.TRAEFIK_SSL_PORT!, 10) || 443; -export const TRAEFIK_PORT = - Number.parseInt(process.env.TRAEFIK_PORT!, 10) || 80; -export const TRAEFIK_HTTP3_PORT = - Number.parseInt(process.env.TRAEFIK_HTTP3_PORT!, 10) || 443; -export const TRAEFIK_VERSION = process.env.TRAEFIK_VERSION || "3.1.2"; +export const TRAEFIK_SSL_PORT = Number.parseInt(process.env.TRAEFIK_SSL_PORT!, 10) || 443; +export const TRAEFIK_PORT = Number.parseInt(process.env.TRAEFIK_PORT!, 10) || 80; +export const TRAEFIK_HTTP3_PORT = Number.parseInt(process.env.TRAEFIK_HTTP3_PORT!, 10) || 443; +export const TRAEFIK_VERSION = process.env.TRAEFIK_VERSION || '3.5.0'; export interface TraefikOptions { - env?: string[]; - serverId?: string; - additionalPorts?: { - targetPort: number; - publishedPort: number; - protocol?: string; - }[]; + env?: string[]; + serverId?: string; + additionalPorts?: { + targetPort: number; + publishedPort: number; + protocol?: string; + }[]; } -export const initializeStandaloneTraefik = async ({ - env, - serverId, - additionalPorts = [], -}: TraefikOptions = {}) => { - const { MAIN_TRAEFIK_PATH, DYNAMIC_TRAEFIK_PATH } = paths(!!serverId); - const imageName = `traefik:v${TRAEFIK_VERSION}`; - const containerName = "dokploy-traefik"; +export const initializeStandaloneTraefik = async ({ env, serverId, additionalPorts = [] }: 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`]: {}, - [`${TRAEFIK_HTTP3_PORT}/udp`]: {}, - }; + const exposedPorts: Record = { + [`${TRAEFIK_PORT}/tcp`]: {}, + [`${TRAEFIK_SSL_PORT}/tcp`]: {}, + [`${TRAEFIK_HTTP3_PORT}/udp`]: {}, + }; - const portBindings: Record> = { - [`${TRAEFIK_PORT}/tcp`]: [{ HostPort: TRAEFIK_PORT.toString() }], - [`${TRAEFIK_SSL_PORT}/tcp`]: [{ HostPort: TRAEFIK_SSL_PORT.toString() }], - [`${TRAEFIK_HTTP3_PORT}/udp`]: [ - { HostPort: TRAEFIK_HTTP3_PORT.toString() }, - ], - }; + const portBindings: Record> = { + [`${TRAEFIK_PORT}/tcp`]: [{ HostPort: TRAEFIK_PORT.toString() }], + [`${TRAEFIK_SSL_PORT}/tcp`]: [{ HostPort: TRAEFIK_SSL_PORT.toString() }], + [`${TRAEFIK_HTTP3_PORT}/udp`]: [{ HostPort: TRAEFIK_HTTP3_PORT.toString() }], + }; - const enableDashboard = additionalPorts.some( - (port) => port.targetPort === 8080, - ); + const enableDashboard = additionalPorts.some((port) => port.targetPort === 8080); - if (enableDashboard) { - exposedPorts["8080/tcp"] = {}; - portBindings["8080/tcp"] = [{ HostPort: "8080" }]; - } + if (enableDashboard) { + exposedPorts['8080/tcp'] = {}; + portBindings['8080/tcp'] = [{ HostPort: '8080' }]; + } - for (const port of additionalPorts) { - const portKey = `${port.targetPort}/${port.protocol ?? "tcp"}`; - exposedPorts[portKey] = {}; - portBindings[portKey] = [{ HostPort: port.publishedPort.toString() }]; - } + for (const port of additionalPorts) { + const portKey = `${port.targetPort}/${port.protocol ?? 'tcp'}`; + exposedPorts[portKey] = {}; + portBindings[portKey] = [{ HostPort: port.publishedPort.toString() }]; + } - const settings: ContainerCreateOptions = { - name: containerName, - Image: imageName, - NetworkingConfig: { - EndpointsConfig: { - "dokploy-network": {}, - }, - }, - ExposedPorts: exposedPorts, - HostConfig: { - RestartPolicy: { - Name: "always", - }, - Binds: [ - `${MAIN_TRAEFIK_PATH}/traefik.yml:/etc/traefik/traefik.yml`, - `${DYNAMIC_TRAEFIK_PATH}:/etc/dokploy/traefik/dynamic`, - "/var/run/docker.sock:/var/run/docker.sock", - ], - PortBindings: portBindings, - }, - Env: env, - }; + const settings: ContainerCreateOptions = { + name: containerName, + Image: imageName, + NetworkingConfig: { + EndpointsConfig: { + 'dokploy-network': {}, + }, + }, + ExposedPorts: exposedPorts, + HostConfig: { + RestartPolicy: { + Name: 'always', + }, + Binds: [ + `${MAIN_TRAEFIK_PATH}/traefik.yml:/etc/traefik/traefik.yml`, + `${DYNAMIC_TRAEFIK_PATH}:/etc/dokploy/traefik/dynamic`, + '/var/run/docker.sock:/var/run/docker.sock', + ], + PortBindings: portBindings, + }, + Env: env, + }; - const docker = await getRemoteDocker(serverId); - try { - const container = docker.getContainer(containerName); - await container.remove({ force: true }); - await new Promise((resolve) => setTimeout(resolve, 5000)); - } catch {} + const docker = await getRemoteDocker(serverId); + try { + const container = docker.getContainer(containerName); + await container.remove({ force: true }); + await new Promise((resolve) => setTimeout(resolve, 5000)); + } catch {} - await docker.createContainer(settings); - const newContainer = docker.getContainer(containerName); - await newContainer.start(); - console.log("Traefik Started ✅"); + await docker.createContainer(settings); + const newContainer = docker.getContainer(containerName); + await newContainer.start(); + console.log('Traefik Started ✅'); }; -export const initializeTraefikService = async ({ - env, - additionalPorts = [], - serverId, -}: TraefikOptions) => { - const { MAIN_TRAEFIK_PATH, DYNAMIC_TRAEFIK_PATH } = paths(!!serverId); - const imageName = `traefik:v${TRAEFIK_VERSION}`; - const appName = "dokploy-traefik"; +export const initializeTraefikService = async ({ env, additionalPorts = [], serverId }: TraefikOptions) => { + const { MAIN_TRAEFIK_PATH, DYNAMIC_TRAEFIK_PATH } = paths(!!serverId); + const imageName = `traefik:v${TRAEFIK_VERSION}`; + const appName = 'dokploy-traefik'; - const settings: CreateServiceOptions = { - Name: appName, - TaskTemplate: { - ContainerSpec: { - Image: imageName, - Env: env, - Mounts: [ - { - Type: "bind", - Source: `${MAIN_TRAEFIK_PATH}/traefik.yml`, - Target: "/etc/traefik/traefik.yml", - }, - { - Type: "bind", - Source: DYNAMIC_TRAEFIK_PATH, - Target: "/etc/dokploy/traefik/dynamic", - }, - { - Type: "bind", - Source: "/var/run/docker.sock", - Target: "/var/run/docker.sock", - }, - ], - }, - Networks: [{ Target: "dokploy-network" }], - Placement: { - Constraints: ["node.role==manager"], - }, - }, - Mode: { - Replicated: { - Replicas: 1, - }, - }, - EndpointSpec: { - Ports: [ - { - TargetPort: 443, - PublishedPort: TRAEFIK_SSL_PORT, - PublishMode: "host", - Protocol: "tcp", - }, - { - TargetPort: 443, - PublishedPort: TRAEFIK_SSL_PORT, - PublishMode: "host", - Protocol: "udp", - }, - { - TargetPort: 80, - PublishedPort: TRAEFIK_PORT, - PublishMode: "host", - Protocol: "tcp", - }, + const settings: CreateServiceOptions = { + Name: appName, + TaskTemplate: { + ContainerSpec: { + Image: imageName, + Env: env, + Mounts: [ + { + Type: 'bind', + Source: `${MAIN_TRAEFIK_PATH}/traefik.yml`, + Target: '/etc/traefik/traefik.yml', + }, + { + Type: 'bind', + Source: DYNAMIC_TRAEFIK_PATH, + Target: '/etc/dokploy/traefik/dynamic', + }, + { + Type: 'bind', + Source: '/var/run/docker.sock', + Target: '/var/run/docker.sock', + }, + ], + }, + Networks: [{ Target: 'dokploy-network' }], + Placement: { + Constraints: ['node.role==manager'], + }, + }, + Mode: { + Replicated: { + Replicas: 1, + }, + }, + EndpointSpec: { + Ports: [ + { + TargetPort: 443, + PublishedPort: TRAEFIK_SSL_PORT, + PublishMode: 'host', + Protocol: 'tcp', + }, + { + TargetPort: 443, + PublishedPort: TRAEFIK_SSL_PORT, + PublishMode: 'host', + Protocol: 'udp', + }, + { + TargetPort: 80, + PublishedPort: TRAEFIK_PORT, + PublishMode: 'host', + Protocol: 'tcp', + }, - ...additionalPorts.map((port) => ({ - TargetPort: port.targetPort, - PublishedPort: port.publishedPort, - Protocol: port.protocol as "tcp" | "udp" | "sctp" | undefined, - PublishMode: "host" as const, - })), - ], - }, - }; - const docker = await getRemoteDocker(serverId); - try { - const service = docker.getService(appName); - const inspect = await service.inspect(); + ...additionalPorts.map((port) => ({ + TargetPort: port.targetPort, + PublishedPort: port.publishedPort, + Protocol: port.protocol as 'tcp' | 'udp' | 'sctp' | undefined, + PublishMode: 'host' as const, + })), + ], + }, + }; + const docker = await getRemoteDocker(serverId); + try { + const service = docker.getService(appName); + const inspect = await service.inspect(); - await service.update({ - version: Number.parseInt(inspect.Version.Index), - ...settings, - TaskTemplate: { - ...settings.TaskTemplate, - ForceUpdate: inspect.Spec.TaskTemplate.ForceUpdate + 1, - }, - }); - console.log("Traefik Updated ✅"); - } catch { - await docker.createService(settings); - console.log("Traefik Started ✅"); - } + await service.update({ + version: Number.parseInt(inspect.Version.Index), + ...settings, + TaskTemplate: { + ...settings.TaskTemplate, + ForceUpdate: inspect.Spec.TaskTemplate.ForceUpdate + 1, + }, + }); + console.log('Traefik Updated ✅'); + } catch { + await docker.createService(settings); + console.log('Traefik Started ✅'); + } }; export const createDefaultServerTraefikConfig = () => { - const { DYNAMIC_TRAEFIK_PATH } = paths(); - const configFilePath = path.join(DYNAMIC_TRAEFIK_PATH, "dokploy.yml"); + const { DYNAMIC_TRAEFIK_PATH } = paths(); + const configFilePath = path.join(DYNAMIC_TRAEFIK_PATH, 'dokploy.yml'); - if (existsSync(configFilePath)) { - console.log("Default traefik config already exists"); - return; - } + if (existsSync(configFilePath)) { + console.log('Default traefik config already exists'); + return; + } - const appName = "dokploy"; - const serviceURLDefault = `http://${appName}:${process.env.PORT || 3000}`; - const config: FileConfig = { - http: { - routers: { - [`${appName}-router-app`]: { - rule: `Host(\`${appName}.docker.localhost\`) && PathPrefix(\`/\`)`, - service: `${appName}-service-app`, - entryPoints: ["web"], - }, - }, - services: { - [`${appName}-service-app`]: { - loadBalancer: { - servers: [{ url: serviceURLDefault }], - passHostHeader: true, - }, - }, - }, - }, - }; + const appName = 'dokploy'; + const serviceURLDefault = `http://${appName}:${process.env.PORT || 3000}`; + const config: FileConfig = { + http: { + routers: { + [`${appName}-router-app`]: { + rule: `Host(\`${appName}.docker.localhost\`) && PathPrefix(\`/\`)`, + service: `${appName}-service-app`, + entryPoints: ['web'], + }, + }, + services: { + [`${appName}-service-app`]: { + loadBalancer: { + servers: [{ url: serviceURLDefault }], + passHostHeader: true, + }, + }, + }, + }, + }; - const yamlStr = dump(config); - mkdirSync(DYNAMIC_TRAEFIK_PATH, { recursive: true }); - writeFileSync( - path.join(DYNAMIC_TRAEFIK_PATH, `${appName}.yml`), - yamlStr, - "utf8", - ); + const yamlStr = dump(config); + mkdirSync(DYNAMIC_TRAEFIK_PATH, { recursive: true }); + writeFileSync(path.join(DYNAMIC_TRAEFIK_PATH, `${appName}.yml`), yamlStr, 'utf8'); }; export const getDefaultTraefikConfig = () => { - const configObject: MainTraefikConfig = { - global: { - sendAnonymousUsage: false, - }, - providers: { - ...(process.env.NODE_ENV === "development" - ? { - docker: { - defaultRule: - "Host(`{{ trimPrefix `/` .Name }}.docker.localhost`)", - }, - } - : { - swarm: { - exposedByDefault: false, - watch: true, - }, - docker: { - exposedByDefault: false, - watch: true, - network: "dokploy-network", - }, - }), - file: { - directory: "/etc/dokploy/traefik/dynamic", - watch: true, - }, - }, - entryPoints: { - web: { - address: `:${TRAEFIK_PORT}`, - }, - websecure: { - address: `:${TRAEFIK_SSL_PORT}`, - http3: { - advertisedPort: TRAEFIK_HTTP3_PORT, - }, - ...(process.env.NODE_ENV === "production" && { - http: { - tls: { - certResolver: "letsencrypt", - }, - }, - }), - }, - }, - api: { - insecure: true, - }, - ...(process.env.NODE_ENV === "production" && { - certificatesResolvers: { - letsencrypt: { - acme: { - email: "test@localhost.com", - storage: "/etc/dokploy/traefik/dynamic/acme.json", - httpChallenge: { - entryPoint: "web", - }, - }, - }, - }, - }), - }; + const configObject: MainTraefikConfig = { + global: { + sendAnonymousUsage: false, + }, + providers: { + ...(process.env.NODE_ENV === 'development' + ? { + docker: { + defaultRule: 'Host(`{{ trimPrefix `/` .Name }}.docker.localhost`)', + }, + } + : { + swarm: { + exposedByDefault: false, + watch: true, + }, + docker: { + exposedByDefault: false, + watch: true, + network: 'dokploy-network', + }, + }), + file: { + directory: '/etc/dokploy/traefik/dynamic', + watch: true, + }, + }, + entryPoints: { + web: { + address: `:${TRAEFIK_PORT}`, + }, + websecure: { + address: `:${TRAEFIK_SSL_PORT}`, + http3: { + advertisedPort: TRAEFIK_HTTP3_PORT, + }, + ...(process.env.NODE_ENV === 'production' && { + http: { + tls: { + certResolver: 'letsencrypt', + }, + }, + }), + }, + }, + api: { + insecure: true, + }, + ...(process.env.NODE_ENV === 'production' && { + certificatesResolvers: { + letsencrypt: { + acme: { + email: 'test@localhost.com', + storage: '/etc/dokploy/traefik/dynamic/acme.json', + httpChallenge: { + entryPoint: 'web', + }, + }, + }, + }, + }), + }; - const yamlStr = dump(configObject); + const yamlStr = dump(configObject); - return yamlStr; + return yamlStr; }; export const getDefaultServerTraefikConfig = () => { - const configObject: MainTraefikConfig = { - providers: { - swarm: { - exposedByDefault: false, - watch: true, - }, - docker: { - exposedByDefault: false, - watch: true, - network: "dokploy-network", - }, - file: { - directory: "/etc/dokploy/traefik/dynamic", - watch: true, - }, - }, - entryPoints: { - web: { - address: `:${TRAEFIK_PORT}`, - }, - websecure: { - address: `:${TRAEFIK_SSL_PORT}`, - http3: { - advertisedPort: TRAEFIK_HTTP3_PORT, - }, - http: { - tls: { - certResolver: "letsencrypt", - }, - }, - }, - }, - api: { - insecure: true, - }, - certificatesResolvers: { - letsencrypt: { - acme: { - email: "test@localhost.com", - storage: "/etc/dokploy/traefik/dynamic/acme.json", - httpChallenge: { - entryPoint: "web", - }, - }, - }, - }, - }; + const configObject: MainTraefikConfig = { + providers: { + swarm: { + exposedByDefault: false, + watch: true, + }, + docker: { + exposedByDefault: false, + watch: true, + network: 'dokploy-network', + }, + file: { + directory: '/etc/dokploy/traefik/dynamic', + watch: true, + }, + }, + entryPoints: { + web: { + address: `:${TRAEFIK_PORT}`, + }, + websecure: { + address: `:${TRAEFIK_SSL_PORT}`, + http3: { + advertisedPort: TRAEFIK_HTTP3_PORT, + }, + http: { + tls: { + certResolver: 'letsencrypt', + }, + }, + }, + }, + api: { + insecure: true, + }, + certificatesResolvers: { + letsencrypt: { + acme: { + email: 'test@localhost.com', + storage: '/etc/dokploy/traefik/dynamic/acme.json', + httpChallenge: { + entryPoint: 'web', + }, + }, + }, + }, + }; - const yamlStr = dump(configObject); + const yamlStr = dump(configObject); - return yamlStr; + return yamlStr; }; export const createDefaultTraefikConfig = () => { - const { MAIN_TRAEFIK_PATH, DYNAMIC_TRAEFIK_PATH } = paths(); - const mainConfig = path.join(MAIN_TRAEFIK_PATH, "traefik.yml"); - const acmeJsonPath = path.join(DYNAMIC_TRAEFIK_PATH, "acme.json"); + const { MAIN_TRAEFIK_PATH, DYNAMIC_TRAEFIK_PATH } = paths(); + const mainConfig = path.join(MAIN_TRAEFIK_PATH, 'traefik.yml'); + const acmeJsonPath = path.join(DYNAMIC_TRAEFIK_PATH, 'acme.json'); - if (existsSync(acmeJsonPath)) { - chmodSync(acmeJsonPath, "600"); - } - if (existsSync(mainConfig)) { - console.log("Main config already exists"); - return; - } - const yamlStr = getDefaultTraefikConfig(); - mkdirSync(MAIN_TRAEFIK_PATH, { recursive: true }); - writeFileSync(mainConfig, yamlStr, "utf8"); + if (existsSync(acmeJsonPath)) { + chmodSync(acmeJsonPath, '600'); + } + if (existsSync(mainConfig)) { + console.log('Main config already exists'); + return; + } + const yamlStr = getDefaultTraefikConfig(); + mkdirSync(MAIN_TRAEFIK_PATH, { recursive: true }); + writeFileSync(mainConfig, yamlStr, 'utf8'); }; export const getDefaultMiddlewares = () => { - const defaultMiddlewares = { - http: { - middlewares: { - "redirect-to-https": { - redirectScheme: { - scheme: "https", - permanent: true, - }, - }, - }, - }, - }; - const yamlStr = dump(defaultMiddlewares); - return yamlStr; + const defaultMiddlewares = { + http: { + middlewares: { + 'redirect-to-https': { + redirectScheme: { + scheme: 'https', + permanent: true, + }, + }, + }, + }, + }; + const yamlStr = dump(defaultMiddlewares); + return yamlStr; }; export const createDefaultMiddlewares = () => { - const { DYNAMIC_TRAEFIK_PATH } = paths(); - const middlewaresPath = path.join(DYNAMIC_TRAEFIK_PATH, "middlewares.yml"); - if (existsSync(middlewaresPath)) { - console.log("Default middlewares already exists"); - return; - } - const yamlStr = getDefaultMiddlewares(); - mkdirSync(DYNAMIC_TRAEFIK_PATH, { recursive: true }); - writeFileSync(middlewaresPath, yamlStr, "utf8"); + const { DYNAMIC_TRAEFIK_PATH } = paths(); + const middlewaresPath = path.join(DYNAMIC_TRAEFIK_PATH, 'middlewares.yml'); + if (existsSync(middlewaresPath)) { + console.log('Default middlewares already exists'); + return; + } + const yamlStr = getDefaultMiddlewares(); + mkdirSync(DYNAMIC_TRAEFIK_PATH, { recursive: true }); + writeFileSync(middlewaresPath, yamlStr, 'utf8'); }; From 2c591cbd03510d24c3f5c9f072bd9a2747b12b49 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Wed, 13 Aug 2025 01:25:30 +0000 Subject: [PATCH 2/2] [autofix.ci] apply automated fixes --- apps/dokploy/setup.ts | 51 +- packages/server/src/setup/traefik-setup.ts | 696 +++++++++++---------- 2 files changed, 385 insertions(+), 362 deletions(-) diff --git a/apps/dokploy/setup.ts b/apps/dokploy/setup.ts index 22dea48d3..13590e4e7 100644 --- a/apps/dokploy/setup.ts +++ b/apps/dokploy/setup.ts @@ -1,28 +1,31 @@ -import { execAsync } from '@dokploy/server'; -import { setupDirectories } from '@dokploy/server/setup/config-paths'; -import { initializePostgres } from '@dokploy/server/setup/postgres-setup'; -import { initializeRedis } from '@dokploy/server/setup/redis-setup'; -import { initializeNetwork, initializeSwarm } from '@dokploy/server/setup/setup'; +import { execAsync } from "@dokploy/server"; +import { setupDirectories } from "@dokploy/server/setup/config-paths"; +import { initializePostgres } from "@dokploy/server/setup/postgres-setup"; +import { initializeRedis } from "@dokploy/server/setup/redis-setup"; import { - createDefaultMiddlewares, - createDefaultServerTraefikConfig, - createDefaultTraefikConfig, - initializeStandaloneTraefik, -} from '@dokploy/server/setup/traefik-setup'; + initializeNetwork, + initializeSwarm, +} from "@dokploy/server/setup/setup"; +import { + createDefaultMiddlewares, + createDefaultServerTraefikConfig, + createDefaultTraefikConfig, + initializeStandaloneTraefik, +} from "@dokploy/server/setup/traefik-setup"; (async () => { - try { - setupDirectories(); - createDefaultMiddlewares(); - await initializeSwarm(); - await initializeNetwork(); - createDefaultTraefikConfig(); - createDefaultServerTraefikConfig(); - await execAsync('docker pull traefik:v3.5.0'); - await initializeStandaloneTraefik(); - await initializeRedis(); - await initializePostgres(); - } catch (e) { - console.error('Error in dokploy setup', e); - } + try { + setupDirectories(); + createDefaultMiddlewares(); + await initializeSwarm(); + await initializeNetwork(); + createDefaultTraefikConfig(); + createDefaultServerTraefikConfig(); + await execAsync("docker pull traefik:v3.5.0"); + await initializeStandaloneTraefik(); + await initializeRedis(); + await initializePostgres(); + } catch (e) { + console.error("Error in dokploy setup", e); + } })(); diff --git a/packages/server/src/setup/traefik-setup.ts b/packages/server/src/setup/traefik-setup.ts index 9022aeb12..17c48d0ff 100644 --- a/packages/server/src/setup/traefik-setup.ts +++ b/packages/server/src/setup/traefik-setup.ts @@ -1,382 +1,402 @@ -import { chmodSync, existsSync, mkdirSync, writeFileSync } from 'node:fs'; -import path from 'node:path'; -import type { ContainerCreateOptions, CreateServiceOptions } from 'dockerode'; -import { dump } from 'js-yaml'; -import { paths } from '../constants'; -import { getRemoteDocker } from '../utils/servers/remote-docker'; -import type { FileConfig } from '../utils/traefik/file-types'; -import type { MainTraefikConfig } from '../utils/traefik/types'; +import { chmodSync, existsSync, mkdirSync, writeFileSync } from "node:fs"; +import path from "node:path"; +import type { ContainerCreateOptions, CreateServiceOptions } from "dockerode"; +import { dump } from "js-yaml"; +import { paths } from "../constants"; +import { getRemoteDocker } from "../utils/servers/remote-docker"; +import type { FileConfig } from "../utils/traefik/file-types"; +import type { MainTraefikConfig } from "../utils/traefik/types"; -export const TRAEFIK_SSL_PORT = Number.parseInt(process.env.TRAEFIK_SSL_PORT!, 10) || 443; -export const TRAEFIK_PORT = Number.parseInt(process.env.TRAEFIK_PORT!, 10) || 80; -export const TRAEFIK_HTTP3_PORT = Number.parseInt(process.env.TRAEFIK_HTTP3_PORT!, 10) || 443; -export const TRAEFIK_VERSION = process.env.TRAEFIK_VERSION || '3.5.0'; +export const TRAEFIK_SSL_PORT = + Number.parseInt(process.env.TRAEFIK_SSL_PORT!, 10) || 443; +export const TRAEFIK_PORT = + Number.parseInt(process.env.TRAEFIK_PORT!, 10) || 80; +export const TRAEFIK_HTTP3_PORT = + Number.parseInt(process.env.TRAEFIK_HTTP3_PORT!, 10) || 443; +export const TRAEFIK_VERSION = process.env.TRAEFIK_VERSION || "3.5.0"; export interface TraefikOptions { - env?: string[]; - serverId?: string; - additionalPorts?: { - targetPort: number; - publishedPort: number; - protocol?: string; - }[]; + env?: string[]; + serverId?: string; + additionalPorts?: { + targetPort: number; + publishedPort: number; + protocol?: string; + }[]; } -export const initializeStandaloneTraefik = async ({ env, serverId, additionalPorts = [] }: TraefikOptions = {}) => { - const { MAIN_TRAEFIK_PATH, DYNAMIC_TRAEFIK_PATH } = paths(!!serverId); - const imageName = `traefik:v${TRAEFIK_VERSION}`; - const containerName = 'dokploy-traefik'; +export const initializeStandaloneTraefik = async ({ + env, + serverId, + additionalPorts = [], +}: 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`]: {}, - [`${TRAEFIK_HTTP3_PORT}/udp`]: {}, - }; + const exposedPorts: Record = { + [`${TRAEFIK_PORT}/tcp`]: {}, + [`${TRAEFIK_SSL_PORT}/tcp`]: {}, + [`${TRAEFIK_HTTP3_PORT}/udp`]: {}, + }; - const portBindings: Record> = { - [`${TRAEFIK_PORT}/tcp`]: [{ HostPort: TRAEFIK_PORT.toString() }], - [`${TRAEFIK_SSL_PORT}/tcp`]: [{ HostPort: TRAEFIK_SSL_PORT.toString() }], - [`${TRAEFIK_HTTP3_PORT}/udp`]: [{ HostPort: TRAEFIK_HTTP3_PORT.toString() }], - }; + const portBindings: Record> = { + [`${TRAEFIK_PORT}/tcp`]: [{ HostPort: TRAEFIK_PORT.toString() }], + [`${TRAEFIK_SSL_PORT}/tcp`]: [{ HostPort: TRAEFIK_SSL_PORT.toString() }], + [`${TRAEFIK_HTTP3_PORT}/udp`]: [ + { HostPort: TRAEFIK_HTTP3_PORT.toString() }, + ], + }; - const enableDashboard = additionalPorts.some((port) => port.targetPort === 8080); + const enableDashboard = additionalPorts.some( + (port) => port.targetPort === 8080, + ); - if (enableDashboard) { - exposedPorts['8080/tcp'] = {}; - portBindings['8080/tcp'] = [{ HostPort: '8080' }]; - } + if (enableDashboard) { + exposedPorts["8080/tcp"] = {}; + portBindings["8080/tcp"] = [{ HostPort: "8080" }]; + } - for (const port of additionalPorts) { - const portKey = `${port.targetPort}/${port.protocol ?? 'tcp'}`; - exposedPorts[portKey] = {}; - portBindings[portKey] = [{ HostPort: port.publishedPort.toString() }]; - } + for (const port of additionalPorts) { + const portKey = `${port.targetPort}/${port.protocol ?? "tcp"}`; + exposedPorts[portKey] = {}; + portBindings[portKey] = [{ HostPort: port.publishedPort.toString() }]; + } - const settings: ContainerCreateOptions = { - name: containerName, - Image: imageName, - NetworkingConfig: { - EndpointsConfig: { - 'dokploy-network': {}, - }, - }, - ExposedPorts: exposedPorts, - HostConfig: { - RestartPolicy: { - Name: 'always', - }, - Binds: [ - `${MAIN_TRAEFIK_PATH}/traefik.yml:/etc/traefik/traefik.yml`, - `${DYNAMIC_TRAEFIK_PATH}:/etc/dokploy/traefik/dynamic`, - '/var/run/docker.sock:/var/run/docker.sock', - ], - PortBindings: portBindings, - }, - Env: env, - }; + const settings: ContainerCreateOptions = { + name: containerName, + Image: imageName, + NetworkingConfig: { + EndpointsConfig: { + "dokploy-network": {}, + }, + }, + ExposedPorts: exposedPorts, + HostConfig: { + RestartPolicy: { + Name: "always", + }, + Binds: [ + `${MAIN_TRAEFIK_PATH}/traefik.yml:/etc/traefik/traefik.yml`, + `${DYNAMIC_TRAEFIK_PATH}:/etc/dokploy/traefik/dynamic`, + "/var/run/docker.sock:/var/run/docker.sock", + ], + PortBindings: portBindings, + }, + Env: env, + }; - const docker = await getRemoteDocker(serverId); - try { - const container = docker.getContainer(containerName); - await container.remove({ force: true }); - await new Promise((resolve) => setTimeout(resolve, 5000)); - } catch {} + const docker = await getRemoteDocker(serverId); + try { + const container = docker.getContainer(containerName); + await container.remove({ force: true }); + await new Promise((resolve) => setTimeout(resolve, 5000)); + } catch {} - await docker.createContainer(settings); - const newContainer = docker.getContainer(containerName); - await newContainer.start(); - console.log('Traefik Started ✅'); + await docker.createContainer(settings); + const newContainer = docker.getContainer(containerName); + await newContainer.start(); + console.log("Traefik Started ✅"); }; -export const initializeTraefikService = async ({ env, additionalPorts = [], serverId }: TraefikOptions) => { - const { MAIN_TRAEFIK_PATH, DYNAMIC_TRAEFIK_PATH } = paths(!!serverId); - const imageName = `traefik:v${TRAEFIK_VERSION}`; - const appName = 'dokploy-traefik'; +export const initializeTraefikService = async ({ + env, + additionalPorts = [], + serverId, +}: TraefikOptions) => { + const { MAIN_TRAEFIK_PATH, DYNAMIC_TRAEFIK_PATH } = paths(!!serverId); + const imageName = `traefik:v${TRAEFIK_VERSION}`; + const appName = "dokploy-traefik"; - const settings: CreateServiceOptions = { - Name: appName, - TaskTemplate: { - ContainerSpec: { - Image: imageName, - Env: env, - Mounts: [ - { - Type: 'bind', - Source: `${MAIN_TRAEFIK_PATH}/traefik.yml`, - Target: '/etc/traefik/traefik.yml', - }, - { - Type: 'bind', - Source: DYNAMIC_TRAEFIK_PATH, - Target: '/etc/dokploy/traefik/dynamic', - }, - { - Type: 'bind', - Source: '/var/run/docker.sock', - Target: '/var/run/docker.sock', - }, - ], - }, - Networks: [{ Target: 'dokploy-network' }], - Placement: { - Constraints: ['node.role==manager'], - }, - }, - Mode: { - Replicated: { - Replicas: 1, - }, - }, - EndpointSpec: { - Ports: [ - { - TargetPort: 443, - PublishedPort: TRAEFIK_SSL_PORT, - PublishMode: 'host', - Protocol: 'tcp', - }, - { - TargetPort: 443, - PublishedPort: TRAEFIK_SSL_PORT, - PublishMode: 'host', - Protocol: 'udp', - }, - { - TargetPort: 80, - PublishedPort: TRAEFIK_PORT, - PublishMode: 'host', - Protocol: 'tcp', - }, + const settings: CreateServiceOptions = { + Name: appName, + TaskTemplate: { + ContainerSpec: { + Image: imageName, + Env: env, + Mounts: [ + { + Type: "bind", + Source: `${MAIN_TRAEFIK_PATH}/traefik.yml`, + Target: "/etc/traefik/traefik.yml", + }, + { + Type: "bind", + Source: DYNAMIC_TRAEFIK_PATH, + Target: "/etc/dokploy/traefik/dynamic", + }, + { + Type: "bind", + Source: "/var/run/docker.sock", + Target: "/var/run/docker.sock", + }, + ], + }, + Networks: [{ Target: "dokploy-network" }], + Placement: { + Constraints: ["node.role==manager"], + }, + }, + Mode: { + Replicated: { + Replicas: 1, + }, + }, + EndpointSpec: { + Ports: [ + { + TargetPort: 443, + PublishedPort: TRAEFIK_SSL_PORT, + PublishMode: "host", + Protocol: "tcp", + }, + { + TargetPort: 443, + PublishedPort: TRAEFIK_SSL_PORT, + PublishMode: "host", + Protocol: "udp", + }, + { + TargetPort: 80, + PublishedPort: TRAEFIK_PORT, + PublishMode: "host", + Protocol: "tcp", + }, - ...additionalPorts.map((port) => ({ - TargetPort: port.targetPort, - PublishedPort: port.publishedPort, - Protocol: port.protocol as 'tcp' | 'udp' | 'sctp' | undefined, - PublishMode: 'host' as const, - })), - ], - }, - }; - const docker = await getRemoteDocker(serverId); - try { - const service = docker.getService(appName); - const inspect = await service.inspect(); + ...additionalPorts.map((port) => ({ + TargetPort: port.targetPort, + PublishedPort: port.publishedPort, + Protocol: port.protocol as "tcp" | "udp" | "sctp" | undefined, + PublishMode: "host" as const, + })), + ], + }, + }; + const docker = await getRemoteDocker(serverId); + try { + const service = docker.getService(appName); + const inspect = await service.inspect(); - await service.update({ - version: Number.parseInt(inspect.Version.Index), - ...settings, - TaskTemplate: { - ...settings.TaskTemplate, - ForceUpdate: inspect.Spec.TaskTemplate.ForceUpdate + 1, - }, - }); - console.log('Traefik Updated ✅'); - } catch { - await docker.createService(settings); - console.log('Traefik Started ✅'); - } + await service.update({ + version: Number.parseInt(inspect.Version.Index), + ...settings, + TaskTemplate: { + ...settings.TaskTemplate, + ForceUpdate: inspect.Spec.TaskTemplate.ForceUpdate + 1, + }, + }); + console.log("Traefik Updated ✅"); + } catch { + await docker.createService(settings); + console.log("Traefik Started ✅"); + } }; export const createDefaultServerTraefikConfig = () => { - const { DYNAMIC_TRAEFIK_PATH } = paths(); - const configFilePath = path.join(DYNAMIC_TRAEFIK_PATH, 'dokploy.yml'); + const { DYNAMIC_TRAEFIK_PATH } = paths(); + const configFilePath = path.join(DYNAMIC_TRAEFIK_PATH, "dokploy.yml"); - if (existsSync(configFilePath)) { - console.log('Default traefik config already exists'); - return; - } + if (existsSync(configFilePath)) { + console.log("Default traefik config already exists"); + return; + } - const appName = 'dokploy'; - const serviceURLDefault = `http://${appName}:${process.env.PORT || 3000}`; - const config: FileConfig = { - http: { - routers: { - [`${appName}-router-app`]: { - rule: `Host(\`${appName}.docker.localhost\`) && PathPrefix(\`/\`)`, - service: `${appName}-service-app`, - entryPoints: ['web'], - }, - }, - services: { - [`${appName}-service-app`]: { - loadBalancer: { - servers: [{ url: serviceURLDefault }], - passHostHeader: true, - }, - }, - }, - }, - }; + const appName = "dokploy"; + const serviceURLDefault = `http://${appName}:${process.env.PORT || 3000}`; + const config: FileConfig = { + http: { + routers: { + [`${appName}-router-app`]: { + rule: `Host(\`${appName}.docker.localhost\`) && PathPrefix(\`/\`)`, + service: `${appName}-service-app`, + entryPoints: ["web"], + }, + }, + services: { + [`${appName}-service-app`]: { + loadBalancer: { + servers: [{ url: serviceURLDefault }], + passHostHeader: true, + }, + }, + }, + }, + }; - const yamlStr = dump(config); - mkdirSync(DYNAMIC_TRAEFIK_PATH, { recursive: true }); - writeFileSync(path.join(DYNAMIC_TRAEFIK_PATH, `${appName}.yml`), yamlStr, 'utf8'); + const yamlStr = dump(config); + mkdirSync(DYNAMIC_TRAEFIK_PATH, { recursive: true }); + writeFileSync( + path.join(DYNAMIC_TRAEFIK_PATH, `${appName}.yml`), + yamlStr, + "utf8", + ); }; export const getDefaultTraefikConfig = () => { - const configObject: MainTraefikConfig = { - global: { - sendAnonymousUsage: false, - }, - providers: { - ...(process.env.NODE_ENV === 'development' - ? { - docker: { - defaultRule: 'Host(`{{ trimPrefix `/` .Name }}.docker.localhost`)', - }, - } - : { - swarm: { - exposedByDefault: false, - watch: true, - }, - docker: { - exposedByDefault: false, - watch: true, - network: 'dokploy-network', - }, - }), - file: { - directory: '/etc/dokploy/traefik/dynamic', - watch: true, - }, - }, - entryPoints: { - web: { - address: `:${TRAEFIK_PORT}`, - }, - websecure: { - address: `:${TRAEFIK_SSL_PORT}`, - http3: { - advertisedPort: TRAEFIK_HTTP3_PORT, - }, - ...(process.env.NODE_ENV === 'production' && { - http: { - tls: { - certResolver: 'letsencrypt', - }, - }, - }), - }, - }, - api: { - insecure: true, - }, - ...(process.env.NODE_ENV === 'production' && { - certificatesResolvers: { - letsencrypt: { - acme: { - email: 'test@localhost.com', - storage: '/etc/dokploy/traefik/dynamic/acme.json', - httpChallenge: { - entryPoint: 'web', - }, - }, - }, - }, - }), - }; + const configObject: MainTraefikConfig = { + global: { + sendAnonymousUsage: false, + }, + providers: { + ...(process.env.NODE_ENV === "development" + ? { + docker: { + defaultRule: + "Host(`{{ trimPrefix `/` .Name }}.docker.localhost`)", + }, + } + : { + swarm: { + exposedByDefault: false, + watch: true, + }, + docker: { + exposedByDefault: false, + watch: true, + network: "dokploy-network", + }, + }), + file: { + directory: "/etc/dokploy/traefik/dynamic", + watch: true, + }, + }, + entryPoints: { + web: { + address: `:${TRAEFIK_PORT}`, + }, + websecure: { + address: `:${TRAEFIK_SSL_PORT}`, + http3: { + advertisedPort: TRAEFIK_HTTP3_PORT, + }, + ...(process.env.NODE_ENV === "production" && { + http: { + tls: { + certResolver: "letsencrypt", + }, + }, + }), + }, + }, + api: { + insecure: true, + }, + ...(process.env.NODE_ENV === "production" && { + certificatesResolvers: { + letsencrypt: { + acme: { + email: "test@localhost.com", + storage: "/etc/dokploy/traefik/dynamic/acme.json", + httpChallenge: { + entryPoint: "web", + }, + }, + }, + }, + }), + }; - const yamlStr = dump(configObject); + const yamlStr = dump(configObject); - return yamlStr; + return yamlStr; }; export const getDefaultServerTraefikConfig = () => { - const configObject: MainTraefikConfig = { - providers: { - swarm: { - exposedByDefault: false, - watch: true, - }, - docker: { - exposedByDefault: false, - watch: true, - network: 'dokploy-network', - }, - file: { - directory: '/etc/dokploy/traefik/dynamic', - watch: true, - }, - }, - entryPoints: { - web: { - address: `:${TRAEFIK_PORT}`, - }, - websecure: { - address: `:${TRAEFIK_SSL_PORT}`, - http3: { - advertisedPort: TRAEFIK_HTTP3_PORT, - }, - http: { - tls: { - certResolver: 'letsencrypt', - }, - }, - }, - }, - api: { - insecure: true, - }, - certificatesResolvers: { - letsencrypt: { - acme: { - email: 'test@localhost.com', - storage: '/etc/dokploy/traefik/dynamic/acme.json', - httpChallenge: { - entryPoint: 'web', - }, - }, - }, - }, - }; + const configObject: MainTraefikConfig = { + providers: { + swarm: { + exposedByDefault: false, + watch: true, + }, + docker: { + exposedByDefault: false, + watch: true, + network: "dokploy-network", + }, + file: { + directory: "/etc/dokploy/traefik/dynamic", + watch: true, + }, + }, + entryPoints: { + web: { + address: `:${TRAEFIK_PORT}`, + }, + websecure: { + address: `:${TRAEFIK_SSL_PORT}`, + http3: { + advertisedPort: TRAEFIK_HTTP3_PORT, + }, + http: { + tls: { + certResolver: "letsencrypt", + }, + }, + }, + }, + api: { + insecure: true, + }, + certificatesResolvers: { + letsencrypt: { + acme: { + email: "test@localhost.com", + storage: "/etc/dokploy/traefik/dynamic/acme.json", + httpChallenge: { + entryPoint: "web", + }, + }, + }, + }, + }; - const yamlStr = dump(configObject); + const yamlStr = dump(configObject); - return yamlStr; + return yamlStr; }; export const createDefaultTraefikConfig = () => { - const { MAIN_TRAEFIK_PATH, DYNAMIC_TRAEFIK_PATH } = paths(); - const mainConfig = path.join(MAIN_TRAEFIK_PATH, 'traefik.yml'); - const acmeJsonPath = path.join(DYNAMIC_TRAEFIK_PATH, 'acme.json'); + const { MAIN_TRAEFIK_PATH, DYNAMIC_TRAEFIK_PATH } = paths(); + const mainConfig = path.join(MAIN_TRAEFIK_PATH, "traefik.yml"); + const acmeJsonPath = path.join(DYNAMIC_TRAEFIK_PATH, "acme.json"); - if (existsSync(acmeJsonPath)) { - chmodSync(acmeJsonPath, '600'); - } - if (existsSync(mainConfig)) { - console.log('Main config already exists'); - return; - } - const yamlStr = getDefaultTraefikConfig(); - mkdirSync(MAIN_TRAEFIK_PATH, { recursive: true }); - writeFileSync(mainConfig, yamlStr, 'utf8'); + if (existsSync(acmeJsonPath)) { + chmodSync(acmeJsonPath, "600"); + } + if (existsSync(mainConfig)) { + console.log("Main config already exists"); + return; + } + const yamlStr = getDefaultTraefikConfig(); + mkdirSync(MAIN_TRAEFIK_PATH, { recursive: true }); + writeFileSync(mainConfig, yamlStr, "utf8"); }; export const getDefaultMiddlewares = () => { - const defaultMiddlewares = { - http: { - middlewares: { - 'redirect-to-https': { - redirectScheme: { - scheme: 'https', - permanent: true, - }, - }, - }, - }, - }; - const yamlStr = dump(defaultMiddlewares); - return yamlStr; + const defaultMiddlewares = { + http: { + middlewares: { + "redirect-to-https": { + redirectScheme: { + scheme: "https", + permanent: true, + }, + }, + }, + }, + }; + const yamlStr = dump(defaultMiddlewares); + return yamlStr; }; export const createDefaultMiddlewares = () => { - const { DYNAMIC_TRAEFIK_PATH } = paths(); - const middlewaresPath = path.join(DYNAMIC_TRAEFIK_PATH, 'middlewares.yml'); - if (existsSync(middlewaresPath)) { - console.log('Default middlewares already exists'); - return; - } - const yamlStr = getDefaultMiddlewares(); - mkdirSync(DYNAMIC_TRAEFIK_PATH, { recursive: true }); - writeFileSync(middlewaresPath, yamlStr, 'utf8'); + const { DYNAMIC_TRAEFIK_PATH } = paths(); + const middlewaresPath = path.join(DYNAMIC_TRAEFIK_PATH, "middlewares.yml"); + if (existsSync(middlewaresPath)) { + console.log("Default middlewares already exists"); + return; + } + const yamlStr = getDefaultMiddlewares(); + mkdirSync(DYNAMIC_TRAEFIK_PATH, { recursive: true }); + writeFileSync(middlewaresPath, yamlStr, "utf8"); };