diff --git a/prisma/migrations/20220327180323_ghost/migration.sql b/prisma/migrations/20220327180323_ghost/migration.sql
new file mode 100644
index 000000000..3c1cec36f
--- /dev/null
+++ b/prisma/migrations/20220327180323_ghost/migration.sql
@@ -0,0 +1,19 @@
+-- CreateTable
+CREATE TABLE "Ghost" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "defaultEmail" TEXT NOT NULL,
+ "defaultPassword" TEXT NOT NULL,
+ "mariadbUser" TEXT NOT NULL,
+ "mariadbPassword" TEXT NOT NULL,
+ "mariadbRootUser" TEXT NOT NULL,
+ "mariadbRootUserPassword" TEXT NOT NULL,
+ "mariadbDatabase" TEXT,
+ "mariadbPublicPort" INTEGER,
+ "serviceId" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "Ghost_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "Service" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+
+-- CreateIndex
+CREATE UNIQUE INDEX "Ghost_serviceId_key" ON "Ghost"("serviceId");
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
index 95310d2aa..a849ae36f 100644
--- a/prisma/schema.prisma
+++ b/prisma/schema.prisma
@@ -278,6 +278,7 @@ model Service {
minio Minio?
vscodeserver Vscodeserver?
wordpress Wordpress?
+ ghost Ghost?
serviceSecret ServiceSecret[]
}
@@ -332,3 +333,19 @@ model Wordpress {
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
+
+model Ghost {
+ id String @id @default(cuid())
+ defaultEmail String
+ defaultPassword String
+ mariadbUser String
+ mariadbPassword String
+ mariadbRootUser String
+ mariadbRootUserPassword String
+ mariadbDatabase String?
+ mariadbPublicPort Int?
+ serviceId String @unique
+ service Service @relation(fields: [serviceId], references: [id])
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+}
diff --git a/src/lib/components/svg/services/Ghost.svelte b/src/lib/components/svg/services/Ghost.svelte
new file mode 100644
index 000000000..2e77177da
--- /dev/null
+++ b/src/lib/components/svg/services/Ghost.svelte
@@ -0,0 +1,9 @@
+
+
+
diff --git a/src/lib/database/common.ts b/src/lib/database/common.ts
index 19922cece..e89105f05 100644
--- a/src/lib/database/common.ts
+++ b/src/lib/database/common.ts
@@ -107,6 +107,7 @@ export const supportedServiceTypesAndVersions = [
name: 'plausibleanalytics',
fancyName: 'Plausible Analytics',
baseImage: 'plausible/analytics',
+ images: ['bitnami/postgresql:13.2.0', 'yandex/clickhouse-server:21.3.2.5'],
versions: ['latest'],
ports: {
main: 8000
@@ -143,6 +144,7 @@ export const supportedServiceTypesAndVersions = [
name: 'wordpress',
fancyName: 'Wordpress',
baseImage: 'wordpress',
+ images: ['bitnami/mysql:5.7'],
versions: ['latest', 'php8.1', 'php8.0', 'php7.4', 'php7.3'],
ports: {
main: 80
@@ -183,6 +185,16 @@ export const supportedServiceTypesAndVersions = [
ports: {
main: 3001
}
+ },
+ {
+ name: 'ghost',
+ fancyName: 'Ghost',
+ baseImage: 'bitnami/ghost',
+ images: ['bitnami/mariadb'],
+ versions: ['latest'],
+ ports: {
+ main: 2368
+ }
}
];
@@ -207,6 +219,13 @@ export function getServiceImage(type) {
}
return '';
}
+export function getServiceImages(type) {
+ const found = supportedServiceTypesAndVersions.find((t) => t.name === type);
+ if (found) {
+ return found.images;
+ }
+ return [];
+}
export function generateDatabaseConfiguration(database) {
const {
id,
diff --git a/src/lib/database/services.ts b/src/lib/database/services.ts
index daec2a5da..a5c2ee9ea 100644
--- a/src/lib/database/services.ts
+++ b/src/lib/database/services.ts
@@ -1,3 +1,4 @@
+import { asyncExecShell, getEngine } from '$lib/common';
import { decrypt, encrypt } from '$lib/crypto';
import cuid from 'cuid';
import { generatePassword } from '.';
@@ -20,6 +21,7 @@ export async function getService({ id, teamId }) {
minio: true,
vscodeserver: true,
wordpress: true,
+ ghost: true,
serviceSecret: true
}
});
@@ -43,12 +45,18 @@ export async function getService({ id, teamId }) {
if (body.wordpress?.mysqlRootUserPassword)
body.wordpress.mysqlRootUserPassword = decrypt(body.wordpress.mysqlRootUserPassword);
+ if (body.ghost?.mariadbPassword) body.ghost.mariadbPassword = decrypt(body.ghost.mariadbPassword);
+ if (body.ghost?.mariadbRootUserPassword)
+ body.ghost.mariadbRootUserPassword = decrypt(body.ghost.mariadbRootUserPassword);
+ if (body.ghost?.defaultPassword) body.ghost.defaultPassword = decrypt(body.ghost.defaultPassword);
+
if (body?.serviceSecret.length > 0) {
body.serviceSecret = body.serviceSecret.map((s) => {
s.value = decrypt(s.value);
return s;
});
}
+
return { ...body };
}
@@ -133,6 +141,30 @@ export async function configureServiceType({ id, type }) {
type
}
});
+ } else if (type === 'ghost') {
+ const defaultEmail = `${cuid()}@coolify.io`;
+ const defaultPassword = encrypt(generatePassword());
+ const mariadbUser = cuid();
+ const mariadbPassword = encrypt(generatePassword());
+ const mariadbRootUser = cuid();
+ const mariadbRootUserPassword = encrypt(generatePassword());
+
+ await prisma.service.update({
+ where: { id },
+ data: {
+ type,
+ ghost: {
+ create: {
+ defaultEmail,
+ defaultPassword,
+ mariadbUser,
+ mariadbPassword,
+ mariadbRootUser,
+ mariadbRootUserPassword
+ }
+ }
+ }
+ });
}
}
export async function setServiceVersion({ id, version }) {
@@ -174,8 +206,15 @@ export async function updateWordpress({ id, fqdn, name, mysqlDatabase, extraConf
export async function updateMinioService({ id, publicPort }) {
return await prisma.minio.update({ where: { serviceId: id }, data: { publicPort } });
}
+export async function updateGhostService({ id, fqdn, name, mariadbDatabase }) {
+ return await prisma.service.update({
+ where: { id },
+ data: { fqdn, name, ghost: { update: { mariadbDatabase } } }
+ });
+}
export async function removeService({ id }) {
+ await prisma.ghost.deleteMany({ where: { serviceId: id } });
await prisma.plausibleAnalytics.deleteMany({ where: { serviceId: id } });
await prisma.minio.deleteMany({ where: { serviceId: id } });
await prisma.vscodeserver.deleteMany({ where: { serviceId: id } });
diff --git a/src/lib/letsencrypt/index.ts b/src/lib/letsencrypt/index.ts
index e85f539de..eb74aa252 100644
--- a/src/lib/letsencrypt/index.ts
+++ b/src/lib/letsencrypt/index.ts
@@ -104,32 +104,34 @@ export async function generateSSLCerts() {
});
for (const application of applications) {
try {
- const {
- fqdn,
- id,
- destinationDocker: { engine, network },
- settings: { previews }
- } = application;
- const isRunning = await checkContainer(engine, id);
- const domain = getDomain(fqdn);
- const isHttps = fqdn.startsWith('https://');
- if (isRunning) {
- if (isHttps) ssls.push({ domain, id, isCoolify: false });
- }
- if (previews) {
- const host = getEngine(engine);
- const { stdout } = await asyncExecShell(
- `DOCKER_HOST=${host} docker container ls --filter="status=running" --filter="network=${network}" --filter="name=${id}-" --format="{{json .Names}}"`
- );
- const containers = stdout
- .trim()
- .split('\n')
- .filter((a) => a)
- .map((c) => c.replace(/"/g, ''));
- if (containers.length > 0) {
- for (const container of containers) {
- let previewDomain = `${container.split('-')[1]}.${domain}`;
- if (isHttps) ssls.push({ domain: previewDomain, id, isCoolify: false });
+ if (application.fqdn && application.destinationDockerId) {
+ const {
+ fqdn,
+ id,
+ destinationDocker: { engine, network },
+ settings: { previews }
+ } = application;
+ const isRunning = await checkContainer(engine, id);
+ const domain = getDomain(fqdn);
+ const isHttps = fqdn.startsWith('https://');
+ if (isRunning) {
+ if (isHttps) ssls.push({ domain, id, isCoolify: false });
+ }
+ if (previews) {
+ const host = getEngine(engine);
+ const { stdout } = await asyncExecShell(
+ `DOCKER_HOST=${host} docker container ls --filter="status=running" --filter="network=${network}" --filter="name=${id}-" --format="{{json .Names}}"`
+ );
+ const containers = stdout
+ .trim()
+ .split('\n')
+ .filter((a) => a)
+ .map((c) => c.replace(/"/g, ''));
+ if (containers.length > 0) {
+ for (const container of containers) {
+ let previewDomain = `${container.split('-')[1]}.${domain}`;
+ if (isHttps) ssls.push({ domain: previewDomain, id, isCoolify: false });
+ }
}
}
}
@@ -143,26 +145,29 @@ export async function generateSSLCerts() {
minio: true,
plausibleAnalytics: true,
vscodeserver: true,
- wordpress: true
+ wordpress: true,
+ ghost: true
},
orderBy: { createdAt: 'desc' }
});
for (const service of services) {
try {
- const {
- fqdn,
- id,
- type,
- destinationDocker: { engine }
- } = service;
- const found = db.supportedServiceTypesAndVersions.find((a) => a.name === type);
- if (found) {
- const domain = getDomain(fqdn);
- const isHttps = fqdn.startsWith('https://');
- const isRunning = await checkContainer(engine, id);
- if (isRunning) {
- if (isHttps) ssls.push({ domain, id, isCoolify: false });
+ if (service.fqdn && service.destinationDockerId) {
+ const {
+ fqdn,
+ id,
+ type,
+ destinationDocker: { engine }
+ } = service;
+ const found = db.supportedServiceTypesAndVersions.find((a) => a.name === type);
+ if (found) {
+ const domain = getDomain(fqdn);
+ const isHttps = fqdn.startsWith('https://');
+ const isRunning = await checkContainer(engine, id);
+ if (isRunning) {
+ if (isHttps) ssls.push({ domain, id, isCoolify: false });
+ }
}
}
} catch (error) {
diff --git a/src/routes/destinations/[id]/_LocalDocker.svelte b/src/routes/destinations/[id]/_LocalDocker.svelte
index bf4d8447a..329d23c2f 100644
--- a/src/routes/destinations/[id]/_LocalDocker.svelte
+++ b/src/routes/destinations/[id]/_LocalDocker.svelte
@@ -103,7 +103,7 @@
}
async function forceRestartProxy() {
const sure = confirm(
- 'Are you sure you want to restart the proxy? Everyting will be reconfigured in ~10 sec.'
+ 'Are you sure you want to restart the proxy? Everything will be reconfigured in ~10 secs.'
);
if (sure) {
try {
diff --git a/src/routes/destinations/[id]/_RemoteDocker.svelte b/src/routes/destinations/[id]/_RemoteDocker.svelte
index 9c13cf465..4de1b82ce 100644
--- a/src/routes/destinations/[id]/_RemoteDocker.svelte
+++ b/src/routes/destinations/[id]/_RemoteDocker.svelte
@@ -106,7 +106,7 @@
}
async function forceRestartProxy() {
const sure = confirm(
- 'Are you sure you want to restart the proxy? Everyting will be reconfigured in ~10 sec.'
+ 'Are you sure you want to restart the proxy? Everything will be reconfigured in ~10 secs.'
);
if (sure) {
try {
diff --git a/src/routes/services/[id]/_Services/_Ghost.svelte b/src/routes/services/[id]/_Services/_Ghost.svelte
new file mode 100644
index 000000000..8a6154ac9
--- /dev/null
+++ b/src/routes/services/[id]/_Services/_Ghost.svelte
@@ -0,0 +1,90 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/routes/services/[id]/_Services/_Services.svelte b/src/routes/services/[id]/_Services/_Services.svelte
index 896953cc4..6a54d9b98 100644
--- a/src/routes/services/[id]/_Services/_Services.svelte
+++ b/src/routes/services/[id]/_Services/_Services.svelte
@@ -10,6 +10,7 @@
import Setting from '$lib/components/Setting.svelte';
import { errorNotification } from '$lib/form';
import { toast } from '@zerodevx/svelte-toast';
+ import Ghost from './_Ghost.svelte';
import MinIo from './_MinIO.svelte';
import PlausibleAnalytics from './_PlausibleAnalytics.svelte';
import VsCodeServer from './_VSCodeServer.svelte';
@@ -142,6 +143,8 @@
{:else if service.type === 'wordpress'}
+ {:else if service.type === 'ghost'}
+
{/if}
diff --git a/src/routes/services/[id]/__layout.svelte b/src/routes/services/[id]/__layout.svelte
index fffce0007..362f89786 100644
--- a/src/routes/services/[id]/__layout.svelte
+++ b/src/routes/services/[id]/__layout.svelte
@@ -35,6 +35,7 @@
}
if (service.plausibleAnalytics?.email && service.plausibleAnalytics.username) readOnly = true;
if (service.wordpress?.mysqlDatabase) readOnly = true;
+ if (service.ghost?.mariadbDatabase && service.ghost.mariadbDatabase) readOnly = true;
return {
props: {
diff --git a/src/routes/services/[id]/configuration/type.svelte b/src/routes/services/[id]/configuration/type.svelte
index 6a56354be..bf8575065 100644
--- a/src/routes/services/[id]/configuration/type.svelte
+++ b/src/routes/services/[id]/configuration/type.svelte
@@ -40,6 +40,7 @@
import LanguageTool from '$lib/components/svg/services/LanguageTool.svelte';
import N8n from '$lib/components/svg/services/N8n.svelte';
import UptimeKuma from '$lib/components/svg/services/UptimeKuma.svelte';
+ import Ghost from '$lib/components/svg/services/Ghost.svelte';
const { id } = $page.params;
const from = $page.url.searchParams.get('from');
@@ -83,6 +84,8 @@
{:else if type.name === 'uptimekuma'}
+ {:else if type.name === 'ghost'}
+
{/if}{type.fancyName}
diff --git a/src/routes/services/[id]/ghost/index.json.ts b/src/routes/services/[id]/ghost/index.json.ts
new file mode 100644
index 000000000..81ca8ade1
--- /dev/null
+++ b/src/routes/services/[id]/ghost/index.json.ts
@@ -0,0 +1,23 @@
+import { getUserDetails } from '$lib/common';
+import * as db from '$lib/database';
+import { ErrorHandler } from '$lib/database';
+import type { RequestHandler } from '@sveltejs/kit';
+
+export const post: RequestHandler = async (event) => {
+ const { status, body } = await getUserDetails(event);
+ if (status === 401) return { status, body };
+ const { id } = event.params;
+
+ let {
+ name,
+ fqdn,
+ ghost: { mariadbDatabase }
+ } = await event.request.json();
+ if (fqdn) fqdn = fqdn.toLowerCase();
+ try {
+ await db.updateGhostService({ id, fqdn, name, mariadbDatabase });
+ return { status: 201 };
+ } catch (error) {
+ return ErrorHandler(error);
+ }
+};
diff --git a/src/routes/services/[id]/ghost/start.json.ts b/src/routes/services/[id]/ghost/start.json.ts
new file mode 100644
index 000000000..f1f2250bd
--- /dev/null
+++ b/src/routes/services/[id]/ghost/start.json.ts
@@ -0,0 +1,134 @@
+import {
+ asyncExecShell,
+ createDirectories,
+ getDomain,
+ getEngine,
+ getUserDetails
+} from '$lib/common';
+import * as db from '$lib/database';
+import { promises as fs } from 'fs';
+import yaml from 'js-yaml';
+import type { RequestHandler } from '@sveltejs/kit';
+import { ErrorHandler, getServiceImage } from '$lib/database';
+import { makeLabelForServices } from '$lib/buildPacks/common';
+
+export const post: RequestHandler = async (event) => {
+ const { teamId, status, body } = await getUserDetails(event);
+ if (status === 401) return { status, body };
+
+ const { id } = event.params;
+
+ try {
+ const service = await db.getService({ id, teamId });
+ const {
+ type,
+ version,
+ destinationDockerId,
+ destinationDocker,
+ serviceSecret,
+ fqdn,
+ ghost: {
+ defaultEmail,
+ defaultPassword,
+ mariadbRootUser,
+ mariadbRootUserPassword,
+ mariadbDatabase,
+ mariadbPassword,
+ mariadbUser
+ }
+ } = service;
+ const network = destinationDockerId && destinationDocker.network;
+ const host = getEngine(destinationDocker.engine);
+
+ const { workdir } = await createDirectories({ repository: type, buildId: id });
+ const image = getServiceImage(type);
+ const domain = getDomain(fqdn);
+ const config = {
+ ghost: {
+ image: `${image}:${version}`,
+ volume: `${id}-ghost:/bitnami/ghost`,
+ environmentVariables: {
+ GHOST_HOST: domain,
+ GHOST_EMAIL: defaultEmail,
+ GHOST_PASSWORD: defaultPassword,
+ GHOST_DATABASE_HOST: `${id}-mariadb`,
+ GHOST_DATABASE_USER: mariadbUser,
+ GHOST_DATABASE_PASSWORD: mariadbPassword,
+ GHOST_DATABASE_NAME: mariadbDatabase,
+ GHOST_DATABASE_PORT_NUMBER: 3306
+ }
+ },
+ mariadb: {
+ image: `bitnami/mariadb:latest`,
+ volume: `${id}-mariadb:/bitnami/mariadb`,
+ environmentVariables: {
+ MARIADB_USER: mariadbUser,
+ MARIADB_PASSWORD: mariadbPassword,
+ MARIADB_DATABASE: mariadbDatabase,
+ MARIADB_ROOT_USER: mariadbRootUser,
+ MARIADB_ROOT_PASSWORD: mariadbRootUserPassword
+ }
+ }
+ };
+ if (serviceSecret.length > 0) {
+ serviceSecret.forEach((secret) => {
+ config.ghost.environmentVariables[secret.name] = secret.value;
+ });
+ }
+ const composeFile = {
+ version: '3.8',
+ services: {
+ [id]: {
+ container_name: id,
+ image: config.ghost.image,
+ networks: [network],
+ volumes: [config.ghost.volume],
+ environment: config.ghost.environmentVariables,
+ restart: 'always',
+ labels: makeLabelForServices('ghost'),
+ depends_on: [`${id}-mariadb`]
+ },
+ [`${id}-mariadb`]: {
+ container_name: `${id}-mariadb`,
+ image: config.mariadb.image,
+ networks: [network],
+ volumes: [config.mariadb.volume],
+ environment: config.mariadb.environmentVariables,
+ restart: 'always'
+ }
+ },
+ networks: {
+ [network]: {
+ external: true
+ }
+ },
+ volumes: {
+ [config.ghost.volume.split(':')[0]]: {
+ name: config.ghost.volume.split(':')[0]
+ },
+ [config.mariadb.volume.split(':')[0]]: {
+ name: config.mariadb.volume.split(':')[0]
+ }
+ }
+ };
+ console.log(JSON.stringify(composeFile.volumes));
+ const composeFileDestination = `${workdir}/docker-compose.yaml`;
+ await fs.writeFile(composeFileDestination, yaml.dump(composeFile));
+
+ try {
+ if (version === 'latest') {
+ await asyncExecShell(
+ `DOCKER_HOST=${host} docker compose -f ${composeFileDestination} pull`
+ );
+ }
+ await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`);
+ return {
+ status: 200
+ };
+ } catch (error) {
+ return ErrorHandler(error);
+ }
+ } catch (error) {
+ return ErrorHandler(error);
+ }
+};
diff --git a/src/routes/services/[id]/ghost/stop.json.ts b/src/routes/services/[id]/ghost/stop.json.ts
new file mode 100644
index 000000000..478f5b946
--- /dev/null
+++ b/src/routes/services/[id]/ghost/stop.json.ts
@@ -0,0 +1,39 @@
+import { getUserDetails, removeDestinationDocker } from '$lib/common';
+import * as db from '$lib/database';
+import { ErrorHandler } from '$lib/database';
+import { checkContainer } from '$lib/haproxy';
+import type { RequestHandler } from '@sveltejs/kit';
+
+export const post: RequestHandler = async (event) => {
+ const { teamId, status, body } = await getUserDetails(event);
+ if (status === 401) return { status, body };
+
+ const { id } = event.params;
+
+ try {
+ const service = await db.getService({ id, teamId });
+ const { destinationDockerId, destinationDocker, fqdn } = service;
+ if (destinationDockerId) {
+ const engine = destinationDocker.engine;
+
+ try {
+ let found = await checkContainer(engine, id);
+ if (found) {
+ await removeDestinationDocker({ id, engine });
+ }
+ found = await checkContainer(engine, `${id}-mariadb`);
+ if (found) {
+ await removeDestinationDocker({ id: `${id}-mariadb`, engine });
+ }
+ } catch (error) {
+ console.error(error);
+ }
+ }
+
+ return {
+ status: 200
+ };
+ } catch (error) {
+ return ErrorHandler(error);
+ }
+};
diff --git a/src/routes/services/[id]/index.json.ts b/src/routes/services/[id]/index.json.ts
index d712c1c72..676ff6405 100644
--- a/src/routes/services/[id]/index.json.ts
+++ b/src/routes/services/[id]/index.json.ts
@@ -4,7 +4,8 @@ import {
generateDatabaseConfiguration,
getServiceImage,
getVersions,
- ErrorHandler
+ ErrorHandler,
+ getServiceImages
} from '$lib/database';
import { dockerInstance } from '$lib/docker';
import type { RequestHandler } from '@sveltejs/kit';
@@ -23,7 +24,13 @@ export const get: RequestHandler = async (event) => {
const host = getEngine(destinationDocker.engine);
const docker = dockerInstance({ destinationDocker });
const baseImage = getServiceImage(type);
+ const images = getServiceImages(type);
docker.engine.pull(`${baseImage}:${version}`);
+ if (images?.length > 0) {
+ for (const image of images) {
+ docker.engine.pull(`${image}:latest`);
+ }
+ }
try {
const { stdout } = await asyncExecShell(
`DOCKER_HOST=${host} docker inspect --format '{{json .State}}' ${id}`
diff --git a/src/routes/services/[id]/index.svelte b/src/routes/services/[id]/index.svelte
index bcc69b8a7..ada5c0d9e 100644
--- a/src/routes/services/[id]/index.svelte
+++ b/src/routes/services/[id]/index.svelte
@@ -41,6 +41,7 @@
import LanguageTool from '$lib/components/svg/services/LanguageTool.svelte';
import N8n from '$lib/components/svg/services/N8n.svelte';
import UptimeKuma from '$lib/components/svg/services/UptimeKuma.svelte';
+ import Ghost from '$lib/components/svg/services/Ghost.svelte';
export let service;
export let isRunning;
@@ -119,6 +120,10 @@
+ {:else if service.type === 'ghost'}
+
+
+
{/if}
diff --git a/src/routes/services/[id]/languagetool/start.json.ts b/src/routes/services/[id]/languagetool/start.json.ts
index 4666fea79..a6a81d475 100644
--- a/src/routes/services/[id]/languagetool/start.json.ts
+++ b/src/routes/services/[id]/languagetool/start.json.ts
@@ -41,7 +41,7 @@ export const post: RequestHandler = async (event) => {
networks: [network],
environment: config.environmentVariables,
restart: 'always',
- volumes: [`${id}-ngrams:/ngrams`],
+ volumes: [config.volume],
labels: makeLabelForServices('languagetool')
}
},
@@ -51,20 +51,20 @@ export const post: RequestHandler = async (event) => {
}
},
volumes: {
- [`${id}-ngrams`]: {
- external: true
+ [config.volume.split(':')[0]]: {
+ name: config.volume.split(':')[0]
}
}
};
const composeFileDestination = `${workdir}/docker-compose.yaml`;
await fs.writeFile(composeFileDestination, yaml.dump(composeFile));
- try {
- await asyncExecShell(`DOCKER_HOST=${host} docker volume create ${id}-ngrams`);
- } catch (error) {
- console.log(error);
- }
try {
+ if (version === 'latest') {
+ await asyncExecShell(
+ `DOCKER_HOST=${host} docker compose -f ${composeFileDestination} pull`
+ );
+ }
await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`);
return {
status: 200
diff --git a/src/routes/services/[id]/minio/start.json.ts b/src/routes/services/[id]/minio/start.json.ts
index 99665dfca..bcffd9e8f 100644
--- a/src/routes/services/[id]/minio/start.json.ts
+++ b/src/routes/services/[id]/minio/start.json.ts
@@ -76,19 +76,13 @@ export const post: RequestHandler = async (event) => {
},
volumes: {
[config.volume.split(':')[0]]: {
- external: true
+ name: config.volume.split(':')[0]
}
}
};
const composeFileDestination = `${workdir}/docker-compose.yaml`;
await fs.writeFile(composeFileDestination, yaml.dump(composeFile));
- try {
- await asyncExecShell(
- `DOCKER_HOST=${host} docker volume create ${config.volume.split(':')[0]}`
- );
- } catch (error) {
- console.log(error);
- }
+
try {
await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`);
await db.updateMinioService({ id, publicPort });
diff --git a/src/routes/services/[id]/n8n/start.json.ts b/src/routes/services/[id]/n8n/start.json.ts
index 6c9f63b76..4a04917c7 100644
--- a/src/routes/services/[id]/n8n/start.json.ts
+++ b/src/routes/services/[id]/n8n/start.json.ts
@@ -59,6 +59,11 @@ export const post: RequestHandler = async (event) => {
await fs.writeFile(composeFileDestination, yaml.dump(composeFile));
try {
+ if (version === 'latest') {
+ await asyncExecShell(
+ `DOCKER_HOST=${host} docker compose -f ${composeFileDestination} pull`
+ );
+ }
await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`);
return {
status: 200
diff --git a/src/routes/services/[id]/nocodb/start.json.ts b/src/routes/services/[id]/nocodb/start.json.ts
index 1088bf817..ebc59ce97 100644
--- a/src/routes/services/[id]/nocodb/start.json.ts
+++ b/src/routes/services/[id]/nocodb/start.json.ts
@@ -52,6 +52,11 @@ export const post: RequestHandler = async (event) => {
await fs.writeFile(composeFileDestination, yaml.dump(composeFile));
try {
+ if (version === 'latest') {
+ await asyncExecShell(
+ `DOCKER_HOST=${host} docker compose -f ${composeFileDestination} pull`
+ );
+ }
await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`);
return {
status: 200
diff --git a/src/routes/services/[id]/plausibleanalytics/start.json.ts b/src/routes/services/[id]/plausibleanalytics/start.json.ts
index 4b635264b..836bd0178 100644
--- a/src/routes/services/[id]/plausibleanalytics/start.json.ts
+++ b/src/routes/services/[id]/plausibleanalytics/start.json.ts
@@ -158,29 +158,21 @@ COPY ./init-db.sh /docker-entrypoint-initdb.d/init-db.sh`;
},
volumes: {
[config.postgresql.volume.split(':')[0]]: {
- external: true
+ name: config.postgresql.volume.split(':')[0]
},
[config.clickhouse.volume.split(':')[0]]: {
- external: true
+ name: config.clickhouse.volume.split(':')[0]
}
}
};
const composeFileDestination = `${workdir}/docker-compose.yaml`;
await fs.writeFile(composeFileDestination, yaml.dump(composeFile));
- try {
- await asyncExecShell(
- `DOCKER_HOST=${host} docker volume create ${config.postgresql.volume.split(':')[0]}`
- );
- await asyncExecShell(
- `DOCKER_HOST=${host} docker volume create ${config.clickhouse.volume.split(':')[0]}`
- );
- } catch (error) {
- console.log(error);
+ if (version === 'latest') {
+ await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} pull`);
}
await asyncExecShell(
`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up --build -d`
);
-
return {
status: 200
};
diff --git a/src/routes/services/[id]/uptimekuma/start.json.ts b/src/routes/services/[id]/uptimekuma/start.json.ts
index 961a546c4..845873bb0 100644
--- a/src/routes/services/[id]/uptimekuma/start.json.ts
+++ b/src/routes/services/[id]/uptimekuma/start.json.ts
@@ -59,6 +59,11 @@ export const post: RequestHandler = async (event) => {
await fs.writeFile(composeFileDestination, yaml.dump(composeFile));
try {
+ if (version === 'latest') {
+ await asyncExecShell(
+ `DOCKER_HOST=${host} docker compose -f ${composeFileDestination} pull`
+ );
+ }
await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`);
return {
status: 200
diff --git a/src/routes/services/[id]/vaultwarden/start.json.ts b/src/routes/services/[id]/vaultwarden/start.json.ts
index 703a71473..f977adda3 100644
--- a/src/routes/services/[id]/vaultwarden/start.json.ts
+++ b/src/routes/services/[id]/vaultwarden/start.json.ts
@@ -52,20 +52,18 @@ export const post: RequestHandler = async (event) => {
},
volumes: {
[config.volume.split(':')[0]]: {
- external: true
+ name: config.volume.split(':')[0]
}
}
};
const composeFileDestination = `${workdir}/docker-compose.yaml`;
await fs.writeFile(composeFileDestination, yaml.dump(composeFile));
try {
- await asyncExecShell(
- `DOCKER_HOST=${host} docker volume create ${config.volume.split(':')[0]}`
- );
- } catch (error) {
- console.log(error);
- }
- try {
+ if (version === 'latest') {
+ await asyncExecShell(
+ `DOCKER_HOST=${host} docker compose -f ${composeFileDestination} pull`
+ );
+ }
await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`);
return {
status: 200
diff --git a/src/routes/services/[id]/vscodeserver/start.json.ts b/src/routes/services/[id]/vscodeserver/start.json.ts
index be43cb2a7..6f51fcf2a 100644
--- a/src/routes/services/[id]/vscodeserver/start.json.ts
+++ b/src/routes/services/[id]/vscodeserver/start.json.ts
@@ -61,29 +61,20 @@ export const post: RequestHandler = async (event) => {
},
volumes: {
[config.volume.split(':')[0]]: {
- external: true
+ name: config.volume.split(':')[0]
}
}
};
const composeFileDestination = `${workdir}/docker-compose.yaml`;
await fs.writeFile(composeFileDestination, yaml.dump(composeFile));
- try {
- await asyncExecShell(
- `DOCKER_HOST=${host} docker volume create ${config.volume.split(':')[0]}`
- );
- } catch (error) {
- console.log(error);
- }
-
- try {
- await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`);
- return {
- status: 200
- };
- } catch (error) {
- return ErrorHandler(error);
+ if (version === 'latest') {
+ await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} pull`);
}
+ await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`);
+ return {
+ status: 200
+ };
} catch (error) {
return ErrorHandler(error);
}
diff --git a/src/routes/services/[id]/wordpress/start.json.ts b/src/routes/services/[id]/wordpress/start.json.ts
index d1685d8b1..98e7d6aab 100644
--- a/src/routes/services/[id]/wordpress/start.json.ts
+++ b/src/routes/services/[id]/wordpress/start.json.ts
@@ -72,6 +72,7 @@ export const post: RequestHandler = async (event) => {
container_name: id,
image: config.wordpress.image,
environment: config.wordpress.environmentVariables,
+ volumes: [config.wordpress.volume],
networks: [network],
restart: 'always',
depends_on: [`${id}-mysql`],
@@ -80,6 +81,7 @@ export const post: RequestHandler = async (event) => {
[`${id}-mysql`]: {
container_name: `${id}-mysql`,
image: config.mysql.image,
+ volumes: [config.mysql.volume],
environment: config.mysql.environmentVariables,
networks: [network],
restart: 'always'
@@ -91,29 +93,22 @@ export const post: RequestHandler = async (event) => {
}
},
volumes: {
- [config.mysql.volume.split(':')[0]]: {
- external: true
- },
[config.wordpress.volume.split(':')[0]]: {
- external: true
+ name: config.wordpress.volume.split(':')[0]
+ },
+ [config.mysql.volume.split(':')[0]]: {
+ name: config.mysql.volume.split(':')[0]
}
}
};
const composeFileDestination = `${workdir}/docker-compose.yaml`;
await fs.writeFile(composeFileDestination, yaml.dump(composeFile));
-
- try {
- await asyncExecShell(
- `DOCKER_HOST=${host} docker volume create ${config.mysql.volume.split(':')[0]}`
- );
- await asyncExecShell(
- `DOCKER_HOST=${host} docker volume create ${config.wordpress.volume.split(':')[0]}`
- );
- } catch (error) {
- console.log(error);
- }
-
try {
+ if (version === 'latest') {
+ await asyncExecShell(
+ `DOCKER_HOST=${host} docker compose -f ${composeFileDestination} pull`
+ );
+ }
await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`);
return {
status: 200
diff --git a/static/ghost.png b/static/ghost.png
new file mode 100644
index 000000000..f4e300654
Binary files /dev/null and b/static/ghost.png differ