diff --git a/package.json b/package.json
index 549e5e7fe..616f39f29 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "coolify",
"description": "An open-source & self-hostable Heroku / Netlify alternative.",
- "version": "2.0.21",
+ "version": "2.0.22",
"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",
diff --git a/src/lib/common.ts b/src/lib/common.ts
index 3ec0c923c..c36196113 100644
--- a/src/lib/common.ts
+++ b/src/lib/common.ts
@@ -103,9 +103,14 @@ export const getUserDetails = async (event, isAdminRequired = true) => {
};
export function getEngine(engine) {
- return engine === '/var/run/docker.sock' ? 'unix:///var/run/docker.sock' : `tcp://${engine}:2375`;
+ return engine === '/var/run/docker.sock' ? 'unix:///var/run/docker.sock' : engine;
}
+// export async function saveSshKey(destination) {
+// return await asyncExecShell(
+// `echo '${destination.sshPrivateKey}' > /tmp/id_rsa_${destination.id} && chmod 600 /tmp/id_rsa_${destination.id}`
+// );
+// }
export async function removeContainer(id, engine) {
const host = getEngine(engine);
try {
diff --git a/src/lib/components/common.ts b/src/lib/components/common.ts
index fd887526a..687819c6d 100644
--- a/src/lib/components/common.ts
+++ b/src/lib/components/common.ts
@@ -15,3 +15,6 @@ export const notNodeDeployments = ['php', 'docker', 'rust'];
export function getDomain(domain) {
return domain?.replace('https://', '').replace('http://', '');
}
+export function generateRemoteEngine(destination) {
+ return `ssh://${destination.user}@${destination.ipAddress}:${destination.port}`;
+}
diff --git a/src/lib/components/svg/applications/Astro.svelte b/src/lib/components/svg/applications/Astro.svelte
new file mode 100644
index 000000000..df8d0804f
--- /dev/null
+++ b/src/lib/components/svg/applications/Astro.svelte
@@ -0,0 +1,21 @@
+
diff --git a/src/lib/components/svg/applications/Eleventy.svelte b/src/lib/components/svg/applications/Eleventy.svelte
new file mode 100644
index 000000000..691a10520
--- /dev/null
+++ b/src/lib/components/svg/applications/Eleventy.svelte
@@ -0,0 +1,6 @@
+
diff --git a/src/lib/database/applications.ts b/src/lib/database/applications.ts
index ffcafbecd..b2d7ceacd 100644
--- a/src/lib/database/applications.ts
+++ b/src/lib/database/applications.ts
@@ -119,7 +119,8 @@ export async function getApplicationWebhook({ projectId, branch }) {
}
export async function getApplicationById({ id }) {
const body = await prisma.application.findFirst({
- where: { id }
+ where: { id },
+ include: { destinationDocker: true }
});
return { ...body };
diff --git a/src/lib/database/destinations.ts b/src/lib/database/destinations.ts
index b566becb4..3f3aadec5 100644
--- a/src/lib/database/destinations.ts
+++ b/src/lib/database/destinations.ts
@@ -1,4 +1,5 @@
import { asyncExecShell, getEngine } from '$lib/common';
+import { decrypt, encrypt } from '$lib/crypto';
import { dockerInstance } from '$lib/docker';
import { startCoolifyProxy } from '$lib/haproxy';
import { getDatabaseImage } from '.';
@@ -47,7 +48,36 @@ export async function updateDestination({ id, name, engine, network }) {
return await prisma.destinationDocker.update({ where: { id }, data: { name, engine, network } });
}
-export async function newDestination({ name, teamId, engine, network, isCoolifyProxyUsed }) {
+export async function newRemoteDestination({
+ name,
+ teamId,
+ engine,
+ network,
+ isCoolifyProxyUsed,
+ remoteEngine,
+ ipAddress,
+ user,
+ port,
+ sshPrivateKey
+}) {
+ const encryptedPrivateKey = encrypt(sshPrivateKey);
+ const destination = await prisma.destinationDocker.create({
+ data: {
+ name,
+ teams: { connect: { id: teamId } },
+ engine,
+ network,
+ isCoolifyProxyUsed,
+ remoteEngine,
+ ipAddress,
+ user,
+ port,
+ sshPrivateKey: encryptedPrivateKey
+ }
+ });
+ return destination.id;
+}
+export async function newLocalDestination({ name, teamId, engine, network, isCoolifyProxyUsed }) {
const host = getEngine(engine);
const docker = dockerInstance({ destinationDocker: { engine, network } });
const found = await docker.engine.listNetworks({ filters: { name: [`^${network}$`] } });
@@ -94,9 +124,13 @@ export async function removeDestination({ id }) {
}
export async function getDestination({ id, teamId }) {
- return await prisma.destinationDocker.findFirst({
+ let destination = await prisma.destinationDocker.findFirst({
where: { id, teams: { some: { id: teamId } } }
});
+ if (destination.remoteEngine) {
+ destination.sshPrivateKey = decrypt(destination.sshPrivateKey);
+ }
+ return destination;
}
export async function getDestinationByApplicationId({ id, teamId }) {
return await prisma.destinationDocker.findFirst({
diff --git a/src/lib/haproxy/index.ts b/src/lib/haproxy/index.ts
index 4e14be487..09d7badd7 100644
--- a/src/lib/haproxy/index.ts
+++ b/src/lib/haproxy/index.ts
@@ -187,6 +187,59 @@ export async function reloadHaproxy(engine) {
const host = getEngine(engine);
return await asyncExecShell(`DOCKER_HOST=${host} docker exec coolify-haproxy kill -HUP 1`);
}
+export async function checkProxyConfigurations() {
+ const haproxy = await haproxyInstance();
+ await checkHAProxy(haproxy);
+ try {
+ const stats: any = await haproxy.get(`v2/services/haproxy/stats/native`).json();
+ for (const stat of stats[0].stats) {
+ if (stat.stats.status === 'DOWN' && stat.type === 'server') {
+ const {
+ name,
+ backend_name: backendName,
+ stats: { lastchg }
+ } = stat;
+ const application = await db.getApplicationById(name);
+ if (!application) {
+ const transactionId = await getNextTransactionId();
+ await haproxy
+ .delete(`v2/services/haproxy/configuration/backends/${backendName}`, {
+ searchParams: {
+ transaction_id: transactionId
+ }
+ })
+ .json();
+ return await completeTransaction(transactionId);
+ }
+ const found = await checkContainer(application.destinationDocker.engine, name);
+ if (!found) {
+ const transactionId = await getNextTransactionId();
+ await haproxy
+ .delete(`v2/services/haproxy/configuration/backends/${backendName}`, {
+ searchParams: {
+ transaction_id: transactionId
+ }
+ })
+ .json();
+ return await completeTransaction(transactionId);
+ }
+ if (lastchg > 120) {
+ const transactionId = await getNextTransactionId();
+ await haproxy
+ .delete(`v2/services/haproxy/configuration/backends/${backendName}`, {
+ searchParams: {
+ transaction_id: transactionId
+ }
+ })
+ .json();
+ await completeTransaction(transactionId);
+ }
+ }
+ }
+ } catch (error) {
+ console.log(error);
+ }
+}
export async function configureProxyForApplication({ domain, imageId, applicationId, port }) {
const haproxy = await haproxyInstance();
await checkHAProxy(haproxy);
diff --git a/src/lib/queues/builder.ts b/src/lib/queues/builder.ts
index c145619be..2bff0ba83 100644
--- a/src/lib/queues/builder.ts
+++ b/src/lib/queues/builder.ts
@@ -4,7 +4,12 @@ import * as buildpacks from '../buildPacks';
import * as importers from '../importers';
import { dockerInstance } from '../docker';
import { asyncExecShell, createDirectories, getDomain, getEngine, saveBuildLog } from '../common';
-import { configureProxyForApplication, reloadHaproxy, setWwwRedirection } from '../haproxy';
+import {
+ checkProxyConfigurations,
+ configureProxyForApplication,
+ reloadHaproxy,
+ setWwwRedirection
+} from '../haproxy';
import * as db from '$lib/database';
import { decrypt } from '$lib/crypto';
import { sentry } from '$lib/common';
@@ -253,6 +258,7 @@ export default async function (job) {
try {
if (destinationDockerId && destinationDocker.isCoolifyProxyUsed) {
saveBuildLog({ line: 'Proxy configuration started!', buildId, applicationId });
+ await checkProxyConfigurations();
await configureProxyForApplication({ domain, imageId, applicationId, port });
if (isHttps) await letsEncrypt({ domain, id: applicationId });
await setWwwRedirection(fqdn);
diff --git a/src/lib/queues/proxy.ts b/src/lib/queues/proxy.ts
index 5f7a8a189..074ac55ab 100644
--- a/src/lib/queues/proxy.ts
+++ b/src/lib/queues/proxy.ts
@@ -3,6 +3,7 @@ import { getApplicationById, prisma, supportedServiceTypesAndVersions } from '$l
import { dockerInstance } from '$lib/docker';
import {
checkContainer,
+ checkProxyConfigurations,
configureCoolifyProxyOn,
configureProxyForApplication,
configureSimpleServiceProxyOn,
@@ -13,13 +14,22 @@ import {
startHttpProxy
} from '$lib/haproxy';
import * as db from '$lib/database';
+// import { generateRemoteEngine } from '$lib/components/common';
export default async function () {
+ try {
+ await checkProxyConfigurations();
+ } catch (error) {
+ console.log(error);
+ }
try {
// Check destination containers and configure proxy if needed
const destinationDockers = await prisma.destinationDocker.findMany({});
for (const destination of destinationDockers) {
if (destination.isCoolifyProxyUsed) {
+ // if (destination.remoteEngine) {
+ // const engine = generateRemoteEngine(destination);
+ // }
const docker = dockerInstance({ destinationDocker: destination });
const containers = await docker.engine.listContainers();
const configurations = containers.filter(
diff --git a/src/routes/__layout.svelte b/src/routes/__layout.svelte
index 093f81d73..eee6acc52 100644
--- a/src/routes/__layout.svelte
+++ b/src/routes/__layout.svelte
@@ -30,7 +30,6 @@
@@ -45,6 +47,10 @@