mirror of
https://github.com/ershisan99/coolify.git
synced 2026-01-21 05:02:06 +00:00
Merge branch 'main' into scshiv29-dev/main
This commit is contained in:
@@ -10,8 +10,7 @@ const createDockerfile = async (data, image): Promise<void> => {
|
||||
Dockerfile.push('WORKDIR /app');
|
||||
Dockerfile.push(`LABEL coolify.buildId=${buildId}`);
|
||||
if (isPnpm) {
|
||||
Dockerfile.push('RUN curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm');
|
||||
Dockerfile.push('RUN pnpm add -g pnpm');
|
||||
Dockerfile.push('RUN curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm@7');
|
||||
}
|
||||
Dockerfile.push(`COPY --from=${applicationId}:${tag}-cache /app/${baseDirectory || ''} ./`);
|
||||
|
||||
|
||||
@@ -35,8 +35,7 @@ const createDockerfile = async (data, image): Promise<void> => {
|
||||
});
|
||||
}
|
||||
if (isPnpm) {
|
||||
Dockerfile.push('RUN curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm');
|
||||
Dockerfile.push('RUN pnpm add -g pnpm');
|
||||
Dockerfile.push('RUN curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm@7');
|
||||
}
|
||||
Dockerfile.push(`COPY .${baseDirectory || ''} ./`);
|
||||
Dockerfile.push(`RUN ${installCommand}`);
|
||||
|
||||
@@ -36,8 +36,7 @@ const createDockerfile = async (data, image): Promise<void> => {
|
||||
});
|
||||
}
|
||||
if (isPnpm) {
|
||||
Dockerfile.push('RUN curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm');
|
||||
Dockerfile.push('RUN pnpm add -g pnpm');
|
||||
Dockerfile.push('RUN curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm@7');
|
||||
}
|
||||
Dockerfile.push(`COPY .${baseDirectory || ''} ./`);
|
||||
Dockerfile.push(`RUN ${installCommand}`);
|
||||
|
||||
@@ -35,8 +35,7 @@ const createDockerfile = async (data, image): Promise<void> => {
|
||||
});
|
||||
}
|
||||
if (isPnpm) {
|
||||
Dockerfile.push('RUN curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm');
|
||||
Dockerfile.push('RUN pnpm add -g pnpm');
|
||||
Dockerfile.push('RUN curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm@7');
|
||||
}
|
||||
Dockerfile.push(`COPY .${baseDirectory || ''} ./`);
|
||||
Dockerfile.push(`RUN ${installCommand}`);
|
||||
|
||||
@@ -96,12 +96,16 @@ export const getUserDetails = async (
|
||||
const userId = event?.locals?.session?.data?.userId || null;
|
||||
let permission = 'read';
|
||||
if (teamId && userId) {
|
||||
const data = await db.prisma.permission.findFirst({
|
||||
where: { teamId, userId },
|
||||
select: { permission: true },
|
||||
rejectOnNotFound: true
|
||||
});
|
||||
if (data.permission) permission = data.permission;
|
||||
try {
|
||||
const data = await db.prisma.permission.findFirst({
|
||||
where: { teamId, userId },
|
||||
select: { permission: true },
|
||||
rejectOnNotFound: true
|
||||
});
|
||||
if (data.permission) permission = data.permission;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
const payload = {
|
||||
|
||||
35
src/lib/components/PageLoader.svelte
Normal file
35
src/lib/components/PageLoader.svelte
Normal file
@@ -0,0 +1,35 @@
|
||||
<script>
|
||||
import { onMount, onDestroy } from 'svelte';
|
||||
import { tweened } from 'svelte/motion';
|
||||
import { cubicOut } from 'svelte/easing';
|
||||
|
||||
let timeout;
|
||||
const progress = tweened(0, {
|
||||
duration: 2000,
|
||||
easing: cubicOut
|
||||
});
|
||||
|
||||
onMount(() => {
|
||||
timeout = setTimeout(() => {
|
||||
progress.set(0.7);
|
||||
}, 500);
|
||||
});
|
||||
onDestroy(() => {
|
||||
clearTimeout(timeout);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="progress-bar">
|
||||
<div class="progress-sliver" style={`--width: ${$progress * 100}%`} />
|
||||
</div>
|
||||
|
||||
<style lang="postcss">
|
||||
.progress-bar {
|
||||
height: 0.2rem;
|
||||
@apply fixed top-0 left-0 right-0;
|
||||
}
|
||||
.progress-sliver {
|
||||
width: var(--width);
|
||||
@apply h-full bg-coollabs;
|
||||
}
|
||||
</style>
|
||||
@@ -62,7 +62,7 @@ export const supportedDatabaseTypesAndVersions = [
|
||||
name: 'postgresql',
|
||||
fancyName: 'PostgreSQL',
|
||||
baseImage: 'bitnami/postgresql',
|
||||
versions: ['14.2.0', '13.6.0', '12.10.0 ', '11.15.0', '10.20.0']
|
||||
versions: ['14.2.0', '13.6.0', '12.10.0', '11.15.0', '10.20.0']
|
||||
},
|
||||
{
|
||||
name: 'redis',
|
||||
@@ -219,6 +219,18 @@ export const supportedServiceTypesAndVersions = [
|
||||
ports: {
|
||||
main: 3000
|
||||
}
|
||||
// },
|
||||
// {
|
||||
// name: 'appwrite',
|
||||
// fancyName: 'AppWrite',
|
||||
// baseImage: 'appwrite/appwrite',
|
||||
// images: ['appwrite/influxdb', 'appwrite/telegraf', 'mariadb:10.7', 'redis:6.0-alpine3.12'],
|
||||
// versions: ['latest', '0.13.0'],
|
||||
// recommendedVersion: '0.13.0',
|
||||
// ports: {
|
||||
// main: 3000
|
||||
// }
|
||||
// }
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@@ -51,10 +51,12 @@ export async function isSecretExists({
|
||||
|
||||
export async function isDomainConfigured({
|
||||
id,
|
||||
fqdn
|
||||
fqdn,
|
||||
checkOwn = false
|
||||
}: {
|
||||
id: string;
|
||||
fqdn: string;
|
||||
checkOwn?: boolean;
|
||||
}): Promise<boolean> {
|
||||
const domain = getDomain(fqdn);
|
||||
const nakedDomain = domain.replace('www.', '');
|
||||
@@ -72,12 +74,15 @@ export async function isDomainConfigured({
|
||||
where: {
|
||||
OR: [
|
||||
{ fqdn: { endsWith: `//${nakedDomain}` } },
|
||||
{ fqdn: { endsWith: `//www.${nakedDomain}` } }
|
||||
{ fqdn: { endsWith: `//www.${nakedDomain}` } },
|
||||
{ minio: { apiFqdn: { endsWith: `//${nakedDomain}` } } },
|
||||
{ minio: { apiFqdn: { endsWith: `//www.${nakedDomain}` } } }
|
||||
],
|
||||
id: { not: id }
|
||||
id: { not: checkOwn ? undefined : id }
|
||||
},
|
||||
select: { fqdn: true }
|
||||
});
|
||||
|
||||
const coolifyFqdn = await prisma.setting.findFirst({
|
||||
where: {
|
||||
OR: [
|
||||
|
||||
@@ -305,6 +305,12 @@ export async function getFreePort() {
|
||||
select: { mysqlPublicPort: true }
|
||||
})
|
||||
).map((a) => a.mysqlPublicPort);
|
||||
const usedPorts = [...dbUsed, ...wpFtpUsed, ...wpUsed];
|
||||
const minioUsed = await (
|
||||
await prisma.minio.findMany({
|
||||
where: { publicPort: { not: null } },
|
||||
select: { publicPort: true }
|
||||
})
|
||||
).map((a) => a.publicPort);
|
||||
const usedPorts = [...dbUsed, ...wpFtpUsed, ...wpUsed, ...minioUsed];
|
||||
return await getPort({ port: portNumbers(minPort, maxPort), exclude: usedPorts });
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { asyncExecShell, getEngine } from '$lib/common';
|
||||
import { dockerInstance } from '$lib/docker';
|
||||
import { startCoolifyProxy } from '$lib/haproxy';
|
||||
import { startCoolifyProxy, startTraefikProxy } from '$lib/haproxy';
|
||||
import { getDatabaseImage } from '.';
|
||||
import { prisma } from './common';
|
||||
import type { DestinationDocker, Service, Application, Prisma } from '@prisma/client';
|
||||
@@ -125,7 +125,14 @@ export async function newLocalDestination({
|
||||
}
|
||||
await prisma.destinationDocker.updateMany({ where: { engine }, data: { isCoolifyProxyUsed } });
|
||||
}
|
||||
if (isCoolifyProxyUsed) await startCoolifyProxy(engine);
|
||||
if (isCoolifyProxyUsed) {
|
||||
const settings = await prisma.setting.findFirst();
|
||||
if (settings?.isTraefikUsed) {
|
||||
await startTraefikProxy(engine);
|
||||
} else {
|
||||
await startCoolifyProxy(engine);
|
||||
}
|
||||
}
|
||||
return destination.id;
|
||||
}
|
||||
export async function removeDestination({ id }: Pick<DestinationDocker, 'id'>): Promise<void> {
|
||||
@@ -133,12 +140,14 @@ export async function removeDestination({ id }: Pick<DestinationDocker, 'id'>):
|
||||
if (destination.isCoolifyProxyUsed) {
|
||||
const host = getEngine(destination.engine);
|
||||
const { network } = destination;
|
||||
const settings = await prisma.setting.findFirst();
|
||||
const containerName = settings.isTraefikUsed ? 'coolify-proxy' : 'coolify-haproxy';
|
||||
const { stdout: found } = await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker ps -a --filter network=${network} --filter name=coolify-haproxy --format '{{.}}'`
|
||||
`DOCKER_HOST=${host} docker ps -a --filter network=${network} --filter name=${containerName} --format '{{.}}'`
|
||||
);
|
||||
if (found) {
|
||||
await asyncExecShell(
|
||||
`DOCKER_HOST="${host}" docker network disconnect ${network} coolify-haproxy`
|
||||
`DOCKER_HOST="${host}" docker network disconnect ${network} ${containerName}`
|
||||
);
|
||||
await asyncExecShell(`DOCKER_HOST="${host}" docker network rm ${network}`);
|
||||
}
|
||||
|
||||
@@ -67,16 +67,10 @@ export async function getSource({
|
||||
return body;
|
||||
}
|
||||
export async function addGitHubSource({ id, teamId, type, name, htmlUrl, apiUrl, organization }) {
|
||||
await prisma.gitSource.update({
|
||||
return await prisma.gitSource.update({
|
||||
where: { id },
|
||||
data: { type, name, htmlUrl, apiUrl, organization }
|
||||
});
|
||||
return await prisma.githubApp.create({
|
||||
data: {
|
||||
teams: { connect: { id: teamId } },
|
||||
gitSource: { connect: { id } }
|
||||
}
|
||||
});
|
||||
}
|
||||
export async function addGitLabSource({
|
||||
id,
|
||||
|
||||
@@ -18,7 +18,7 @@ const include: Prisma.ServiceInclude = {
|
||||
hasura: true,
|
||||
fider: true
|
||||
};
|
||||
export async function listServicesWithIncludes() {
|
||||
export async function listServicesWithIncludes(): Promise<Service[]> {
|
||||
return await prisma.service.findMany({
|
||||
include,
|
||||
orderBy: { createdAt: 'desc' }
|
||||
@@ -360,7 +360,24 @@ export async function updateService({
|
||||
}): Promise<Service> {
|
||||
return await prisma.service.update({ where: { id }, data: { fqdn, name, exposePort } });
|
||||
}
|
||||
|
||||
export async function updateMinioService({
|
||||
id,
|
||||
fqdn,
|
||||
apiFqdn,
|
||||
exposePort,
|
||||
name
|
||||
}: {
|
||||
id: string;
|
||||
fqdn: string;
|
||||
apiFqdn: string;
|
||||
exposePort?: number;
|
||||
name: string;
|
||||
}): Promise<Service> {
|
||||
return await prisma.service.update({
|
||||
where: { id },
|
||||
data: { fqdn, name, exposePort, minio: { update: { apiFqdn } } }
|
||||
});
|
||||
}
|
||||
export async function updateFiderService({
|
||||
id,
|
||||
fqdn,
|
||||
@@ -418,7 +435,6 @@ export async function updateWordpress({
|
||||
fqdn,
|
||||
name,
|
||||
exposePort,
|
||||
ownMysql,
|
||||
mysqlDatabase,
|
||||
extraConfig,
|
||||
mysqlHost,
|
||||
@@ -459,7 +475,7 @@ export async function updateWordpress({
|
||||
});
|
||||
}
|
||||
|
||||
export async function updateMinioService({
|
||||
export async function updateMinioServicePort({
|
||||
id,
|
||||
publicPort
|
||||
}: {
|
||||
|
||||
@@ -66,8 +66,7 @@ export async function buildCacheImageWithNode(data, imageForBuild) {
|
||||
});
|
||||
}
|
||||
if (isPnpm) {
|
||||
Dockerfile.push('RUN curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm');
|
||||
Dockerfile.push('RUN pnpm add -g pnpm');
|
||||
Dockerfile.push('RUN curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm@7');
|
||||
}
|
||||
if (installCommand) {
|
||||
Dockerfile.push(`COPY .${baseDirectory || ''}/package.json ./`);
|
||||
|
||||
@@ -3,12 +3,22 @@ import { asyncExecShell, getEngine } from '$lib/common';
|
||||
import got, { type Got, type Response } from 'got';
|
||||
import * as db from '$lib/database';
|
||||
import type { DestinationDocker } from '@prisma/client';
|
||||
|
||||
import fs from 'fs/promises';
|
||||
import yaml from 'js-yaml';
|
||||
const url = dev ? 'http://localhost:5555' : 'http://coolify-haproxy:5555';
|
||||
|
||||
export const defaultProxyImage = `coolify-haproxy-alpine:latest`;
|
||||
export const defaultProxyImageTcp = `coolify-haproxy-tcp-alpine:latest`;
|
||||
export const defaultProxyImageHttp = `coolify-haproxy-http-alpine:latest`;
|
||||
export const defaultTraefikImage = `traefik:v2.6`;
|
||||
|
||||
const mainTraefikEndpoint = dev
|
||||
? 'http://host.docker.internal:3000/webhooks/traefik/main.json'
|
||||
: 'http://coolify:3000/webhooks/traefik/main.json';
|
||||
|
||||
const otherTraefikEndpoint = dev
|
||||
? 'http://host.docker.internal:3000/webhooks/traefik/other.json'
|
||||
: 'http://coolify:3000/webhooks/traefik/other.json';
|
||||
|
||||
export async function haproxyInstance(): Promise<Got> {
|
||||
const { proxyPassword } = await db.listSettings();
|
||||
@@ -98,13 +108,21 @@ export async function checkHAProxy(haproxy?: Got): Promise<void> {
|
||||
}
|
||||
|
||||
export async function stopTcpHttpProxy(
|
||||
id: string,
|
||||
destinationDocker: DestinationDocker,
|
||||
publicPort: number
|
||||
publicPort: number,
|
||||
forceName: string = null
|
||||
): Promise<{ stdout: string; stderr: string } | Error> {
|
||||
const { engine } = destinationDocker;
|
||||
const host = getEngine(engine);
|
||||
const containerName = `haproxy-for-${publicPort}`;
|
||||
const settings = await db.listSettings();
|
||||
let containerName = `${id}-${publicPort}`;
|
||||
if (!settings.isTraefikUsed) {
|
||||
containerName = `haproxy-for-${publicPort}`;
|
||||
}
|
||||
if (forceName) containerName = forceName;
|
||||
const found = await checkContainer(engine, containerName);
|
||||
|
||||
try {
|
||||
if (found) {
|
||||
return await asyncExecShell(
|
||||
@@ -115,12 +133,77 @@ export async function stopTcpHttpProxy(
|
||||
return error;
|
||||
}
|
||||
}
|
||||
export async function startTcpProxy(
|
||||
export async function startTraefikTCPProxy(
|
||||
destinationDocker: DestinationDocker,
|
||||
id: string,
|
||||
publicPort: number,
|
||||
privatePort: number,
|
||||
volume?: string
|
||||
type?: string
|
||||
): Promise<{ stdout: string; stderr: string } | Error> {
|
||||
const { network, engine } = destinationDocker;
|
||||
const host = getEngine(engine);
|
||||
const containerName = `${id}-${publicPort}`;
|
||||
const found = await checkContainer(engine, containerName, true);
|
||||
let dependentId = id;
|
||||
if (type === 'wordpressftp') dependentId = `${id}-ftp`;
|
||||
const foundDependentContainer = await checkContainer(engine, dependentId, true);
|
||||
try {
|
||||
if (foundDependentContainer && !found) {
|
||||
const { stdout: Config } = await asyncExecShell(
|
||||
`DOCKER_HOST="${host}" docker network inspect bridge --format '{{json .IPAM.Config }}'`
|
||||
);
|
||||
const ip = JSON.parse(Config)[0].Gateway;
|
||||
const tcpProxy = {
|
||||
version: '3.5',
|
||||
services: {
|
||||
[`${id}-${publicPort}`]: {
|
||||
container_name: containerName,
|
||||
image: 'traefik:v2.6',
|
||||
command: [
|
||||
`--entrypoints.tcp.address=:${publicPort}`,
|
||||
`--entryPoints.tcp.forwardedHeaders.insecure=true`,
|
||||
`--providers.http.endpoint=${otherTraefikEndpoint}?id=${id}&privatePort=${privatePort}&publicPort=${publicPort}&type=tcp&address=${dependentId}`,
|
||||
'--providers.http.pollTimeout=2s',
|
||||
'--log.level=error'
|
||||
],
|
||||
ports: [`${publicPort}:${publicPort}`],
|
||||
extra_hosts: ['host.docker.internal:host-gateway', `host.docker.internal:${ip}`],
|
||||
volumes: ['/var/run/docker.sock:/var/run/docker.sock'],
|
||||
networks: ['coolify-infra', network]
|
||||
}
|
||||
},
|
||||
networks: {
|
||||
[network]: {
|
||||
external: false,
|
||||
name: network
|
||||
},
|
||||
'coolify-infra': {
|
||||
external: false,
|
||||
name: 'coolify-infra'
|
||||
}
|
||||
}
|
||||
};
|
||||
await fs.writeFile(`/tmp/docker-compose-${id}.yaml`, yaml.dump(tcpProxy));
|
||||
await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker compose -f /tmp/docker-compose-${id}.yaml up -d`
|
||||
);
|
||||
await fs.rm(`/tmp/docker-compose-${id}.yaml`);
|
||||
}
|
||||
if (!foundDependentContainer && found) {
|
||||
return await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker stop -t 0 ${containerName} && docker rm ${containerName}`
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
export async function startTcpProxy(
|
||||
destinationDocker: DestinationDocker,
|
||||
id: string,
|
||||
publicPort: number,
|
||||
privatePort: number
|
||||
): Promise<{ stdout: string; stderr: string } | Error> {
|
||||
const { network, engine } = destinationDocker;
|
||||
const host = getEngine(engine);
|
||||
@@ -128,7 +211,6 @@ export async function startTcpProxy(
|
||||
const containerName = `haproxy-for-${publicPort}`;
|
||||
const found = await checkContainer(engine, containerName, true);
|
||||
const foundDependentContainer = await checkContainer(engine, id, true);
|
||||
|
||||
try {
|
||||
if (foundDependentContainer && !found) {
|
||||
const { stdout: Config } = await asyncExecShell(
|
||||
@@ -136,9 +218,7 @@ export async function startTcpProxy(
|
||||
);
|
||||
const ip = JSON.parse(Config)[0].Gateway;
|
||||
return await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker run --restart always -e PORT=${publicPort} -e APP=${id} -e PRIVATE_PORT=${privatePort} --add-host 'host.docker.internal:host-gateway' --add-host 'host.docker.internal:${ip}' --network ${network} -p ${publicPort}:${publicPort} --name ${containerName} ${
|
||||
volume ? `-v ${volume}` : ''
|
||||
} -d coollabsio/${defaultProxyImageTcp}`
|
||||
`DOCKER_HOST=${host} docker run --restart always -e PORT=${publicPort} -e APP=${id} -e PRIVATE_PORT=${privatePort} --add-host 'host.docker.internal:host-gateway' --add-host 'host.docker.internal:${ip}' --network ${network} -p ${publicPort}:${publicPort} --name ${containerName} -d coollabsio/${defaultProxyImageTcp}`
|
||||
);
|
||||
}
|
||||
if (!foundDependentContainer && found) {
|
||||
@@ -151,6 +231,76 @@ export async function startTcpProxy(
|
||||
}
|
||||
}
|
||||
|
||||
export async function startTraefikHTTPProxy(
|
||||
destinationDocker: DestinationDocker,
|
||||
id: string,
|
||||
publicPort: number,
|
||||
privatePort: number
|
||||
): Promise<{ stdout: string; stderr: string } | Error> {
|
||||
const { network, engine } = destinationDocker;
|
||||
const host = getEngine(engine);
|
||||
|
||||
const containerName = `${id}-${publicPort}`;
|
||||
const found = await checkContainer(engine, containerName, true);
|
||||
const foundDependentContainer = await checkContainer(engine, id, true);
|
||||
|
||||
try {
|
||||
if (foundDependentContainer && !found) {
|
||||
const { stdout: Config } = await asyncExecShell(
|
||||
`DOCKER_HOST="${host}" docker network inspect bridge --format '{{json .IPAM.Config }}'`
|
||||
);
|
||||
const ip = JSON.parse(Config)[0].Gateway;
|
||||
const tcpProxy = {
|
||||
version: '3.5',
|
||||
services: {
|
||||
[`${id}-${publicPort}`]: {
|
||||
container_name: containerName,
|
||||
image: 'traefik:v2.6',
|
||||
command: [
|
||||
`--entrypoints.http.address=:${publicPort}`,
|
||||
`--entryPoints.http.forwardedHeaders.insecure=true`,
|
||||
`--providers.http.endpoint=${otherTraefikEndpoint}?id=${id}&privatePort=${privatePort}&publicPort=${publicPort}&type=http`,
|
||||
'--providers.http.pollTimeout=2s',
|
||||
'--certificatesresolvers.letsencrypt.acme.httpchallenge=true',
|
||||
'--certificatesresolvers.letsencrypt.acme.storage=/etc/traefik/acme/acme.json',
|
||||
'--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=http',
|
||||
'--log.level=error'
|
||||
],
|
||||
ports: [`${publicPort}:${publicPort}`],
|
||||
extra_hosts: ['host.docker.internal:host-gateway', `host.docker.internal:${ip}`],
|
||||
networks: ['coolify-infra', network],
|
||||
volumes: ['coolify-traefik-letsencrypt:/etc/traefik/acme']
|
||||
}
|
||||
},
|
||||
networks: {
|
||||
[network]: {
|
||||
external: false,
|
||||
name: network
|
||||
},
|
||||
'coolify-infra': {
|
||||
external: false,
|
||||
name: 'coolify-infra'
|
||||
}
|
||||
},
|
||||
volumes: {
|
||||
'coolify-traefik-letsencrypt': {}
|
||||
}
|
||||
};
|
||||
await fs.writeFile(`/tmp/docker-compose-${id}.yaml`, yaml.dump(tcpProxy));
|
||||
await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker compose -f /tmp/docker-compose-${id}.yaml up -d`
|
||||
);
|
||||
await fs.rm(`/tmp/docker-compose-${id}.yaml`);
|
||||
}
|
||||
if (!foundDependentContainer && found) {
|
||||
return await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker stop -t 0 ${containerName} && docker rm ${containerName}`
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
export async function startHttpProxy(
|
||||
destinationDocker: DestinationDocker,
|
||||
id: string,
|
||||
@@ -197,10 +347,50 @@ export async function startCoolifyProxy(engine: string): Promise<void> {
|
||||
`DOCKER_HOST="${host}" docker run -e HAPROXY_USERNAME=${proxyUser} -e HAPROXY_PASSWORD=${proxyPassword} --restart always --add-host 'host.docker.internal:host-gateway' --add-host 'host.docker.internal:${ip}' -v coolify-ssl-certs:/usr/local/etc/haproxy/ssl --network coolify-infra -p "80:80" -p "443:443" -p "8404:8404" -p "5555:5555" -p "5000:5000" --name coolify-haproxy -d coollabsio/${defaultProxyImage}`
|
||||
);
|
||||
await db.prisma.setting.update({ where: { id }, data: { proxyHash: null } });
|
||||
await db.setDestinationSettings({ engine, isCoolifyProxyUsed: true });
|
||||
}
|
||||
await configureNetworkCoolifyProxy(engine);
|
||||
}
|
||||
|
||||
export async function startTraefikProxy(engine: string): Promise<void> {
|
||||
const host = getEngine(engine);
|
||||
const found = await checkContainer(engine, 'coolify-proxy', true);
|
||||
const { id, proxyPassword, proxyUser } = await db.listSettings();
|
||||
if (!found) {
|
||||
const { stdout: Config } = await asyncExecShell(
|
||||
`DOCKER_HOST="${host}" docker network inspect bridge --format '{{json .IPAM.Config }}'`
|
||||
);
|
||||
const ip = JSON.parse(Config)[0].Gateway;
|
||||
await asyncExecShell(
|
||||
`DOCKER_HOST="${host}" docker run --restart always \
|
||||
--add-host 'host.docker.internal:host-gateway' \
|
||||
--add-host 'host.docker.internal:${ip}' \
|
||||
-v coolify-traefik-letsencrypt:/etc/traefik/acme \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
--network coolify-infra \
|
||||
-p "80:80" \
|
||||
-p "443:443" \
|
||||
--name coolify-proxy \
|
||||
-d ${defaultTraefikImage} \
|
||||
--entrypoints.web.address=:80 \
|
||||
--entrypoints.web.forwardedHeaders.insecure=true \
|
||||
--entrypoints.websecure.address=:443 \
|
||||
--entrypoints.websecure.forwardedHeaders.insecure=true \
|
||||
--providers.docker=true \
|
||||
--providers.docker.exposedbydefault=false \
|
||||
--providers.http.endpoint=${mainTraefikEndpoint} \
|
||||
--providers.http.pollTimeout=5s \
|
||||
--certificatesresolvers.letsencrypt.acme.httpchallenge=true \
|
||||
--certificatesresolvers.letsencrypt.acme.storage=/etc/traefik/acme/acme.json \
|
||||
--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web \
|
||||
--log.level=error`
|
||||
);
|
||||
await db.prisma.setting.update({ where: { id }, data: { proxyHash: null } });
|
||||
await db.setDestinationSettings({ engine, isCoolifyProxyUsed: true });
|
||||
}
|
||||
await configureNetworkTraefikProxy(engine);
|
||||
}
|
||||
|
||||
export async function isContainerExited(engine: string, containerName: string): Promise<boolean> {
|
||||
let isExited = false;
|
||||
const host = getEngine(engine);
|
||||
@@ -245,6 +435,21 @@ export async function checkContainer(
|
||||
return containerFound;
|
||||
}
|
||||
|
||||
export async function getContainerUsage(engine: string, container: string): Promise<any> {
|
||||
const host = getEngine(engine);
|
||||
try {
|
||||
const { stdout } = await asyncExecShell(
|
||||
`DOCKER_HOST="${host}" docker container stats ${container} --no-stream --no-trunc --format "{{json .}}"`
|
||||
);
|
||||
return JSON.parse(stdout);
|
||||
} catch (err) {
|
||||
return {
|
||||
MemUsage: 0,
|
||||
CPUPerc: 0,
|
||||
NetIO: 0
|
||||
};
|
||||
}
|
||||
}
|
||||
export async function stopCoolifyProxy(
|
||||
engine: string
|
||||
): Promise<{ stdout: string; stderr: string } | Error> {
|
||||
@@ -263,6 +468,24 @@ export async function stopCoolifyProxy(
|
||||
return error;
|
||||
}
|
||||
}
|
||||
export async function stopTraefikProxy(
|
||||
engine: string
|
||||
): Promise<{ stdout: string; stderr: string } | Error> {
|
||||
const host = getEngine(engine);
|
||||
const found = await checkContainer(engine, 'coolify-proxy');
|
||||
await db.setDestinationSettings({ engine, isCoolifyProxyUsed: false });
|
||||
const { id } = await db.prisma.setting.findFirst({});
|
||||
await db.prisma.setting.update({ where: { id }, data: { proxyHash: null } });
|
||||
try {
|
||||
if (found) {
|
||||
await asyncExecShell(
|
||||
`DOCKER_HOST="${host}" docker stop -t 0 coolify-proxy && docker rm coolify-proxy`
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function configureNetworkCoolifyProxy(engine: string): Promise<void> {
|
||||
const host = getEngine(engine);
|
||||
@@ -279,3 +502,19 @@ export async function configureNetworkCoolifyProxy(engine: string): Promise<void
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function configureNetworkTraefikProxy(engine: string): Promise<void> {
|
||||
const host = getEngine(engine);
|
||||
const destinations = await db.prisma.destinationDocker.findMany({ where: { engine } });
|
||||
const { stdout: networks } = await asyncExecShell(
|
||||
`DOCKER_HOST="${host}" docker ps -a --filter name=coolify-proxy --format '{{json .Networks}}'`
|
||||
);
|
||||
const configuredNetworks = networks.replace(/"/g, '').replace('\n', '').split(',');
|
||||
for (const destination of destinations) {
|
||||
if (!configuredNetworks.includes(destination.network)) {
|
||||
await asyncExecShell(
|
||||
`DOCKER_HOST="${host}" docker network connect ${destination.network} coolify-proxy`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ErrorHandler } from '$lib/database';
|
||||
import { ErrorHandler, prisma } from '$lib/database';
|
||||
import { configureHAProxy } from '$lib/haproxy/configuration';
|
||||
|
||||
export default async function (): Promise<void | {
|
||||
@@ -6,7 +6,10 @@ export default async function (): Promise<void | {
|
||||
body: { message: string; error: string };
|
||||
}> {
|
||||
try {
|
||||
return await configureHAProxy();
|
||||
const settings = await prisma.setting.findFirst();
|
||||
if (!settings.isTraefikUsed) {
|
||||
return await configureHAProxy();
|
||||
}
|
||||
} catch (error) {
|
||||
return ErrorHandler(error.response?.body || error);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
import { ErrorHandler, generateDatabaseConfiguration, prisma } from '$lib/database';
|
||||
import { startCoolifyProxy, startHttpProxy, startTcpProxy } from '$lib/haproxy';
|
||||
import {
|
||||
checkContainer,
|
||||
startCoolifyProxy,
|
||||
startHttpProxy,
|
||||
startTcpProxy,
|
||||
startTraefikHTTPProxy,
|
||||
startTraefikProxy,
|
||||
startTraefikTCPProxy,
|
||||
stopCoolifyProxy,
|
||||
stopTcpHttpProxy,
|
||||
stopTraefikProxy
|
||||
} from '$lib/haproxy';
|
||||
|
||||
export default async function (): Promise<void | {
|
||||
status: number;
|
||||
@@ -7,12 +18,23 @@ export default async function (): Promise<void | {
|
||||
}> {
|
||||
try {
|
||||
// Coolify Proxy
|
||||
const engine = '/var/run/docker.sock';
|
||||
const settings = await prisma.setting.findFirst();
|
||||
const localDocker = await prisma.destinationDocker.findFirst({
|
||||
where: { engine: '/var/run/docker.sock' }
|
||||
where: { engine, network: 'coolify' }
|
||||
});
|
||||
if (localDocker && localDocker.isCoolifyProxyUsed) {
|
||||
await startCoolifyProxy('/var/run/docker.sock');
|
||||
if (settings.isTraefikUsed) {
|
||||
const found = await checkContainer(engine, 'coolify-haproxy');
|
||||
if (found) await stopCoolifyProxy(engine);
|
||||
await startTraefikProxy(engine);
|
||||
} else {
|
||||
const found = await checkContainer(engine, 'coolify-proxy');
|
||||
if (found) await stopTraefikProxy(engine);
|
||||
await startCoolifyProxy(engine);
|
||||
}
|
||||
}
|
||||
|
||||
// TCP Proxies
|
||||
const databasesWithPublicPort = await prisma.database.findMany({
|
||||
where: { publicPort: { not: null } },
|
||||
@@ -21,8 +43,16 @@ export default async function (): Promise<void | {
|
||||
for (const database of databasesWithPublicPort) {
|
||||
const { destinationDockerId, destinationDocker, publicPort, id } = database;
|
||||
if (destinationDockerId) {
|
||||
const { privatePort } = generateDatabaseConfiguration(database);
|
||||
await startTcpProxy(destinationDocker, id, publicPort, privatePort);
|
||||
if (destinationDocker.isCoolifyProxyUsed) {
|
||||
const { privatePort } = generateDatabaseConfiguration(database);
|
||||
if (settings.isTraefikUsed) {
|
||||
await stopTcpHttpProxy(id, destinationDocker, publicPort, `haproxy-for-${publicPort}`);
|
||||
await startTraefikTCPProxy(destinationDocker, id, publicPort, privatePort);
|
||||
} else {
|
||||
await stopTcpHttpProxy(id, destinationDocker, publicPort, `${id}-${publicPort}`);
|
||||
await startTcpProxy(destinationDocker, id, publicPort, privatePort);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const wordpressWithFtp = await prisma.wordpress.findMany({
|
||||
@@ -33,20 +63,38 @@ export default async function (): Promise<void | {
|
||||
const { service, ftpPublicPort } = ftp;
|
||||
const { destinationDockerId, destinationDocker, id } = service;
|
||||
if (destinationDockerId) {
|
||||
await startTcpProxy(destinationDocker, `${id}-ftp`, ftpPublicPort, 22);
|
||||
if (destinationDocker.isCoolifyProxyUsed) {
|
||||
if (settings.isTraefikUsed) {
|
||||
await stopTcpHttpProxy(
|
||||
id,
|
||||
destinationDocker,
|
||||
ftpPublicPort,
|
||||
`haproxy-for-${ftpPublicPort}`
|
||||
);
|
||||
await startTraefikTCPProxy(destinationDocker, id, ftpPublicPort, 22, 'wordpressftp');
|
||||
} else {
|
||||
await stopTcpHttpProxy(id, destinationDocker, ftpPublicPort, `${id}-${ftpPublicPort}`);
|
||||
await startTcpProxy(destinationDocker, `${id}-ftp`, ftpPublicPort, 22);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// HTTP Proxies
|
||||
const minioInstances = await prisma.minio.findMany({
|
||||
where: { publicPort: { not: null } },
|
||||
include: { service: { include: { destinationDocker: true } } }
|
||||
});
|
||||
for (const minio of minioInstances) {
|
||||
const { service, publicPort } = minio;
|
||||
const { destinationDockerId, destinationDocker, id } = service;
|
||||
if (destinationDockerId) {
|
||||
await startHttpProxy(destinationDocker, id, publicPort, 9000);
|
||||
if (!settings.isTraefikUsed) {
|
||||
const minioInstances = await prisma.minio.findMany({
|
||||
where: { publicPort: { not: null } },
|
||||
include: { service: { include: { destinationDocker: true } } }
|
||||
});
|
||||
for (const minio of minioInstances) {
|
||||
const { service, publicPort } = minio;
|
||||
const { destinationDockerId, destinationDocker, id } = service;
|
||||
if (destinationDockerId) {
|
||||
if (destinationDocker.isCoolifyProxyUsed) {
|
||||
await stopTcpHttpProxy(id, destinationDocker, publicPort, `${id}-${publicPort}`);
|
||||
await startHttpProxy(destinationDocker, id, publicPort, 9000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
import { generateSSLCerts } from '$lib/letsencrypt';
|
||||
import { prisma } from '$lib/database';
|
||||
|
||||
export default async function (): Promise<void> {
|
||||
try {
|
||||
return await generateSSLCerts();
|
||||
const settings = await prisma.setting.findFirst();
|
||||
if (!settings.isTraefikUsed) {
|
||||
return await generateSSLCerts();
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
throw error;
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
import { renewSSLCerts } from '$lib/letsencrypt';
|
||||
import { prisma } from '$lib/database';
|
||||
|
||||
export default async function (): Promise<void> {
|
||||
try {
|
||||
return await renewSSLCerts();
|
||||
const settings = await prisma.setting.findFirst();
|
||||
if (!settings.isTraefikUsed) {
|
||||
return await renewSSLCerts();
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
throw error;
|
||||
|
||||
3
src/lib/realtime.ts
Normal file
3
src/lib/realtime.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
// import ioClient from 'socket.io-client';
|
||||
// const socket = ioClient('http://localhost:3000');
|
||||
// export const io = socket;
|
||||
@@ -12,3 +12,14 @@ export const features: Readable<{ latestVersion: string; beta: boolean }> = read
|
||||
beta: browser && window.localStorage.getItem('beta') === 'true',
|
||||
latestVersion: browser && window.localStorage.getItem('latestVersion')
|
||||
});
|
||||
|
||||
export const isTraefikUsed: Writable<boolean> = writable(false);
|
||||
|
||||
export const status: Writable<any> = writable({
|
||||
application: {
|
||||
isRunning: false,
|
||||
isExited: false,
|
||||
loading: false,
|
||||
initialLoading: true
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user