feat: VaultWarden service
This commit is contained in:
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "coolify",
|
"name": "coolify",
|
||||||
"description": "An open-source & self-hostable Heroku / Netlify alternative.",
|
"description": "An open-source & self-hostable Heroku / Netlify alternative.",
|
||||||
"version": "2.0.4",
|
"version": "2.0.5",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "docker-compose -f docker-compose-dev.yaml up -d && NODE_ENV=development svelte-kit dev --host 0.0.0.0",
|
"dev": "docker compose -f docker-compose-dev.yaml up -d && NODE_ENV=development svelte-kit dev --host 0.0.0.0",
|
||||||
"dev:stop": "docker-compose -f docker-compose-dev.yaml down",
|
"dev:stop": "docker compose -f docker-compose-dev.yaml down",
|
||||||
"dev:logs": "docker-compose -f docker-compose-dev.yaml logs -f --tail 10",
|
"dev:logs": "docker compose -f docker-compose-dev.yaml logs -f --tail 10",
|
||||||
"studio": "npx prisma studio",
|
"studio": "npx prisma studio",
|
||||||
"start": "npx prisma migrate deploy && npx prisma generate && npx prisma db seed && node index.js",
|
"start": "npx prisma migrate deploy && npx prisma generate && npx prisma db seed && node index.js",
|
||||||
"build": "svelte-kit build",
|
"build": "svelte-kit build",
|
||||||
|
35
src/lib/components/svg/services/VaultWarden.svelte
Normal file
35
src/lib/components/svg/services/VaultWarden.svelte
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
export let isAbsolute = false;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svg
|
||||||
|
class={isAbsolute ? 'w-10 absolute top-0 left-0 -m-5' : 'w-8 mx-auto'}
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
version="1.1"
|
||||||
|
id="Icon"
|
||||||
|
x="0px"
|
||||||
|
y="0px"
|
||||||
|
viewBox="0 0 1024 1024"
|
||||||
|
style="enable-background:new 0 0 1024 1024;"
|
||||||
|
xml:space="preserve"
|
||||||
|
>
|
||||||
|
<style type="text/css">
|
||||||
|
.st0 {
|
||||||
|
fill: #175ddc;
|
||||||
|
}
|
||||||
|
.st1 {
|
||||||
|
fill: #ffffff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<path
|
||||||
|
id="Background"
|
||||||
|
class="st0"
|
||||||
|
d="M1024,864c0,88.4-71.6,160-160,160H160C71.6,1024,0,952.4,0,864V160C0,71.6,71.6,0,160,0h704 c88.4,0,160,71.6,160,160V864z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
id="Identity"
|
||||||
|
class="st1"
|
||||||
|
d="M829.8,128.6c-6.5-6.5-14.2-9.7-23-9.7H217.2c-8.9,0-16.5,3.2-23,9.7c-6.5,6.5-9.7,14.2-9.7,23 v393.1c0,29.3,5.7,58.4,17.1,87.3c11.4,28.8,25.6,54.4,42.5,76.8c16.9,22.3,37,44.1,60.4,65.3c23.4,21.2,45,38.7,64.7,52.7 c19.8,14,40.4,27.2,61.9,39.7c21.5,12.5,36.8,20.9,45.8,25.3c9,4.4,16.3,7.9,21.7,10.2c4.1,2,8.5,3.1,13.3,3.1c4.8,0,9.2-1,13.3-3.1 c5.5-2.4,12.7-5.8,21.8-10.2c9-4.4,24.3-12.9,45.8-25.3c21.5-12.5,42.1-25.7,61.9-39.7c19.8-14,41.4-31.6,64.8-52.7 c23.4-21.2,43.5-42.9,60.4-65.3c16.9-22.4,31-47.9,42.5-76.8c11.4-28.8,17.1-57.9,17.1-87.3V151.7 C839.6,142.8,836.3,135.1,829.8,128.6z M753.8,548.4c0,142.3-241.8,264.9-241.8,264.9V203.1h241.8 C753.8,203.1,753.8,406.1,753.8,548.4z"
|
||||||
|
/>
|
||||||
|
</svg>
|
@@ -116,6 +116,12 @@ export const supportedServiceTypesAndVersions = [
|
|||||||
fancyName: 'Wordpress',
|
fancyName: 'Wordpress',
|
||||||
baseImage: 'wordpress',
|
baseImage: 'wordpress',
|
||||||
versions: ['latest', 'php8.1', 'php8.0', 'php7.4', 'php7.3']
|
versions: ['latest', 'php8.1', 'php8.0', 'php7.4', 'php7.3']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'vaultwarden',
|
||||||
|
fancyName: 'Vaultwarden',
|
||||||
|
baseImage: 'vaultwarden/server',
|
||||||
|
versions: ['latest']
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@@ -99,6 +99,13 @@ export async function configureServiceType({ id, type }) {
|
|||||||
wordpress: { create: { mysqlPassword, mysqlRootUserPassword, mysqlRootUser, mysqlUser } }
|
wordpress: { create: { mysqlPassword, mysqlRootUserPassword, mysqlRootUser, mysqlUser } }
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} else if (type === 'vaultwarden') {
|
||||||
|
await prisma.service.update({
|
||||||
|
where: { id },
|
||||||
|
data: {
|
||||||
|
type
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export async function setService({ id, version }) {
|
export async function setService({ id, version }) {
|
||||||
@@ -115,6 +122,9 @@ export async function updatePlausibleAnalyticsService({ id, fqdn, email, usernam
|
|||||||
export async function updateNocoDbOrMinioService({ id, fqdn, name }) {
|
export async function updateNocoDbOrMinioService({ id, fqdn, name }) {
|
||||||
return await prisma.service.update({ where: { id }, data: { fqdn, name } });
|
return await prisma.service.update({ where: { id }, data: { fqdn, name } });
|
||||||
}
|
}
|
||||||
|
export async function updateVaultWardenService({ id, fqdn, name }) {
|
||||||
|
return await prisma.service.update({ where: { id }, data: { fqdn, name } });
|
||||||
|
}
|
||||||
export async function updateVsCodeServer({ id, fqdn, name }) {
|
export async function updateVsCodeServer({ id, fqdn, name }) {
|
||||||
return await prisma.service.update({ where: { id }, data: { fqdn, name } });
|
return await prisma.service.update({ where: { id }, data: { fqdn, name } });
|
||||||
}
|
}
|
||||||
|
@@ -602,11 +602,7 @@ export async function configureNetworkCoolifyProxy(engine) {
|
|||||||
|
|
||||||
export async function configureSimpleServiceProxyOn({ id, domain, port }) {
|
export async function configureSimpleServiceProxyOn({ id, domain, port }) {
|
||||||
const haproxy = await haproxyInstance();
|
const haproxy = await haproxyInstance();
|
||||||
try {
|
await checkHAProxy(haproxy);
|
||||||
await checkHAProxy(haproxy);
|
|
||||||
} catch (error) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
await haproxy.get(`v2/services/haproxy/configuration/backends/${domain}`).json();
|
await haproxy.get(`v2/services/haproxy/configuration/backends/${domain}`).json();
|
||||||
return;
|
return;
|
||||||
|
@@ -36,6 +36,7 @@
|
|||||||
import Wordpress from '$lib/components/svg/services/Wordpress.svelte';
|
import Wordpress from '$lib/components/svg/services/Wordpress.svelte';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import { post } from '$lib/api';
|
import { post } from '$lib/api';
|
||||||
|
import VaultWarden from '$lib/components/svg/services/VaultWarden.svelte';
|
||||||
|
|
||||||
const { id } = $page.params;
|
const { id } = $page.params;
|
||||||
const from = $page.url.searchParams.get('from');
|
const from = $page.url.searchParams.get('from');
|
||||||
@@ -71,6 +72,8 @@
|
|||||||
<VsCodeServer isAbsolute />
|
<VsCodeServer isAbsolute />
|
||||||
{:else if type.name === 'wordpress'}
|
{:else if type.name === 'wordpress'}
|
||||||
<Wordpress isAbsolute />
|
<Wordpress isAbsolute />
|
||||||
|
{:else if type.name === 'vaultwarden'}
|
||||||
|
<VaultWarden isAbsolute />
|
||||||
{/if}{type.fancyName}
|
{/if}{type.fancyName}
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
@@ -36,6 +36,7 @@
|
|||||||
import Wordpress from '$lib/components/svg/services/Wordpress.svelte';
|
import Wordpress from '$lib/components/svg/services/Wordpress.svelte';
|
||||||
import Services from './_Services/_Services.svelte';
|
import Services from './_Services/_Services.svelte';
|
||||||
import { getDomain } from '$lib/components/common';
|
import { getDomain } from '$lib/components/common';
|
||||||
|
import VaultWarden from '$lib/components/svg/services/VaultWarden.svelte';
|
||||||
|
|
||||||
export let service;
|
export let service;
|
||||||
export let isRunning;
|
export let isRunning;
|
||||||
@@ -94,6 +95,10 @@
|
|||||||
<a href="https://wordpress.org" target="_blank">
|
<a href="https://wordpress.org" target="_blank">
|
||||||
<Wordpress />
|
<Wordpress />
|
||||||
</a>
|
</a>
|
||||||
|
{:else if service.type === 'vaultwarden'}
|
||||||
|
<a href="https://github.com/dani-garcia/vaultwarden" target="_blank">
|
||||||
|
<VaultWarden />
|
||||||
|
</a>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
20
src/routes/services/[id]/vaultwarden/index.json.ts
Normal file
20
src/routes/services/[id]/vaultwarden/index.json.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import { getUserDetails } from '$lib/common';
|
||||||
|
import * as db from '$lib/database';
|
||||||
|
import { PrismaErrorHandler } from '$lib/database';
|
||||||
|
import type { RequestHandler } from '@sveltejs/kit';
|
||||||
|
|
||||||
|
export const post: RequestHandler = async (event) => {
|
||||||
|
const { status, body } = await getUserDetails(event);
|
||||||
|
if (status === 401) return { status, body };
|
||||||
|
const { id } = event.params;
|
||||||
|
|
||||||
|
let { name, fqdn } = await event.request.json();
|
||||||
|
if (fqdn) fqdn = fqdn.toLowerCase();
|
||||||
|
|
||||||
|
try {
|
||||||
|
await db.updateVaultWardenService({ id, fqdn, name });
|
||||||
|
return { status: 201 };
|
||||||
|
} catch (error) {
|
||||||
|
return PrismaErrorHandler(error);
|
||||||
|
}
|
||||||
|
};
|
83
src/routes/services/[id]/vaultwarden/start.json.ts
Normal file
83
src/routes/services/[id]/vaultwarden/start.json.ts
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
import { asyncExecShell, createDirectories, getEngine, getUserDetails } from '$lib/common';
|
||||||
|
import * as db from '$lib/database';
|
||||||
|
import { promises as fs } from 'fs';
|
||||||
|
import yaml from 'js-yaml';
|
||||||
|
import type { RequestHandler } from '@sveltejs/kit';
|
||||||
|
import { letsEncrypt } from '$lib/letsencrypt';
|
||||||
|
import { configureSimpleServiceProxyOn, reloadHaproxy } from '$lib/haproxy';
|
||||||
|
import { getDomain } from '$lib/components/common';
|
||||||
|
import { getServiceImage, PrismaErrorHandler } from '$lib/database';
|
||||||
|
|
||||||
|
export const post: RequestHandler = async (event) => {
|
||||||
|
const { teamId, status, body } = await getUserDetails(event);
|
||||||
|
if (status === 401) return { status, body };
|
||||||
|
|
||||||
|
const { id } = event.params;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const service = await db.getService({ id, teamId });
|
||||||
|
const { type, version, fqdn, destinationDockerId, destinationDocker } = service;
|
||||||
|
|
||||||
|
const domain = getDomain(fqdn);
|
||||||
|
const isHttps = fqdn.startsWith('https://');
|
||||||
|
|
||||||
|
const network = destinationDockerId && destinationDocker.network;
|
||||||
|
const host = getEngine(destinationDocker.engine);
|
||||||
|
|
||||||
|
const { workdir } = await createDirectories({ repository: type, buildId: id });
|
||||||
|
const baseImage = getServiceImage(type);
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
image: `${baseImage}:${version}`,
|
||||||
|
volume: `${id}-vaultwarden-data:/data/`
|
||||||
|
};
|
||||||
|
|
||||||
|
const composeFile = {
|
||||||
|
version: '3.8',
|
||||||
|
services: {
|
||||||
|
[id]: {
|
||||||
|
container_name: id,
|
||||||
|
image: config.image,
|
||||||
|
networks: [network],
|
||||||
|
volumes: [config.volume],
|
||||||
|
restart: 'always'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
networks: {
|
||||||
|
[network]: {
|
||||||
|
external: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
volumes: {
|
||||||
|
[config.volume.split(':')[0]]: {
|
||||||
|
external: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const composeFileDestination = `${workdir}/docker-compose.yaml`;
|
||||||
|
await fs.writeFile(composeFileDestination, yaml.dump(composeFile));
|
||||||
|
try {
|
||||||
|
await asyncExecShell(
|
||||||
|
`DOCKER_HOST=${host} docker volume create ${config.volume.split(':')[0]}`
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`);
|
||||||
|
await configureSimpleServiceProxyOn({ id, domain, port: 80 });
|
||||||
|
|
||||||
|
if (isHttps) {
|
||||||
|
await letsEncrypt({ domain, id });
|
||||||
|
}
|
||||||
|
await reloadHaproxy(destinationDocker.engine);
|
||||||
|
return {
|
||||||
|
status: 200
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
return PrismaErrorHandler(error);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
return PrismaErrorHandler(error);
|
||||||
|
}
|
||||||
|
};
|
39
src/routes/services/[id]/vaultwarden/stop.json.ts
Normal file
39
src/routes/services/[id]/vaultwarden/stop.json.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import { getUserDetails, removeDestinationDocker } from '$lib/common';
|
||||||
|
import { getDomain } from '$lib/components/common';
|
||||||
|
import * as db from '$lib/database';
|
||||||
|
import { PrismaErrorHandler } from '$lib/database';
|
||||||
|
import { dockerInstance } from '$lib/docker';
|
||||||
|
import { checkContainer, configureSimpleServiceProxyOff } from '$lib/haproxy';
|
||||||
|
import type { RequestHandler } from '@sveltejs/kit';
|
||||||
|
|
||||||
|
export const post: RequestHandler = async (event) => {
|
||||||
|
const { teamId, status, body } = await getUserDetails(event);
|
||||||
|
if (status === 401) return { status, body };
|
||||||
|
|
||||||
|
const { id } = event.params;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const service = await db.getService({ id, teamId });
|
||||||
|
const { destinationDockerId, destinationDocker, fqdn } = service;
|
||||||
|
const domain = getDomain(fqdn);
|
||||||
|
if (destinationDockerId) {
|
||||||
|
const engine = destinationDocker.engine;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const found = await checkContainer(engine, id);
|
||||||
|
if (found) {
|
||||||
|
await removeDestinationDocker({ id, engine });
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
await configureSimpleServiceProxyOff({ domain });
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
status: 200
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
return PrismaErrorHandler(error);
|
||||||
|
}
|
||||||
|
};
|
@@ -25,6 +25,7 @@
|
|||||||
import MinIo from '$lib/components/svg/services/MinIO.svelte';
|
import MinIo from '$lib/components/svg/services/MinIO.svelte';
|
||||||
import VsCodeServer from '$lib/components/svg/services/VSCodeServer.svelte';
|
import VsCodeServer from '$lib/components/svg/services/VSCodeServer.svelte';
|
||||||
import Wordpress from '$lib/components/svg/services/Wordpress.svelte';
|
import Wordpress from '$lib/components/svg/services/Wordpress.svelte';
|
||||||
|
import VaultWarden from '$lib/components/svg/services/VaultWarden.svelte';
|
||||||
|
|
||||||
export let services;
|
export let services;
|
||||||
</script>
|
</script>
|
||||||
@@ -67,6 +68,8 @@
|
|||||||
<VsCodeServer isAbsolute />
|
<VsCodeServer isAbsolute />
|
||||||
{:else if service.type === 'wordpress'}
|
{:else if service.type === 'wordpress'}
|
||||||
<Wordpress isAbsolute />
|
<Wordpress isAbsolute />
|
||||||
|
{:else if service.type === 'vaultwarden'}
|
||||||
|
<VaultWarden isAbsolute />
|
||||||
{/if}
|
{/if}
|
||||||
<div class="font-bold text-xl text-center truncate">
|
<div class="font-bold text-xl text-center truncate">
|
||||||
{service.name}
|
{service.name}
|
||||||
|
Reference in New Issue
Block a user