feat: www <-> non-www redirection for apps
This commit is contained in:
parent
3deff162bb
commit
69d3cb5dd8
@ -1,5 +1,5 @@
|
|||||||
import { dev } from '$app/env';
|
import { dev } from '$app/env';
|
||||||
import { asyncExecShell, getEngine } from '$lib/common';
|
import { asyncExecShell, getDomain, getEngine } from '$lib/common';
|
||||||
import got from 'got';
|
import got from 'got';
|
||||||
import * as db from '$lib/database';
|
import * as db from '$lib/database';
|
||||||
import { letsEncrypt } from '$lib/letsencrypt';
|
import { letsEncrypt } from '$lib/letsencrypt';
|
||||||
@ -50,8 +50,8 @@ export async function completeTransaction(transactionId) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function removeProxyConfiguration({ domain }) {
|
export async function removeProxyConfiguration({ domain }) {
|
||||||
const haproxy = await haproxyInstance();
|
|
||||||
const transactionId = await getNextTransactionId();
|
const transactionId = await getNextTransactionId();
|
||||||
|
const haproxy = await haproxyInstance();
|
||||||
const backendFound = await haproxy
|
const backendFound = await haproxy
|
||||||
.get(`v2/services/haproxy/configuration/backends/${domain}`)
|
.get(`v2/services/haproxy/configuration/backends/${domain}`)
|
||||||
.json();
|
.json();
|
||||||
@ -63,8 +63,32 @@ export async function removeProxyConfiguration({ domain }) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.json();
|
.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 }) {
|
export async function forceSSLOffApplication({ domain }) {
|
||||||
if (!dev) {
|
if (!dev) {
|
||||||
@ -124,7 +148,9 @@ export async function forceSSLOnApplication({ domain }) {
|
|||||||
.json();
|
.json();
|
||||||
let nextRule = 0;
|
let nextRule = 0;
|
||||||
if (rules.data.length > 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;
|
if (rule) return;
|
||||||
nextRule = rules.data[rules.data.length - 1].index + 1;
|
nextRule = rules.data[rules.data.length - 1].index + 1;
|
||||||
}
|
}
|
||||||
@ -138,7 +164,7 @@ export async function forceSSLOnApplication({ domain }) {
|
|||||||
json: {
|
json: {
|
||||||
index: nextRule,
|
index: nextRule,
|
||||||
cond: 'if',
|
cond: 'if',
|
||||||
cond_test: `{ hdr(Host) -i ${domain} } !{ ssl_fc }`,
|
cond_test: `{ hdr(host) -i ${domain} } !{ ssl_fc }`,
|
||||||
type: 'redirect',
|
type: 'redirect',
|
||||||
redir_type: 'scheme',
|
redir_type: 'scheme',
|
||||||
redir_value: 'https',
|
redir_value: 'https',
|
||||||
@ -572,3 +598,59 @@ export async function configureSimpleServiceProxyOff({ domain }) {
|
|||||||
} catch (error) {}
|
} catch (error) {}
|
||||||
return;
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -4,7 +4,7 @@ import * as buildpacks from '../buildPacks';
|
|||||||
import * as importers from '../importers';
|
import * as importers from '../importers';
|
||||||
import { dockerInstance } from '../docker';
|
import { dockerInstance } from '../docker';
|
||||||
import { asyncExecShell, createDirectories, getDomain, getEngine, saveBuildLog } from '../common';
|
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 * as db from '$lib/database';
|
||||||
import { decrypt } from '$lib/crypto';
|
import { decrypt } from '$lib/crypto';
|
||||||
import { sentry } from '$lib/common';
|
import { sentry } from '$lib/common';
|
||||||
@ -248,6 +248,7 @@ export default async function (job) {
|
|||||||
saveBuildLog({ line: 'Proxy configuration started!', buildId, applicationId });
|
saveBuildLog({ line: 'Proxy configuration started!', buildId, applicationId });
|
||||||
await configureProxyForApplication({ domain, imageId, applicationId, port });
|
await configureProxyForApplication({ domain, imageId, applicationId, port });
|
||||||
if (isHttps) await letsEncrypt({ domain, id: applicationId });
|
if (isHttps) await letsEncrypt({ domain, id: applicationId });
|
||||||
|
await setWwwRedirection(fqdn);
|
||||||
await reloadHaproxy(destinationDocker.engine);
|
await reloadHaproxy(destinationDocker.engine);
|
||||||
saveBuildLog({ line: 'Proxy configuration successful!', buildId, applicationId });
|
saveBuildLog({ line: 'Proxy configuration successful!', buildId, applicationId });
|
||||||
} else {
|
} else {
|
||||||
|
@ -266,7 +266,7 @@
|
|||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
<Explainer
|
<Explainer
|
||||||
text="If you specify <span class='text-green-600 font-bold'>https</span>, the application will be accessible only over https. SSL certificate will be generated for you.<br>To modify the domain, you must first stop the application."
|
text="If you specify <span class='text-green-600 font-bold'>https</span>, the application will be accessible only over https. SSL certificate will be generated for you.<br>If you specify <span class='text-green-600 font-bold'>www</span>, the application will be redirected (302) from non-www and vice versa.<br><br>To modify the domain, you must first stop the application."
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -110,25 +110,9 @@
|
|||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
<Explainer
|
<Explainer
|
||||||
text="If you specify <span class='text-green-600 font-bold'>https</span>, the application will be accessible only over https. SSL certificate will be generated for you."
|
text="If you specify <span class='text-pink-600 font-bold'>https</span>, the application will be accessible only over https. SSL certificate will be generated for you.<br>If you specify <span class='text-pink-600 font-bold'>www</span>, the application will be redirected (302) from non-www and vice versa.<br><br>To modify the domain, you must first stop the application."
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<!-- {:else}
|
|
||||||
<label for="fqdn" class="pt-2">Domain (FQDN)</label>
|
|
||||||
<div class="col-span-2 ">
|
|
||||||
<CopyPasswordField
|
|
||||||
placeholder="eg: https://analytics.coollabs.io"
|
|
||||||
readonly={!$session.isAdmin}
|
|
||||||
name="fqdn"
|
|
||||||
id="fqdn"
|
|
||||||
bind:value={service.fqdn}
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
<Explainer
|
|
||||||
text="If you specify <span class='text-green-600'>https</span>, the application will be accessible only over https. SSL certificate will be generated for you."
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{/if} -->
|
|
||||||
</div>
|
</div>
|
||||||
{#if service.type === 'plausibleanalytics'}
|
{#if service.type === 'plausibleanalytics'}
|
||||||
<PlausibleAnalytics bind:service {readOnly} />
|
<PlausibleAnalytics bind:service {readOnly} />
|
||||||
|
@ -118,7 +118,7 @@
|
|||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
<Explainer
|
<Explainer
|
||||||
text="Set the fully qualified domain name for your Coolify instance. <br>If you specify <span class='text-green-600 font-bold'>https</span>, it will be accessible only over https. <br>SSL certificate will be generated for you."
|
text="If you specify <span class='text-green-600 font-bold'>https</span>, Coolify will be accessible only over https. SSL certificate will be generated for you.<br>If you specify <span class='text-green-600 font-bold'>www</span>, Coolify will be redirected (302) from non-www and vice versa."
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user