feat: custom dns servers
This commit is contained in:
parent
1bd08cb2db
commit
727133e28b
@ -0,0 +1,2 @@
|
|||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "Setting" ADD COLUMN "DNSServers" TEXT;
|
@ -20,6 +20,7 @@ model Setting {
|
|||||||
proxyHash String?
|
proxyHash String?
|
||||||
isAutoUpdateEnabled Boolean @default(false)
|
isAutoUpdateEnabled Boolean @default(false)
|
||||||
isDNSCheckEnabled Boolean @default(true)
|
isDNSCheckEnabled Boolean @default(true)
|
||||||
|
DNSServers String?
|
||||||
isTraefikUsed Boolean @default(true)
|
isTraefikUsed Boolean @default(true)
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
|
@ -307,6 +307,10 @@ export async function checkDoubleBranch(branch: string, projectId: number): Prom
|
|||||||
}
|
}
|
||||||
export async function isDNSValid(hostname: any, domain: string): Promise<any> {
|
export async function isDNSValid(hostname: any, domain: string): Promise<any> {
|
||||||
const { isIP } = await import('is-ip');
|
const { isIP } = await import('is-ip');
|
||||||
|
const { DNSServers } = await listSettings();
|
||||||
|
if (DNSServers) {
|
||||||
|
dns.setServers([DNSServers]);
|
||||||
|
}
|
||||||
let resolves = [];
|
let resolves = [];
|
||||||
try {
|
try {
|
||||||
if (isIP(hostname)) {
|
if (isIP(hostname)) {
|
||||||
@ -320,7 +324,6 @@ export async function isDNSValid(hostname: any, domain: string): Promise<any> {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
let ipDomainFound = false;
|
let ipDomainFound = false;
|
||||||
dns.setServers(['1.1.1.1', '8.8.8.8']);
|
|
||||||
const dnsResolve = await dns.resolve4(domain);
|
const dnsResolve = await dns.resolve4(domain);
|
||||||
if (dnsResolve.length > 0) {
|
if (dnsResolve.length > 0) {
|
||||||
for (const ip of dnsResolve) {
|
for (const ip of dnsResolve) {
|
||||||
@ -412,7 +415,12 @@ export async function checkDomainsIsValidInDNS({ hostname, fqdn, dualCerts }): P
|
|||||||
const { isIP } = await import('is-ip');
|
const { isIP } = await import('is-ip');
|
||||||
const domain = getDomain(fqdn);
|
const domain = getDomain(fqdn);
|
||||||
const domainDualCert = domain.includes('www.') ? domain.replace('www.', '') : `www.${domain}`;
|
const domainDualCert = domain.includes('www.') ? domain.replace('www.', '') : `www.${domain}`;
|
||||||
dns.setServers(['1.1.1.1', '8.8.8.8']);
|
|
||||||
|
const { DNSServers } = await listSettings();
|
||||||
|
if (DNSServers) {
|
||||||
|
dns.setServers([DNSServers]);
|
||||||
|
}
|
||||||
|
|
||||||
let resolves = [];
|
let resolves = [];
|
||||||
try {
|
try {
|
||||||
if (isIP(hostname)) {
|
if (isIP(hostname)) {
|
||||||
|
@ -18,7 +18,7 @@ export async function listApplications(request: FastifyRequest) {
|
|||||||
const { teamId } = request.user
|
const { teamId } = request.user
|
||||||
const applications = await prisma.application.findMany({
|
const applications = await prisma.application.findMany({
|
||||||
where: { teams: { some: { id: teamId === '0' ? undefined : teamId } } },
|
where: { teams: { some: { id: teamId === '0' ? undefined : teamId } } },
|
||||||
include: { teams: true, destinationDocker: true }
|
include: { teams: true, destinationDocker: true, settings: true }
|
||||||
});
|
});
|
||||||
const settings = await prisma.setting.findFirst()
|
const settings = await prisma.setting.findFirst()
|
||||||
return {
|
return {
|
||||||
|
@ -4,7 +4,7 @@ import axios from 'axios';
|
|||||||
import compare from 'compare-versions';
|
import compare from 'compare-versions';
|
||||||
import cuid from 'cuid';
|
import cuid from 'cuid';
|
||||||
import bcrypt from 'bcryptjs';
|
import bcrypt from 'bcryptjs';
|
||||||
import { asyncExecShell, asyncSleep, cleanupDockerStorage, errorHandler, isDev, prisma, uniqueName, version } from '../../../lib/common';
|
import { asyncExecShell, asyncSleep, cleanupDockerStorage, errorHandler, isDev, listSettings, prisma, uniqueName, version } from '../../../lib/common';
|
||||||
|
|
||||||
import type { FastifyReply, FastifyRequest } from 'fastify';
|
import type { FastifyReply, FastifyRequest } from 'fastify';
|
||||||
import type { Login, Update } from '.';
|
import type { Login, Update } from '.';
|
||||||
@ -97,7 +97,8 @@ export async function showDashboard(request: FastifyRequest) {
|
|||||||
const userId = request.user.userId;
|
const userId = request.user.userId;
|
||||||
const teamId = request.user.teamId;
|
const teamId = request.user.teamId;
|
||||||
const applications = await prisma.application.findMany({
|
const applications = await prisma.application.findMany({
|
||||||
where: { teams: { some: { id: teamId === '0' ? undefined : teamId } } }
|
where: { teams: { some: { id: teamId === '0' ? undefined : teamId } } },
|
||||||
|
include: { settings: true }
|
||||||
});
|
});
|
||||||
const databases = await prisma.database.findMany({
|
const databases = await prisma.database.findMany({
|
||||||
where: { teams: { some: { id: teamId === '0' ? undefined : teamId } } }
|
where: { teams: { some: { id: teamId === '0' ? undefined : teamId } } }
|
||||||
@ -105,10 +106,12 @@ export async function showDashboard(request: FastifyRequest) {
|
|||||||
const services = await prisma.service.findMany({
|
const services = await prisma.service.findMany({
|
||||||
where: { teams: { some: { id: teamId === '0' ? undefined : teamId } } }
|
where: { teams: { some: { id: teamId === '0' ? undefined : teamId } } }
|
||||||
});
|
});
|
||||||
|
const settings = await listSettings();
|
||||||
return {
|
return {
|
||||||
applications,
|
applications,
|
||||||
databases,
|
databases,
|
||||||
services,
|
services,
|
||||||
|
settings,
|
||||||
};
|
};
|
||||||
} catch ({ status, message }) {
|
} catch ({ status, message }) {
|
||||||
return errorHandler({ status, message })
|
return errorHandler({ status, message })
|
||||||
|
@ -33,12 +33,13 @@ export async function saveSettings(request: FastifyRequest<SaveSettings>, reply:
|
|||||||
minPort,
|
minPort,
|
||||||
maxPort,
|
maxPort,
|
||||||
isAutoUpdateEnabled,
|
isAutoUpdateEnabled,
|
||||||
isDNSCheckEnabled
|
isDNSCheckEnabled,
|
||||||
|
DNSServers
|
||||||
} = request.body
|
} = request.body
|
||||||
const { id } = await listSettings();
|
const { id } = await listSettings();
|
||||||
await prisma.setting.update({
|
await prisma.setting.update({
|
||||||
where: { id },
|
where: { id },
|
||||||
data: { isRegistrationEnabled, dualCerts, isAutoUpdateEnabled, isDNSCheckEnabled }
|
data: { isRegistrationEnabled, dualCerts, isAutoUpdateEnabled, isDNSCheckEnabled, DNSServers }
|
||||||
});
|
});
|
||||||
if (fqdn) {
|
if (fqdn) {
|
||||||
await prisma.setting.update({ where: { id }, data: { fqdn } });
|
await prisma.setting.update({ where: { id }, data: { fqdn } });
|
||||||
@ -54,6 +55,10 @@ export async function saveSettings(request: FastifyRequest<SaveSettings>, reply:
|
|||||||
export async function deleteDomain(request: FastifyRequest<DeleteDomain>, reply: FastifyReply) {
|
export async function deleteDomain(request: FastifyRequest<DeleteDomain>, reply: FastifyReply) {
|
||||||
try {
|
try {
|
||||||
const { fqdn } = request.body
|
const { fqdn } = request.body
|
||||||
|
const { DNSServers } = await listSettings();
|
||||||
|
if (DNSServers) {
|
||||||
|
dns.setServers([DNSServers]);
|
||||||
|
}
|
||||||
let ip;
|
let ip;
|
||||||
try {
|
try {
|
||||||
ip = await dns.resolve(fqdn);
|
ip = await dns.resolve(fqdn);
|
||||||
|
@ -8,7 +8,8 @@ export interface SaveSettings {
|
|||||||
minPort: number,
|
minPort: number,
|
||||||
maxPort: number,
|
maxPort: number,
|
||||||
isAutoUpdateEnabled: boolean,
|
isAutoUpdateEnabled: boolean,
|
||||||
isDNSCheckEnabled: boolean
|
isDNSCheckEnabled: boolean,
|
||||||
|
DNSServers: string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export interface DeleteDomain {
|
export interface DeleteDomain {
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { dev } from '$app/env';
|
||||||
import cuid from 'cuid';
|
import cuid from 'cuid';
|
||||||
import { writable, readable, type Writable } from 'svelte/store';
|
import { writable, readable, type Writable } from 'svelte/store';
|
||||||
|
|
||||||
@ -73,7 +74,7 @@ export const location: Writable<null | string> = writable(null)
|
|||||||
export const setLocation = (resource: any, settings?: any) => {
|
export const setLocation = (resource: any, settings?: any) => {
|
||||||
if (resource.settings.isBot && resource.exposePort) {
|
if (resource.settings.isBot && resource.exposePort) {
|
||||||
disabledButton.set(false);
|
disabledButton.set(false);
|
||||||
return location.set(`http://${settings.ipv4}:${resource.exposePort}`)
|
return location.set(`http://${dev ? 'localhost' : settings.ipv4}:${resource.exposePort}`)
|
||||||
}
|
}
|
||||||
if (GITPOD_WORKSPACE_URL && resource.exposePort) {
|
if (GITPOD_WORKSPACE_URL && resource.exposePort) {
|
||||||
const { href } = new URL(GITPOD_WORKSPACE_URL);
|
const { href } = new URL(GITPOD_WORKSPACE_URL);
|
||||||
|
@ -141,8 +141,8 @@
|
|||||||
if (
|
if (
|
||||||
application.gitSourceId &&
|
application.gitSourceId &&
|
||||||
application.destinationDockerId &&
|
application.destinationDockerId &&
|
||||||
application.fqdn &&
|
(application.fqdn ||
|
||||||
!application.settings.isBot
|
application.settings.isBot)
|
||||||
) {
|
) {
|
||||||
await getStatus();
|
await getStatus();
|
||||||
statusInterval = setInterval(async () => {
|
statusInterval = setInterval(async () => {
|
||||||
@ -409,6 +409,7 @@
|
|||||||
</svg>
|
</svg>
|
||||||
</button></a
|
</button></a
|
||||||
>
|
>
|
||||||
|
{#if !application.settings.isBot}
|
||||||
<a
|
<a
|
||||||
href={!$disabledButton ? `/applications/${id}/previews` : null}
|
href={!$disabledButton ? `/applications/${id}/previews` : null}
|
||||||
sveltekit:prefetch
|
sveltekit:prefetch
|
||||||
@ -440,6 +441,7 @@
|
|||||||
</svg></button
|
</svg></button
|
||||||
></a
|
></a
|
||||||
>
|
>
|
||||||
|
{/if}
|
||||||
<div class="border border-coolgray-500 h-8" />
|
<div class="border border-coolgray-500 h-8" />
|
||||||
<a
|
<a
|
||||||
href={!$disabledButton && $status.application.isRunning ? `/applications/${id}/logs` : null}
|
href={!$disabledButton && $status.application.isRunning ? `/applications/${id}/logs` : null}
|
||||||
|
@ -779,6 +779,7 @@
|
|||||||
description={$t('application.enable_auto_deploy_webhooks')}
|
description={$t('application.enable_auto_deploy_webhooks')}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
{#if !application.settings.isBot}
|
||||||
<div class="grid grid-cols-2 items-center">
|
<div class="grid grid-cols-2 items-center">
|
||||||
<Setting
|
<Setting
|
||||||
isCenter={false}
|
isCenter={false}
|
||||||
@ -788,6 +789,7 @@
|
|||||||
description={$t('application.enable_preview_deploy_mr_pr_requests')}
|
description={$t('application.enable_preview_deploy_mr_pr_requests')}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
{/if}
|
||||||
<div class="grid grid-cols-2 items-center">
|
<div class="grid grid-cols-2 items-center">
|
||||||
<Setting
|
<Setting
|
||||||
isCenter={false}
|
isCenter={false}
|
||||||
|
@ -98,7 +98,7 @@
|
|||||||
<div class="truncate text-center font-bold text-red-500 group-hover:text-white">
|
<div class="truncate text-center font-bold text-red-500 group-hover:text-white">
|
||||||
Destination Missing
|
Destination Missing
|
||||||
</div>
|
</div>
|
||||||
{:else if !application.fqdn}
|
{:else if !application.fqdn && !application.settings.isBot}
|
||||||
<div class="truncate text-center font-bold text-red-500 group-hover:text-white">
|
<div class="truncate text-center font-bold text-red-500 group-hover:text-white">
|
||||||
URL Missing
|
URL Missing
|
||||||
</div>
|
</div>
|
||||||
|
@ -20,6 +20,11 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
export let applications: any;
|
||||||
|
export let databases: any;
|
||||||
|
export let services: any;
|
||||||
|
export let settings: any;
|
||||||
|
|
||||||
import { get, post } from '$lib/api';
|
import { get, post } from '$lib/api';
|
||||||
import Usage from '$lib/components/Usage.svelte';
|
import Usage from '$lib/components/Usage.svelte';
|
||||||
import { t } from '$lib/translations';
|
import { t } from '$lib/translations';
|
||||||
@ -29,23 +34,21 @@
|
|||||||
import ApplicationsIcons from '$lib/components/svg/applications/ApplicationIcons.svelte';
|
import ApplicationsIcons from '$lib/components/svg/applications/ApplicationIcons.svelte';
|
||||||
import DatabaseIcons from '$lib/components/svg/databases/DatabaseIcons.svelte';
|
import DatabaseIcons from '$lib/components/svg/databases/DatabaseIcons.svelte';
|
||||||
import ServiceIcons from '$lib/components/svg/services/ServiceIcons.svelte';
|
import ServiceIcons from '$lib/components/svg/services/ServiceIcons.svelte';
|
||||||
|
import { dev } from '$app/env';
|
||||||
|
|
||||||
let loading = {
|
let loading = {
|
||||||
cleanup: false
|
cleanup: false
|
||||||
};
|
};
|
||||||
|
|
||||||
export let applications: any;
|
|
||||||
export let databases: any;
|
|
||||||
export let services: any;
|
|
||||||
let numberOfGetStatus = 0;
|
let numberOfGetStatus = 0;
|
||||||
|
|
||||||
function getRndInteger(min: number, max: number) {
|
function getRndInteger(min: number, max: number) {
|
||||||
return Math.floor(Math.random() * (max - min + 1) ) + min;
|
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getStatus(resources: any) {
|
async function getStatus(resources: any) {
|
||||||
while (numberOfGetStatus > 1){
|
while (numberOfGetStatus > 1) {
|
||||||
await asyncSleep(getRndInteger(100,200));
|
await asyncSleep(getRndInteger(100, 200));
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
numberOfGetStatus++;
|
numberOfGetStatus++;
|
||||||
@ -121,8 +124,13 @@
|
|||||||
<ApplicationsIcons {application} isAbsolute={false} />
|
<ApplicationsIcons {application} isAbsolute={false} />
|
||||||
</td>
|
</td>
|
||||||
<td class="px-10">
|
<td class="px-10">
|
||||||
<div class="badge badge-outline text-xs border-applications rounded text-white">
|
<div
|
||||||
|
class="badge badge-outline text-xs border-applications rounded text-white"
|
||||||
|
>
|
||||||
Application
|
Application
|
||||||
|
{#if application.settings.isBot}
|
||||||
|
| BOT
|
||||||
|
{/if}
|
||||||
</div></td
|
</div></td
|
||||||
>
|
>
|
||||||
<td class="flex justify-end">
|
<td class="flex justify-end">
|
||||||
@ -148,6 +156,30 @@
|
|||||||
</svg></a
|
</svg></a
|
||||||
>
|
>
|
||||||
{/if}
|
{/if}
|
||||||
|
{#if application.settings.isBot && application.exposePort}
|
||||||
|
<a
|
||||||
|
href={`http://${dev ? 'localhost' : settings.ipv4}:${
|
||||||
|
application.exposePort
|
||||||
|
}`}
|
||||||
|
target="_blank"
|
||||||
|
class="icons bg-transparent text-sm inline-flex"
|
||||||
|
><svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
class="h-6 w-6"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke-width="1.5"
|
||||||
|
stroke="currentColor"
|
||||||
|
fill="none"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
>
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||||
|
<path d="M11 7h-5a2 2 0 0 0 -2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2 -2v-5" />
|
||||||
|
<line x1="10" y1="14" x2="20" y2="4" />
|
||||||
|
<polyline points="15 4 20 4 20 9" />
|
||||||
|
</svg></a
|
||||||
|
>
|
||||||
|
{/if}
|
||||||
<a
|
<a
|
||||||
href={`/applications/${application.id}`}
|
href={`/applications/${application.id}`}
|
||||||
class="icons bg-transparent text-sm inline-flex"
|
class="icons bg-transparent text-sm inline-flex"
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
let dualCerts = settings.dualCerts;
|
let dualCerts = settings.dualCerts;
|
||||||
let isAutoUpdateEnabled = settings.isAutoUpdateEnabled;
|
let isAutoUpdateEnabled = settings.isAutoUpdateEnabled;
|
||||||
let isDNSCheckEnabled = settings.isDNSCheckEnabled;
|
let isDNSCheckEnabled = settings.isDNSCheckEnabled;
|
||||||
|
let DNSServers = settings.DNSServers;
|
||||||
let minPort = settings.minPort;
|
let minPort = settings.minPort;
|
||||||
let maxPort = settings.maxPort;
|
let maxPort = settings.maxPort;
|
||||||
|
|
||||||
@ -105,6 +105,10 @@
|
|||||||
settings.minPort = minPort;
|
settings.minPort = minPort;
|
||||||
settings.maxPort = maxPort;
|
settings.maxPort = maxPort;
|
||||||
}
|
}
|
||||||
|
if (DNSServers !== settings.DNSServers) {
|
||||||
|
await post(`/settings`, { DNSServers });
|
||||||
|
settings.DNSServers = DNSServers;
|
||||||
|
}
|
||||||
forceSave = false;
|
forceSave = false;
|
||||||
return addToast({
|
return addToast({
|
||||||
message: 'Configuration saved.',
|
message: 'Configuration saved.',
|
||||||
@ -275,6 +279,17 @@
|
|||||||
on:click={() => changeSettings('isDNSCheckEnabled')}
|
on:click={() => changeSettings('isDNSCheckEnabled')}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="grid grid-cols-2 items-center">
|
||||||
|
<div class="flex-col">
|
||||||
|
<div class="pt-2 text-base font-bold text-stone-100">
|
||||||
|
Custom DNS servers
|
||||||
|
</div>
|
||||||
|
<Explainer text="You can specify a custom DNS server to verify your domains all over Coolify.<br><br>By default, the OS defined DNS servers are used." />
|
||||||
|
</div>
|
||||||
|
<div class="mx-auto flex-row items-center justify-center space-y-2">
|
||||||
|
<input placeholder="1.1.1.1,8.8.8.8" bind:value={DNSServers} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="grid grid-cols-2 items-center">
|
<div class="grid grid-cols-2 items-center">
|
||||||
<Setting
|
<Setting
|
||||||
dataTooltip={$t('setting.must_remove_domain_before_changing')}
|
dataTooltip={$t('setting.must_remove_domain_before_changing')}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user