diff --git a/Dockerfile b/Dockerfile index 83d513cec..9ca82df2c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,6 +8,8 @@ RUN yarn build FROM node:16.14.0-alpine WORKDIR /app +LABEL coolify.managed true + RUN apk add --no-cache git openssh-client curl jq cmake sqlite RUN curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm@6 diff --git a/package.json b/package.json index db46808ff..b34df3e5a 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,12 @@ { "name": "coolify", "description": "An open-source & self-hostable Heroku / Netlify alternative.", - "version": "2.0.4", + "version": "2.0.5", "license": "AGPL-3.0", "scripts": { - "dev": "docker-compose -f docker-compose-dev.yaml up -d && NODE_ENV=development svelte-kit dev --host 0.0.0.0", - "dev:stop": "docker-compose -f docker-compose-dev.yaml down", - "dev:logs": "docker-compose -f docker-compose-dev.yaml logs -f --tail 10", + "dev": "docker compose -f docker-compose-dev.yaml up -d && NODE_ENV=development svelte-kit dev --host 0.0.0.0", + "dev:stop": "docker compose -f docker-compose-dev.yaml down", + "dev:logs": "docker compose -f docker-compose-dev.yaml logs -f --tail 10", "studio": "npx prisma studio", "start": "npx prisma migrate deploy && npx prisma generate && npx prisma db seed && node index.js", "build": "svelte-kit build", @@ -16,8 +16,7 @@ "db:generate": "prisma generate", "db:push": "prisma db push && prisma generate", "db:seed": "prisma db seed", - "stagrelease": "cross-var docker build -t coollabsio/coolify:$npm_package_version . && docker push coollabsio/coolify:$npm_package_version", - "prerelease": "cross-var docker build -t coollabsio/coolify:$npm_package_version -t coollabsio/coolify:latest .", + "release:staging": "cross-var docker build -t coollabsio/coolify:$npm_package_version . && docker push coollabsio/coolify:$npm_package_version", "release:coolify": "cross-var yarn prerelease && docker push coollabsio/coolify:$npm_package_version && docker image push coollabsio/coolify:$npm_package_version && docker push coollabsio/coolify:latest", "release:haproxy": "docker build -f haproxy.Dockerfile -t coollabsio/coolify-haproxy-alpine:1.0.0 -t coollabsio/coolify-haproxy-alpine:latest . && docker image push --all-tags coollabsio/coolify-haproxy-alpine", "release:haproxy:tcp": "docker build -f haproxy-tcp.Dockerfile -t coollabsio/coolify-haproxy-tcp-alpine:1.0.0 -t coollabsio/coolify-haproxy-tcp-alpine:latest . && docker image push --all-tags coollabsio/coolify-haproxy-tcp-alpine", diff --git a/src/app.html b/src/app.html index d5c431e11..2dc97f37d 100644 --- a/src/app.html +++ b/src/app.html @@ -4,9 +4,6 @@ - - -
diff --git a/src/lib/components/svg/services/NocoDB.svelte b/src/lib/components/svg/services/NocoDB.svelte
index 3e61a2b8f..ba93c4f78 100644
--- a/src/lib/components/svg/services/NocoDB.svelte
+++ b/src/lib/components/svg/services/NocoDB.svelte
@@ -5,5 +5,5 @@
diff --git a/src/lib/components/svg/services/PlausibleAnalytics.svelte b/src/lib/components/svg/services/PlausibleAnalytics.svelte
index 920f2ecf1..9ae5774fc 100644
--- a/src/lib/components/svg/services/PlausibleAnalytics.svelte
+++ b/src/lib/components/svg/services/PlausibleAnalytics.svelte
@@ -5,5 +5,5 @@
diff --git a/src/lib/components/svg/services/VaultWarden.svelte b/src/lib/components/svg/services/VaultWarden.svelte
new file mode 100644
index 000000000..3e4f6b8b5
--- /dev/null
+++ b/src/lib/components/svg/services/VaultWarden.svelte
@@ -0,0 +1,35 @@
+
+
+
diff --git a/src/lib/database/applications.ts b/src/lib/database/applications.ts
index 037334873..ece44bffa 100644
--- a/src/lib/database/applications.ts
+++ b/src/lib/database/applications.ts
@@ -1,6 +1,6 @@
import { decrypt, encrypt } from '$lib/crypto';
import { removeProxyConfiguration } from '$lib/haproxy';
-import { asyncExecShell, getEngine, removeContainer } from '$lib/common';
+import { asyncExecShell, getEngine } from '$lib/common';
import { getDomain, removeDestinationDocker } from '$lib/common';
import { prisma } from './common';
diff --git a/src/lib/database/checks.ts b/src/lib/database/checks.ts
index 884c6d2bd..38ddc96b9 100644
--- a/src/lib/database/checks.ts
+++ b/src/lib/database/checks.ts
@@ -1,5 +1,5 @@
import { getDomain } from '$lib/common';
-import { prisma, PrismaErrorHandler } from './common';
+import { prisma } from './common';
export async function isBranchAlreadyUsed({ repository, branch, id }) {
const application = await prisma.application.findUnique({
diff --git a/src/lib/database/common.ts b/src/lib/database/common.ts
index c79e9d101..c94dadd28 100644
--- a/src/lib/database/common.ts
+++ b/src/lib/database/common.ts
@@ -116,6 +116,12 @@ export const supportedServiceTypesAndVersions = [
fancyName: 'Wordpress',
baseImage: 'wordpress',
versions: ['latest', 'php8.1', 'php8.0', 'php7.4', 'php7.3']
+ },
+ {
+ name: 'vaultwarden',
+ fancyName: 'Vaultwarden',
+ baseImage: 'vaultwarden/server',
+ versions: ['latest']
}
];
diff --git a/src/lib/database/databases.ts b/src/lib/database/databases.ts
index 00afa4827..6ca187ffb 100644
--- a/src/lib/database/databases.ts
+++ b/src/lib/database/databases.ts
@@ -114,15 +114,6 @@ export async function updateDatabase({
});
}
-// export async function setDatabaseSettings({ id, isPublic }) {
-// try {
-// await prisma.databaseSettings.update({ where: { databaseId: id }, data: { isPublic } })
-// return { status: 201 }
-// } catch (e) {
-// throw PrismaErrorHandler(e)
-// }
-// }
-
export async function stopDatabase(database) {
let everStarted = false;
const {
diff --git a/src/lib/database/destinations.ts b/src/lib/database/destinations.ts
index a4e5ec228..4a8c46ef9 100644
--- a/src/lib/database/destinations.ts
+++ b/src/lib/database/destinations.ts
@@ -1,8 +1,8 @@
import { asyncExecShell, getEngine } from '$lib/common';
import { dockerInstance } from '$lib/docker';
-import { defaultProxyImageHttp, defaultProxyImageTcp, startCoolifyProxy } from '$lib/haproxy';
+import { startCoolifyProxy } from '$lib/haproxy';
import { getDatabaseImage } from '.';
-import { prisma, PrismaErrorHandler } from './common';
+import { prisma } from './common';
export async function listDestinations(teamId) {
return await prisma.destinationDocker.findMany({ where: { teams: { some: { id: teamId } } } });
@@ -37,11 +37,9 @@ export async function configureDestinationForDatabase({ id, destinationId }) {
const host = getEngine(engine);
if (type && version) {
const baseImage = getDatabaseImage(type);
- asyncExecShell(`DOCKER_HOST=${host} docker pull ${baseImage}:${version}`);
- asyncExecShell(`DOCKER_HOST=${host} docker pull coollabsio/${defaultProxyImageTcp}`);
- asyncExecShell(`DOCKER_HOST=${host} docker pull coollabsio/${defaultProxyImageHttp}`);
- asyncExecShell(`DOCKER_HOST=${host} docker pull certbot/certbot:latest`);
- asyncExecShell(`DOCKER_HOST=${host} docker pull alpine:latest`);
+ asyncExecShell(
+ `DOCKER_HOST=${host} docker pull ${baseImage}:${version} && echo "FROM ${baseImage}:${version}" | docker build --label coolify.managed="true" -t "${baseImage}:${version}" -`
+ );
}
}
}
diff --git a/src/lib/database/gitSources.ts b/src/lib/database/gitSources.ts
index b2f43a092..927907964 100644
--- a/src/lib/database/gitSources.ts
+++ b/src/lib/database/gitSources.ts
@@ -1,5 +1,5 @@
import { decrypt, encrypt } from '$lib/crypto';
-import { prisma, PrismaErrorHandler } from './common';
+import { prisma } from './common';
export async function listSources(teamId) {
return await prisma.gitSource.findMany({
diff --git a/src/lib/database/github.ts b/src/lib/database/github.ts
index 46f57159f..339b8e008 100644
--- a/src/lib/database/github.ts
+++ b/src/lib/database/github.ts
@@ -1,5 +1,5 @@
import { decrypt, encrypt } from '$lib/crypto';
-import { prisma, PrismaErrorHandler } from './common';
+import { prisma } from './common';
export async function addInstallation({ gitSourceId, installation_id }) {
const source = await prisma.gitSource.findUnique({
diff --git a/src/lib/database/gitlab.ts b/src/lib/database/gitlab.ts
index e8020794b..eb9bdfb1b 100644
--- a/src/lib/database/gitlab.ts
+++ b/src/lib/database/gitlab.ts
@@ -1,5 +1,5 @@
import { encrypt } from '$lib/crypto';
-import { generateSshKeyPair, prisma, PrismaErrorHandler } from './common';
+import { generateSshKeyPair, prisma } from './common';
export async function updateDeployKey({ id, deployKeyId }) {
const application = await prisma.application.findUnique({
diff --git a/src/lib/database/logs.ts b/src/lib/database/logs.ts
index e4dd7a3e6..0b92654b7 100644
--- a/src/lib/database/logs.ts
+++ b/src/lib/database/logs.ts
@@ -7,7 +7,7 @@ export async function listLogs({ buildId, last = 0 }) {
orderBy: { time: 'asc' }
});
return [...body];
- } catch (e) {
- throw PrismaErrorHandler(e);
+ } catch (error) {
+ return PrismaErrorHandler(error);
}
}
diff --git a/src/lib/database/secrets.ts b/src/lib/database/secrets.ts
index 06f6592b2..c03ec9459 100644
--- a/src/lib/database/secrets.ts
+++ b/src/lib/database/secrets.ts
@@ -1,5 +1,5 @@
import { encrypt } from '$lib/crypto';
-import { prisma, PrismaErrorHandler } from './common';
+import { prisma } from './common';
export async function listSecrets({ applicationId }) {
return await prisma.secret.findMany({
diff --git a/src/lib/database/services.ts b/src/lib/database/services.ts
index 6b7ac2f3f..5568cd4a7 100644
--- a/src/lib/database/services.ts
+++ b/src/lib/database/services.ts
@@ -1,8 +1,7 @@
import { decrypt, encrypt } from '$lib/crypto';
-import { dockerInstance } from '$lib/docker';
import cuid from 'cuid';
import { generatePassword } from '.';
-import { prisma, PrismaErrorHandler } from './common';
+import { prisma } from './common';
export async function listServices(teamId) {
return await prisma.service.findMany({ where: { teams: { some: { id: teamId } } } });
@@ -99,6 +98,13 @@ export async function configureServiceType({ id, type }) {
wordpress: { create: { mysqlPassword, mysqlRootUserPassword, mysqlRootUser, mysqlUser } }
}
});
+ } else if (type === 'vaultwarden') {
+ await prisma.service.update({
+ where: { id },
+ data: {
+ type
+ }
+ });
}
}
export async function setService({ id, version }) {
@@ -115,6 +121,9 @@ export async function updatePlausibleAnalyticsService({ id, fqdn, email, usernam
export async function updateNocoDbOrMinioService({ id, fqdn, name }) {
return await prisma.service.update({ where: { id }, data: { fqdn, name } });
}
+export async function updateVaultWardenService({ id, fqdn, name }) {
+ return await prisma.service.update({ where: { id }, data: { fqdn, name } });
+}
export async function updateVsCodeServer({ id, fqdn, name }) {
return await prisma.service.update({ where: { id }, data: { fqdn, name } });
}
diff --git a/src/lib/database/teams.ts b/src/lib/database/teams.ts
index 3e1cf9928..dd9a14cff 100644
--- a/src/lib/database/teams.ts
+++ b/src/lib/database/teams.ts
@@ -1,4 +1,4 @@
-import { prisma, PrismaErrorHandler } from './common';
+import { prisma } from './common';
export async function listTeams() {
return await prisma.team.findMany();
diff --git a/src/lib/database/users.ts b/src/lib/database/users.ts
index 663ede1a4..7b15ff4d2 100644
--- a/src/lib/database/users.ts
+++ b/src/lib/database/users.ts
@@ -1,8 +1,8 @@
import cuid from 'cuid';
import bcrypt from 'bcrypt';
-import { prisma, PrismaErrorHandler } from './common';
-import { asyncExecShell, removeContainer, uniqueName } from '$lib/common';
+import { prisma } from './common';
+import { asyncExecShell, uniqueName } from '$lib/common';
import * as db from '$lib/database';
import { startCoolifyProxy } from '$lib/haproxy';
diff --git a/src/lib/haproxy/index.ts b/src/lib/haproxy/index.ts
index 2b811967a..7679fe28f 100644
--- a/src/lib/haproxy/index.ts
+++ b/src/lib/haproxy/index.ts
@@ -106,7 +106,11 @@ export async function forceSSLOffApplication({ domain }) {
export async function forceSSLOnApplication({ domain }) {
if (!dev) {
const haproxy = await haproxyInstance();
- await checkHAProxy(haproxy);
+ try {
+ await checkHAProxy(haproxy);
+ } catch (error) {
+ return;
+ }
const transactionId = await getNextTransactionId();
try {
@@ -278,7 +282,11 @@ export async function reloadHaproxy(engine) {
}
export async function configureProxyForApplication({ domain, imageId, applicationId, port }) {
const haproxy = await haproxyInstance();
- await checkHAProxy(haproxy);
+ try {
+ await checkHAProxy(haproxy);
+ } catch (error) {
+ return;
+ }
let serverConfigured = false;
let backendAvailable: any = null;
@@ -358,7 +366,11 @@ export async function configureProxyForApplication({ domain, imageId, applicatio
export async function configureCoolifyProxyOff({ domain }) {
const haproxy = await haproxyInstance();
- await checkHAProxy(haproxy);
+ try {
+ await checkHAProxy(haproxy);
+ } catch (error) {
+ return;
+ }
try {
const transactionId = await getNextTransactionId();
@@ -388,7 +400,11 @@ export async function checkHAProxy(haproxy) {
}
export async function configureCoolifyProxyOn({ domain }) {
const haproxy = await haproxyInstance();
- await checkHAProxy(haproxy);
+ try {
+ await checkHAProxy(haproxy);
+ } catch (error) {
+ return;
+ }
let serverConfigured = false;
let backendAvailable: any = null;
try {
@@ -586,11 +602,7 @@ export async function configureNetworkCoolifyProxy(engine) {
export async function configureSimpleServiceProxyOn({ id, domain, port }) {
const haproxy = await haproxyInstance();
- try {
- await checkHAProxy(haproxy);
- } catch (error) {
- return;
- }
+ await checkHAProxy(haproxy);
try {
await haproxy.get(`v2/services/haproxy/configuration/backends/${domain}`).json();
return;
@@ -627,12 +639,15 @@ export async function configureSimpleServiceProxyOn({ id, domain, port }) {
export async function configureSimpleServiceProxyOff({ domain }) {
const haproxy = await haproxyInstance();
- await checkHAProxy(haproxy);
+ try {
+ await checkHAProxy(haproxy);
+ } catch (error) {
+ return;
+ }
try {
await haproxy.get(`v2/services/haproxy/configuration/backends/${domain}`).json();
const transactionId = await getNextTransactionId();
-
await haproxy
.delete(`v2/services/haproxy/configuration/backends/${domain}`, {
searchParams: {
diff --git a/src/lib/queues/builder.ts b/src/lib/queues/builder.ts
index 9430e786e..aba494d92 100644
--- a/src/lib/queues/builder.ts
+++ b/src/lib/queues/builder.ts
@@ -7,6 +7,7 @@ import { asyncExecShell, createDirectories, getDomain, getEngine, saveBuildLog }
import { configureProxyForApplication, reloadHaproxy } from '../haproxy';
import * as db from '$lib/database';
import { decrypt } from '$lib/crypto';
+import { sentry } from '$lib/common';
import {
copyBaseConfigurationFiles,
makeLabelForStandaloneApplication,
@@ -246,19 +247,22 @@ export default async function (job) {
} catch (error) {
throw new Error(error);
}
-
- if (destinationDockerId && destinationDocker.isCoolifyProxyUsed) {
- saveBuildLog({ line: 'Proxy configuration started!', buildId, applicationId });
- await configureProxyForApplication({ domain, imageId, applicationId, port });
- if (isHttps) await letsEncrypt({ domain, id: applicationId });
- await reloadHaproxy(destinationDocker.engine);
- saveBuildLog({ line: 'Proxy configuration successful!', buildId, applicationId });
- } else {
- saveBuildLog({
- line: 'Coolify Proxy is not configured for this destination. Nothing else to do.',
- buildId,
- applicationId
- });
+ try {
+ if (destinationDockerId && destinationDocker.isCoolifyProxyUsed) {
+ saveBuildLog({ line: 'Proxy configuration started!', buildId, applicationId });
+ await configureProxyForApplication({ domain, imageId, applicationId, port });
+ if (isHttps) await letsEncrypt({ domain, id: applicationId });
+ await reloadHaproxy(destinationDocker.engine);
+ saveBuildLog({ line: 'Proxy configuration successful!', buildId, applicationId });
+ } else {
+ saveBuildLog({
+ line: 'Coolify Proxy is not configured for this destination. Nothing else to do.',
+ buildId,
+ applicationId
+ });
+ }
+ } catch (error) {
+ sentry.captureException(error);
}
}
}
diff --git a/src/lib/queues/cleanup.ts b/src/lib/queues/cleanup.ts
index 14a1d3fa3..e7bd31e1f 100644
--- a/src/lib/queues/cleanup.ts
+++ b/src/lib/queues/cleanup.ts
@@ -1,22 +1,43 @@
import { dev } from '$app/env';
import { asyncExecShell, getEngine } from '$lib/common';
import { prisma } from '$lib/database';
+import { defaultProxyImageHttp, defaultProxyImageTcp } from '$lib/haproxy';
export default async function () {
if (!dev) {
const destinationDockers = await prisma.destinationDocker.findMany();
for (const destinationDocker of destinationDockers) {
const host = getEngine(destinationDocker.engine);
+ // Tagging images with labels
try {
- // await asyncExecShell(`DOCKER_HOST=${host} docker container prune -f`);
+ const images = [
+ `coollabsio/${defaultProxyImageTcp}`,
+ `coollabsio/${defaultProxyImageHttp}`,
+ 'certbot/certbot:latest',
+ 'node:16.14.0-alpine',
+ 'alpine:latest',
+ 'nginx:stable-alpine',
+ 'node:lts',
+ 'php:apache',
+ 'rust:latest'
+ ];
+ for (const image of images) {
+ await asyncExecShell(
+ `DOCKER_HOST=${host} docker pull ${image} && echo "FROM ${image}" | docker build --label coolify.managed="true" -t "${image}" -`
+ );
+ }
+ } catch (error) {}
+ try {
+ await asyncExecShell(`DOCKER_HOST=${host} docker container prune -f`);
} catch (error) {
- //
console.log(error);
}
+ // Cleanup images that are not managed by coolify
try {
- // await asyncExecShell(`DOCKER_HOST=${host} docker image prune -f`);
+ await asyncExecShell(
+ `DOCKER_HOST=${host} docker image prune --filter 'label!=coolify.managed=true' -a -f`
+ );
} catch (error) {
- //
console.log(error);
}
}
diff --git a/src/lib/queues/index.ts b/src/lib/queues/index.ts
index 8a0d0ecb8..e1889bd4f 100644
--- a/src/lib/queues/index.ts
+++ b/src/lib/queues/index.ts
@@ -107,7 +107,7 @@ cron().catch((error) => {
console.log(error);
});
-const buildQueueName = dev ? cuid() : 'build_queue';
+const buildQueueName = 'build_queue';
const buildQueue = new Queue(buildQueueName, connectionOptions);
const buildWorker = new Worker(buildQueueName, async (job) => await builder(job), {
concurrency: 2,
@@ -120,11 +120,8 @@ buildWorker.on('completed', async (job: Bullmq.Job) => {
} catch (err) {
console.log(err);
} finally {
- const workdir = `/tmp/build-sources/${job.data.repository}/${job.data.build_id}`;
+ const workdir = `/tmp/build-sources/${job.data.repository}/`;
await asyncExecShell(`rm -fr ${workdir}`);
- await asyncExecShell(
- `test -f /tmp/build-sources/${job.data.repository}/id.rsa && rm /tmp/build-sources/${job.data.repository}/id.rsa`
- );
}
return;
});
@@ -136,11 +133,8 @@ buildWorker.on('failed', async (job: Bullmq.Job, failedReason) => {
} catch (error) {
console.log(error);
} finally {
- const workdir = `/tmp/build-sources/${job.data.repository}/${job.data.build_id}`;
+ const workdir = `/tmp/build-sources/${job.data.repository}`;
await asyncExecShell(`rm -fr ${workdir}`);
- await asyncExecShell(
- `test -f /tmp/build-sources/${job.data.repository}/id.rsa && rm /tmp/build-sources/${job.data.repository}/id.rsa`
- );
}
saveBuildLog({ line: 'Failed build!', buildId: job.data.build_id, applicationId: job.data.id });
saveBuildLog({
diff --git a/src/routes/destinations/[id]/index.json.ts b/src/routes/destinations/[id]/index.json.ts
index 3b878f9ca..e6fc9d075 100644
--- a/src/routes/destinations/[id]/index.json.ts
+++ b/src/routes/destinations/[id]/index.json.ts
@@ -12,7 +12,8 @@ export const get: RequestHandler = async (event) => {
try {
const destination = await db.getDestination({ id, teamId });
const settings = await db.listSettings();
- const state = await checkContainer(destination.engine, 'coolify-haproxy');
+ const state =
+ destination?.engine && (await checkContainer(destination.engine, 'coolify-haproxy'));
return {
status: 200,
body: {
diff --git a/src/routes/services/[id]/configuration/type.svelte b/src/routes/services/[id]/configuration/type.svelte
index 5fb0a0559..398f6a4d5 100644
--- a/src/routes/services/[id]/configuration/type.svelte
+++ b/src/routes/services/[id]/configuration/type.svelte
@@ -36,6 +36,7 @@
import Wordpress from '$lib/components/svg/services/Wordpress.svelte';
import { goto } from '$app/navigation';
import { post } from '$lib/api';
+ import VaultWarden from '$lib/components/svg/services/VaultWarden.svelte';
const { id } = $page.params;
const from = $page.url.searchParams.get('from');
@@ -71,6 +72,8 @@