wip(fix): traefik
This commit is contained in:
		@@ -108,6 +108,7 @@ export async function checkHAProxy(haproxy?: Got): Promise<void> {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export async function stopTcpHttpProxy(
 | 
					export async function stopTcpHttpProxy(
 | 
				
			||||||
 | 
						id: string,
 | 
				
			||||||
	destinationDocker: DestinationDocker,
 | 
						destinationDocker: DestinationDocker,
 | 
				
			||||||
	publicPort: number,
 | 
						publicPort: number,
 | 
				
			||||||
	forceName: string = null
 | 
						forceName: string = null
 | 
				
			||||||
@@ -115,7 +116,7 @@ export async function stopTcpHttpProxy(
 | 
				
			|||||||
	const { engine } = destinationDocker;
 | 
						const { engine } = destinationDocker;
 | 
				
			||||||
	const host = getEngine(engine);
 | 
						const host = getEngine(engine);
 | 
				
			||||||
	const settings = await db.listSettings();
 | 
						const settings = await db.listSettings();
 | 
				
			||||||
	let containerName = `proxy-for-${publicPort}`;
 | 
						let containerName = `${id}-${publicPort}`;
 | 
				
			||||||
	if (!settings.isTraefikUsed) {
 | 
						if (!settings.isTraefikUsed) {
 | 
				
			||||||
		containerName = `haproxy-for-${publicPort}`;
 | 
							containerName = `haproxy-for-${publicPort}`;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -141,7 +142,7 @@ export async function startTraefikTCPProxy(
 | 
				
			|||||||
	const { network, engine } = destinationDocker;
 | 
						const { network, engine } = destinationDocker;
 | 
				
			||||||
	const host = getEngine(engine);
 | 
						const host = getEngine(engine);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const containerName = `proxy-for-${publicPort}`;
 | 
						const containerName = `${id}-${publicPort}`;
 | 
				
			||||||
	const found = await checkContainer(engine, containerName, true);
 | 
						const found = await checkContainer(engine, containerName, true);
 | 
				
			||||||
	const foundDependentContainer = await checkContainer(engine, id, true);
 | 
						const foundDependentContainer = await checkContainer(engine, id, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -154,8 +155,8 @@ export async function startTraefikTCPProxy(
 | 
				
			|||||||
			const tcpProxy = {
 | 
								const tcpProxy = {
 | 
				
			||||||
				version: '3.5',
 | 
									version: '3.5',
 | 
				
			||||||
				services: {
 | 
									services: {
 | 
				
			||||||
					[id]: {
 | 
										[`${id}-${publicPort}`]: {
 | 
				
			||||||
						container_name: `proxy-for-${publicPort}`,
 | 
											container_name: containerName,
 | 
				
			||||||
						image: 'traefik:v2.6',
 | 
											image: 'traefik:v2.6',
 | 
				
			||||||
						command: [
 | 
											command: [
 | 
				
			||||||
							`--entrypoints.tcp.address=:${publicPort}`,
 | 
												`--entrypoints.tcp.address=:${publicPort}`,
 | 
				
			||||||
@@ -241,7 +242,7 @@ export async function startTraefikHTTPProxy(
 | 
				
			|||||||
	const { network, engine } = destinationDocker;
 | 
						const { network, engine } = destinationDocker;
 | 
				
			||||||
	const host = getEngine(engine);
 | 
						const host = getEngine(engine);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const containerName = `proxy-for-${publicPort}`;
 | 
						const containerName = `${id}-${publicPort}`;
 | 
				
			||||||
	const found = await checkContainer(engine, containerName, true);
 | 
						const found = await checkContainer(engine, containerName, true);
 | 
				
			||||||
	const foundDependentContainer = await checkContainer(engine, id, true);
 | 
						const foundDependentContainer = await checkContainer(engine, id, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -251,21 +252,21 @@ export async function startTraefikHTTPProxy(
 | 
				
			|||||||
				`DOCKER_HOST="${host}" docker network inspect bridge --format '{{json .IPAM.Config }}'`
 | 
									`DOCKER_HOST="${host}" docker network inspect bridge --format '{{json .IPAM.Config }}'`
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
			const ip = JSON.parse(Config)[0].Gateway;
 | 
								const ip = JSON.parse(Config)[0].Gateway;
 | 
				
			||||||
 | 
								console.log({ privatePort, publicPort });
 | 
				
			||||||
			const tcpProxy = {
 | 
								const tcpProxy = {
 | 
				
			||||||
				version: '3.5',
 | 
									version: '3.5',
 | 
				
			||||||
				services: {
 | 
									services: {
 | 
				
			||||||
					[id]: {
 | 
										[`${id}-${publicPort}`]: {
 | 
				
			||||||
						container_name: `proxy-for-${publicPort}`,
 | 
											container_name: containerName,
 | 
				
			||||||
						image: 'traefik:v2.6',
 | 
											image: 'traefik:v2.6',
 | 
				
			||||||
						command: [
 | 
											command: [
 | 
				
			||||||
							`--entrypoints.http.address=:${publicPort}`,
 | 
												`--entrypoints.http.address=:${publicPort}`,
 | 
				
			||||||
							`--providers.http.endpoint=${otherTraefikEndpoint}?id=${id}&privatePort=${privatePort}&publicPort=${publicPort}&type=http`,
 | 
												`--providers.http.endpoint=${otherTraefikEndpoint}?id=${id}&privatePort=${privatePort}&publicPort=${publicPort}&type=http`,
 | 
				
			||||||
							'--providers.http.pollTimeout=2s',
 | 
												'--providers.http.pollTimeout=2s',
 | 
				
			||||||
							'--log.level=error'
 | 
												'--log.level=debug'
 | 
				
			||||||
						],
 | 
											],
 | 
				
			||||||
						ports: [`${publicPort}:${publicPort}`],
 | 
											ports: [`${publicPort}:${publicPort}`],
 | 
				
			||||||
						extra_hosts: ['host.docker.internal:host-gateway', `host.docker.internal:${ip}`],
 | 
											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: ['coolify-infra', network]
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
@@ -377,7 +378,7 @@ export async function startTraefikProxy(engine: string): Promise<void> {
 | 
				
			|||||||
			--certificatesresolvers.letsencrypt.acme.httpchallenge=true \
 | 
								--certificatesresolvers.letsencrypt.acme.httpchallenge=true \
 | 
				
			||||||
			--certificatesresolvers.letsencrypt.acme.storage=/etc/traefik/acme/acme.json \
 | 
								--certificatesresolvers.letsencrypt.acme.storage=/etc/traefik/acme/acme.json \
 | 
				
			||||||
			--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web \
 | 
								--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web \
 | 
				
			||||||
			--log.level=error`
 | 
								--log.level=debug`
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
		await db.prisma.setting.update({ where: { id }, data: { proxyHash: null } });
 | 
							await db.prisma.setting.update({ where: { id }, data: { proxyHash: null } });
 | 
				
			||||||
		await db.setDestinationSettings({ engine, isCoolifyProxyUsed: true });
 | 
							await db.setDestinationSettings({ engine, isCoolifyProxyUsed: true });
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,7 +21,7 @@ export default async function (): Promise<void | {
 | 
				
			|||||||
		const engine = '/var/run/docker.sock';
 | 
							const engine = '/var/run/docker.sock';
 | 
				
			||||||
		const settings = await prisma.setting.findFirst();
 | 
							const settings = await prisma.setting.findFirst();
 | 
				
			||||||
		const localDocker = await prisma.destinationDocker.findFirst({
 | 
							const localDocker = await prisma.destinationDocker.findFirst({
 | 
				
			||||||
			where: { engine }
 | 
								where: { engine, network: 'coolify' }
 | 
				
			||||||
		});
 | 
							});
 | 
				
			||||||
		if (localDocker && localDocker.isCoolifyProxyUsed) {
 | 
							if (localDocker && localDocker.isCoolifyProxyUsed) {
 | 
				
			||||||
			if (settings.isTraefikUsed) {
 | 
								if (settings.isTraefikUsed) {
 | 
				
			||||||
@@ -46,10 +46,10 @@ export default async function (): Promise<void | {
 | 
				
			|||||||
				if (destinationDocker.isCoolifyProxyUsed) {
 | 
									if (destinationDocker.isCoolifyProxyUsed) {
 | 
				
			||||||
					const { privatePort } = generateDatabaseConfiguration(database);
 | 
										const { privatePort } = generateDatabaseConfiguration(database);
 | 
				
			||||||
					if (settings.isTraefikUsed) {
 | 
										if (settings.isTraefikUsed) {
 | 
				
			||||||
						await stopTcpHttpProxy(destinationDocker, publicPort, `haproxy-for-${publicPort}`);
 | 
											await stopTcpHttpProxy(id, destinationDocker, publicPort, `haproxy-for-${publicPort}`);
 | 
				
			||||||
						await startTraefikTCPProxy(destinationDocker, id, publicPort, privatePort);
 | 
											await startTraefikTCPProxy(destinationDocker, id, publicPort, privatePort);
 | 
				
			||||||
					} else {
 | 
										} else {
 | 
				
			||||||
						await stopTcpHttpProxy(destinationDocker, publicPort, `proxy-for-${publicPort}`);
 | 
											await stopTcpHttpProxy(id, destinationDocker, publicPort, `${id}-${publicPort}`);
 | 
				
			||||||
						await startTcpProxy(destinationDocker, id, publicPort, privatePort);
 | 
											await startTcpProxy(destinationDocker, id, publicPort, privatePort);
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
@@ -66,13 +66,14 @@ export default async function (): Promise<void | {
 | 
				
			|||||||
				if (destinationDocker.isCoolifyProxyUsed) {
 | 
									if (destinationDocker.isCoolifyProxyUsed) {
 | 
				
			||||||
					if (settings.isTraefikUsed) {
 | 
										if (settings.isTraefikUsed) {
 | 
				
			||||||
						await stopTcpHttpProxy(
 | 
											await stopTcpHttpProxy(
 | 
				
			||||||
 | 
												id,
 | 
				
			||||||
							destinationDocker,
 | 
												destinationDocker,
 | 
				
			||||||
							ftpPublicPort,
 | 
												ftpPublicPort,
 | 
				
			||||||
							`haproxy-for-${ftpPublicPort}`
 | 
												`haproxy-for-${ftpPublicPort}`
 | 
				
			||||||
						);
 | 
											);
 | 
				
			||||||
						await startTraefikTCPProxy(destinationDocker, `${id}-ftp`, ftpPublicPort, 22);
 | 
											await startTraefikTCPProxy(destinationDocker, `${id}-ftp`, ftpPublicPort, 22);
 | 
				
			||||||
					} else {
 | 
										} else {
 | 
				
			||||||
						await stopTcpHttpProxy(destinationDocker, ftpPublicPort, `proxy-for-${ftpPublicPort}`);
 | 
											await stopTcpHttpProxy(id, destinationDocker, ftpPublicPort, `${id}-${ftpPublicPort}`);
 | 
				
			||||||
						await startTcpProxy(destinationDocker, `${id}-ftp`, ftpPublicPort, 22);
 | 
											await startTcpProxy(destinationDocker, `${id}-ftp`, ftpPublicPort, 22);
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
@@ -90,10 +91,10 @@ export default async function (): Promise<void | {
 | 
				
			|||||||
			if (destinationDockerId) {
 | 
								if (destinationDockerId) {
 | 
				
			||||||
				if (destinationDocker.isCoolifyProxyUsed) {
 | 
									if (destinationDocker.isCoolifyProxyUsed) {
 | 
				
			||||||
					if (settings.isTraefikUsed) {
 | 
										if (settings.isTraefikUsed) {
 | 
				
			||||||
						await stopTcpHttpProxy(destinationDocker, publicPort, `haproxy-for-${publicPort}`);
 | 
											await stopTcpHttpProxy(id, destinationDocker, publicPort, `haproxy-for-${publicPort}`);
 | 
				
			||||||
						await startTraefikHTTPProxy(destinationDocker, id, publicPort, 9000);
 | 
											await startTraefikHTTPProxy(destinationDocker, id, publicPort, 9000);
 | 
				
			||||||
					} else {
 | 
										} else {
 | 
				
			||||||
						await stopTcpHttpProxy(destinationDocker, publicPort, `proxy-for-${publicPort}`);
 | 
											await stopTcpHttpProxy(id, destinationDocker, publicPort, `${id}-${publicPort}`);
 | 
				
			||||||
						await startHttpProxy(destinationDocker, id, publicPort, 9000);
 | 
											await startHttpProxy(destinationDocker, id, publicPort, 9000);
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,6 @@ import * as db from '$lib/database';
 | 
				
			|||||||
import { promises as fs } from 'fs';
 | 
					import { promises as fs } from 'fs';
 | 
				
			||||||
import yaml from 'js-yaml';
 | 
					import yaml from 'js-yaml';
 | 
				
			||||||
import type { RequestHandler } from '@sveltejs/kit';
 | 
					import type { RequestHandler } from '@sveltejs/kit';
 | 
				
			||||||
import { startHttpProxy } from '$lib/haproxy';
 | 
					 | 
				
			||||||
import { ErrorHandler, getFreePort, getServiceImage } from '$lib/database';
 | 
					import { ErrorHandler, getFreePort, getServiceImage } from '$lib/database';
 | 
				
			||||||
import { makeLabelForServices } from '$lib/buildPacks/common';
 | 
					import { makeLabelForServices } from '$lib/buildPacks/common';
 | 
				
			||||||
import type { ComposeFile } from '$lib/types/composeFile';
 | 
					import type { ComposeFile } from '$lib/types/composeFile';
 | 
				
			||||||
@@ -95,7 +94,6 @@ export const post: RequestHandler = async (event) => {
 | 
				
			|||||||
			await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} pull`);
 | 
								await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} pull`);
 | 
				
			||||||
			await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`);
 | 
								await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`);
 | 
				
			||||||
			await db.updateMinioService({ id, publicPort });
 | 
								await db.updateMinioService({ id, publicPort });
 | 
				
			||||||
			await startHttpProxy(destinationDocker, id, publicPort, apiPort);
 | 
					 | 
				
			||||||
			return {
 | 
								return {
 | 
				
			||||||
				status: 200
 | 
									status: 200
 | 
				
			||||||
			};
 | 
								};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,38 +6,10 @@ import { listServicesWithIncludes } from '$lib/database';
 | 
				
			|||||||
import { checkContainer } from '$lib/haproxy';
 | 
					import { checkContainer } from '$lib/haproxy';
 | 
				
			||||||
import type { RequestHandler } from '@sveltejs/kit';
 | 
					import type { RequestHandler } from '@sveltejs/kit';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const traefik = {
 | 
					function configureMiddleware(
 | 
				
			||||||
	http: {
 | 
						{ id, port, domain, nakedDomain, isHttps, isWWW, isDualCerts },
 | 
				
			||||||
		routers: {},
 | 
						traefik
 | 
				
			||||||
		services: {},
 | 
					) {
 | 
				
			||||||
		middlewares: {
 | 
					 | 
				
			||||||
			'redirect-to-https': {
 | 
					 | 
				
			||||||
				redirectscheme: {
 | 
					 | 
				
			||||||
					scheme: 'https'
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			'redirect-to-http': {
 | 
					 | 
				
			||||||
				redirectscheme: {
 | 
					 | 
				
			||||||
					scheme: 'http'
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			'redirect-to-non-www': {
 | 
					 | 
				
			||||||
				redirectregex: {
 | 
					 | 
				
			||||||
					regex: '^https?://www\\.(.+)',
 | 
					 | 
				
			||||||
					replacement: 'http://${1}'
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			'redirect-to-www': {
 | 
					 | 
				
			||||||
				redirectregex: {
 | 
					 | 
				
			||||||
					regex: '^https?://(?:www\\.)?(.+)',
 | 
					 | 
				
			||||||
					replacement: 'http://www.${1}'
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function configureMiddleware({ id, port, domain, nakedDomain, isHttps, isWWW, isDualCerts }) {
 | 
					 | 
				
			||||||
	if (isHttps) {
 | 
						if (isHttps) {
 | 
				
			||||||
		traefik.http.routers[id] = {
 | 
							traefik.http.routers[id] = {
 | 
				
			||||||
			entrypoints: ['web'],
 | 
								entrypoints: ['web'],
 | 
				
			||||||
@@ -155,6 +127,36 @@ function configureMiddleware({ id, port, domain, nakedDomain, isHttps, isWWW, is
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
export const get: RequestHandler = async (event) => {
 | 
					export const get: RequestHandler = async (event) => {
 | 
				
			||||||
 | 
						const traefik = {
 | 
				
			||||||
 | 
							http: {
 | 
				
			||||||
 | 
								routers: {},
 | 
				
			||||||
 | 
								services: {},
 | 
				
			||||||
 | 
								middlewares: {
 | 
				
			||||||
 | 
									'redirect-to-https': {
 | 
				
			||||||
 | 
										redirectscheme: {
 | 
				
			||||||
 | 
											scheme: 'https'
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									'redirect-to-http': {
 | 
				
			||||||
 | 
										redirectscheme: {
 | 
				
			||||||
 | 
											scheme: 'http'
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									'redirect-to-non-www': {
 | 
				
			||||||
 | 
										redirectregex: {
 | 
				
			||||||
 | 
											regex: '^https?://www\\.(.+)',
 | 
				
			||||||
 | 
											replacement: 'http://${1}'
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									'redirect-to-www': {
 | 
				
			||||||
 | 
										redirectregex: {
 | 
				
			||||||
 | 
											regex: '^https?://(?:www\\.)?(.+)',
 | 
				
			||||||
 | 
											replacement: 'http://www.${1}'
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
	const applications = await db.prisma.application.findMany({
 | 
						const applications = await db.prisma.application.findMany({
 | 
				
			||||||
		include: { destinationDocker: true, settings: true }
 | 
							include: { destinationDocker: true, settings: true }
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
@@ -230,7 +232,6 @@ export const get: RequestHandler = async (event) => {
 | 
				
			|||||||
			type,
 | 
								type,
 | 
				
			||||||
			destinationDocker,
 | 
								destinationDocker,
 | 
				
			||||||
			destinationDockerId,
 | 
								destinationDockerId,
 | 
				
			||||||
			updatedAt,
 | 
					 | 
				
			||||||
			dualCerts,
 | 
								dualCerts,
 | 
				
			||||||
			plausibleAnalytics
 | 
								plausibleAnalytics
 | 
				
			||||||
		} = service;
 | 
							} = service;
 | 
				
			||||||
@@ -288,11 +289,11 @@ export const get: RequestHandler = async (event) => {
 | 
				
			|||||||
		});
 | 
							});
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for (const application of data.applications) {
 | 
						for (const application of data.applications) {
 | 
				
			||||||
		configureMiddleware(application);
 | 
							configureMiddleware(application, traefik);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for (const service of data.services) {
 | 
						for (const service of data.services) {
 | 
				
			||||||
		const { id, scriptName } = service;
 | 
							const { id, scriptName } = service;
 | 
				
			||||||
		configureMiddleware(service);
 | 
							configureMiddleware(service, traefik);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (scriptName) {
 | 
							if (scriptName) {
 | 
				
			||||||
			traefik.http.middlewares[`${id}-redir`] = {
 | 
								traefik.http.middlewares[`${id}-redir`] = {
 | 
				
			||||||
@@ -309,9 +310,14 @@ export const get: RequestHandler = async (event) => {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for (const coolify of data.coolify) {
 | 
						for (const coolify of data.coolify) {
 | 
				
			||||||
		configureMiddleware(coolify);
 | 
							configureMiddleware(coolify, traefik);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (Object.keys(traefik.http.routers).length === 0) {
 | 
				
			||||||
 | 
							traefik.http.routers = null;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (Object.keys(traefik.http.services).length === 0) {
 | 
				
			||||||
 | 
							traefik.http.services = null;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	return {
 | 
						return {
 | 
				
			||||||
		status: 200,
 | 
							status: 200,
 | 
				
			||||||
		body: {
 | 
							body: {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -40,14 +40,14 @@ export const get: RequestHandler = async (event) => {
 | 
				
			|||||||
					traefik = {
 | 
										traefik = {
 | 
				
			||||||
						[type]: {
 | 
											[type]: {
 | 
				
			||||||
							routers: {
 | 
												routers: {
 | 
				
			||||||
								[id]: {
 | 
													[`${id}-${publicPort}`]: {
 | 
				
			||||||
									entrypoints: [type],
 | 
														entrypoints: [type],
 | 
				
			||||||
									rule: `Host(\`${domain}\`)`,
 | 
														rule: `Host(\`${domain}\`)`,
 | 
				
			||||||
									service: id
 | 
														service: `${id}-${publicPort}`
 | 
				
			||||||
								}
 | 
													}
 | 
				
			||||||
							},
 | 
												},
 | 
				
			||||||
							services: {
 | 
												services: {
 | 
				
			||||||
								[id]: {
 | 
													[`${id}-${publicPort}`]: {
 | 
				
			||||||
									loadbalancer: {
 | 
														loadbalancer: {
 | 
				
			||||||
										servers: [{ url: `http://${id}:${privatePort}` }]
 | 
															servers: [{ url: `http://${id}:${privatePort}` }]
 | 
				
			||||||
									}
 | 
														}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user