diff --git a/src/lib/database/applications.ts b/src/lib/database/applications.ts index ece44bffa..e96d41e63 100644 --- a/src/lib/database/applications.ts +++ b/src/lib/database/applications.ts @@ -1,5 +1,5 @@ import { decrypt, encrypt } from '$lib/crypto'; -import { removeProxyConfiguration } from '$lib/haproxy'; +import { removeProxyConfiguration, removeWwwRedirection } from '$lib/haproxy'; import { asyncExecShell, getEngine } from '$lib/common'; import { getDomain, removeDestinationDocker } from '$lib/common'; diff --git a/src/lib/haproxy/index.ts b/src/lib/haproxy/index.ts index ffed44d2a..56b7ce789 100644 --- a/src/lib/haproxy/index.ts +++ b/src/lib/haproxy/index.ts @@ -50,12 +50,12 @@ export async function completeTransaction(transactionId) { } export async function removeProxyConfiguration({ domain }) { - const transactionId = await getNextTransactionId(); const haproxy = await haproxyInstance(); const backendFound = await haproxy .get(`v2/services/haproxy/configuration/backends/${domain}`) .json(); if (backendFound) { + const transactionId = await getNextTransactionId(); await haproxy .delete(`v2/services/haproxy/configuration/backends/${domain}`, { searchParams: { @@ -63,32 +63,9 @@ export async function removeProxyConfiguration({ domain }) { } }) .json(); + await completeTransaction(transactionId); } - const rules: any = await haproxy - .get(`v2/services/haproxy/configuration/http_request_rules`, { - searchParams: { - parent_name: 'http', - parent_type: 'frontend' - } - }) - .json(); - if (rules.data.length > 0) { - const rule = rules.data.find((rule) => - rule.redir_value.includes(`${domain}%[capture.req.uri]`) - ); - if (rule) { - await haproxy - .delete(`v2/services/haproxy/configuration/http_request_rules/${rule.index}`, { - searchParams: { - transaction_id: transactionId, - parent_name: 'http', - parent_type: 'frontend' - } - }) - .json(); - } - } - await completeTransaction(transactionId); + await removeWwwRedirection(domain); } export async function forceSSLOffApplication({ domain }) { if (!dev) { @@ -303,7 +280,8 @@ export async function configureProxyForApplication({ domain, imageId, applicatio } } -export async function configureCoolifyProxyOff({ domain }) { +export async function configureCoolifyProxyOff(fqdn) { + const domain = getDomain(fqdn); const haproxy = await haproxyInstance(); try { await checkHAProxy(haproxy); @@ -325,6 +303,7 @@ export async function configureCoolifyProxyOff({ domain }) { if (!dev) { await forceSSLOffApplication({ domain }); } + await setWwwRedirection(fqdn); } catch (error) { throw error?.response?.body || error; } @@ -337,7 +316,8 @@ export async function checkHAProxy(haproxy) { throw 'HAProxy is not running, but it should be!'; } } -export async function configureCoolifyProxyOn({ domain }) { +export async function configureCoolifyProxyOn(fqdn) { + const domain = getDomain(fqdn); const haproxy = await haproxyInstance(); try { await checkHAProxy(haproxy); @@ -544,7 +524,15 @@ export async function configureSimpleServiceProxyOn({ id, domain, port }) { await checkHAProxy(haproxy); try { await haproxy.get(`v2/services/haproxy/configuration/backends/${domain}`).json(); - return; + const transactionId = await getNextTransactionId(); + await haproxy + .delete(`v2/services/haproxy/configuration/backends/${domain}`, { + searchParams: { + transaction_id: transactionId + } + }) + .json(); + await completeTransaction(transactionId); } catch (error) {} try { const transactionId = await getNextTransactionId(); @@ -570,6 +558,12 @@ export async function configureSimpleServiceProxyOn({ id, domain, port }) { port: port } }); + console.log({ + address: id, + check: 'enabled', + name: id, + port: port + }); await completeTransaction(transactionId); } catch (error) { console.log(error); @@ -596,9 +590,45 @@ export async function configureSimpleServiceProxyOff({ domain }) { .json(); await completeTransaction(transactionId); } catch (error) {} + await removeWwwRedirection(domain); return; } +export async function removeWwwRedirection(domain) { + const haproxy = await haproxyInstance(); + try { + await checkHAProxy(haproxy); + } catch (error) { + return; + } + + const rules: any = await haproxy + .get(`v2/services/haproxy/configuration/http_request_rules`, { + searchParams: { + parent_name: 'http', + parent_type: 'frontend' + } + }) + .json(); + if (rules.data.length > 0) { + const rule = rules.data.find((rule) => + rule.redir_value.includes(`${domain}%[capture.req.uri]`) + ); + if (rule) { + const transactionId = await getNextTransactionId(); + await haproxy + .delete(`v2/services/haproxy/configuration/http_request_rules/${rule.index}`, { + searchParams: { + transaction_id: transactionId, + parent_name: 'http', + parent_type: 'frontend' + } + }) + .json(); + await completeTransaction(transactionId); + } + } +} export async function setWwwRedirection(fqdn) { const haproxy = await haproxyInstance(); try { @@ -612,6 +642,7 @@ export async function setWwwRedirection(fqdn) { const domain = getDomain(fqdn); const isHttps = fqdn.startsWith('https://'); const isWWW = fqdn.includes('www.'); + const contTest = `{ req.hdr(host) -i ${isWWW ? domain.replace('www.', '') : `www.${domain}`} }`; const rules: any = await haproxy .get(`v2/services/haproxy/configuration/http_request_rules`, { searchParams: { @@ -638,12 +669,12 @@ export async function setWwwRedirection(fqdn) { }, json: { index: nextRule, - cond: `${isWWW ? 'unless' : 'if'}`, - cond_test: `{ hdr_beg(host) -i www }`, + cond: 'if', + cond_test: contTest, type: 'redirect', redir_type: 'location', redir_value: redirectValue, - redir_code: 301 + redir_code: dev ? 302 : 301 } }) .json(); diff --git a/src/lib/queues/proxy.ts b/src/lib/queues/proxy.ts index 90dedde80..1e1b9c2f3 100644 --- a/src/lib/queues/proxy.ts +++ b/src/lib/queues/proxy.ts @@ -7,6 +7,7 @@ import { configureProxyForApplication, forceSSLOnApplication, reloadHaproxy, + setWwwRedirection, startCoolifyProxy } from '$lib/haproxy'; import * as db from '$lib/database'; @@ -40,6 +41,7 @@ export default async function () { }); const isHttps = fqdn.startsWith('https://'); if (isHttps) await forceSSLOnApplication({ domain }); + await setWwwRedirection(fqdn); } } } @@ -52,6 +54,7 @@ export default async function () { const found = await checkContainer('/var/run/docker.sock', 'coolify-haproxy'); if (!found) await startCoolifyProxy('/var/run/docker.sock'); await configureCoolifyProxyOn({ domain }); + await setWwwRedirection(fqdn); const isHttps = fqdn.startsWith('https://'); if (isHttps) await forceSSLOnApplication({ domain }); } diff --git a/src/routes/services/[id]/minio/start.json.ts b/src/routes/services/[id]/minio/start.json.ts index 3b7d78525..dbdf65613 100644 --- a/src/routes/services/[id]/minio/start.json.ts +++ b/src/routes/services/[id]/minio/start.json.ts @@ -7,6 +7,7 @@ import { letsEncrypt } from '$lib/letsencrypt'; import { configureSimpleServiceProxyOn, reloadHaproxy, + setWwwRedirection, startHttpProxy, startTcpProxy } from '$lib/haproxy'; @@ -86,13 +87,13 @@ export const post: RequestHandler = async (event) => { try { await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`); await configureSimpleServiceProxyOn({ id, domain, port: consolePort }); - await db.updateMinioService({ id, publicPort }); await startHttpProxy(destinationDocker, id, publicPort, apiPort); if (isHttps) { await letsEncrypt({ domain, id }); } + await setWwwRedirection(fqdn); await reloadHaproxy(destinationDocker.engine); return { status: 200 diff --git a/src/routes/services/[id]/nocodb/start.json.ts b/src/routes/services/[id]/nocodb/start.json.ts index 6d7d214a8..b0e29457c 100644 --- a/src/routes/services/[id]/nocodb/start.json.ts +++ b/src/routes/services/[id]/nocodb/start.json.ts @@ -4,7 +4,7 @@ import { promises as fs } from 'fs'; import yaml from 'js-yaml'; import type { RequestHandler } from '@sveltejs/kit'; import { letsEncrypt } from '$lib/letsencrypt'; -import { configureSimpleServiceProxyOn, reloadHaproxy } from '$lib/haproxy'; +import { configureSimpleServiceProxyOn, reloadHaproxy, setWwwRedirection } from '$lib/haproxy'; import { getDomain } from '$lib/components/common'; import { PrismaErrorHandler } from '$lib/database'; @@ -52,6 +52,7 @@ export const post: RequestHandler = async (event) => { if (isHttps) { await letsEncrypt({ domain, id }); } + await setWwwRedirection(fqdn); await reloadHaproxy(destinationDocker.engine); return { status: 200 diff --git a/src/routes/services/[id]/plausibleanalytics/start.json.ts b/src/routes/services/[id]/plausibleanalytics/start.json.ts index 406e67adc..9314f9c01 100644 --- a/src/routes/services/[id]/plausibleanalytics/start.json.ts +++ b/src/routes/services/[id]/plausibleanalytics/start.json.ts @@ -4,7 +4,7 @@ import { promises as fs } from 'fs'; import yaml from 'js-yaml'; import type { RequestHandler } from '@sveltejs/kit'; import { letsEncrypt } from '$lib/letsencrypt'; -import { configureSimpleServiceProxyOn, reloadHaproxy } from '$lib/haproxy'; +import { configureSimpleServiceProxyOn, reloadHaproxy, setWwwRedirection } from '$lib/haproxy'; import { getDomain } from '$lib/components/common'; import { PrismaErrorHandler } from '$lib/database'; @@ -185,6 +185,7 @@ COPY ./init-db.sh /docker-entrypoint-initdb.d/init-db.sh`; if (isHttps) { await letsEncrypt({ domain, id }); } + await setWwwRedirection(fqdn); await reloadHaproxy(destinationDocker.engine); return { status: 200 diff --git a/src/routes/services/[id]/vaultwarden/start.json.ts b/src/routes/services/[id]/vaultwarden/start.json.ts index a84366092..f219acfb2 100644 --- a/src/routes/services/[id]/vaultwarden/start.json.ts +++ b/src/routes/services/[id]/vaultwarden/start.json.ts @@ -4,7 +4,7 @@ import { promises as fs } from 'fs'; import yaml from 'js-yaml'; import type { RequestHandler } from '@sveltejs/kit'; import { letsEncrypt } from '$lib/letsencrypt'; -import { configureSimpleServiceProxyOn, reloadHaproxy } from '$lib/haproxy'; +import { configureSimpleServiceProxyOn, reloadHaproxy, setWwwRedirection } from '$lib/haproxy'; import { getDomain } from '$lib/components/common'; import { getServiceImage, PrismaErrorHandler } from '$lib/database'; @@ -70,6 +70,7 @@ export const post: RequestHandler = async (event) => { if (isHttps) { await letsEncrypt({ domain, id }); } + await setWwwRedirection(fqdn); await reloadHaproxy(destinationDocker.engine); return { status: 200 diff --git a/src/routes/services/[id]/vscodeserver/start.json.ts b/src/routes/services/[id]/vscodeserver/start.json.ts index 4e762c7c7..8b58c575b 100644 --- a/src/routes/services/[id]/vscodeserver/start.json.ts +++ b/src/routes/services/[id]/vscodeserver/start.json.ts @@ -4,7 +4,7 @@ import { promises as fs } from 'fs'; import yaml from 'js-yaml'; import type { RequestHandler } from '@sveltejs/kit'; import { letsEncrypt } from '$lib/letsencrypt'; -import { configureSimpleServiceProxyOn, reloadHaproxy } from '$lib/haproxy'; +import { configureSimpleServiceProxyOn, reloadHaproxy, setWwwRedirection } from '$lib/haproxy'; import { getDomain } from '$lib/components/common'; import { PrismaErrorHandler } from '$lib/database'; @@ -80,6 +80,7 @@ export const post: RequestHandler = async (event) => { if (isHttps) { await letsEncrypt({ domain, id }); } + await setWwwRedirection(fqdn); await reloadHaproxy(destinationDocker.engine); return { status: 200 diff --git a/src/routes/services/[id]/wordpress/start.json.ts b/src/routes/services/[id]/wordpress/start.json.ts index ffb0c11e7..182cac019 100644 --- a/src/routes/services/[id]/wordpress/start.json.ts +++ b/src/routes/services/[id]/wordpress/start.json.ts @@ -4,7 +4,7 @@ import { promises as fs } from 'fs'; import yaml from 'js-yaml'; import type { RequestHandler } from '@sveltejs/kit'; import { letsEncrypt } from '$lib/letsencrypt'; -import { configureSimpleServiceProxyOn, reloadHaproxy } from '$lib/haproxy'; +import { configureSimpleServiceProxyOn, reloadHaproxy, setWwwRedirection } from '$lib/haproxy'; import { getDomain } from '$lib/components/common'; import { PrismaErrorHandler } from '$lib/database'; @@ -117,6 +117,7 @@ export const post: RequestHandler = async (event) => { if (isHttps) { await letsEncrypt({ domain, id }); } + await setWwwRedirection(fqdn); await reloadHaproxy(destinationDocker.engine); return { status: 200 diff --git a/src/routes/settings/index.json.ts b/src/routes/settings/index.json.ts index 3a2498179..48604156a 100644 --- a/src/routes/settings/index.json.ts +++ b/src/routes/settings/index.json.ts @@ -9,6 +9,8 @@ import { forceSSLOffApplication, forceSSLOnApplication, reloadHaproxy, + removeWwwRedirection, + setWwwRedirection, startCoolifyProxy } from '$lib/haproxy'; import { letsEncrypt } from '$lib/letsencrypt'; @@ -45,9 +47,10 @@ export const del: RequestHandler = async (event) => { const { fqdn } = await event.request.json(); try { - await db.prisma.setting.update({ where: { fqdn }, data: { fqdn: null } }); const domain = getDomain(fqdn); - await configureCoolifyProxyOff({ domain }); + await db.prisma.setting.update({ where: { fqdn }, data: { fqdn: null } }); + await configureCoolifyProxyOff(fqdn); + await removeWwwRedirection(domain); return { status: 201 }; @@ -77,9 +80,10 @@ export const post: RequestHandler = async (event) => { await db.prisma.setting.update({ where: { id }, data: { isRegistrationEnabled } }); } if (oldFqdn && oldFqdn !== fqdn) { - const oldDomain = getDomain(oldFqdn); if (oldFqdn) { - await configureCoolifyProxyOff({ domain: oldDomain }); + const oldDomain = getDomain(oldFqdn); + await configureCoolifyProxyOff(oldFqdn); + await removeWwwRedirection(oldDomain); } } if (fqdn) { @@ -88,7 +92,8 @@ export const post: RequestHandler = async (event) => { const domain = getDomain(fqdn); const isHttps = fqdn.startsWith('https://'); if (domain) { - await configureCoolifyProxyOn({ domain }); + await configureCoolifyProxyOn(fqdn); + await setWwwRedirection(fqdn); if (isHttps && !dev) { await letsEncrypt({ domain, isCoolify: true }); await forceSSLOnApplication({ domain }); diff --git a/src/routes/settings/index.svelte b/src/routes/settings/index.svelte index e7235c3b9..91bba0e2b 100644 --- a/src/routes/settings/index.svelte +++ b/src/routes/settings/index.svelte @@ -106,7 +106,7 @@
Domain (FQDN)
-