diff --git a/src/lib/haproxy/index.ts b/src/lib/haproxy/index.ts
index 3199008fa..ffed44d2a 100644
--- a/src/lib/haproxy/index.ts
+++ b/src/lib/haproxy/index.ts
@@ -1,5 +1,5 @@
import { dev } from '$app/env';
-import { asyncExecShell, getEngine } from '$lib/common';
+import { asyncExecShell, getDomain, getEngine } from '$lib/common';
import got from 'got';
import * as db from '$lib/database';
import { letsEncrypt } from '$lib/letsencrypt';
@@ -50,8 +50,8 @@ export async function completeTransaction(transactionId) {
}
export async function removeProxyConfiguration({ domain }) {
- const haproxy = await haproxyInstance();
const transactionId = await getNextTransactionId();
+ const haproxy = await haproxyInstance();
const backendFound = await haproxy
.get(`v2/services/haproxy/configuration/backends/${domain}`)
.json();
@@ -63,8 +63,32 @@ 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);
}
export async function forceSSLOffApplication({ domain }) {
if (!dev) {
@@ -124,7 +148,9 @@ export async function forceSSLOnApplication({ domain }) {
.json();
let nextRule = 0;
if (rules.data.length > 0) {
- const rule = rules.data.find((rule) => rule.cond_test.includes(`-i ${domain}`));
+ const rule = rules.data.find((rule) =>
+ rule.cond_test.includes(`{ hdr(host) -i ${domain} } !{ ssl_fc }`)
+ );
if (rule) return;
nextRule = rules.data[rules.data.length - 1].index + 1;
}
@@ -138,7 +164,7 @@ export async function forceSSLOnApplication({ domain }) {
json: {
index: nextRule,
cond: 'if',
- cond_test: `{ hdr(Host) -i ${domain} } !{ ssl_fc }`,
+ cond_test: `{ hdr(host) -i ${domain} } !{ ssl_fc }`,
type: 'redirect',
redir_type: 'scheme',
redir_value: 'https',
@@ -572,3 +598,59 @@ export async function configureSimpleServiceProxyOff({ domain }) {
} catch (error) {}
return;
}
+
+export async function setWwwRedirection(fqdn) {
+ const haproxy = await haproxyInstance();
+ try {
+ await checkHAProxy(haproxy);
+ } catch (error) {
+ return;
+ }
+ const transactionId = await getNextTransactionId();
+
+ try {
+ const domain = getDomain(fqdn);
+ const isHttps = fqdn.startsWith('https://');
+ const isWWW = fqdn.includes('www.');
+ const rules: any = await haproxy
+ .get(`v2/services/haproxy/configuration/http_request_rules`, {
+ searchParams: {
+ parent_name: 'http',
+ parent_type: 'frontend'
+ }
+ })
+ .json();
+ let nextRule = 0;
+ if (rules.data.length > 0) {
+ const rule = rules.data.find((rule) =>
+ rule.redir_value.includes(`${domain}%[capture.req.uri]`)
+ );
+ if (rule) return;
+ nextRule = rules.data[rules.data.length - 1].index + 1;
+ }
+ const redirectValue = `${isHttps ? 'https://' : 'http://'}${domain}%[capture.req.uri]`;
+ await haproxy
+ .post(`v2/services/haproxy/configuration/http_request_rules`, {
+ searchParams: {
+ transaction_id: transactionId,
+ parent_name: 'http',
+ parent_type: 'frontend'
+ },
+ json: {
+ index: nextRule,
+ cond: `${isWWW ? 'unless' : 'if'}`,
+ cond_test: `{ hdr_beg(host) -i www }`,
+ type: 'redirect',
+ redir_type: 'location',
+ redir_value: redirectValue,
+ redir_code: 301
+ }
+ })
+ .json();
+ } catch (error) {
+ console.log(error);
+ throw error;
+ } finally {
+ await completeTransaction(transactionId);
+ }
+}
diff --git a/src/lib/queues/builder.ts b/src/lib/queues/builder.ts
index 89513ebcf..8d35ac8d1 100644
--- a/src/lib/queues/builder.ts
+++ b/src/lib/queues/builder.ts
@@ -4,7 +4,7 @@ import * as buildpacks from '../buildPacks';
import * as importers from '../importers';
import { dockerInstance } from '../docker';
import { asyncExecShell, createDirectories, getDomain, getEngine, saveBuildLog } from '../common';
-import { configureProxyForApplication, reloadHaproxy } from '../haproxy';
+import { configureProxyForApplication, reloadHaproxy, setWwwRedirection } from '../haproxy';
import * as db from '$lib/database';
import { decrypt } from '$lib/crypto';
import { sentry } from '$lib/common';
@@ -248,6 +248,7 @@ export default async function (job) {
saveBuildLog({ line: 'Proxy configuration started!', buildId, applicationId });
await configureProxyForApplication({ domain, imageId, applicationId, port });
if (isHttps) await letsEncrypt({ domain, id: applicationId });
+ await setWwwRedirection(fqdn);
await reloadHaproxy(destinationDocker.engine);
saveBuildLog({ line: 'Proxy configuration successful!', buildId, applicationId });
} else {
diff --git a/src/routes/applications/[id]/index.svelte b/src/routes/applications/[id]/index.svelte
index 91bc1c69f..930088ec5 100644
--- a/src/routes/applications/[id]/index.svelte
+++ b/src/routes/applications/[id]/index.svelte
@@ -266,7 +266,7 @@
required
/>
diff --git a/src/routes/services/[id]/_Services/_Services.svelte b/src/routes/services/[id]/_Services/_Services.svelte
index 0b1d6f622..6754d31fe 100644
--- a/src/routes/services/[id]/_Services/_Services.svelte
+++ b/src/routes/services/[id]/_Services/_Services.svelte
@@ -110,25 +110,9 @@
required
/>
-
{#if service.type === 'plausibleanalytics'}
diff --git a/src/routes/settings/index.svelte b/src/routes/settings/index.svelte
index 48407e8b3..e7235c3b9 100644
--- a/src/routes/settings/index.svelte
+++ b/src/routes/settings/index.svelte
@@ -118,7 +118,7 @@
required
/>