feat: add redis installation on server and deploy applications on servers

This commit is contained in:
Mauricio Siu
2024-09-08 22:10:24 -06:00
parent 1a34ba175e
commit 3d60236b36
39 changed files with 8616 additions and 155 deletions

View File

@@ -57,3 +57,44 @@ export const buildCustomDocker = async (
throw error;
}
};
export const getDockerCommand = (
application: ApplicationNested,
logPath: string,
) => {
const { appName, env, publishDirectory, buildArgs, dockerBuildStage } =
application;
const dockerFilePath = getBuildAppDirectory(application);
try {
const image = `${appName}`;
const defaultContextPath =
dockerFilePath.substring(0, dockerFilePath.lastIndexOf("/") + 1) || ".";
const args = prepareEnvironmentVariables(buildArgs);
const dockerContextPath =
getDockerContextPath(application) || defaultContextPath;
const commandArgs = ["build", "-t", image, "-f", dockerFilePath, "."];
if (dockerBuildStage) {
commandArgs.push("--target", dockerBuildStage);
}
for (const arg of args) {
commandArgs.push("--build-arg", arg);
}
const command = `
echo "Building ${appName}" >> ${logPath};
cd ${dockerContextPath} || exit 1;
docker ${commandArgs.join(" ")} >> ${logPath} 2>&1;
echo "Docker build completed." >> ${logPath};
`;
return command;
} catch (error) {
throw error;
}
};

View File

@@ -38,3 +38,35 @@ export const buildHeroku = async (
throw e;
}
};
export const getHerokuCommand = (
application: ApplicationNested,
logPath: string,
) => {
const { env, appName } = application;
const buildAppDirectory = getBuildAppDirectory(application);
const envVariables = prepareEnvironmentVariables(env);
const args = [
"build",
appName,
"--path",
buildAppDirectory,
"--builder",
"heroku/builder:24",
];
for (const env of envVariables) {
args.push("--env", env);
}
const command = `pack ${args.join(" ")}`;
const bashCommand = `
echo "Starting heroku build..." >> ${logPath};
${command} >> ${logPath} 2>&1;
echo "Heroku build completed." >> ${logPath};
`;
return bashCommand;
};

View File

