fix: ssl + sslrenew
This commit is contained in:
parent
6da78cd3e5
commit
23e12c9c44
@ -6,7 +6,6 @@ import crypto from 'crypto';
|
|||||||
import * as db from '$lib/database';
|
import * as db from '$lib/database';
|
||||||
import { checkContainer, checkHAProxy } from '.';
|
import { checkContainer, checkHAProxy } from '.';
|
||||||
import { asyncExecShell, getDomain, getEngine } from '$lib/common';
|
import { asyncExecShell, getDomain, getEngine } from '$lib/common';
|
||||||
import { letsEncrypt } from '$lib/letsencrypt';
|
|
||||||
|
|
||||||
const url = dev ? 'http://localhost:5555' : 'http://coolify-haproxy:5555';
|
const url = dev ? 'http://localhost:5555' : 'http://coolify-haproxy:5555';
|
||||||
|
|
||||||
@ -115,7 +114,6 @@ export async function haproxyInstance() {
|
|||||||
export async function configureHAProxy() {
|
export async function configureHAProxy() {
|
||||||
const haproxy = await haproxyInstance();
|
const haproxy = await haproxyInstance();
|
||||||
await checkHAProxy(haproxy);
|
await checkHAProxy(haproxy);
|
||||||
const ssls = [];
|
|
||||||
const data = {
|
const data = {
|
||||||
applications: [],
|
applications: [],
|
||||||
services: [],
|
services: [],
|
||||||
@ -147,7 +145,6 @@ export async function configureHAProxy() {
|
|||||||
redirectValue,
|
redirectValue,
|
||||||
redirectTo: isWWW ? domain : 'www.' + domain
|
redirectTo: isWWW ? domain : 'www.' + domain
|
||||||
});
|
});
|
||||||
if (isHttps) ssls.push({ domain, id, isCoolify: false });
|
|
||||||
}
|
}
|
||||||
if (previews) {
|
if (previews) {
|
||||||
const host = getEngine(engine);
|
const host = getEngine(engine);
|
||||||
@ -171,7 +168,6 @@ export async function configureHAProxy() {
|
|||||||
redirectValue,
|
redirectValue,
|
||||||
redirectTo: isWWW ? previewDomain : 'www.' + previewDomain
|
redirectTo: isWWW ? previewDomain : 'www.' + previewDomain
|
||||||
});
|
});
|
||||||
if (isHttps) ssls.push({ domain: previewDomain, id, isCoolify: false });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -202,17 +198,18 @@ export async function configureHAProxy() {
|
|||||||
const isHttps = fqdn.startsWith('https://');
|
const isHttps = fqdn.startsWith('https://');
|
||||||
const isWWW = fqdn.includes('www.');
|
const isWWW = fqdn.includes('www.');
|
||||||
const redirectValue = `${isHttps ? 'https://' : 'http://'}${domain}%[capture.req.uri]`;
|
const redirectValue = `${isHttps ? 'https://' : 'http://'}${domain}%[capture.req.uri]`;
|
||||||
data.services.push({
|
if (isRunning) {
|
||||||
id,
|
data.services.push({
|
||||||
port,
|
id,
|
||||||
publicPort,
|
port,
|
||||||
domain,
|
publicPort,
|
||||||
isRunning,
|
domain,
|
||||||
isHttps,
|
isRunning,
|
||||||
redirectValue,
|
isHttps,
|
||||||
redirectTo: isWWW ? domain : 'www.' + domain
|
redirectValue,
|
||||||
});
|
redirectTo: isWWW ? domain : 'www.' + domain
|
||||||
if (isHttps) ssls.push({ domain, id, isCoolify: false });
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const { fqdn } = await db.prisma.setting.findFirst();
|
const { fqdn } = await db.prisma.setting.findFirst();
|
||||||
@ -229,7 +226,6 @@ export async function configureHAProxy() {
|
|||||||
redirectValue,
|
redirectValue,
|
||||||
redirectTo: isWWW ? domain : 'www.' + domain
|
redirectTo: isWWW ? domain : 'www.' + domain
|
||||||
});
|
});
|
||||||
if (!dev && isHttps) ssls.push({ domain, id: 'coolify', isCoolify: true });
|
|
||||||
}
|
}
|
||||||
const output = mustache.render(template, data);
|
const output = mustache.render(template, data);
|
||||||
const newHash = crypto.createHash('md5').update(output).digest('hex');
|
const newHash = crypto.createHash('md5').update(output).digest('hex');
|
||||||
@ -249,13 +245,4 @@ export async function configureHAProxy() {
|
|||||||
} else {
|
} else {
|
||||||
// console.log('HAProxy configuration is up to date');
|
// console.log('HAProxy configuration is up to date');
|
||||||
}
|
}
|
||||||
if (ssls.length > 0) {
|
|
||||||
for (const ssl of ssls) {
|
|
||||||
if (!dev) {
|
|
||||||
await letsEncrypt(ssl.domain, ssl.id, ssl.isCoolify);
|
|
||||||
} else {
|
|
||||||
// console.log('Generate ssl for', ssl.domain);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { dev } from '$app/env';
|
import { asyncExecShell, getDomain, getEngine } from '$lib/common';
|
||||||
import { forceSSLOffApplication, forceSSLOnApplication } from '$lib/haproxy';
|
import { checkContainer } from '$lib/haproxy';
|
||||||
import { asyncExecShell, getEngine } from './common';
|
|
||||||
import * as db from '$lib/database';
|
import * as db from '$lib/database';
|
||||||
|
import { dev } from '$app/env';
|
||||||
import cuid from 'cuid';
|
import cuid from 'cuid';
|
||||||
import getPort, { portNumbers } from 'get-port';
|
import getPort, { portNumbers } from 'get-port';
|
||||||
|
|
||||||
@ -13,7 +13,7 @@ export async function letsEncrypt(domain, id = null, isCoolify = false) {
|
|||||||
const nakedDomain = domain.replace('www.', '');
|
const nakedDomain = domain.replace('www.', '');
|
||||||
const wwwDomain = `www.${nakedDomain}`;
|
const wwwDomain = `www.${nakedDomain}`;
|
||||||
const randomCuid = cuid();
|
const randomCuid = cuid();
|
||||||
const randomPort = 9000;
|
const randomPort = await getPort({ port: portNumbers(minPort, maxPort) });
|
||||||
|
|
||||||
let host;
|
let host;
|
||||||
let dualCerts = false;
|
let dualCerts = false;
|
||||||
@ -72,3 +72,83 @@ export async function letsEncrypt(domain, id = null, isCoolify = false) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function generateSSLCerts() {
|
||||||
|
const ssls = [];
|
||||||
|
const applications = await db.prisma.application.findMany({
|
||||||
|
include: { destinationDocker: true, settings: true }
|
||||||
|
});
|
||||||
|
for (const application of applications) {
|
||||||
|
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 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const services = await db.prisma.service.findMany({
|
||||||
|
include: {
|
||||||
|
destinationDocker: true,
|
||||||
|
minio: true,
|
||||||
|
plausibleAnalytics: true,
|
||||||
|
vscodeserver: true,
|
||||||
|
wordpress: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const service of services) {
|
||||||
|
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 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const { fqdn } = await db.prisma.setting.findFirst();
|
||||||
|
if (fqdn) {
|
||||||
|
const domain = getDomain(fqdn);
|
||||||
|
const isHttps = fqdn.startsWith('https://');
|
||||||
|
if (isHttps) ssls.push({ domain, id: 'coolify', isCoolify: true });
|
||||||
|
}
|
||||||
|
if (ssls.length > 0) {
|
||||||
|
for (const ssl of ssls) {
|
||||||
|
if (!dev) {
|
||||||
|
await letsEncrypt(ssl.domain, ssl.id, ssl.isCoolify);
|
||||||
|
} else {
|
||||||
|
console.log('Generate ssl for', ssl.domain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -86,9 +86,9 @@ const cron = async () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
await queue.proxy.add('proxy', {}, { repeat: { every: 10000 } });
|
await queue.proxy.add('proxy', {}, { repeat: { every: 10000 } });
|
||||||
// await queue.ssl.add('ssl', {}, { repeat: { every: 10000 } });
|
await queue.ssl.add('ssl', {}, { repeat: { every: 60000 } });
|
||||||
// await queue.cleanup.add('cleanup', {}, { repeat: { every: 600000 } });
|
await queue.cleanup.add('cleanup', {}, { repeat: { every: 600000 } });
|
||||||
// await queue.sslRenew.add('sslRenew', {}, { repeat: { every: 1800000 } });
|
await queue.sslRenew.add('sslRenew', {}, { repeat: { every: 1800000 } });
|
||||||
|
|
||||||
const events = {
|
const events = {
|
||||||
proxy: new QueueEvents('proxy', { ...connectionOptions }),
|
proxy: new QueueEvents('proxy', { ...connectionOptions }),
|
||||||
|
@ -1,76 +1,9 @@
|
|||||||
import { asyncExecShell, getDomain, getEngine } from '$lib/common';
|
import { generateSSLCerts } from '$lib/letsencrypt';
|
||||||
import { prisma } from '$lib/database';
|
|
||||||
import { dockerInstance } from '$lib/docker';
|
|
||||||
import { forceSSLOnApplication } from '$lib/haproxy';
|
|
||||||
import * as db from '$lib/database';
|
|
||||||
import { dev } from '$app/env';
|
|
||||||
import getPort, { portNumbers } from 'get-port';
|
|
||||||
import cuid from 'cuid';
|
|
||||||
|
|
||||||
export default async function () {
|
export default async function () {
|
||||||
try {
|
try {
|
||||||
const data = await db.prisma.setting.findFirst();
|
return await generateSSLCerts();
|
||||||
const { minPort, maxPort } = data;
|
|
||||||
|
|
||||||
const publicPort = await getPort({ port: portNumbers(minPort, maxPort) });
|
|
||||||
const randomCuid = cuid();
|
|
||||||
const destinationDockers = await prisma.destinationDocker.findMany({});
|
|
||||||
for (const destination of destinationDockers) {
|
|
||||||
if (destination.isCoolifyProxyUsed) {
|
|
||||||
const docker = dockerInstance({ destinationDocker: destination });
|
|
||||||
const containers = await docker.engine.listContainers();
|
|
||||||
const configurations = containers.filter(
|
|
||||||
(container) => container.Labels['coolify.managed']
|
|
||||||
);
|
|
||||||
for (const configuration of configurations) {
|
|
||||||
const parsedConfiguration = JSON.parse(
|
|
||||||
Buffer.from(configuration.Labels['coolify.configuration'], 'base64').toString()
|
|
||||||
);
|
|
||||||
if (configuration.Labels['coolify.type'] === 'standalone-application') {
|
|
||||||
const { fqdn } = parsedConfiguration;
|
|
||||||
if (fqdn) {
|
|
||||||
const domain = getDomain(fqdn);
|
|
||||||
const isHttps = fqdn.startsWith('https://');
|
|
||||||
if (isHttps) {
|
|
||||||
if (dev) {
|
|
||||||
console.log('DEV MODE: SSL is enabled');
|
|
||||||
} else {
|
|
||||||
const host = getEngine(destination.engine);
|
|
||||||
await asyncExecShell(
|
|
||||||
`DOCKER_HOST=${host} docker run --rm --name certbot-${randomCuid} -p 9080:${publicPort} -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 ${publicPort} -d ${domain} --agree-tos --non-interactive --register-unsafely-without-email`
|
|
||||||
);
|
|
||||||
const { stderr } = await asyncExecShell(
|
|
||||||
`DOCKER_HOST=${host} 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const { fqdn } = await db.listSettings();
|
|
||||||
if (fqdn) {
|
|
||||||
const domain = getDomain(fqdn);
|
|
||||||
const isHttps = fqdn.startsWith('https://');
|
|
||||||
if (isHttps) {
|
|
||||||
if (dev) {
|
|
||||||
console.log('DEV MODE: SSL is enabled');
|
|
||||||
} else {
|
|
||||||
await asyncExecShell(
|
|
||||||
`docker run --rm --name certbot-${randomCuid} -p 9080:${publicPort} -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 ${publicPort} -d ${domain} --agree-tos --non-interactive --register-unsafely-without-email`
|
|
||||||
);
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,6 +78,7 @@
|
|||||||
if (fqdn !== settings.fqdn) {
|
if (fqdn !== settings.fqdn) {
|
||||||
await post(`/settings/check.json`, { fqdn });
|
await post(`/settings/check.json`, { fqdn });
|
||||||
await post(`/settings.json`, { fqdn });
|
await post(`/settings.json`, { fqdn });
|
||||||
|
return window.location.reload();
|
||||||
}
|
}
|
||||||
if (minPort !== settings.minPort || maxPort !== settings.maxPort) {
|
if (minPort !== settings.minPort || maxPort !== settings.maxPort) {
|
||||||
await post(`/settings.json`, { minPort, maxPort });
|
await post(`/settings.json`, { minPort, maxPort });
|
||||||
@ -98,7 +99,7 @@
|
|||||||
{#if $session.teamId === '0'}
|
{#if $session.teamId === '0'}
|
||||||
<div class="mx-auto max-w-4xl px-6">
|
<div class="mx-auto max-w-4xl px-6">
|
||||||
<form on:submit|preventDefault={handleSubmit} class="grid grid-flow-row gap-2 py-4">
|
<form on:submit|preventDefault={handleSubmit} class="grid grid-flow-row gap-2 py-4">
|
||||||
<div class="flex space-x-1 py-6">
|
<div class="flex space-x-1 pb-6">
|
||||||
<div class="title font-bold">Global Settings</div>
|
<div class="title font-bold">Global Settings</div>
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
|
Loading…
Reference in New Issue
Block a user