diff --git a/package.json b/package.json
index e03c678b0..50dba74e9 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.13",
+ "version": "2.0.14",
"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",
@@ -76,6 +76,7 @@
"jsonwebtoken": "8.5.1",
"node-forge": "1.2.1",
"svelte-kit-cookie-session": "2.0.2",
+ "tailwindcss-scrollbar": "^0.1.0",
"unique-names-generator": "4.6.0"
},
"prisma": {
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 58ddfd8c6..b6e75d0bc 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -43,9 +43,10 @@ specifiers:
prisma: 3.9.2
svelte: 3.46.4
svelte-check: 2.4.3
- svelte-kit-cookie-session: 2.0.5
+ svelte-kit-cookie-session: 2.0.2
svelte-preprocess: 4.10.3
tailwindcss: 3.0.22
+ tailwindcss-scrollbar: ^0.1.0
ts-node: 10.5.0
tslib: 2.3.1
typescript: 4.5.5
@@ -70,7 +71,8 @@ dependencies:
js-yaml: 4.1.0
jsonwebtoken: 8.5.1
node-forge: 1.2.1
- svelte-kit-cookie-session: 2.0.5
+ svelte-kit-cookie-session: 2.0.2
+ tailwindcss-scrollbar: 0.1.0_tailwindcss@3.0.22
unique-names-generator: 4.6.0
devDependencies:
@@ -5203,10 +5205,10 @@ packages:
svelte: 3.46.4
dev: true
- /svelte-kit-cookie-session/2.0.5:
+ /svelte-kit-cookie-session/2.0.2:
resolution:
{
- integrity: sha512-IX1IXtn42UTz/isem1LqH0SAZdCx6Z6Iu2V4Q83V2EScFbXZWfeFY08Azl8ZrPKdIDhSNHBLAAumRjA6TBxCvQ==
+ integrity: sha512-+JfunYbraIOkecOJlC1iYqH9g6YOY8MXyUdE3hTZquR1JrODmOZZ+pVPmZuVIFpM5sStJf/jF1NT5306TWE9Gw==
}
dev: false
@@ -5288,6 +5290,17 @@ packages:
strip-ansi: 6.0.1
dev: true
+ /tailwindcss-scrollbar/0.1.0_tailwindcss@3.0.22:
+ resolution:
+ {
+ integrity: sha512-egipxw4ooQDh94x02XQpPck0P0sfwazwoUGfA9SedPATIuYDR+6qe8d31Gl7YsSMRiOKDkkqfI0kBvEw9lT/Hg==
+ }
+ peerDependencies:
+ tailwindcss: '>= 2.x.x'
+ dependencies:
+ tailwindcss: 3.0.22_c940fbabf228b85b1c73d314b43e31f1
+ dev: false
+
/tailwindcss/3.0.22_c940fbabf228b85b1c73d314b43e31f1:
resolution:
{
diff --git a/prisma/migrations/20220217211304_dualcerts/migration.sql b/prisma/migrations/20220217211304_dualcerts/migration.sql
new file mode 100644
index 000000000..a6ea0a57d
--- /dev/null
+++ b/prisma/migrations/20220217211304_dualcerts/migration.sql
@@ -0,0 +1,47 @@
+-- RedefineTables
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_Setting" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "fqdn" TEXT,
+ "isRegistrationEnabled" BOOLEAN NOT NULL DEFAULT false,
+ "dualCerts" BOOLEAN NOT NULL DEFAULT false,
+ "proxyPassword" TEXT NOT NULL,
+ "proxyUser" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL
+);
+INSERT INTO "new_Setting" ("createdAt", "fqdn", "id", "isRegistrationEnabled", "proxyPassword", "proxyUser", "updatedAt") SELECT "createdAt", "fqdn", "id", "isRegistrationEnabled", "proxyPassword", "proxyUser", "updatedAt" FROM "Setting";
+DROP TABLE "Setting";
+ALTER TABLE "new_Setting" RENAME TO "Setting";
+CREATE UNIQUE INDEX "Setting_fqdn_key" ON "Setting"("fqdn");
+CREATE TABLE "new_ApplicationSettings" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "applicationId" TEXT NOT NULL,
+ "dualCerts" BOOLEAN NOT NULL DEFAULT false,
+ "debug" BOOLEAN NOT NULL DEFAULT false,
+ "previews" BOOLEAN NOT NULL DEFAULT false,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "ApplicationSettings_applicationId_fkey" FOREIGN KEY ("applicationId") REFERENCES "Application" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+INSERT INTO "new_ApplicationSettings" ("applicationId", "createdAt", "debug", "id", "previews", "updatedAt") SELECT "applicationId", "createdAt", "debug", "id", "previews", "updatedAt" FROM "ApplicationSettings";
+DROP TABLE "ApplicationSettings";
+ALTER TABLE "new_ApplicationSettings" RENAME TO "ApplicationSettings";
+CREATE UNIQUE INDEX "ApplicationSettings_applicationId_key" ON "ApplicationSettings"("applicationId");
+CREATE TABLE "new_Service" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "name" TEXT NOT NULL,
+ "fqdn" TEXT,
+ "dualCerts" BOOLEAN NOT NULL DEFAULT false,
+ "type" TEXT,
+ "version" TEXT,
+ "destinationDockerId" TEXT,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "Service_destinationDockerId_fkey" FOREIGN KEY ("destinationDockerId") REFERENCES "DestinationDocker" ("id") ON DELETE SET NULL ON UPDATE CASCADE
+);
+INSERT INTO "new_Service" ("createdAt", "destinationDockerId", "fqdn", "id", "name", "type", "updatedAt", "version") SELECT "createdAt", "destinationDockerId", "fqdn", "id", "name", "type", "updatedAt", "version" FROM "Service";
+DROP TABLE "Service";
+ALTER TABLE "new_Service" RENAME TO "Service";
+PRAGMA foreign_key_check;
+PRAGMA foreign_keys=ON;
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
index b064d09ab..cf9684f53 100644
--- a/prisma/schema.prisma
+++ b/prisma/schema.prisma
@@ -11,6 +11,7 @@ model Setting {
id String @id @default(cuid())
fqdn String? @unique
isRegistrationEnabled Boolean @default(false)
+ dualCerts Boolean @default(false)
proxyPassword String
proxyUser String
createdAt DateTime @default(now())
@@ -97,6 +98,7 @@ model ApplicationSettings {
id String @id @default(cuid())
application Application @relation(fields: [applicationId], references: [id])
applicationId String @unique
+ dualCerts Boolean @default(false)
debug Boolean @default(false)
previews Boolean @default(false)
createdAt DateTime @default(now())
@@ -105,7 +107,7 @@ model ApplicationSettings {
model Secret {
id String @id @default(cuid())
- name String
+ name String
value String
isBuildSecret Boolean @default(false)
createdAt DateTime @default(now())
@@ -234,6 +236,7 @@ model Service {
id String @id @default(cuid())
name String
fqdn String?
+ dualCerts Boolean @default(false)
type String?
version String?
teams Team[]
diff --git a/src/lib/components/Explainer.svelte b/src/lib/components/Explainer.svelte
index 4eaf3a398..b47c03ec1 100644
--- a/src/lib/components/Explainer.svelte
+++ b/src/lib/components/Explainer.svelte
@@ -1,6 +1,6 @@
-
{@html text}
+{@html text}
diff --git a/src/lib/components/Setting.svelte b/src/lib/components/Setting.svelte
index b26e3e072..c431273e6 100644
--- a/src/lib/components/Setting.svelte
+++ b/src/lib/components/Setting.svelte
@@ -4,15 +4,17 @@
export let setting;
export let title;
export let description;
- export let isPadding = true;
+ export let isCenter = true;
export let disabled = false;
-
-
-
{title}
+
+
diff --git a/src/lib/database/applications.ts b/src/lib/database/applications.ts
index 738ebe594..f2e779bee 100644
--- a/src/lib/database/applications.ts
+++ b/src/lib/database/applications.ts
@@ -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/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/haproxy/index.ts b/src/lib/haproxy/index.ts
index 0eaee0109..0daf1d493 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';
diff --git a/src/lib/letsencrypt.ts b/src/lib/letsencrypt.ts
index 6e166d8f2..6ee29f812 100644
--- a/src/lib/letsencrypt.ts
+++ b/src/lib/letsencrypt.ts
@@ -3,49 +3,70 @@ import { 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 });
+ const randomPort = getPort();
+
+ let host;
+ let dualCerts = false;
+ if (isCoolify) {
+ const data = await db.prisma.setting.findFirst();
+ dualCerts = data.dualCerts;
+ host = '/var/run/docker.sock';
} 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 ${nakedDomain} -d ${wwwDomain} --expand --agree-tos --non-interactive --register-unsafely-without-email`
- );
-
- const { stderr: copyError } = await asyncExecShell(
- `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"`
- );
-
- if (copyError) throw copyError;
- return;
+ // 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 }
- });
+ if (serviceData) {
+ if (serviceData?.destinationDockerId && serviceData?.destinationDocker) {
+ host = getEngine(serviceData.destinationDocker.engine);
+ }
+ if (serviceData?.dualCerts) {
+ dualCerts = serviceData.dualCerts;
+ }
}
- // Set SSL with Let's encrypt
- if (data.destinationDockerId && data.destinationDocker) {
- const host = getEngine(data.destinationDocker.engine);
+ }
+ if (!dev) {
+ if (dualCerts) {
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 ${nakedDomain} -d ${wwwDomain} --expand --agree-tos --non-interactive --register-unsafely-without-email`
+ `DOCKER_HOST=${host} docker run --rm --name certbot-${randomCuid} -p ${randomPort}:${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`
);
- const { stderr: copyError } = await asyncExecShell(
+ 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"`
);
- if (copyError) throw copyError;
- await forceSSLOnApplication({ domain });
+ } else {
+ await asyncExecShell(
+ `DOCKER_HOST=${host} docker run --rm --name certbot-${randomCuid} -p ${randomPort}:${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`
+ );
+ 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"`
+ );
}
+ } else {
+ console.log({ dualCerts, host, wwwDomain, nakedDomain, domain });
+ }
+ if (!isCoolify) {
+ await forceSSLOnApplication({ domain });
}
} catch (error) {
console.log(error);
diff --git a/src/routes/applications/[id]/index.svelte b/src/routes/applications/[id]/index.svelte
index 930088ec5..a5d19eb6b 100644
--- a/src/routes/applications/[id]/index.svelte
+++ b/src/routes/applications/[id]/index.svelte
@@ -52,6 +52,7 @@
let loading = false;
let debug = application.settings.debug;
let previews = application.settings.previews;
+ let dualCerts = application.settings.dualCerts;
onMount(() => {
domainEl.focus();
@@ -64,8 +65,11 @@
if (name === 'previews') {
previews = !previews;
}
+ if (name === 'dualCerts') {
+ dualCerts = !dualCerts;
+ }
try {
- await post(`/applications/${id}/settings.json`, { previews, debug });
+ await post(`/applications/${id}/settings.json`, { previews, debug, dualCerts });
return toast.push('Settings saved.');
} catch ({ error }) {
return errorNotification(error);
@@ -252,7 +256,7 @@
-
Domain (FQDN)
+
Domain (FQDN)
-
+
+ changeSettings('dualCerts')}
+ />
+
{#if !staticDeployments.includes(application.buildPack)}
Port
@@ -285,6 +297,7 @@
{/if}
+
{#if !notNodeDeployments.includes(application.buildPack)}
Install Command
@@ -361,8 +374,7 @@
-
diff --git a/src/routes/applications/[id]/settings.json.ts b/src/routes/applications/[id]/settings.json.ts
index ddd7bb5ca..6b0b3f808 100644
--- a/src/routes/applications/[id]/settings.json.ts
+++ b/src/routes/applications/[id]/settings.json.ts
@@ -8,10 +8,10 @@ export const post: RequestHandler = async (event) => {
if (status === 401) return { status, body };
const { id } = event.params;
- const { debug, previews } = await event.request.json();
+ const { debug, previews, dualCerts } = await event.request.json();
try {
- await db.setApplicationSettings({ id, debug, previews });
+ await db.setApplicationSettings({ id, debug, previews, dualCerts });
return { status: 201 };
} catch (error) {
return ErrorHandler(error);
diff --git a/src/routes/databases/[id]/_Databases/_CouchDb.svelte b/src/routes/databases/[id]/_Databases/_CouchDb.svelte
index 0d41ec184..3cba4ef93 100644
--- a/src/routes/databases/[id]/_Databases/_CouchDb.svelte
+++ b/src/routes/databases/[id]/_Databases/_CouchDb.svelte
@@ -7,72 +7,62 @@
CouchDB
-
+
-
+
-
+
-
+
-
diff --git a/src/routes/databases/[id]/_Databases/_Databases.svelte b/src/routes/databases/[id]/_Databases/_Databases.svelte
index cd91c8d6a..e09e8d278 100644
--- a/src/routes/databases/[id]/_Databases/_Databases.svelte
+++ b/src/routes/databases/[id]/_Databases/_Databases.svelte
@@ -88,70 +88,60 @@
-
+
-
+
Destination
-
- {#if database.destinationDockerId}
-
-
-
- {/if}
-
+ {#if database.destinationDockerId}
+
+
+
+ {/if}
-
-
+
-
@@ -166,44 +156,42 @@
{:else if database.type === 'couchdb'}
{/if}
-
+
Connection String
-
-
-
+
-
diff --git a/src/routes/databases/[id]/_Databases/_MongoDB.svelte b/src/routes/databases/[id]/_Databases/_MongoDB.svelte
index cbf3ffe35..54518c012 100644
--- a/src/routes/databases/[id]/_Databases/_MongoDB.svelte
+++ b/src/routes/databases/[id]/_Databases/_MongoDB.svelte
@@ -7,31 +7,27 @@
MongoDB
-
+
-
diff --git a/src/routes/databases/[id]/_Databases/_MySQL.svelte b/src/routes/databases/[id]/_Databases/_MySQL.svelte
index e361cc9fe..4f24862b3 100644
--- a/src/routes/databases/[id]/_Databases/_MySQL.svelte
+++ b/src/routes/databases/[id]/_Databases/_MySQL.svelte
@@ -7,72 +7,62 @@
MySQL
-
+
-
+
-
+
-
+
-
diff --git a/src/routes/databases/[id]/_Databases/_PostgreSQL.svelte b/src/routes/databases/[id]/_Databases/_PostgreSQL.svelte
index dc585c8e4..758aaccb0 100644
--- a/src/routes/databases/[id]/_Databases/_PostgreSQL.svelte
+++ b/src/routes/databases/[id]/_Databases/_PostgreSQL.svelte
@@ -7,45 +7,39 @@
PostgreSQL
-
+
-
+
-
diff --git a/src/routes/databases/[id]/_Databases/_Redis.svelte b/src/routes/databases/[id]/_Databases/_Redis.svelte
index ff8f83113..7c02a313e 100644
--- a/src/routes/databases/[id]/_Databases/_Redis.svelte
+++ b/src/routes/databases/[id]/_Databases/_Redis.svelte
@@ -7,32 +7,17 @@
Redis