WIP: Traefik
This commit is contained in:
parent
c095cb58b3
commit
ae5d90eb47
23
data/traefik/docker-compose-tcp.yaml
Normal file
23
data/traefik/docker-compose-tcp.yaml
Normal file
@ -0,0 +1,23 @@
|
||||
version: '3.5'
|
||||
|
||||
services:
|
||||
${ID}:
|
||||
container_name: proxy-for-${PORT}
|
||||
image: traefik:v2.6
|
||||
command:
|
||||
- --api.insecure=true
|
||||
- --entrypoints.web.address=:${PORT}
|
||||
- --providers.docker=false
|
||||
- --providers.docker.exposedbydefault=false
|
||||
- --providers.http.endpoint=http://host.docker.internal:3000/traefik.json?id=${ID}
|
||||
- --providers.http.pollTimeout=5s
|
||||
- --log.level=error
|
||||
ports:
|
||||
- '${PORT}:${PORT}'
|
||||
networks:
|
||||
- ${NETWORK}
|
||||
|
||||
networks:
|
||||
net:
|
||||
external: false
|
||||
name: ${NETWORK}
|
@ -6,6 +6,7 @@ services:
|
||||
command:
|
||||
- --api.insecure=true
|
||||
- --entrypoints.web.address=:80
|
||||
- --entrypoints.websecure.address=:443
|
||||
- --providers.docker=false
|
||||
- --providers.docker.exposedbydefault=false
|
||||
- --providers.http.endpoint=http://host.docker.internal:3000/traefik.json
|
||||
|
@ -1,24 +0,0 @@
|
||||
-- RedefineTables
|
||||
PRAGMA foreign_keys=OFF;
|
||||
CREATE TABLE "new_Setting" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"fqdn" TEXT,
|
||||
"isRegistrationEnabled" BOOLEAN NOT NULL DEFAULT false,
|
||||
"dualCerts" BOOLEAN NOT NULL DEFAULT false,
|
||||
"minPort" INTEGER NOT NULL DEFAULT 9000,
|
||||
"maxPort" INTEGER NOT NULL DEFAULT 9100,
|
||||
"proxyPassword" TEXT NOT NULL,
|
||||
"proxyUser" TEXT NOT NULL,
|
||||
"proxyHash" TEXT,
|
||||
"isAutoUpdateEnabled" BOOLEAN NOT NULL DEFAULT false,
|
||||
"isDNSCheckEnabled" BOOLEAN NOT NULL DEFAULT true,
|
||||
"disableHaproxy" BOOLEAN NOT NULL DEFAULT false,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL
|
||||
);
|
||||
INSERT INTO "new_Setting" ("createdAt", "dualCerts", "fqdn", "id", "isAutoUpdateEnabled", "isDNSCheckEnabled", "isRegistrationEnabled", "maxPort", "minPort", "proxyHash", "proxyPassword", "proxyUser", "updatedAt") SELECT "createdAt", "dualCerts", "fqdn", "id", "isAutoUpdateEnabled", "isDNSCheckEnabled", "isRegistrationEnabled", "maxPort", "minPort", "proxyHash", "proxyPassword", "proxyUser", "updatedAt" FROM "Setting";
|
||||
DROP TABLE "Setting";
|
||||
ALTER TABLE "new_Setting" RENAME TO "Setting";
|
||||
CREATE UNIQUE INDEX "Setting_fqdn_key" ON "Setting"("fqdn");
|
||||
PRAGMA foreign_key_check;
|
||||
PRAGMA foreign_keys=ON;
|
@ -20,7 +20,7 @@ model Setting {
|
||||
proxyHash String?
|
||||
isAutoUpdateEnabled Boolean @default(false)
|
||||
isDNSCheckEnabled Boolean @default(true)
|
||||
disableHaproxy Boolean @default(false)
|
||||
isTraefikUsed Boolean @default(false)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
@ -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}`);
|
||||
}
|
||||
|
@ -3,12 +3,17 @@ 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 coolifyEndpoint = dev
|
||||
? 'http://host.docker.internal:3000/traefik.json'
|
||||
: 'http://coolify:3000/traefik.json';
|
||||
|
||||
export async function haproxyInstance(): Promise<Got> {
|
||||
const { proxyPassword } = await db.listSettings();
|
||||
@ -99,11 +104,17 @@ export async function checkHAProxy(haproxy?: Got): Promise<void> {
|
||||
|
||||
export async function stopTcpHttpProxy(
|
||||
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 = `proxy-for-${publicPort}`;
|
||||
if (!settings.isTraefikUsed) {
|
||||
containerName = `haproxy-for-${publicPort}`;
|
||||
}
|
||||
if (forceName) containerName = forceName;
|
||||
const found = await checkContainer(engine, containerName);
|
||||
try {
|
||||
if (found) {
|
||||
@ -115,6 +126,67 @@ export async function stopTcpHttpProxy(
|
||||
return error;
|
||||
}
|
||||
}
|
||||
export async function startTraefikTCPProxy(
|
||||
destinationDocker: DestinationDocker,
|
||||
id: string,
|
||||
publicPort: number,
|
||||
privatePort: number,
|
||||
volume?: string
|
||||
): Promise<{ stdout: string; stderr: string } | Error> {
|
||||
const { network, engine } = destinationDocker;
|
||||
const host = getEngine(engine);
|
||||
|
||||
const containerName = `proxy-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(
|
||||
`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]: {
|
||||
container_name: `proxy-for-${publicPort}`,
|
||||
image: 'traefik:v2.6',
|
||||
command: [
|
||||
`--entrypoints.tcp.address=:${publicPort}`,
|
||||
`--providers.http.endpoint=${coolifyEndpoint}?id=${id}&privatePort=${privatePort}&publicPort=${publicPort}&type=tcp`,
|
||||
'--providers.http.pollTimeout=2s',
|
||||
'--log.level=debug'
|
||||
],
|
||||
ports: [`${publicPort}:${publicPort}`],
|
||||
extra_hosts: ['host.docker.internal:host-gateway', `host.docker.internal:${ip}`],
|
||||
volumes: ['/var/run/docker.sock:/var/run/docker.sock'],
|
||||
networks: [network]
|
||||
}
|
||||
},
|
||||
networks: {
|
||||
[network]: {
|
||||
external: false,
|
||||
name: network
|
||||
}
|
||||
}
|
||||
};
|
||||
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,
|
||||
@ -151,6 +223,65 @@ 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 = `proxy-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(
|
||||
`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]: {
|
||||
container_name: `proxy-for-${publicPort}`,
|
||||
image: 'traefik:v2.6',
|
||||
command: [
|
||||
`--entrypoints.http.address=:${publicPort}`,
|
||||
`--providers.http.endpoint=${coolifyEndpoint}?id=${id}&privatePort=${privatePort}&publicPort=${publicPort}&type=http`,
|
||||
'--providers.http.pollTimeout=2s',
|
||||
'--log.level=debug'
|
||||
],
|
||||
ports: [`${publicPort}:${publicPort}`],
|
||||
extra_hosts: ['host.docker.internal:host-gateway', `host.docker.internal:${ip}`],
|
||||
volumes: ['/var/run/docker.sock:/var/run/docker.sock'],
|
||||
networks: [network]
|
||||
}
|
||||
},
|
||||
networks: {
|
||||
[network]: {
|
||||
external: false,
|
||||
name: network
|
||||
}
|
||||
}
|
||||
};
|
||||
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 +328,29 @@ 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 } = 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-ssl-certs:/usr/local/etc/haproxy/ssl -v /var/run/docker.sock:/var/run/docker.sock --network coolify-infra -p "80:80" -p "443:443" -p "8080:8080" --name coolify-proxy -d ${defaultTraefikImage} --api.insecure=true --entrypoints.web.address=:80 --entrypoints.websecure.address=:443 --providers.docker=false --providers.docker.exposedbydefault=false --providers.http.endpoint=${coolifyEndpoint} --providers.http.pollTimeout=5s --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);
|
||||
@ -263,6 +413,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 +447,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,13 @@
|
||||
import { ErrorHandler, generateDatabaseConfiguration, prisma } from '$lib/database';
|
||||
import { startCoolifyProxy, startHttpProxy, startTcpProxy } from '$lib/haproxy';
|
||||
import {
|
||||
startCoolifyProxy,
|
||||
startHttpProxy,
|
||||
startTcpProxy,
|
||||
startTraefikHTTPProxy,
|
||||
startTraefikProxy,
|
||||
startTraefikTCPProxy,
|
||||
stopTcpHttpProxy
|
||||
} from '$lib/haproxy';
|
||||
|
||||
export default async function (): Promise<void | {
|
||||
status: number;
|
||||
@ -11,11 +19,14 @@ export default async function (): Promise<void | {
|
||||
const localDocker = await prisma.destinationDocker.findFirst({
|
||||
where: { engine: '/var/run/docker.sock' }
|
||||
});
|
||||
console.log(settings.disableHaproxy);
|
||||
if (localDocker && localDocker.isCoolifyProxyUsed && !settings.disableHaproxy) {
|
||||
console.log('asd');
|
||||
await startCoolifyProxy('/var/run/docker.sock');
|
||||
if (localDocker && localDocker.isCoolifyProxyUsed) {
|
||||
if (settings.isTraefikUsed) {
|
||||
await startTraefikProxy('/var/run/docker.sock');
|
||||
} else {
|
||||
await startCoolifyProxy('/var/run/docker.sock');
|
||||
}
|
||||
}
|
||||
|
||||
// TCP Proxies
|
||||
const databasesWithPublicPort = await prisma.database.findMany({
|
||||
where: { publicPort: { not: null } },
|
||||
@ -24,8 +35,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(destinationDocker, publicPort, `haproxy-for-${publicPort}`);
|
||||
await startTraefikTCPProxy(destinationDocker, id, publicPort, privatePort);
|
||||
} else {
|
||||
await stopTcpHttpProxy(destinationDocker, publicPort, `proxy-for-${publicPort}`);
|
||||
await startTcpProxy(destinationDocker, id, publicPort, privatePort);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const wordpressWithFtp = await prisma.wordpress.findMany({
|
||||
@ -36,7 +55,15 @@ 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(destinationDocker, ftpPublicPort, `${id}-ftp`);
|
||||
await startTraefikTCPProxy(destinationDocker, `${id}-ftp`, ftpPublicPort, 22);
|
||||
} else {
|
||||
await stopTcpHttpProxy(destinationDocker, ftpPublicPort, `${id}-ftp`);
|
||||
await startTcpProxy(destinationDocker, `${id}-ftp`, ftpPublicPort, 22);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,7 +76,15 @@ export default async function (): Promise<void | {
|
||||
const { service, publicPort } = minio;
|
||||
const { destinationDockerId, destinationDocker, id } = service;
|
||||
if (destinationDockerId) {
|
||||
await startHttpProxy(destinationDocker, id, publicPort, 9000);
|
||||
if (destinationDocker.isCoolifyProxyUsed) {
|
||||
if (settings.isTraefikUsed) {
|
||||
await stopTcpHttpProxy(destinationDocker, publicPort, `haproxy-for-${publicPort}`);
|
||||
await startTraefikHTTPProxy(destinationDocker, id, publicPort, 9000);
|
||||
} else {
|
||||
await stopTcpHttpProxy(destinationDocker, publicPort, `proxy-for-${publicPort}`);
|
||||
await startHttpProxy(destinationDocker, id, publicPort, 9000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
|
@ -12,3 +12,5 @@ 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);
|
||||
|
@ -34,6 +34,7 @@
|
||||
</script>
|
||||
|
||||
<script>
|
||||
export let settings;
|
||||
import '../tailwind.css';
|
||||
import { SvelteToast, toast } from '@zerodevx/svelte-toast';
|
||||
import { page, session } from '$app/stores';
|
||||
@ -42,9 +43,11 @@
|
||||
import { asyncSleep } from '$lib/components/common';
|
||||
import { del, get, post } from '$lib/api';
|
||||
import { dev } from '$app/env';
|
||||
import { features } from '$lib/store';
|
||||
let isUpdateAvailable = false;
|
||||
import { features, isTraefikUsed } from '$lib/store';
|
||||
|
||||
$isTraefikUsed = settings?.isTraefikUsed || false;
|
||||
|
||||
let isUpdateAvailable = false;
|
||||
let updateStatus = {
|
||||
found: false,
|
||||
loading: false,
|
||||
@ -124,13 +127,6 @@
|
||||
return errorNotification(error);
|
||||
}
|
||||
}
|
||||
async function migrateToTraefik() {
|
||||
try {
|
||||
await post(`/update.json`, { type: 'migrateToTraefik' });
|
||||
} catch ({ error }) {
|
||||
return errorNotification(error);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
@ -522,13 +518,15 @@
|
||||
>Powered by <a href="https://coolify.io" target="_blank">Coolify</a></span
|
||||
>
|
||||
{/if}
|
||||
<span class="fixed bottom-[20px] right-[10px] z-50 m-2 px-4 text-xs ">
|
||||
<button on:click={migrateToTraefik}
|
||||
>New proxy is available! <br />It is based on Traefik! Why?<br /><br />Haproxy uses a lots of
|
||||
unnecessary memory. The update will cause a small interruption, but everything should go back
|
||||
to normal in a few seconds!</button
|
||||
>
|
||||
</span>
|
||||
{#if !$isTraefikUsed}
|
||||
<span class="fixed bottom-[20px] right-[10px] z-50 m-2 px-4 text-xs ">
|
||||
<a href="/settings"
|
||||
><button class="bg-coollabs hover:bg-coollabs-100"
|
||||
>New proxy is available! <br />Click here to get more details</button
|
||||
></a
|
||||
>
|
||||
</span>
|
||||
{/if}
|
||||
{/if}
|
||||
<main>
|
||||
<slot />
|
||||
|
@ -49,6 +49,7 @@ export const get: RequestHandler = async (event) => {
|
||||
where: { userId },
|
||||
include: { team: { include: { _count: { select: { users: true } } } } }
|
||||
});
|
||||
const settings = await db.prisma.setting.findFirst();
|
||||
return {
|
||||
body: {
|
||||
teams,
|
||||
@ -57,7 +58,8 @@ export const get: RequestHandler = async (event) => {
|
||||
destinationsCount,
|
||||
teamsCount,
|
||||
databasesCount,
|
||||
servicesCount
|
||||
servicesCount,
|
||||
settings
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { getUserDetails } from '$lib/common';
|
||||
import * as db from '$lib/database';
|
||||
import { generateDatabaseConfiguration, ErrorHandler, getFreePort } from '$lib/database';
|
||||
import { startTcpProxy, stopTcpHttpProxy } from '$lib/haproxy';
|
||||
import { startTcpProxy, startTraefikTCPProxy, stopTcpHttpProxy } from '$lib/haproxy';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
|
||||
export const post: RequestHandler = async (event) => {
|
||||
@ -13,6 +13,7 @@ export const post: RequestHandler = async (event) => {
|
||||
const publicPort = await getFreePort();
|
||||
|
||||
try {
|
||||
const settings = await db.listSettings();
|
||||
await db.setDatabase({ id, isPublic, appendOnly });
|
||||
const database = await db.getDatabase({ id, teamId });
|
||||
const { destinationDockerId, destinationDocker, publicPort: oldPublicPort } = database;
|
||||
@ -21,7 +22,11 @@ export const post: RequestHandler = async (event) => {
|
||||
if (destinationDockerId) {
|
||||
if (isPublic) {
|
||||
await db.prisma.database.update({ where: { id }, data: { publicPort } });
|
||||
await startTcpProxy(destinationDocker, id, publicPort, privatePort);
|
||||
if (settings.isTraefikUsed) {
|
||||
await startTraefikTCPProxy(destinationDocker, id, publicPort, privatePort);
|
||||
} else {
|
||||
await startTcpProxy(destinationDocker, id, publicPort, privatePort);
|
||||
}
|
||||
} else {
|
||||
await db.prisma.database.update({ where: { id }, data: { publicPort: null } });
|
||||
await stopTcpHttpProxy(destinationDocker, oldPublicPort);
|
||||
|
@ -26,8 +26,12 @@ export const get: RequestHandler = async (event) => {
|
||||
// // await saveSshKey(destination);
|
||||
// payload.state = await checkContainer(engine, 'coolify-haproxy');
|
||||
} else {
|
||||
let containerName = 'coolify-proxy';
|
||||
if (!settings.isTraefikUsed) {
|
||||
containerName = 'coolify-haproxy';
|
||||
}
|
||||
payload.state =
|
||||
destination?.engine && (await checkContainer(destination.engine, 'coolify-haproxy'));
|
||||
destination?.engine && (await checkContainer(destination.engine, containerName));
|
||||
}
|
||||
return {
|
||||
status: 200,
|
||||
|
@ -1,7 +1,12 @@
|
||||
import { getUserDetails } from '$lib/common';
|
||||
import { ErrorHandler } from '$lib/database';
|
||||
import * as db from '$lib/database';
|
||||
import { startCoolifyProxy, stopCoolifyProxy } from '$lib/haproxy';
|
||||
import {
|
||||
startCoolifyProxy,
|
||||
startTraefikProxy,
|
||||
stopCoolifyProxy,
|
||||
stopTraefikProxy
|
||||
} from '$lib/haproxy';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
|
||||
export const post: RequestHandler = async (event) => {
|
||||
@ -11,9 +16,16 @@ export const post: RequestHandler = async (event) => {
|
||||
const { engine } = await event.request.json();
|
||||
|
||||
try {
|
||||
await stopCoolifyProxy(engine);
|
||||
await startCoolifyProxy(engine);
|
||||
const settings = await db.prisma.setting.findFirst({});
|
||||
if (settings?.isTraefikUsed) {
|
||||
await stopTraefikProxy(engine);
|
||||
await startTraefikProxy(engine);
|
||||
} else {
|
||||
await stopCoolifyProxy(engine);
|
||||
await startCoolifyProxy(engine);
|
||||
}
|
||||
await db.setDestinationSettings({ engine, isCoolifyProxyUsed: true });
|
||||
|
||||
return {
|
||||
status: 200
|
||||
};
|
||||
|
@ -1,6 +1,12 @@
|
||||
import { getUserDetails } from '$lib/common';
|
||||
import { ErrorHandler } from '$lib/database';
|
||||
import { startCoolifyProxy, stopCoolifyProxy } from '$lib/haproxy';
|
||||
import * as db from '$lib/database';
|
||||
import {
|
||||
startCoolifyProxy,
|
||||
startTraefikProxy,
|
||||
stopCoolifyProxy,
|
||||
stopTraefikProxy
|
||||
} from '$lib/haproxy';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
|
||||
export const post: RequestHandler = async (event) => {
|
||||
@ -8,14 +14,24 @@ export const post: RequestHandler = async (event) => {
|
||||
if (status === 401) return { status, body };
|
||||
|
||||
const { engine } = await event.request.json();
|
||||
const settings = await db.prisma.setting.findFirst({});
|
||||
|
||||
try {
|
||||
await startCoolifyProxy(engine);
|
||||
if (settings?.isTraefikUsed) {
|
||||
await startTraefikProxy(engine);
|
||||
} else {
|
||||
await startCoolifyProxy(engine);
|
||||
}
|
||||
|
||||
return {
|
||||
status: 200
|
||||
};
|
||||
} catch (error) {
|
||||
await stopCoolifyProxy(engine);
|
||||
if (settings?.isTraefikUsed) {
|
||||
await stopTraefikProxy(engine);
|
||||
} else {
|
||||
await stopCoolifyProxy(engine);
|
||||
}
|
||||
return ErrorHandler(error);
|
||||
}
|
||||
};
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { getUserDetails } from '$lib/common';
|
||||
import { ErrorHandler } from '$lib/database';
|
||||
import { stopCoolifyProxy } from '$lib/haproxy';
|
||||
import * as db from '$lib/database';
|
||||
import { stopCoolifyProxy, stopTraefikProxy } from '$lib/haproxy';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
|
||||
export const post: RequestHandler = async (event) => {
|
||||
@ -9,7 +10,13 @@ export const post: RequestHandler = async (event) => {
|
||||
|
||||
const { engine } = await event.request.json();
|
||||
try {
|
||||
await stopCoolifyProxy(engine);
|
||||
const settings = await db.prisma.setting.findFirst({});
|
||||
if (settings?.isTraefikUsed) {
|
||||
await stopTraefikProxy(engine);
|
||||
} else {
|
||||
await stopCoolifyProxy(engine);
|
||||
}
|
||||
|
||||
return {
|
||||
status: 200
|
||||
};
|
||||
|
@ -195,7 +195,6 @@ COPY ./init-db.sh /docker-entrypoint-initdb.d/init-db.sh`;
|
||||
}
|
||||
};
|
||||
const composeFileDestination = `${workdir}/docker-compose.yaml`;
|
||||
console.log(JSON.stringify(composeFile, null, 2));
|
||||
await fs.writeFile(composeFileDestination, yaml.dump(composeFile));
|
||||
await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} pull`);
|
||||
await asyncExecShell(
|
||||
|
@ -3,7 +3,12 @@ import { asyncExecShell, getEngine, getUserDetails } from '$lib/common';
|
||||
import { decrypt, encrypt } from '$lib/crypto';
|
||||
import * as db from '$lib/database';
|
||||
import { ErrorHandler, generatePassword, getFreePort } from '$lib/database';
|
||||
import { checkContainer, startTcpProxy, stopTcpHttpProxy } from '$lib/haproxy';
|
||||
import {
|
||||
checkContainer,
|
||||
startTcpProxy,
|
||||
startTraefikTCPProxy,
|
||||
stopTcpHttpProxy
|
||||
} from '$lib/haproxy';
|
||||
import type { ComposeFile } from '$lib/types/composeFile';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
import cuid from 'cuid';
|
||||
@ -142,8 +147,12 @@ export const post: RequestHandler = async (event) => {
|
||||
await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker compose -f ${hostkeyDir}/${id}-docker-compose.yml up -d`
|
||||
);
|
||||
|
||||
await startTcpProxy(destinationDocker, `${id}-ftp`, publicPort, 22);
|
||||
const settings = await db.prisma.setting.findFirst();
|
||||
if (settings.isTraefikUsed) {
|
||||
await startTraefikTCPProxy(destinationDocker, `${id}-ftp`, publicPort, 22);
|
||||
} else {
|
||||
await startTcpProxy(destinationDocker, `${id}-ftp`, publicPort, 22);
|
||||
}
|
||||
} else {
|
||||
await db.prisma.wordpress.update({
|
||||
where: { serviceId: id },
|
||||
|
@ -72,8 +72,7 @@ export const post: RequestHandler = async (event) => {
|
||||
minPort,
|
||||
maxPort,
|
||||
isAutoUpdateEnabled,
|
||||
isDNSCheckEnabled,
|
||||
forceSave
|
||||
isDNSCheckEnabled
|
||||
} = await event.request.json();
|
||||
try {
|
||||
const { id } = await db.listSettings();
|
||||
|
@ -37,12 +37,13 @@
|
||||
import { getDomain } from '$lib/components/common';
|
||||
import { toast } from '@zerodevx/svelte-toast';
|
||||
import { t } from '$lib/translations';
|
||||
import { features } from '$lib/store';
|
||||
import { features, isTraefikUsed } from '$lib/store';
|
||||
|
||||
let isRegistrationEnabled = settings.isRegistrationEnabled;
|
||||
let dualCerts = settings.dualCerts;
|
||||
let isAutoUpdateEnabled = settings.isAutoUpdateEnabled;
|
||||
let isDNSCheckEnabled = settings.isDNSCheckEnabled;
|
||||
$isTraefikUsed = settings.isTraefikUsed;
|
||||
|
||||
let minPort = settings.minPort;
|
||||
let maxPort = settings.maxPort;
|
||||
@ -55,7 +56,8 @@
|
||||
let isFqdnSet = !!settings.fqdn;
|
||||
let loading = {
|
||||
save: false,
|
||||
remove: false
|
||||
remove: false,
|
||||
proxyMigration: false
|
||||
};
|
||||
|
||||
async function removeFqdn() {
|
||||
@ -86,6 +88,7 @@
|
||||
if (name === 'isDNSCheckEnabled') {
|
||||
isDNSCheckEnabled = !isDNSCheckEnabled;
|
||||
}
|
||||
|
||||
await post(`/settings.json`, {
|
||||
isRegistrationEnabled,
|
||||
dualCerts,
|
||||
@ -156,6 +159,20 @@
|
||||
function resetView() {
|
||||
forceSave = false;
|
||||
}
|
||||
async function migrateProxy(to) {
|
||||
if (loading.proxyMigration) return;
|
||||
try {
|
||||
loading.proxyMigration = true;
|
||||
await post(`/update.json`, { type: to });
|
||||
const data = await get(`/settings.json`);
|
||||
$isTraefikUsed = data.settings.isTraefikUsed;
|
||||
return toast.push('Proxy migration completed.');
|
||||
} catch ({ error }) {
|
||||
return errorNotification(error);
|
||||
} finally {
|
||||
loading.proxyMigration = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="flex space-x-1 p-6 font-bold">
|
||||
@ -192,6 +209,26 @@
|
||||
</div>
|
||||
<div class="grid grid-flow-row gap-2 px-10">
|
||||
<!-- <Language /> -->
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<div class="flex items-center py-4 pr-8">
|
||||
<div class="flex w-96 flex-col">
|
||||
<div class="text-xs font-bold text-stone-100 md:text-base">New Proxy Available!</div>
|
||||
<Explainer
|
||||
text="We are changing to <span class='text-sky-500 font-bold'>Traefik</span> as <span class='text-red-500 font-bold'>HAProxy</span> had several problems and uses a LOT of unnecessary memory (<span class='text-sky-500 font-bold'>~20MB</span> vs <span class='text-red-500 font-bold'>~200MB</span>).<br><br>You can switch back to HAProxy if something is not working and <span class='text-yellow-500 font-bold'>please let us know</span>!"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
disabled={loading.proxyMigration}
|
||||
class="bg-green-600 text-white hover:bg-green-500"
|
||||
on:click={() => migrateProxy($isTraefikUsed ? 'haproxy' : 'traefik')}
|
||||
>{loading.proxyMigration
|
||||
? 'Migrating...'
|
||||
: $isTraefikUsed
|
||||
? 'Switch back to HAProxy'
|
||||
: 'Migrate to Traefik'}</button
|
||||
>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-start">
|
||||
<div class="flex-col">
|
||||
<div class="pt-2 text-base font-bold text-stone-100">
|
||||
|
@ -1,152 +1,308 @@
|
||||
import { dev } from '$app/env';
|
||||
import { asyncExecShell, getDomain, getEngine } from '$lib/common';
|
||||
import { supportedServiceTypesAndVersions } from '$lib/components/common';
|
||||
import * as db from '$lib/database';
|
||||
import { listServicesWithIncludes } from '$lib/database';
|
||||
import { checkContainer } from '$lib/haproxy';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
|
||||
export const get = async () => {
|
||||
const applications = await db.prisma.application.findMany({
|
||||
include: { destinationDocker: true, settings: true }
|
||||
});
|
||||
const data = {
|
||||
applications: [],
|
||||
services: [],
|
||||
coolify: []
|
||||
};
|
||||
for (const application of applications) {
|
||||
const {
|
||||
fqdn,
|
||||
id,
|
||||
port,
|
||||
destinationDocker,
|
||||
destinationDockerId,
|
||||
settings: { previews },
|
||||
updatedAt
|
||||
} = application;
|
||||
if (destinationDockerId) {
|
||||
const { engine, network } = destinationDocker;
|
||||
const isRunning = await checkContainer(engine, id);
|
||||
if (fqdn) {
|
||||
const domain = getDomain(fqdn);
|
||||
const isHttps = fqdn.startsWith('https://');
|
||||
const isWWW = fqdn.includes('www.');
|
||||
const redirectValue = `${isHttps ? 'https://' : 'http://'}${domain}%[capture.req.uri]`;
|
||||
if (isRunning) {
|
||||
data.applications.push({
|
||||
id,
|
||||
port: port || 3000,
|
||||
domain,
|
||||
isRunning,
|
||||
isHttps,
|
||||
redirectValue,
|
||||
redirectTo: isWWW ? domain.replace('www.', '') : 'www.' + domain,
|
||||
updatedAt: updatedAt.getTime()
|
||||
});
|
||||
export const get: RequestHandler = async (event) => {
|
||||
const id = event.url.searchParams.get('id');
|
||||
if (id) {
|
||||
const privatePort = event.url.searchParams.get('privatePort');
|
||||
const publicPort = event.url.searchParams.get('publicPort');
|
||||
const type = event.url.searchParams.get('type');
|
||||
let traefik = {};
|
||||
if (publicPort) {
|
||||
traefik = {
|
||||
[type]: {
|
||||
routers: {
|
||||
[id]: {
|
||||
entrypoints: [type],
|
||||
rule: `HostSNI(\`*\`)`,
|
||||
service: id
|
||||
}
|
||||
},
|
||||
services: {
|
||||
[id]: {
|
||||
loadbalancer: {
|
||||
servers: []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (previews) {
|
||||
const host = getEngine(engine);
|
||||
const { stdout } = await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker container ls --filter="status=running" --filter="network=${network}" --filter="name=${id}-" --format="{{json .Names}}"`
|
||||
);
|
||||
const containers = stdout
|
||||
.trim()
|
||||
.split('\n')
|
||||
.filter((a) => a)
|
||||
.map((c) => c.replace(/"/g, ''));
|
||||
if (containers.length > 0) {
|
||||
for (const container of containers) {
|
||||
const previewDomain = `${container.split('-')[1]}.${domain}`;
|
||||
data.applications.push({
|
||||
id: container,
|
||||
port: port || 3000,
|
||||
domain: previewDomain,
|
||||
};
|
||||
}
|
||||
if (type === 'tcp') {
|
||||
traefik[type].services[id].loadbalancer.servers.push({ address: `${id}:${privatePort}` });
|
||||
} else {
|
||||
traefik[type].services[id].loadbalancer.servers.push({ url: `http://${id}:${privatePort}` });
|
||||
}
|
||||
return {
|
||||
status: 200,
|
||||
body: {
|
||||
...traefik
|
||||
}
|
||||
};
|
||||
} else {
|
||||
const applications = await db.prisma.application.findMany({
|
||||
include: { destinationDocker: true, settings: true }
|
||||
});
|
||||
const data = {
|
||||
applications: [],
|
||||
services: [],
|
||||
coolify: []
|
||||
};
|
||||
for (const application of applications) {
|
||||
const {
|
||||
fqdn,
|
||||
id,
|
||||
port,
|
||||
destinationDocker,
|
||||
destinationDockerId,
|
||||
settings: { previews },
|
||||
updatedAt
|
||||
} = application;
|
||||
if (destinationDockerId) {
|
||||
const { engine, network } = destinationDocker;
|
||||
const isRunning = await checkContainer(engine, id);
|
||||
if (fqdn) {
|
||||
const domain = getDomain(fqdn);
|
||||
const isHttps = fqdn.startsWith('https://');
|
||||
const isWWW = fqdn.includes('www.');
|
||||
const redirectValue = `${isHttps ? 'https://' : 'http://'}${domain}%[capture.req.uri]`;
|
||||
if (isRunning) {
|
||||
data.applications.push({
|
||||
id,
|
||||
port: port || 3000,
|
||||
domain,
|
||||
isRunning,
|
||||
isHttps,
|
||||
redirectValue,
|
||||
redirectTo: isWWW ? domain.replace('www.', '') : 'www.' + domain,
|
||||
updatedAt: updatedAt.getTime()
|
||||
});
|
||||
}
|
||||
if (previews) {
|
||||
const host = getEngine(engine);
|
||||
const { stdout } = await asyncExecShell(
|
||||
`DOCKER_HOST=${host} docker container ls --filter="status=running" --filter="network=${network}" --filter="name=${id}-" --format="{{json .Names}}"`
|
||||
);
|
||||
const containers = stdout
|
||||
.trim()
|
||||
.split('\n')
|
||||
.filter((a) => a)
|
||||
.map((c) => c.replace(/"/g, ''));
|
||||
if (containers.length > 0) {
|
||||
for (const container of containers) {
|
||||
const previewDomain = `${container.split('-')[1]}.${domain}`;
|
||||
data.applications.push({
|
||||
id: container,
|
||||
port: port || 3000,
|
||||
domain: previewDomain,
|
||||
isRunning,
|
||||
isHttps,
|
||||
redirectValue,
|
||||
redirectTo: isWWW ? previewDomain.replace('www.', '') : 'www.' + previewDomain,
|
||||
updatedAt: updatedAt.getTime()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const services = await listServicesWithIncludes();
|
||||
|
||||
for (const service of services) {
|
||||
const {
|
||||
fqdn,
|
||||
id,
|
||||
type,
|
||||
destinationDocker,
|
||||
destinationDockerId,
|
||||
updatedAt,
|
||||
plausibleAnalytics
|
||||
} = service;
|
||||
if (destinationDockerId) {
|
||||
const { engine } = destinationDocker;
|
||||
const found = supportedServiceTypesAndVersions.find((a) => a.name === type);
|
||||
if (found) {
|
||||
const port = found.ports.main;
|
||||
const publicPort = service[type]?.publicPort;
|
||||
const isRunning = await checkContainer(engine, id);
|
||||
if (fqdn) {
|
||||
const domain = getDomain(fqdn);
|
||||
const isHttps = fqdn.startsWith('https://');
|
||||
const isWWW = fqdn.includes('www.');
|
||||
const redirectValue = `${isHttps ? 'https://' : 'http://'}${domain}%[capture.req.uri]`;
|
||||
if (isRunning) {
|
||||
// Plausible Analytics custom script
|
||||
let scriptName = false;
|
||||
if (
|
||||
type === 'plausibleanalytics' &&
|
||||
plausibleAnalytics.scriptName !== 'plausible.js'
|
||||
) {
|
||||
scriptName = plausibleAnalytics.scriptName;
|
||||
}
|
||||
|
||||
data.services.push({
|
||||
id,
|
||||
port,
|
||||
publicPort,
|
||||
domain,
|
||||
isRunning,
|
||||
isHttps,
|
||||
redirectValue,
|
||||
redirectTo: isWWW ? previewDomain.replace('www.', '') : 'www.' + previewDomain,
|
||||
updatedAt: updatedAt.getTime()
|
||||
redirectTo: isWWW ? domain.replace('www.', '') : 'www.' + domain,
|
||||
updatedAt: updatedAt.getTime(),
|
||||
scriptName
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const traefik = {
|
||||
http: {
|
||||
routers: {},
|
||||
services: {}
|
||||
const { fqdn } = await db.prisma.setting.findFirst();
|
||||
if (fqdn) {
|
||||
const domain = getDomain(fqdn);
|
||||
const isHttps = fqdn.startsWith('https://');
|
||||
const isWWW = fqdn.includes('www.');
|
||||
const redirectValue = `${isHttps ? 'https://' : 'http://'}${domain}%[capture.req.uri]`;
|
||||
data.coolify.push({
|
||||
id: dev ? 'host.docker.internal' : 'coolify',
|
||||
port: 3000,
|
||||
domain,
|
||||
isHttps,
|
||||
redirectValue,
|
||||
redirectTo: isWWW ? domain.replace('www.', '') : 'www.' + domain
|
||||
});
|
||||
}
|
||||
};
|
||||
for (const application of data.applications) {
|
||||
const { id, port, domain, isHttps, redirectValue, redirectTo, updatedAt } = application;
|
||||
traefik.http.routers[id] = {
|
||||
entrypoints: ['web'],
|
||||
rule: `Host(\`${domain}\`)`,
|
||||
service: id
|
||||
const traefik = {
|
||||
http: {
|
||||
routers: {},
|
||||
services: {}
|
||||
}
|
||||
};
|
||||
traefik.http.services[id] = {
|
||||
loadbalancer: {
|
||||
servers: [
|
||||
{
|
||||
url: `http://${id}:${port}`
|
||||
for (const application of data.applications) {
|
||||
const { id, port, domain, isHttps, redirectValue, redirectTo, updatedAt } = application;
|
||||
traefik.http.routers[id] = {
|
||||
entrypoints: ['web'],
|
||||
rule: `Host(\`${domain}\`)`,
|
||||
service: id
|
||||
};
|
||||
traefik.http.services[id] = {
|
||||
loadbalancer: {
|
||||
servers: [
|
||||
{
|
||||
url: `http://${id}:${port}`
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
}
|
||||
for (const application of data.services) {
|
||||
const { id, port, domain, isHttps, redirectValue, redirectTo, updatedAt, scriptName } =
|
||||
application;
|
||||
|
||||
traefik.http.routers[id] = {
|
||||
entrypoints: ['web'],
|
||||
rule: `Host(\`${domain}\`)`,
|
||||
service: id
|
||||
};
|
||||
traefik.http.services[id] = {
|
||||
loadbalancer: {
|
||||
servers: [
|
||||
{
|
||||
url: `http://${id}:${port}`
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
if (scriptName) {
|
||||
if (!traefik.http.middlewares) traefik.http.middlewares = {};
|
||||
traefik.http.middlewares[`${id}-redir`] = {
|
||||
replacepathregex: {
|
||||
regex: `/js/${scriptName}`,
|
||||
replacement: '/js/plausible.js'
|
||||
}
|
||||
]
|
||||
};
|
||||
traefik.http.routers[id].middlewares = [`${id}-redir`];
|
||||
}
|
||||
}
|
||||
for (const application of data.coolify) {
|
||||
const { domain, id, port } = application;
|
||||
traefik.http.routers['coolify'] = {
|
||||
entrypoints: ['web'],
|
||||
rule: `Host(\`${domain}\`)`,
|
||||
service: id
|
||||
};
|
||||
traefik.http.services[id] = {
|
||||
loadbalancer: {
|
||||
servers: [
|
||||
{
|
||||
url: `http://${id}:${port}`
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
status: 200,
|
||||
body: {
|
||||
...traefik
|
||||
// "http": {
|
||||
// "routers": {
|
||||
// "coolify": {
|
||||
// "entrypoints": [
|
||||
// "web"
|
||||
// ],
|
||||
// "middlewares": [
|
||||
// "coolify-hc"
|
||||
// ],
|
||||
// "rule": "Host(`staging.coolify.io`)",
|
||||
// "service": "coolify"
|
||||
// },
|
||||
// "static.example.coolify.io": {
|
||||
// "entrypoints": [
|
||||
// "web"
|
||||
// ],
|
||||
// "rule": "Host(`static.example.coolify.io`)",
|
||||
// "service": "static.example.coolify.io"
|
||||
// }
|
||||
// },
|
||||
// "services": {
|
||||
// "coolify": {
|
||||
// "loadbalancer": {
|
||||
// "servers": [
|
||||
// {
|
||||
// "url": "http://coolify:3000"
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// },
|
||||
// "static.example.coolify.io": {
|
||||
// "loadbalancer": {
|
||||
// "servers": [
|
||||
// {
|
||||
// "url": "http://cl32p06f58068518cs3thg6vbc7:80"
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
// "middlewares": {
|
||||
// "coolify-hc": {
|
||||
// "replacepathregex": {
|
||||
// "regex": "/dead.json",
|
||||
// "replacement": "/undead.json"
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
};
|
||||
}
|
||||
return {
|
||||
status: 200,
|
||||
body: {
|
||||
...traefik
|
||||
// "http": {
|
||||
// "routers": {
|
||||
// "coolify": {
|
||||
// "entrypoints": [
|
||||
// "web"
|
||||
// ],
|
||||
// "middlewares": [
|
||||
// "coolify-hc"
|
||||
// ],
|
||||
// "rule": "Host(`staging.coolify.io`)",
|
||||
// "service": "coolify"
|
||||
// },
|
||||
// "static.example.coolify.io": {
|
||||
// "entrypoints": [
|
||||
// "web"
|
||||
// ],
|
||||
// "rule": "Host(`static.example.coolify.io`)",
|
||||
// "service": "static.example.coolify.io"
|
||||
// }
|
||||
// },
|
||||
// "services": {
|
||||
// "coolify": {
|
||||
// "loadbalancer": {
|
||||
// "servers": [
|
||||
// {
|
||||
// "url": "http://coolify:3000"
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// },
|
||||
// "static.example.coolify.io": {
|
||||
// "loadbalancer": {
|
||||
// "servers": [
|
||||
// {
|
||||
// "url": "http://cl32p06f58068518cs3thg6vbc7:80"
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
// "middlewares": {
|
||||
// "coolify-hc": {
|
||||
// "replacepathregex": {
|
||||
// "regex": "/dead.json",
|
||||
// "replacement": "/undead.json"
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
};
|
||||
};
|
||||
|
@ -6,6 +6,12 @@ import * as db from '$lib/database';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
import compare from 'compare-versions';
|
||||
import got from 'got';
|
||||
import {
|
||||
checkContainer,
|
||||
configureNetworkTraefikProxy,
|
||||
startCoolifyProxy,
|
||||
startTraefikProxy
|
||||
} from '$lib/haproxy';
|
||||
|
||||
export const get: RequestHandler = async (request) => {
|
||||
try {
|
||||
@ -34,14 +40,14 @@ export const get: RequestHandler = async (request) => {
|
||||
|
||||
export const post: RequestHandler = async (event) => {
|
||||
const { type, latestVersion } = await event.request.json();
|
||||
const settings = await db.prisma.setting.findFirst();
|
||||
if (type === 'update') {
|
||||
try {
|
||||
if (!dev) {
|
||||
const { isAutoUpdateEnabled } = await db.prisma.setting.findFirst();
|
||||
await asyncExecShell(`docker pull coollabsio/coolify:${latestVersion}`);
|
||||
await asyncExecShell(`env | grep COOLIFY > .env`);
|
||||
await asyncExecShell(
|
||||
`sed -i '/COOLIFY_AUTO_UPDATE=/c\COOLIFY_AUTO_UPDATE=${isAutoUpdateEnabled}' .env`
|
||||
`sed -i '/COOLIFY_AUTO_UPDATE=/c\COOLIFY_AUTO_UPDATE=${settings.isAutoUpdateEnabled}' .env`
|
||||
);
|
||||
await asyncExecShell(
|
||||
`docker run --rm -tid --env-file .env -v /var/run/docker.sock:/var/run/docker.sock -v coolify-db coollabsio/coolify:${latestVersion} /bin/sh -c "env | grep COOLIFY > .env && echo 'TAG=${latestVersion}' >> .env && docker stop -t 0 coolify coolify-redis && docker rm coolify coolify-redis && docker compose up -d --force-recreate"`
|
||||
@ -61,15 +67,37 @@ export const post: RequestHandler = async (event) => {
|
||||
} catch (error) {
|
||||
return ErrorHandler(error);
|
||||
}
|
||||
} else if (type === 'migrateToTraefik') {
|
||||
} else if (type === 'traefik') {
|
||||
try {
|
||||
const settings = await db.prisma.setting.findFirst({});
|
||||
const found = await checkContainer('/var/run/docker.sock', 'coolify-haproxy');
|
||||
if (found) {
|
||||
await asyncExecShell(`docker stop -t 0 coolify-haproxy`);
|
||||
await asyncExecShell(`docker rm coolify-haproxy`);
|
||||
}
|
||||
await startTraefikProxy('/var/run/docker.sock');
|
||||
await db.prisma.setting.update({
|
||||
where: { id: settings.id },
|
||||
data: { disableHaproxy: true }
|
||||
data: { isTraefikUsed: true }
|
||||
});
|
||||
return {
|
||||
status: 200,
|
||||
body: {}
|
||||
};
|
||||
} catch (error) {
|
||||
return ErrorHandler(error);
|
||||
}
|
||||
} else if (type === 'haproxy') {
|
||||
try {
|
||||
const found = await checkContainer('/var/run/docker.sock', 'coolify-proxy');
|
||||
if (found) {
|
||||
await asyncExecShell(`docker stop -t 0 coolify-proxy`);
|
||||
await asyncExecShell(`docker rm coolify-proxy`);
|
||||
}
|
||||
await startCoolifyProxy('/var/run/docker.sock');
|
||||
await db.prisma.setting.update({
|
||||
where: { id: settings.id },
|
||||
data: { isTraefikUsed: false }
|
||||
});
|
||||
await asyncExecShell(`docker stop -t 0 coolify-haproxy`);
|
||||
await asyncExecShell(`docker rm coolify-haproxy`);
|
||||
return {
|
||||
status: 200,
|
||||
body: {}
|
||||
|
Loading…
x
Reference in New Issue
Block a user