fix: Minio urls + domain checks
This commit is contained in:
parent
b01f5f47b3
commit
6fb6a514ac
@ -0,0 +1,2 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "Minio" ADD COLUMN "apiFqdn" TEXT;
|
@ -345,6 +345,7 @@ model Minio {
|
||||
rootUser String
|
||||
rootUserPassword String
|
||||
publicPort Int?
|
||||
apiFqdn String?
|
||||
serviceId String @unique
|
||||
service Service @relation(fields: [serviceId], references: [id])
|
||||
createdAt DateTime @default(now())
|
||||
|
@ -51,10 +51,12 @@ export async function isSecretExists({
|
||||
|
||||
export async function isDomainConfigured({
|
||||
id,
|
||||
fqdn
|
||||
fqdn,
|
||||
checkOwn = false
|
||||
}: {
|
||||
id: string;
|
||||
fqdn: string;
|
||||
checkOwn?: boolean;
|
||||
}): Promise<boolean> {
|
||||
const domain = getDomain(fqdn);
|
||||
const nakedDomain = domain.replace('www.', '');
|
||||
@ -72,12 +74,15 @@ export async function isDomainConfigured({
|
||||
where: {
|
||||
OR: [
|
||||
{ fqdn: { endsWith: `//${nakedDomain}` } },
|
||||
{ fqdn: { endsWith: `//www.${nakedDomain}` } }
|
||||
{ fqdn: { endsWith: `//www.${nakedDomain}` } },
|
||||
{ minio: { apiFqdn: { endsWith: `//${nakedDomain}` } } },
|
||||
{ minio: { apiFqdn: { endsWith: `//www.${nakedDomain}` } } }
|
||||
],
|
||||
id: { not: id }
|
||||
id: { not: checkOwn ? undefined : id }
|
||||
},
|
||||
select: { fqdn: true }
|
||||
});
|
||||
|
||||
const coolifyFqdn = await prisma.setting.findFirst({
|
||||
where: {
|
||||
OR: [
|
||||
|
@ -305,12 +305,12 @@ export async function getFreePort() {
|
||||
select: { mysqlPublicPort: true }
|
||||
})
|
||||
).map((a) => a.mysqlPublicPort);
|
||||
const minioUSed = await (
|
||||
const minioUsed = await (
|
||||
await prisma.minio.findMany({
|
||||
where: { publicPort: { not: null } },
|
||||
select: { publicPort: true }
|
||||
})
|
||||
).map((a) => a.publicPort);
|
||||
const usedPorts = [...dbUsed, ...wpFtpUsed, ...wpUsed, ...minioUSed];
|
||||
const usedPorts = [...dbUsed, ...wpFtpUsed, ...wpUsed, ...minioUsed];
|
||||
return await getPort({ port: portNumbers(minPort, maxPort), exclude: usedPorts });
|
||||
}
|
||||
|
@ -360,7 +360,24 @@ export async function updateService({
|
||||
}): Promise<Service> {
|
||||
return await prisma.service.update({ where: { id }, data: { fqdn, name, exposePort } });
|
||||
}
|
||||
|
||||
export async function updateMinioService({
|
||||
id,
|
||||
fqdn,
|
||||
apiFqdn,
|
||||
exposePort,
|
||||
name
|
||||
}: {
|
||||
id: string;
|
||||
fqdn: string;
|
||||
apiFqdn: string;
|
||||
exposePort?: number;
|
||||
name: string;
|
||||
}): Promise<Service> {
|
||||
return await prisma.service.update({
|
||||
where: { id },
|
||||
data: { fqdn, name, exposePort, minio: { update: { apiFqdn } } }
|
||||
});
|
||||
}
|
||||
export async function updateFiderService({
|
||||
id,
|
||||
fqdn,
|
||||
@ -459,7 +476,7 @@ export async function updateWordpress({
|
||||
});
|
||||
}
|
||||
|
||||
export async function updateMinioService({
|
||||
export async function updateMinioServicePort({
|
||||
id,
|
||||
publicPort
|
||||
}: {
|
||||
|
@ -81,6 +81,7 @@ export default async function (): Promise<void | {
|
||||
}
|
||||
|
||||
// HTTP Proxies
|
||||
if (!settings.isTraefikUsed) {
|
||||
const minioInstances = await prisma.minio.findMany({
|
||||
where: { publicPort: { not: null } },
|
||||
include: { service: { include: { destinationDocker: true } } }
|
||||
@ -90,10 +91,6 @@ export default async function (): Promise<void | {
|
||||
const { destinationDockerId, destinationDocker, id } = service;
|
||||
if (destinationDockerId) {
|
||||
if (destinationDocker.isCoolifyProxyUsed) {
|
||||
if (settings.isTraefikUsed) {
|
||||
await stopTcpHttpProxy(id, destinationDocker, publicPort, `haproxy-for-${publicPort}`);
|
||||
await startTraefikHTTPProxy(destinationDocker, id, publicPort, 9000);
|
||||
} else {
|
||||
await stopTcpHttpProxy(id, destinationDocker, publicPort, `${id}-${publicPort}`);
|
||||
await startHttpProxy(destinationDocker, id, publicPort, 9000);
|
||||
}
|
||||
|
@ -30,7 +30,8 @@
|
||||
value={service.minio.rootUserPassword}
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
{#if !service.minio.apiFqdn}
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<label for="publicPort">{$t('forms.api_port')}</label>
|
||||
<input
|
||||
name="publicPort"
|
||||
@ -40,4 +41,5 @@
|
||||
readonly
|
||||
placeholder={$t('forms.generated_automatically_after_start')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
@ -33,6 +33,7 @@
|
||||
try {
|
||||
await post(`/services/${id}/check.json`, {
|
||||
fqdn: service.fqdn,
|
||||
otherFqdns: [service.minio.apiFqdn],
|
||||
exposePort: service.exposePort
|
||||
});
|
||||
await post(`/services/${id}/${service.type}.json`, { ...service });
|
||||
@ -89,6 +90,14 @@
|
||||
</div>
|
||||
|
||||
<div class="grid grid-flow-row gap-2">
|
||||
{#if service.type === 'minio' && !service.minio.apiFqdn && isRunning}
|
||||
<div class="text-center">
|
||||
<span class="font-bold text-red-500">IMPORTANT!</span> There was a small modification with
|
||||
Minio in the latest version of Coolify. Now you can separate the Console URL from the API URL,
|
||||
so you could use both through SSL. But this proccess cannot be done automatically, so you have
|
||||
to stop your Minio instance, configure the new domain and start it back. Sorry for any inconvenience.
|
||||
</div>
|
||||
{/if}
|
||||
<div class="mt-2 grid grid-cols-2 items-center px-10">
|
||||
<label for="name" class="text-base font-bold text-stone-100">{$t('forms.name')}</label>
|
||||
<div>
|
||||
@ -134,6 +143,41 @@
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{#if service.type === 'minio'}
|
||||
<div class="grid grid-cols-2 px-10">
|
||||
<div class="flex-col ">
|
||||
<label for="fqdn" class="pt-2 text-base font-bold text-stone-100">Console URL</label>
|
||||
</div>
|
||||
|
||||
<CopyPasswordField
|
||||
placeholder="eg: https://console.min.io"
|
||||
readonly={!$session.isAdmin && !isRunning}
|
||||
disabled={!$session.isAdmin || isRunning}
|
||||
name="fqdn"
|
||||
id="fqdn"
|
||||
pattern="^https?://([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{'{'}2,{'}'}$"
|
||||
bind:value={service.fqdn}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 px-10">
|
||||
<div class="flex-col ">
|
||||
<label for="apiFqdn" class="pt-2 text-base font-bold text-stone-100">API URL</label>
|
||||
<Explainer text={$t('application.https_explainer')} />
|
||||
</div>
|
||||
|
||||
<CopyPasswordField
|
||||
placeholder="eg: https://min.io"
|
||||
readonly={!$session.isAdmin && !isRunning}
|
||||
disabled={!$session.isAdmin || isRunning}
|
||||
name="apiFqdn"
|
||||
id="apiFqdn"
|
||||
pattern="^https?://([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{'{'}2,{'}'}$"
|
||||
bind:value={service.minio.apiFqdn}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="grid grid-cols-2 px-10">
|
||||
<div class="flex-col ">
|
||||
<label for="fqdn" class="pt-2 text-base font-bold text-stone-100"
|
||||
@ -153,6 +197,8 @@
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="grid grid-cols-2 items-center px-10">
|
||||
<Setting
|
||||
disabled={isRunning}
|
||||
|
@ -10,12 +10,14 @@ export const post: RequestHandler = async (event) => {
|
||||
if (status === 401) return { status, body };
|
||||
|
||||
const { id } = event.params;
|
||||
let { fqdn, exposePort } = await event.request.json();
|
||||
let { fqdn, exposePort, otherFqdns } = await event.request.json();
|
||||
|
||||
if (fqdn) fqdn = fqdn.toLowerCase();
|
||||
if (otherFqdns) otherFqdns = otherFqdns.map((fqdn) => fqdn.toLowerCase());
|
||||
if (exposePort) exposePort = Number(exposePort);
|
||||
|
||||
try {
|
||||
const found = await db.isDomainConfigured({ id, fqdn });
|
||||
let found = await db.isDomainConfigured({ id, fqdn });
|
||||
if (found) {
|
||||
throw {
|
||||
message: t.get('application.domain_already_in_use', {
|
||||
@ -23,6 +25,20 @@ export const post: RequestHandler = async (event) => {
|
||||
})
|
||||
};
|
||||
}
|
||||
if (otherFqdns) {
|
||||
for (const ofqdn of otherFqdns) {
|
||||
const domain = getDomain(ofqdn);
|
||||
const nakedDomain = domain.replace('www.', '');
|
||||
found = await db.isDomainConfigured({ id, fqdn: ofqdn, checkOwn: true });
|
||||
if (found) {
|
||||
throw {
|
||||
message: t.get('application.domain_already_in_use', {
|
||||
domain: nakedDomain
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
if (exposePort) {
|
||||
exposePort = Number(exposePort);
|
||||
|
||||
|
@ -9,12 +9,17 @@ export const post: RequestHandler = async (event) => {
|
||||
|
||||
const { id } = event.params;
|
||||
|
||||
let { name, fqdn, exposePort } = await event.request.json();
|
||||
let {
|
||||
name,
|
||||
fqdn,
|
||||
exposePort,
|
||||
minio: { apiFqdn }
|
||||
} = await event.request.json();
|
||||
if (fqdn) fqdn = fqdn.toLowerCase();
|
||||
if (exposePort) exposePort = Number(exposePort);
|
||||
|
||||
if (apiFqdn) apiFqdn = apiFqdn.toLowerCase();
|
||||
try {
|
||||
await db.updateService({ id, fqdn, name, exposePort });
|
||||
await db.updateMinioService({ id, fqdn, apiFqdn, name, exposePort });
|
||||
return { status: 201 };
|
||||
} catch (error) {
|
||||
return ErrorHandler(error);
|
||||
|
@ -34,7 +34,6 @@ export const post: RequestHandler = async (event) => {
|
||||
const publicPort = await getFreePort();
|
||||
|
||||
const consolePort = 9001;
|
||||
const apiPort = 9000;
|
||||
|
||||
const { workdir } = await createDirectories({ repository: type, buildId: id });
|
||||
const image = getServiceImage(type);
|
||||
@ -93,7 +92,7 @@ export const post: RequestHandler = async (event) => {
|
||||
try {
|
||||
await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} pull`);
|
||||
await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`);
|
||||
await db.updateMinioService({ id, publicPort });
|
||||
await db.updateMinioServicePort({ id, publicPort });
|
||||
return {
|
||||
status: 200
|
||||
};
|
||||
|
@ -7,7 +7,7 @@ import { checkContainer } from '$lib/haproxy';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
|
||||
function configureMiddleware(
|
||||
{ id, port, domain, nakedDomain, isHttps, isWWW, isDualCerts },
|
||||
{ id, container, port, domain, nakedDomain, isHttps, isWWW, isDualCerts },
|
||||
traefik
|
||||
) {
|
||||
if (isHttps) {
|
||||
@ -22,7 +22,7 @@ function configureMiddleware(
|
||||
loadbalancer: {
|
||||
servers: [
|
||||
{
|
||||
url: `http://${id}:${port}`
|
||||
url: `http://${container}:${port}`
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -109,7 +109,7 @@ function configureMiddleware(
|
||||
loadbalancer: {
|
||||
servers: [
|
||||
{
|
||||
url: `http://${id}:${port}`
|
||||
url: `http://${container}:${port}`
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -172,8 +172,7 @@ export const get: RequestHandler = async (event) => {
|
||||
port,
|
||||
destinationDocker,
|
||||
destinationDockerId,
|
||||
settings: { previews, dualCerts },
|
||||
updatedAt
|
||||
settings: { previews, dualCerts }
|
||||
} = application;
|
||||
if (destinationDockerId) {
|
||||
const { engine, network } = destinationDocker;
|
||||
@ -186,6 +185,7 @@ export const get: RequestHandler = async (event) => {
|
||||
if (isRunning) {
|
||||
data.applications.push({
|
||||
id,
|
||||
container: id,
|
||||
port: port || 3000,
|
||||
domain,
|
||||
nakedDomain,
|
||||
@ -208,14 +208,17 @@ export const get: RequestHandler = async (event) => {
|
||||
if (containers.length > 0) {
|
||||
for (const container of containers) {
|
||||
const previewDomain = `${container.split('-')[1]}.${domain}`;
|
||||
const nakedDomain = previewDomain.replace(/^www\./, '');
|
||||
data.applications.push({
|
||||
id: container,
|
||||
container,
|
||||
port: port || 3000,
|
||||
domain: previewDomain,
|
||||
isRunning,
|
||||
nakedDomain,
|
||||
isHttps,
|
||||
redirectTo: isWWW ? previewDomain.replace('www.', '') : 'www.' + previewDomain,
|
||||
updatedAt: updatedAt.getTime()
|
||||
isWWW,
|
||||
isDualCerts: dualCerts
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -254,8 +257,26 @@ export const get: RequestHandler = async (event) => {
|
||||
scriptName = plausibleAnalytics.scriptName;
|
||||
}
|
||||
|
||||
let container = id;
|
||||
let otherDomain = null;
|
||||
let otherNakedDomain = null;
|
||||
let otherIsHttps = null;
|
||||
let otherIsWWW = null;
|
||||
|
||||
if (type === 'minio') {
|
||||
otherDomain = getDomain(service.minio.apiFqdn);
|
||||
otherNakedDomain = otherDomain.replace(/^www\./, '');
|
||||
otherIsHttps = service.minio.apiFqdn.startsWith('https://');
|
||||
otherIsWWW = service.minio.apiFqdn.includes('www.');
|
||||
}
|
||||
data.services.push({
|
||||
id,
|
||||
container,
|
||||
type,
|
||||
otherDomain,
|
||||
otherNakedDomain,
|
||||
otherIsHttps,
|
||||
otherIsWWW,
|
||||
port,
|
||||
publicPort,
|
||||
domain,
|
||||
@ -280,6 +301,7 @@ export const get: RequestHandler = async (event) => {
|
||||
const isWWW = fqdn.includes('www.');
|
||||
data.coolify.push({
|
||||
id: dev ? 'host.docker.internal' : 'coolify',
|
||||
container: dev ? 'host.docker.internal' : 'coolify',
|
||||
port: 3000,
|
||||
domain,
|
||||
nakedDomain,
|
||||
@ -293,7 +315,18 @@ export const get: RequestHandler = async (event) => {
|
||||
}
|
||||
for (const service of data.services) {
|
||||
const { id, scriptName } = service;
|
||||
|
||||
configureMiddleware(service, traefik);
|
||||
if (service.type === 'minio') {
|
||||
service.id = id + '-minio';
|
||||
service.container = id;
|
||||
service.domain = service.otherDomain;
|
||||
service.nakedDomain = service.otherNakedDomain;
|
||||
service.isHttps = service.otherIsHttps;
|
||||
service.isWWW = service.otherIsWWW;
|
||||
service.port = 9000;
|
||||
configureMiddleware(service, traefik);
|
||||
}
|
||||
|
||||
if (scriptName) {
|
||||
traefik.http.middlewares[`${id}-redir`] = {
|
||||
|
@ -1,9 +1,6 @@
|
||||
import { dev } from '$app/env';
|
||||
import { asyncExecShell, getDomain, getEngine } from '$lib/common';
|
||||
import { supportedServiceTypesAndVersions } from '$lib/components/common';
|
||||
import { getDomain } from '$lib/common';
|
||||
import * as db from '$lib/database';
|
||||
import { listServicesWithIncludes } from '$lib/database';
|
||||
import { checkContainer } from '$lib/haproxy';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
|
||||
export const get: RequestHandler = async (event) => {
|
||||
@ -13,7 +10,7 @@ export const get: RequestHandler = async (event) => {
|
||||
const publicPort = event.url.searchParams.get('publicPort');
|
||||
const type = event.url.searchParams.get('type');
|
||||
let traefik = {};
|
||||
if (publicPort) {
|
||||
if (publicPort && type && privatePort) {
|
||||
if (type === 'tcp') {
|
||||
traefik = {
|
||||
[type]: {
|
||||
@ -34,10 +31,18 @@ export const get: RequestHandler = async (event) => {
|
||||
}
|
||||
};
|
||||
} else if (type === 'http') {
|
||||
const service = await db.prisma.service.findFirst({ where: { id } });
|
||||
if (service?.fqdn) {
|
||||
const domain = getDomain(service.fqdn);
|
||||
const isHttps = service.fqdn.startsWith('https://');
|
||||
const service = await db.prisma.service.findFirst({
|
||||
where: { id },
|
||||
include: { minio: true }
|
||||
});
|
||||
if (service) {
|
||||
if (service.type === 'minio') {
|
||||
if (service?.minio?.apiFqdn) {
|
||||
const {
|
||||
minio: { apiFqdn }
|
||||
} = service;
|
||||
const domain = getDomain(apiFqdn);
|
||||
const isHttps = apiFqdn.startsWith('https://');
|
||||
traefik = {
|
||||
[type]: {
|
||||
routers: {
|
||||
@ -70,7 +75,53 @@ export const get: RequestHandler = async (event) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (service?.fqdn) {
|
||||
const domain = getDomain(service.fqdn);
|
||||
const isHttps = service.fqdn.startsWith('https://');
|
||||
traefik = {
|
||||
[type]: {
|
||||
routers: {
|
||||
[id]: {
|
||||
entrypoints: [type],
|
||||
rule: `Host(\`${domain}:${privatePort}\`)`,
|
||||
service: id
|
||||
}
|
||||
},
|
||||
services: {
|
||||
[id]: {
|
||||
loadbalancer: {
|
||||
servers: [{ url: `http://${id}:${privatePort}` }]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
if (isHttps) {
|
||||
if (dev) {
|
||||
traefik[type].routers[id].tls = {
|
||||
domains: {
|
||||
main: `${domain}`
|
||||
}
|
||||
};
|
||||
} else {
|
||||
traefik[type].routers[id].tls = {
|
||||
certresolver: 'letsencrypt'
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
status: 500
|
||||
};
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
status: 500
|
||||
};
|
||||
}
|
||||
return {
|
||||
status: 200,
|
||||
|
Loading…
x
Reference in New Issue
Block a user