This commit is contained in:
Andras Bacsai 2021-06-24 23:31:08 +02:00 committed by GitHub
parent a8e9668c2b
commit 2d0f22b379
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 2220 additions and 1070 deletions

View File

@ -54,7 +54,6 @@ With Github integration
- [VSCode Server](https://github.com/cdr/code-server) - [VSCode Server](https://github.com/cdr/code-server)
- [MinIO](https://min.io) - [MinIO](https://min.io)
## Support ## Support
- Twitter: [@andrasbacsai](https://twitter.com/andrasbacsai) - Twitter: [@andrasbacsai](https://twitter.com/andrasbacsai)

View File

@ -1,7 +1,7 @@
{ {
"name": "coolify", "name": "coolify",
"description": "An open-source, hassle-free, self-hostable Heroku & Netlify alternative.", "description": "An open-source, hassle-free, self-hostable Heroku & Netlify alternative.",
"version": "1.0.21", "version": "1.0.22",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"scripts": { "scripts": {
"dev:docker:start": "docker-compose -f docker-compose-dev.yml up -d", "dev:docker:start": "docker-compose -f docker-compose-dev.yml up -d",
@ -50,6 +50,7 @@
"generate-password": "^1.6.0", "generate-password": "^1.6.0",
"js-yaml": "^4.1.0", "js-yaml": "^4.1.0",
"jsonwebtoken": "^8.5.1", "jsonwebtoken": "^8.5.1",
"microtip": "^0.2.2",
"mongoose": "^5.12.13", "mongoose": "^5.12.13",
"shelljs": "^0.8.4", "shelljs": "^0.8.4",
"svelte-kit-cookie-session": "^1.0.6", "svelte-kit-cookie-session": "^1.0.6",

2528
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,6 @@
<link rel="dns-prefetch" href="https://cdn.coollabs.io/" /> <link rel="dns-prefetch" href="https://cdn.coollabs.io/" />
<link rel="preconnect" href="https://cdn.coollabs.io/" crossorigin="" /> <link rel="preconnect" href="https://cdn.coollabs.io/" crossorigin="" />
<link rel="stylesheet" href="https://cdn.coollabs.io/fonts/montserrat/montserrat.css" /> <link rel="stylesheet" href="https://cdn.coollabs.io/fonts/montserrat/montserrat.css" />
<link rel="stylesheet" href="https://cdn.coollabs.io/css/microtip-0.2.2.min.css" />
%svelte.head% %svelte.head%
</head> </head>
<body> <body>

View File

@ -101,7 +101,7 @@ export async function handle({ request, resolve }) {
cookie: { path: '/', secure: true } cookie: { path: '/', secure: true }
}); });
} catch (error) { } catch (error) {
console.log(error) console.log(error);
return { return {
status: 302, status: 302,
headers: { headers: {
@ -124,7 +124,7 @@ export async function handle({ request, resolve }) {
if (!session['set-cookie']) { if (!session['set-cookie']) {
if (!session?.data?.coolToken && !publicPages.includes(request.path)) { if (!session?.data?.coolToken && !publicPages.includes(request.path)) {
return { return {
status: 301, status: 302,
headers: { headers: {
location: '/' location: '/'
} }

View File

@ -70,9 +70,9 @@ export default async function (configuration, imageChanged) {
} }
async function purgeImagesAsync(found) { async function purgeImagesAsync(found) {
await delay(10000); await delay(10000);
await purgeImagesContainers(found, true); await purgeImagesContainers(found);
} }
purgeImagesAsync(configuration); //purgeImagesAsync(configuration);
await saveAppLog('### Published done!', configuration); await saveAppLog('### Published done!', configuration);
} }

View File

@ -1,2 +1,8 @@
export const publicPages = ['/', '/api/v1/login/github/app', '/api/v1/webhooks/deploy', '/success', '/api/v1/login/email'] export const publicPages = [
export const VITE_GITHUB_APP_NAME = import.meta.env.VITE_GITHUB_APP_NAME '/',
'/api/v1/login/github/app',
'/api/v1/webhooks/deploy',
'/success',
'/api/v1/login/email'
];
export const VITE_GITHUB_APP_NAME = import.meta.env.VITE_GITHUB_APP_NAME;

View File

@ -9,7 +9,7 @@
if (!publicPages.includes(path)) { if (!publicPages.includes(path)) {
if (!session.session.isLoggedIn) { if (!session.session.isLoggedIn) {
return { return {
status: 301, status: 302,
redirect: '/' redirect: '/'
}; };
} }
@ -17,7 +17,7 @@
} }
if (!publicPages.includes(path)) { if (!publicPages.includes(path)) {
return { return {
status: 301, status: 302,
redirect: '/' redirect: '/'
}; };
} }
@ -26,6 +26,7 @@
</script> </script>
<script lang="ts"> <script lang="ts">
import 'microtip/microtip.css';
import '../app.postcss'; import '../app.postcss';
export let initDashboard; export let initDashboard;
import { onMount } from 'svelte'; import { onMount } from 'svelte';

View File

@ -9,97 +9,96 @@ import type { Request } from '@sveltejs/kit';
const saltRounds = 15; const saltRounds = 15;
export async function post(request: Request) { export async function post(request: Request) {
const { email, password } = request.body const { email, password } = request.body;
const { JWT_SIGN_KEY } = process.env; const { JWT_SIGN_KEY } = process.env;
const settings = await Settings.findOne({ applicationName: 'coolify' }); const settings = await Settings.findOne({ applicationName: 'coolify' });
const registeredUsers = await User.find().countDocuments(); const registeredUsers = await User.find().countDocuments();
const foundUser = await User.findOne({ email }); const foundUser = await User.findOne({ email });
try { try {
let uid = cuid(); let uid = cuid();
if (foundUser) { if (foundUser) {
if (foundUser.type === 'github') { if (foundUser.type === 'github') {
return { return {
status: 500, status: 500,
body: { body: {
error: 'Wrong password or email address.' error: 'Wrong password or email address.'
} }
}; };
} }
uid = foundUser.uid; uid = foundUser.uid;
if (!await bcrypt.compare(password, foundUser.password)) { if (!(await bcrypt.compare(password, foundUser.password))) {
return { return {
status: 500, status: 500,
body: { body: {
error: 'Wrong password or email address.' error: 'Wrong password or email address.'
} }
}; };
} }
} else { } else {
if (registeredUsers === 0) { if (registeredUsers === 0) {
const newUser = new User({ const newUser = new User({
_id: new mongoose.Types.ObjectId(), _id: new mongoose.Types.ObjectId(),
email, email,
uid, uid,
type: 'email', type: 'email',
password: await bcrypt.hash(password, saltRounds) password: await bcrypt.hash(password, saltRounds)
}); });
const defaultSettings = new Settings({ const defaultSettings = new Settings({
_id: new mongoose.Types.ObjectId() _id: new mongoose.Types.ObjectId()
}); });
try { try {
await newUser.save(); await newUser.save();
await defaultSettings.save(); await defaultSettings.save();
} catch (error) { } catch (error) {
return { return {
status: 500, status: 500,
error: error.message || error error: error.message || error
}; };
} }
} else { } else {
if (!settings?.allowRegistration) { if (!settings?.allowRegistration) {
return { return {
status: 500, status: 500,
body: { body: {
error: 'Registration disabled, enable it in settings.' error: 'Registration disabled, enable it in settings.'
} }
}; };
} else { } else {
const newUser = new User({ const newUser = new User({
_id: new mongoose.Types.ObjectId(), _id: new mongoose.Types.ObjectId(),
email, email,
uid, uid,
type: 'email', type: 'email',
password: await bcrypt.hash(password, saltRounds) password: await bcrypt.hash(password, saltRounds)
}); });
try { try {
await newUser.save(); await newUser.save();
} catch (error) { } catch (error) {
return { return {
status: 500, status: 500,
error: error.message || error error: error.message || error
}; };
} }
} }
} }
} }
const coolToken = jsonwebtoken.sign({}, JWT_SIGN_KEY, { const coolToken = jsonwebtoken.sign({}, JWT_SIGN_KEY, {
expiresIn: 15778800, expiresIn: 15778800,
algorithm: 'HS256', algorithm: 'HS256',
audience: 'coolLabs', audience: 'coolLabs',
issuer: 'coolLabs', issuer: 'coolLabs',
jwtid: uid, jwtid: uid,
subject: `User:${uid}`, subject: `User:${uid}`,
notBefore: -1000 notBefore: -1000
}); });
request.locals.session.data = { coolToken, ghToken: null }; request.locals.session.data = { coolToken, ghToken: null };
return { return {
status: 200, status: 200,
body: { body: {
message: "Successfully logged in." message: 'Successfully logged in.'
} }
}; };
} catch (error) { } catch (error) {
return { status: 500, body: { error: error.message || error } }; return { status: 500, body: { error: error.message || error } };
} }
}
}

View File

@ -2,24 +2,26 @@ import { saveServerLog } from '$lib/api/applications/logging';
import { execShellAsync } from '$lib/api/common'; import { execShellAsync } from '$lib/api/common';
import type { Request } from '@sveltejs/kit'; import type { Request } from '@sveltejs/kit';
export async function post(request: Request) { export async function post(request: Request) {
try { try {
const output = await execShellAsync('docker builder prune -af') const output = await execShellAsync('docker builder prune -af');
return { return {
status: 200, status: 200,
body: { body: {
message: 'OK', message: 'OK',
output: output.replace(/^(?=\n)$|^\s*|\s*$|\n\n+/gm,"").split('\n').pop() output: output
} .replace(/^(?=\n)$|^\s*|\s*$|\n\n+/gm, '')
} .split('\n')
} catch (error) { .pop()
await saveServerLog(error); }
return { };
status: 500, } catch (error) {
body: { await saveServerLog(error);
error: error.message || error return {
} status: 500,
}; body: {
} error: error.message || error
}
};
}
} }

View File

@ -2,24 +2,26 @@ import { saveServerLog } from '$lib/api/applications/logging';
import { execShellAsync } from '$lib/api/common'; import { execShellAsync } from '$lib/api/common';
import type { Request } from '@sveltejs/kit'; import type { Request } from '@sveltejs/kit';
export async function post(request: Request) { export async function post(request: Request) {
try { try {
const output = await execShellAsync('docker container prune -f') const output = await execShellAsync('docker container prune -f');
return { return {
status: 200, status: 200,
body: { body: {
message: 'OK', message: 'OK',
output: output.replace(/^(?=\n)$|^\s*|\s*$|\n\n+/gm,"").split('\n').pop() output: output
} .replace(/^(?=\n)$|^\s*|\s*$|\n\n+/gm, '')
} .split('\n')
} catch (error) { .pop()
await saveServerLog(error); }
return { };
status: 500, } catch (error) {
body: { await saveServerLog(error);
error: error.message || error return {
} status: 500,
}; body: {
} error: error.message || error
}
};
}
} }

View File

@ -2,24 +2,26 @@ import { saveServerLog } from '$lib/api/applications/logging';
import { execShellAsync } from '$lib/api/common'; import { execShellAsync } from '$lib/api/common';
import type { Request } from '@sveltejs/kit'; import type { Request } from '@sveltejs/kit';
export async function post(request: Request) { export async function post(request: Request) {
try { try {
const output = await execShellAsync('docker image prune -af') const output = await execShellAsync('docker image prune -af');
return { return {
status: 200, status: 200,
body: { body: {
message: 'OK', message: 'OK',
output: output.replace(/^(?=\n)$|^\s*|\s*$|\n\n+/gm,"").split('\n').pop() output: output
} .replace(/^(?=\n)$|^\s*|\s*$|\n\n+/gm, '')
} .split('\n')
} catch (error) { .pop()
await saveServerLog(error); }
return { };
status: 500, } catch (error) {
body: { await saveServerLog(error);
error: error.message || error return {
} status: 500,
}; body: {
} error: error.message || error
}
};
}
} }

View File

@ -2,24 +2,26 @@ import { saveServerLog } from '$lib/api/applications/logging';
import { execShellAsync } from '$lib/api/common'; import { execShellAsync } from '$lib/api/common';
import type { Request } from '@sveltejs/kit'; import type { Request } from '@sveltejs/kit';
export async function post(request: Request) { export async function post(request: Request) {
try { try {
const output = await execShellAsync('docker volume prune -f') const output = await execShellAsync('docker volume prune -f');
return { return {
status: 200, status: 200,
body: { body: {
message: 'OK', message: 'OK',
output: output.replace(/^(?=\n)$|^\s*|\s*$|\n\n+/gm,"").split('\n').pop() output: output
} .replace(/^(?=\n)$|^\s*|\s*$|\n\n+/gm, '')
} .split('\n')
} catch (error) { .pop()
await saveServerLog(error); }
return { };
status: 500, } catch (error) {
body: { await saveServerLog(error);
error: error.message || error return {
} status: 500,
}; body: {
} error: error.message || error
}
};
}
} }

View File

@ -2,26 +2,26 @@ import { saveServerLog } from '$lib/api/applications/logging';
import { execShellAsync } from '$lib/api/common'; import { execShellAsync } from '$lib/api/common';
import { docker } from '$lib/api/docker'; import { docker } from '$lib/api/docker';
import type { Request } from '@sveltejs/kit'; import type { Request } from '@sveltejs/kit';
import systeminformation from 'systeminformation' import systeminformation from 'systeminformation';
export async function get(request: Request) { export async function get(request: Request) {
try { try {
const df = await execShellAsync( const df = await execShellAsync(`docker system df --format '{{ json . }}'`);
`docker system df --format '{{ json . }}'`
);
const dockerReclaimable = df const dockerReclaimable = df
.split('\n') .split('\n')
.filter((n) => n) .filter((n) => n)
.map((s) => JSON.parse(s)) .map((s) => JSON.parse(s));
return { return {
status: 200, status: 200,
body: { body: {
hostname: await (await systeminformation.osInfo()).hostname, hostname: await (await systeminformation.osInfo()).hostname,
filesystems: await (await systeminformation.fsSize()).filter(fs => !fs.fs.match('/dev/loop') || !fs.fs.match('/var/lib/docker/')), filesystems: await (
await systeminformation.fsSize()
).filter((fs) => !fs.fs.match('/dev/loop') || !fs.fs.match('/var/lib/docker/')),
dockerReclaimable dockerReclaimable
} }
} };
} catch (error) { } catch (error) {
await saveServerLog(error); await saveServerLog(error);
return { return {

View File

@ -59,8 +59,8 @@ export async function post(request: Request) {
volumes: { volumes: {
[`${deployId}-code-server-data`]: { [`${deployId}-code-server-data`]: {
external: true external: true
}, }
}, }
}; };
await execShellAsync(`mkdir -p ${workdir}`); await execShellAsync(`mkdir -p ${workdir}`);
await fs.writeFile(`${workdir}/stack.yml`, yaml.dump(stack)); await fs.writeFile(`${workdir}/stack.yml`, yaml.dump(stack));

View File

@ -1,6 +1,6 @@
import { execShellAsync } from '$lib/api/common'; import { execShellAsync } from '$lib/api/common';
import type { Request } from '@sveltejs/kit'; import type { Request } from '@sveltejs/kit';
import yaml from "js-yaml" import yaml from 'js-yaml';
export async function get(request: Request) { export async function get(request: Request) {
// const { POSTGRESQL_USERNAME, POSTGRESQL_PASSWORD, POSTGRESQL_DATABASE } = JSON.parse( // const { POSTGRESQL_USERNAME, POSTGRESQL_PASSWORD, POSTGRESQL_DATABASE } = JSON.parse(
@ -15,10 +15,12 @@ export async function get(request: Request) {
.trim() .trim()
.split('\n'); .split('\n');
const codeServer = containers.find((container) => container.startsWith('code-server')); const codeServer = containers.find((container) => container.startsWith('code-server'));
const configYaml = yaml.load(await execShellAsync( const configYaml = yaml.load(
`docker exec ${codeServer} cat /home/coder/.config/code-server/config.yaml` await execShellAsync(
)) `docker exec ${codeServer} cat /home/coder/.config/code-server/config.yaml`
return { )
);
return {
status: 200, status: 200,
body: { message: 'OK', password: configYaml.password } body: { message: 'OK', password: configYaml.password }
}; };

View File

@ -13,9 +13,14 @@ export async function post(request: Request) {
const workdir = '/tmp/minio'; const workdir = '/tmp/minio';
const deployId = 'minio'; const deployId = 'minio';
const secrets = [ const secrets = [
{ name: 'MINIO_ROOT_USER', value: generator.generate({ length: 12, numbers: true, strict: true }) }, {
{ name: 'MINIO_ROOT_PASSWORD', value: generator.generate({ length: 24, numbers: true, strict: true }) } name: 'MINIO_ROOT_USER',
value: generator.generate({ length: 12, numbers: true, strict: true })
},
{
name: 'MINIO_ROOT_PASSWORD',
value: generator.generate({ length: 24, numbers: true, strict: true })
}
]; ];
const generateEnvsMinIO = {}; const generateEnvsMinIO = {};
for (const secret of secrets) generateEnvsMinIO[secret.name] = secret.value; for (const secret of secrets) generateEnvsMinIO[secret.name] = secret.value;
@ -36,18 +41,18 @@ export async function post(request: Request) {
'type=service', 'type=service',
'serviceName=minio', 'serviceName=minio',
'configuration=' + 'configuration=' +
JSON.stringify({ JSON.stringify({
baseURL, baseURL,
generateEnvsMinIO generateEnvsMinIO
}), }),
'traefik.enable=true', 'traefik.enable=true',
'traefik.http.services.' + deployId + '.loadbalancer.server.port=9000', 'traefik.http.services.' + deployId + '.loadbalancer.server.port=9000',
'traefik.http.routers.' + deployId + '.entrypoints=websecure', 'traefik.http.routers.' + deployId + '.entrypoints=websecure',
'traefik.http.routers.' + 'traefik.http.routers.' +
deployId + deployId +
'.rule=Host(`' + '.rule=Host(`' +
traefikURL + traefikURL +
'`) && PathPrefix(`/`)', '`) && PathPrefix(`/`)',
'traefik.http.routers.' + deployId + '.tls.certresolver=letsencrypt', 'traefik.http.routers.' + deployId + '.tls.certresolver=letsencrypt',
'traefik.http.routers.' + deployId + '.middlewares=global-compress' 'traefik.http.routers.' + deployId + '.middlewares=global-compress'
] ]
@ -62,8 +67,8 @@ export async function post(request: Request) {
volumes: { volumes: {
[`${deployId}-minio-data`]: { [`${deployId}-minio-data`]: {
external: true external: true
}, }
}, }
}; };
await execShellAsync(`mkdir -p ${workdir}`); await execShellAsync(`mkdir -p ${workdir}`);
await fs.writeFile(`${workdir}/stack.yml`, yaml.dump(stack)); await fs.writeFile(`${workdir}/stack.yml`, yaml.dump(stack));

View File

@ -7,166 +7,166 @@ import { baseServiceConfiguration } from '$lib/api/applications/common';
import { cleanupTmp, execShellAsync } from '$lib/api/common'; import { cleanupTmp, execShellAsync } from '$lib/api/common';
export async function post(request: Request) { export async function post(request: Request) {
let { baseURL, remoteDB, database, wordpressExtraConfiguration } = request.body; let { baseURL, remoteDB, database, wordpressExtraConfiguration } = request.body;
const traefikURL = baseURL; const traefikURL = baseURL;
baseURL = `https://${baseURL}`; baseURL = `https://${baseURL}`;
console.log({ baseURL, remoteDB, database, wordpressExtraConfiguration }) console.log({ baseURL, remoteDB, database, wordpressExtraConfiguration });
const workdir = '/tmp/wordpress'; const workdir = '/tmp/wordpress';
const deployId = `wp-${generator.generate({ length: 5, numbers: true, strict: true })}` const deployId = `wp-${generator.generate({ length: 5, numbers: true, strict: true })}`;
const defaultDatabaseName = generator.generate({ length: 12, numbers: true, strict: true }) const defaultDatabaseName = generator.generate({ length: 12, numbers: true, strict: true });
const defaultDatabaseHost = `${deployId}-mysql` const defaultDatabaseHost = `${deployId}-mysql`;
const defaultDatabaseUser = generator.generate({ length: 12, numbers: true, strict: true }) const defaultDatabaseUser = generator.generate({ length: 12, numbers: true, strict: true });
const defaultDatabasePassword = generator.generate({ length: 24, numbers: true, strict: true }) const defaultDatabasePassword = generator.generate({ length: 24, numbers: true, strict: true });
const defaultDatabaseRootPassword = generator.generate({ length: 24, numbers: true, strict: true }) const defaultDatabaseRootPassword = generator.generate({
const defaultDatabaseRootUser = generator.generate({ length: 12, numbers: true, strict: true }) length: 24,
let secrets = [ numbers: true,
{ name: 'WORDPRESS_DB_HOST', value: defaultDatabaseHost }, strict: true
{ name: 'WORDPRESS_DB_USER', value: defaultDatabaseUser }, });
{ name: 'WORDPRESS_DB_PASSWORD', value: defaultDatabasePassword }, const defaultDatabaseRootUser = generator.generate({ length: 12, numbers: true, strict: true });
{ name: 'WORDPRESS_DB_NAME', value: defaultDatabaseName }, let secrets = [
{ name: 'WORDPRESS_CONFIG_EXTRA', value: wordpressExtraConfiguration } { name: 'WORDPRESS_DB_HOST', value: defaultDatabaseHost },
]; { name: 'WORDPRESS_DB_USER', value: defaultDatabaseUser },
{ name: 'WORDPRESS_DB_PASSWORD', value: defaultDatabasePassword },
{ name: 'WORDPRESS_DB_NAME', value: defaultDatabaseName },
{ name: 'WORDPRESS_CONFIG_EXTRA', value: wordpressExtraConfiguration }
];
const generateEnvsMySQL = { const generateEnvsMySQL = {
MYSQL_ROOT_PASSWORD: defaultDatabaseRootPassword, MYSQL_ROOT_PASSWORD: defaultDatabaseRootPassword,
MYSQL_ROOT_USER: defaultDatabaseRootUser, MYSQL_ROOT_USER: defaultDatabaseRootUser,
MYSQL_USER: defaultDatabaseUser, MYSQL_USER: defaultDatabaseUser,
MYSQL_PASSWORD: defaultDatabasePassword, MYSQL_PASSWORD: defaultDatabasePassword,
MYSQL_DATABASE: defaultDatabaseName MYSQL_DATABASE: defaultDatabaseName
}; };
const image = 'bitnami/mysql:8.0'; const image = 'bitnami/mysql:8.0';
const volume = `${deployId}-mysql-data:/bitnami/mysql/data`; const volume = `${deployId}-mysql-data:/bitnami/mysql/data`;
if (remoteDB) { if (remoteDB) {
secrets = [ secrets = [
{ name: 'WORDPRESS_DB_HOST', value: database.host }, { name: 'WORDPRESS_DB_HOST', value: database.host },
{ name: 'WORDPRESS_DB_USER', value: database.user }, { name: 'WORDPRESS_DB_USER', value: database.user },
{ name: 'WORDPRESS_DB_PASSWORD', value: database.password }, { name: 'WORDPRESS_DB_PASSWORD', value: database.password },
{ name: 'WORDPRESS_DB_NAME', value: database.name }, { name: 'WORDPRESS_DB_NAME', value: database.name },
{ name: 'WORDPRESS_TABLE_PREFIX', value: database.tablePrefix }, { name: 'WORDPRESS_TABLE_PREFIX', value: database.tablePrefix },
{ name: 'WORDPRESS_CONFIG_EXTRA', value: wordpressExtraConfiguration } { name: 'WORDPRESS_CONFIG_EXTRA', value: wordpressExtraConfiguration }
] ];
} }
const generateEnvsWordpress = {}; const generateEnvsWordpress = {};
for (const secret of secrets) generateEnvsWordpress[secret.name] = secret.value; for (const secret of secrets) generateEnvsWordpress[secret.name] = secret.value;
let stack = { let stack = {
version: '3.8', version: '3.8',
services: { services: {
[deployId]: { [deployId]: {
image: 'wordpress', image: 'wordpress',
networks: [`${docker.network}`], networks: [`${docker.network}`],
environment: generateEnvsWordpress, environment: generateEnvsWordpress,
volumes: [`${deployId}-wordpress-data:/var/www/html`], volumes: [`${deployId}-wordpress-data:/var/www/html`],
deploy: { deploy: {
...baseServiceConfiguration, ...baseServiceConfiguration,
labels: [ labels: [
'managedBy=coolify', 'managedBy=coolify',
'type=service', 'type=service',
'serviceName=' + deployId, 'serviceName=' + deployId,
'configuration=' + 'configuration=' +
JSON.stringify({ JSON.stringify({
deployId, deployId,
baseURL, baseURL,
generateEnvsWordpress generateEnvsWordpress
}), }),
'traefik.enable=true', 'traefik.enable=true',
'traefik.http.services.' + deployId + '.loadbalancer.server.port=80', 'traefik.http.services.' + deployId + '.loadbalancer.server.port=80',
'traefik.http.routers.' + deployId + '.entrypoints=websecure', 'traefik.http.routers.' + deployId + '.entrypoints=websecure',
'traefik.http.routers.' + 'traefik.http.routers.' +
deployId + deployId +
'.rule=Host(`' + '.rule=Host(`' +
traefikURL + traefikURL +
'`) && PathPrefix(`/`)', '`) && PathPrefix(`/`)',
'traefik.http.routers.' + deployId + '.tls.certresolver=letsencrypt', 'traefik.http.routers.' + deployId + '.tls.certresolver=letsencrypt',
'traefik.http.routers.' + deployId + '.middlewares=global-compress' 'traefik.http.routers.' + deployId + '.middlewares=global-compress'
] ]
} }
}, },
[`${deployId}-mysql`]: { [`${deployId}-mysql`]: {
image, image,
networks: [`${docker.network}`], networks: [`${docker.network}`],
environment: generateEnvsMySQL, environment: generateEnvsMySQL,
volumes: [volume], volumes: [volume],
deploy: { deploy: {
...baseServiceConfiguration, ...baseServiceConfiguration,
labels: [ labels: ['managedBy=coolify', 'type=service', 'serviceName=' + deployId]
'managedBy=coolify', }
'type=service', }
'serviceName=' + deployId, },
] networks: {
} [`${docker.network}`]: {
} external: true
}, }
networks: { },
[`${docker.network}`]: { volumes: {
external: true [`${deployId}-wordpress-data`]: {
} external: true
}, },
volumes: { [`${deployId}-mysql-data`]: {
[`${deployId}-wordpress-data`]: { external: true
external: true }
}, }
[`${deployId}-mysql-data`]: { };
external: true if (remoteDB) {
} stack = {
}, version: '3.8',
}; services: {
if (remoteDB) { [deployId]: {
stack = { image: 'wordpress',
version: '3.8', networks: [`${docker.network}`],
services: { environment: generateEnvsWordpress,
[deployId]: { volumes: [`${deployId}-wordpress-data:/var/www/html`],
image: 'wordpress', deploy: {
networks: [`${docker.network}`], ...baseServiceConfiguration,
environment: generateEnvsWordpress, labels: [
volumes: [`${deployId}-wordpress-data:/var/www/html`], 'managedBy=coolify',
deploy: { 'type=service',
...baseServiceConfiguration, 'serviceName=' + deployId,
labels: [ 'configuration=' +
'managedBy=coolify', JSON.stringify({
'type=service', deployId,
'serviceName=' + deployId, baseURL,
'configuration=' + generateEnvsWordpress
JSON.stringify({ }),
deployId, 'traefik.enable=true',
baseURL, 'traefik.http.services.' + deployId + '.loadbalancer.server.port=80',
generateEnvsWordpress 'traefik.http.routers.' + deployId + '.entrypoints=websecure',
}), 'traefik.http.routers.' +
'traefik.enable=true', deployId +
'traefik.http.services.' + deployId + '.loadbalancer.server.port=80', '.rule=Host(`' +
'traefik.http.routers.' + deployId + '.entrypoints=websecure', traefikURL +
'traefik.http.routers.' + '`) && PathPrefix(`/`)',
deployId + 'traefik.http.routers.' + deployId + '.tls.certresolver=letsencrypt',
'.rule=Host(`' + 'traefik.http.routers.' + deployId + '.middlewares=global-compress'
traefikURL + ]
'`) && PathPrefix(`/`)', }
'traefik.http.routers.' + deployId + '.tls.certresolver=letsencrypt', }
'traefik.http.routers.' + deployId + '.middlewares=global-compress' },
] networks: {
} [`${docker.network}`]: {
} external: true
}, }
networks: { },
[`${docker.network}`]: { volumes: {
external: true [`${deployId}-wordpress-data`]: {
} external: true
}, }
volumes: { }
[`${deployId}-wordpress-data`]: { };
external: true }
} await execShellAsync(`mkdir -p ${workdir}`);
}, await fs.writeFile(`${workdir}/stack.yml`, yaml.dump(stack));
}; await execShellAsync(`docker stack rm ${deployId}`);
} await execShellAsync(`cat ${workdir}/stack.yml | docker stack deploy --prune -c - ${deployId}`);
await execShellAsync(`mkdir -p ${workdir}`); cleanupTmp(workdir);
await fs.writeFile(`${workdir}/stack.yml`, yaml.dump(stack)); return {
await execShellAsync(`docker stack rm ${deployId}`); status: 200,
await execShellAsync(`cat ${workdir}/stack.yml | docker stack deploy --prune -c - ${deployId}`); body: { message: 'OK' }
cleanupTmp(workdir); };
return {
status: 200,
body: { message: 'OK' }
};
} }

View File

@ -5,7 +5,7 @@
export async function load(session) { export async function load(session) {
if (!browser && !process.env.VITE_GITHUB_APP_CLIENTID) { if (!browser && !process.env.VITE_GITHUB_APP_CLIENTID) {
return { return {
status: 301, status: 302,
redirect: '/dashboard/services' redirect: '/dashboard/services'
}; };
} }

View File

@ -6,7 +6,7 @@
export async function load(session) { export async function load(session) {
if (!browser && !process.env.VITE_GITHUB_APP_CLIENTID) { if (!browser && !process.env.VITE_GITHUB_APP_CLIENTID) {
return { return {
status: 301, status: 302,
redirect: '/dashboard/services' redirect: '/dashboard/services'
}; };
} }

View File

@ -5,7 +5,7 @@
export async function load(session) { export async function load(session) {
if (!browser && !process.env.VITE_GITHUB_APP_CLIENTID) { if (!browser && !process.env.VITE_GITHUB_APP_CLIENTID) {
return { return {
status: 301, status: 302,
redirect: '/dashboard/services' redirect: '/dashboard/services'
}; };
} }

View File

@ -8,7 +8,7 @@ import type {
import { writable } from 'svelte/store'; import { writable } from 'svelte/store';
export const settings = writable({ export const settings = writable({
clientId: null clientId: null
}) });
export const dashboard = writable<Dashboard>({ export const dashboard = writable<Dashboard>({
databases: { databases: {
deployed: [] deployed: []