mirror of
https://github.com/ershisan99/coolify.git
synced 2025-12-18 12:33:06 +00:00
feat: WP could have custom db
This commit is contained in:
@@ -0,0 +1,32 @@
|
|||||||
|
-- RedefineTables
|
||||||
|
PRAGMA foreign_keys=OFF;
|
||||||
|
CREATE TABLE "new_Wordpress" (
|
||||||
|
"id" TEXT NOT NULL PRIMARY KEY,
|
||||||
|
"extraConfig" TEXT,
|
||||||
|
"tablePrefix" TEXT,
|
||||||
|
"ownMysql" BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
"mysqlHost" TEXT,
|
||||||
|
"mysqlPort" INTEGER,
|
||||||
|
"mysqlUser" TEXT NOT NULL,
|
||||||
|
"mysqlPassword" TEXT NOT NULL,
|
||||||
|
"mysqlRootUser" TEXT NOT NULL,
|
||||||
|
"mysqlRootUserPassword" TEXT NOT NULL,
|
||||||
|
"mysqlDatabase" TEXT,
|
||||||
|
"mysqlPublicPort" INTEGER,
|
||||||
|
"ftpEnabled" BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
"ftpUser" TEXT,
|
||||||
|
"ftpPassword" TEXT,
|
||||||
|
"ftpPublicPort" INTEGER,
|
||||||
|
"ftpHostKey" TEXT,
|
||||||
|
"ftpHostKeyPrivate" TEXT,
|
||||||
|
"serviceId" TEXT NOT NULL,
|
||||||
|
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" DATETIME NOT NULL,
|
||||||
|
CONSTRAINT "Wordpress_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "Service" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
INSERT INTO "new_Wordpress" ("createdAt", "extraConfig", "ftpEnabled", "ftpHostKey", "ftpHostKeyPrivate", "ftpPassword", "ftpPublicPort", "ftpUser", "id", "mysqlDatabase", "mysqlPassword", "mysqlPublicPort", "mysqlRootUser", "mysqlRootUserPassword", "mysqlUser", "serviceId", "tablePrefix", "updatedAt") SELECT "createdAt", "extraConfig", "ftpEnabled", "ftpHostKey", "ftpHostKeyPrivate", "ftpPassword", "ftpPublicPort", "ftpUser", "id", "mysqlDatabase", "mysqlPassword", "mysqlPublicPort", "mysqlRootUser", "mysqlRootUserPassword", "mysqlUser", "serviceId", "tablePrefix", "updatedAt" FROM "Wordpress";
|
||||||
|
DROP TABLE "Wordpress";
|
||||||
|
ALTER TABLE "new_Wordpress" RENAME TO "Wordpress";
|
||||||
|
CREATE UNIQUE INDEX "Wordpress_serviceId_key" ON "Wordpress"("serviceId");
|
||||||
|
PRAGMA foreign_key_check;
|
||||||
|
PRAGMA foreign_keys=ON;
|
||||||
@@ -353,6 +353,9 @@ model Wordpress {
|
|||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
extraConfig String?
|
extraConfig String?
|
||||||
tablePrefix String?
|
tablePrefix String?
|
||||||
|
ownMysql Boolean @default(false)
|
||||||
|
mysqlHost String?
|
||||||
|
mysqlPort Int?
|
||||||
mysqlUser String
|
mysqlUser String
|
||||||
mysqlPassword String
|
mysqlPassword String
|
||||||
mysqlRootUser String
|
mysqlRootUser String
|
||||||
|
|||||||
@@ -4,6 +4,6 @@
|
|||||||
|
|
||||||
<img
|
<img
|
||||||
alt="plausible logo"
|
alt="plausible logo"
|
||||||
class={isAbsolute ? 'w-10 absolute top-0 left-0 -m-5' : 'w-6 mx-auto'}
|
class={isAbsolute ? 'w-9 absolute top-0 left-0 -m-4' : 'w-6 mx-auto'}
|
||||||
src="/plausible.png"
|
src="/plausible.png"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ if (!dev) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const prisma = new PrismaClient({
|
export const prisma = new PrismaClient({
|
||||||
errorFormat: 'pretty',
|
errorFormat: 'minimal',
|
||||||
rejectOnNotFound: false
|
rejectOnNotFound: false
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -419,7 +419,9 @@ export async function updateWordpress({
|
|||||||
name,
|
name,
|
||||||
exposePort,
|
exposePort,
|
||||||
mysqlDatabase,
|
mysqlDatabase,
|
||||||
extraConfig
|
extraConfig,
|
||||||
|
mysqlHost,
|
||||||
|
mysqlPort
|
||||||
}: {
|
}: {
|
||||||
id: string;
|
id: string;
|
||||||
fqdn: string;
|
fqdn: string;
|
||||||
@@ -427,10 +429,24 @@ export async function updateWordpress({
|
|||||||
exposePort?: number;
|
exposePort?: number;
|
||||||
mysqlDatabase: string;
|
mysqlDatabase: string;
|
||||||
extraConfig: string;
|
extraConfig: string;
|
||||||
|
mysqlHost?: string;
|
||||||
|
mysqlPort?: number;
|
||||||
}): Promise<Service> {
|
}): Promise<Service> {
|
||||||
return await prisma.service.update({
|
return await prisma.service.update({
|
||||||
where: { id },
|
where: { id },
|
||||||
data: { fqdn, name, exposePort, wordpress: { update: { mysqlDatabase, extraConfig } } }
|
data: {
|
||||||
|
fqdn,
|
||||||
|
name,
|
||||||
|
exposePort,
|
||||||
|
wordpress: {
|
||||||
|
update: {
|
||||||
|
mysqlDatabase,
|
||||||
|
extraConfig,
|
||||||
|
mysqlHost,
|
||||||
|
mysqlPort
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -60,7 +60,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col flex-wrap justify-center">
|
<div class="flex justify-center">
|
||||||
{#if !applications || ownApplications.length === 0}
|
{#if !applications || ownApplications.length === 0}
|
||||||
<div class="flex-col">
|
<div class="flex-col">
|
||||||
<div class="text-center text-xl font-bold">{$t('application.no_applications_found')}</div>
|
<div class="text-center text-xl font-bold">{$t('application.no_applications_found')}</div>
|
||||||
|
|||||||
@@ -47,7 +47,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-col flex-wrap justify-center">
|
<div class="flex justify-center">
|
||||||
{#if !databases || ownDatabases.length === 0}
|
{#if !databases || ownDatabases.length === 0}
|
||||||
<div class="flex-col">
|
<div class="flex-col">
|
||||||
<div class="text-center text-xl font-bold">{$t('database.no_databases_found')}</div>
|
<div class="text-center text-xl font-bold">{$t('database.no_databases_found')}</div>
|
||||||
|
|||||||
@@ -39,10 +39,13 @@
|
|||||||
import { t } from '$lib/translations';
|
import { t } from '$lib/translations';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex space-x-1 p-6 text-2xl font-bold">
|
<div class="flex h-20 items-center space-x-2 p-5 px-6 font-bold">
|
||||||
<div class="tracking-tight">{$t('application.destination')}</div>
|
<div class="-mb-5 flex-col">
|
||||||
<span class="arrow-right-applications px-1">></span>
|
<div class="md:max-w-64 truncate text-base tracking-tight md:text-2xl lg:block">
|
||||||
<span class="pr-2">{destination.name}</span>
|
Configuration
|
||||||
|
</div>
|
||||||
|
<span class="text-xs">{destination.name}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mx-auto max-w-4xl px-6">
|
<div class="mx-auto max-w-4xl px-6">
|
||||||
|
|||||||
@@ -141,21 +141,21 @@
|
|||||||
<div class="title font-bold">Server Usage</div>
|
<div class="title font-bold">Server Usage</div>
|
||||||
<dl class="relative mt-5 grid grid-cols-1 gap-5 sm:grid-cols-3">
|
<dl class="relative mt-5 grid grid-cols-1 gap-5 sm:grid-cols-3">
|
||||||
<Loading />
|
<Loading />
|
||||||
<div class="overflow-hidden rounded-lg px-4 py-5 sm:p-6">
|
<div class="overflow-hidden rounded px-4 py-5 sm:p-6">
|
||||||
<dt class="truncate text-sm font-medium text-white">Total Memory</dt>
|
<dt class="truncate text-sm font-medium text-white">Total Memory</dt>
|
||||||
<dd class="mt-1 text-3xl font-semibold text-white">
|
<dd class="mt-1 text-3xl font-semibold text-white">
|
||||||
{(usage?.memory.totalMemMb).toFixed(0)}
|
{(usage?.memory.totalMemMb).toFixed(0)}
|
||||||
</dd>
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="overflow-hidden rounded-lg px-4 py-5 sm:p-6">
|
<div class="overflow-hidden rounded px-4 py-5 sm:p-6">
|
||||||
<dt class="truncate text-sm font-medium text-white">Used Memory</dt>
|
<dt class="truncate text-sm font-medium text-white">Used Memory</dt>
|
||||||
<dd class="mt-1 text-3xl font-semibold text-white ">
|
<dd class="mt-1 text-3xl font-semibold text-white ">
|
||||||
{(usage?.memory.usedMemMb).toFixed(0)}
|
{(usage?.memory.usedMemMb).toFixed(0)}
|
||||||
</dd>
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="overflow-hidden rounded-lg px-4 py-5 sm:p-6" class:bg-red-500={memoryWarning}>
|
<div class="overflow-hidden rounded px-4 py-5 sm:p-6" class:bg-red-500={memoryWarning}>
|
||||||
<dt class="truncate text-sm font-medium text-white">Free Memory</dt>
|
<dt class="truncate text-sm font-medium text-white">Free Memory</dt>
|
||||||
<dd class="mt-1 flex items-center text-3xl font-semibold text-white">
|
<dd class="mt-1 flex items-center text-3xl font-semibold text-white">
|
||||||
{usage?.memory.freeMemPercentage}%
|
{usage?.memory.freeMemPercentage}%
|
||||||
@@ -166,19 +166,19 @@
|
|||||||
</div>
|
</div>
|
||||||
</dl>
|
</dl>
|
||||||
<dl class="relative mt-5 grid grid-cols-1 gap-5 sm:grid-cols-3">
|
<dl class="relative mt-5 grid grid-cols-1 gap-5 sm:grid-cols-3">
|
||||||
<div class="overflow-hidden rounded-lg px-4 py-5 sm:p-6">
|
<div class="overflow-hidden rounded px-4 py-5 sm:p-6">
|
||||||
<dt class="truncate text-sm font-medium text-white">Total CPUs</dt>
|
<dt class="truncate text-sm font-medium text-white">Total CPUs</dt>
|
||||||
<dd class="mt-1 text-3xl font-semibold text-white">
|
<dd class="mt-1 text-3xl font-semibold text-white">
|
||||||
{usage?.cpu.count}
|
{usage?.cpu.count}
|
||||||
</dd>
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
<div class="overflow-hidden rounded-lg px-4 py-5 sm:p-6">
|
<div class="overflow-hidden rounded px-4 py-5 sm:p-6">
|
||||||
<dt class="truncate text-sm font-medium text-white">Load Average (5/10/30mins)</dt>
|
<dt class="truncate text-sm font-medium text-white">Load Average (5/10/30mins)</dt>
|
||||||
<dd class="mt-1 text-3xl font-semibold text-white">
|
<dd class="mt-1 text-3xl font-semibold text-white">
|
||||||
{usage?.cpu.load.join('/')}
|
{usage?.cpu.load.join('/')}
|
||||||
</dd>
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
<div class="overflow-hidden rounded-lg px-4 py-5 sm:p-6" class:bg-red-500={cpuWarning}>
|
<div class="overflow-hidden rounded px-4 py-5 sm:p-6" class:bg-red-500={cpuWarning}>
|
||||||
<dt class="truncate text-sm font-medium text-white">CPU Usage</dt>
|
<dt class="truncate text-sm font-medium text-white">CPU Usage</dt>
|
||||||
<dd class="mt-1 flex items-center text-3xl font-semibold text-white">
|
<dd class="mt-1 flex items-center text-3xl font-semibold text-white">
|
||||||
{usage?.cpu.usage}%
|
{usage?.cpu.usage}%
|
||||||
@@ -189,19 +189,19 @@
|
|||||||
</div>
|
</div>
|
||||||
</dl>
|
</dl>
|
||||||
<dl class="relative mt-5 grid grid-cols-1 gap-5 sm:grid-cols-3">
|
<dl class="relative mt-5 grid grid-cols-1 gap-5 sm:grid-cols-3">
|
||||||
<div class="overflow-hidden rounded-lg px-4 py-5 sm:p-6">
|
<div class="overflow-hidden rounded px-4 py-5 sm:p-6">
|
||||||
<dt class="truncate text-sm font-medium text-white">Total Disk</dt>
|
<dt class="truncate text-sm font-medium text-white">Total Disk</dt>
|
||||||
<dd class="mt-1 text-3xl font-semibold text-white">
|
<dd class="mt-1 text-3xl font-semibold text-white">
|
||||||
{usage?.disk.totalGb}GB
|
{usage?.disk.totalGb}GB
|
||||||
</dd>
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
<div class="overflow-hidden rounded-lg px-4 py-5 sm:p-6">
|
<div class="overflow-hidden rounded px-4 py-5 sm:p-6">
|
||||||
<dt class="truncate text-sm font-medium text-white">Used Disk</dt>
|
<dt class="truncate text-sm font-medium text-white">Used Disk</dt>
|
||||||
<dd class="mt-1 text-3xl font-semibold text-white">
|
<dd class="mt-1 text-3xl font-semibold text-white">
|
||||||
{usage?.disk.usedGb}GB
|
{usage?.disk.usedGb}GB
|
||||||
</dd>
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
<div class="overflow-hidden rounded-lg px-4 py-5 sm:p-6" class:bg-red-500={diskWarning}>
|
<div class="overflow-hidden rounded px-4 py-5 sm:p-6" class:bg-red-500={diskWarning}>
|
||||||
<dt class="truncate text-sm font-medium text-white">Free Disk</dt>
|
<dt class="truncate text-sm font-medium text-white">Free Disk</dt>
|
||||||
<dd class="mt-1 flex items-center text-3xl font-semibold text-white">
|
<dd class="mt-1 flex items-center text-3xl font-semibold text-white">
|
||||||
{usage?.disk.freePercentage}%
|
{usage?.disk.freePercentage}%
|
||||||
@@ -217,7 +217,7 @@
|
|||||||
<a
|
<a
|
||||||
href="/applications"
|
href="/applications"
|
||||||
sveltekit:prefetch
|
sveltekit:prefetch
|
||||||
class="overflow-hidden rounded-lg px-4 py-5 text-green-500 no-underline transition-all duration-100 hover:bg-green-500 hover:text-white sm:p-6"
|
class="overflow-hidden rounded px-4 py-5 text-green-500 no-underline transition-all duration-100 hover:bg-green-500 hover:text-white sm:p-6"
|
||||||
>
|
>
|
||||||
<dt class="truncate text-sm font-medium text-white">{$t('index.applications')}</dt>
|
<dt class="truncate text-sm font-medium text-white">{$t('index.applications')}</dt>
|
||||||
<dd class="mt-1 text-3xl font-semibold ">
|
<dd class="mt-1 text-3xl font-semibold ">
|
||||||
@@ -227,7 +227,7 @@
|
|||||||
<a
|
<a
|
||||||
href="/destinations"
|
href="/destinations"
|
||||||
sveltekit:prefetch
|
sveltekit:prefetch
|
||||||
class="overflow-hidden rounded-lg px-4 py-5 text-sky-500 no-underline transition-all duration-100 hover:bg-sky-500 hover:text-white sm:p-6"
|
class="overflow-hidden rounded px-4 py-5 text-sky-500 no-underline transition-all duration-100 hover:bg-sky-500 hover:text-white sm:p-6"
|
||||||
>
|
>
|
||||||
<dt class="truncate text-sm font-medium text-white">{$t('index.destinations')}</dt>
|
<dt class="truncate text-sm font-medium text-white">{$t('index.destinations')}</dt>
|
||||||
<dd class="mt-1 text-3xl font-semibold ">
|
<dd class="mt-1 text-3xl font-semibold ">
|
||||||
@@ -238,7 +238,7 @@
|
|||||||
<a
|
<a
|
||||||
href="/sources"
|
href="/sources"
|
||||||
sveltekit:prefetch
|
sveltekit:prefetch
|
||||||
class="overflow-hidden rounded-lg px-4 py-5 text-orange-500 no-underline transition-all duration-100 hover:bg-orange-500 hover:text-white sm:p-6"
|
class="overflow-hidden rounded px-4 py-5 text-orange-500 no-underline transition-all duration-100 hover:bg-orange-500 hover:text-white sm:p-6"
|
||||||
>
|
>
|
||||||
<dt class="truncate text-sm font-medium text-white">{$t('index.git_sources')}</dt>
|
<dt class="truncate text-sm font-medium text-white">{$t('index.git_sources')}</dt>
|
||||||
<dd class="mt-1 text-3xl font-semibold">
|
<dd class="mt-1 text-3xl font-semibold">
|
||||||
@@ -250,7 +250,7 @@
|
|||||||
<a
|
<a
|
||||||
href="/databases"
|
href="/databases"
|
||||||
sveltekit:prefetch
|
sveltekit:prefetch
|
||||||
class="overflow-hidden rounded-lg px-4 py-5 text-purple-500 no-underline transition-all duration-100 hover:bg-purple-500 hover:text-white sm:p-6"
|
class="overflow-hidden rounded px-4 py-5 text-purple-500 no-underline transition-all duration-100 hover:bg-purple-500 hover:text-white sm:p-6"
|
||||||
>
|
>
|
||||||
<dt class="truncate text-sm font-medium text-white">{$t('index.databases')}</dt>
|
<dt class="truncate text-sm font-medium text-white">{$t('index.databases')}</dt>
|
||||||
<dd class="mt-1 text-3xl font-semibold ">
|
<dd class="mt-1 text-3xl font-semibold ">
|
||||||
@@ -261,7 +261,7 @@
|
|||||||
<a
|
<a
|
||||||
href="/services"
|
href="/services"
|
||||||
sveltekit:prefetch
|
sveltekit:prefetch
|
||||||
class="overflow-hidden rounded-lg px-4 py-5 text-pink-500 no-underline transition-all duration-100 hover:bg-pink-500 hover:text-white sm:p-6"
|
class="overflow-hidden rounded px-4 py-5 text-pink-500 no-underline transition-all duration-100 hover:bg-pink-500 hover:text-white sm:p-6"
|
||||||
>
|
>
|
||||||
<dt class="truncate text-sm font-medium text-white">{$t('index.services')}</dt>
|
<dt class="truncate text-sm font-medium text-white">{$t('index.services')}</dt>
|
||||||
<dd class="mt-1 text-3xl font-semibold ">
|
<dd class="mt-1 text-3xl font-semibold ">
|
||||||
@@ -272,7 +272,7 @@
|
|||||||
<a
|
<a
|
||||||
href="/iam"
|
href="/iam"
|
||||||
sveltekit:prefetch
|
sveltekit:prefetch
|
||||||
class="overflow-hidden rounded-lg px-4 py-5 text-cyan-500 no-underline transition-all duration-100 hover:bg-cyan-500 hover:text-white sm:p-6"
|
class="overflow-hidden rounded px-4 py-5 text-cyan-500 no-underline transition-all duration-100 hover:bg-cyan-500 hover:text-white sm:p-6"
|
||||||
>
|
>
|
||||||
<dt class="truncate text-sm font-medium text-white">{$t('index.teams')}</dt>
|
<dt class="truncate text-sm font-medium text-white">{$t('index.teams')}</dt>
|
||||||
<dd class="mt-1 text-3xl font-semibold ">
|
<dd class="mt-1 text-3xl font-semibold ">
|
||||||
|
|||||||
@@ -96,16 +96,3 @@
|
|||||||
disabled
|
disabled
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<!-- <div class="grid grid-cols-3 items-center">
|
|
||||||
<label for="postgresqlPublicPort">Public Port</label>
|
|
||||||
<div class="col-span-2 ">
|
|
||||||
<CopyPasswordField
|
|
||||||
placeholder="{ $t('forms.generated_automatically_after_start') }"
|
|
||||||
readonly
|
|
||||||
disabled
|
|
||||||
id="postgresqlPublicPort"
|
|
||||||
name="postgresqlPublicPort"
|
|
||||||
value={service.plausibleAnalytics.postgresqlPublicPort}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div> -->
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
let ftpUser = service.wordpress.ftpUser;
|
let ftpUser = service.wordpress.ftpUser;
|
||||||
let ftpPassword = service.wordpress.ftpPassword;
|
let ftpPassword = service.wordpress.ftpPassword;
|
||||||
let ftpLoading = false;
|
let ftpLoading = false;
|
||||||
|
let ownMysql = service.wordpress.ownMysql;
|
||||||
|
|
||||||
function generateUrl(publicPort) {
|
function generateUrl(publicPort) {
|
||||||
return browser
|
return browser
|
||||||
@@ -40,7 +41,7 @@
|
|||||||
publicPort,
|
publicPort,
|
||||||
ftpUser: user,
|
ftpUser: user,
|
||||||
ftpPassword: password
|
ftpPassword: password
|
||||||
} = await post(`/services/${id}/wordpress/settings.json`, {
|
} = await post(`/services/${id}/wordpress/ftp.json`, {
|
||||||
ftpEnabled
|
ftpEnabled
|
||||||
});
|
});
|
||||||
ftpUrl = generateUrl(publicPort);
|
ftpUrl = generateUrl(publicPort);
|
||||||
@@ -52,6 +53,18 @@
|
|||||||
} finally {
|
} finally {
|
||||||
ftpLoading = false;
|
ftpLoading = false;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
if (name === 'ownMysql') {
|
||||||
|
ownMysql = !ownMysql;
|
||||||
|
}
|
||||||
|
await post(`/services/${id}/wordpress/settings.json`, {
|
||||||
|
ownMysql
|
||||||
|
});
|
||||||
|
service.wordpress.ownMysql = ownMysql;
|
||||||
|
} catch ({ error }) {
|
||||||
|
return errorNotification(error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@@ -106,18 +119,55 @@ define('SUBDOMAIN_INSTALL', false);`
|
|||||||
<div class="flex space-x-1 py-5 font-bold">
|
<div class="flex space-x-1 py-5 font-bold">
|
||||||
<div class="title">MySQL</div>
|
<div class="title">MySQL</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="grid grid-cols-2 items-center px-10">
|
||||||
|
<Setting
|
||||||
|
dataTooltip={$t('forms.must_be_stopped_to_modify')}
|
||||||
|
bind:setting={service.wordpress.ownMysql}
|
||||||
|
disabled={isRunning}
|
||||||
|
on:click={() => !isRunning && changeSettings('ownMysql')}
|
||||||
|
title="Use your own MySQL server"
|
||||||
|
description="Enables the use of your own MySQL server. If you don't have one, you can use the one provided by Coolify."
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{#if service.wordpress.ownMysql}
|
||||||
|
<div class="grid grid-cols-2 items-center px-10">
|
||||||
|
<label for="mysqlHost">Host</label>
|
||||||
|
<input
|
||||||
|
name="mysqlHost"
|
||||||
|
id="mysqlHost"
|
||||||
|
required
|
||||||
|
readonly={isRunning}
|
||||||
|
disabled={isRunning}
|
||||||
|
bind:value={service.wordpress.mysqlHost}
|
||||||
|
placeholder="{$t('forms.eg')}: db.coolify.io"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 items-center px-10">
|
||||||
|
<label for="mysqlPort">Port</label>
|
||||||
|
<input
|
||||||
|
name="mysqlPort"
|
||||||
|
id="mysqlPort"
|
||||||
|
required
|
||||||
|
readonly={isRunning}
|
||||||
|
disabled={isRunning}
|
||||||
|
bind:value={service.wordpress.mysqlPort}
|
||||||
|
placeholder="{$t('forms.eg')}: 3306"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
<div class="grid grid-cols-2 items-center px-10">
|
<div class="grid grid-cols-2 items-center px-10">
|
||||||
<label for="mysqlDatabase">{$t('index.database')}</label>
|
<label for="mysqlDatabase">{$t('index.database')}</label>
|
||||||
<input
|
<input
|
||||||
name="mysqlDatabase"
|
name="mysqlDatabase"
|
||||||
id="mysqlDatabase"
|
id="mysqlDatabase"
|
||||||
required
|
required
|
||||||
readonly={readOnly}
|
readonly={readOnly && !service.wordpress.ownMysql}
|
||||||
disabled={readOnly}
|
disabled={readOnly && !service.wordpress.ownMysql}
|
||||||
bind:value={service.wordpress.mysqlDatabase}
|
bind:value={service.wordpress.mysqlDatabase}
|
||||||
placeholder="{$t('forms.eg')}: wordpress_db"
|
placeholder="{$t('forms.eg')}: wordpress_db"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
{#if !service.wordpress.ownMysql}
|
||||||
<div class="grid grid-cols-2 items-center px-10">
|
<div class="grid grid-cols-2 items-center px-10">
|
||||||
<label for="mysqlRootUser">{$t('forms.root_user')}</label>
|
<label for="mysqlRootUser">{$t('forms.root_user')}</label>
|
||||||
<input
|
<input
|
||||||
@@ -125,8 +175,8 @@ define('SUBDOMAIN_INSTALL', false);`
|
|||||||
id="mysqlRootUser"
|
id="mysqlRootUser"
|
||||||
placeholder="MySQL {$t('forms.root_user')}"
|
placeholder="MySQL {$t('forms.root_user')}"
|
||||||
value={service.wordpress.mysqlRootUser}
|
value={service.wordpress.mysqlRootUser}
|
||||||
disabled
|
readonly={isRunning || !service.wordpress.ownMysq}
|
||||||
readonly
|
disabled={isRunning || !service.wordpress.ownMysq}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-2 items-center px-10">
|
<div class="grid grid-cols-2 items-center px-10">
|
||||||
@@ -134,23 +184,30 @@ define('SUBDOMAIN_INSTALL', false);`
|
|||||||
<CopyPasswordField
|
<CopyPasswordField
|
||||||
id="mysqlRootUserPassword"
|
id="mysqlRootUserPassword"
|
||||||
isPasswordField
|
isPasswordField
|
||||||
readonly
|
readonly={isRunning || !service.wordpress.ownMysq}
|
||||||
disabled
|
disabled={isRunning || !service.wordpress.ownMysq}
|
||||||
name="mysqlRootUserPassword"
|
name="mysqlRootUserPassword"
|
||||||
value={service.wordpress.mysqlRootUserPassword}
|
value={service.wordpress.mysqlRootUserPassword}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
{/if}
|
||||||
<div class="grid grid-cols-2 items-center px-10">
|
<div class="grid grid-cols-2 items-center px-10">
|
||||||
<label for="mysqlUser">{$t('forms.user')}</label>
|
<label for="mysqlUser">{$t('forms.user')}</label>
|
||||||
<input name="mysqlUser" id="mysqlUser" value={service.wordpress.mysqlUser} disabled readonly />
|
<input
|
||||||
|
name="mysqlUser"
|
||||||
|
id="mysqlUser"
|
||||||
|
value={service.wordpress.mysqlUser}
|
||||||
|
readonly={isRunning || !service.wordpress.ownMysql}
|
||||||
|
disabled={isRunning || !service.wordpress.ownMysql}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-2 items-center px-10">
|
<div class="grid grid-cols-2 items-center px-10">
|
||||||
<label for="mysqlPassword">{$t('forms.password')}</label>
|
<label for="mysqlPassword">{$t('forms.password')}</label>
|
||||||
<CopyPasswordField
|
<CopyPasswordField
|
||||||
id="mysqlPassword"
|
id="mysqlPassword"
|
||||||
isPasswordField
|
isPasswordField
|
||||||
readonly
|
readonly={isRunning || !service.wordpress.ownMysql}
|
||||||
disabled
|
disabled={isRunning || !service.wordpress.ownMysql}
|
||||||
name="mysqlPassword"
|
name="mysqlPassword"
|
||||||
value={service.wordpress.mysqlPassword}
|
value={service.wordpress.mysqlPassword}
|
||||||
/>
|
/>
|
||||||
|
|||||||
185
src/routes/services/[id]/wordpress/ftp.json.ts
Normal file
185
src/routes/services/[id]/wordpress/ftp.json.ts
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
import { dev } from '$app/env';
|
||||||
|
import { asyncExecShell, getEngine, getUserDetails } from '$lib/common';
|
||||||
|
import { decrypt, encrypt } from '$lib/crypto';
|
||||||
|
import * as db from '$lib/database';
|
||||||
|
import { ErrorHandler, generatePassword, getFreePort } from '$lib/database';
|
||||||
|
import { checkContainer, startTcpProxy, stopTcpHttpProxy } from '$lib/haproxy';
|
||||||
|
import type { ComposeFile } from '$lib/types/composeFile';
|
||||||
|
import type { RequestHandler } from '@sveltejs/kit';
|
||||||
|
import cuid from 'cuid';
|
||||||
|
import fs from 'fs/promises';
|
||||||
|
import yaml from 'js-yaml';
|
||||||
|
|
||||||
|
export const post: RequestHandler = async (event) => {
|
||||||
|
const { status, body, teamId } = await getUserDetails(event);
|
||||||
|
if (status === 401) return { status, body };
|
||||||
|
|
||||||
|
const { id } = event.params;
|
||||||
|
|
||||||
|
const { ftpEnabled } = await event.request.json();
|
||||||
|
const publicPort = await getFreePort();
|
||||||
|
|
||||||
|
let ftpUser = cuid();
|
||||||
|
let ftpPassword = generatePassword();
|
||||||
|
|
||||||
|
const hostkeyDir = dev ? '/tmp/hostkeys' : '/app/ssl/hostkeys';
|
||||||
|
try {
|
||||||
|
const data = await db.prisma.wordpress.update({
|
||||||
|
where: { serviceId: id },
|
||||||
|
data: { ftpEnabled },
|
||||||
|
include: { service: { include: { destinationDocker: true } } }
|
||||||
|
});
|
||||||
|
const {
|
||||||
|
service: { destinationDockerId, destinationDocker },
|
||||||
|
ftpPublicPort: oldPublicPort,
|
||||||
|
ftpUser: user,
|
||||||
|
ftpPassword: savedPassword,
|
||||||
|
ftpHostKey,
|
||||||
|
ftpHostKeyPrivate
|
||||||
|
} = data;
|
||||||
|
if (user) ftpUser = user;
|
||||||
|
if (savedPassword) ftpPassword = decrypt(savedPassword);
|
||||||
|
|
||||||
|
const { stdout: password } = await asyncExecShell(
|
||||||
|
`echo ${ftpPassword} | openssl passwd -1 -stdin`
|
||||||
|
);
|
||||||
|
if (destinationDockerId) {
|
||||||
|
try {
|
||||||
|
await fs.stat(hostkeyDir);
|
||||||
|
} catch (error) {
|
||||||
|
await asyncExecShell(`mkdir -p ${hostkeyDir}`);
|
||||||
|
}
|
||||||
|
if (!ftpHostKey) {
|
||||||
|
await asyncExecShell(
|
||||||
|
`ssh-keygen -t ed25519 -f ssh_host_ed25519_key -N "" -q -f ${hostkeyDir}/${id}.ed25519`
|
||||||
|
);
|
||||||
|
const { stdout: ftpHostKey } = await asyncExecShell(`cat ${hostkeyDir}/${id}.ed25519`);
|
||||||
|
await db.prisma.wordpress.update({
|
||||||
|
where: { serviceId: id },
|
||||||
|
data: { ftpHostKey: encrypt(ftpHostKey) }
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await asyncExecShell(`echo "${decrypt(ftpHostKey)}" > ${hostkeyDir}/${id}.ed25519`);
|
||||||
|
}
|
||||||
|
if (!ftpHostKeyPrivate) {
|
||||||
|
await asyncExecShell(`ssh-keygen -t rsa -b 4096 -N "" -f ${hostkeyDir}/${id}.rsa`);
|
||||||
|
const { stdout: ftpHostKeyPrivate } = await asyncExecShell(`cat ${hostkeyDir}/${id}.rsa`);
|
||||||
|
await db.prisma.wordpress.update({
|
||||||
|
where: { serviceId: id },
|
||||||
|
data: { ftpHostKeyPrivate: encrypt(ftpHostKeyPrivate) }
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await asyncExecShell(`echo "${decrypt(ftpHostKeyPrivate)}" > ${hostkeyDir}/${id}.rsa`);
|
||||||
|
}
|
||||||
|
const { network, engine } = destinationDocker;
|
||||||
|
const host = getEngine(engine);
|
||||||
|
if (ftpEnabled) {
|
||||||
|
await db.prisma.wordpress.update({
|
||||||
|
where: { serviceId: id },
|
||||||
|
data: {
|
||||||
|
ftpPublicPort: publicPort,
|
||||||
|
ftpUser: user ? undefined : ftpUser,
|
||||||
|
ftpPassword: savedPassword ? undefined : encrypt(ftpPassword)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const isRunning = await checkContainer(engine, `${id}-ftp`);
|
||||||
|
if (isRunning) {
|
||||||
|
await asyncExecShell(
|
||||||
|
`DOCKER_HOST=${host} docker stop -t 0 ${id}-ftp && docker rm ${id}-ftp`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
//
|
||||||
|
}
|
||||||
|
const volumes = [
|
||||||
|
`${id}-wordpress-data:/home/${ftpUser}`,
|
||||||
|
`${
|
||||||
|
dev ? hostkeyDir : '/var/lib/docker/volumes/coolify-ssl-certs/_data/hostkeys'
|
||||||
|
}/${id}.ed25519:/etc/ssh/ssh_host_ed25519_key`,
|
||||||
|
`${
|
||||||
|
dev ? hostkeyDir : '/var/lib/docker/volumes/coolify-ssl-certs/_data/hostkeys'
|
||||||
|
}/${id}.rsa:/etc/ssh/ssh_host_rsa_key`,
|
||||||
|
`${
|
||||||
|
dev ? hostkeyDir : '/var/lib/docker/volumes/coolify-ssl-certs/_data/hostkeys'
|
||||||
|
}/${id}.sh:/etc/sftp.d/chmod.sh`
|
||||||
|
];
|
||||||
|
|
||||||
|
const compose: ComposeFile = {
|
||||||
|
version: '3.8',
|
||||||
|
services: {
|
||||||
|
[`${id}-ftp`]: {
|
||||||
|
image: `atmoz/sftp:alpine`,
|
||||||
|
command: `'${ftpUser}:${password.replace('\n', '').replace(/\$/g, '$$$')}:e:33'`,
|
||||||
|
extra_hosts: ['host.docker.internal:host-gateway'],
|
||||||
|
container_name: `${id}-ftp`,
|
||||||
|
volumes,
|
||||||
|
networks: [network],
|
||||||
|
depends_on: [],
|
||||||
|
restart: 'always'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
networks: {
|
||||||
|
[network]: {
|
||||||
|
external: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
volumes: {
|
||||||
|
[`${id}-wordpress-data`]: {
|
||||||
|
external: true,
|
||||||
|
name: `${id}-wordpress-data`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
await fs.writeFile(
|
||||||
|
`${hostkeyDir}/${id}.sh`,
|
||||||
|
`#!/bin/bash\nchmod 600 /etc/ssh/ssh_host_ed25519_key /etc/ssh/ssh_host_rsa_key`
|
||||||
|
);
|
||||||
|
await asyncExecShell(`chmod +x ${hostkeyDir}/${id}.sh`);
|
||||||
|
await fs.writeFile(`${hostkeyDir}/${id}-docker-compose.yml`, yaml.dump(compose));
|
||||||
|
await asyncExecShell(
|
||||||
|
`DOCKER_HOST=${host} docker compose -f ${hostkeyDir}/${id}-docker-compose.yml up -d`
|
||||||
|
);
|
||||||
|
|
||||||
|
await startTcpProxy(destinationDocker, `${id}-ftp`, publicPort, 22);
|
||||||
|
} else {
|
||||||
|
await db.prisma.wordpress.update({
|
||||||
|
where: { serviceId: id },
|
||||||
|
data: { ftpPublicPort: null }
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
await asyncExecShell(
|
||||||
|
`DOCKER_HOST=${host} docker stop -t 0 ${id}-ftp && docker rm ${id}-ftp`
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
await stopTcpHttpProxy(destinationDocker, oldPublicPort);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ftpEnabled) {
|
||||||
|
return {
|
||||||
|
status: 201,
|
||||||
|
body: {
|
||||||
|
publicPort,
|
||||||
|
ftpUser,
|
||||||
|
ftpPassword
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
status: 200,
|
||||||
|
body: {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
return ErrorHandler(error);
|
||||||
|
} finally {
|
||||||
|
await asyncExecShell(
|
||||||
|
`rm -f ${hostkeyDir}/${id}-docker-compose.yml ${hostkeyDir}/${id}.ed25519 ${hostkeyDir}/${id}.ed25519.pub ${hostkeyDir}/${id}.rsa ${hostkeyDir}/${id}.rsa.pub ${hostkeyDir}/${id}.sh`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -12,13 +12,24 @@ export const post: RequestHandler = async (event) => {
|
|||||||
name,
|
name,
|
||||||
fqdn,
|
fqdn,
|
||||||
exposePort,
|
exposePort,
|
||||||
wordpress: { extraConfig, mysqlDatabase }
|
wordpress: { extraConfig, mysqlDatabase, mysqlHost, mysqlPort }
|
||||||
} = await event.request.json();
|
} = await event.request.json();
|
||||||
|
|
||||||
if (fqdn) fqdn = fqdn.toLowerCase();
|
if (fqdn) fqdn = fqdn.toLowerCase();
|
||||||
if (exposePort) exposePort = Number(exposePort);
|
if (exposePort) exposePort = Number(exposePort);
|
||||||
|
if (mysqlPort) mysqlPort = Number(mysqlPort);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await db.updateWordpress({ id, fqdn, name, extraConfig, mysqlDatabase, exposePort });
|
await db.updateWordpress({
|
||||||
|
id,
|
||||||
|
fqdn,
|
||||||
|
name,
|
||||||
|
extraConfig,
|
||||||
|
mysqlDatabase,
|
||||||
|
exposePort,
|
||||||
|
mysqlHost,
|
||||||
|
mysqlPort
|
||||||
|
});
|
||||||
return { status: 201 };
|
return { status: 201 };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return ErrorHandler(error);
|
return ErrorHandler(error);
|
||||||
|
|||||||
@@ -16,170 +16,17 @@ export const post: RequestHandler = async (event) => {
|
|||||||
|
|
||||||
const { id } = event.params;
|
const { id } = event.params;
|
||||||
|
|
||||||
const { ftpEnabled } = await event.request.json();
|
const { ownMysql } = await event.request.json();
|
||||||
const publicPort = await getFreePort();
|
|
||||||
|
|
||||||
let ftpUser = cuid();
|
|
||||||
let ftpPassword = generatePassword();
|
|
||||||
|
|
||||||
const hostkeyDir = dev ? '/tmp/hostkeys' : '/app/ssl/hostkeys';
|
|
||||||
try {
|
try {
|
||||||
const data = await db.prisma.wordpress.update({
|
|
||||||
where: { serviceId: id },
|
|
||||||
data: { ftpEnabled },
|
|
||||||
include: { service: { include: { destinationDocker: true } } }
|
|
||||||
});
|
|
||||||
const {
|
|
||||||
service: { destinationDockerId, destinationDocker },
|
|
||||||
ftpPublicPort: oldPublicPort,
|
|
||||||
ftpUser: user,
|
|
||||||
ftpPassword: savedPassword,
|
|
||||||
ftpHostKey,
|
|
||||||
ftpHostKeyPrivate
|
|
||||||
} = data;
|
|
||||||
if (user) ftpUser = user;
|
|
||||||
if (savedPassword) ftpPassword = decrypt(savedPassword);
|
|
||||||
|
|
||||||
const { stdout: password } = await asyncExecShell(
|
|
||||||
`echo ${ftpPassword} | openssl passwd -1 -stdin`
|
|
||||||
);
|
|
||||||
if (destinationDockerId) {
|
|
||||||
try {
|
|
||||||
await fs.stat(hostkeyDir);
|
|
||||||
} catch (error) {
|
|
||||||
await asyncExecShell(`mkdir -p ${hostkeyDir}`);
|
|
||||||
}
|
|
||||||
if (!ftpHostKey) {
|
|
||||||
await asyncExecShell(
|
|
||||||
`ssh-keygen -t ed25519 -f ssh_host_ed25519_key -N "" -q -f ${hostkeyDir}/${id}.ed25519`
|
|
||||||
);
|
|
||||||
const { stdout: ftpHostKey } = await asyncExecShell(`cat ${hostkeyDir}/${id}.ed25519`);
|
|
||||||
await db.prisma.wordpress.update({
|
await db.prisma.wordpress.update({
|
||||||
where: { serviceId: id },
|
where: { serviceId: id },
|
||||||
data: { ftpHostKey: encrypt(ftpHostKey) }
|
data: { ownMysql }
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
await asyncExecShell(`echo "${decrypt(ftpHostKey)}" > ${hostkeyDir}/${id}.ed25519`);
|
|
||||||
}
|
|
||||||
if (!ftpHostKeyPrivate) {
|
|
||||||
await asyncExecShell(`ssh-keygen -t rsa -b 4096 -N "" -f ${hostkeyDir}/${id}.rsa`);
|
|
||||||
const { stdout: ftpHostKeyPrivate } = await asyncExecShell(`cat ${hostkeyDir}/${id}.rsa`);
|
|
||||||
await db.prisma.wordpress.update({
|
|
||||||
where: { serviceId: id },
|
|
||||||
data: { ftpHostKeyPrivate: encrypt(ftpHostKeyPrivate) }
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
await asyncExecShell(`echo "${decrypt(ftpHostKeyPrivate)}" > ${hostkeyDir}/${id}.rsa`);
|
|
||||||
}
|
|
||||||
const { network, engine } = destinationDocker;
|
|
||||||
const host = getEngine(engine);
|
|
||||||
if (ftpEnabled) {
|
|
||||||
await db.prisma.wordpress.update({
|
|
||||||
where: { serviceId: id },
|
|
||||||
data: {
|
|
||||||
ftpPublicPort: publicPort,
|
|
||||||
ftpUser: user ? undefined : ftpUser,
|
|
||||||
ftpPassword: savedPassword ? undefined : encrypt(ftpPassword)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
|
||||||
const isRunning = await checkContainer(engine, `${id}-ftp`);
|
|
||||||
if (isRunning) {
|
|
||||||
await asyncExecShell(
|
|
||||||
`DOCKER_HOST=${host} docker stop -t 0 ${id}-ftp && docker rm ${id}-ftp`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.log(error);
|
|
||||||
//
|
|
||||||
}
|
|
||||||
const volumes = [
|
|
||||||
`${id}-wordpress-data:/home/${ftpUser}`,
|
|
||||||
`${
|
|
||||||
dev ? hostkeyDir : '/var/lib/docker/volumes/coolify-ssl-certs/_data/hostkeys'
|
|
||||||
}/${id}.ed25519:/etc/ssh/ssh_host_ed25519_key`,
|
|
||||||
`${
|
|
||||||
dev ? hostkeyDir : '/var/lib/docker/volumes/coolify-ssl-certs/_data/hostkeys'
|
|
||||||
}/${id}.rsa:/etc/ssh/ssh_host_rsa_key`,
|
|
||||||
`${
|
|
||||||
dev ? hostkeyDir : '/var/lib/docker/volumes/coolify-ssl-certs/_data/hostkeys'
|
|
||||||
}/${id}.sh:/etc/sftp.d/chmod.sh`
|
|
||||||
];
|
|
||||||
|
|
||||||
const compose: ComposeFile = {
|
|
||||||
version: '3.8',
|
|
||||||
services: {
|
|
||||||
[`${id}-ftp`]: {
|
|
||||||
image: `atmoz/sftp:alpine`,
|
|
||||||
command: `'${ftpUser}:${password.replace('\n', '').replace(/\$/g, '$$$')}:e:33'`,
|
|
||||||
extra_hosts: ['host.docker.internal:host-gateway'],
|
|
||||||
container_name: `${id}-ftp`,
|
|
||||||
volumes,
|
|
||||||
networks: [network],
|
|
||||||
depends_on: [],
|
|
||||||
restart: 'always'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
networks: {
|
|
||||||
[network]: {
|
|
||||||
external: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
volumes: {
|
|
||||||
[`${id}-wordpress-data`]: {
|
|
||||||
external: true,
|
|
||||||
name: `${id}-wordpress-data`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
await fs.writeFile(
|
|
||||||
`${hostkeyDir}/${id}.sh`,
|
|
||||||
`#!/bin/bash\nchmod 600 /etc/ssh/ssh_host_ed25519_key /etc/ssh/ssh_host_rsa_key`
|
|
||||||
);
|
|
||||||
await asyncExecShell(`chmod +x ${hostkeyDir}/${id}.sh`);
|
|
||||||
await fs.writeFile(`${hostkeyDir}/${id}-docker-compose.yml`, yaml.dump(compose));
|
|
||||||
await asyncExecShell(
|
|
||||||
`DOCKER_HOST=${host} docker compose -f ${hostkeyDir}/${id}-docker-compose.yml up -d`
|
|
||||||
);
|
|
||||||
|
|
||||||
await startTcpProxy(destinationDocker, `${id}-ftp`, publicPort, 22);
|
|
||||||
} else {
|
|
||||||
await db.prisma.wordpress.update({
|
|
||||||
where: { serviceId: id },
|
|
||||||
data: { ftpPublicPort: null }
|
|
||||||
});
|
|
||||||
try {
|
|
||||||
await asyncExecShell(
|
|
||||||
`DOCKER_HOST=${host} docker stop -t 0 ${id}-ftp && docker rm ${id}-ftp`
|
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
await stopTcpHttpProxy(destinationDocker, oldPublicPort);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ftpEnabled) {
|
|
||||||
return {
|
return {
|
||||||
status: 201,
|
status: 201
|
||||||
body: {
|
|
||||||
publicPort,
|
|
||||||
ftpUser,
|
|
||||||
ftpPassword
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
status: 200,
|
|
||||||
body: {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
return ErrorHandler(error);
|
return ErrorHandler(error);
|
||||||
} finally {
|
|
||||||
await asyncExecShell(
|
|
||||||
`rm -f ${hostkeyDir}/${id}-docker-compose.yml ${hostkeyDir}/${id}.ed25519 ${hostkeyDir}/${id}.ed25519.pub ${hostkeyDir}/${id}.rsa ${hostkeyDir}/${id}.rsa.pub ${hostkeyDir}/${id}.sh`
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -26,11 +26,14 @@ export const post: RequestHandler = async (event) => {
|
|||||||
exposePort,
|
exposePort,
|
||||||
wordpress: {
|
wordpress: {
|
||||||
mysqlDatabase,
|
mysqlDatabase,
|
||||||
|
mysqlHost,
|
||||||
|
mysqlPort,
|
||||||
mysqlUser,
|
mysqlUser,
|
||||||
mysqlPassword,
|
mysqlPassword,
|
||||||
extraConfig,
|
extraConfig,
|
||||||
mysqlRootUser,
|
mysqlRootUser,
|
||||||
mysqlRootUserPassword
|
mysqlRootUserPassword,
|
||||||
|
ownMysql
|
||||||
}
|
}
|
||||||
} = service;
|
} = service;
|
||||||
|
|
||||||
@@ -45,7 +48,7 @@ export const post: RequestHandler = async (event) => {
|
|||||||
image: `${image}:${version}`,
|
image: `${image}:${version}`,
|
||||||
volume: `${id}-wordpress-data:/var/www/html`,
|
volume: `${id}-wordpress-data:/var/www/html`,
|
||||||
environmentVariables: {
|
environmentVariables: {
|
||||||
WORDPRESS_DB_HOST: `${id}-mysql`,
|
WORDPRESS_DB_HOST: ownMysql ? `${mysqlHost}:${mysqlPort}` : `${id}-mysql`,
|
||||||
WORDPRESS_DB_USER: mysqlUser,
|
WORDPRESS_DB_USER: mysqlUser,
|
||||||
WORDPRESS_DB_PASSWORD: mysqlPassword,
|
WORDPRESS_DB_PASSWORD: mysqlPassword,
|
||||||
WORDPRESS_DB_NAME: mysqlDatabase,
|
WORDPRESS_DB_NAME: mysqlDatabase,
|
||||||
@@ -69,7 +72,7 @@ export const post: RequestHandler = async (event) => {
|
|||||||
config.wordpress.environmentVariables[secret.name] = secret.value;
|
config.wordpress.environmentVariables[secret.name] = secret.value;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const composeFile: ComposeFile = {
|
let composeFile: ComposeFile = {
|
||||||
version: '3.8',
|
version: '3.8',
|
||||||
services: {
|
services: {
|
||||||
[id]: {
|
[id]: {
|
||||||
@@ -80,7 +83,6 @@ export const post: RequestHandler = async (event) => {
|
|||||||
networks: [network],
|
networks: [network],
|
||||||
restart: 'always',
|
restart: 'always',
|
||||||
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}),
|
||||||
depends_on: [`${id}-mysql`],
|
|
||||||
labels: makeLabelForServices('wordpress'),
|
labels: makeLabelForServices('wordpress'),
|
||||||
deploy: {
|
deploy: {
|
||||||
restart_policy: {
|
restart_policy: {
|
||||||
@@ -90,22 +92,6 @@ export const post: RequestHandler = async (event) => {
|
|||||||
window: '120s'
|
window: '120s'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
[`${id}-mysql`]: {
|
|
||||||
container_name: `${id}-mysql`,
|
|
||||||
image: config.mysql.image,
|
|
||||||
volumes: [config.mysql.volume],
|
|
||||||
environment: config.mysql.environmentVariables,
|
|
||||||
networks: [network],
|
|
||||||
restart: 'always',
|
|
||||||
deploy: {
|
|
||||||
restart_policy: {
|
|
||||||
condition: 'on-failure',
|
|
||||||
delay: '5s',
|
|
||||||
max_attempts: 3,
|
|
||||||
window: '120s'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
networks: {
|
networks: {
|
||||||
@@ -116,12 +102,32 @@ export const post: RequestHandler = async (event) => {
|
|||||||
volumes: {
|
volumes: {
|
||||||
[config.wordpress.volume.split(':')[0]]: {
|
[config.wordpress.volume.split(':')[0]]: {
|
||||||
name: config.wordpress.volume.split(':')[0]
|
name: config.wordpress.volume.split(':')[0]
|
||||||
},
|
|
||||||
[config.mysql.volume.split(':')[0]]: {
|
|
||||||
name: config.mysql.volume.split(':')[0]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
if (!ownMysql) {
|
||||||
|
composeFile.services[id].depends_on = [`${id}-mysql`];
|
||||||
|
composeFile.services[`${id}-mysql`] = {
|
||||||
|
container_name: `${id}-mysql`,
|
||||||
|
image: config.mysql.image,
|
||||||
|
volumes: [config.mysql.volume],
|
||||||
|
environment: config.mysql.environmentVariables,
|
||||||
|
networks: [network],
|
||||||
|
restart: 'always',
|
||||||
|
deploy: {
|
||||||
|
restart_policy: {
|
||||||
|
condition: 'on-failure',
|
||||||
|
delay: '5s',
|
||||||
|
max_attempts: 3,
|
||||||
|
window: '120s'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
composeFile.volumes[config.mysql.volume.split(':')[0]] = {
|
||||||
|
name: config.mysql.volume.split(':')[0]
|
||||||
|
};
|
||||||
|
}
|
||||||
const composeFileDestination = `${workdir}/docker-compose.yaml`;
|
const composeFileDestination = `${workdir}/docker-compose.yaml`;
|
||||||
await fs.writeFile(composeFileDestination, yaml.dump(composeFile));
|
await fs.writeFile(composeFileDestination, yaml.dump(composeFile));
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -55,7 +55,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-col flex-wrap justify-center">
|
<div class="flex justify-center">
|
||||||
{#if !services || ownServices.length === 0}
|
{#if !services || ownServices.length === 0}
|
||||||
<div class="flex-col">
|
<div class="flex-col">
|
||||||
<div class="text-center text-xl font-bold">{$t('service.no_service')}</div>
|
<div class="text-center text-xl font-bold">{$t('service.no_service')}</div>
|
||||||
|
|||||||
@@ -68,10 +68,48 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex space-x-1 p-6 px-6 text-2xl font-bold">
|
<div class="flex h-20 items-center space-x-2 p-5 px-6 font-bold">
|
||||||
<div class="tracking-tight">{$t('application.git_source')}</div>
|
<div class="-mb-5 flex-col">
|
||||||
<span class="arrow-right-applications px-1 text-orange-500">></span>
|
<div class="md:max-w-64 truncate text-base tracking-tight md:text-2xl lg:block">
|
||||||
<span class="pr-2">{source.name}</span>
|
Configuration
|
||||||
|
</div>
|
||||||
|
<span class="text-xs">{source.name}</span>
|
||||||
|
</div>
|
||||||
|
{#if source?.type === 'gitlab'}
|
||||||
|
<svg viewBox="0 0 128 128" class="w-8">
|
||||||
|
<path
|
||||||
|
fill="#FC6D26"
|
||||||
|
d="M126.615 72.31l-7.034-21.647L105.64 7.76c-.716-2.206-3.84-2.206-4.556 0l-13.94 42.903H40.856L26.916 7.76c-.717-2.206-3.84-2.206-4.557 0L8.42 50.664 1.385 72.31a4.792 4.792 0 001.74 5.358L64 121.894l60.874-44.227a4.793 4.793 0 001.74-5.357"
|
||||||
|
/><path fill="#E24329" d="M64 121.894l23.144-71.23H40.856L64 121.893z" /><path
|
||||||
|
fill="#FC6D26"
|
||||||
|
d="M64 121.894l-23.144-71.23H8.42L64 121.893z"
|
||||||
|
/><path
|
||||||
|
fill="#FCA326"
|
||||||
|
d="M8.42 50.663L1.384 72.31a4.79 4.79 0 001.74 5.357L64 121.894 8.42 50.664z"
|
||||||
|
/><path
|
||||||
|
fill="#E24329"
|
||||||
|
d="M8.42 50.663h32.436L26.916 7.76c-.717-2.206-3.84-2.206-4.557 0L8.42 50.664z"
|
||||||
|
/><path fill="#FC6D26" d="M64 121.894l23.144-71.23h32.437L64 121.893z" /><path
|
||||||
|
fill="#FCA326"
|
||||||
|
d="M119.58 50.663l7.035 21.647a4.79 4.79 0 01-1.74 5.357L64 121.894l55.58-71.23z"
|
||||||
|
/><path
|
||||||
|
fill="#E24329"
|
||||||
|
d="M119.58 50.663H87.145l13.94-42.902c.717-2.206 3.84-2.206 4.557 0l13.94 42.903z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
{:else if source?.type === 'github'}
|
||||||
|
<svg viewBox="0 0 128 128" class="w-8">
|
||||||
|
<g fill="#ffffff"
|
||||||
|
><path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
d="M64 5.103c-33.347 0-60.388 27.035-60.388 60.388 0 26.682 17.303 49.317 41.297 57.303 3.017.56 4.125-1.31 4.125-2.905 0-1.44-.056-6.197-.082-11.243-16.8 3.653-20.345-7.125-20.345-7.125-2.747-6.98-6.705-8.836-6.705-8.836-5.48-3.748.413-3.67.413-3.67 6.063.425 9.257 6.223 9.257 6.223 5.386 9.23 14.127 6.562 17.573 5.02.542-3.903 2.107-6.568 3.834-8.076-13.413-1.525-27.514-6.704-27.514-29.843 0-6.593 2.36-11.98 6.223-16.21-.628-1.52-2.695-7.662.584-15.98 0 0 5.07-1.623 16.61 6.19C53.7 35 58.867 34.327 64 34.304c5.13.023 10.3.694 15.127 2.033 11.526-7.813 16.59-6.19 16.59-6.19 3.287 8.317 1.22 14.46.593 15.98 3.872 4.23 6.215 9.617 6.215 16.21 0 23.194-14.127 28.3-27.574 29.796 2.167 1.874 4.097 5.55 4.097 11.183 0 8.08-.07 14.583-.07 16.572 0 1.607 1.088 3.49 4.148 2.897 23.98-7.994 41.263-30.622 41.263-57.294C124.388 32.14 97.35 5.104 64 5.104z"
|
||||||
|
/><path
|
||||||
|
d="M26.484 91.806c-.133.3-.605.39-1.035.185-.44-.196-.685-.605-.543-.906.13-.31.603-.395 1.04-.188.44.197.69.61.537.91zm2.446 2.729c-.287.267-.85.143-1.232-.28-.396-.42-.47-.983-.177-1.254.298-.266.844-.14 1.24.28.394.426.472.984.17 1.255zM31.312 98.012c-.37.258-.976.017-1.35-.52-.37-.538-.37-1.183.01-1.44.373-.258.97-.025 1.35.507.368.545.368 1.19-.01 1.452zm3.261 3.361c-.33.365-1.036.267-1.552-.23-.527-.487-.674-1.18-.343-1.544.336-.366 1.045-.264 1.564.23.527.486.686 1.18.333 1.543zm4.5 1.951c-.147.473-.825.688-1.51.486-.683-.207-1.13-.76-.99-1.238.14-.477.823-.7 1.512-.485.683.206 1.13.756.988 1.237zm4.943.361c.017.498-.563.91-1.28.92-.723.017-1.308-.387-1.315-.877 0-.503.568-.91 1.29-.924.717-.013 1.306.387 1.306.88zm4.598-.782c.086.485-.413.984-1.126 1.117-.7.13-1.35-.172-1.44-.653-.086-.498.422-.997 1.122-1.126.714-.123 1.354.17 1.444.663zm0 0"
|
||||||
|
/></g
|
||||||
|
>
|
||||||
|
</svg>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-col justify-center">
|
<div class="flex flex-col justify-center">
|
||||||
|
|||||||
@@ -62,7 +62,7 @@
|
|||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col flex-wrap justify-center">
|
<div class="flex justify-center">
|
||||||
{#if !sources || ownSources.length === 0}
|
{#if !sources || ownSources.length === 0}
|
||||||
<div class="flex-col">
|
<div class="flex-col">
|
||||||
<div class="text-center text-xl font-bold">{$t('source.no_git_sources_found')}</div>
|
<div class="text-center text-xl font-bold">{$t('source.no_git_sources_found')}</div>
|
||||||
@@ -74,11 +74,48 @@
|
|||||||
{#each ownSources as source}
|
{#each ownSources as source}
|
||||||
<a href="/sources/{source.id}" class="w-96 p-2 no-underline">
|
<a href="/sources/{source.id}" class="w-96 p-2 no-underline">
|
||||||
<div
|
<div
|
||||||
class="box-selection group hover:bg-orange-600"
|
class="box-selection group relative hover:bg-orange-600"
|
||||||
class:border-red-500={source.gitlabApp && !source.gitlabAppId}
|
class:border-red-500={source.gitlabApp && !source.gitlabAppId}
|
||||||
class:border-0={source.gitlabApp && !source.gitlabAppId}
|
class:border-0={source.gitlabApp && !source.gitlabAppId}
|
||||||
class:border-l-4={source.gitlabApp && !source.gitlabAppId}
|
class:border-l-4={source.gitlabApp && !source.gitlabAppId}
|
||||||
>
|
>
|
||||||
|
<div class="absolute top-0 left-0 -m-5 h-10 w-10">
|
||||||
|
{#if source?.type === 'gitlab'}
|
||||||
|
<svg viewBox="0 0 128 128">
|
||||||
|
<path
|
||||||
|
fill="#FC6D26"
|
||||||
|
d="M126.615 72.31l-7.034-21.647L105.64 7.76c-.716-2.206-3.84-2.206-4.556 0l-13.94 42.903H40.856L26.916 7.76c-.717-2.206-3.84-2.206-4.557 0L8.42 50.664 1.385 72.31a4.792 4.792 0 001.74 5.358L64 121.894l60.874-44.227a4.793 4.793 0 001.74-5.357"
|
||||||
|
/><path fill="#E24329" d="M64 121.894l23.144-71.23H40.856L64 121.893z" /><path
|
||||||
|
fill="#FC6D26"
|
||||||
|
d="M64 121.894l-23.144-71.23H8.42L64 121.893z"
|
||||||
|
/><path
|
||||||
|
fill="#FCA326"
|
||||||
|
d="M8.42 50.663L1.384 72.31a4.79 4.79 0 001.74 5.357L64 121.894 8.42 50.664z"
|
||||||
|
/><path
|
||||||
|
fill="#E24329"
|
||||||
|
d="M8.42 50.663h32.436L26.916 7.76c-.717-2.206-3.84-2.206-4.557 0L8.42 50.664z"
|
||||||
|
/><path fill="#FC6D26" d="M64 121.894l23.144-71.23h32.437L64 121.893z" /><path
|
||||||
|
fill="#FCA326"
|
||||||
|
d="M119.58 50.663l7.035 21.647a4.79 4.79 0 01-1.74 5.357L64 121.894l55.58-71.23z"
|
||||||
|
/><path
|
||||||
|
fill="#E24329"
|
||||||
|
d="M119.58 50.663H87.145l13.94-42.902c.717-2.206 3.84-2.206 4.557 0l13.94 42.903z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
{:else if source?.type === 'github'}
|
||||||
|
<svg viewBox="0 0 128 128">
|
||||||
|
<g fill="#ffffff"
|
||||||
|
><path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
d="M64 5.103c-33.347 0-60.388 27.035-60.388 60.388 0 26.682 17.303 49.317 41.297 57.303 3.017.56 4.125-1.31 4.125-2.905 0-1.44-.056-6.197-.082-11.243-16.8 3.653-20.345-7.125-20.345-7.125-2.747-6.98-6.705-8.836-6.705-8.836-5.48-3.748.413-3.67.413-3.67 6.063.425 9.257 6.223 9.257 6.223 5.386 9.23 14.127 6.562 17.573 5.02.542-3.903 2.107-6.568 3.834-8.076-13.413-1.525-27.514-6.704-27.514-29.843 0-6.593 2.36-11.98 6.223-16.21-.628-1.52-2.695-7.662.584-15.98 0 0 5.07-1.623 16.61 6.19C53.7 35 58.867 34.327 64 34.304c5.13.023 10.3.694 15.127 2.033 11.526-7.813 16.59-6.19 16.59-6.19 3.287 8.317 1.22 14.46.593 15.98 3.872 4.23 6.215 9.617 6.215 16.21 0 23.194-14.127 28.3-27.574 29.796 2.167 1.874 4.097 5.55 4.097 11.183 0 8.08-.07 14.583-.07 16.572 0 1.607 1.088 3.49 4.148 2.897 23.98-7.994 41.263-30.622 41.263-57.294C124.388 32.14 97.35 5.104 64 5.104z"
|
||||||
|
/><path
|
||||||
|
d="M26.484 91.806c-.133.3-.605.39-1.035.185-.44-.196-.685-.605-.543-.906.13-.31.603-.395 1.04-.188.44.197.69.61.537.91zm2.446 2.729c-.287.267-.85.143-1.232-.28-.396-.42-.47-.983-.177-1.254.298-.266.844-.14 1.24.28.394.426.472.984.17 1.255zM31.312 98.012c-.37.258-.976.017-1.35-.52-.37-.538-.37-1.183.01-1.44.373-.258.97-.025 1.35.507.368.545.368 1.19-.01 1.452zm3.261 3.361c-.33.365-1.036.267-1.552-.23-.527-.487-.674-1.18-.343-1.544.336-.366 1.045-.264 1.564.23.527.486.686 1.18.333 1.543zm4.5 1.951c-.147.473-.825.688-1.51.486-.683-.207-1.13-.76-.99-1.238.14-.477.823-.7 1.512-.485.683.206 1.13.756.988 1.237zm4.943.361c.017.498-.563.91-1.28.92-.723.017-1.308-.387-1.315-.877 0-.503.568-.91 1.29-.924.717-.013 1.306.387 1.306.88zm4.598-.782c.086.485-.413.984-1.126 1.117-.7.13-1.35-.172-1.44-.653-.086-.498.422-.997 1.122-1.126.714-.123 1.354.17 1.444.663zm0 0"
|
||||||
|
/></g
|
||||||
|
>
|
||||||
|
</svg>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
<div class="truncate text-center text-xl font-bold">{source.name}</div>
|
<div class="truncate text-center text-xl font-bold">{source.name}</div>
|
||||||
{#if $session.teamId === '0' && otherSources.length > 0}
|
{#if $session.teamId === '0' && otherSources.length > 0}
|
||||||
<div class="truncate text-center">{source.teams[0].name}</div>
|
<div class="truncate text-center">{source.teams[0].name}</div>
|
||||||
|
|||||||
@@ -356,7 +356,7 @@ a {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.box-selection {
|
.box-selection {
|
||||||
@apply min-w-[16rem] max-w-[24rem] justify-center rounded border-transparent bg-coolgray-200 p-6 shadow-lg transition duration-150 hover:scale-105 hover:border-transparent hover:bg-coolgray-400;
|
@apply min-w-[16rem] max-w-[24rem] justify-center rounded border-transparent bg-coolgray-200 p-6 hover:border-transparent hover:bg-coolgray-400;
|
||||||
}
|
}
|
||||||
|
|
||||||
._toastBar {
|
._toastBar {
|
||||||
|
|||||||
Reference in New Issue
Block a user