feat: redirect catch-all rule

This commit is contained in:
Andras Bacsai 2022-11-04 10:50:16 +01:00
parent bf33d6c34e
commit 13c1734753
7 changed files with 68 additions and 10 deletions

View File

@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "Setting" ADD COLUMN "proxyDefaultRedirect" TEXT;

View File

@ -29,6 +29,7 @@ model Setting {
proxyPassword String
proxyUser String
proxyHash String?
proxyDefaultRedirect String?
isAutoUpdateEnabled Boolean @default(false)
isDNSCheckEnabled Boolean @default(true)
DNSServers String?

View File

@ -111,12 +111,13 @@ const host = '0.0.0.0';
fastify.register(cors);
fastify.register(socketIO, {
cors: {
origin: "http://localhost:3000"
origin: isDev ? "*" : ''
}
})
// To detect allowed origins
// fastify.addHook('onRequest', async (request, reply) => {
// console.log(request.headers.host)
// let allowedList = ['coolify:3000'];
// const { ipv4, ipv6, fqdn } = await prisma.setting.findFirst({})

View File

@ -44,16 +44,18 @@ export async function saveSettings(request: FastifyRequest<SaveSettings>, reply:
maxPort,
isAutoUpdateEnabled,
isDNSCheckEnabled,
DNSServers
DNSServers,
proxyDefaultRedirect
} = request.body
const { id } = await listSettings();
await prisma.setting.update({
where: { id },
data: { isRegistrationEnabled, dualCerts, isAutoUpdateEnabled, isDNSCheckEnabled, DNSServers, isAPIDebuggingEnabled }
data: { isRegistrationEnabled, dualCerts, isAutoUpdateEnabled, isDNSCheckEnabled, DNSServers, isAPIDebuggingEnabled, }
});
if (fqdn) {
await prisma.setting.update({ where: { id }, data: { fqdn } });
}
await prisma.setting.update({ where: { id }, data: { proxyDefaultRedirect } });
if (minPort && maxPort) {
await prisma.setting.update({ where: { id }, data: { minPort, maxPort } });
}

View File

@ -10,7 +10,8 @@ export interface SaveSettings {
maxPort: number,
isAutoUpdateEnabled: boolean,
isDNSCheckEnabled: boolean,
DNSServers: string
DNSServers: string,
proxyDefaultRedirect: string
}
}
export interface DeleteDomain {

View File

@ -20,12 +20,14 @@ function generateRouters(id, domain, nakedDomain, pathPrefix, isHttps, isWWW, is
entrypoints: ['web'],
rule: `Host(\`${nakedDomain}\`)${pathPrefix ? ` && PathPrefix(\`${pathPrefix}\`)` : ''}`,
service: `${id}`,
priority: 2,
middlewares: []
}
let https: any = {
entrypoints: ['websecure'],
rule: `Host(\`${nakedDomain}\`)${pathPrefix ? ` && PathPrefix(\`${pathPrefix}\`)` : ''}`,
service: `${id}`,
priority: 2,
tls: {
certresolver: 'letsencrypt'
},
@ -35,12 +37,14 @@ function generateRouters(id, domain, nakedDomain, pathPrefix, isHttps, isWWW, is
entrypoints: ['web'],
rule: `Host(\`www.${nakedDomain}\`)${pathPrefix ? ` && PathPrefix(\`${pathPrefix}\`)` : ''}`,
service: `${id}`,
priority: 2,
middlewares: []
}
let httpsWWW: any = {
entrypoints: ['websecure'],
rule: `Host(\`www.${nakedDomain}\`)${pathPrefix ? ` && PathPrefix(\`${pathPrefix}\`)` : ''}`,
service: `${id}`,
priority: 2,
tls: {
certresolver: 'letsencrypt'
},
@ -54,6 +58,7 @@ function generateRouters(id, domain, nakedDomain, pathPrefix, isHttps, isWWW, is
httpWWW.middlewares.push('redirect-to-non-www');
httpsWWW.middlewares.push('redirect-to-non-www');
delete https.tls
delete httpsWWW.tls
}
// 3. http + www only
@ -64,6 +69,7 @@ function generateRouters(id, domain, nakedDomain, pathPrefix, isHttps, isWWW, is
http.middlewares.push('redirect-to-www');
https.middlewares.push('redirect-to-www');
delete https.tls
delete httpsWWW.tls
}
// 5. https + non-www only
if (isHttps && !isWWW) {
@ -164,6 +170,32 @@ export async function proxyConfiguration(request: FastifyRequest<OnlyId>, remote
};
try {
const { id = null } = request.params;
const settings = await prisma.setting.findFirst();
if (settings.isTraefikUsed && settings.proxyDefaultRedirect) {
traefik.http.routers['catchall'] = {
entrypoints: ["web"],
rule: "HostRegexp(`{catchall:.*}`)",
service: "noop",
priority: 1,
middlewares: ["redirect-regexp"]
}
traefik.http.middlewares['redirect-regexp'] = {
redirectregex: {
regex: '(.*)',
replacement: settings.proxyDefaultRedirect,
permanent: false
}
}
traefik.http.services['noop'] = {
loadBalancer: {
servers: [
{
url: ''
}
]
}
}
}
const sslpath = '/etc/traefik/acme/custom';
let certificates = await prisma.certificate.findMany({ where: { team: { applications: { some: { settings: { isCustomSSL: true } } }, destinationDocker: { some: { remoteEngine: false, isCoolifyProxyUsed: true } } } } })
@ -306,7 +338,7 @@ export async function proxyConfiguration(request: FastifyRequest<OnlyId>, remote
const port = 3000
const pathPrefix = '/'
const isCustomSSL = false
traefik.http.routers = { ...traefik.http.routers, ...generateRouters(`${id}-${port || 'default'}`, domain, nakedDomain, pathPrefix, isHttps, isWWW, dualCerts, isCustomSSL) }
traefik.http.services = { ...traefik.http.services, ...generateServices(id, container, port) }
}

View File

@ -18,16 +18,12 @@
<script lang="ts">
export let settings: any;
export let certificates: any;
import Setting from '$lib/components/Setting.svelte';
import { del, get, post } from '$lib/api';
import { browser } from '$app/env';
import { t } from '$lib/translations';
import { addToast, appSession, features } from '$lib/store';
import { asyncSleep, errorNotification, getDomain } from '$lib/common';
import Menu from './_Menu.svelte';
import Explainer from '$lib/components/Explainer.svelte';
import Upload from '$lib/components/Upload.svelte';
let isAPIDebuggingEnabled = settings.isAPIDebuggingEnabled;
let isRegistrationEnabled = settings.isRegistrationEnabled;
@ -37,6 +33,7 @@
let DNSServers = settings.DNSServers;
let minPort = settings.minPort;
let maxPort = settings.maxPort;
let proxyDefaultRedirect = settings.proxyDefaultRedirect;
let forceSave = false;
let fqdn = settings.fqdn;
@ -107,6 +104,9 @@
await post(`/settings`, { fqdn });
return window.location.reload();
}
if (proxyDefaultRedirect !== settings.proxyDefaultRedirect) {
await post(`/settings`, { proxyDefaultRedirect });
}
if (minPort !== settings.minPort || maxPort !== settings.maxPort) {
await post(`/settings`, { minPort, maxPort });
settings.minPort = minPort;
@ -228,7 +228,7 @@
</div>
</div>
<div class="flex lg:flex-row flex-col">
<div class="grid grid-flow-row gap-2 px-4 pr-5">
<div class="grid grid-flow-row gap-2 px-4 pr-5">
<div class="grid grid-cols-2 items-center">
<div>
{$t('application.url_fqdn')}
@ -281,6 +281,25 @@
</div>
{/if}
</div>
<div class="grid grid-cols-2 items-center">
<div>
Default Redirect URL
<Explainer
position="dropdown-bottom"
explanation="You can specify where to redirect all requests that does not have a running resource."
/>
</div>
<input
class="w-full"
bind:value={proxyDefaultRedirect}
readonly={!$appSession.isAdmin}
disabled={!$appSession.isAdmin}
name="proxyDefaultRedirect"
id="proxyDefaultRedirect"
pattern="^https?://([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{'{'}2,{'}'}$"
placeholder="{$t('forms.eg')}: https://coolify.io"
/>
</div>
<div class="grid grid-cols-2 items-center">
<Setting
id="dualCerts"