@@ -1,8 +1,9 @@
import { createWriteStream } from "node:fs";
import { docker } from "@/server/constants";
// import { docker } from "@/server/constants";
import type { InferResultType } from "@/server/types/with";
import type { CreateServiceOptions } from "dockerode";
import { uploadImage } from "../cluster/upload";
import Dockerode from "dockerode";
import {
calculateResources,
generateBindMounts,
@@ -11,11 +12,14 @@ import {
generateVolumeMounts,
prepareEnvironmentVariables,
} from "../docker/utils";
import { buildCustomDocker } from "./docker-file";
import { buildHeroku } from "./heroku";
import { buildNixpacks } from "./nixpacks";
import { buildPaketo } from "./paketo";
import { buildCustomDocker, getDockerCommand } from "./docker-file";
import { buildHeroku, getHerokuCommand } from "./heroku";
import { buildNixpacks, getNixpacksCommand } from "./nixpacks";
import { buildPaketo, getPaketoCommand } from "./paketo";
import { buildStatic } from "./static";
import { findServerById } from "@/server/api/services/server";
import { readSSHKey } from "../filesystem/ssh";
import { getRemoteDocker } from "../servers/remote-docker";
// NIXPACKS codeDirectory = where is the path of the code directory
// HEROKU codeDirectory = where is the path of the code directory
@@ -65,6 +69,25 @@ export const buildApplication = async (
}
};
export const getBuildCommand = (
application: ApplicationNested,
logPath: string,
) => {
const { buildType } = application;
switch (buildType) {
case "nixpacks":
return getNixpacksCommand(application, logPath);
case "heroku_buildpacks":
return getHerokuCommand(application, logPath);
case "paketo_buildpacks":
return getPaketoCommand(application, logPath);
// case "static":
// return buildStatic(application, writeStream);
case "dockerfile":
return getDockerCommand(application, logPath);
}
};
export const mechanizeDockerContainer = async (
application: ApplicationNested,
) => {
@@ -106,6 +129,21 @@ export const mechanizeDockerContainer = async (
const image = getImageName(application);
const authConfig = getAuthConfig(application);
const docker = await getRemoteDocker(application.serverId);
// const server = await findServerById(application.serverId);
// if (!server.sshKeyId) return;
// const keys = await readSSHKey(server.sshKeyId);
// const docker = new Dockerode({
// host: server.ipAddress,
// port: server.port,
// username: server.username,
// protocol: "ssh",
// sshOptions: {
// privateKey: keys.privateKey,
// },
// });
// const results = await docker2.listContainers();
// console.log(results);
const settings: CreateServiceOptions = {
authconfig: authConfig,

View File

@@ -6,12 +6,13 @@ import type { ApplicationNested } from ".";
import { prepareEnvironmentVariables } from "../docker/utils";
import { getBuildAppDirectory } from "../filesystem/directory";
import { spawnAsync } from "../process/spawnAsync";
import { executeCommand } from "../servers/command";
export const buildNixpacks = async (
application: ApplicationNested,
writeStream: WriteStream,
) => {
const { env, appName, publishDirectory } = application;
const { env, appName, publishDirectory, serverId } = application;
const buildAppDirectory = getBuildAppDirectory(application);
const buildContainerId = `${appName}-${nanoid(10)}`;
@@ -71,3 +72,55 @@ export const buildNixpacks = async (
throw e;
}
};
export const getNixpacksCommand = (
application: ApplicationNested,
logPath: string,
) => {
const { env, appName, publishDirectory, serverId } = application;
const buildAppDirectory = getBuildAppDirectory(application);
const buildContainerId = `${appName}-${nanoid(10)}`;
const envVariables = prepareEnvironmentVariables(env);
try {
const args = ["build", buildAppDirectory, "--name", appName];
for (const env of envVariables) {
args.push("--env", env);
}
if (publishDirectory) {
/* No need for any start command, since we'll use nginx later on */
args.push("--no-error-without-start");
}
const command = `nixpacks ${args.join(" ")}`;
const bashCommand = `
echo "Starting nixpacks build..." >> ${logPath};
${command} >> ${logPath} 2>&1;
echo "Nixpacks build completed." >> ${logPath};
`;
/*
Run the container with the image created by nixpacks,
and copy the artifacts on the host filesystem.
Then, remove the container and create a static build.
*/
// if (publishDirectory) {
// bashCommand += `
// docker create --name ${buildContainerId} ${appName}
// docker cp ${buildContainerId}:/app/${publishDirectory} ${path.join(buildAppDirectory, publishDirectory)}
// docker rm ${buildContainerId}
// buildStatic ${application} ${writeStream}
// `;
// }
return bashCommand;
} catch (e) {
// await spawnAsync("docker", ["rm", buildContainerId], writeToStream);
throw e;
}
};

View File

@@ -4,7 +4,6 @@ import { prepareEnvironmentVariables } from "../docker/utils";
import { getBuildAppDirectory } from "../filesystem/directory";
import { spawnAsync } from "../process/spawnAsync";
// TODO: integrate in the vps sudo chown -R $(whoami) ~/.docker
export const buildPaketo = async (
application: ApplicationNested,
writeStream: WriteStream,
@@ -36,3 +35,35 @@ export const buildPaketo = async (
throw e;
}
};
export const getPaketoCommand = (
application: ApplicationNested,
logPath: string,
) => {
const { env, appName } = application;
const buildAppDirectory = getBuildAppDirectory(application);
const envVariables = prepareEnvironmentVariables(env);
const args = [
"build",
appName,
"--path",
buildAppDirectory,
"--builder",
"paketobuildpacks/builder-jammy-full",
];
for (const env of envVariables) {
args.push("--env", env);
}
const command = `pack ${args.join(" ")}`;
const bashCommand = `
echo "Starting Paketo build..." >> ${logPath};
${command} >> ${logPath} 2>&1;
echo "Paketo build completed." >> ${logPath};
`;
return bashCommand;
};

View File

@@ -10,3 +10,13 @@ export const createEnvFile = (directory: string, env: string | null) => {
const envFileContent = prepareEnvironmentVariables(env).join("\n");
writeFileSync(envFilePath, envFileContent);
};
export const createEnvFileCommand = (directory: string, env: string | null) => {
const envFilePath = join(dirname(directory), ".env");
// let command = ``
if (!existsSync(dirname(envFilePath))) {
mkdirSync(dirname(envFilePath), { recursive: true });
}
const envFileContent = prepareEnvironmentVariables(env).join("\n");
return `echo "${envFileContent}" > ${envFilePath}`;
};

View File

@@ -6,6 +6,7 @@ import type { ContainerInfo, ResourceRequirements } from "dockerode";
import { parse } from "dotenv";
import type { ApplicationNested } from "../builders";
import { execAsync } from "../process/execAsync";
import { getRemoteDocker } from "../servers/remote-docker";
interface RegistryAuth {
username: string;
@@ -51,6 +52,51 @@ export const pullImage = async (
}
};
export const pullRemoteImage = async (
dockerImage: string,
serverId: string,
onData?: (data: any) => void,
authConfig?: Partial<RegistryAuth>,
): Promise<void> => {
try {
if (!dockerImage) {
throw new Error("Docker image not found");
}
const remoteDocker = await getRemoteDocker(serverId);
await new Promise((resolve, reject) => {
remoteDocker.pull(
dockerImage,
{ authconfig: authConfig },
(err, stream) => {
if (err) {
reject(err);
return;
}
remoteDocker.modem.followProgress(
stream as Readable,
(err: Error | null, res) => {
if (!err) {
resolve(res);
}
if (err) {
reject(err);
}
},
(event) => {
onData?.(event);
},
);
},
);
});
} catch (error) {
throw error;
}
};
export const containerExists = async (containerName: string) => {
const container = docker.getContainer(containerName);
try {

View File

@@ -117,6 +117,55 @@ export const cloneRawBitbucketRepository = async (entity: Compose) => {
}
};
export const getBitbucketCloneCommand = async (
entity: ApplicationWithBitbucket | ComposeWithBitbucket,
logPath: string,
isCompose = false,
) => {
const {
appName,
bitbucketRepository,
bitbucketOwner,
bitbucketBranch,
bitbucketId,
serverId,
bitbucket,
} = entity;
if (!serverId) {
throw new TRPCError({
code: "NOT_FOUND",
message: "Server not found",
});
}
if (!bitbucketId) {
throw new TRPCError({
code: "NOT_FOUND",
message: "Bitbucket Provider not found",
});
}
const bitbucketProvider = await findBitbucketById(bitbucketId);
const basePath = COMPOSE_PATH;
const outputPath = join(basePath, appName, "code");
await recreateDirectory(outputPath);
const repoclone = `bitbucket.org/${bitbucketOwner}/${bitbucketRepository}.git`;
const cloneUrl = `https://${bitbucketProvider?.bitbucketUsername}:${bitbucketProvider?.appPassword}@${repoclone}`;
const cloneCommand = `
rm -rf ${outputPath};
mkdir -p ${outputPath};
if ! git clone --branch ${bitbucketBranch} --depth 1 --progress ${cloneUrl} ${outputPath} >> ${logPath} 2>&1; then
echo "[ERROR] Fail to clone the repository ${repoclone}" >> ${logPath};
exit 1;
fi
echo "Cloned ${repoclone} to ${outputPath}: ✅" >> ${logPath};
`;
return cloneCommand;
};
export const getBitbucketRepositories = async (bitbucketId?: string) => {
if (!bitbucketId) {
return [];

View File

@@ -47,3 +47,38 @@ export const buildDocker = async (
writeStream.end();
}
};
export const buildRemoteDocker = async (
application: ApplicationNested,
logPath: string,
) => {
const { sourceType, dockerImage, username, password } = application;
try {
if (!dockerImage) {
throw new Error("Docker image not found");
}
let command = `
echo "Building ${sourceType}" >> ${logPath};
echo "Pulling ${dockerImage}" >> ${logPath};
`;
if (username && password) {
command += `
if ! docker login --username ${username} --password ${password} https://index.docker.io/v1/ >> ${logPath} 2>&1; then
echo "Error logging in to Docker Hub" >> ${logPath};
exit 1;
fi
`;
}
command += `
echo "Pulling ${dockerImage}" >> ${logPath};
docker pull ${dockerImage} >> ${logPath} 2>&1;
`;
return command;
} catch (error) {
throw error;
}
};

View File

@@ -87,6 +87,66 @@ export const cloneGitRepository = async (
}
};
export const getCustomGitCloneCommand = async (
entity: {
appName: string;
customGitUrl?: string | null;
customGitBranch?: string | null;
customGitSSHKeyId?: string | null;
},
logPath: string,
isCompose = false,
) => {
const { appName, customGitUrl, customGitBranch, customGitSSHKeyId } = entity;
if (!customGitUrl || !customGitBranch) {
throw new TRPCError({
code: "BAD_REQUEST",
message: "Error: Repository not found",
});
}
const keyPath = path.join(SSH_PATH, `${customGitSSHKeyId}_rsa`);
const basePath = isCompose ? COMPOSE_PATH : APPLICATIONS_PATH;
const outputPath = join(basePath, appName, "code");
const knownHostsPath = path.join(SSH_PATH, "known_hosts");
if (customGitSSHKeyId) {
await updateSSHKeyById({
sshKeyId: customGitSSHKeyId,
lastUsedAt: new Date().toISOString(),
});
}
try {
const command = [];
if (!isHttpOrHttps(customGitUrl)) {
command.push(addHostToKnownHostsCommand(customGitUrl));
}
command.push(`rm -rf ${outputPath};`);
command.push(`mkdir -p ${outputPath};`);
command.push(
`echo "Cloning Custom Git ${customGitUrl}" to ${outputPath}: ✅ >> ${logPath};`,
);
if (customGitSSHKeyId) {
command.push(
`GIT_SSH_COMMAND="ssh -i ${keyPath} -o UserKnownHostsFile=${knownHostsPath}"`,
);
}
command.push(
`if ! git clone --branch ${customGitBranch} --depth 1 --progress ${customGitUrl} ${outputPath} >> ${logPath} 2>&1; then
echo "[ERROR] Fail to clone the repository ${customGitUrl}" >> ${logPath};
exit 1;
fi
`,
);
command.push(`echo "Cloned Custom Git ${customGitUrl}: ✅" >> ${logPath}`);
return command.join("\n");
} catch (error) {
throw error;
}
};
const isHttpOrHttps = (url: string): boolean => {
const regex = /^https?:\/\//;
return regex.test(url);
@@ -104,6 +164,13 @@ const addHostToKnownHosts = async (repositoryURL: string) => {
throw error;
}
};
const addHostToKnownHostsCommand = (repositoryURL: string) => {
const { domain, port } = sanitizeRepoPathSSH(repositoryURL);
const knownHostsPath = path.join(SSH_PATH, "known_hosts");
return `ssh-keyscan -p ${port} ${domain} >> ${knownHostsPath};`;
};
const sanitizeRepoPathSSH = (input: string) => {
const SSH_PATH_RE = new RegExp(
[

View File

@@ -11,6 +11,7 @@ import { spawnAsync } from "../process/spawnAsync";
import type { Compose } from "@/server/api/services/compose";
import { type Github, findGithubById } from "@/server/api/services/github";
import type { apiFindGithubBranches } from "@/server/db/schema";
import { executeCommand } from "../servers/command";
export const authGithub = (githubProvider: Github) => {
if (!haveGithubRequirements(githubProvider)) {
@@ -142,6 +143,63 @@ export const cloneGithubRepository = async (
}
};
export const getGithubCloneCommand = async (
entity: ApplicationWithGithub | ComposeWithGithub,
logPath: string,
isCompose = false,
) => {
const { appName, repository, owner, branch, githubId, serverId } = entity;
if (!githubId || !serverId) {
throw new TRPCError({
code: "NOT_FOUND",
message: "GitHub Provider not found",
});
}
const requirements = getErrorCloneRequirements(entity);
// Build log messages
let logMessages = "";
if (requirements.length > 0) {
logMessages += `\nGitHub Repository configuration failed for application: ${appName}\n`;
logMessages += "Reasons:\n";
logMessages += requirements.join("\n");
const escapedLogMessages = logMessages
.replace(/\\/g, "\\\\")
.replace(/"/g, '\\"')
.replace(/\n/g, "\\n");
const bashCommand = `
echo "${escapedLogMessages}" >> ${logPath};
exit 1; # Exit with error code
`;
await executeCommand(serverId, bashCommand);
return;
}
const githubProvider = await findGithubById(githubId);
const basePath = isCompose ? COMPOSE_PATH : APPLICATIONS_PATH;
const outputPath = join(basePath, appName, "code");
const octokit = authGithub(githubProvider);
const token = await getGithubToken(octokit);
const repoclone = `github.com/${owner}/${repository}.git`;
const cloneUrl = `https://oauth2:${token}@${repoclone}`;
const cloneCommand = `
rm -rf ${outputPath};
mkdir -p ${outputPath};
if ! git clone --branch ${branch} --depth 1 --progress ${cloneUrl} ${outputPath} >> ${logPath} 2>&1; then
echo "[ERROR] Fallo al clonar el repositorio ${repoclone}" >> ${logPath};
exit 1;
fi
echo "Cloned ${repoclone} to ${outputPath}: ✅" >> ${logPath};
`;
return cloneCommand;
};
export const cloneRawGithubRepository = async (entity: Compose) => {
const { appName, repository, owner, branch, githubId } = entity;

View File

@@ -12,6 +12,7 @@ import type { InferResultType } from "@/server/types/with";
import { TRPCError } from "@trpc/server";
import { recreateDirectory } from "../filesystem/directory";
import { spawnAsync } from "../process/spawnAsync";
import { executeCommand } from "../servers/command";
export const refreshGitlabToken = async (gitlabProviderId: string) => {
const gitlabProvider = await findGitlabById(gitlabProviderId);
@@ -153,6 +154,78 @@ export const cloneGitlabRepository = async (
}
};
export const getGitlabCloneCommand = async (
entity: ApplicationWithGitlab | ComposeWithGitlab,
logPath: string,
isCompose = false,
) => {
const {
appName,
gitlabRepository,
gitlabOwner,
gitlabPathNamespace,
gitlabBranch,
gitlabId,
serverId,
gitlab,
} = entity;
if (!serverId) {
throw new TRPCError({
code: "NOT_FOUND",
message: "Server not found",
});
}
if (!gitlabId) {
throw new TRPCError({
code: "NOT_FOUND",
message: "Gitlab Provider not found",
});
}
const requirements = getErrorCloneRequirements(entity);
// Build log messages
let logMessages = "";
if (requirements.length > 0) {
logMessages += `\nGitLab Repository configuration failed for application: ${appName}\n`;
logMessages += "Reasons:\n";
logMessages += requirements.join("\n");
const escapedLogMessages = logMessages
.replace(/\\/g, "\\\\")
.replace(/"/g, '\\"')
.replace(/\n/g, "\\n");
const bashCommand = `
echo "${escapedLogMessages}" >> ${logPath};
exit 1; # Exit with error code
`;
await executeCommand(serverId, bashCommand);
return;
}
await refreshGitlabToken(gitlabId);
const basePath = isCompose ? COMPOSE_PATH : APPLICATIONS_PATH;
const outputPath = join(basePath, appName, "code");
await recreateDirectory(outputPath);
const repoclone = `gitlab.com/${gitlabPathNamespace}.git`;
const cloneUrl = `https://oauth2:${gitlab?.accessToken}@${repoclone}`;
const cloneCommand = `
rm -rf ${outputPath};
mkdir -p ${outputPath};
if ! git clone --branch ${gitlabBranch} --depth 1 --progress ${cloneUrl} ${outputPath} >> ${logPath} 2>&1; then
echo "[ERROR] Fail to clone the repository ${repoclone}" >> ${logPath};
exit 1;
fi
echo "Cloned ${repoclone} to ${outputPath}: ✅" >> ${logPath};
`;
return cloneCommand;
};
export const getGitlabRepositories = async (gitlabId?: string) => {
if (!gitlabId) {
return [];

View File

@@ -0,0 +1,47 @@
import { findServerById } from "@/server/api/services/server";
import { readSSHKey } from "../filesystem/ssh";
import { Client } from "ssh2";
export const executeCommand = async (serverId: string, command: string) => {
const server = await findServerById(serverId);
if (!server.sshKeyId) return;
const keys = await readSSHKey(server.sshKeyId);
const client = new Client();
return new Promise<void>((resolve, reject) => {
client
.on("ready", () => {
console.log("Client :: ready", command);
client.exec(command, (err, stream) => {
if (err) {
console.error("Execution error:", err);
reject(err);
return;
}
stream
.on("close", (code, signal) => {
console.log("Connection closed ✅");
client.end();
if (code === 0) {
resolve();
} else {
reject(new Error(`Command exited with code ${code}`));
}
})
.on("data", (data: string) => {
console.log(`OUTPUT: ${data.toString()}`);
})
.stderr.on("data", (data) => {
console.error(`STDERR: ${data.toString()}`);
});
});
})
.connect({
host: server.ipAddress,
port: server.port,
username: server.username,
privateKey: keys.privateKey,
timeout: 99999,
});
});
};

View File

@@ -0,0 +1,23 @@
import { findServerById } from "@/server/api/services/server";
import { readSSHKey } from "../filesystem/ssh";
import Dockerode from "dockerode";
import { docker } from "@/server/constants";
export const getRemoteDocker = async (serverId: string | null) => {
if (!serverId) return docker;
const server = await findServerById(serverId);
if (!server.sshKeyId) return docker;
const keys = await readSSHKey(server.sshKeyId);
const dockerode = new Dockerode({
host: server.ipAddress,
port: server.port,
username: server.username,
protocol: "ssh",
// @ts-ignore
sshOptions: {
privateKey: keys.privateKey,
},
});
return dockerode;
};

View File

@@ -17,9 +17,13 @@ import {
createServerDeployment,
updateDeploymentStatus,
} from "@/server/api/services/deployment";
import { chmodSync, createWriteStream } from "node:fs";
import { createWriteStream } from "node:fs";
import { Client } from "ssh2";
import { readSSHKey } from "../filesystem/ssh";
import {
getDefaultMiddlewares,
getDefaultTraefikConfig,
} from "@/server/setup/traefik-setup";
export const setupServer = async (serverId: string) => {
const server = await findServerById(serverId);
@@ -76,6 +80,12 @@ const connectToServer = async (serverId: string, logPath: string) => {
${setupNetwork()}
${setupMainDirectory()}
${setupDirectories()}
${createTraefikConfig()}
${createDefaultMiddlewares()}
${createTraefikInstance()}
${installNixpacks()}
${installBuildpacks()}
${setupRedis()}
`;
client.exec(bashCommand, (err, stream) => {
@@ -90,13 +100,11 @@ const connectToServer = async (serverId: string, logPath: string) => {
client.end();
resolve();
})
.on("data", (data) => {
.on("data", (data: string) => {
writeStream.write(data.toString());
console.log(`OUTPUT: ${data}`);
})
.stderr.on("data", (data) => {
writeStream.write(data.toString());
console.log(`STDERR: ${data}`);
});
});
})
@@ -105,7 +113,7 @@ const connectToServer = async (serverId: string, logPath: string) => {
port: server.port,
username: server.username,
privateKey: keys.privateKey,
timeout: 10000,
timeout: 99999,
});
});
};
@@ -135,7 +143,6 @@ const setupDirectories = () => {
${chmodCommand}
`;
console.log(command);
return command;
};
@@ -203,16 +210,102 @@ const installDocker = () => `
const validatePorts = () => `
# check if something is running on port 80
if ss -tulnp | grep ':80 ' >/dev/null; then
echo "Error: something is already running on port 80" >&2
exit 1
echo "Something is already running on port 80" >&2
fi
# check if something is running on port 443
if ss -tulnp | grep ':443 ' >/dev/null; then
echo "Error: something is already running on port 443" >&2
exit 1
echo "Something is already running on port 443" >&2
fi
`;
// mkdir -p "/Users/mauricio/Documents/Github/Personal/dokploy/apps/dokploy/.docker" && mkdir -p "/Users/mauricio/Documents/Github/Personal/dokploy/apps/dokploy/.docker/traefik" && mkdir -p "/Users/mauricio/Documents/Github/Personal/dokploy/apps/dokploy/.docker/traefik/dynamic" && mkdir -p "/Users/mauricio/Documents/Github/Personal/dokploy/apps/dokploy/.docker/logs" && mkdir -p "/Users/mauricio/Documents/Github/Personal/dokploy/apps/dokploy/.docker/applications" && mkdir -p "/Users/mauricio/Documents/Github/Personal/dokploy/apps/dokploy/.docker/ssh" && mkdir -p "/Users/mauricio/Documents/Github/Personal/dokploy/apps/dokploy/.docker/traefik/dynamic/certificates" && mkdir -p "/Users/mauricio/Documents/Github/Personal/dokploy/apps/dokploy/.docker/monitoring"
// chmod 700 "/Users/mauricio/Documents/Github/Personal/dokploy/apps/dokploy/.docker/ssh"
const createTraefikConfig = () => {
const config = getDefaultTraefikConfig();
const command = `
if [ -f "/etc/dokploy/traefik/dynamic/acme.json" ]; then
chmod 600 "/etc/dokploy/traefik/dynamic/acme.json"
fi
if [ -f "/etc/dokploy/traefik/traefik.yml" ]; then
echo "Traefik config already exists ✅"
else
echo "${config}" > /etc/dokploy/traefik/traefik.yml
fi
`;
return command;
};
export const createDefaultMiddlewares = () => {
const config = getDefaultMiddlewares();
const command = `
if [ -f "/etc/dokploy/traefik/dynamic/middlewares.yml" ]; then
echo "Middlewares config already exists ✅"
else
echo "${config}" > /etc/dokploy/traefik/dynamic/middlewares.yml
fi
`;
return command;
};
export const createTraefikInstance = () => {
const command = `
# Check if dokpyloy-traefik exists
if docker service ls | grep -q 'dokploy-traefik'; then
echo "Traefik already exists ✅"
else
# Create the dokploy-traefik service
docker service create \
--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 \
--label traefik.enable=true \
--publish mode=host,target=443,published=443 \
--publish mode=host,target=80,published=80 \
--publish mode=host,target=8080,published=8080 \
traefik:v3.1.2
fi
`;
return command;
};
const installNixpacks = () => `
if command_exists nixpacks; then
echo "Nixpacks already installed ✅"
else
VERSION=1.28.1 bash -c "$(curl -fsSL https://nixpacks.com/install.sh)"
echo "Nixpacks version 1.28.1 installed ✅"
fi
`;
const installBuildpacks = () => `
if command_exists pack; then
echo "Buildpacks already installed ✅"
else
curl -sSL "https://github.com/buildpacks/pack/releases/download/v0.35.0/pack-v0.35.0-linux.tgz" | tar -C /usr/local/bin/ --no-same-owner -xzv pack
echo "Buildpacks version 0.35.0 installed ✅"
fi
`;
const setupRedis = () => `
# Check if redis is already installed
if docker service ls | grep -q 'dokploy-redis'; then
echo "Redis already installed ✅"
else
# Install Redis
docker service create \
--name dokploy-redis \
--replicas 1 \
--constraint 'node.role==manager' \
--mount type=volume,source=redis-data-volume,target=/data \
--network dokploy-network \
--publish target=6379,published=6379,protocol=tcp,mode=host \
redis:7
fi
`;