-
{title}
+
+
diff --git a/src/lib/components/templates.ts b/src/lib/components/templates.ts
index fb52efddb..d6029e4d2 100644
--- a/src/lib/components/templates.ts
+++ b/src/lib/components/templates.ts
@@ -18,7 +18,6 @@ export const buildPacks = [
{
name: 'static',
- ...defaultBuildAndDeploy,
publishDirectory: 'dist',
port: 80,
fancyName: 'Static',
diff --git a/src/lib/database/applications.ts b/src/lib/database/applications.ts
index 738ebe594..ffcafbecd 100644
--- a/src/lib/database/applications.ts
+++ b/src/lib/database/applications.ts
@@ -1,5 +1,5 @@
import { decrypt, encrypt } from '$lib/crypto';
-import { removeProxyConfiguration, removeWwwRedirection } from '$lib/haproxy';
+import { removeProxyConfiguration } from '$lib/haproxy';
import { asyncExecShell, getEngine } from '$lib/common';
import { getDomain, removeDestinationDocker } from '$lib/common';
@@ -209,10 +209,10 @@ export async function configureApplication({
});
}
-export async function setApplicationSettings({ id, debug, previews }) {
+export async function setApplicationSettings({ id, debug, previews, dualCerts }) {
return await prisma.application.update({
where: { id },
- data: { settings: { update: { debug, previews } } },
+ data: { settings: { update: { debug, previews, dualCerts } } },
include: { destinationDocker: true }
});
}
diff --git a/src/lib/database/checks.ts b/src/lib/database/checks.ts
index 7cc066605..d825de701 100644
--- a/src/lib/database/checks.ts
+++ b/src/lib/database/checks.ts
@@ -15,22 +15,41 @@ export async function isDockerNetworkExists({ network }) {
return await prisma.destinationDocker.findFirst({ where: { network } });
}
-export async function isSecretExists({ id, name }) {
- return await prisma.secret.findFirst({ where: { name, applicationId: id } });
+export async function isSecretExists({ id, name, isPRMRSecret }) {
+ return await prisma.secret.findFirst({ where: { name, applicationId: id, isPRMRSecret } });
}
export async function isDomainConfigured({ id, fqdn }) {
const domain = getDomain(fqdn);
+ const nakedDomain = domain.replace('www.', '');
const foundApp = await prisma.application.findFirst({
- where: { fqdn: { endsWith: `//${domain}` }, id: { not: id } },
+ where: {
+ OR: [
+ { fqdn: { endsWith: `//${nakedDomain}` } },
+ { fqdn: { endsWith: `//www.${nakedDomain}` } }
+ ],
+ id: { not: id }
+ },
select: { fqdn: true }
});
const foundService = await prisma.service.findFirst({
- where: { fqdn: { endsWith: `//${domain}` }, id: { not: id } },
+ where: {
+ OR: [
+ { fqdn: { endsWith: `//${nakedDomain}` } },
+ { fqdn: { endsWith: `//www.${nakedDomain}` } }
+ ],
+ id: { not: id }
+ },
select: { fqdn: true }
});
const coolifyFqdn = await prisma.setting.findFirst({
- where: { fqdn: { endsWith: `//${domain}` }, id: { not: id } },
+ where: {
+ OR: [
+ { fqdn: { endsWith: `//${nakedDomain}` } },
+ { fqdn: { endsWith: `//www.${nakedDomain}` } }
+ ],
+ id: { not: id }
+ },
select: { fqdn: true }
});
if (foundApp || foundService || coolifyFqdn) return true;
diff --git a/src/lib/database/common.ts b/src/lib/database/common.ts
index 290ecd2b5..04bf54d6b 100644
--- a/src/lib/database/common.ts
+++ b/src/lib/database/common.ts
@@ -2,6 +2,7 @@ import { dev } from '$app/env';
import { sentry } from '$lib/common';
import * as Prisma from '@prisma/client';
import { default as ProdPrisma } from '@prisma/client';
+import type { PrismaClientOptions } from '@prisma/client/runtime';
import generator from 'generate-password';
import forge from 'node-forge';
@@ -19,28 +20,20 @@ if (!dev) {
PrismaClient = ProdPrisma.PrismaClient;
P = ProdPrisma.Prisma;
}
-let prismaOptions = {
+
+export const prisma = new PrismaClient({
+ errorFormat: 'pretty',
rejectOnNotFound: false
-};
-if (dev) {
- prismaOptions = {
- errorFormat: 'pretty',
- rejectOnNotFound: false,
- log: [
- {
- emit: 'event',
- level: 'query'
- }
- ]
- };
-}
-export const prisma = new PrismaClient(prismaOptions);
+});
export function ErrorHandler(e) {
if (e! instanceof Error) {
e = new Error(e.toString());
}
let truncatedError = e;
+ if (e.stdout) {
+ truncatedError = e.stdout;
+ }
if (e.message?.includes('docker run')) {
let truncatedArray = [];
truncatedArray = truncatedError.message.split('-').filter((line) => {
diff --git a/src/lib/database/secrets.ts b/src/lib/database/secrets.ts
index c03ec9459..167d061f5 100644
--- a/src/lib/database/secrets.ts
+++ b/src/lib/database/secrets.ts
@@ -1,19 +1,41 @@
-import { encrypt } from '$lib/crypto';
+import { encrypt, decrypt } from '$lib/crypto';
import { prisma } from './common';
-export async function listSecrets({ applicationId }) {
- return await prisma.secret.findMany({
+export async function listSecrets(applicationId: string) {
+ let secrets = await prisma.secret.findMany({
where: { applicationId },
- orderBy: { createdAt: 'desc' },
- select: { id: true, createdAt: true, name: true, isBuildSecret: true }
+ orderBy: { createdAt: 'desc' }
+ });
+ secrets = secrets.map((secret) => {
+ secret.value = decrypt(secret.value);
+ return secret;
+ });
+
+ return secrets;
+}
+
+export async function createSecret({ id, name, value, isBuildSecret, isPRMRSecret }) {
+ value = encrypt(value);
+ return await prisma.secret.create({
+ data: { name, value, isBuildSecret, isPRMRSecret, application: { connect: { id } } }
});
}
-export async function createSecret({ id, name, value, isBuildSecret }) {
+export async function updateSecret({ id, name, value, isBuildSecret, isPRMRSecret }) {
value = encrypt(value);
- return await prisma.secret.create({
- data: { name, value, isBuildSecret, application: { connect: { id } } }
- });
+ const found = await prisma.secret.findFirst({ where: { applicationId: id, name, isPRMRSecret } });
+ console.log(found);
+
+ if (found) {
+ return await prisma.secret.updateMany({
+ where: { applicationId: id, name, isPRMRSecret },
+ data: { value, isBuildSecret, isPRMRSecret }
+ });
+ } else {
+ return await prisma.secret.create({
+ data: { name, value, isBuildSecret, isPRMRSecret, application: { connect: { id } } }
+ });
+ }
}
export async function removeSecret({ id, name }) {
diff --git a/src/lib/database/services.ts b/src/lib/database/services.ts
index 5568cd4a7..5cbf2cbfb 100644
--- a/src/lib/database/services.ts
+++ b/src/lib/database/services.ts
@@ -107,13 +107,20 @@ export async function configureServiceType({ id, type }) {
});
}
}
-export async function setService({ id, version }) {
+export async function setServiceVersion({ id, version }) {
return await prisma.service.update({
where: { id },
data: { version }
});
}
+export async function setServiceSettings({ id, dualCerts }) {
+ return await prisma.service.update({
+ where: { id },
+ data: { dualCerts }
+ });
+}
+
export async function updatePlausibleAnalyticsService({ id, fqdn, email, username, name }) {
await prisma.plausibleAnalytics.update({ where: { serviceId: id }, data: { email, username } });
await prisma.service.update({ where: { id }, data: { name, fqdn } });
diff --git a/src/lib/database/users.ts b/src/lib/database/users.ts
index 5c99143a9..9c09d0aaf 100644
--- a/src/lib/database/users.ts
+++ b/src/lib/database/users.ts
@@ -6,19 +6,23 @@ import { asyncExecShell, uniqueName } from '$lib/common';
import * as db from '$lib/database';
import { startCoolifyProxy } from '$lib/haproxy';
-
-export async function login({ email, password }) {
+export async function hashPassword(password: string) {
const saltRounds = 15;
+ return bcrypt.hash(password, saltRounds);
+}
+export async function login({ email, password }) {
const users = await prisma.user.count();
const userFound = await prisma.user.findUnique({
where: { email },
- include: { teams: true },
+ include: { teams: true, permission: true },
rejectOnNotFound: false
});
// Registration disabled if database is not seeded properly
const { isRegistrationEnabled, id } = await db.listSettings();
let uid = cuid();
+ let permission = 'read';
+ let isAdmin = false;
// Disable registration if we are registering the first user.
if (users === 0) {
await prisma.setting.update({ where: { id }, data: { isRegistrationEnabled: false } });
@@ -50,6 +54,8 @@ export async function login({ email, password }) {
};
}
uid = userFound.id;
+ // permission = userFound.permission;
+ isAdmin = true;
}
} else {
// If registration disabled, return 403
@@ -59,8 +65,10 @@ export async function login({ email, password }) {
};
}
- const hashedPassword = await bcrypt.hash(password, saltRounds);
+ const hashedPassword = await hashPassword(password);
if (users === 0) {
+ permission = 'owner';
+ isAdmin = true;
await prisma.user.create({
data: {
id: uid,
@@ -103,8 +111,10 @@ export async function login({ email, password }) {
'Set-Cookie': `teamId=${uid}; HttpOnly; Path=/; Max-Age=15778800;`
},
body: {
- uid,
- teamId: uid
+ userId: uid,
+ teamId: uid,
+ permission,
+ isAdmin
}
};
}
diff --git a/src/lib/docker.ts b/src/lib/docker.ts
index 52f5d1bef..b3cf89e37 100644
--- a/src/lib/docker.ts
+++ b/src/lib/docker.ts
@@ -13,15 +13,24 @@ export async function buildCacheImageWithNode(data, imageForBuild) {
installCommand,
buildCommand,
debug,
- secrets
+ secrets,
+ pullmergeRequestId
} = data;
const Dockerfile: Array
= [];
Dockerfile.push(`FROM ${imageForBuild}`);
Dockerfile.push('WORKDIR /usr/src/app');
if (secrets.length > 0) {
secrets.forEach((secret) => {
- if (!secret.isBuildSecret) {
- Dockerfile.push(`ARG ${secret.name} ${secret.value}`);
+ if (secret.isBuildSecret) {
+ if (pullmergeRequestId) {
+ if (secret.isPRMRSecret) {
+ Dockerfile.push(`ARG ${secret.name} ${secret.value}`);
+ }
+ } else {
+ if (!secret.isPRMRSecret) {
+ Dockerfile.push(`ARG ${secret.name} ${secret.value}`);
+ }
+ }
}
});
}
diff --git a/src/lib/haproxy/index.ts b/src/lib/haproxy/index.ts
index 0eaee0109..4e14be487 100644
--- a/src/lib/haproxy/index.ts
+++ b/src/lib/haproxy/index.ts
@@ -2,7 +2,6 @@ import { dev } from '$app/env';
import { asyncExecShell, getDomain, getEngine } from '$lib/common';
import got from 'got';
import * as db from '$lib/database';
-import { letsEncrypt } from '$lib/letsencrypt';
const url = dev ? 'http://localhost:5555' : 'http://coolify-haproxy:5555';
@@ -49,7 +48,8 @@ export async function completeTransaction(transactionId) {
return await haproxy.put(`v2/services/haproxy/transactions/${transactionId}`);
}
-export async function removeProxyConfiguration({ domain }) {
+export async function removeProxyConfiguration(fqdn) {
+ const domain = getDomain(fqdn);
const haproxy = await haproxyInstance();
const backendFound = await haproxy
.get(`v2/services/haproxy/configuration/backends/${domain}`)
@@ -65,97 +65,92 @@ export async function removeProxyConfiguration({ domain }) {
.json();
await completeTransaction(transactionId);
}
- await removeWwwRedirection(domain);
+ await forceSSLOffApplication(domain);
+ await removeWwwRedirection(fqdn);
}
-export async function forceSSLOffApplication({ domain }) {
- if (!dev) {
- const haproxy = await haproxyInstance();
- await checkHAProxy(haproxy);
- let transactionId;
- try {
- const rules: any = await haproxy
- .get(`v2/services/haproxy/configuration/http_request_rules`, {
- searchParams: {
- parent_name: 'http',
- parent_type: 'frontend'
- }
- })
- .json();
- if (rules.data.length > 0) {
- const rule = rules.data.find((rule) => rule.cond_test.includes(`-i ${domain}`));
- if (rule) {
- transactionId = await getNextTransactionId();
-
- await haproxy
- .delete(`v2/services/haproxy/configuration/http_request_rules/${rule.index}`, {
- searchParams: {
- transaction_id: transactionId,
- parent_name: 'http',
- parent_type: 'frontend'
- }
- })
- .json();
+export async function forceSSLOffApplication(domain) {
+ const haproxy = await haproxyInstance();
+ await checkHAProxy(haproxy);
+ let transactionId;
+ try {
+ const rules: any = await haproxy
+ .get(`v2/services/haproxy/configuration/http_request_rules`, {
+ searchParams: {
+ parent_name: 'http',
+ parent_type: 'frontend'
}
+ })
+ .json();
+ if (rules.data.length > 0) {
+ const rule = rules.data.find((rule) =>
+ rule.cond_test.includes(`{ hdr(host) -i ${domain} } !{ ssl_fc }`)
+ );
+ if (rule) {
+ transactionId = await getNextTransactionId();
+
+ await haproxy
+ .delete(`v2/services/haproxy/configuration/http_request_rules/${rule.index}`, {
+ searchParams: {
+ transaction_id: transactionId,
+ parent_name: 'http',
+ parent_type: 'frontend'
+ }
+ })
+ .json();
}
- } catch (error) {
- console.log(error);
- } finally {
- if (transactionId) await completeTransaction(transactionId);
}
- } else {
- console.log(`[DEBUG] Removing ssl for ${domain}`);
+ } catch (error) {
+ console.log(error);
+ } finally {
+ if (transactionId) await completeTransaction(transactionId);
}
}
-export async function forceSSLOnApplication({ domain }) {
- if (!dev) {
- const haproxy = await haproxyInstance();
- await checkHAProxy(haproxy);
- let transactionId;
- try {
- const rules: any = await haproxy
- .get(`v2/services/haproxy/configuration/http_request_rules`, {
- searchParams: {
- parent_name: 'http',
- parent_type: 'frontend'
- }
- })
- .json();
- let nextRule = 0;
- if (rules.data.length > 0) {
- const rule = rules.data.find((rule) =>
- rule.cond_test.includes(`{ hdr(host) -i ${domain} } !{ ssl_fc }`)
- );
- if (rule) return;
- nextRule = rules.data[rules.data.length - 1].index + 1;
- }
- transactionId = await getNextTransactionId();
-
- await haproxy
- .post(`v2/services/haproxy/configuration/http_request_rules`, {
- searchParams: {
- transaction_id: transactionId,
- parent_name: 'http',
- parent_type: 'frontend'
- },
- json: {
- index: nextRule,
- cond: 'if',
- cond_test: `{ hdr(host) -i ${domain} } !{ ssl_fc }`,
- type: 'redirect',
- redir_type: 'scheme',
- redir_value: 'https',
- redir_code: 301
- }
- })
- .json();
- } catch (error) {
- console.log(error);
- throw error;
- } finally {
- if (transactionId) await completeTransaction(transactionId);
+export async function forceSSLOnApplication(domain) {
+ const haproxy = await haproxyInstance();
+ await checkHAProxy(haproxy);
+ let transactionId;
+ try {
+ const rules: any = await haproxy
+ .get(`v2/services/haproxy/configuration/http_request_rules`, {
+ searchParams: {
+ parent_name: 'http',
+ parent_type: 'frontend'
+ }
+ })
+ .json();
+ let nextRule = 0;
+ if (rules.data.length > 0) {
+ const rule = rules.data.find((rule) =>
+ rule.cond_test.includes(`{ hdr(host) -i ${domain} } !{ ssl_fc }`)
+ );
+ if (rule) return;
+ nextRule = rules.data[rules.data.length - 1].index + 1;
}
- } else {
- console.log(`[DEBUG] Adding ssl for ${domain}`);
+ transactionId = await getNextTransactionId();
+
+ await haproxy
+ .post(`v2/services/haproxy/configuration/http_request_rules`, {
+ searchParams: {
+ transaction_id: transactionId,
+ parent_name: 'http',
+ parent_type: 'frontend'
+ },
+ json: {
+ index: nextRule,
+ cond: 'if',
+ cond_test: `{ hdr(host) -i ${domain} } !{ ssl_fc }`,
+ type: 'redirect',
+ redir_type: 'scheme',
+ redir_value: 'https',
+ redir_code: dev ? 302 : 301
+ }
+ })
+ .json();
+ } catch (error) {
+ console.log(error);
+ throw error;
+ } finally {
+ if (transactionId) await completeTransaction(transactionId);
}
}
@@ -274,6 +269,7 @@ export async function configureProxyForApplication({ domain, imageId, applicatio
export async function configureCoolifyProxyOff(fqdn) {
const domain = getDomain(fqdn);
+ const isHttps = fqdn.startsWith('https://');
const haproxy = await haproxyInstance();
await checkHAProxy(haproxy);
@@ -288,10 +284,8 @@ export async function configureCoolifyProxyOff(fqdn) {
})
.json();
await completeTransaction(transactionId);
- if (!dev) {
- await forceSSLOffApplication({ domain });
- }
- await setWwwRedirection(fqdn);
+ if (isHttps) await forceSSLOffApplication(domain);
+ await removeWwwRedirection(fqdn);
} catch (error) {
throw error?.response?.body || error;
}
@@ -565,7 +559,8 @@ export async function configureSimpleServiceProxyOn({ id, domain, port }) {
await completeTransaction(transactionId);
}
-export async function configureSimpleServiceProxyOff({ domain }) {
+export async function configureSimpleServiceProxyOff(fqdn) {
+ const domain = getDomain(fqdn);
const haproxy = await haproxyInstance();
await checkHAProxy(haproxy);
try {
@@ -580,11 +575,16 @@ export async function configureSimpleServiceProxyOff({ domain }) {
.json();
await completeTransaction(transactionId);
} catch (error) {}
- await removeWwwRedirection(domain);
+ await forceSSLOffApplication(domain);
+ await removeWwwRedirection(fqdn);
return;
}
-export async function removeWwwRedirection(domain) {
+export async function removeWwwRedirection(fqdn) {
+ const domain = getDomain(fqdn);
+ const isHttps = fqdn.startsWith('https://');
+ const redirectValue = `${isHttps ? 'https://' : 'http://'}${domain}%[capture.req.uri]`;
+
const haproxy = await haproxyInstance();
await checkHAProxy();
const rules: any = await haproxy
@@ -596,9 +596,7 @@ export async function removeWwwRedirection(domain) {
})
.json();
if (rules.data.length > 0) {
- const rule = rules.data.find((rule) =>
- rule.redir_value.includes(`${domain}%[capture.req.uri]`)
- );
+ const rule = rules.data.find((rule) => rule.redir_value.includes(redirectValue));
if (rule) {
const transactionId = await getNextTransactionId();
await haproxy
@@ -623,6 +621,7 @@ export async function setWwwRedirection(fqdn) {
const domain = getDomain(fqdn);
const isHttps = fqdn.startsWith('https://');
const isWWW = fqdn.includes('www.');
+ const redirectValue = `${isHttps ? 'https://' : 'http://'}${domain}%[capture.req.uri]`;
const contTest = `{ req.hdr(host) -i ${isWWW ? domain.replace('www.', '') : `www.${domain}`} }`;
const rules: any = await haproxy
.get(`v2/services/haproxy/configuration/http_request_rules`, {
@@ -634,13 +633,11 @@ export async function setWwwRedirection(fqdn) {
.json();
let nextRule = 0;
if (rules.data.length > 0) {
- const rule = rules.data.find((rule) =>
- rule.redir_value.includes(`${domain}%[capture.req.uri]`)
- );
+ const rule = rules.data.find((rule) => rule.redir_value.includes(redirectValue));
if (rule) return;
nextRule = rules.data[rules.data.length - 1].index + 1;
}
- const redirectValue = `${isHttps ? 'https://' : 'http://'}${domain}%[capture.req.uri]`;
+
transactionId = await getNextTransactionId();
await haproxy
.post(`v2/services/haproxy/configuration/http_request_rules`, {
diff --git a/src/lib/letsencrypt.ts b/src/lib/letsencrypt.ts
index 86d9e6e25..dc4c9d6f7 100644
--- a/src/lib/letsencrypt.ts
+++ b/src/lib/letsencrypt.ts
@@ -1,50 +1,78 @@
import { dev } from '$app/env';
-import { forceSSLOffApplication, forceSSLOnApplication, getNextTransactionId } from '$lib/haproxy';
+import { forceSSLOffApplication, forceSSLOnApplication } from '$lib/haproxy';
import { asyncExecShell, getEngine } from './common';
import * as db from '$lib/database';
import cuid from 'cuid';
+import getPort from 'get-port';
export async function letsEncrypt({ domain, isCoolify = false, id = null }) {
try {
+ const nakedDomain = domain.replace('www.', '');
+ const wwwDomain = `www.${nakedDomain}`;
const randomCuid = cuid();
- if (dev) {
- return await forceSSLOnApplication({ domain });
- } else {
- if (isCoolify) {
- await asyncExecShell(
- `docker run --rm --name certbot-${randomCuid} -p 9080:9080 -v "coolify-letsencrypt:/etc/letsencrypt" certbot/certbot --logs-dir /etc/letsencrypt/logs certonly --standalone --preferred-challenges http --http-01-address 0.0.0.0 --http-01-port 9080 -d ${domain} --agree-tos --non-interactive --register-unsafely-without-email`
- );
+ const randomPort = 9080;
- const { stderr } = await asyncExecShell(
- `docker run --rm -v "coolify-letsencrypt:/etc/letsencrypt" -v "coolify-ssl-certs:/app/ssl" alpine:latest cat /etc/letsencrypt/live/${domain}/fullchain.pem /etc/letsencrypt/live/${domain}/privkey.pem > /app/ssl/${domain}.pem`
- );
- if (stderr) throw new Error(stderr);
- return;
+ let host;
+ let dualCerts = false;
+ if (isCoolify) {
+ const data = await db.prisma.setting.findFirst();
+ dualCerts = data.dualCerts;
+ host = 'unix:///var/run/docker.sock';
+ } else {
+ // Check Application
+ const applicationData = await db.prisma.application.findUnique({
+ where: { id },
+ include: { destinationDocker: true, settings: true }
+ });
+ if (applicationData) {
+ if (applicationData?.destinationDockerId && applicationData?.destinationDocker) {
+ host = getEngine(applicationData.destinationDocker.engine);
+ }
+ if (applicationData?.settings?.dualCerts) {
+ dualCerts = applicationData.settings.dualCerts;
+ }
}
- let data: any = await db.prisma.application.findUnique({
+ // Check Service
+ const serviceData = await db.prisma.service.findUnique({
where: { id },
include: { destinationDocker: true }
});
- if (!data) {
- data = await db.prisma.service.findUnique({
- where: { id },
- include: { destinationDocker: true }
- });
- }
- // Set SSL with Let's encrypt
- if (data.destinationDockerId && data.destinationDocker) {
- const host = getEngine(data.destinationDocker.engine);
- await asyncExecShell(
- `DOCKER_HOST=${host} docker run --rm --name certbot-${randomCuid} -p 9080:9080 -v "coolify-letsencrypt:/etc/letsencrypt" certbot/certbot --logs-dir /etc/letsencrypt/logs certonly --standalone --preferred-challenges http --http-01-address 0.0.0.0 --http-01-port 9080 -d ${domain} --agree-tos --non-interactive --register-unsafely-without-email`
- );
- const { stderr } = await asyncExecShell(
- `DOCKER_HOST=${host} docker run --rm --name bash-${randomCuid} -v "coolify-letsencrypt:/etc/letsencrypt" -v "coolify-ssl-certs:/app/ssl" alpine:latest cat /etc/letsencrypt/live/${domain}/fullchain.pem /etc/letsencrypt/live/${domain}/privkey.pem > /app/ssl/${domain}.pem`
- );
- if (stderr) throw new Error(stderr);
- await forceSSLOnApplication({ domain });
+ if (serviceData) {
+ if (serviceData?.destinationDockerId && serviceData?.destinationDocker) {
+ host = getEngine(serviceData.destinationDocker.engine);
+ }
+ if (serviceData?.dualCerts) {
+ dualCerts = serviceData.dualCerts;
+ }
}
}
+ await forceSSLOffApplication(domain);
+ if (dualCerts) {
+ await asyncExecShell(
+ `DOCKER_HOST=${host} docker run --rm --name certbot-${randomCuid} -p 9080:${randomPort} -v "coolify-letsencrypt:/etc/letsencrypt" certbot/certbot --logs-dir /etc/letsencrypt/logs certonly --standalone --preferred-challenges http --http-01-address 0.0.0.0 --http-01-port ${randomPort} -d ${nakedDomain} -d ${wwwDomain} --expand --agree-tos --non-interactive --register-unsafely-without-email ${
+ dev ? '--test-cert' : ''
+ }`
+ );
+ await asyncExecShell(
+ `DOCKER_HOST=${host} docker run --rm -v "coolify-letsencrypt:/etc/letsencrypt" -v "coolify-ssl-certs:/app/ssl" alpine:latest sh -c "test -d /etc/letsencrypt/live/${nakedDomain}/ && cat /etc/letsencrypt/live/${nakedDomain}/fullchain.pem /etc/letsencrypt/live/${nakedDomain}/privkey.pem > /app/ssl/${nakedDomain}.pem || cat /etc/letsencrypt/live/${wwwDomain}/fullchain.pem /etc/letsencrypt/live/${wwwDomain}/privkey.pem > /app/ssl/${wwwDomain}.pem"`
+ );
+ } else {
+ await asyncExecShell(
+ `DOCKER_HOST=${host} docker run --rm --name certbot-${randomCuid} -p 9080:${randomPort} -v "coolify-letsencrypt:/etc/letsencrypt" certbot/certbot --logs-dir /etc/letsencrypt/logs certonly --standalone --preferred-challenges http --http-01-address 0.0.0.0 --http-01-port ${randomPort} -d ${domain} --expand --agree-tos --non-interactive --register-unsafely-without-email ${
+ dev ? '--test-cert' : ''
+ }`
+ );
+ await asyncExecShell(
+ `DOCKER_HOST=${host} docker run --rm -v "coolify-letsencrypt:/etc/letsencrypt" -v "coolify-ssl-certs:/app/ssl" alpine:latest sh -c "cat /etc/letsencrypt/live/${domain}/fullchain.pem /etc/letsencrypt/live/${domain}/privkey.pem > /app/ssl/${domain}.pem"`
+ );
+ }
} catch (error) {
- throw error;
+ if (error.code !== 0) {
+ throw error;
+ }
+ } finally {
+ if (!isCoolify) {
+ await forceSSLOnApplication(domain);
+ }
}
}
diff --git a/src/lib/queues/builder.ts b/src/lib/queues/builder.ts
index 41b11dc1e..c145619be 100644
--- a/src/lib/queues/builder.ts
+++ b/src/lib/queues/builder.ts
@@ -64,7 +64,6 @@ export default async function (job) {
if (destinationDockerId) {
destinationType = 'docker';
}
-
if (destinationType === 'docker') {
const docker = dockerInstance({ destinationDocker });
const host = getEngine(destinationDocker.engine);
@@ -205,7 +204,15 @@ export default async function (job) {
const envs = [];
if (secrets.length > 0) {
secrets.forEach((secret) => {
- envs.push(`${secret.name}=${secret.value}`);
+ if (pullmergeRequestId) {
+ if (secret.isPRMRSecret) {
+ envs.push(`${secret.name}=${secret.value}`);
+ }
+ } else {
+ if (!secret.isPRMRSecret) {
+ envs.push(`${secret.name}=${secret.value}`);
+ }
+ }
});
}
await fs.writeFile(`${workdir}/.env`, envs.join('\n'));
@@ -239,6 +246,8 @@ export default async function (job) {
if (stderr) console.log(stderr);
saveBuildLog({ line: 'Deployment successful!', buildId, applicationId });
} catch (error) {
+ saveBuildLog({ line: error, buildId, applicationId });
+ sentry.captureException(error);
throw new Error(error);
}
try {
@@ -257,7 +266,9 @@ export default async function (job) {
});
}
} catch (error) {
+ saveBuildLog({ line: error.stdout || error, buildId, applicationId });
sentry.captureException(error);
+ throw new Error(error);
}
}
}
diff --git a/src/lib/queues/index.ts b/src/lib/queues/index.ts
index f8525c4e0..3d0dda4f1 100644
--- a/src/lib/queues/index.ts
+++ b/src/lib/queues/index.ts
@@ -127,7 +127,6 @@ buildWorker.on('completed', async (job: Bullmq.Job) => {
});
buildWorker.on('failed', async (job: Bullmq.Job, failedReason) => {
- console.log(failedReason);
try {
await prisma.build.update({ where: { id: job.data.build_id }, data: { status: 'failed' } });
} catch (error) {
@@ -136,7 +135,11 @@ buildWorker.on('failed', async (job: Bullmq.Job, failedReason) => {
const workdir = `/tmp/build-sources/${job.data.repository}`;
await asyncExecShell(`rm -fr ${workdir}`);
}
- saveBuildLog({ line: 'Failed build!', buildId: job.data.build_id, applicationId: job.data.id });
+ saveBuildLog({
+ line: 'Failed to deploy!',
+ buildId: job.data.build_id,
+ applicationId: job.data.id
+ });
saveBuildLog({
line: `Reason: ${failedReason.toString()}`,
buildId: job.data.build_id,
diff --git a/src/lib/queues/proxy.ts b/src/lib/queues/proxy.ts
index 92d14f738..36ac37ff9 100644
--- a/src/lib/queues/proxy.ts
+++ b/src/lib/queues/proxy.ts
@@ -48,7 +48,7 @@ export default async function () {
port
});
const isHttps = fqdn.startsWith('https://');
- if (isHttps) await forceSSLOnApplication({ domain });
+ if (isHttps) await forceSSLOnApplication(domain);
await setWwwRedirection(fqdn);
}
}
@@ -98,7 +98,7 @@ export default async function () {
await configureCoolifyProxyOn(fqdn);
await setWwwRedirection(fqdn);
const isHttps = fqdn.startsWith('https://');
- if (isHttps) await forceSSLOnApplication({ domain });
+ if (isHttps) await forceSSLOnApplication(domain);
}
} catch (error) {
console.log(error);
diff --git a/src/lib/settings.ts b/src/lib/settings.ts
index d9e7cff2c..79742e434 100644
--- a/src/lib/settings.ts
+++ b/src/lib/settings.ts
@@ -1,5 +1,7 @@
export const publicPaths = [
'/login',
+ '/reset',
+ '/reset/password',
'/webhooks/success',
'/webhooks/github',
'/webhooks/github/install',
diff --git a/src/routes/__layout.svelte b/src/routes/__layout.svelte
index 027a11e3d..04310b8b3 100644
--- a/src/routes/__layout.svelte
+++ b/src/routes/__layout.svelte
@@ -2,14 +2,14 @@
import type { Load } from '@sveltejs/kit';
import { publicPaths } from '$lib/settings';
- export const load: Load = async ({ fetch, url, params, session }) => {
- if (!session.uid && !publicPaths.includes(url.pathname)) {
+ export const load: Load = async ({ fetch, url, session }) => {
+ if (!session.userId && !publicPaths.includes(url.pathname)) {
return {
status: 302,
redirect: '/login'
};
}
- if (!session.uid) {
+ if (!session.userId) {
return {};
}
const endpoint = `/teams.json`;
@@ -49,7 +49,7 @@
};
let latestVersion = 'latest';
onMount(async () => {
- if ($session.uid) {
+ if ($session.userId) {
const overrideVersion = browser && window.localStorage.getItem('latestVersion');
try {
await get(`/login.json`);
@@ -84,7 +84,7 @@
}
async function switchTeam() {
try {
- await post(`/index.json?from=${$page.url.pathname}`, {
+ await post(`/dashboard.json?from=${$page.url.pathname}`, {
cookie: 'teamId',
value: selectedTeamId
});
@@ -129,7 +129,7 @@
Coolify
-{#if $session.uid}
+{#if $session.userId}