diff --git a/apps/client/src/lib/components/DocLink.svelte b/apps/client/src/lib/components/DocLink.svelte
new file mode 100644
index 000000000..803b48583
--- /dev/null
+++ b/apps/client/src/lib/components/DocLink.svelte
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+ {text}
+ {#if isExternal}
+
+ {/if}
+
+{#if !text}
+ See details in the documentation
+{/if}
diff --git a/apps/client/src/lib/components/ExternalLink.svelte b/apps/client/src/lib/components/ExternalLink.svelte
new file mode 100644
index 000000000..62f2e312a
--- /dev/null
+++ b/apps/client/src/lib/components/ExternalLink.svelte
@@ -0,0 +1,10 @@
+
+
+
diff --git a/apps/client/src/lib/components/icons/services/ServiceIcons.svelte b/apps/client/src/lib/components/icons/services/ServiceIcons.svelte
index 7f146e3fb..7f3ead42e 100644
--- a/apps/client/src/lib/components/icons/services/ServiceIcons.svelte
+++ b/apps/client/src/lib/components/icons/services/ServiceIcons.svelte
@@ -5,6 +5,7 @@
const handleError = (ev: { target: { src: string } }) => (ev.target.src = fallback);
let extension = 'png';
let svgs = [
+ 'directus',
'pocketbase',
'gitea',
'languagetool',
diff --git a/apps/client/src/lib/store.ts b/apps/client/src/lib/store.ts
index 87afa0034..dc45778b2 100644
--- a/apps/client/src/lib/store.ts
+++ b/apps/client/src/lib/store.ts
@@ -171,3 +171,11 @@ export const setLocation = (resource: any, settings?: any) => {
}
};
export const selectedBuildId: any = writable(null)
+export function checkIfDeploymentEnabledServices( service: any) {
+ return (
+ service.fqdn &&
+ service.destinationDocker &&
+ service.version &&
+ service.type
+ );
+}
\ No newline at end of file
diff --git a/apps/client/src/routes/services/[id]/+layout.svelte b/apps/client/src/routes/services/[id]/+layout.svelte
new file mode 100644
index 000000000..f218a664c
--- /dev/null
+++ b/apps/client/src/routes/services/[id]/+layout.svelte
@@ -0,0 +1,366 @@
+
+
+
+
+
+ {#if $status.service.initialLoading}
+
+
+
+
+
+
+
+
+
+
+ {$status.service.startup[id] || 'Loading...'}
+
+ {:else if $status.service.overallStatus === 'healthy'}
+
restartService()}
+ >
+
+
+
+
+
+ Force Redeploy
+
+
stopService(false)}
+ type="submit"
+ disabled={!$isDeploymentEnabled || !$appSession.isAdmin}
+ class="btn btn-sm gap-2"
+ >
+
+
+
+
+
+ Stop
+
+ {:else if $status.service.overallStatus === 'degraded'}
+
stopService()}
+ type="submit"
+ disabled={!$isDeploymentEnabled || !$appSession.isAdmin}
+ class="btn btn-sm gap-2"
+ >
+
+
+
+
+ Stop
+
+ {:else if $status.service.overallStatus === 'stopped'}
+ {#if $status.service.overallStatus === 'degraded'}
+
restartService()}
+ >
+
+
+
+
+ {$status.application.statuses.length === 1 ? 'Force Redeploy' : 'Redeploy Stack'}
+
+ {:else if $status.service.overallStatus === 'stopped'}
+
startService()}
+ >
+
+
+
+
+ Deploy
+
+ {/if}
+ {/if}
+
+
+
+
+ {#if !$page.url.pathname.startsWith(`/services/${id}/configuration/`)}
+
+ {/if}
+
+
+
+
diff --git a/apps/client/src/routes/services/[id]/+layout.ts b/apps/client/src/routes/services/[id]/+layout.ts
new file mode 100644
index 000000000..9027326c5
--- /dev/null
+++ b/apps/client/src/routes/services/[id]/+layout.ts
@@ -0,0 +1,46 @@
+import { error } from '@sveltejs/kit';
+import { trpc } from '$lib/store';
+import type { LayoutLoad } from './$types';
+import { redirect } from '@sveltejs/kit';
+
+function checkConfiguration(service: any): string | null {
+ let configurationPhase = null;
+ if (!service.type) {
+ configurationPhase = 'type';
+ } else if (!service.destinationDockerId) {
+ configurationPhase = 'destination';
+ }
+ return configurationPhase;
+}
+
+export const load: LayoutLoad = async ({ params, url }) => {
+ const { pathname } = new URL(url);
+ const { id } = params;
+ try {
+ const service = await trpc.services.getServices.query({ id });
+ if (!service) {
+ throw redirect(307, '/services');
+ }
+ const configurationPhase = checkConfiguration(service);
+ console.log({ configurationPhase });
+ // if (
+ // configurationPhase &&
+ // pathname !== `/applications/${params.id}/configuration/${configurationPhase}`
+ // ) {
+ // throw redirect(302, `/applications/${params.id}/configuration/${configurationPhase}`);
+ // }
+ return {
+ ...service.data
+ };
+ } catch (err) {
+ if (err instanceof Error) {
+ throw error(500, {
+ message: 'An unexpected error occurred, please try again later.' + ' ' + err.message
+ });
+ }
+
+ throw error(500, {
+ message: 'An unexpected error occurred, please try again later.'
+ });
+ }
+};
diff --git a/apps/client/src/routes/services/[id]/+page.svelte b/apps/client/src/routes/services/[id]/+page.svelte
new file mode 100644
index 000000000..2dd38eadb
--- /dev/null
+++ b/apps/client/src/routes/services/[id]/+page.svelte
@@ -0,0 +1,562 @@
+
+
+
diff --git a/apps/client/src/routes/services/[id]/components/Menu.svelte b/apps/client/src/routes/services/[id]/components/Menu.svelte
new file mode 100644
index 000000000..bfc3a577a
--- /dev/null
+++ b/apps/client/src/routes/services/[id]/components/Menu.svelte
@@ -0,0 +1,138 @@
+
+
+
diff --git a/apps/client/src/routes/services/[id]/components/ServiceLinks.svelte b/apps/client/src/routes/services/[id]/components/ServiceLinks.svelte
new file mode 100644
index 000000000..c4a23e5b7
--- /dev/null
+++ b/apps/client/src/routes/services/[id]/components/ServiceLinks.svelte
@@ -0,0 +1,14 @@
+
+
+{#if linkToDocs}
+
+{:else}
+
+{/if}
diff --git a/apps/client/src/routes/services/[id]/components/ServiceStatus.svelte b/apps/client/src/routes/services/[id]/components/ServiceStatus.svelte
new file mode 100644
index 000000000..f6cb092f5
--- /dev/null
+++ b/apps/client/src/routes/services/[id]/components/ServiceStatus.svelte
@@ -0,0 +1,37 @@
+
+
+{#if serviceStatus.isExcluded}
+ Excluded
+{:else if serviceStatus.isRunning}
+ Running
+{:else if serviceStatus.isStopped || serviceStatus.isExited}
+ Stopped
+{:else if serviceStatus.isRestarting}
+ Restarting
+{/if}
diff --git a/apps/client/src/routes/services/[id]/components/Wordpress.svelte b/apps/client/src/routes/services/[id]/components/Wordpress.svelte
new file mode 100644
index 000000000..7d5c2234a
--- /dev/null
+++ b/apps/client/src/routes/services/[id]/components/Wordpress.svelte
@@ -0,0 +1,85 @@
+
+
+
+ changeSettings('ftpEnabled')}
+ title="Enable sFTP connection to WordPress data"
+ description="Enables an on-demand sFTP connection to the WordPress data directory. This is useful if you want to use sFTP to upload files."
+ />
+
+{#if service.wordpress?.ftpEnabled}
+
+ sFTP Connection URI
+
+
+
+ User
+
+
+
+ Password
+
+
+{/if}
diff --git a/apps/client/src/routes/services/[id]/danger/+page.svelte b/apps/client/src/routes/services/[id]/danger/+page.svelte
new file mode 100644
index 000000000..dc064d129
--- /dev/null
+++ b/apps/client/src/routes/services/[id]/danger/+page.svelte
@@ -0,0 +1,46 @@
+
+
+
+
+
deleteService()}
+ type="submit"
+ disabled={!$appSession.isAdmin}
+ class:bg-red-600={$appSession.isAdmin}
+ class:hover:bg-red-500={$appSession.isAdmin}
+ class="btn btn-lg btn-error text-sm"
+ >
+ Delete Service
+
+
diff --git a/apps/client/src/routes/services/[id]/logs/+page.svelte b/apps/client/src/routes/services/[id]/logs/+page.svelte
new file mode 100644
index 000000000..87bc77010
--- /dev/null
+++ b/apps/client/src/routes/services/[id]/logs/+page.svelte
@@ -0,0 +1,173 @@
+
+
+
+
+{#if template}
+
+ {#each Object.keys(template) as service}
+ selectService(service, true)}
+ class:bg-primary={selectedService === service}
+ class:bg-coolgray-200={selectedService !== service}
+ class="w-full rounded p-5 hover:bg-primary font-bold"
+ >
+ {#if template[service].name}
+ {template[service].name || ''} ({service})
+ {:else}
+ {service}
+ {/if}
+
+ {/each}
+
+{:else}
+ Loading components...
+{/if}
+
+{#if selectedService}
+
+ {#if logs.length === 0}
+ {#if noContainer}
+
Container not found / exited.
+ {/if}
+ {:else}
+
+
+
+
+
+
+
+
+
+
+ {followingLogs ? 'Following Logs...' : 'Follow Logs'}
+
+ {#if loadLogsInterval}
+
Streaming logs
+ {/if}
+
+
+
+ {/if}
+
+{/if}
diff --git a/apps/client/src/routes/services/[id]/secrets/+page.svelte b/apps/client/src/routes/services/[id]/secrets/+page.svelte
new file mode 100644
index 000000000..2005404f7
--- /dev/null
+++ b/apps/client/src/routes/services/[id]/secrets/+page.svelte
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+
+
+ Name
+ Value
+ Action
+
+
+
+ {#each secrets as secret}
+ {#key secret.id}
+
+
+
+ {/key}
+ {/each}
+
+
+
+
+
+
+ {#if $appSession.isAdmin}
+
+
+
+
Paste .env
file
+
Add Secrets in Batch
+
+
+
+
+
+ {/if}
+
diff --git a/apps/client/src/routes/services/[id]/secrets/+page.ts b/apps/client/src/routes/services/[id]/secrets/+page.ts
new file mode 100644
index 000000000..ee881f4e7
--- /dev/null
+++ b/apps/client/src/routes/services/[id]/secrets/+page.ts
@@ -0,0 +1,16 @@
+import { error } from '@sveltejs/kit';
+import { trpc } from '$lib/store';
+import type { PageLoad } from './$types';
+export const ssr = false;
+
+export const load: PageLoad = async ({ params }) => {
+ try {
+ const { id } = params;
+ const { data } = await trpc.services.getSecrets.query({ id });
+ return data;
+ } catch (err) {
+ throw error(500, {
+ message: 'An unexpected error occurred, please try again later.'
+ });
+ }
+};
diff --git a/apps/client/src/routes/services/[id]/secrets/components/Secret.svelte b/apps/client/src/routes/services/[id]/secrets/components/Secret.svelte
new file mode 100644
index 000000000..1ad678005
--- /dev/null
+++ b/apps/client/src/routes/services/[id]/secrets/components/Secret.svelte
@@ -0,0 +1,101 @@
+
+
+
+
+
+
+
+
+
+{#if $appSession.isAdmin}
+
+ {#if isNewSecret}
+
+ saveSecret(true)}>Add
+
+ {:else if !readonly}
+
+
+ saveSecret(false)}>Set
+
+
+ Remove
+
+
+ {/if}
+
+{/if}
diff --git a/apps/client/src/routes/services/[id]/secrets/utils.ts b/apps/client/src/routes/services/[id]/secrets/utils.ts
new file mode 100644
index 000000000..d2cabd386
--- /dev/null
+++ b/apps/client/src/routes/services/[id]/secrets/utils.ts
@@ -0,0 +1,78 @@
+import { errorNotification } from '$lib/common';
+import { trpc } from '$lib/store';
+
+type Props = {
+ isNew: boolean;
+ name: string;
+ value: string;
+ isBuildSecret?: boolean;
+ isPRMRSecret?: boolean;
+ isNewSecret?: boolean;
+ serviceId: string;
+};
+
+export async function saveSecret({
+ isNew,
+ name,
+ value,
+ isBuildSecret,
+ isNewSecret
+}: Props): Promise {
+ if (!name) return errorNotification('Name is required');
+ if (!value) return errorNotification('Value is required');
+ try {
+ await trpc.services.createSecret.mutate({
+ name,
+ value,
+ isBuildSecret,
+ isNew: isNew || false
+ });
+
+ if (isNewSecret) {
+ name = '';
+ value = '';
+ isBuildSecret = false;
+ }
+ } catch (error) {
+ throw error;
+ }
+}
+
+export async function saveForm(formData: any, service: any) {
+ const settings = service.serviceSetting.map((setting: { name: string }) => setting.name);
+ const secrets = service.serviceSecret.map((secret: { name: string }) => secret.name);
+ const baseCoolifySetting = ['name', 'fqdn', 'exposePort', 'version'];
+ for (let field of formData) {
+ const [key, value] = field;
+ if (secrets.includes(key) && value) {
+ await trpc.services.createSecret.mutate({
+ name: key,
+ value
+ });
+ } else {
+ service.serviceSetting = service.serviceSetting.map((setting: any) => {
+ if (setting.name === key) {
+ setting.changed = true;
+ setting.value = value;
+ }
+ return setting;
+ });
+ if (!settings.includes(key) && !baseCoolifySetting.includes(key)) {
+ service.serviceSetting.push({
+ id: service.id,
+ name: key,
+ value: value,
+ isNew: true
+ });
+ }
+ if (baseCoolifySetting.includes(key)) {
+ service[key] = value;
+ }
+ }
+ }
+ await trpc.services.saveService.mutate(service);
+ const {
+ data: { service: reloadedService }
+ } = await trpc.services.getServices.query({ id: service.id });
+ return reloadedService;
+}
diff --git a/apps/client/src/routes/services/[id]/storages/+page.svelte b/apps/client/src/routes/services/[id]/storages/+page.svelte
new file mode 100644
index 000000000..7b0fa33df
--- /dev/null
+++ b/apps/client/src/routes/services/[id]/storages/+page.svelte
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+ Persistent Volumes
+
+
+ {#if persistentStorages.filter((s) => s.predefined).length > 0}
+
Predefined Volumes
+
+
+
Container
+
Volume ID : Mount Dir
+
+
+
+ {#each persistentStorages.filter((s) => s.predefined) as storage}
+ {#key storage.id}
+
+ {/key}
+ {/each}
+ {/if}
+
+ {#if persistentStorages.filter((s) => !s.predefined).length > 0}
+
s.predefined).length > 0}>
+ Custom Volumes
+
+
+ {#each persistentStorages.filter((s) => !s.predefined) as storage}
+ {#key storage.id}
+
+ {/key}
+ {/each}
+ {/if}
+ {#if $appSession.isAdmin}
+
s.predefined).length > 0}>
+ Add New Volume
+
+
+ {/if}
+
+
diff --git a/apps/client/src/routes/services/[id]/storages/+page.ts b/apps/client/src/routes/services/[id]/storages/+page.ts
new file mode 100644
index 000000000..5c21ebee9
--- /dev/null
+++ b/apps/client/src/routes/services/[id]/storages/+page.ts
@@ -0,0 +1,16 @@
+import { error } from '@sveltejs/kit';
+import { trpc } from '$lib/store';
+import type { PageLoad } from './$types';
+export const ssr = false;
+
+export const load: PageLoad = async ({ params }) => {
+ try {
+ const { id } = params;
+ const { data } = await trpc.services.getStorages.query({ id });
+ return data;
+ } catch (err) {
+ throw error(500, {
+ message: 'An unexpected error occurred, please try again later.'
+ });
+ }
+};
diff --git a/apps/client/src/routes/services/[id]/storages/components/Storage.svelte b/apps/client/src/routes/services/[id]/storages/components/Storage.svelte
new file mode 100644
index 000000000..cb4f0fafd
--- /dev/null
+++ b/apps/client/src/routes/services/[id]/storages/components/Storage.svelte
@@ -0,0 +1,167 @@
+
+
+
+ {#if storage.predefined}
+
+ {:else if isNew}
+
+
+
+
+ Container
+
+ {#if services.length === 1}
+ {#if services[0].name}
+ {services[0].name}
+ {:else}
+ {services[0]}
+ {/if}
+ {:else}
+ {#each services as service}
+ {#if service.name}
+ {service.name}
+ {:else}
+ {service}
+ {/if}
+ {/each}
+ {/if}
+
+
+
+ Path
+
+
+
+
+ Add
+
+
+
+ {:else}
+
+ s.id === storage.containerId).name || storage.containerId}`}
+ />
+
+ removeStorage(storage)}>Remove
+
+ {/if}
+
diff --git a/apps/client/src/routes/services/[id]/utils.ts b/apps/client/src/routes/services/[id]/utils.ts
new file mode 100644
index 000000000..e2aeac4b2
--- /dev/null
+++ b/apps/client/src/routes/services/[id]/utils.ts
@@ -0,0 +1,79 @@
+import { errorNotification } from '$lib/common';
+
+type Props = {
+ isNew: boolean;
+ name: string;
+ value: string;
+ isBuildSecret?: boolean;
+ isPRMRSecret?: boolean;
+ isNewSecret?: boolean;
+ serviceId: string;
+};
+
+export async function saveSecret({
+ isNew,
+ name,
+ value,
+ isBuildSecret,
+ isPRMRSecret,
+ isNewSecret,
+ serviceId
+}: Props): Promise {
+ if (!name) return errorNotification('Name is required');
+ if (!value) return errorNotification('Value is required');
+ try {
+ // await post(`/services/${serviceId}/secrets`, {
+ // name,
+ // value,
+ // isBuildSecret,
+ // isPRMRSecret,
+ // isNew: isNew || false
+ // });
+ if (isNewSecret) {
+ name = '';
+ value = '';
+ isBuildSecret = false;
+ }
+ } catch (error) {
+ throw error
+ }
+}
+
+export async function saveForm(formData: any, service: any) {
+ const settings = service.serviceSetting.map((setting: { name: string }) => setting.name);
+ const secrets = service.serviceSecret.map((secret: { name: string }) => secret.name);
+ const baseCoolifySetting = ['name', 'fqdn', 'exposePort', 'version'];
+ for (let field of formData) {
+ const [key, value] = field;
+ if (secrets.includes(key) && value) {
+ // await post(`/services/${service.id}/secrets`, {
+ // name: key,
+ // value,
+ // });
+ } else {
+ service.serviceSetting = service.serviceSetting.map((setting: any) => {
+ if (setting.name === key) {
+ setting.changed = true;
+ setting.value = value;
+ }
+ return setting;
+ });
+ if (!settings.includes(key) && !baseCoolifySetting.includes(key)) {
+ service.serviceSetting.push({
+ id: service.id,
+ name: key,
+ value: value,
+ isNew: true
+ });
+ }
+ if (baseCoolifySetting.includes(key)) {
+ service[key] = value;
+ }
+ }
+
+ }
+ // await post(`/services/${service.id}`, { ...service });
+ // const { service: reloadedService } = await get(`/services/${service.id}`);
+ // return reloadedService;
+
+}
diff --git a/apps/server/devTags.json b/apps/server/devTags.json
new file mode 100644
index 000000000..5d4ef05cd
--- /dev/null
+++ b/apps/server/devTags.json
@@ -0,0 +1,1013 @@
+[
+ { "name": "directus-postgresql", "image": "directus/directus", "tags": ["9.22"] },
+ { "name": "whoogle", "image": "benbusby/whoogle-search", "tags": ["0.8.1"] },
+ { "name": "libretranslate", "image": "libretranslate/libretranslate", "tags": ["v1.3.8"] },
+ {
+ "name": "appsmith",
+ "image": "appsmith/appsmith-ce",
+ "tags": [
+ "v1.9.1",
+ "v1.8.15",
+ "v1.8.12",
+ "v1.8.10",
+ "v1.8.9",
+ "v1.8.7",
+ "v1.8.5",
+ "v1.8.3",
+ "v1.8.0",
+ "v1.7.13",
+ "v1.7.11",
+ "v1.7.8",
+ "v1.7.6",
+ "v1.7.4",
+ "v1.7.2",
+ "v1.7.1",
+ "v1.6.22",
+ "v1.6.20",
+ "v1.6.19",
+ "v1.6.17",
+ "v1.6.15",
+ "v1.6.13",
+ "v1.6.11",
+ "v1.6.9",
+ "v1.6.7",
+ "v1.6.5",
+ "v1.6.3",
+ "v1.6.1",
+ "v1.5.30",
+ "v1.5.28"
+ ]
+ },
+ {
+ "name": "appwrite",
+ "image": "appwrite/appwrite",
+ "tags": [
+ "1.2.0",
+ "1.1.2",
+ "1.1.0",
+ "1.0.3",
+ "1.0.1",
+ "1.0.0",
+ "0.15.2",
+ "0.15.0",
+ "0.14.2",
+ "0.14.0",
+ "0.13.4",
+ "0.13.2",
+ "0.13.0",
+ "0.12.3",
+ "0.12.1",
+ "0.12.0",
+ "0.11.2",
+ "0.11.0",
+ "0.10.4",
+ "0.10.2",
+ "0.10.0",
+ "0.9.3",
+ "0.9.1",
+ "0.8.0",
+ "0.7.1",
+ "0.6.2",
+ "0.6.0",
+ "0.5.2",
+ "0.5.0",
+ "0.3.1"
+ ]
+ },
+ {
+ "name": "fider",
+ "image": "getfider/fider",
+ "tags": [
+ "stable",
+ "master",
+ "main",
+ "dev",
+ "SHA_ee6e83cfaadadaa56ab76e089e01f5631af3506f",
+ "SHA_deb4f9b4f561d890d8a80e6872fea9a98a265cc6",
+ "SHA_d5cc307909d43447200483d76b5db74d8ed8349e",
+ "SHA_d1674476577a7fd3c88fc29f91c3f35f5bd6a260",
+ "SHA_d107cbb157abca6576110080736213efe0955cff",
+ "SHA_c9c55b2f5b33a76015241b97e03cfac1254b42a7",
+ "SHA_bcf451a3cb02d5c8a489fd30309249296057b084",
+ "SHA_bbfe419639514f949a042807addf0fde7d4de225",
+ "SHA_adc3afc4c7bcf96931a5f90cab65c282d860dbfd",
+ "SHA_ab5283ae95334f10b5041402dce79e333c472015",
+ "SHA_a3f4cb5ed0a4ee2d726705fc426636364aac17a1",
+ "SHA_a18224142bf51bc6463c3d22f45f62287902e9a6",
+ "SHA_8e5cff30d95963eaee2587488d351e0d658c8195",
+ "SHA_8cabe2817ce7ccaf2f0a9fdbb1b5d3411de87f81",
+ "SHA_7851f9da566132d87fa2a63004e78c3bc9c09c6c",
+ "SHA_6c0f2bed1754e9d579eb9575129a6e3dbc529c32",
+ "SHA_603508c8790d6a6fb1e852df1a58ead8e5b3ea6c",
+ "SHA_55efacf164a4749b50ee68ae8925e7dc9dfa3a0c",
+ "SHA_4bdd291ce61e5f5dfc063fa1b2d9be8c9ff1d4c4",
+ "SHA_3fba9cb6a9ceab0c78c6cff3220610f591f657cb",
+ "SHA_3d635b57606a9885babe91fe975b11429e0f2c38",
+ "SHA_3b794edbd9789a8aa38ecd3714bc536a675d3058",
+ "SHA_3570c454ad3252b690608f7bf8051737d8519f8a",
+ "SHA_263e2709fd145f3ea511e5557e170102899995b0",
+ "SHA_255c30ed012fc4c39ffc97efc1d3b00425b17c72",
+ "SHA_17f92b16ef790003338f0926fc8d791a9a61333c"
+ ]
+ },
+ {
+ "name": "ghost-mariadb",
+ "image": "bitnami/ghost",
+ "tags": [
+ "5.28.0",
+ "5.27.0",
+ "5.26.4",
+ "5.26.3",
+ "5.26.2",
+ "5.26.1",
+ "5.26.0",
+ "5.25.5",
+ "5.25.4",
+ "5.25.3",
+ "5.25.2",
+ "5.25.1",
+ "5.25.0",
+ "5.24.2",
+ "5.24.1",
+ "5.24.0",
+ "5.23.0",
+ "5.22.11",
+ "5.22.10",
+ "5.22.9",
+ "5.22.8",
+ "5.22.7",
+ "5.22.6",
+ "5.22.5",
+ "5.22.4",
+ "5.22.3",
+ "5.22.2",
+ "5.22.1",
+ "5.22.0",
+ "5.21.0",
+ "4.48.8"
+ ]
+ },
+ {
+ "name": "ghost-mysql",
+ "image": "library/ghost",
+ "tags": [
+ "5.28.0",
+ "5.27.0",
+ "5.26.4",
+ "5.26.3",
+ "5.26.2",
+ "5.26.1",
+ "5.25.5",
+ "5.25.3",
+ "5.25.2",
+ "5.25.1",
+ "5.25.0",
+ "5.24.2",
+ "5.24.1",
+ "5.23.0",
+ "5.22.11",
+ "5.22.10",
+ "5.22.9",
+ "5.22.8",
+ "5.22.4",
+ "5.22.1",
+ "5.20.0",
+ "5.19.3",
+ "5.19.0",
+ "5.18.0",
+ "5.17.2",
+ "5.17.1",
+ "5.17.0",
+ "5.16.2",
+ "5.14.2",
+ "5.14.1"
+ ]
+ },
+ {
+ "name": "ghost-only",
+ "image": "library/ghost",
+ "tags": [
+ "5.28.0",
+ "5.27.0",
+ "5.26.4",
+ "5.26.3",
+ "5.26.2",
+ "5.26.1",
+ "5.25.5",
+ "5.25.3",
+ "5.25.2",
+ "5.25.1",
+ "5.25.0",
+ "5.24.2",
+ "5.24.1",
+ "5.23.0",
+ "5.22.11",
+ "5.22.10",
+ "5.22.9",
+ "5.22.8",
+ "5.22.4",
+ "5.22.1",
+ "5.20.0",
+ "5.19.3",
+ "5.19.0",
+ "5.18.0",
+ "5.17.2",
+ "5.17.1",
+ "5.17.0",
+ "5.16.2",
+ "5.14.2",
+ "5.14.1"
+ ]
+ },
+ {
+ "name": "gitea",
+ "image": "gitea/gitea",
+ "tags": [
+ "1.18.0",
+ "1.17.4",
+ "1.17.3",
+ "1.17.2",
+ "1.17.1",
+ "1.17.0",
+ "1.16.9",
+ "1.16.8",
+ "1.16.7",
+ "1.16.6",
+ "1.16.5",
+ "1.16.4",
+ "1.16.3",
+ "1.16.2",
+ "1.16.1",
+ "1.16.0",
+ "1.15.11",
+ "1.15.10",
+ "1.15.9",
+ "1.15.8",
+ "1.15.7",
+ "1.15.6",
+ "1.15.5",
+ "1.15.4",
+ "1.15.3",
+ "1.15.2",
+ "1.15.1",
+ "1.15.0",
+ "1.14.7",
+ "1.14.6"
+ ]
+ },
+ {
+ "name": "glitchtip",
+ "image": "glitchtip/glitchtip",
+ "tags": [
+ "v3.0.2",
+ "v3.0.0",
+ "v2.0.7",
+ "v2.0.5",
+ "v2.0.2",
+ "v2.0.0",
+ "v1.12.4",
+ "v1.12.2",
+ "v1.12.0",
+ "v1.10.3",
+ "v1.10.1",
+ "v1.9.2",
+ "v1.9.0",
+ "v1.8.4",
+ "v1.8.2",
+ "v1.8.0",
+ "v1.7.1",
+ "v1.6.4",
+ "v1.6.2",
+ "v1.6.0",
+ "v1.5.3",
+ "v1.5.1",
+ "v1.4.1",
+ "v1.3.3",
+ "v1.3.1",
+ "v1.2.6",
+ "v1.2.4",
+ "v1.2.2",
+ "v1.2.0",
+ "v1.1.2"
+ ]
+ },
+ {
+ "name": "grafana",
+ "image": "grafana/grafana",
+ "tags": [
+ "9.3.2",
+ "9.3.1",
+ "9.3.0",
+ "9.2.8",
+ "9.2.7",
+ "9.2.6",
+ "9.2.5",
+ "9.2.4",
+ "9.2.3",
+ "9.2.2",
+ "9.2.1",
+ "9.2.0",
+ "9.1.8",
+ "9.1.7",
+ "9.1.6",
+ "9.1.5",
+ "9.1.4",
+ "9.1.3",
+ "9.1.2",
+ "9.1.1",
+ "9.1.0",
+ "9.0.9",
+ "9.0.8",
+ "9.0.7",
+ "9.0.6",
+ "9.0.5",
+ "9.0.4",
+ "9.0.3",
+ "9.0.2",
+ "9.0.1"
+ ]
+ },
+ {
+ "name": "hasura",
+ "image": "hasura/graphql-engine",
+ "tags": [
+ "v2.16.1",
+ "v2.16.0",
+ "v2.15.2",
+ "v2.14.1",
+ "v2.13.2",
+ "v2.12.1",
+ "v2.11.3",
+ "v2.10.2",
+ "v2.9.0",
+ "v2.8.4",
+ "v2.8.3",
+ "v2.8.2",
+ "v2.8.1",
+ "v2.8.0",
+ "v2.7.0",
+ "v2.6.2",
+ "v2.6.1",
+ "v2.6.0",
+ "v2.5.2",
+ "v2.5.1",
+ "v2.5.0",
+ "v2.4.0",
+ "v2.3.1",
+ "v2.3.0",
+ "v2.2.2",
+ "v2.2.1",
+ "v2.2.0",
+ "v2.1.1",
+ "v2.1.0",
+ "v2.0.10"
+ ]
+ },
+ {
+ "name": "keycloak",
+ "image": "quay.io/keycloak/keycloak",
+ "tags": [
+ "9.0.3",
+ "9.0.0",
+ "8.0.1",
+ "7.0.0",
+ "6.0.1",
+ "6.0.0",
+ "20.0.2",
+ "20.0.1",
+ "20.0.0",
+ "19.0.3",
+ "19.0.1",
+ "19.0.0",
+ "18.0.1",
+ "18.0.0",
+ "17.0.1",
+ "17.0.0",
+ "16.1.0",
+ "15.1.1",
+ "15.0.2",
+ "15.0.0",
+ "13.0.1",
+ "12.0.4",
+ "12.0.2",
+ "12.0.0",
+ "11.0.2",
+ "11.0.0",
+ "10.0.1"
+ ]
+ },
+ {
+ "name": "languagetool",
+ "image": "silviof/docker-languagetool",
+ "tags": ["latest", "6.0", "5.8", "5.7", "5.6", "5.5", "5.4", "5.3"]
+ },
+ {
+ "name": "lavalink",
+ "image": "fredboat/lavalink",
+ "tags": [
+ "v3.7",
+ "v3.6",
+ "v3-vda0b3a4b3916a7b1a2b79702de1143c3a6939810-SNAPSHOT",
+ "v3-vc92690c425390bd20f6c51643c67ba79ab85b7e0-SNAPSHOT",
+ "v3-vab81dcd46adf3e8a961dd57eacd2a1bde1233e6c-SNAPSHOT",
+ "v3-v9c9432704d6a4badfcbd06a57597c54bed8f4326-SNAPSHOT",
+ "v3-v3.0",
+ "v3-v3",
+ "v3-v124f8fae7dab299f9cdf1cb4c1715be455497286-SNAPSHOT",
+ "v3-",
+ "v3",
+ "v2.0.1",
+ "v2.0",
+ "v2",
+ "update-udpqueue-vb4a439d6147dbd8641ea4f265e8efc9f1e16e2d3-SNAPSHOT",
+ "update-udpqueue-",
+ "update-udpqueue",
+ "revert-713-fix-error-for-loading-jda-nas",
+ "refactor-github-actions",
+ "patch-update-lp",
+ "patch-update-github-actions",
+ "patch-more-configurable-github-actions",
+ "patch-lavaplayer-update",
+ "patch-lavaplayer-bump",
+ "patch-build-number",
+ "next-api-vd4db194cac7a839a3899857f1f6d7b910369309d-SNAPSHOT",
+ "next-api-vc2e018d5ffef54b2d17244b3d213e31723a084d6-SNAPSHOT",
+ "next-api-v42cb5f7c58e98d1911e87bffb35aee0a235b85f8-SNAPSHOT",
+ "next-api-v31a243bda80badbd7d643f68fc1f87e99639060f-SNAPSHOT",
+ "next-api-v17f6884434c2d70d1704b2322a951d9f07af8865-SNAPSHOT"
+ ]
+ },
+ {
+ "name": "meilisearch",
+ "image": "getmeili/meilisearch",
+ "tags": [
+ "v0.30.5",
+ "v0.30.3",
+ "v0.30.1",
+ "v0.30.0",
+ "v0.29.3",
+ "v0.29.1",
+ "v0.29.0",
+ "v0.28.1",
+ "v0.28.0",
+ "v0.27.1",
+ "v0.27.0",
+ "v0.26.1",
+ "v0.26.0",
+ "v0.25.1",
+ "v0.25.0",
+ "v0.23.1",
+ "v0.23.0",
+ "v0.21.1",
+ "v0.21.0",
+ "v0.20.0",
+ "v0.19.0",
+ "v0.18.1",
+ "v0.18.0",
+ "v0.17.0",
+ "v0.16.0",
+ "0.14.1",
+ "v0.14.1",
+ "v0.14.0",
+ "v0.12.0",
+ "v0.11.0"
+ ]
+ },
+ {
+ "name": "minio",
+ "image": "minio/minio",
+ "tags": [
+ "RELEASE.2023-01-06T18-11-18Z",
+ "RELEASE.2023-01-02T09-40-09Z",
+ "RELEASE.2022-12-12T19-27-27Z",
+ "RELEASE.2022-12-07T00-56-37Z",
+ "RELEASE.2022-12-02T19-19-22Z",
+ "RELEASE.2022-11-29T23-40-49Z",
+ "RELEASE.2022-11-26T22-43-32Z",
+ "RELEASE.2022-11-17T23-20-09Z",
+ "RELEASE.2022-11-11T03-44-20Z",
+ "RELEASE.2022-11-10T18-20-21Z",
+ "RELEASE.2022-11-08T05-27-07Z",
+ "RELEASE.2022-10-29T06-21-33Z",
+ "RELEASE.2022-10-24T18-35-07Z.hotfix.7906ac5be",
+ "RELEASE.2022-10-24T18-35-07Z",
+ "RELEASE.2022-10-21T22-37-48Z",
+ "RELEASE.2022-10-20T00-55-09Z",
+ "RELEASE.2022-10-15T19-57-03Z",
+ "RELEASE.2022-10-08T20-11-00Z",
+ "RELEASE.2022-10-05T14-58-27Z",
+ "RELEASE.2022-10-02T19-29-29Z",
+ "RELEASE.2022-09-25T15-44-53Z",
+ "RELEASE.2022-09-22T18-57-27Z",
+ "RELEASE.2022-09-17T00-09-45Z.hotfix.f76e5da9f",
+ "RELEASE.2022-09-17T00-09-45Z.fips",
+ "RELEASE.2022-09-07T22-25-02Z.fips",
+ "RELEASE.2022-09-01T23-53-36Z.fips",
+ "RELEASE.2022-08-26T19-53-15Z.fips",
+ "RELEASE.2022-08-25T07-17-05Z.fips",
+ "RELEASE.2022-08-22T23-53-06Z.hotfix.5fa3967bb",
+ "RELEASE.2022-08-22T23-53-06Z"
+ ]
+ },
+ {
+ "name": "n8n",
+ "image": "n8nio/n8n",
+ "tags": [
+ "0.210.1",
+ "0.210.0",
+ "0.209.4",
+ "0.209.3",
+ "0.209.2",
+ "0.209.1",
+ "0.209.0",
+ "0.208.1",
+ "0.208.0",
+ "0.207.1",
+ "0.207.0",
+ "0.206.1",
+ "0.205.0",
+ "0.204.0",
+ "0.203.1",
+ "0.202.1",
+ "0.202.0",
+ "0.201.0",
+ "0.200.1",
+ "0.199.0",
+ "0.198.1",
+ "0.198.0",
+ "0.197.1",
+ "0.197.0",
+ "0.196.0",
+ "0.195.5",
+ "0.195.4",
+ "0.195.3",
+ "0.195.2",
+ "0.195.1"
+ ]
+ },
+ {
+ "name": "nocodb",
+ "image": "nocodb/nocodb",
+ "tags": [
+ "0.100.1",
+ "0.99.1",
+ "0.98.4",
+ "0.98.2",
+ "0.98.0",
+ "0.96.4",
+ "0.96.2",
+ "0.96.0",
+ "0.92.3",
+ "0.91.10",
+ "0.91.9",
+ "0.91.7",
+ "0.91.0",
+ "0.90.10",
+ "0.90.7",
+ "0.90.4",
+ "0.90.2",
+ "0.90.0",
+ "0.84.15",
+ "0.84.12",
+ "0.84.8",
+ "0.84.6",
+ "0.84.2",
+ "0.84.1",
+ "0.83.6",
+ "0.83.3",
+ "0.83.1",
+ "0.82.0",
+ "0.81.0",
+ "0.11.46"
+ ]
+ },
+ {
+ "name": "openblocks",
+ "image": "openblocksdev/openblocks-ce",
+ "tags": ["latest", "heroku", "beta", "1.1.3", "1.1.2", "1.1.1", "1.1.0", "1.0.21"]
+ },
+ {
+ "name": "plausibleanalytics-arm",
+ "image": "plausible/analytics",
+ "tags": [
+ "v1.5.1",
+ "v1.5.0-rc.2",
+ "v1.5.0-rc.1",
+ "v1.5.0",
+ "v1.5",
+ "v1.4.4",
+ "v1.4.3",
+ "v1.4.2",
+ "v1.4.1",
+ "v1.4.0.rc.0",
+ "v1.4.0-rc.0",
+ "v1.4.0",
+ "v1.4",
+ "v1.3.0-rc.1",
+ "v1.3.0-rc.0",
+ "v1.3.0",
+ "v1.3",
+ "v1.2.1",
+ "v1.2.0",
+ "v1.2-rc.1",
+ "v1.2-rc.0",
+ "v1.2",
+ "v1.1.1",
+ "v1.1.0",
+ "v1.1",
+ "v1.0.0",
+ "v1.0",
+ "v1",
+ "stable",
+ "master"
+ ]
+ },
+ {
+ "name": "plausibleanalytics",
+ "image": "plausible/analytics",
+ "tags": [
+ "v1.5.1",
+ "v1.5.0-rc.2",
+ "v1.5.0-rc.1",
+ "v1.5.0",
+ "v1.5",
+ "v1.4.4",
+ "v1.4.3",
+ "v1.4.2",
+ "v1.4.1",
+ "v1.4.0.rc.0",
+ "v1.4.0-rc.0",
+ "v1.4.0",
+ "v1.4",
+ "v1.3.0-rc.1",
+ "v1.3.0-rc.0",
+ "v1.3.0",
+ "v1.3",
+ "v1.2.1",
+ "v1.2.0",
+ "v1.2-rc.1",
+ "v1.2-rc.0",
+ "v1.2",
+ "v1.1.1",
+ "v1.1.0",
+ "v1.1",
+ "v1.0.0",
+ "v1.0",
+ "v1",
+ "stable",
+ "master"
+ ]
+ },
+ {
+ "name": "pocketbase",
+ "image": "coollabsio/pocketbase",
+ "tags": [
+ "0.8.0-arm64",
+ "0.8.0-amd64",
+ "0.8.0-aarch64",
+ "0.8.0",
+ "0.10.2-arm64",
+ "0.10.2-amd64",
+ "0.10.2-aarch64",
+ "0.10.2"
+ ]
+ },
+ {
+ "name": "searxng",
+ "image": "searxng/searxng",
+ "tags": [
+ "2023.01.09-afd71a6c",
+ "2023.01.09-a90ed481",
+ "2023.01.08-54e63839",
+ "2023.01.08-4e735b28",
+ "2023.01.08-217395b8",
+ "2023.01.08-0c429d70",
+ "2023.01.07-cb7b0916",
+ "2023.01.07-a98c5156",
+ "2023.01.07-633ba8b1",
+ "2023.01.07-4e355564",
+ "2023.01.06-b241015e",
+ "2023.01.06-269a72ee",
+ "2023.01.05-aba969cc",
+ "2022.12.30-b6d98be7",
+ "2022.12.30-647a0aa9",
+ "2022.12.30-17516290",
+ "2022.12.29-d531f893",
+ "2022.12.29-9b31976c",
+ "2022.12.29-76cd808a",
+ "2022.12.29-3ec58b06",
+ "2022.12.29-174e6851",
+ "2022.12.26-0d489617",
+ "2022.12.23-e8f72d70",
+ "2022.12.23-a2d506d4",
+ "2022.12.22-d75ae7c8",
+ "2022.12.16-f5bd73d9",
+ "2022.12.16-b9274821",
+ "2022.12.16-42ca37a6",
+ "2022.12.16-2a51c856",
+ "2022.12.16-0dac581c"
+ ]
+ },
+ {
+ "name": "trilium",
+ "image": "zadam/trilium",
+ "tags": [
+ "0.57.4",
+ "0.57.2",
+ "0.56.1",
+ "0.55.1",
+ "0.54.2",
+ "0.53.2",
+ "0.52.4",
+ "0.52.2",
+ "0.51.2",
+ "0.50.3",
+ "0.50.1",
+ "0.49.5",
+ "0.49.3",
+ "0.48.9",
+ "0.48.7",
+ "0.48.4",
+ "0.48.2",
+ "0.47.8",
+ "0.47.6",
+ "0.47.4",
+ "0.47.2",
+ "0.46.7",
+ "0.46.5",
+ "0.45.10",
+ "0.45.9",
+ "0.45.7",
+ "0.45.5",
+ "0.45.3",
+ "0.44.8",
+ "0.44.6"
+ ]
+ },
+ {
+ "name": "umami-postgresql",
+ "image": "ghcr.io/umami-software/umami",
+ "tags": [
+ "postgresql-v1.39.5",
+ "postgresql-v1.39.4",
+ "postgresql-v1.39.3",
+ "postgresql-v1.39.2",
+ "postgresql-v1.39.1",
+ "postgresql-v1.39.0",
+ "postgresql-v1.38.0",
+ "postgresql-v1.37.0",
+ "postgresql-v1.36.1",
+ "postgresql-v1.36.0",
+ "postgresql-v1.35.0",
+ "postgresql-v1.34.0",
+ "postgresql-v1.33.3",
+ "postgresql-latest",
+ "mysql-v1.39.5",
+ "mysql-v1.39.4",
+ "mysql-v1.39.3",
+ "mysql-v1.39.2",
+ "mysql-v1.39.1",
+ "mysql-v1.39.0",
+ "mysql-v1.38.0",
+ "mysql-v1.37.0",
+ "mysql-v1.36.1",
+ "mysql-v1.36.0",
+ "mysql-v1.35.0",
+ "mysql-v1.34.0",
+ "mysql-v1.33.3",
+ "mysql-latest"
+ ]
+ },
+ {
+ "name": "umami",
+ "image": "ghcr.io/umami-software/umami",
+ "tags": [
+ "postgresql-v1.39.5",
+ "postgresql-v1.39.4",
+ "postgresql-v1.39.3",
+ "postgresql-v1.39.2",
+ "postgresql-v1.39.1",
+ "postgresql-v1.39.0",
+ "postgresql-v1.38.0",
+ "postgresql-v1.37.0",
+ "postgresql-v1.36.1",
+ "postgresql-v1.36.0",
+ "postgresql-v1.35.0",
+ "postgresql-v1.34.0",
+ "postgresql-v1.33.3",
+ "postgresql-latest",
+ "mysql-v1.39.5",
+ "mysql-v1.39.4",
+ "mysql-v1.39.3",
+ "mysql-v1.39.2",
+ "mysql-v1.39.1",
+ "mysql-v1.39.0",
+ "mysql-v1.38.0",
+ "mysql-v1.37.0",
+ "mysql-v1.36.1",
+ "mysql-v1.36.0",
+ "mysql-v1.35.0",
+ "mysql-v1.34.0",
+ "mysql-v1.33.3",
+ "mysql-latest"
+ ]
+ },
+ {
+ "name": "uptimekuma",
+ "image": "louislam/uptime-kuma",
+ "tags": [
+ "1.19.4",
+ "1.19.3",
+ "1.19.2",
+ "1.19.1",
+ "1.19.0",
+ "1.18.5",
+ "1.18.4",
+ "1.18.3",
+ "1.18.2",
+ "1.18.1",
+ "1.18.0",
+ "1.17.1",
+ "1.17.0",
+ "1.16.1",
+ "1.16.0",
+ "1.15.1",
+ "1.15.0",
+ "1.14.1",
+ "1.14.0",
+ "1.13.2",
+ "1.13.1",
+ "1.13.0",
+ "1.12.1",
+ "1.11.4",
+ "1.11.3",
+ "1.11.2",
+ "1.11.1",
+ "1.11.0",
+ "1.10.2",
+ "1.10.1"
+ ]
+ },
+ {
+ "name": "vaultwarden",
+ "image": "vaultwarden/server",
+ "tags": [
+ "1.27.0",
+ "1.26.0",
+ "1.25.2",
+ "1.25.1",
+ "1.25.0",
+ "1.24.0",
+ "1.23.1",
+ "1.23.0",
+ "1.22.2",
+ "1.22.1",
+ "1.22.0",
+ "1.21.0"
+ ]
+ },
+ {
+ "name": "vscodeserver",
+ "image": "codercom/code-server",
+ "tags": [
+ "4.9.1",
+ "4.9.0",
+ "4.8.3",
+ "4.8.2",
+ "4.8.1",
+ "4.8.0",
+ "4.7.0",
+ "4.6.0",
+ "4.5.1",
+ "4.4.0",
+ "4.2.0",
+ "4.0.2",
+ "3.11.1",
+ "3.10.2",
+ "3.10.0",
+ "3.9.3",
+ "3.9.1",
+ "3.8.1",
+ "3.7.4",
+ "3.7.2",
+ "3.7.0",
+ "3.6.1",
+ "3.5.0",
+ "3.4.0",
+ "3.3.0",
+ "3.2.0",
+ "3.1.1",
+ "3.1.0",
+ "3.0.2",
+ "3.0.0"
+ ]
+ },
+ {
+ "name": "weblate",
+ "image": "weblate/weblate",
+ "tags": [
+ "latest",
+ "edge-2023-01-10-1df5c9dd96a6d8650f6881942fecbe33e1884295",
+ "edge-2023-01-09-7029b7b6c630be7cdac07d1629573dd2b81bc05f",
+ "edge-2023-01-09-4b05a878aa25b2c544a4e77027769b5934ec561f",
+ "edge-2023-01-07-df50259ff209720b0fd3c983bd7a5d01b564149c",
+ "edge-2023-01-07-719b3034de0ed369cd63554ea652f11142b9a540",
+ "edge-2023-01-07-14d4aec6cd8e1e6e0b7c1dc3a9cf4a74ccfc5e37",
+ "edge-2023-01-07-00f2d980c4388d799ba0df3a27c10bf941b7edd3",
+ "edge-2023-01-04-e92fe933b22e36e92f6de57a0ecb16752852d815",
+ "edge-2023-01-04-4c413c6ba33c39a6b7f3238f255bc09c69e96345",
+ "edge-2023-01-02-fd57652cce9dd2a12c7ff1dc644f5a969e57ea76",
+ "edge-2023-01-02-738d270784bca0cfaaef59e6cfb8c307f68a9939",
+ "edge-2023-01-02-3f6a7a183bbda4dc2e8d7e468370adc6f9e50527",
+ "edge-2023-01-01-5580a7a4755bf71403c85999fb4dff2078293403",
+ "edge-2022-12-29-8f422f23930880809a26d1207f9e43315ef54ad2",
+ "edge-2022-12-28-375fd99195711641246ccd09e3ce394d6928eaef",
+ "edge-2022-12-25-358c8ce6071f2781ae027bbc3a46d906ce08d9e7",
+ "edge-2022-12-24-3e1503494ce06ad6ff32f02db1a7d59224e5c860",
+ "edge-2022-12-21-cac4b09f943fe97700e3a33b7caf23277d2fcc11",
+ "edge-2022-12-21-3a8dd1bf66a7295f3512346bc1c97d55c5649dcf",
+ "edge-2022-12-16-e93caa3b014543b716b946f2c7fbf4a8f9be6099",
+ "edge-2022-12-16-318a467d2e529a081e9ea9dbad993c1736ff1a00",
+ "edge-2022-12-16-1af41ec4bd3838f967d88b68dec8195419e01e6f",
+ "edge-2022-12-16-02e9d020b01d004655c3af20c68a30f6c4645c1a",
+ "edge-2022-12-15-a6af1384a0831b17c43da7262f80d0cfbc766835",
+ "edge-2022-12-15-a1c9f77b301a9e23fc05ef2adc4694cceb632c25",
+ "edge-2022-12-15-1305f7115ef79b75e638b097772680d9cadbd4d0",
+ "edge-2022-12-14-b400145f05687e647bd4c8192be99f7f04373fb5",
+ "edge-2022-12-12-c0db193a3baacd107c5f2c28c6e0af89c3d5afa3",
+ "edge-2022-12-09-647d40c67cf405870ba71a01584a42cfaec5915f"
+ ]
+ },
+ {
+ "name": "wordpress-only",
+ "image": "library/wordpress",
+ "tags": [
+ "php8.2-fpm-alpine",
+ "php8.2-fpm",
+ "php8.2-apache",
+ "php8.2",
+ "php8.1-fpm-alpine",
+ "php8.1-fpm",
+ "php8.1-apache",
+ "php8.1",
+ "php8.0-fpm-alpine",
+ "php8.0-fpm",
+ "php8.0-apache",
+ "php8.0",
+ "php7.4-fpm-alpine",
+ "php7.4-fpm",
+ "php7.4-apache",
+ "php7.4",
+ "php7.3-fpm-alpine",
+ "php7.3-fpm",
+ "php7.3-apache",
+ "php7.3",
+ "php7.2-fpm-alpine",
+ "php7.2-fpm",
+ "php7.2-apache",
+ "php7.2",
+ "php7.1-fpm-alpine",
+ "php7.1-fpm",
+ "php7.1-apache",
+ "php7.1",
+ "php7.0-fpm-alpine",
+ "php7.0-fpm"
+ ]
+ },
+ {
+ "name": "wordpress",
+ "image": "library/wordpress",
+ "tags": [
+ "php8.2-fpm-alpine",
+ "php8.2-fpm",
+ "php8.2-apache",
+ "php8.2",
+ "php8.1-fpm-alpine",
+ "php8.1-fpm",
+ "php8.1-apache",
+ "php8.1",
+ "php8.0-fpm-alpine",
+ "php8.0-fpm",
+ "php8.0-apache",
+ "php8.0",
+ "php7.4-fpm-alpine",
+ "php7.4-fpm",
+ "php7.4-apache",
+ "php7.4",
+ "php7.3-fpm-alpine",
+ "php7.3-fpm",
+ "php7.3-apache",
+ "php7.3",
+ "php7.2-fpm-alpine",
+ "php7.2-fpm",
+ "php7.2-apache",
+ "php7.2",
+ "php7.1-fpm-alpine",
+ "php7.1-fpm",
+ "php7.1-apache",
+ "php7.1",
+ "php7.0-fpm-alpine",
+ "php7.0-fpm"
+ ]
+ }
+]
diff --git a/apps/server/devTemplates.yaml b/apps/server/devTemplates.yaml
new file mode 100644
index 000000000..4cff705db
--- /dev/null
+++ b/apps/server/devTemplates.yaml
@@ -0,0 +1,3582 @@
+- templateVersion: 1.0.0
+ defaultVersion: "9.22"
+ documentation: https://docs.directus.io/getting-started/introduction.html
+ type: directus-postgresql
+ name: Directus
+ subname: (PostgreSQL)
+ description: >-
+ Directus is a free and open-source headless CMS framework for managing custom SQL-based databases.
+ labels:
+ - CMS
+ - headless
+ services:
+ $$id:
+ name: Directus
+ depends_on:
+ - $$id-postgresql
+ - $$id-redis
+ image: directus/directus:$$core_version
+ volumes:
+ - $$id-uploads:/directus/uploads
+ - $$id-database:/directus/database
+ - $$id-extensions:/directus/extensions
+ environment:
+ - KEY=$$secret_key
+ - SECRET=$$secret_secret
+ - DB_CLIENT=pg
+ - DB_CONNECTION_STRING=$$secret_db_connection_string
+ - CACHE_ENABLED=true
+ - CACHE_STORE=redis
+ - CACHE_REDIS=$$secret_cache_redis
+ - ADMIN_EMAIL=$$config_admin_email
+ - ADMIN_PASSWORD=$$secret_admin_password
+ - CACHE_AUTO_PURGE=true
+ - PUBLIC_URL=$$config_public_url
+ ports:
+ - "8055"
+ $$id-postgresql:
+ name: Directus PostgreSQL
+ depends_on: []
+ image: postgres:14-alpine
+ volumes:
+ - $$id-postgresql-data:/var/lib/postgresql/data
+ environment:
+ - POSTGRES_USER=$$config_postgres_user
+ - POSTGRES_PASSWORD=$$secret_postgres_password
+ - POSTGRES_DB=$$config_postgres_db
+ ports: []
+ $$id-redis:
+ name: Directus Redis
+ depends_on: []
+ image: redis:7.0.4-alpine
+ command: "--maxmemory 512mb --maxmemory-policy allkeys-lru --maxmemory-samples 5"
+ volumes:
+ - "$$id-redis:/data"
+ environment: []
+ variables:
+ - id: $$config_public_url
+ name: PUBLIC_URL
+ label: Public URL
+ defaultValue: $$generate_fqdn
+ description: ""
+ - id: $$secret_db_connection_string
+ name: DB_CONNECTION_STRING
+ label: Directus Database Url
+ defaultValue: postgresql://$$config_postgres_user:$$secret_postgres_password@$$id-postgresql:5432/$$config_postgres_db
+ description: ""
+ - id: $$config_postgres_db
+ main: $$id-postgresql
+ name: POSTGRES_DB
+ label: Database
+ defaultValue: directus
+ description: ""
+ - id: $$config_postgres_user
+ main: $$id-postgresql
+ name: POSTGRES_USER
+ label: User
+ defaultValue: $$generate_username
+ description: ""
+ - id: $$secret_postgres_password
+ main: $$id-postgresql
+ name: POSTGRES_PASSWORD
+ label: Password
+ defaultValue: $$generate_password
+ description: ""
+ showOnConfiguration: true
+ - id: $$secret_cache_redis
+ name: CACHE_REDIS
+ label: Redis Url
+ defaultValue: redis://$$id-redis:6379
+ description: ""
+ - id: $$config_admin_email
+ name: ADMIN_EMAIL
+ label: Initial Admin Email
+ defaultValue: "admin@example.com"
+ description: "The email address of the first user that is automatically created. You can change it later in Directus."
+ - id: $$secret_admin_password
+ name: ADMIN_PASSWORD
+ label: Initial Admin Password
+ defaultValue: $$generate_password
+ description: "The password of the first user that is automatically created."
+ showOnConfiguration: true
+ - id: $$secret_key
+ name: KEY
+ label: Key
+ defaultValue: $$generate_password
+ description: "Unique identifier for the project."
+ showOnConfiguration: true
+ - id: $$secret_secret
+ name: SECRET
+ label: Secret
+ defaultValue: $$generate_password
+ description: "Secret string for the project."
+ showOnConfiguration: true
+
+- templateVersion: 1.0.0
+ defaultVersion: v1.3.8
+ documentation: https://github.com/LibreTranslate/LibreTranslate
+ description: Free and Open Source Machine Translation API. 100% self-hosted, offline capable and easy to setup.
+ type: libretranslate
+ name: Libretranslate
+ labels:
+ - translator
+ - argos
+ - python
+ - libretranslate
+ services:
+ $$id:
+ name: Libretranslate
+ image: libretranslate/libretranslate:$$core_version
+ environment:
+ - LT_HOST=0.0.0.0
+ - LT_SUGGESTIONS=true
+ - LT_CHAR_LIMIT=$$config_lt_char_limit
+ - LT_REQ_LIMIT=$$config_lt_req_limit
+ - LT_BATCH_LIMIT=$$config_lt_batch_limit
+ - LT_GA_ID=$$config_lt_ga_id
+ - LT_DISABLE_WEB_UI=$$config_lt_web_ui
+ volumes:
+ - $$id-libretranslate:/libretranslate
+ ports:
+ - "5000"
+ variables:
+ - id: $$config_lt_char_limit
+ name: LT_CHAR_LIMIT
+ label: Char limit
+ defaultValue: "5000"
+ description: "Set character limit."
+ - id: $$config_lt_req_limit
+ name: LT_REQ_LIMIT
+ label: Request limit
+ defaultValue: "5000"
+ description: "Set maximum number of requests per minute per client."
+ - id: $$config_lt_batch_limit
+ name: LT_BATCH_LIMIT
+ label: Batch Limit
+ defaultValue: "5000"
+ description: "Set maximum number of texts to translate in a batch request."
+ - id: $$config_lt_ga_id
+ name: LT_GA_ID
+ label: Google Analytics ID
+ defaultValue: ""
+ description: "Enable Google Analytics on the API client page by providing an ID"
+ - id: $$config_lt_web_ui
+ name: LT_DISABLE_WEB_UI
+ label: Web UI
+ defaultValue: "false"
+ description: "Disable or enable web ui. True or false."
+- templateVersion: 1.0.0
+ defaultVersion: 0.8.1
+ documentation: https://github.com/benbusby/whoogle-search
+ type: whoogle
+ name: Whoogle Search
+ description: A self-hosted, ad-free, privacy-respecting metasearch engine
+ labels:
+ - search
+ - google
+ services:
+ $$id:
+ name: Whoogle Search
+ documentation: https://github.com/benbusby/whoogle-search
+ depends_on: []
+ image: benbusby/whoogle-search:$$core_version
+ cap_drop:
+ - ALL
+ environment:
+ - WHOOGLE_USER=$$config_whoogle_username
+ - WHOOGLE_PASS=$$secret_whoogle_password
+ - WHOOGLE_CONFIG_PREFERENCES_KEY=$$secret_whoogle_preferences_key
+ ulimits:
+ nofile:
+ soft: 262144
+ hard: 262144
+ ports:
+ - "5000"
+ variables:
+ - id: $$config_whoogle_username
+ name: WHOOGLE_USER
+ label: Whoogle User
+ defaultValue: $$generate_username
+ description: "Username to log into Whoogle"
+ - id: $$secret_whoogle_password
+ name: WHOOGLE_PASSWORD
+ label: Whoogle Password
+ defaultValue: $$generate_password
+ description: "Password to log into Whoogle"
+ showOnConfiguration: true
+ - id: $$secret_whoogle_preferences_key
+ name: WHOOGLE_CONFIG_PREFERENCES_KEY
+ label: Whoogle preferences key
+ defaultValue: $$generate_password
+ description: "password to encrypt preferences"
+- templateVersion: 1.0.0
+ defaultVersion: 1.1.3
+ documentation: https://docs.openblocks.dev/
+ type: openblocks
+ name: Openblocks
+ description: The Open Source Retool Alternative
+ services:
+ $$id:
+ image: openblocksdev/openblocks-ce:$$core_version
+ volumes:
+ - $$id-stacks-data:/openblocks-stacks
+ ports:
+ - "3000"
+- templateVersion: 1.0.0
+ defaultVersion: "0.10.2"
+ documentation: https://pocketbase.io/docs/
+ type: pocketbase
+ name: Pocketbase
+ description: "Open Source realtime backend in 1 file"
+ services:
+ $$id:
+ image: coollabsio/pocketbase:$$core_version
+ volumes:
+ - $$id-data:/app/pb_data
+ ports:
+ - "8080"
+- templateVersion: 1.0.0
+ defaultVersion: v1.5.1
+ documentation: https://plausible.io/doc/
+ type: plausibleanalytics-arm
+ name: Plausible Analytics (ARM)
+ description: A lightweight and open-source website analytics tool.
+ labels:
+ - analytics
+ - statistics
+ - plausible
+ - gdpr
+ - no-cookie
+ - google analytics
+ services:
+ $$id:
+ name: Plausible Analytics
+ command: >-
+ sh -c "sleep 10 && /entrypoint.sh db createdb && /entrypoint.sh db migrate
+ && /entrypoint.sh db init-admin && /entrypoint.sh run"
+ depends_on:
+ - $$id-postgresql
+ - $$id-clickhouse
+ image: plausible/analytics:$$core_version
+ environment:
+ - ADMIN_USER_EMAIL=$$config_admin_user_email
+ - ADMIN_USER_NAME=$$config_admin_user_name
+ - ADMIN_USER_PWD=$$secret_admin_user_pwd
+ - BASE_URL=$$config_base_url
+ - SECRET_KEY_BASE=$$secret_secret_key_base
+ - DISABLE_AUTH=$$config_disable_auth
+ - DISABLE_REGISTRATION=$$config_disable_registration
+ - DATABASE_URL=$$secret_database_url
+ - CLICKHOUSE_DATABASE_URL=$$secret_clickhouse_database_url
+ ports:
+ - "8000"
+ $$id-postgresql:
+ name: PostgreSQL
+ image: postgres:14-alpine
+ volumes:
+ - $$id-postgresql-data:/var/lib/postgresql/data
+ environment:
+ - POSTGRES_PASSWORD=$$secret_postgres_password
+ - POSTGRES_USER=$$config_postgres_user
+ - POSTGRES_DB=$$config_postgres_db
+ $$id-clickhouse:
+ name: Clickhouse
+ volumes:
+ - $$id-clickhouse-data:/var/lib/clickhouse
+ image: clickhouse/clickhouse-server:22.6-alpine
+ ulimits:
+ nofile:
+ soft: 262144
+ hard: 262144
+ files:
+ - location: /etc/clickhouse-server/users.d/logging.xml
+ content: >-
+ warning true
+ - location: /etc/clickhouse-server/config.d/logging.xml
+ content: >-
+ 0 0
+ - location: /docker-entrypoint-initdb.d/init.query
+ content: CREATE DATABASE IF NOT EXISTS plausible;
+ - location: /docker-entrypoint-initdb.d/init-db.sh
+ content: >-
+ clickhouse client --queries-file
+ /docker-entrypoint-initdb.d/init.query
+ variables:
+ - id: $$config_base_url
+ name: BASE_URL
+ label: Base URL
+ defaultValue: $$generate_fqdn
+ description: >-
+ You must set this to the FQDN of the Plausible Analytics instance. This is
+ used to generate the links to the Plausible Analytics instance.
+ - id: $$secret_database_url
+ name: DATABASE_URL
+ label: Database URL for PostgreSQL
+ defaultValue: >-
+ postgresql://$$config_postgres_user:$$secret_postgres_password@$$id-postgresql:5432/$$config_postgres_db
+ description: ""
+ - id: $$secret_clickhouse_database_url
+ name: CLICKHOUSE_DATABASE_URL
+ label: Database URL for Clickhouse
+ defaultValue: http://$$id-clickhouse:8123/plausible
+ description: ""
+ - id: $$config_admin_user_email
+ name: ADMIN_USER_EMAIL
+ label: Admin Email Address
+ defaultValue: admin@example.com
+ description: This is the admin email. Please change it.
+ - id: $$config_admin_user_name
+ name: ADMIN_USER_NAME
+ label: Admin User Name
+ defaultValue: $$generate_username
+ description: This is the admin username. Please change it.
+ - id: $$secret_admin_user_pwd
+ name: ADMIN_USER_PWD
+ label: Admin User Password
+ defaultValue: $$generate_password
+ description: This is the admin password. Please change it.
+ showOnConfiguration: true
+ - id: $$secret_secret_key_base
+ name: SECRET_KEY_BASE
+ label: Secret Key Base
+ defaultValue: $$generate_hex(64)
+ description: ""
+ - id: $$config_disable_auth
+ name: DISABLE_AUTH
+ label: Authentication
+ defaultValue: "false"
+ description: ""
+ - id: $$config_disable_registration
+ name: DISABLE_REGISTRATION
+ label: Registration
+ defaultValue: "true"
+ description: ""
+ - id: $$config_postgres_user
+ main: $$id-postgresql
+ name: POSTGRES_USER
+ label: PostgreSQL Username
+ defaultValue: postgresql
+ description: ""
+ - id: $$secret_postgres_password
+ main: $$id-postgresql
+ name: POSTGRES_PASSWORD
+ label: PostgreSQL Password
+ defaultValue: $$generate_password
+ description: ""
+ showOnConfiguration: true
+ - id: $$config_postgres_db
+ main: $$id-postgresql
+ name: POSTGRES_DB
+ label: PostgreSQL Database
+ defaultValue: plausible
+ description: ""
+ - id: $$config_scriptName
+ name: SCRIPT_NAME
+ label: Custom Script Name
+ defaultValue: plausible.js
+ description: This is the default script name.
+- templateVersion: 1.0.0
+ defaultVersion: "1.17"
+ documentation: https://docs.gitea.io
+ type: gitea
+ name: Gitea
+ description: Gitea is a community managed lightweight code hosting solution written in Go.
+ labels:
+ - storage
+ - git
+ services:
+ $$id:
+ name: Gitea
+ documentation: https://docs.gitea.io
+ image: gitea/gitea:$$core_version
+ volumes:
+ - $$id-data:/data
+ - /etc/timezone:/etc/timezone:ro
+ - /etc/localtime:/etc/localtime:ro
+ environment:
+ - USER_UID=1000
+ - USER_GID=1000
+ - DOMAIN=$$config_domain
+ - SSH_DOMAIN=$$config_ssh_domain
+ - ROOT_URL=$$config_root_url
+ - SECRET_KEY=$$secret_secret_key
+ - INTERNAL_TOKEN=$$secret_internal_token
+ - SSH_PORT=22
+ - START_SSH_SERVER=$$config_start_ssh_server
+ ports:
+ - "3000"
+ - "22"
+ proxy:
+ - port: "22"
+ hostPort: $$config_hostport_ssh
+ variables:
+ - id: $$config_hostport_ssh
+ name: SSH_PORT
+ label: SSH Port
+ defaultValue: "8022"
+ description: ""
+ required: true
+ - id: $$config_domain
+ name: DOMAIN
+ label: Domain
+ defaultValue: $$generate_domain
+ description: ""
+ - id: $$config_ssh_domain
+ name: SSH_DOMAIN
+ label: SSH Domain
+ defaultValue: $$generate_domain
+ description: ""
+ - id: $$config_start_ssh_server
+ name: START_SSH_SERVER
+ label: Start SSH Server
+ defaultValue: "true"
+ description: ""
+ - id: $$config_root_url
+ name: ROOT_URL
+ label: Root URL of Gitea
+ defaultValue: $$generate_fqdn_slash
+ description: ""
+ - id: $$secret_secret_key
+ name: SECRET_KEY
+ label: Secret Key
+ defaultValue: $$generate_hex(32)
+ description: ""
+ - id: $$secret_internal_token
+ name: INTERNAL_TOKEN
+ label: Internal JWT Token
+ defaultValue: $$generate_token
+ description: ""
+- templateVersion: 1.0.0
+ defaultVersion: "20.0"
+ documentation: https://www.keycloak.org/documentation
+ type: keycloak
+ name: Keycloak
+ description: "Keycloak provides user federation, strong authentication, user management, fine-grained authorization, and more."
+ labels:
+ - authentication
+ - authorization
+ - oidconnect
+ - saml2
+ services:
+ $$id:
+ name: Keycloak
+ command: start --db=postgres --features=token-exchange --import-realm
+ depends_on:
+ - $$id-postgresql
+ image: "quay.io/keycloak/keycloak:$$core_version"
+ volumes:
+ - $$id-import:/opt/keycloak/data/import
+ environment:
+ - KC_HEALTH_ENABLED=true
+ - KC_PROXY=edge
+ - KC_DB=postgres
+ - KC_HOSTNAME=$$config_keycloak_domain
+ - KEYCLOAK_ADMIN=$$config_admin_user
+ - KEYCLOAK_ADMIN_PASSWORD=$$secret_keycloak_admin_password
+ - KC_DB_PASSWORD=$$secret_postgres_password
+ - KC_DB_USERNAME=$$config_postgres_user
+ - KC_DB_URL=$$secret_keycloak_database_url
+ ports:
+ - "8080"
+ $$id-postgresql:
+ name: PostgreSQL
+ depends_on: []
+ image: "postgres:14-alpine"
+ volumes:
+ - "$$id-postgresql-data:/var/lib/postgresql/data"
+ environment:
+ - POSTGRES_USER=$$config_postgres_user
+ - POSTGRES_PASSWORD=$$secret_postgres_password
+ - POSTGRES_DB=$$config_postgres_db
+ ports: []
+ variables:
+ - id: $$config_keycloak_domain
+ name: KEYCLOAK_DOMAIN
+ label: Keycloak Domain
+ defaultValue: $$generate_domain
+ description: ""
+ - id: $$secret_keycloak_database_url
+ name: KEYCLOAK_DATABASE_URL
+ label: Keycloak Database Url
+ defaultValue: >-
+ jdbc:postgresql://$$id-postgresql:5432/$$config_postgres_db
+ description: ""
+ - id: $$config_admin_user
+ name: KEYCLOAK_ADMIN
+ label: Keycloak Admin User
+ defaultValue: $$generate_username
+ description: ""
+ - id: $$secret_keycloak_admin_password
+ name: KEYCLOAK_ADMIN_PASSWORD
+ label: Keycloak Admin Password
+ defaultValue: $$generate_password
+ description: ""
+ showOnConfiguration: true
+ - id: $$config_postgres_user
+ main: $$id-postgresql
+ name: POSTGRES_USER
+ label: PostgreSQL User
+ defaultValue: $$generate_username
+ description: ""
+ - id: $$secret_postgres_password
+ main: $$id-postgresql
+ name: POSTGRES_PASSWORD
+ label: PostgreSQL Password
+ defaultValue: $$generate_password
+ description: ""
+ showOnConfiguration: true
+ - id: $$config_postgres_db
+ main: $$id-postgresql
+ name: POSTGRES_DB
+ label: PostgreSQL Database
+ defaultValue: keycloak
+ description: ""
+- templateVersion: 1.0.0
+ defaultVersion: v3.7
+ documentation: https://github.com/freyacodes/Lavalink
+ description: Standalone audio sending node based on Lavaplayer.
+ type: lavalink
+ name: Lavalink
+ labels:
+ - discord
+ - discord bot
+ - audio
+ - lavalink
+ - jda
+ services:
+ $$id:
+ name: Lavalink
+ image: fredboat/lavalink:$$core_version
+ environment: []
+ volumes:
+ - $$id-lavalink:/lavalink
+ ports:
+ - $$config_port
+ files:
+ - location: /opt/Lavalink/application.yml
+ content: >-
+ server:
+ port: 2333
+ address: 0.0.0.0
+ lavalink:
+ server:
+ password: "$$secret_password"
+ sources:
+ youtube: true
+ bandcamp: true
+ soundcloud: true
+ twitch: true
+ vimeo: true
+ http: true
+ local: false
+
+ logging:
+ file:
+ path: ./logs/
+
+ level:
+ root: INFO
+ lavalink: INFO
+
+ logback:
+ rollingpolicy:
+ max-file-size: 1GB
+ max-history: 30
+ variables:
+ - id: $$secret_password
+ name: PASSWORD
+ label: Password
+ defaultValue: $$generate_password
+ required: true
+- templateVersion: 1.0.0
+ defaultVersion: v1.8.9
+ documentation: https://docs.appsmith.com/getting-started/setup/instance-configuration/
+ type: appsmith
+ name: Appsmith
+ description: "Fastest way to build internal apps over any database or API."
+ services:
+ $$id:
+ image: appsmith/appsmith-ce:$$core_version
+ environment:
+ - APPSMITH_MAIL_ENABLED=$$config_appsmith_mail_enabled
+ - APPSMITH_DISABLE_TELEMETRY=$$config_appsmith_disable_telemetry
+ - APPSMITH_DISABLE_INTERCOM=$$config_appsmith_disable_intercom
+ volumes:
+ - $$id-stacks-data:/appsmith-stacks
+ ports:
+ - "80"
+ variables:
+ - id: $$config_appsmith_mail_enabled
+ name: APPSMITH_MAIL_ENABLED
+ label: Enable Mail
+ defaultValue: "false"
+ description: ""
+ - id: $$config_appsmith_disable_telemetry
+ name: APPSMITH_DISABLE_TELEMETRY
+ label: Disable Telemetry
+ defaultValue: "true"
+ description: ""
+ - id: $$config_appsmith_disable_intercom
+ name: APPSMITH_DISABLE_INTERCOM
+ label: Disable Intercom
+ defaultValue: "true"
+ description: ""
+- templateVersion: 1.0.0
+ defaultVersion: 0.57.4
+ documentation: https://hub.docker.com/r/zadam/trilium
+ description: "A hierarchical note taking application with focus on building large personal knowledge bases."
+ labels:
+ - personal
+ - knowledge
+ - notes
+ - wiki
+ type: trilium
+ name: Trilium Notes
+ services:
+ $$id:
+ image: zadam/trilium:$$core_version
+ environment: []
+ volumes:
+ - $$id-trilium:/home/node/trilium-data
+ ports:
+ - "8080"
+ variables: []
+- templateVersion: 1.0.0
+ defaultVersion: 1.18.5
+ documentation: https://hub.docker.com/r/louislam/uptime-kuma
+ description: A free & fancy self-hosted monitoring tool.
+ labels:
+ - uptime
+ type: uptimekuma
+ name: UptimeKuma
+ services:
+ $$id:
+ image: louislam/uptime-kuma:$$core_version
+ environment: []
+ volumes:
+ - $$id-uptimekuma:/app/data
+ ports:
+ - "3001"
+ variables: []
+- templateVersion: 1.0.0
+ defaultVersion: "5.8"
+ documentation: https://hub.docker.com/r/silviof/docker-languagetool
+ description: "A multilingual grammar, style and spell checker."
+ type: languagetool
+ name: LanguageTool
+ services:
+ $$id:
+ image: silviof/docker-languagetool:$$core_version
+ environment: []
+ volumes:
+ - $$id-ngrams:/ngrams
+ ports:
+ - "8010"
+ variables: []
+- templateVersion: 1.0.0
+ defaultVersion: 1.26.0
+ documentation: https://hub.docker.com/r/vaultwarden/server
+ description: "Bitwarden compatible server written in Rust."
+ type: vaultwarden
+ name: VaultWarden
+ labels:
+ - bitwarden
+ - password manager
+ services:
+ $$id:
+ image: vaultwarden/server:$$core_version
+ environment: []
+ volumes:
+ - $$id-data:/data
+ ports:
+ - "80"
+ variables: []
+- templateVersion: 1.0.0
+ defaultVersion: 9.3.1
+ documentation: https://hub.docker.com/r/grafana/grafana
+ type: grafana
+ name: Grafana
+ description: >-
+ Grafana allows you to query, visualize, alert on and understand your metrics.
+ labels:
+ - monitoring
+ - metrics
+ - dashboard
+ services:
+ $$id:
+ image: grafana/grafana:$$core_version
+ environment: []
+ volumes:
+ - $$id-config:/etc/grafana
+ - $$id-grafana:/var/lib/grafana
+ ports:
+ - "3000"
+ variables: []
+- templateVersion: 1.0.0
+ defaultVersion: 1.1.2
+ documentation: https://appwrite.io/docs
+ type: appwrite
+ name: Appwrite
+ description: Secure Backend Server for Web, Mobile & Flutter Developers.
+ labels:
+ - serverless
+ - backend
+ - storage
+ - api
+ services:
+ "$$id":
+ image: appwrite/appwrite:$$core_version
+ environment:
+ - _APP_ENV=$$config__app_env
+ - _APP_WORKER_PER_CORE=$$config__app_worker_per_core
+ - _APP_LOCALE=$$config__app_locale
+ - _APP_CONSOLE_WHITELIST_ROOT=$$config__app_console_whitelist_root
+ - _APP_CONSOLE_WHITELIST_EMAILS=$$config__app_console_whitelist_emails
+ - _APP_CONSOLE_WHITELIST_IPS=$$config__app_console_whitelist_ips
+ - _APP_SYSTEM_EMAIL_NAME=$$config__app_system_email_name
+ - _APP_SYSTEM_EMAIL_ADDRESS=$$config__app_system_email_address
+ - _APP_SYSTEM_SECURITY_EMAIL_ADDRESS=$$config__app_system_security_email_address
+ - _APP_SYSTEM_RESPONSE_FORMAT=$$config__app_system_response_format
+ - _APP_OPTIONS_ABUSE=$$config__app_options_abuse
+ - _APP_OPTIONS_FORCE_HTTPS=$$config__app_options_force_https
+ - _APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1
+ - _APP_DOMAIN=$$config__app_domain
+ - _APP_DOMAIN_TARGET=$$config__app_domain_target
+ - _APP_REDIS_HOST=$$config__app_redis_host
+ - _APP_REDIS_PORT=$$config__app_redis_port
+ - _APP_REDIS_USER=$$config__app_redis_user
+ - _APP_REDIS_PASS=$$secret__app_redis_pass
+ - _APP_DB_HOST=$$config__app_db_host
+ - _APP_DB_PORT=$$config__app_db_port
+ - _APP_DB_SCHEMA=$$config__app_db_schema
+ - _APP_DB_USER=$$config__app_db_user
+ - _APP_DB_PASS=$$secret__app_db_pass
+ - _APP_SMTP_HOST=$$config__app_smtp_host
+ - _APP_SMTP_PORT=$$config__app_smtp_port
+ - _APP_SMTP_SECURE=$$config__app_smtp_secure
+ - _APP_SMTP_USERNAME=$$config__app_smtp_username
+ - _APP_SMTP_PASSWORD=$$secret__app_smtp_password
+ - _APP_USAGE_STATS=$$config__app_usage_stats
+ - _APP_INFLUXDB_HOST=$$config__app_influxdb_host
+ - _APP_INFLUXDB_PORT=$$config__app_influxdb_port
+ - _APP_STORAGE_LIMIT=$$config__app_storage_limit
+ - _APP_STORAGE_PREVIEW_LIMIT=$$config__app_storage_preview_limit
+ - _APP_STORAGE_ANTIVIRUS=$$config__app_storage_antivirus_enabled
+ - _APP_STORAGE_ANTIVIRUS_HOST=$$config__app_storage_antivirus_host
+ - _APP_STORAGE_ANTIVIRUS_PORT=$$config__app_storage_antivirus_port
+ - _APP_STORAGE_DEVICE=$$config__app_storage_device
+ - _APP_STORAGE_S3_ACCESS_KEY=$$secret__app_storage_s3_access_key
+ - _APP_STORAGE_S3_SECRET=$$secret__app_storage_s3_secret
+ - _APP_STORAGE_S3_REGION=$$config__app_storage_s3_region
+ - _APP_STORAGE_S3_BUCKET=$$config__app_storage_s3_bucket
+ - _APP_STORAGE_DO_SPACES_ACCESS_KEY=$$secret__app_storage_do_spaces_access_key
+ - _APP_STORAGE_DO_SPACES_SECRET=$$secret__app_storage_do_spaces_secret
+ - _APP_STORAGE_DO_SPACES_REGION=$$config__app_storage_do_spaces_region
+ - _APP_STORAGE_DO_SPACES_BUCKET=$$config__app_storage_do_spaces_bucket
+ - _APP_STORAGE_BACKBLAZE_ACCESS_KEY=$$secret__app_storage_backblaze_access_key
+ - _APP_STORAGE_BACKBLAZE_SECRET=$$secret__app_storage_backblaze_secret
+ - _APP_STORAGE_BACKBLAZE_REGION=$$config__app_storage_backblaze_region
+ - _APP_STORAGE_BACKBLAZE_BUCKET=$$config__app_storage_backblaze_bucket
+ - _APP_STORAGE_LINODE_ACCESS_KEY=$$secret__app_storage_linode_access_key
+ - _APP_STORAGE_LINODE_SECRET=$$secret__app_storage_linode_secret
+ - _APP_STORAGE_LINODE_REGION=$$config__app_storage_linode_region
+ - _APP_STORAGE_LINODE_BUCKET=$$config__app_storage_linode_bucket
+ - _APP_STORAGE_WASABI_ACCESS_KEY=$$secret__app_storage_wasabi_access_key
+ - _APP_STORAGE_WASABI_SECRET=$$secret__app_storage_wasabi_secret
+ - _APP_STORAGE_WASABI_REGION=$$config__app_storage_wasabi_region
+ - _APP_STORAGE_WASABI_BUCKET=$$config__app_storage_wasabi_bucket
+ - _APP_FUNCTIONS_SIZE_LIMIT=$$config__app_functions_size_limit
+ - _APP_FUNCTIONS_TIMEOUT=$$config__app_functions_timeout
+ - _APP_FUNCTIONS_BUILD_TIMEOUT=$$config__app_functions_build_timeout
+ - _APP_FUNCTIONS_CONTAINERS=$$config__app_functions_containers
+ - _APP_FUNCTIONS_CPUS=$$config__app_functions_cpus
+ - _APP_FUNCTIONS_MEMORY=$$config__app_functions_memory_allocated
+ - _APP_FUNCTIONS_MEMORY_SWAP=$$config__app_functions_memory_swap
+ - _APP_FUNCTIONS_RUNTIMES=$$config__app_functions_runtimes
+ - _APP_EXECUTOR_SECRET=$$secret__app_executor_secret
+ - _APP_EXECUTOR_HOST=$$config__app_executor_host
+ - _APP_LOGGING_PROVIDER=$$config__app_logging_provider
+ - _APP_LOGGING_CONFIG=$$config__app_logging_config
+ - _APP_STATSD_HOST=$$config__app_statsd_host
+ - _APP_STATSD_PORT=$$config__app_statsd_port
+ - _APP_MAINTENANCE_INTERVAL=$$config__app_maintenance_interval
+ - _APP_MAINTENANCE_RETENTION_EXECUTION=$$config__app_maintenance_retention_execution
+ - _APP_MAINTENANCE_RETENTION_CACHE=$$config__app_maintenance_retention_cache
+ - _APP_MAINTENANCE_RETENTION_ABUSE=$$config__app_maintenance_retention_abuse
+ - _APP_MAINTENANCE_RETENTION_AUDIT=$$config__app_maintenance_retention_audit
+ - _APP_SMS_PROVIDER=$$config__app_sms_provider
+ - _APP_SMS_FROM=$$config__app_sms_from
+ - OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network
+ volumes:
+ - "$$id-uploads:/storage/uploads"
+ - "$$id-cache:/storage/cache"
+ - "$$id-config:/storage/config"
+ - "$$id-certificates:/storage/certificates"
+ - "$$id-functions:/storage/functions"
+ ports:
+ - "80"
+ proxy:
+ - port: "80"
+ "$$id-executor":
+ image: appwrite/appwrite:$$core_version
+ environment:
+ - _APP_ENV=$$config__app_env
+ - _APP_FUNCTIONS_TIMEOUT=$$config__app_functions_timeout
+ - _APP_FUNCTIONS_BUILD_TIMEOUT=$$config__app_functions_build_timeout
+ - _APP_FUNCTIONS_CONTAINERS=$$config__app_functions_containers
+ - _APP_FUNCTIONS_RUNTIMES=$$config__app_functions_runtimes
+ - _APP_FUNCTIONS_CPUS=$$config__app_functions_cpus
+ - _APP_FUNCTIONS_MEMORY=$$config__app_functions_memory_allocated
+ - _APP_FUNCTIONS_MEMORY_SWAP=$$config__app_functions_memory_swap
+ - _APP_FUNCTIONS_INACTIVE_THRESHOLD=$$config__app_functions_inactive_threshold
+ - _APP_EXECUTOR_SECRET=$$secret__app_executor_secret
+ - _APP_LOGGING_PROVIDER=$$config__app_logging_provider
+ - _APP_LOGGING_CONFIG=$$config__app_logging_config
+ - _APP_STORAGE_DEVICE=$$config__app_storage_device
+ - _APP_STORAGE_S3_ACCESS_KEY=$$secret__app_storage_s3_access_key
+ - _APP_STORAGE_S3_SECRET=$$secret__app_storage_s3_secret
+ - _APP_STORAGE_S3_REGION=$$config__app_storage_s3_region
+ - _APP_STORAGE_S3_BUCKET=$$config__app_storage_s3_bucket
+ - _APP_STORAGE_DO_SPACES_ACCESS_KEY=$$secret__app_storage_do_spaces_access_key
+ - _APP_STORAGE_DO_SPACES_SECRET=$$secret__app_storage_do_spaces_secret
+ - _APP_STORAGE_DO_SPACES_REGION=$$config__app_storage_do_spaces_region
+ - _APP_STORAGE_DO_SPACES_BUCKET=$$config__app_storage_do_spaces_bucket
+ - _APP_STORAGE_BACKBLAZE_ACCESS_KEY=$$secret__app_storage_backblaze_access_key
+ - _APP_STORAGE_BACKBLAZE_SECRET=$$secret__app_storage_backblaze_secret
+ - _APP_STORAGE_BACKBLAZE_REGION=$$config__app_storage_backblaze_region
+ - _APP_STORAGE_BACKBLAZE_BUCKET=$$config__app_storage_backblaze_bucket
+ - _APP_STORAGE_LINODE_ACCESS_KEY=$$secret__app_storage_linode_access_key
+ - _APP_STORAGE_LINODE_SECRET=$$secret__app_storage_linode_secret
+ - _APP_STORAGE_LINODE_REGION=$$config__app_storage_linode_region
+ - _APP_STORAGE_LINODE_BUCKET=$$config__app_storage_linode_bucket
+ - _APP_STORAGE_WASABI_ACCESS_KEY=$$secret__app_storage_wasabi_access_key
+ - _APP_STORAGE_WASABI_SECRET=$$secret__app_storage_wasabi_secret
+ - _APP_STORAGE_WASABI_REGION=$$config__app_storage_wasabi_region
+ - _APP_STORAGE_WASABI_BUCKET=$$config__app_storage_wasabi_bucket
+ - DOCKERHUB_PULL_USERNAME=$$config_dockerhub_pull_username
+ - DOCKERHUB_PULL_PASSWORD=$$secret_dockerhub_pull_password
+ - OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network
+ volumes:
+ - "$$id-functions:/storage/functions"
+ - "$$id-builds:/storage/builds"
+ - "/var/run/docker.sock:/var/run/docker.sock"
+ - "/tmp:/tmp:rw"
+ entrypoint: executor
+ "$$id-influxdb":
+ image: appwrite/influxdb:1.5.0
+ environment: []
+ volumes:
+ - "$$id-influxdb:/var/lib/influxdb"
+ "$$id-maintenance":
+ image: appwrite/appwrite:$$core_version
+ environment:
+ - _APP_ENV=$$config__app_env
+ - _APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1
+ - _APP_DOMAIN=$$config__app_domain
+ - _APP_DOMAIN_TARGET=$$config__app_domain_target
+ - _APP_REDIS_HOST=$$config__app_redis_host
+ - _APP_REDIS_PORT=$$config__app_redis_port
+ - _APP_REDIS_USER=$$config__app_redis_user
+ - _APP_REDIS_PASS=$$secret__app_redis_pass
+ - _APP_DB_HOST=$$config__app_db_host
+ - _APP_DB_PORT=$$config__app_db_port
+ - _APP_DB_SCHEMA=$$config__app_db_schema
+ - _APP_DB_USER=$$config__app_db_user
+ - _APP_DB_PASS=$$secret__app_db_pass
+ - _APP_MAINTENANCE_INTERVAL=$$config__app_maintenance_interval
+ - _APP_MAINTENANCE_RETENTION_EXECUTION=$$config__app_maintenance_retention_execution
+ - _APP_MAINTENANCE_RETENTION_CACHE=$$config__app_maintenance_retention_cache
+ - _APP_MAINTENANCE_RETENTION_ABUSE=$$config__app_maintenance_retention_abuse
+ - _APP_MAINTENANCE_RETENTION_AUDIT=$$config__app_maintenance_retention_audit
+ - OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network
+ volumes: []
+ entrypoint: maintenance
+ "$$id-mariadb":
+ image: mariadb:10.7
+ command: "--innodb-flush-method fsync"
+ environment:
+ - MARIADB_ROOT_PASSWORD=$$secret__app_db_root_pass
+ - MARIADB_DATABASE=$$config__app_db_schema
+ - MARIADB_USER=$$config__app_db_user
+ - MARIADB_PASSWORD=$$secret__app_db_pass
+ - OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network
+ volumes:
+ - "$$id-mariadb:/var/lib/mysql"
+ "$$id-realtime":
+ image: appwrite/appwrite:$$core_version
+ environment:
+ - _APP_ENV=$$config__app_env
+ - _APP_WORKER_PER_CORE=$$config__app_worker_per_core
+ - _APP_OPTIONS_ABUSE=$$config__app_options_abuse
+ - _APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1
+ - _APP_REDIS_HOST=$$config__app_redis_host
+ - _APP_REDIS_PORT=$$config__app_redis_port
+ - _APP_DB_HOST=$$config__app_db_host
+ - _APP_DB_PORT=$$config__app_db_port
+ - _APP_DB_SCHEMA=$$config__app_db_schema
+ - _APP_DB_USER=$$config__app_db_user
+ - _APP_DB_PASS=$$secret__app_db_pass
+ - _APP_USAGE_STATS=$$config__app_usage_stats
+ - _APP_LOGGING_PROVIDER=$$config__app_logging_provider
+ - _APP_LOGGING_CONFIG=$$config__app_logging_config
+ - OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network
+ volumes: []
+ entrypoint: realtime
+ proxy:
+ - port: "80"
+ pathPrefix: "/v1/realtime"
+ "$$id-redis":
+ image: redis:7.0.4-alpine
+ command:
+ "--maxmemory 512mb --maxmemory-policy allkeys-lru --maxmemory-samples
+ 5"
+ environment: []
+ volumes:
+ - "$$id-redis:/data"
+ "$$id-schedule":
+ image: appwrite/appwrite:$$core_version
+ environment:
+ - _APP_ENV=$$config__app_env
+ - _APP_REDIS_HOST=$$config__app_redis_host
+ - _APP_REDIS_PORT=$$config__app_redis_port
+ - _APP_REDIS_USER=$$config__app_redis_user
+ - _APP_REDIS_PASS=$$secret__app_redis_pass
+ - OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network
+ volumes: []
+ entrypoint: schedule
+ "$$id-telegraf":
+ image: appwrite/telegraf:1.4.0
+ environment:
+ - _APP_INFLUXDB_HOST=$$config__app_influxdb_host
+ - _APP_INFLUXDB_PORT=$$config__app_influxdb_port
+ - OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network
+ volumes:
+ - "$$id-influxdb:/var/lib/influxdb"
+ "$$id-usage-database":
+ image: appwrite/appwrite:$$core_version
+ environment:
+ - _APP_ENV=$$config__app_env
+ - _APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1
+ - _APP_DB_HOST=$$config__app_db_host
+ - _APP_DB_PORT=$$config__app_db_port
+ - _APP_DB_SCHEMA=$$config__app_db_schema
+ - _APP_DB_USER=$$config__app_db_user
+ - _APP_DB_PASS=$$secret__app_db_pass
+ - _APP_INFLUXDB_HOST=$$config__app_influxdb_host
+ - _APP_INFLUXDB_PORT=$$config__app_influxdb_port
+ - _APP_USAGE_TIMESERIES_INTERVAL=$$config__app_usage_timeseries_interval
+ - _APP_USAGE_DATABASE_INTERVAL=$$config__app_usage_database_interval
+ - _APP_REDIS_HOST=$$config__app_redis_host
+ - _APP_REDIS_PORT=$$config__app_redis_port
+ - _APP_REDIS_USER=$$config__app_redis_user
+ - _APP_REDIS_PASS=$$secret__app_redis_pass
+ - _APP_LOGGING_PROVIDER=$$config__app_logging_provider
+ - _APP_LOGGING_CONFIG=$$config__app_logging_config
+ - OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network
+ volumes: []
+ entrypoint: usage --type database
+ "$$id-usage":
+ image: appwrite/appwrite:$$core_version
+ environment:
+ - _APP_ENV=$$config__app_env
+ - _APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1
+ - _APP_DB_HOST=$$config__app_db_host
+ - _APP_DB_PORT=$$config__app_db_port
+ - _APP_DB_SCHEMA=$$config__app_db_schema
+ - _APP_DB_USER=$$config__app_db_user
+ - _APP_DB_PASS=$$secret__app_db_pass
+ - _APP_INFLUXDB_HOST=$$config__app_influxdb_host
+ - _APP_INFLUXDB_PORT=$$config__app_influxdb_port
+ - _APP_USAGE_TIMESERIES_INTERVAL=$$config__app_usage_timeseries_interval
+ - _APP_USAGE_DATABASE_INTERVAL=$$config__app_usage_database_interval
+ - _APP_REDIS_HOST=$$config__app_redis_host
+ - _APP_REDIS_PORT=$$config__app_redis_port
+ - _APP_REDIS_USER=$$config__app_redis_user
+ - _APP_REDIS_PASS=$$secret__app_redis_pass
+ - _APP_LOGGING_PROVIDER=$$config__app_logging_provider
+ - _APP_LOGGING_CONFIG=$$config__app_logging_config
+ - OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network
+ volumes: []
+ entrypoint: usage --type timeseries
+ "$$id-worker-audits":
+ image: appwrite/appwrite:$$core_version
+ environment:
+ - _APP_ENV=$$config__app_env
+ - _APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1
+ - _APP_REDIS_HOST=$$config__app_redis_host
+ - _APP_REDIS_PORT=$$config__app_redis_port
+ - _APP_REDIS_USER=$$config__app_redis_user
+ - _APP_REDIS_PASS=$$secret__app_redis_pass
+ - _APP_DB_HOST=$$config__app_db_host
+ - _APP_DB_PORT=$$config__app_db_port
+ - _APP_DB_SCHEMA=$$config__app_db_schema
+ - _APP_DB_USER=$$config__app_db_user
+ - _APP_DB_PASS=$$secret__app_db_pass
+ - _APP_LOGGING_PROVIDER=$$config__app_logging_provider
+ - _APP_LOGGING_CONFIG=$$config__app_logging_config
+ - OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network
+ volumes: []
+ entrypoint: worker-audits
+ "$$id-worker-builds":
+ image: appwrite/appwrite:$$core_version
+ environment:
+ - _APP_ENV=$$config__app_env
+ - _APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1
+ - _APP_EXECUTOR_SECRET=$$secret__app_executor_secret
+ - _APP_EXECUTOR_HOST=$$config__app_executor_host
+ - _APP_REDIS_HOST=$$config__app_redis_host
+ - _APP_REDIS_PORT=$$config__app_redis_port
+ - _APP_REDIS_USER=$$config__app_redis_user
+ - _APP_REDIS_PASS=$$secret__app_redis_pass
+ - _APP_DB_HOST=$$config__app_db_host
+ - _APP_DB_PORT=$$config__app_db_port
+ - _APP_DB_SCHEMA=$$config__app_db_schema
+ - _APP_DB_USER=$$config__app_db_user
+ - _APP_DB_PASS=$$secret__app_db_pass
+ - _APP_LOGGING_PROVIDER=$$config__app_logging_provider
+ - _APP_LOGGING_CONFIG=$$config__app_logging_config
+ - OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network
+ volumes: []
+ entrypoint: worker-builds
+ "$$id-worker-certificates":
+ image: appwrite/appwrite:$$core_version
+ environment:
+ - _APP_ENV=$$config__app_env
+ - _APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1
+ - _APP_DOMAIN=$$config__app_domain
+ - _APP_DOMAIN_TARGET=$$config__app_domain_target
+ - _APP_SYSTEM_SECURITY_EMAIL_ADDRESS=$$config__app_system_security_email_address
+ - _APP_REDIS_HOST=$$config__app_redis_host
+ - _APP_REDIS_PORT=$$config__app_redis_port
+ - _APP_REDIS_USER=$$config__app_redis_user
+ - _APP_REDIS_PASS=$$secret__app_redis_pass
+ - _APP_DB_HOST=$$config__app_db_host
+ - _APP_DB_PORT=$$config__app_db_port
+ - _APP_DB_SCHEMA=$$config__app_db_schema
+ - _APP_DB_USER=$$config__app_db_user
+ - _APP_DB_PASS=$$secret__app_db_pass
+ - _APP_LOGGING_PROVIDER=$$config__app_logging_provider
+ - _APP_LOGGING_CONFIG=$$config__app_logging_config
+ - OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network
+ volumes:
+ - "$$id-config:/storage/config"
+ - "$$id-certificates:/storage/certificates"
+ entrypoint: worker-certificates
+ "$$id-worker-databases":
+ image: appwrite/appwrite:$$core_version
+ environment:
+ - _APP_ENV=$$config__app_env
+ - _APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1
+ - _APP_REDIS_HOST=$$config__app_redis_host
+ - _APP_REDIS_PORT=$$config__app_redis_port
+ - _APP_REDIS_USER=$$config__app_redis_user
+ - _APP_REDIS_PASS=$$secret__app_redis_pass
+ - _APP_DB_HOST=$$config__app_db_host
+ - _APP_DB_PORT=$$config__app_db_port
+ - _APP_DB_SCHEMA=$$config__app_db_schema
+ - _APP_DB_USER=$$config__app_db_user
+ - _APP_DB_PASS=$$secret__app_db_pass
+ - _APP_LOGGING_PROVIDER=$$config__app_logging_provider
+ - _APP_LOGGING_CONFIG=$$config__app_logging_config
+ - OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network
+ volumes: []
+ entrypoint: worker-databases
+ "$$id-worker-deletes":
+ image: appwrite/appwrite:$$core_version
+ environment:
+ - _APP_ENV=$$config__app_env
+ - _APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1
+ - _APP_REDIS_HOST=$$config__app_redis_host
+ - _APP_REDIS_PORT=$$config__app_redis_port
+ - _APP_REDIS_USER=$$config__app_redis_user
+ - _APP_REDIS_PASS=$$secret__app_redis_pass
+ - _APP_DB_HOST=$$config__app_db_host
+ - _APP_DB_PORT=$$config__app_db_port
+ - _APP_DB_SCHEMA=$$config__app_db_schema
+ - _APP_DB_USER=$$config__app_db_user
+ - _APP_DB_PASS=$$secret__app_db_pass
+ - _APP_STORAGE_DEVICE=$$config__app_storage_device
+ - _APP_STORAGE_S3_ACCESS_KEY=$$secret__app_storage_s3_access_key
+ - _APP_STORAGE_S3_SECRET=$$secret__app_storage_s3_secret
+ - _APP_STORAGE_S3_REGION=$$config__app_storage_s3_region
+ - _APP_STORAGE_S3_BUCKET=$$config__app_storage_s3_bucket
+ - _APP_STORAGE_DO_SPACES_ACCESS_KEY=$$secret__app_storage_do_spaces_access_key
+ - _APP_STORAGE_DO_SPACES_SECRET=$$secret__app_storage_do_spaces_secret
+ - _APP_STORAGE_DO_SPACES_REGION=$$config__app_storage_do_spaces_region
+ - _APP_STORAGE_DO_SPACES_BUCKET=$$config__app_storage_do_spaces_bucket
+ - _APP_STORAGE_BACKBLAZE_ACCESS_KEY=$$secret__app_storage_backblaze_access_key
+ - _APP_STORAGE_BACKBLAZE_SECRET=$$secret__app_storage_backblaze_secret
+ - _APP_STORAGE_BACKBLAZE_REGION=$$config__app_storage_backblaze_region
+ - _APP_STORAGE_BACKBLAZE_BUCKET=$$config__app_storage_backblaze_bucket
+ - _APP_STORAGE_LINODE_ACCESS_KEY=$$secret__app_storage_linode_access_key
+ - _APP_STORAGE_LINODE_SECRET=$$secret__app_storage_linode_secret
+ - _APP_STORAGE_LINODE_REGION=$$config__app_storage_linode_region
+ - _APP_STORAGE_LINODE_BUCKET=$$config__app_storage_linode_bucket
+ - _APP_STORAGE_WASABI_ACCESS_KEY=$$secret__app_storage_wasabi_access_key
+ - _APP_STORAGE_WASABI_SECRET=$$secret__app_storage_wasabi_secret
+ - _APP_STORAGE_WASABI_REGION=$$config__app_storage_wasabi_region
+ - _APP_STORAGE_WASABI_BUCKET=$$config__app_storage_wasabi_bucket
+ - _APP_LOGGING_PROVIDER=$$config__app_logging_provider
+ - _APP_LOGGING_CONFIG=$$config__app_logging_config
+ - _APP_EXECUTOR_SECRET=$$secret__app_executor_secret
+ - _APP_EXECUTOR_HOST=$$config__app_executor_host
+ - OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network
+ volumes:
+ - "$$id-uploads:/storage/uploads"
+ - "$$id-cache:/storage/cache"
+ - "$$id-functions:/storage/functions"
+ - "$$id-builds:/storage/builds"
+ - "$$id-certificates:/storage/certificates"
+ entrypoint: worker-deletes
+ "$$id-worker-functions":
+ image: appwrite/appwrite:$$core_version
+ environment:
+ - _APP_ENV=$$config__app_env
+ - _APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1
+ - _APP_REDIS_HOST=$$config__app_redis_host
+ - _APP_REDIS_PORT=$$config__app_redis_port
+ - _APP_REDIS_USER=$$config__app_redis_user
+ - _APP_REDIS_PASS=$$secret__app_redis_pass
+ - _APP_DB_HOST=$$config__app_db_host
+ - _APP_DB_PORT=$$config__app_db_port
+ - _APP_DB_SCHEMA=$$config__app_db_schema
+ - _APP_DB_USER=$$config__app_db_user
+ - _APP_DB_PASS=$$secret__app_db_pass
+ - _APP_FUNCTIONS_TIMEOUT=$$config__app_functions_timeout
+ - _APP_EXECUTOR_SECRET=$$secret__app_executor_secret
+ - _APP_EXECUTOR_HOST=$$config__app_executor_host
+ - _APP_USAGE_STATS=$$config__app_usage_stats
+ - DOCKERHUB_PULL_USERNAME=$$config_dockerhub_pull_username
+ - DOCKERHUB_PULL_PASSWORD=$$secret_dockerhub_pull_password
+ - OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network
+ volumes: []
+ entrypoint: worker-functions
+ "$$id-worker-mails":
+ image: appwrite/appwrite:$$core_version
+ environment:
+ - _APP_ENV=$$config__app_env
+ - _APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1
+ - _APP_SYSTEM_EMAIL_NAME=$$config__app_system_email_name
+ - _APP_SYSTEM_EMAIL_ADDRESS=$$config__app_system_email_address
+ - _APP_REDIS_HOST=$$config__app_redis_host
+ - _APP_REDIS_PORT=$$config__app_redis_port
+ - _APP_REDIS_USER=$$config__app_redis_user
+ - _APP_REDIS_PASS=$$secret__app_redis_pass
+ - _APP_SMTP_HOST=$$config__app_smtp_host
+ - _APP_SMTP_PORT=$$config__app_smtp_port
+ - _APP_SMTP_SECURE=$$config__app_smtp_secure
+ - _APP_SMTP_USERNAME=$$config__app_smtp_username
+ - _APP_SMTP_PASSWORD=$$secret__app_smtp_password
+ - _APP_LOGGING_PROVIDER=$$config__app_logging_provider
+ - _APP_LOGGING_CONFIG=$$config__app_logging_config
+ - OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network
+ volumes: []
+ entrypoint: worker-mails
+ "$$id-worker-messaging":
+ image: appwrite/appwrite:$$core_version
+ environment:
+ - _APP_ENV=$$config__app_env
+ - _APP_REDIS_HOST=$$config__app_redis_host
+ - _APP_REDIS_PORT=$$config__app_redis_port
+ - _APP_REDIS_USER=$$config__app_redis_user
+ - _APP_REDIS_PASS=$$secret__app_redis_pass
+ - _APP_SMS_PROVIDER=$$config__app_sms_provider
+ - _APP_SMS_FROM=$$config__app_sms_from
+ - _APP_LOGGING_PROVIDER=$$config__app_logging_provider
+ - _APP_LOGGING_CONFIG=$$config__app_logging_config
+ - OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network
+ volumes: []
+ entrypoint: worker-messaging
+ "$$id-worker-webhooks":
+ image: appwrite/appwrite:$$core_version
+ environment:
+ - _APP_ENV=$$config__app_env
+ - _APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1
+ - _APP_SYSTEM_SECURITY_EMAIL_ADDRESS=$$config__app_system_security_email_address
+ - _APP_REDIS_HOST=$$config__app_redis_host
+ - _APP_REDIS_PORT=$$config__app_redis_port
+ - _APP_REDIS_USER=$$config__app_redis_user
+ - _APP_REDIS_PASS=$$secret__app_redis_pass
+ - _APP_LOGGING_PROVIDER=$$config__app_logging_provider
+ - _APP_LOGGING_CONFIG=$$config__app_logging_config
+ - OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network
+ volumes: []
+ entrypoint: worker-webhooks
+ variables:
+ - id: "$$config__app_influxdb_host"
+ name: _APP_INFLUXDB_HOST
+ label: InfluxDB | _APP_INFLUXDB_HOST
+ defaultValue: "$$id-influxdb"
+ description: ""
+ - id: "$$config__app_influxdb_port"
+ name: _APP_INFLUXDB_PORT
+ label: InfluxDB | _APP_INFLUXDB_PORT
+ defaultValue: "8086"
+ description: InfluxDB server TCP port.
+ - id: "$$config__app_env"
+ name: _APP_ENV
+ label: General | _APP_ENV
+ defaultValue: production
+ description: Set your server running environment.
+ - id: "$$config__app_worker_per_core"
+ name: _APP_WORKER_PER_CORE
+ label: General | _APP_WORKER_PER_CORE
+ defaultValue: "6"
+ description:
+ Internal Worker per core for the API, Realtime and Executor containers.
+ Can be configured to optimize performance.
+ - id: "$$config__app_locale"
+ name: _APP_LOCALE
+ label: General | _APP_LOCALE
+ defaultValue: en
+ description: Set your Appwrite's locale. By default, the locale is set to 'en'.
+ - id: "$$config__app_console_whitelist_root"
+ name: _APP_CONSOLE_WHITELIST_ROOT
+ label: General | _APP_CONSOLE_WHITELIST_ROOT
+ defaultValue: enabled
+ description:
+ This option allows you to disable the creation of new users on the
+ Appwrite console. When enabled only 1 user will be able to use the registration
+ form. New users can be added by inviting them to your project. By default this
+ option is enabled.
+ - id: "$$config__app_console_whitelist_emails"
+ name: _APP_CONSOLE_WHITELIST_EMAILS
+ label: General | _APP_CONSOLE_WHITELIST_EMAILS
+ defaultValue: ""
+ description:
+ This option allows you to limit creation of new users on the Appwrite
+ console. This option is very useful for small teams or sole developers. To enable
+ it, pass a list of allowed email addresses separated by a comma.
+ - id: "$$config__app_console_whitelist_ips"
+ name: _APP_CONSOLE_WHITELIST_IPS
+ label: General | _APP_CONSOLE_WHITELIST_IPS
+ defaultValue: ""
+ description:
+ This last option allows you to limit creation of users in Appwrite
+ console for users sharing the same set of IP addresses. This option is very
+ useful for team working with a VPN service or a company IP.\n\nTo enable/activate
+ this option, pass a list of allowed IP addresses separated by a comma.
+ - id: "$$config__app_system_email_name"
+ name: _APP_SYSTEM_EMAIL_NAME
+ label: General | _APP_SYSTEM_EMAIL_NAME
+ defaultValue: Appwrite
+ description:
+ This is the sender name value that will appear on email messages
+ sent to developers from the Appwrite console. You can use url encoded strings
+ for spaces and special chars.
+ - id: "$$config__app_system_email_address"
+ name: _APP_SYSTEM_EMAIL_ADDRESS
+ label: General | _APP_SYSTEM_EMAIL_ADDRESS
+ defaultValue: team@appwrite.io
+ description:
+ This is the sender email address that will appear on email messages
+ sent to developers from the Appwrite console. You should choose an email address
+ that is allowed to be used from your SMTP server to avoid the server email ending
+ in the users' SPAM folders.
+ - id: "$$config__app_system_security_email_address"
+ name: _APP_SYSTEM_SECURITY_EMAIL_ADDRESS
+ label: General | _APP_SYSTEM_SECURITY_EMAIL_ADDRESS
+ defaultValue: certs@appwrite.io
+ description:
+ This is the email address used to issue SSL certificates for custom
+ domains or the user agent in your webhooks payload.
+ - id: "$$config__app_system_response_format"
+ name: _APP_SYSTEM_RESPONSE_FORMAT
+ label: General | _APP_SYSTEM_RESPONSE_FORMAT
+ defaultValue: ""
+ description:
+ Use this environment variable to set the default Appwrite HTTP response
+ format to support an older version of Appwrite. This option is useful to overcome
+ breaking changes between versions. You can also use the X-Appwrite-Response-Format
+ HTTP request header to overwrite the response for a specific request. This variable
+ accepts any valid Appwrite version. To use the current version format, leave
+ the value of the variable empty.
+ - id: "$$config__app_options_abuse"
+ name: _APP_OPTIONS_ABUSE
+ label: General | _APP_OPTIONS_ABUSE
+ defaultValue: enabled
+ description:
+ Allows you to disable abuse checks and API rate limiting. By default,
+ set to 'enabled'. To cancel the abuse checking, set to 'disabled'. It is not
+ recommended to disable this check-in a production environment.
+ - id: "$$config__app_options_force_https"
+ name: _APP_OPTIONS_FORCE_HTTPS
+ label: General | _APP_OPTIONS_FORCE_HTTPS
+ defaultValue: disabled
+ description:
+ Allows you to force HTTPS connection to your API. This feature redirects
+ any HTTP call to HTTPS and adds the 'Strict-Transport-Security' header to all
+ HTTP responses.
+ - id: "$$secret__app_openssl_key_v1"
+ name: _APP_OPENSSL_KEY_V1
+ label: General | _APP_OPENSSL_KEY_V1
+ defaultValue: "$$generate_hex(256)"
+ description:
+ This is your server private secret key that is used to encrypt all
+ sensitive data on your server. Appwrite server encrypts all secret data on your
+ server like webhooks, HTTP passwords, user sessions, and storage files. Keep
+ it a secret and have a backup for it.
+ - id: "$$config__app_domain"
+ name: _APP_DOMAIN
+ label: General | _APP_DOMAIN
+ defaultValue: $$generate_domain
+ description:
+ Your Appwrite domain address. When setting a public suffix domain,
+ Appwrite will attempt to issue a valid SSL certificate automatically. When used
+ with a dev domain, Appwrite will assign a self-signed SSL certificate. The default
+ value is 'localhost'.
+ - id: "$$config__app_domain_target"
+ name: _APP_DOMAIN_TARGET
+ label: General | _APP_DOMAIN_TARGET
+ defaultValue: $$generate_fqdn
+ description:
+ A DNS A record hostname to serve as a CNAME target for your Appwrite
+ custom domains. You can use the same value as used for the Appwrite '_APP_DOMAIN'
+ variable. The default value is 'localhost'.
+ - id: "$$config__app_redis_host"
+ name: _APP_REDIS_HOST
+ label: Redis | _APP_REDIS_HOST
+ defaultValue: "$$id-redis"
+ description: ""
+ - id: "$$config__app_redis_port"
+ name: _APP_REDIS_PORT
+ label: Redis | _APP_REDIS_PORT
+ defaultValue: "6379"
+ description: Redis server TCP port.
+ - id: "$$config__app_redis_user"
+ name: _APP_REDIS_USER
+ label: Redis | _APP_REDIS_USER
+ defaultValue: ""
+ description:
+ Redis server user. This is an optional variable. Default value is
+ an empty string.
+ - id: "$$secret__app_redis_pass"
+ name: _APP_REDIS_PASS
+ label: Redis | _APP_REDIS_PASS
+ defaultValue: ""
+ description:
+ Redis server password. This is an optional variable. Default value
+ is an empty string.
+ - id: "$$config__app_db_host"
+ name: _APP_DB_HOST
+ label: MariaDB | _APP_DB_HOST
+ defaultValue: "$$id-mariadb"
+ description: ""
+ - id: "$$config__app_db_port"
+ name: _APP_DB_PORT
+ label: MariaDB | _APP_DB_PORT
+ defaultValue: "3306"
+ description: MariaDB server TCP port.
+ - id: "$$config__app_db_schema"
+ name: _APP_DB_SCHEMA
+ label: MariaDB | _APP_DB_SCHEMA
+ defaultValue: appwrite
+ description: MariaDB server database schema.
+ - id: "$$config__app_db_user"
+ name: _APP_DB_USER
+ label: MariaDB | _APP_DB_USER
+ defaultValue: user
+ description: MariaDB server user name.
+ - id: "$$secret__app_db_root_pass"
+ name: MARIADB_ROOT_PASSWORD
+ label: MariaDB | MARIADB_ROOT_PASSWORD
+ defaultValue: "$$generate_hex(16)"
+ description: MariaDB server root user password.
+ - id: "$$secret__app_db_pass"
+ name: _APP_DB_PASS
+ label: MariaDB | _APP_DB_PASS
+ defaultValue: "$$generate_hex(16)"
+ description: MariaDB server user password.
+ - id: "$$config__app_smtp_host"
+ name: _APP_SMTP_HOST
+ label: SMTP | _APP_SMTP_HOST
+ defaultValue: ""
+ description:
+ SMTP server host name address. Use an empty string to disable all
+ mail sending from the server. The default value for this variable is an empty
+ string.
+ - id: "$$config__app_smtp_port"
+ name: _APP_SMTP_PORT
+ label: SMTP | _APP_SMTP_PORT
+ defaultValue: ""
+ description: SMTP server TCP port. Empty by default.
+ - id: "$$config__app_smtp_secure"
+ name: _APP_SMTP_SECURE
+ label: SMTP | _APP_SMTP_SECURE
+ defaultValue: ""
+ description:
+ SMTP secure connection protocol. Empty by default, change to 'tls'
+ if running on a secure connection.
+ - id: "$$config__app_smtp_username"
+ name: _APP_SMTP_USERNAME
+ label: SMTP | _APP_SMTP_USERNAME
+ defaultValue: ""
+ description: SMTP server user name. Empty by default.
+ - id: "$$secret__app_smtp_password"
+ name: _APP_SMTP_PASSWORD
+ label: SMTP | _APP_SMTP_PASSWORD
+ defaultValue: ""
+ description: SMTP server user password. Empty by default.
+ - id: "$$config__app_usage_stats"
+ name: _APP_USAGE_STATS
+ label: General | _APP_USAGE_STATS
+ defaultValue: enabled
+ description:
+ This variable allows you to disable the collection and displaying
+ of usage stats. This value is set to 'enabled' by default, to disable the usage
+ stats set the value to 'disabled'. When disabled, it's recommended to turn off
+ the Worker Usage, Influxdb and Telegraf containers for better resource usage.
+ - id: "$$config__app_storage_limit"
+ name: _APP_STORAGE_LIMIT
+ label: Storage | _APP_STORAGE_LIMIT
+ defaultValue: "30000000"
+ description:
+ Maximum file size allowed for file upload. The default value is 30MB.
+ You should pass your size limit value in bytes.
+ - id: "$$config__app_storage_preview_limit"
+ name: _APP_STORAGE_PREVIEW_LIMIT
+ label: Storage | _APP_STORAGE_PREVIEW_LIMIT
+ defaultValue: "20000000"
+ description:
+ Maximum file size allowed for file image preview. The default value
+ is 20MB. You should pass your size limit value in bytes.
+ - id: "$$config__app_storage_antivirus_enabled"
+ name: _APP_STORAGE_ANTIVIRUS
+ label: Storage | _APP_STORAGE_ANTIVIRUS
+ defaultValue: disabled
+ description:
+ This variable allows you to disable the internal anti-virus scans.
+ This value is set to 'disabled' by default, to enable the scans set the value
+ to 'enabled'. Before enabling, you must add the ClamAV service and depend on
+ it on main Appwrite service.
+ - id: "$$config__app_storage_antivirus_host"
+ name: _APP_STORAGE_ANTIVIRUS_HOST
+ label: Storage | _APP_STORAGE_ANTIVIRUS_HOST
+ defaultValue: clamav
+ description: ClamAV server host name address.
+ - id: "$$config__app_storage_antivirus_port"
+ name: _APP_STORAGE_ANTIVIRUS_PORT
+ label: Storage | _APP_STORAGE_ANTIVIRUS_PORT
+ defaultValue: "3310"
+ description: ClamAV server TCP port.
+ - id: "$$config__app_storage_device"
+ name: _APP_STORAGE_DEVICE
+ label: Storage | _APP_STORAGE_DEVICE
+ defaultValue: Local
+ description:
+ Select default storage device. The default value is 'Local'. List
+ of supported adapters are 'Local', 'S3', 'DOSpaces', 'Backblaze', 'Linode' and
+ 'Wasabi'.
+ - id: "$$secret__app_storage_s3_access_key"
+ name: _APP_STORAGE_S3_ACCESS_KEY
+ label: Storage | _APP_STORAGE_S3_ACCESS_KEY
+ defaultValue: ""
+ description:
+ AWS S3 storage access key. Required when the storage adapter is set
+ to S3. You can get your access key from your AWS console.
+ - id: "$$secret__app_storage_s3_secret"
+ name: _APP_STORAGE_S3_SECRET
+ label: Storage | _APP_STORAGE_S3_SECRET
+ defaultValue: ""
+ description:
+ AWS S3 storage secret key. Required when the storage adapter is set
+ to S3. You can get your secret key from your AWS console.
+ - id: "$$config__app_storage_s3_region"
+ name: _APP_STORAGE_S3_REGION
+ label: Storage | _APP_STORAGE_S3_REGION
+ defaultValue: us-east-1
+ description:
+ AWS S3 storage region. Required when storage adapter is set to S3.
+ You can find your region info for your bucket from AWS console.
+ - id: "$$config__app_storage_s3_bucket"
+ name: _APP_STORAGE_S3_BUCKET
+ label: Storage | _APP_STORAGE_S3_BUCKET
+ defaultValue: ""
+ description:
+ AWS S3 storage bucket. Required when storage adapter is set to S3.
+ You can create buckets in your AWS console.
+ - id: "$$secret__app_storage_do_spaces_access_key"
+ name: _APP_STORAGE_DO_SPACES_ACCESS_KEY
+ label: Storage | _APP_STORAGE_DO_SPACES_ACCESS_KEY
+ defaultValue: ""
+ description:
+ DigitalOcean spaces access key. Required when the storage adapter
+ is set to DOSpaces. You can get your access key from your DigitalOcean console.
+ - id: "$$secret__app_storage_do_spaces_secret"
+ name: _APP_STORAGE_DO_SPACES_SECRET
+ label: Storage | _APP_STORAGE_DO_SPACES_SECRET
+ defaultValue: ""
+ description:
+ DigitalOcean spaces secret key. Required when the storage adapter
+ is set to DOSpaces. You can get your secret key from your DigitalOcean console.
+ - id: "$$config__app_storage_do_spaces_region"
+ name: _APP_STORAGE_DO_SPACES_REGION
+ label: Storage | _APP_STORAGE_DO_SPACES_REGION
+ defaultValue: us-east-1
+ description:
+ DigitalOcean spaces region. Required when storage adapter is set
+ to DOSpaces. You can find your region info for your space from DigitalOcean
+ console.
+ - id: "$$config__app_storage_do_spaces_bucket"
+ name: _APP_STORAGE_DO_SPACES_BUCKET
+ label: Storage | _APP_STORAGE_DO_SPACES_BUCKET
+ defaultValue: ""
+ description:
+ DigitalOcean spaces bucket. Required when storage adapter is set
+ to DOSpaces. You can create spaces in your DigitalOcean console.
+ - id: "$$secret__app_storage_backblaze_access_key"
+ name: _APP_STORAGE_BACKBLAZE_ACCESS_KEY
+ label: Storage | _APP_STORAGE_BACKBLAZE_ACCESS_KEY
+ defaultValue: ""
+ description:
+ Backblaze access key. Required when the storage adapter is set to
+ Backblaze. Your Backblaze keyID will be your access key. You can get your keyID
+ from your Backblaze console.
+ - id: "$$secret__app_storage_backblaze_secret"
+ name: _APP_STORAGE_BACKBLAZE_SECRET
+ label: Storage | _APP_STORAGE_BACKBLAZE_SECRET
+ defaultValue: ""
+ description:
+ Backblaze secret key. Required when the storage adapter is set to
+ Backblaze. Your Backblaze applicationKey will be your secret key. You can get
+ your applicationKey from your Backblaze console.
+ - id: "$$config__app_storage_backblaze_region"
+ name: _APP_STORAGE_BACKBLAZE_REGION
+ label: Storage | _APP_STORAGE_BACKBLAZE_REGION
+ defaultValue: us-west-004
+ description:
+ Backblaze region. Required when storage adapter is set to Backblaze.
+ You can find your region info from your Backblaze console.
+ - id: "$$config__app_storage_backblaze_bucket"
+ name: _APP_STORAGE_BACKBLAZE_BUCKET
+ label: Storage | _APP_STORAGE_BACKBLAZE_BUCKET
+ defaultValue: ""
+ description:
+ Backblaze bucket. Required when storage adapter is set to Backblaze.
+ You can create your bucket from your Backblaze console.
+ - id: "$$secret__app_storage_linode_access_key"
+ name: _APP_STORAGE_LINODE_ACCESS_KEY
+ label: Storage | _APP_STORAGE_LINODE_ACCESS_KEY
+ defaultValue: ""
+ description:
+ Linode object storage access key. Required when the storage adapter
+ is set to Linode. You can get your access key from your Linode console.
+ - id: "$$secret__app_storage_linode_secret"
+ name: _APP_STORAGE_LINODE_SECRET
+ label: Storage | _APP_STORAGE_LINODE_SECRET
+ defaultValue: ""
+ description:
+ Linode object storage secret key. Required when the storage adapter
+ is set to Linode. You can get your secret key from your Linode console.
+ - id: "$$config__app_storage_linode_region"
+ name: _APP_STORAGE_LINODE_REGION
+ label: Storage | _APP_STORAGE_LINODE_REGION
+ defaultValue: eu-central-1
+ description:
+ Linode object storage region. Required when storage adapter is set
+ to Linode. You can find your region info from your Linode console.
+ - id: "$$config__app_storage_linode_bucket"
+ name: _APP_STORAGE_LINODE_BUCKET
+ label: Storage | _APP_STORAGE_LINODE_BUCKET
+ defaultValue: ""
+ description:
+ Linode object storage bucket. Required when storage adapter is set
+ to Linode. You can create buckets in your Linode console.
+ - id: "$$secret__app_storage_wasabi_access_key"
+ name: _APP_STORAGE_WASABI_ACCESS_KEY
+ label: Storage | _APP_STORAGE_WASABI_ACCESS_KEY
+ defaultValue: ""
+ description:
+ Wasabi access key. Required when the storage adapter is set to Wasabi.
+ You can get your access key from your Wasabi console.
+ - id: "$$secret__app_storage_wasabi_secret"
+ name: _APP_STORAGE_WASABI_SECRET
+ label: Storage | _APP_STORAGE_WASABI_SECRET
+ defaultValue: ""
+ description:
+ Wasabi secret key. Required when the storage adapter is set to Wasabi.
+ You can get your secret key from your Wasabi console.
+ - id: "$$config__app_storage_wasabi_region"
+ name: _APP_STORAGE_WASABI_REGION
+ label: Storage | _APP_STORAGE_WASABI_REGION
+ defaultValue: eu-central-1
+ description:
+ Wasabi region. Required when storage adapter is set to Wasabi. You
+ can find your region info from your Wasabi console.
+ - id: "$$config__app_storage_wasabi_bucket"
+ name: _APP_STORAGE_WASABI_BUCKET
+ label: Storage | _APP_STORAGE_WASABI_BUCKET
+ defaultValue: ""
+ description:
+ Wasabi bucket. Required when storage adapter is set to Wasabi. You
+ can create buckets in your Wasabi console.
+ - id: "$$config__app_functions_size_limit"
+ name: _APP_FUNCTIONS_SIZE_LIMIT
+ label: Functions | _APP_FUNCTIONS_SIZE_LIMIT
+ defaultValue: "30000000"
+ description: The maximum size deployment in bytes. The default value is 30MB.
+ - id: "$$config__app_functions_timeout"
+ name: _APP_FUNCTIONS_TIMEOUT
+ label: Functions | _APP_FUNCTIONS_TIMEOUT
+ defaultValue: "900"
+ description:
+ The maximum number of seconds allowed as a timeout value when creating
+ a new function. The default value is 900 seconds.
+ - id: "$$config__app_functions_build_timeout"
+ name: _APP_FUNCTIONS_BUILD_TIMEOUT
+ label: Functions | _APP_FUNCTIONS_BUILD_TIMEOUT
+ defaultValue: "900"
+ description:
+ The maximum number of seconds allowed as a timeout value when building
+ a new function. The default value is 900 seconds.
+ - id: "$$config__app_functions_containers"
+ name: _APP_FUNCTIONS_CONTAINERS
+ label: Functions | _APP_FUNCTIONS_CONTAINERS
+ defaultValue: "10"
+ description:
+ The maximum number of containers Appwrite is allowed to keep alive
+ in the background for function environments. Running containers allow faster
+ execution time as there is no need to recreate each container every time a function
+ gets executed. The default value is 10.
+ - id: "$$config__app_functions_cpus"
+ name: _APP_FUNCTIONS_CPUS
+ label: Functions | _APP_FUNCTIONS_CPUS
+ defaultValue: ""
+ description:
+ The maximum number of CPU core a single cloud function is allowed
+ to use. Please note that setting a value higher than available cores will result
+ in a function error, which might result in an error. The default value is empty.
+ When it's empty, CPU limit will be disabled.
+ - id: "$$config__app_functions_memory_allocated"
+ name: _APP_FUNCTIONS_MEMORY
+ label: Functions | _APP_FUNCTIONS_MEMORY
+ defaultValue: ""
+ description:
+ The maximum amount of memory a single cloud function is allowed to
+ use in megabytes. The default value is empty. When it's empty, memory limit
+ will be disabled.
+ - id: "$$config__app_functions_memory_swap"
+ name: _APP_FUNCTIONS_MEMORY_SWAP
+ label: Functions | _APP_FUNCTIONS_MEMORY_SWAP
+ defaultValue: ""
+ description:
+ The maximum amount of swap memory a single cloud function is allowed
+ to use in megabytes. The default value is empty. When it's empty, swap memory
+ limit will be disabled.
+ - id: "$$config__app_functions_runtimes"
+ name: _APP_FUNCTIONS_RUNTIMES
+ label: Functions | _APP_FUNCTIONS_RUNTIMES
+ defaultValue: node-18.0
+ description: |-
+ This option allows you to limit the available environments for cloud functions. This option is very useful for low-cost servers to safe disk space.
+ To enable/activate this option, pass a list of allowed environments separated by a comma.
+ Currently, supported environments are: node-14.5, node-16.0, node-18.0, php-8.0, php-8.1, ruby-3.0, ruby-3.1, python-3.8, python-3.9, python-3.10, deno-1.21, deno-1.24, dart-2.15, dart-2.16, dart-2.17, dotnet-3.1, dotnet-6.0, java-8.0, java-11.0, java-17.0, java-18.0, swift-5.5, kotlin-1.6, cpp-17.0
+ - id: "$$secret__app_executor_secret"
+ name: _APP_EXECUTOR_SECRET
+ label: Functions | _APP_EXECUTOR_SECRET
+ defaultValue: "$$generate_hex(16)"
+ description:
+ The secret key used by Appwrite to communicate with the function
+ executor.
+ - id: "$$config__app_executor_host"
+ name: _APP_EXECUTOR_HOST
+ label: ""
+ defaultValue: http://$$id-executor/v1
+ description: ""
+ - id: "$$config__app_logging_provider"
+ name: _APP_LOGGING_PROVIDER
+ label: General | _APP_LOGGING_PROVIDER
+ defaultValue: ""
+ description:
+ This variable allows you to enable logging errors to 3rd party providers.
+ This value is empty by default, to enable the logger set the value to one of
+ 'sentry', 'raygun', 'appsignal', 'logowl'
+ - id: "$$config__app_logging_config"
+ name: _APP_LOGGING_CONFIG
+ label: General | _APP_LOGGING_CONFIG
+ defaultValue: ""
+ description:
+ This variable configures authentication to 3rd party error logging
+ providers. If using Sentry, this should be 'SENTRY_API_KEY;SENTRY_APP_ID'. If
+ using Raygun, this should be Raygun API key. If using AppSignal, this should
+ be AppSignal API key. If using LogOwl, this should be LogOwl Service Ticket.
+ - id: "$$config__app_statsd_host"
+ name: _APP_STATSD_HOST
+ label: ""
+ defaultValue: "$$id-telegraf"
+ description: ""
+ - id: "$$config__app_statsd_port"
+ name: _APP_STATSD_PORT
+ label: StatsD | _APP_STATSD_PORT
+ defaultValue: "8125"
+ description: StatsD server TCP port.
+ - id: "$$config__app_maintenance_interval"
+ name: _APP_MAINTENANCE_INTERVAL
+ label: Functions | _APP_MAINTENANCE_INTERVAL
+ defaultValue: "86400"
+ description:
+ Interval value containing the number of seconds that the Appwrite
+ maintenance process should wait before executing system cleanups and optimizations.
+ The default value is 86400 seconds (1 day).
+ - id: "$$config__app_maintenance_retention_execution"
+ name: _APP_MAINTENANCE_RETENTION_EXECUTION
+ label: Functions | _APP_MAINTENANCE_RETENTION_EXECUTION
+ defaultValue: "1209600"
+ description:
+ The maximum duration (in seconds) upto which to retain execution
+ logs. The default value is 1209600 seconds (14 days).
+ - id: "$$config__app_maintenance_retention_cache"
+ name: _APP_MAINTENANCE_RETENTION_CACHE
+ label: Functions | _APP_MAINTENANCE_RETENTION_CACHE
+ defaultValue: "2592000"
+ description:
+ The maximum duration (in seconds) upto which to retain cached files.
+ The default value is 2592000 seconds (30 days).
+ - id: "$$config__app_maintenance_retention_abuse"
+ name: _APP_MAINTENANCE_RETENTION_ABUSE
+ label: Functions | _APP_MAINTENANCE_RETENTION_ABUSE
+ defaultValue: "86400"
+ description:
+ The maximum duration (in seconds) upto which to retain abuse logs.
+ The default value is 86400 seconds (1 day).
+ - id: "$$config__app_maintenance_retention_audit"
+ name: _APP_MAINTENANCE_RETENTION_AUDIT
+ label: Functions | _APP_MAINTENANCE_RETENTION_AUDIT
+ defaultValue: "1209600"
+ description:
+ The maximum duration (in seconds) upto which to retain audit logs.
+ The default value is 1209600 seconds (14 days).
+ - id: "$$config__app_sms_provider"
+ name: _APP_SMS_PROVIDER
+ label: Phone | _APP_SMS_PROVIDER
+ defaultValue: ""
+ description:
+ "Provider used for delivering SMS for Phone authentication. Use the
+ following format: 'sms://[USER]:[SECRET]@[PROVIDER]'. Available providers
+ are twilio, text-magic, telesign, msg91, and vonage."
+ - id: "$$config__app_sms_from"
+ name: _APP_SMS_FROM
+ label: Phone | _APP_SMS_FROM
+ defaultValue: ""
+ description:
+ Phone number used for sending out messages. Must start with a leading
+ '+' and maximum of 15 digits without spaces (+123456789).
+ - id: "$$config__app_functions_inactive_threshold"
+ name: _APP_FUNCTIONS_INACTIVE_THRESHOLD
+ label: Functions | _APP_FUNCTIONS_INACTIVE_THRESHOLD
+ defaultValue: "60"
+ description:
+ The minimum time a function can be inactive before it's container
+ is shutdown and put to sleep. The default value is 60 seconds
+ - id: "$$config_open_runtimes_network"
+ name: OPEN_RUNTIMES_NETWORK
+ label: ""
+ defaultValue: "$$generate_network"
+ description: ""
+ - id: "$$config_dockerhub_pull_username"
+ name: DOCKERHUB_PULL_USERNAME
+ label: Functions | DOCKERHUB_PULL_USERNAME
+ defaultValue: ""
+ description:
+ The username for hub.docker.com. This variable is used to pull images
+ from hub.docker.com.
+ - id: "$$secret_dockerhub_pull_password"
+ name: DOCKERHUB_PULL_PASSWORD
+ label: Functions | DOCKERHUB_PULL_PASSWORD
+ defaultValue: ""
+ description:
+ The password for hub.docker.com. This variable is used to pull images
+ from hub.docker.com.
+ - id: "$$config__app_usage_timeseries_interval"
+ name: _APP_USAGE_TIMESERIES_INTERVAL
+ label: General | _APP_USAGE_TIMESERIES_INTERVAL
+ defaultValue: "30"
+ description:
+ Interval value containing the number of seconds that the Appwrite
+ usage process should wait before aggregating stats and syncing it to mariadb
+ from InfluxDB. The default value is 30 seconds.
+ - id: "$$config__app_usage_database_interval"
+ name: _APP_USAGE_DATABASE_INTERVAL
+ label: General | _APP_USAGE_DATABASE_INTERVAL
+ defaultValue: "900"
+ description:
+ Interval value containing the number of seconds that the Appwrite
+ usage process should wait before aggregating stats from data in Appwrite Database.
+ The default value is 15 minutes.
+- templateVersion: 1.0.0
+ defaultVersion: latest
+ documentation: https://docs.weblate.org/en/latest/admin/install/docker.html
+ description: "A copylefted libre software web-based continuous localization system."
+ type: weblate
+ name: Weblate
+ labels:
+ - translate
+ - localization
+ services:
+ $$id:
+ name: Weblate
+ depends_on:
+ - $$id-postgresql
+ - $$id-redis
+ image: "weblate/weblate:$$core_version"
+ volumes:
+ - "$$id-data:/app/data"
+ environment:
+ - WEBLATE_SITE_DOMAIN=$$config_weblate_site_domain
+ - WEBLATE_ADMIN_PASSWORD=$$secret_weblate_admin_password
+ - POSTGRES_PASSWORD=$$secret_postgres_password
+ - POSTGRES_USER=$$config_postgres_user
+ - POSTGRES_DATABASE=$$config_postgres_db
+ - POSTGRES_HOST=$$id-postgresql
+ - POSTGRES_PORT=5432
+ - REDIS_HOST=$$id-redis
+ ports:
+ - "8080"
+ $$id-postgresql:
+ name: PostgreSQL
+ depends_on: []
+ image: "postgres:14-alpine"
+ volumes:
+ - "$$id-postgresql-data:/var/lib/postgresql/data"
+ environment:
+ - POSTGRES_USER=$$config_postgres_user
+ - POSTGRES_PASSWORD=$$secret_postgres_password
+ - POSTGRES_DB=$$config_postgres_db
+ ports: []
+ $$id-redis:
+ name: Redis
+ depends_on: []
+ image: "redis:7-alpine"
+ volumes:
+ - "$$id-redis-data:/data"
+ environment: []
+ ports: []
+ variables:
+ - id: $$config_weblate_site_domain
+ name: WEBLATE_SITE_DOMAIN
+ label: Weblate Domain
+ defaultValue: $$generate_domain
+ description: ""
+ - id: $$secret_weblate_admin_password
+ name: WEBLATE_ADMIN_PASSWORD
+ label: Weblate Admin Password
+ defaultValue: $$generate_password
+ description: ""
+ showOnConfiguration: true
+ - id: $$config_postgres_user
+ main: $$id-postgresql
+ name: POSTGRES_USER
+ label: PostgreSQL User
+ defaultValue: $$generate_username
+ description: ""
+ - id: $$secret_postgres_password
+ main: $$id-postgresql
+ name: POSTGRES_PASSWORD
+ label: PostgreSQL Password
+ defaultValue: $$generate_password
+ description: ""
+ showOnConfiguration: true
+ - id: $$config_postgres_db
+ main: $$id-postgresql
+ name: POSTGRES_DB
+ label: PostgreSQL Database
+ defaultValue: weblate
+ description: ""
+- templateVersion: 1.0.0
+ defaultVersion: 2022.12.12-966e9c3c
+ documentation: https://docs.searxng.org/
+ type: searxng
+ name: SearXNG
+ description: "Free internet metasearch engine which aggregates results from more than 70 search services."
+ services:
+ $$id:
+ name: SearXNG
+ depends_on:
+ - $$id-redis
+ image: "searxng/searxng:$$core_version"
+ volumes:
+ - "$$id-searxng:/etc/searxng"
+ environment:
+ - SEARXNG_BASE_URL=$$config_searxng_base_url
+ ports:
+ - "8080"
+ cap_drop:
+ - ALL
+ cap_add:
+ - CHOWN
+ - SETGID
+ - SETUID
+ - DAC_OVERRIDE
+ files:
+ - location: /etc/searxng/settings.yml
+ content: |2-
+
+ # see https://docs.searxng.org/admin/engines/settings.html#use-default-settings
+ use_default_settings: true
+ server:
+ secret_key: $$secret_secret_key
+ limiter: true
+ image_proxy: true
+ ui:
+ static_use_hash: true
+ redis:
+ url: redis://:$$secret_redis_password@$$id-redis:6379/0
+ $$id-redis:
+ name: Redis
+ command: >-
+ redis-server --requirepass $$secret_redis_password --save ""
+ --appendonly "no"
+ depends_on: []
+ image: "redis:7-alpine"
+ volumes:
+ - "$$id-redis-data:/data"
+ environment:
+ - REDIS_PASSWORD=$$secret_redis_password
+ ports: []
+ cap_drop:
+ - ALL
+ cap_add:
+ - SETGID
+ - SETUID
+ - DAC_OVERRIDE
+ variables:
+ - id: $$config_searxng_base_url
+ name: SEARXNG_BASE_URL
+ label: SearXNG Base URL
+ defaultValue: $$generate_fqdn
+ description: ""
+ - id: $$secret_secret_key
+ name: SECRET_KEY
+ label: Secret Key
+ defaultValue: $$generate_hex(64)
+ description: ""
+ - id: $$secret_redis_password
+ name: REDIS_PASSWORD
+ label: Redis Password
+ defaultValue: $$generate_password
+ description: ""
+- templateVersion: 1.0.0
+ defaultVersion: v3.0.0
+ documentation: https://glitchtip.com/documentation
+ type: glitchtip
+ name: GlitchTip
+ description: "Simple, open source error tracking."
+ labels:
+ - sentry
+ - bugsnag
+ services:
+ $$id:
+ name: GlitchTip
+ depends_on:
+ - $$id-postgresql
+ - $$id-redis
+ image: "glitchtip/glitchtip:$$core_version"
+ volumes: []
+ environment:
+ - PORT=$$config_port
+ - GLITCHTIP_DOMAIN=$$config_glitchtip_domain
+ - SECRET_KEY=$$secret_secret_key
+ - DATABASE_URL=$$secret_database_url
+ - REDIS_URL=$$secret_redis_url
+ - DEFAULT_FROM_EMAIL=$$config_default_from_email
+ - EMAIL_URL=$$secret_email_url
+ - EMAIL_HOST=$$config_email_host
+ - EMAIL_PORT=$$config_email_port
+ - EMAIL_HOST_USER=$$config_email_host_user
+ - EMAIL_HOST_PASSWORD=$$secret_email_host_password
+ - EMAIL_USE_TLS=$$config_email_use_tls
+ - EMAIL_USE_SSL=$$config_email_use_ssl
+ - EMAIL_BACKEND=$$config_email_backend
+ - MAILGUN_API_KEY=$$secret_mailgun_api_key
+ - SENDGRID_API_KEY=$$secret_sendgrid_api_key
+ - ENABLE_OPEN_USER_REGISTRATION=$$config_enable_open_user_registration
+ - DJANGO_SUPERUSER_EMAIL=$$config_django_superuser_email
+ - DJANGO_SUPERUSER_PASSWORD=$$secret_django_superuser_password
+ - DJANGO_SUPERUSER_USERNAME=$$config_django_superuser_username
+ - CELERY_WORKER_CONCURRENCY=$$config_celery_worker_concurrency
+ ports:
+ - "8000"
+ $$id-worker:
+ name: Celery Worker
+ command: ./bin/run-celery-with-beat.sh
+ depends_on:
+ - $$id-postgresql
+ - $$id-redis
+ image: "glitchtip/glitchtip:$$core_version"
+ environment:
+ - GLITCHTIP_DOMAIN=$$config_glitchtip_domain
+ - SECRET_KEY=$$secret_secret_key
+ - DATABASE_URL=$$secret_database_url
+ - REDIS_URL=$$secret_redis_url
+ - DEFAULT_FROM_EMAIL=$$config_default_from_email
+ - EMAIL_URL=$$secret_email_url
+ - CELERY_WORKER_CONCURRENCY=$$config_celery_worker_concurrency
+ ports: []
+ $$id-migrate:
+ exclude: true
+ name: Migrate
+ command: ./manage.py migrate
+ depends_on:
+ - $$id-postgresql
+ - $$id-redis
+ image: "glitchtip/glitchtip:$$core_version"
+ environment:
+ - GLITCHTIP_DOMAIN=$$config_glitchtip_domain
+ - SECRET_KEY=$$secret_secret_key
+ - DATABASE_URL=$$secret_database_url
+ - REDIS_URL=$$secret_redis_url
+ - DEFAULT_FROM_EMAIL=$$config_default_from_email
+ - EMAIL_URL=$$secret_email_url
+ ports: []
+ $$id-postgresql:
+ name: PostgreSQL
+ depends_on: []
+ image: "postgres:14-alpine"
+ volumes:
+ - "$$id-postgresql-data:/var/lib/postgresql/data"
+ environment:
+ - POSTGRES_USER=$$config_postgres_user
+ - POSTGRES_PASSWORD=$$secret_postgres_password
+ - POSTGRES_DB=$$config_postgres_db
+ ports: []
+ $$id-redis:
+ name: Redis
+ depends_on: []
+ image: "redis:7-alpine"
+ volumes:
+ - "$$id-postgresql-redis-data:/data"
+ environment: []
+ ports: []
+ variables:
+ - id: $$config_django_superuser_username
+ name: DJANGO_SUPERUSER_USERNAME
+ label: Django Superuser Username
+ defaultValue: $$generate_username
+ description: ""
+ - id: $$secret_django_superuser_password
+ name: DJANGO_SUPERUSER_PASSWORD
+ label: Django Superuser Password
+ defaultValue: $$generate_password
+ description: ""
+ showOnConfiguration: true
+ - id: $$config_port
+ name: PORT
+ label: GlitchTip Port
+ defaultValue: "8000"
+ description: ""
+ - id: $$config_celery_worker_concurrency
+ main: $$id-worker
+ name: CELERY_WORKER_CONCURRENCY
+ label: Celery Worker Concurrency
+ defaultValue: "2"
+ description: ""
+ - id: $$config_glitchtip_domain
+ name: GLITCHTIP_DOMAIN
+ label: GlitchTip Domain
+ defaultValue: $$generate_fqdn
+ description: ""
+ - id: $$secret_email_url
+ name: EMAIL_URL
+ label: SMTP Email URL
+ defaultValue: >-
+ smtp://$$config_email_host_user:$$secret_email_host_password@$$config_email_host:$$config_email_port
+ description: ""
+ - id: $$secret_database_url
+ name: DATABASE_URL
+ label: Database URL for PostgreSQL
+ defaultValue: >-
+ postgresql://$$config_postgres_user:$$secret_postgres_password@$$id-postgresql:5432/$$config_postgres_db
+ description: ""
+ - id: $$secret_redis_url
+ name: REDIS_URL
+ label: Redis URL
+ defaultValue: "redis://$$id-redis:6379/0"
+ description: ""
+ - id: $$config_default_from_email
+ name: DEFAULT_FROM_EMAIL
+ label: Default Email Address
+ defaultValue: noreply@example.com
+ description: ""
+ - id: $$config_email_host
+ name: EMAIL_HOST
+ label: Email SMTP Host
+ defaultValue: ""
+ description: ""
+ - id: $$config_email_port
+ name: EMAIL_PORT
+ label: Email SMTP Port
+ defaultValue: "25"
+ description: ""
+ - id: $$config_email_host_user
+ name: EMAIL_HOST_USER
+ label: Email SMTP User
+ defaultValue: ""
+ description: ""
+ - id: $$secret_email_host_password
+ name: EMAIL_HOST_PASSWORD
+ label: Email SMTP Password
+ defaultValue: ""
+ description: ""
+ - id: $$config_email_use_tls
+ name: EMAIL_USE_TLS
+ label: Email Use TLS
+ defaultValue: "false"
+ description: ""
+ - id: $$config_email_use_ssl
+ name: EMAIL_USE_SSL
+ label: Email Use SSL
+ defaultValue: "false"
+ description: ""
+ - id: $$secret_email_smtp_password
+ name: EMAIL_SMTP_PASSWORD
+ label: SMTP Password
+ defaultValue: ""
+ description: ""
+ - id: $$config_email_backend
+ name: EMAIL_BACKEND
+ label: Email Backend
+ defaultValue: ""
+ description: ""
+ - id: $$secret_mailgun_api_key
+ name: MAILGUN_API_KEY
+ label: Mailgun API Key
+ defaultValue: ""
+ description: ""
+ showOnConfiguration: true
+ - id: $$secret_sendgrid_api_key
+ name: SENDGRID_API_KEY
+ label: Sendgrid API Key
+ defaultValue: ""
+ description: ""
+ showOnConfiguration: true
+ - id: $$config_enable_open_user_registration
+ name: ENABLE_OPEN_USER_REGISTRATION
+ label: Enable Open User Registration
+ defaultValue: "true"
+ description: ""
+ - id: $$config_django_superuser_email
+ name: DJANGO_SUPERUSER_EMAIL
+ label: Django Superuser Email
+ defaultValue: noreply@example.com
+ description: ""
+ - id: $$config_postgres_user
+ main: $$id-postgresql
+ name: POSTGRES_USER
+ label: PostgreSQL User
+ defaultValue: $$generate_username
+ description: ""
+ - id: $$secret_postgres_password
+ main: $$id-postgresql
+ name: POSTGRES_PASSWORD
+ label: PostgreSQL Password
+ defaultValue: $$generate_password
+ description: ""
+ - id: $$config_postgres_db
+ main: $$id-postgresql
+ name: POSTGRES_DB
+ label: PostgreSQL Database
+ defaultValue: glitchtip
+ description: ""
+- templateVersion: 1.0.0
+ defaultVersion: v2.16.0
+ documentation: https://hasura.io/docs/latest/index/
+ type: hasura
+ name: Hasura
+ description: "Instant realtime GraphQL APIs on any Postgres application, existing or new."
+ labels:
+ - graphql
+ - database
+ services:
+ $$id:
+ name: Hasura
+ depends_on:
+ - $$id-postgresql
+ image: "hasura/graphql-engine:$$core_version"
+ volumes: []
+ environment:
+ - HASURA_GRAPHQL_ENABLE_CONSOLE=$$config_hasura_graphql_enable_console
+ - >-
+ HASURA_GRAPHQL_METADATA_DATABASE_URL=$$secret_hasura_graphql_metadata_database_url
+ - HASURA_GRAPHQL_ADMIN_SECRET=$$secret_hasura_graphql_admin_secret
+ ports:
+ - "8080"
+ $$id-postgresql:
+ name: PostgreSQL
+ depends_on: []
+ image: "postgres:12-alpine"
+ volumes:
+ - "$$id-postgresql-data:/var/lib/postgresql/data"
+ environment:
+ - POSTGRES_USER=$$config_postgres_user
+ - POSTGRES_PASSWORD=$$secret_postgres_password
+ - POSTGRES_DB=$$config_postgres_db
+ ports: []
+ variables:
+ - id: $$config_hasura_graphql_enable_console
+ name: HASURA_GRAPHQL_ENABLE_CONSOLE
+ label: Enable Hasura Console
+ defaultValue: "true"
+ description: ""
+ - id: $$secret_hasura_graphql_metadata_database_url
+ name: HASURA_GRAPHQL_METADATA_DATABASE_URL
+ label: Hasura Metadata Database URL
+ defaultValue: >-
+ postgresql://$$config_postgres_user:$$secret_postgres_password@$$id-postgresql:5432/$$config_postgres_db
+ description: ""
+ - id: $$secret_hasura_graphql_admin_secret
+ name: HASURA_GRAPHQL_ADMIN_SECRET
+ label: Hasura Admin Password
+ defaultValue: $$generate_password
+ description: ""
+ showOnConfiguration: true
+ - id: $$config_postgres_user
+ name: POSTGRES_USER
+ label: PostgreSQL User
+ defaultValue: $$generate_username
+ description: ""
+ - id: $$secret_postgres_password
+ name: POSTGRES_PASSWORD
+ label: PostgreSQL Password
+ defaultValue: $$generate_password
+ description: ""
+ - id: $$config_postgres_db
+ name: POSTGRES_DB
+ label: PostgreSQL Database
+ defaultValue: hasura
+ description: ""
+- templateVersion: 1.0.0
+ defaultVersion: postgresql-v1.39.5
+ documentation: https://umami.is/docs/getting-started
+ type: umami-postgresql
+ name: Umami
+ subname: (PostgreSQL)
+ description: >-
+ A simple, easy to use, self-hosted web analytics solution.
+ services:
+ $$id:
+ name: Umami
+ depends_on:
+ - $$id-postgresql
+ image: "ghcr.io/umami-software/umami:$$core_version"
+ volumes: []
+ environment:
+ - ADMIN_PASSWORD=$$secret_admin_password
+ - DATABASE_URL=$$secret_database_url
+ - DATABASE_TYPE=$$config_database_type
+ - HASH_SALT=$$secret_hash_salt
+ ports:
+ - "3000"
+ $$id-postgresql:
+ name: PostgreSQL
+ depends_on: []
+ image: "postgres:12-alpine"
+ volumes:
+ - "$$id-postgresql-data:/var/lib/postgresql/data"
+ environment:
+ - POSTGRES_USER=$$config_postgres_user
+ - POSTGRES_PASSWORD=$$secret_postgres_password
+ - POSTGRES_DB=$$config_postgres_db
+ ports: []
+ files:
+ - location: /docker-entrypoint-initdb.d/schema.postgresql.sql
+ content: |2-
+
+ -- CreateTable
+ CREATE TABLE "account" (
+ "user_id" SERIAL NOT NULL,
+ "username" VARCHAR(255) NOT NULL,
+ "password" VARCHAR(60) NOT NULL,
+ "is_admin" BOOLEAN NOT NULL DEFAULT false,
+ "created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,
+ "updated_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,
+
+ PRIMARY KEY ("user_id")
+ );
+
+ -- CreateTable
+ CREATE TABLE "event" (
+ "event_id" SERIAL NOT NULL,
+ "website_id" INTEGER NOT NULL,
+ "session_id" INTEGER NOT NULL,
+ "created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,
+ "url" VARCHAR(500) NOT NULL,
+ "event_type" VARCHAR(50) NOT NULL,
+ "event_value" VARCHAR(50) NOT NULL,
+
+ PRIMARY KEY ("event_id")
+ );
+
+ -- CreateTable
+ CREATE TABLE "pageview" (
+ "view_id" SERIAL NOT NULL,
+ "website_id" INTEGER NOT NULL,
+ "session_id" INTEGER NOT NULL,
+ "created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,
+ "url" VARCHAR(500) NOT NULL,
+ "referrer" VARCHAR(500),
+
+ PRIMARY KEY ("view_id")
+ );
+
+ -- CreateTable
+ CREATE TABLE "session" (
+ "session_id" SERIAL NOT NULL,
+ "session_uuid" UUID NOT NULL,
+ "website_id" INTEGER NOT NULL,
+ "created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,
+ "hostname" VARCHAR(100),
+ "browser" VARCHAR(20),
+ "os" VARCHAR(20),
+ "device" VARCHAR(20),
+ "screen" VARCHAR(11),
+ "language" VARCHAR(35),
+ "country" CHAR(2),
+
+ PRIMARY KEY ("session_id")
+ );
+
+ -- CreateTable
+ CREATE TABLE "website" (
+ "website_id" SERIAL NOT NULL,
+ "website_uuid" UUID NOT NULL,
+ "user_id" INTEGER NOT NULL,
+ "name" VARCHAR(100) NOT NULL,
+ "domain" VARCHAR(500),
+ "share_id" VARCHAR(64),
+ "created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,
+
+ PRIMARY KEY ("website_id")
+ );
+
+ -- CreateIndex
+ CREATE UNIQUE INDEX "account.username_unique" ON "account"("username");
+
+ -- CreateIndex
+ CREATE INDEX "event_created_at_idx" ON "event"("created_at");
+
+ -- CreateIndex
+ CREATE INDEX "event_session_id_idx" ON "event"("session_id");
+
+ -- CreateIndex
+ CREATE INDEX "event_website_id_idx" ON "event"("website_id");
+
+ -- CreateIndex
+ CREATE INDEX "pageview_created_at_idx" ON "pageview"("created_at");
+
+ -- CreateIndex
+ CREATE INDEX "pageview_session_id_idx" ON "pageview"("session_id");
+
+ -- CreateIndex
+ CREATE INDEX "pageview_website_id_created_at_idx" ON "pageview"("website_id", "created_at");
+
+ -- CreateIndex
+ CREATE INDEX "pageview_website_id_idx" ON "pageview"("website_id");
+
+ -- CreateIndex
+ CREATE INDEX "pageview_website_id_session_id_created_at_idx" ON "pageview"("website_id", "session_id", "created_at");
+
+ -- CreateIndex
+ CREATE UNIQUE INDEX "session.session_uuid_unique" ON "session"("session_uuid");
+
+ -- CreateIndex
+ CREATE INDEX "session_created_at_idx" ON "session"("created_at");
+
+ -- CreateIndex
+ CREATE INDEX "session_website_id_idx" ON "session"("website_id");
+
+ -- CreateIndex
+ CREATE UNIQUE INDEX "website.website_uuid_unique" ON "website"("website_uuid");
+
+ -- CreateIndex
+ CREATE UNIQUE INDEX "website.share_id_unique" ON "website"("share_id");
+
+ -- CreateIndex
+ CREATE INDEX "website_user_id_idx" ON "website"("user_id");
+
+ -- AddForeignKey
+ ALTER TABLE "event" ADD FOREIGN KEY ("session_id") REFERENCES "session"("session_id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+ -- AddForeignKey
+ ALTER TABLE "event" ADD FOREIGN KEY ("website_id") REFERENCES "website"("website_id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+ -- AddForeignKey
+ ALTER TABLE "pageview" ADD FOREIGN KEY ("session_id") REFERENCES "session"("session_id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+ -- AddForeignKey
+ ALTER TABLE "pageview" ADD FOREIGN KEY ("website_id") REFERENCES "website"("website_id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+ -- AddForeignKey
+ ALTER TABLE "session" ADD FOREIGN KEY ("website_id") REFERENCES "website"("website_id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+ -- AddForeignKey
+ ALTER TABLE "website" ADD FOREIGN KEY ("user_id") REFERENCES "account"("user_id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+ insert into account (username, password, is_admin) values ('admin', '$$hashed$$secret_admin_password', true);
+ variables:
+ - id: $$secret_database_url
+ name: DATABASE_URL
+ label: Database URL for PostgreSQL
+ defaultValue: >-
+ postgresql://$$config_postgres_user:$$secret_postgres_password@$$id-postgresql:5432/$$config_postgres_db
+ description: ""
+ - id: $$secret_hash_salt
+ name: HASH_SALT
+ label: Hash Salt
+ defaultValue: $$generate_hex(64)
+ description: ""
+ - id: $$config_database_type
+ name: DATABASE_TYPE
+ label: Database Type
+ defaultValue: "postgresql"
+ description: ""
+ - id: $$config_postgres_user
+ name: POSTGRES_USER
+ label: PostgreSQL User
+ defaultValue: $$generate_username
+ description: ""
+ - id: $$secret_postgres_password
+ name: POSTGRES_PASSWORD
+ label: PostgreSQL Password
+ defaultValue: $$generate_password
+ description: ""
+ - id: $$config_postgres_db
+ name: POSTGRES_DB
+ label: PostgreSQL Database
+ defaultValue: umami
+ description: ""
+ - id: $$secret_admin_password
+ name: ADMIN_PASSWORD
+ label: Initial Admin Password
+ defaultValue: $$generate_password
+ description: ""
+ showOnConfiguration: true
+- templateVersion: 1.0.0
+ ignore: true
+ defaultVersion: postgresql-v1.39.5
+ documentation: https://umami.is/docs/getting-started
+ type: umami
+ name: Umami
+ subname: (PostgreSQL)
+ description: >-
+ A simple, easy to use, self-hosted web analytics solution.
+ services:
+ $$id:
+ name: Umami
+ depends_on:
+ - $$id-postgresql
+ image: "ghcr.io/umami-software/umami:$$core_version"
+ volumes: []
+ environment:
+ - ADMIN_PASSWORD=$$secret_admin_password
+ - DATABASE_URL=$$secret_database_url
+ - DATABASE_TYPE=$$config_database_type
+ - HASH_SALT=$$secret_hash_salt
+ ports:
+ - "3000"
+ $$id-postgresql:
+ name: PostgreSQL
+ depends_on: []
+ image: "postgres:12-alpine"
+ volumes:
+ - "$$id-postgresql-data:/var/lib/postgresql/data"
+ environment:
+ - POSTGRES_USER=$$config_postgres_user
+ - POSTGRES_PASSWORD=$$secret_postgres_password
+ - POSTGRES_DB=$$config_postgres_db
+ ports: []
+ files:
+ - location: /docker-entrypoint-initdb.d/schema.postgresql.sql
+ content: |2-
+
+ -- CreateTable
+ CREATE TABLE "account" (
+ "user_id" SERIAL NOT NULL,
+ "username" VARCHAR(255) NOT NULL,
+ "password" VARCHAR(60) NOT NULL,
+ "is_admin" BOOLEAN NOT NULL DEFAULT false,
+ "created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,
+ "updated_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,
+
+ PRIMARY KEY ("user_id")
+ );
+
+ -- CreateTable
+ CREATE TABLE "event" (
+ "event_id" SERIAL NOT NULL,
+ "website_id" INTEGER NOT NULL,
+ "session_id" INTEGER NOT NULL,
+ "created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,
+ "url" VARCHAR(500) NOT NULL,
+ "event_type" VARCHAR(50) NOT NULL,
+ "event_value" VARCHAR(50) NOT NULL,
+
+ PRIMARY KEY ("event_id")
+ );
+
+ -- CreateTable
+ CREATE TABLE "pageview" (
+ "view_id" SERIAL NOT NULL,
+ "website_id" INTEGER NOT NULL,
+ "session_id" INTEGER NOT NULL,
+ "created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,
+ "url" VARCHAR(500) NOT NULL,
+ "referrer" VARCHAR(500),
+
+ PRIMARY KEY ("view_id")
+ );
+
+ -- CreateTable
+ CREATE TABLE "session" (
+ "session_id" SERIAL NOT NULL,
+ "session_uuid" UUID NOT NULL,
+ "website_id" INTEGER NOT NULL,
+ "created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,
+ "hostname" VARCHAR(100),
+ "browser" VARCHAR(20),
+ "os" VARCHAR(20),
+ "device" VARCHAR(20),
+ "screen" VARCHAR(11),
+ "language" VARCHAR(35),
+ "country" CHAR(2),
+
+ PRIMARY KEY ("session_id")
+ );
+
+ -- CreateTable
+ CREATE TABLE "website" (
+ "website_id" SERIAL NOT NULL,
+ "website_uuid" UUID NOT NULL,
+ "user_id" INTEGER NOT NULL,
+ "name" VARCHAR(100) NOT NULL,
+ "domain" VARCHAR(500),
+ "share_id" VARCHAR(64),
+ "created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,
+
+ PRIMARY KEY ("website_id")
+ );
+
+ -- CreateIndex
+ CREATE UNIQUE INDEX "account.username_unique" ON "account"("username");
+
+ -- CreateIndex
+ CREATE INDEX "event_created_at_idx" ON "event"("created_at");
+
+ -- CreateIndex
+ CREATE INDEX "event_session_id_idx" ON "event"("session_id");
+
+ -- CreateIndex
+ CREATE INDEX "event_website_id_idx" ON "event"("website_id");
+
+ -- CreateIndex
+ CREATE INDEX "pageview_created_at_idx" ON "pageview"("created_at");
+
+ -- CreateIndex
+ CREATE INDEX "pageview_session_id_idx" ON "pageview"("session_id");
+
+ -- CreateIndex
+ CREATE INDEX "pageview_website_id_created_at_idx" ON "pageview"("website_id", "created_at");
+
+ -- CreateIndex
+ CREATE INDEX "pageview_website_id_idx" ON "pageview"("website_id");
+
+ -- CreateIndex
+ CREATE INDEX "pageview_website_id_session_id_created_at_idx" ON "pageview"("website_id", "session_id", "created_at");
+
+ -- CreateIndex
+ CREATE UNIQUE INDEX "session.session_uuid_unique" ON "session"("session_uuid");
+
+ -- CreateIndex
+ CREATE INDEX "session_created_at_idx" ON "session"("created_at");
+
+ -- CreateIndex
+ CREATE INDEX "session_website_id_idx" ON "session"("website_id");
+
+ -- CreateIndex
+ CREATE UNIQUE INDEX "website.website_uuid_unique" ON "website"("website_uuid");
+
+ -- CreateIndex
+ CREATE UNIQUE INDEX "website.share_id_unique" ON "website"("share_id");
+
+ -- CreateIndex
+ CREATE INDEX "website_user_id_idx" ON "website"("user_id");
+
+ -- AddForeignKey
+ ALTER TABLE "event" ADD FOREIGN KEY ("session_id") REFERENCES "session"("session_id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+ -- AddForeignKey
+ ALTER TABLE "event" ADD FOREIGN KEY ("website_id") REFERENCES "website"("website_id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+ -- AddForeignKey
+ ALTER TABLE "pageview" ADD FOREIGN KEY ("session_id") REFERENCES "session"("session_id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+ -- AddForeignKey
+ ALTER TABLE "pageview" ADD FOREIGN KEY ("website_id") REFERENCES "website"("website_id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+ -- AddForeignKey
+ ALTER TABLE "session" ADD FOREIGN KEY ("website_id") REFERENCES "website"("website_id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+ -- AddForeignKey
+ ALTER TABLE "website" ADD FOREIGN KEY ("user_id") REFERENCES "account"("user_id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+ insert into account (username, password, is_admin) values ('admin', '$$hashed$$secret_admin_password', true);
+ variables:
+ - id: $$secret_database_url
+ name: DATABASE_URL
+ label: Database URL for PostgreSQL
+ defaultValue: >-
+ postgresql://$$config_postgres_user:$$secret_postgres_password@$$id-postgresql:5432/$$config_postgres_db
+ description: ""
+ - id: $$secret_hash_salt
+ name: HASH_SALT
+ label: Hash Salt
+ defaultValue: $$generate_hex(64)
+ description: ""
+ - id: $$config_database_type
+ name: DATABASE_TYPE
+ label: Database Type
+ defaultValue: "postgresql"
+ description: ""
+ - id: $$config_postgres_user
+ name: POSTGRES_USER
+ label: PostgreSQL User
+ defaultValue: $$generate_username
+ description: ""
+ - id: $$secret_postgres_password
+ name: POSTGRES_PASSWORD
+ label: PostgreSQL Password
+ defaultValue: $$generate_password
+ description: ""
+ - id: $$config_postgres_db
+ name: POSTGRES_DB
+ label: PostgreSQL Database
+ defaultValue: umami
+ description: ""
+ - id: $$secret_admin_password
+ name: ADMIN_PASSWORD
+ label: Initial Admin Password
+ defaultValue: $$generate_password
+ description: ""
+ showOnConfiguration: true
+- templateVersion: 1.0.0
+ defaultVersion: v0.30.1
+ documentation: https://docs.meilisearch.com/learn/getting_started/quick_start.html
+ type: meilisearch
+ name: MeiliSearch
+ description: >-
+ A lightning Fast, Ultra Relevant, and Typo-Tolerant Search Engine.
+ services:
+ $$id:
+ name: MeiliSearch
+ documentation: https://docs.meilisearch.com/
+ depends_on: []
+ image: "getmeili/meilisearch:$$core_version"
+ volumes:
+ - "$$id-datams:/meili_data/data.ms"
+ - "$$id-data:/meili_data"
+ - "$$id-snapshot:/snapshot"
+ - "$$id-dump:/dumps"
+ environment:
+ - MEILI_MASTER_KEY=$$secret_meili_master_key
+ ports:
+ - "7700"
+ variables:
+ - id: $$secret_meili_master_key
+ name: MEILI_MASTER_KEY
+ label: Master Key
+ defaultValue: $$generate_hex(64)
+ description: ""
+ showOnConfiguration: true
+- templateVersion: 1.0.0
+ ignore: true
+ defaultVersion: latest
+ documentation: https://docs.ghost.org
+ arch: amd64
+ type: ghost-mariadb
+ name: Ghost
+ subname: (MariaDB)
+ description: >-
+ Free and open source blogging platform.
+ labels:
+ - cms
+ - blog
+ services:
+ $$id:
+ name: Ghost
+ depends_on:
+ - $$id-mariadb
+ image: "bitnami/ghost:$$core_version"
+ volumes:
+ - "$$id-ghost:/bitnami/ghost"
+ environment:
+ - url=$$config_url
+ - GHOST_HOST=$$config_ghost_host
+ - GHOST_ENABLE_HTTPS=$$config_ghost_enable_https
+ - GHOST_EMAIL=$$config_ghost_email
+ - GHOST_PASSWORD=$$secret_ghost_password
+ - GHOST_DATABASE_HOST=$$config_ghost_database_host
+ - GHOST_DATABASE_USER=$$config_mariadb_user
+ - GHOST_DATABASE_PASSWORD=$$secret_ghost_database_password
+ - GHOST_DATABASE_NAME=$$config_mariadb_database
+ - GHOST_DATABASE_PORT_NUMBER=3306
+ ports:
+ - "2368"
+ $$id-mariadb:
+ name: MariaDB
+ depends_on: []
+ image: "bitnami/mariadb:latest"
+ volumes:
+ - "$$id-mariadb:/bitnami/mariadb"
+ environment:
+ - MARIADB_USER=$$config_mariadb_user
+ - MARIADB_PASSWORD=$$secret_mariadb_password
+ - MARIADB_DATABASE=$$config_mariadb_database
+ - MARIADB_ROOT_USER=$$config_mariadb_root_user
+ - MARIADB_ROOT_PASSWORD=$$secret_mariadb_root_password
+ ports: []
+ variables:
+ - id: $$config_url
+ name: url
+ label: URL
+ defaultValue: $$generate_fqdn
+ description: ""
+ - id: $$config_ghost_host
+ name: GHOST_HOST
+ label: Ghost Host
+ defaultValue: $$generate_domain
+ description: ""
+ - id: $$config_ghost_enable_https
+ name: GHOST_ENABLE_HTTPS
+ label: Ghost Enable HTTPS
+ defaultValue: "no"
+ description: ""
+ - id: $$config_ghost_email
+ name: GHOST_EMAIL
+ label: Ghost Default Email
+ defaultValue: admin@example.com
+ description: ""
+ - id: $$secret_ghost_password
+ name: GHOST_PASSWORD
+ label: Ghost Default Password
+ defaultValue: $$generate_password
+ description: ""
+ showOnConfiguration: true
+ - id: $$config_ghost_database_host
+ name: GHOST_DATABASE_HOST
+ label: Ghost Database Host
+ defaultValue: $$id-mariadb
+ description: ""
+ - id: $$config_ghost_database_user
+ name: GHOST_DATABASE_USER
+ label: MariaDB User
+ defaultValue: $$config_mariadb_user
+ description: ""
+ - id: $$secret_ghost_database_password
+ name: GHOST_DATABASE_PASSWORD
+ label: MariaDB Password
+ defaultValue: $$secret_mariadb_password
+ description: ""
+ - id: $$config_ghost_database_name
+ name: GHOST_DATABASE_NAME
+ label: MariaDB Database
+ defaultValue: $$config_mariadb_database
+ description: ""
+ - id: $$config_mariadb_user
+ name: MARIADB_USER
+ label: MariaDB User
+ defaultValue: $$generate_username
+ description: ""
+ - id: $$secret_mariadb_password
+ name: MARIADB_PASSWORD
+ label: MariaDB Password
+ defaultValue: $$generate_password
+ description: ""
+ - id: $$config_mariadb_database
+ name: MARIADB_DATABASE
+ label: MariaDB Database
+ defaultValue: ghost
+ description: ""
+ - id: $$config_mariadb_root_user
+ name: MARIADB_ROOT_USER
+ label: MariaDB Root User
+ defaultValue: $$generate_username
+ description: ""
+ - id: $$secret_mariadb_root_password
+ name: MARIADB_ROOT_PASSWORD
+ label: MariaDB Root Password
+ defaultValue: $$generate_password
+ description: ""
+- templateVersion: 1.0.0
+ defaultVersion: "5.25.3"
+ documentation: https://docs.ghost.org
+ type: ghost-only
+ name: Ghost
+ subname: (without Database)
+ description: >-
+ Free and open source blogging platform.
+ services:
+ $$id:
+ name: Ghost
+ image: "ghost:$$core_version"
+ volumes:
+ - "$$id-ghost:/var/lib/ghost/content"
+ environment:
+ - url=$$config_url
+ - database__client=$$config_database__client
+ - database__connection__host=$$config_database__connection__host
+ - database__connection__user=$$config_database__connection__user
+ - database__connection__password=$$secret_database__connection__password
+ - database__connection__database=$$config_database__connection__database
+ ports:
+ - "2368"
+ variables:
+ - id: $$config_url
+ name: url
+ label: URL
+ defaultValue: $$generate_fqdn
+ description: ""
+ - id: $$config_database__client
+ name: database__client
+ label: Database Client
+ defaultValue: mysql
+ description: ""
+ required: true
+ - id: $$config_database__connection__host
+ name: database__connection__host
+ label: Database Host
+ defaultValue: ""
+ description: ""
+ required: true
+ placeholder: "db.coolify.io"
+ - id: $$config_database__connection__user
+ name: database__connection__user
+ label: Database User
+ defaultValue: ""
+ description: ""
+ placeholder: "ghost"
+ required: true
+ - id: $$secret_database__connection__password
+ name: database__connection__password
+ label: Database Password
+ defaultValue: ""
+ description: ""
+ placeholder: "superSecretP4ssword"
+ showOnConfiguration: true
+ required: true
+ - id: $$config_database__connection__database
+ name: database__connection__database
+ label: Database Name
+ defaultValue: ""
+ description: ""
+ placeholder: "ghost_db"
+ required: true
+- templateVersion: 1.0.0
+ defaultVersion: "5.25.3"
+ documentation: https://docs.ghost.org
+ type: ghost-mysql
+ name: Ghost
+ subname: (MySQL)
+ description: >-
+ Ghost is a free and open source blogging platform.
+ services:
+ $$id:
+ name: Ghost
+ depends_on:
+ - $$id-mysql
+ image: "ghost:$$core_version"
+ volumes:
+ - "$$id-ghost:/var/lib/ghost/content"
+ environment:
+ - url=$$config_url
+ - database__client=$$config_database__client
+ - database__connection__host=$$config_database__connection__host
+ - database__connection__user=$$config_mysql_user
+ - database__connection__password=$$secret_mysql_password
+ - database__connection__database=$$config_mysql_database
+ ports:
+ - "2368"
+ $$id-mysql:
+ name: MySQL
+ depends_on: []
+ image: "mysql:8.0"
+ volumes:
+ - "$$id-mysql:/var/lib/mysql"
+ environment:
+ - MYSQL_USER=$$config_mysql_user
+ - MYSQL_PASSWORD=$$secret_mysql_password
+ - MYSQL_DATABASE=$$config_mysql_database
+ - MYSQL_ROOT_PASSWORD=$$secret_mysql_root_password
+ ports: []
+ variables:
+ - id: $$config_url
+ name: url
+ label: URL
+ defaultValue: $$generate_fqdn
+ description: ""
+ - id: $$config_database__client
+ name: database__client
+ label: Database Client
+ defaultValue: mysql
+ description: ""
+ readOnly: true
+ - id: $$config_database__connection__host
+ name: database__connection__host
+ label: Database Host
+ defaultValue: $$id-mysql
+ description: ""
+ - id: $$config_mysql_user
+ main: $$id-mysql
+ name: MYSQL_USER
+ label: MySQL User
+ defaultValue: $$generate_username
+ description: ""
+ - id: $$secret_mysql_password
+ main: $$id-mysql
+ name: MYSQL_PASSWORD
+ label: MySQL Password
+ defaultValue: $$generate_password
+ description: ""
+ - id: $$config_mysql_database
+ main: $$id-mysql
+ name: MYSQL_DATABASE
+ label: MySQL Database
+ defaultValue: ghost
+ description: ""
+ - id: $$secret_mysql_root_password
+ name: MYSQL_ROOT_PASSWORD
+ label: MySQL Root Password
+ defaultValue: $$generate_password
+ description: ""
+- templateVersion: 1.0.0
+ defaultVersion: php8.1
+ documentation: https://wordpress.org/
+ type: wordpress
+ name: WordPress
+ subname: (MySQL)
+ description: A content management system based on PHP.
+ labels:
+ - "wordpress"
+ - "php"
+ - "cms"
+ services:
+ $$id:
+ name: WordPress
+ depends_on:
+ - $$id-mysql
+ image: "wordpress:$$core_version"
+ volumes:
+ - "$$id-wordpress-data:/var/www/html"
+ environment:
+ - WORDPRESS_DB_HOST=$$config_wordpress_db_host
+ - WORDPRESS_DB_USER=$$config_mysql_user
+ - WORDPRESS_DB_PASSWORD=$$secret_mysql_password
+ - WORDPRESS_DB_NAME=$$config_mysql_database
+ - WORDPRESS_CONFIG_EXTRA=$$config_wordpress_config_extra
+ ports:
+ - "80"
+ $$id-mysql:
+ name: MySQL
+ depends_on: []
+ image: "bitnami/mysql:5.7"
+ imageArm: "mysql:8.0"
+ volumes:
+ - "$$id-mysql-data:/bitnami/mysql/data"
+ volumesArm:
+ - "$$id-mysql-data:/var/lib/mysql"
+ environment:
+ - MYSQL_ROOT_PASSWORD=$$secret_mysql_root_password
+ - MYSQL_ROOT_USER=$$config_mysql_root_user
+ - MYSQL_DATABASE=$$config_mysql_database
+ - MYSQL_USER=$$config_mysql_user
+ - MYSQL_PASSWORD=$$secret_mysql_password
+ variables:
+ - id: $$config_wordpress_db_host
+ name: WORDPRESS_DB_HOST
+ label: Database Host
+ defaultValue: $$id-mysql
+ description: ""
+ readOnly: true
+ - id: $$config_wordpress_config_extra
+ name: WORDPRESS_CONFIG_EXTRA
+ label: WordPress Config Extra
+ defaultValue: ""
+ description: ""
+ type: "textarea"
+ placeholder: |
+ define('WP_DEBUG', true);
+ define('WP_DEBUG_LOG', true);
+ define('WP_DEBUG_DISPLAY', false);
+ @ini_set('display_errors', 0);
+ - id: $$secret_mysql_root_password
+ name: MYSQL_ROOT_PASSWORD
+ label: MySQL Root Password
+ defaultValue: $$generate_password
+ description: ""
+ readOnly: true
+ - id: $$config_mysql_root_user
+ name: MYSQL_ROOT_USER
+ label: MySQL Root User
+ defaultValue: $$generate_username
+ description: ""
+ readOnly: true
+ - id: $$config_mysql_database
+ name: MYSQL_DATABASE
+ label: MySQL Database
+ defaultValue: wordpress
+ description: ""
+ readOnly: true
+ - id: $$config_mysql_user
+ name: MYSQL_USER
+ label: MySQL User
+ defaultValue: $$generate_username
+ description: ""
+ readOnly: true
+ - id: $$secret_mysql_password
+ name: MYSQL_PASSWORD
+ label: MySQL Password
+ defaultValue: $$generate_password
+ description: ""
+ readOnly: true
+- templateVersion: 1.0.0
+ defaultVersion: php8.1
+ documentation: https://wordpress.org/
+ type: wordpress-only
+ name: WordPress
+ subname: (without DB)
+ description: A content management system based on PHP.
+ labels:
+ - "wordpress"
+ - "php"
+ - "cms"
+ services:
+ $$id:
+ name: WordPress
+ image: "wordpress:$$core_version"
+ volumes:
+ - "$$id-wordpress-data:/var/www/html"
+ environment:
+ - WORDPRESS_DB_HOST=$$config_wordpress_db_host
+ - WORDPRESS_DB_PORT=$$config_wordpress_db_port
+ - WORDPRESS_DB_USER=$$config_wordpress_db_user
+ - WORDPRESS_DB_PASSWORD=$$secret_wordpress_db_password
+ - WORDPRESS_DB_NAME=$$config_wordpress_db_name
+ - WORDPRESS_CONFIG_EXTRA=$$config_wordpress_config_extra
+ ports:
+ - "80"
+ variables:
+ - id: $$config_wordpress_db_host
+ name: WORDPRESS_DB_HOST
+ label: Database Host
+ defaultValue: ""
+ description: ""
+ placeholder: "db.coollabs.io"
+ required: true
+ - id: $$config_wordpress_db_port
+ name: WORDPRESS_DB_PORT
+ label: Database Port
+ defaultValue: ""
+ description: ""
+ placeholder: "3306"
+ required: true
+ - id: $$config_wordpress_db_user
+ name: WORDPRESS_DB_USER
+ label: Database User
+ defaultValue: ""
+ description: ""
+ placeholder: "wordpress"
+ required: true
+ - id: $$secret_wordpress_db_password
+ name: WORDPRESS_DB_PASSWORD
+ label: Database Password
+ defaultValue: ""
+ description: ""
+ placeholder: "supers3cr3tpassw0rd!"
+ required: true
+ showOnConfiguration: true
+ - id: $$config_wordpress_db_name
+ name: WORDPRESS_DB_NAME
+ label: Database Name
+ defaultValue: ""
+ description: ""
+ placeholder: "wordpress"
+ required: true
+ - id: $$config_wordpress_config_extra
+ name: WORDPRESS_CONFIG_EXTRA
+ label: Extra Config
+ defaultValue: ""
+ description: ""
+ type: "textarea"
+ placeholder: |
+ define('WP_DEBUG', true);
+ define('WP_DEBUG_LOG', true);
+ define('WP_DEBUG_DISPLAY', false);
+ @ini_set('display_errors', 0);
+- templateVersion: 1.0.0
+ defaultVersion: 4.9.0
+ documentation: https://coder.com/docs/coder-oss/latest
+ type: vscodeserver
+ name: VSCode Server
+ description: >-
+ Visual Studio Code on a remote server, accessible through the browser.
+ labels:
+ - vscode
+ - ide
+ services:
+ $$id:
+ name: VSCode Server
+ depends_on: []
+ image: "codercom/code-server:$$core_version"
+ volumes:
+ - "$$id-config-data:/home/coder/.local/share/code-server"
+ - "$$id-vscodeserver-data:/home/coder"
+ - "$$id-keys-directory:/root/.ssh"
+ - "$$id-theme-and-plugin-directory:/root/.local/share/code-server"
+ environment:
+ - PASSWORD=$$secret_password
+ ports:
+ - "8080"
+ variables:
+ - id: $$secret_password
+ name: PASSWORD
+ label: Password
+ defaultValue: $$generate_password
+ description: ""
+ showOnConfiguration: true
+- templateVersion: 1.0.0
+ defaultVersion: RELEASE.2022-12-12T19-27-27Z
+ documentation: https://min.io/docs/minio
+ type: minio
+ name: MinIO
+ description: "A cloud storage server compatible with Amazon S3."
+ labels:
+ - storage
+ - s3
+ services:
+ $$id:
+ name: MinIO
+ command: "server /data --console-address :9001"
+ depends_on: []
+ image: "minio/minio:$$core_version"
+ volumes:
+ - "$$id-minio-data:/data"
+ - "$$id-data-write:/files"
+ environment:
+ - MINIO_SERVER_URL=$$config_coolify_fqdn_minio_console
+ - MINIO_BROWSER_REDIRECT_URL=$$config_minio_browser_redirect_url
+ - MINIO_DOMAIN=$$config_minio_domain
+ - MINIO_ROOT_USER=$$config_minio_root_user
+ - MINIO_ROOT_PASSWORD=$$secret_minio_root_password
+ ports:
+ - "9000"
+ - "9001"
+ proxy:
+ - port: "9000"
+ domain: $$config_coolify_fqdn_minio_console
+ - port: "9001"
+ variables:
+ - id: $$config_coolify_fqdn_minio_console
+ name: MINIO_SERVER_URL
+ label: MinIO Server URL
+ defaultValue: ""
+ description: "Specify the URL hostname the MinIO Console should use for connecting to the MinIO Server."
+ required: true
+ - id: $$config_minio_browser_redirect_url
+ name: MINIO_BROWSER_REDIRECT_URL
+ label: Browser Redirect URL
+ defaultValue: $$generate_fqdn
+ description: ""
+ - id: $$config_minio_domain
+ name: MINIO_DOMAIN
+ label: Domain
+ defaultValue: $$generate_domain
+ description: ""
+ - id: $$config_minio_root_user
+ name: MINIO_ROOT_USER
+ label: Root User
+ defaultValue: $$generate_username
+ description: ""
+ - id: $$secret_minio_root_password
+ name: MINIO_ROOT_PASSWORD
+ label: Root User Password
+ defaultValue: $$generate_password
+ description: ""
+ showOnConfiguration: true
+- templateVersion: 1.0.0
+ defaultVersion: 0.21.1
+ documentation: https://fider.io/docs
+ type: fider
+ name: Fider
+ description: A platform to collect and organize customer feedback.
+ labels:
+ - suggestion
+ - feedback
+ services:
+ $$id:
+ name: Fider
+ image: "getfider/fider:$$core_version"
+ depends_on:
+ - $$id-postgresql
+ environment:
+ - BASE_URL=$$config_base_url
+ - DATABASE_URL=$$secret_database_url
+ - JWT_SECRET=$$secret_jwt_secret
+ - EMAIL_NOREPLY=$$config_email_noreply
+ - EMAIL_MAILGUN_API=$$secret_email_mailgun_api
+ - EMAIL_MAILGUN_REGION=$$config_email_mailgun_region
+ - EMAIL_MAILGUN_DOMAIN=$$config_email_mailgun_domain
+ - EMAIL_SMTP_HOST=$$config_email_smtp_host
+ - EMAIL_SMTP_PORT=$$config_email_smtp_port
+ - EMAIL_SMTP_USER=$$config_email_smtp_user
+ - EMAIL_SMTP_PASSWORD=$$secret_email_smtp_password
+ - EMAIL_SMTP_ENABLE_STARTTLS=$$config_email_smtp_enable_starttls
+ ports:
+ - "3000"
+ $$id-postgresql:
+ name: PostgreSQL
+ depends_on: []
+ image: "postgres:12-alpine"
+ volumes:
+ - "$$id-postgresql-data:/var/lib/postgresql/data"
+ environment:
+ - POSTGRES_USER=$$config_postgres_user
+ - POSTGRES_PASSWORD=$$secret_postgres_password
+ - POSTGRES_DB=$$config_postgres_db
+ variables:
+ - id: $$config_base_url
+ name: BASE_URL
+ label: Base URL
+ defaultValue: $$generate_fqdn
+ description: ""
+ - id: $$secret_database_url
+ name: DATABASE_URL
+ label: Database URL for PostgreSQL
+ defaultValue: >-
+ postgresql://$$config_postgres_user:$$secret_postgres_password@$$id-postgresql:5432/$$config_postgres_db?sslmode=disable
+ description: ""
+ - id: $$secret_jwt_secret
+ name: JWT_SECRET
+ label: JWT Secret
+ defaultValue: $$generate_hex(64)
+ description: ""
+ - id: $$config_email_noreply
+ name: EMAIL_NOREPLY
+ label: No Reply Email Address
+ defaultValue: noreply@example.com
+ description: ""
+ - id: $$secret_email_mailgun_api
+ name: EMAIL_MAILGUN_API
+ label: Mailgun API Key
+ defaultValue: ""
+ description: ""
+ showOnConfiguration: true
+ - id: $$config_email_mailgun_region
+ name: EMAIL_MAILGUN_REGION
+ label: Mailgun Region
+ defaultValue: EU
+ description: ""
+ - id: $$config_email_mailgun_domain
+ name: EMAIL_MAILGUN_DOMAIN
+ label: Mailgun Domain
+ defaultValue: ""
+ description: ""
+ - id: $$config_email_smtp_host
+ name: EMAIL_SMTP_HOST
+ label: SMTP Host
+ defaultValue: ""
+ description: ""
+ - id: $$config_email_smtp_port
+ name: EMAIL_SMTP_PORT
+ label: SMTP Port
+ defaultValue: "587"
+ description: ""
+ - id: $$config_email_smtp_user
+ name: EMAIL_SMTP_USER
+ label: SMTP User
+ defaultValue: ""
+ description: ""
+ - id: $$secret_email_smtp_password
+ name: EMAIL_SMTP_PASSWORD
+ label: SMTP Password
+ defaultValue: ""
+ description: ""
+ showOnConfiguration: true
+ - id: $$config_email_smtp_enable_starttls
+ name: EMAIL_SMTP_ENABLE_STARTTLS
+ label: SMTP Enable StartTLS
+ defaultValue: "false"
+ description: ""
+ - id: $$config_postgres_user
+ name: POSTGRES_USER
+ label: PostgreSQL User
+ defaultValue: $$generate_username
+ description: ""
+ - id: $$secret_postgres_password
+ name: POSTGRES_PASSWORD
+ label: PostgreSQL Password
+ defaultValue: $$generate_password
+ description: ""
+ - id: $$config_postgres_db
+ name: POSTGRES_DB
+ label: PostgreSQL Database
+ defaultValue: $$generate_username
+ description: ""
+- templateVersion: 1.0.0
+ defaultVersion: 0.207.0
+ documentation: https://docs.n8n.io
+ type: n8n
+ name: n8n.io
+ description: A free and open node based Workflow Automation Tool.
+ labels:
+ - workflow
+ - automation
+ - ifttt
+ - zapier
+ - nodered
+ services:
+ $$id:
+ name: N8n
+ depends_on: []
+ image: "n8nio/n8n:$$core_version"
+ volumes:
+ - "$$id-data:/root/.n8n"
+ - "$$id-data-write:/files"
+ - "/var/run/docker.sock:/var/run/docker.sock"
+ environment:
+ - WEBHOOK_URL=$$config_webhook_url
+ ports:
+ - "5678"
+ variables:
+ - id: $$config_webhook_url
+ name: WEBHOOK_URL
+ label: Webhook URL
+ defaultValue: $$generate_fqdn
+ description: ""
+- templateVersion: 1.0.0
+ defaultVersion: stable
+ documentation: https://plausible.io/doc/
+ arch: amd64
+ type: plausibleanalytics
+ name: Plausible Analytics
+ description: A lightweight and open-source website analytics tool.
+ labels:
+ - analytics
+ - statistics
+ - plausible
+ - gdpr
+ - no-cookie
+ - google analytics
+ services:
+ $$id:
+ name: Plausible Analytics
+ command: >-
+ sh -c "sleep 10 && /entrypoint.sh db createdb && /entrypoint.sh db
+ migrate && /entrypoint.sh db init-admin && /entrypoint.sh run"
+ depends_on:
+ - $$id-postgresql
+ - $$id-clickhouse
+ image: "plausible/analytics:$$core_version"
+ environment:
+ - ADMIN_USER_EMAIL=$$config_admin_user_email
+ - ADMIN_USER_NAME=$$config_admin_user_name
+ - ADMIN_USER_PWD=$$secret_admin_user_pwd
+ - BASE_URL=$$config_base_url
+ - SECRET_KEY_BASE=$$secret_secret_key_base
+ - DISABLE_AUTH=$$config_disable_auth
+ - DISABLE_REGISTRATION=$$config_disable_registration
+ - DATABASE_URL=$$secret_database_url
+ - CLICKHOUSE_DATABASE_URL=$$secret_clickhouse_database_url
+ ports:
+ - "8000"
+ $$id-postgresql:
+ name: PostgreSQL
+ image: "bitnami/postgresql:13"
+ volumes:
+ - "$$id-postgresql-data:/bitnami/postgresql"
+ environment:
+ - POSTGRESQL_PASSWORD=$$secret_postgresql_password
+ - POSTGRESQL_USERNAME=$$config_postgresql_username
+ - POSTGRESQL_DATABASE=$$config_postgresql_database
+ $$id-clickhouse:
+ name: Clickhouse
+ volumes:
+ - "$$id-clickhouse-data:/var/lib/clickhouse"
+ image: "clickhouse/clickhouse-server:22.6-alpine"
+ ulimits:
+ nofile:
+ soft: 262144
+ hard: 262144
+ files:
+ - location: /etc/clickhouse-server/users.d/logging.xml
+ content: >-
+ warning true
+ - location: /etc/clickhouse-server/config.d/logging.xml
+ content: >-
+ 0 0
+ - location: /docker-entrypoint-initdb.d/init.query
+ content: CREATE DATABASE IF NOT EXISTS plausible;
+ - location: /docker-entrypoint-initdb.d/init-db.sh
+ content: >-
+ clickhouse client --queries-file
+ /docker-entrypoint-initdb.d/init.query
+ variables:
+ - id: $$config_base_url
+ name: BASE_URL
+ label: Base URL
+ defaultValue: $$generate_fqdn
+ description: >-
+ You must set this to the FQDN of the Plausible Analytics instance. This
+ is used to generate the links to the Plausible Analytics instance.
+ - id: $$secret_database_url
+ name: DATABASE_URL
+ label: Database URL for PostgreSQL
+ defaultValue: >-
+ postgresql://$$config_postgresql_username:$$secret_postgresql_password@$$id-postgresql:5432/$$config_postgresql_database
+ description: ""
+ - id: $$secret_clickhouse_database_url
+ name: CLICKHOUSE_DATABASE_URL
+ label: Database URL for Clickhouse
+ defaultValue: "http://$$id-clickhouse:8123/plausible"
+ description: ""
+ - id: $$config_admin_user_email
+ name: ADMIN_USER_EMAIL
+ label: Admin Email Address
+ defaultValue: admin@example.com
+ description: This is the admin email. Please change it.
+ - id: $$config_admin_user_name
+ name: ADMIN_USER_NAME
+ label: Admin User Name
+ defaultValue: $$generate_username
+ description: This is the admin username. Please change it.
+ - id: $$secret_admin_user_pwd
+ name: ADMIN_USER_PWD
+ label: Admin User Password
+ defaultValue: $$generate_password
+ description: This is the admin password. Please change it.
+ showOnConfiguration: true
+ - id: $$secret_secret_key_base
+ name: SECRET_KEY_BASE
+ label: Secret Key Base
+ defaultValue: $$generate_hex(64)
+ description: ""
+ - id: $$config_disable_auth
+ name: DISABLE_AUTH
+ label: Authentication
+ defaultValue: "false"
+ description: ""
+ - id: $$config_disable_registration
+ name: DISABLE_REGISTRATION
+ label: Registration
+ defaultValue: "true"
+ description: ""
+ - id: $$config_postgresql_username
+ main: $$id-postgresql
+ name: POSTGRESQL_USERNAME
+ label: PostgreSQL Username
+ defaultValue: postgresql
+ description: ""
+ - id: $$secret_postgresql_password
+ main: $$id-postgresql
+ name: POSTGRESQL_PASSWORD
+ label: PostgreSQL Password
+ defaultValue: $$generate_password
+ description: ""
+ showOnConfiguration: true
+ - id: $$config_postgresql_database
+ main: $$id-postgresql
+ name: POSTGRESQL_DATABASE
+ label: PostgreSQL Database
+ defaultValue: plausible
+ description: ""
+ - id: $$config_scriptName
+ name: SCRIPT_NAME
+ label: Custom Script Name
+ defaultValue: plausible.js
+ description: This is the default script name.
+- templateVersion: 1.0.0
+ defaultVersion: 0.99.1
+ documentation: https://docs.nocodb.com
+ type: nocodb
+ name: NocoDB
+ description: >-
+ Turns any MySQL, PostgreSQL, SQL Server, SQLite & MariaDB into a smart-spreadsheet.
+ labels:
+ - database
+ - airtable
+ - spreadsheet
+ services:
+ $$id:
+ name: NocoDB
+ image: nocodb/nocodb:$$core_version
+ environment:
+ - PORT=$$config_port
+ - NC_DB=$$config_nc_db
+ - DATABASE_URL=$$secret_database_url
+ - NC_PUBLIC_URL=$$config_public_url
+ - NC_AUTH_JWT_SECRET=$$secret_auth_jwt_secret
+ - NC_SENTRY_DSN=$$secret_sentry_dsn
+ - >-
+ NC_CONNECT_TO_EXTERNAL_DB_DISABLED=$$config_connect_to_external_db_disabled
+ - NC_DISABLE_TELE=$$config_disable_tele
+ volumes:
+ - $$id-data:/usr/app/data
+ ports:
+ - "8080"
+ variables:
+ - id: $$config_nc_db
+ name: NC_DB
+ label: Database
+ defaultValue: ""
+ description: >-
+ MySQL, PostgreSQL and MSSQL connection urls supported. If absent: A
+ local SQLite will be created in root folder.
+ - id: $$config_port
+ name: PORT
+ label: Port
+ defaultValue: "8080"
+ description: >-
+
+ - id: $$secret_database_url
+ name: DATABASE_URL
+ label: Database URL
+ defaultValue: ""
+ description: >-
+ JDBC URL Format. Can be used instead of NC_DB. Used in 1-Click Heroku
+ deployment.
+ - id: $$config_public_url
+ name: NC_PUBLIC_URL
+ label: Public URL
+ defaultValue: ""
+ description: >-
+ Used for sending Email invitations. If absent: Best guess from http
+ request params.
+ - id: $$secret_auth_jwt_secret
+ name: NC_AUTH_JWT_SECRET
+ label: Auth JWT Secret
+ defaultValue: $$generate_hex(64)
+ description: >-
+ JWT secret used for auth and storing other secrets. If absent: A Random
+ secret will be generated.
+ - id: $$secret_sentry_dsn
+ name: NC_SENTRY_DSN
+ label: Sentry DSN
+ defaultValue: ""
+ description: For Sentry monitoring.
+ - id: $$config_connect_to_external_db_disabled
+ name: NC_CONNECT_TO_EXTERNAL_DB_DISABLED
+ label: Disable External Database
+ defaultValue: "0"
+ description: Disable Project creation with external database. (Enter "1" to disable).
+ - id: $$config_disable_tele
+ name: NC_DISABLE_TELE
+ label: NocoDB Disable Telemetry
+ defaultValue: "1"
+ description: Disable telemetry (Enter "1" to disable).
diff --git a/apps/server/src/lib/common.ts b/apps/server/src/lib/common.ts
index b415790aa..57991d242 100644
--- a/apps/server/src/lib/common.ts
+++ b/apps/server/src/lib/common.ts
@@ -665,4 +665,46 @@ export async function getContainerUsage(dockerId: string, container: string): Pr
NetIO: 0
};
}
-}
\ No newline at end of file
+}
+export function fixType(type) {
+ return type?.replaceAll(' ', '').toLowerCase() || null;
+}
+const compareSemanticVersions = (a: string, b: string) => {
+ const a1 = a.split('.');
+ const b1 = b.split('.');
+ const len = Math.min(a1.length, b1.length);
+ for (let i = 0; i < len; i++) {
+ const a2 = +a1[i] || 0;
+ const b2 = +b1[i] || 0;
+ if (a2 !== b2) {
+ return a2 > b2 ? 1 : -1;
+ }
+ }
+ return b1.length - a1.length;
+};
+export async function getTags(type: string) {
+ try {
+ if (type) {
+ const tagsPath = isDev ? './tags.json' : '/app/tags.json';
+ const data = await fs.readFile(tagsPath, 'utf8');
+ let tags = JSON.parse(data);
+ if (tags) {
+ tags = tags.find((tag: any) => tag.name.includes(type));
+ tags.tags = tags.tags.sort(compareSemanticVersions).reverse();
+ return tags;
+ }
+ }
+ } catch (error) {
+ return [];
+ }
+}
+export function makeLabelForServices(type) {
+ return [
+ 'coolify.managed=true',
+ `coolify.version=${version}`,
+ `coolify.type=service`,
+ `coolify.service.type=${type}`
+ ];
+}
+export const asyncSleep = (delay: number): Promise =>
+ new Promise((resolve) => setTimeout(resolve, delay));
\ No newline at end of file
diff --git a/apps/server/src/scheduler.ts b/apps/server/src/scheduler.ts
index 3ec5c7990..9a8583fc2 100644
--- a/apps/server/src/scheduler.ts
+++ b/apps/server/src/scheduler.ts
@@ -9,7 +9,7 @@ Bree.extend(TSBree);
const options: any = {
defaultExtension: 'js',
- logger: new Cabin({}),
+ logger: false,
jobs: [{ name: 'applicationBuildQueue' }]
};
if (isDev) options.root = path.join(__dirname, './jobs');
diff --git a/apps/server/src/trpc/routers/services.ts b/apps/server/src/trpc/routers/services.ts
deleted file mode 100644
index 6368d60f1..000000000
--- a/apps/server/src/trpc/routers/services.ts
+++ /dev/null
@@ -1,171 +0,0 @@
-import { z } from 'zod';
-import { privateProcedure, router } from '../trpc';
-import { decrypt, getTemplates, removeService } from '../../lib/common';
-import { prisma } from '../../prisma';
-import { executeCommand } from '../../lib/executeCommand';
-
-export const servicesRouter = router({
- status: privateProcedure.input(z.object({ id: z.string() })).query(async ({ ctx, input }) => {
- const id = input.id;
- const teamId = ctx.user?.teamId;
- if (!teamId) {
- throw { status: 400, message: 'Team not found.' };
- }
- const service = await getServiceFromDB({ id, teamId });
- const { destinationDockerId } = service;
- let payload = {};
- if (destinationDockerId) {
- const { stdout: containers } = await executeCommand({
- dockerId: service.destinationDocker.id,
- command: `docker ps -a --filter "label=com.docker.compose.project=${id}" --format '{{json .}}'`
- });
- if (containers) {
- const containersArray = containers.trim().split('\n');
- if (containersArray.length > 0 && containersArray[0] !== '') {
- const templates = await getTemplates();
- let template = templates.find((t: { type: string }) => t.type === service.type);
- const templateStr = JSON.stringify(template);
- if (templateStr) {
- template = JSON.parse(templateStr.replaceAll('$$id', service.id));
- }
- for (const container of containersArray) {
- let isRunning = false;
- let isExited = false;
- let isRestarting = false;
- let isExcluded = false;
- const containerObj = JSON.parse(container);
- const exclude = template?.services[containerObj.Names]?.exclude;
- if (exclude) {
- payload[containerObj.Names] = {
- status: {
- isExcluded: true,
- isRunning: false,
- isExited: false,
- isRestarting: false
- }
- };
- continue;
- }
-
- const status = containerObj.State;
- if (status === 'running') {
- isRunning = true;
- }
- if (status === 'exited') {
- isExited = true;
- }
- if (status === 'restarting') {
- isRestarting = true;
- }
- payload[containerObj.Names] = {
- status: {
- isExcluded,
- isRunning,
- isExited,
- isRestarting
- }
- };
- }
- }
- }
- }
- return payload;
- }),
- cleanup: privateProcedure.query(async ({ ctx }) => {
- const teamId = ctx.user?.teamId;
- let services = await prisma.service.findMany({
- where: { teams: { some: { id: teamId === '0' ? undefined : teamId } } },
- include: { destinationDocker: true, teams: true }
- });
- for (const service of services) {
- if (!service.fqdn) {
- if (service.destinationDockerId) {
- const { stdout: containers } = await executeCommand({
- dockerId: service.destinationDockerId,
- command: `docker ps -a --filter 'label=com.docker.compose.project=${service.id}' --format {{.ID}}`
- });
- if (containers) {
- const containerArray = containers.split('\n');
- if (containerArray.length > 0) {
- for (const container of containerArray) {
- await executeCommand({
- dockerId: service.destinationDockerId,
- command: `docker stop -t 0 ${container}`
- });
- await executeCommand({
- dockerId: service.destinationDockerId,
- command: `docker rm --force ${container}`
- });
- }
- }
- }
- }
- await removeService({ id: service.id });
- }
- }
- }),
- delete: privateProcedure
- .input(z.object({ force: z.boolean(), id: z.string() }))
- .mutation(async ({ input }) => {
- // todo: check if user is allowed to delete service
- const { id } = input;
- await prisma.serviceSecret.deleteMany({ where: { serviceId: id } });
- await prisma.serviceSetting.deleteMany({ where: { serviceId: id } });
- await prisma.servicePersistentStorage.deleteMany({ where: { serviceId: id } });
- await prisma.meiliSearch.deleteMany({ where: { serviceId: id } });
- await prisma.fider.deleteMany({ where: { serviceId: id } });
- await prisma.ghost.deleteMany({ where: { serviceId: id } });
- await prisma.umami.deleteMany({ where: { serviceId: id } });
- await prisma.hasura.deleteMany({ where: { serviceId: id } });
- await prisma.plausibleAnalytics.deleteMany({ where: { serviceId: id } });
- await prisma.minio.deleteMany({ where: { serviceId: id } });
- await prisma.vscodeserver.deleteMany({ where: { serviceId: id } });
- await prisma.wordpress.deleteMany({ where: { serviceId: id } });
- await prisma.glitchTip.deleteMany({ where: { serviceId: id } });
- await prisma.moodle.deleteMany({ where: { serviceId: id } });
- await prisma.appwrite.deleteMany({ where: { serviceId: id } });
- await prisma.searxng.deleteMany({ where: { serviceId: id } });
- await prisma.weblate.deleteMany({ where: { serviceId: id } });
- await prisma.taiga.deleteMany({ where: { serviceId: id } });
-
- await prisma.service.delete({ where: { id } });
- return {};
- })
-});
-
-export async function getServiceFromDB({
- id,
- teamId
-}: {
- id: string;
- teamId: string;
-}): Promise {
- const settings = await prisma.setting.findFirst();
- const body = await prisma.service.findFirst({
- where: { id, teams: { some: { id: teamId === '0' ? undefined : teamId } } },
- include: {
- destinationDocker: true,
- persistentStorage: true,
- serviceSecret: true,
- serviceSetting: true,
- wordpress: true,
- plausibleAnalytics: true
- }
- });
- if (!body) {
- return null;
- }
- // body.type = fixType(body.type);
-
- if (body?.serviceSecret.length > 0) {
- body.serviceSecret = body.serviceSecret.map((s) => {
- s.value = decrypt(s.value);
- return s;
- });
- }
- if (body.wordpress) {
- body.wordpress.ftpPassword = decrypt(body.wordpress.ftpPassword);
- }
-
- return { ...body, settings };
-}
diff --git a/apps/server/src/trpc/routers/services/index.ts b/apps/server/src/trpc/routers/services/index.ts
new file mode 100644
index 000000000..e58faf2e5
--- /dev/null
+++ b/apps/server/src/trpc/routers/services/index.ts
@@ -0,0 +1,895 @@
+import { z } from 'zod';
+import yaml from 'js-yaml';
+import fs from 'fs/promises';
+import path from 'path';
+import { privateProcedure, router } from '../../trpc';
+import {
+ createDirectories,
+ decrypt,
+ encrypt,
+ fixType,
+ getTags,
+ getTemplates,
+ isARM,
+ isDev,
+ listSettings,
+ makeLabelForServices,
+ removeService
+} from '../../../lib/common';
+import { prisma } from '../../../prisma';
+import { executeCommand } from '../../../lib/executeCommand';
+import {
+ generatePassword,
+ getFreePublicPort,
+ parseAndFindServiceTemplates,
+ persistentVolumes,
+ startServiceContainers,
+ verifyAndDecryptServiceSecrets
+} from './lib';
+import { checkContainer, defaultComposeConfiguration, stopTcpHttpProxy } from '../../../lib/docker';
+import cuid from 'cuid';
+import { day } from '../../../lib/dayjs';
+
+export const servicesRouter = router({
+ getLogs: privateProcedure
+ .input(
+ z.object({
+ id: z.string(),
+ containerId: z.string(),
+ since: z.number().optional().default(0)
+ })
+ )
+ .query(async ({ input, ctx }) => {
+ let { id, containerId, since } = input;
+ if (since !== 0) {
+ since = day(since).unix();
+ }
+ const {
+ destinationDockerId,
+ destinationDocker: { id: dockerId }
+ } = await prisma.service.findUnique({
+ where: { id },
+ include: { destinationDocker: true }
+ });
+ if (destinationDockerId) {
+ try {
+ const { default: ansi } = await import('strip-ansi');
+ const { stdout, stderr } = await executeCommand({
+ dockerId,
+ command: `docker logs --since ${since} --tail 5000 --timestamps ${containerId}`
+ });
+ const stripLogsStdout = stdout
+ .toString()
+ .split('\n')
+ .map((l) => ansi(l))
+ .filter((a) => a);
+ const stripLogsStderr = stderr
+ .toString()
+ .split('\n')
+ .map((l) => ansi(l))
+ .filter((a) => a);
+ const logs = stripLogsStderr.concat(stripLogsStdout);
+ const sortedLogs = logs.sort((a, b) =>
+ day(a.split(' ')[0]).isAfter(day(b.split(' ')[0])) ? 1 : -1
+ );
+ return {
+ data: {
+ logs: sortedLogs
+ }
+ };
+ // }
+ } catch (error) {
+ const { statusCode, stderr } = error;
+ if (stderr.startsWith('Error: No such container')) {
+ return {
+ data: {
+ logs: [],
+ noContainer: true
+ }
+ };
+ }
+ if (statusCode === 404) {
+ return {
+ data: {
+ logs: []
+
+ }
+ };
+ }
+ }
+ }
+ return {
+ message: 'No logs found.'
+ };
+ }),
+ deleteStorage: privateProcedure
+ .input(
+ z.object({
+ storageId: z.string()
+ })
+ )
+ .mutation(async ({ input, ctx }) => {
+ const { storageId } = input;
+ await prisma.servicePersistentStorage.deleteMany({ where: { id: storageId } });
+ }),
+ saveStorage: privateProcedure
+ .input(
+ z.object({
+ id: z.string(),
+ path: z.string(),
+ isNewStorage: z.boolean(),
+ storageId: z.string().optional().nullable(),
+ containerId: z.string().optional()
+ })
+ )
+ .mutation(async ({ input, ctx }) => {
+ const { id, path, isNewStorage, storageId, containerId } = input;
+
+ if (isNewStorage) {
+ const volumeName = `${id}-custom${path.replace(/\//gi, '-')}`;
+ const found = await prisma.servicePersistentStorage.findFirst({
+ where: { path, containerId }
+ });
+ if (found) {
+ throw {
+ status: 500,
+ message: 'Persistent storage already exists for this container and path.'
+ };
+ }
+ await prisma.servicePersistentStorage.create({
+ data: { path, volumeName, containerId, service: { connect: { id } } }
+ });
+ } else {
+ await prisma.servicePersistentStorage.update({
+ where: { id: storageId },
+ data: { path, containerId }
+ });
+ }
+ }),
+ getStorages: privateProcedure
+ .input(z.object({ id: z.string() }))
+ .query(async ({ input, ctx }) => {
+ const { id } = input;
+ const persistentStorages = await prisma.servicePersistentStorage.findMany({
+ where: { serviceId: id }
+ });
+ return {
+ success: true,
+ data: {
+ persistentStorages
+ }
+ };
+ }),
+ deleteSecret: privateProcedure
+ .input(z.object({ id: z.string(), name: z.string() }))
+ .mutation(async ({ input, ctx }) => {
+ const { id, name } = input;
+ await prisma.serviceSecret.deleteMany({ where: { serviceId: id, name } });
+ }),
+ saveService: privateProcedure
+ .input(
+ z.object({
+ id: z.string(),
+ name: z.string(),
+ fqdn: z.string().optional(),
+ exposePort: z.string().optional(),
+ type: z.string(),
+ serviceSetting: z.any(),
+ version: z.string().optional()
+ })
+ )
+ .mutation(async ({ input, ctx }) => {
+ const teamId = ctx.user?.teamId;
+ let { id, name, fqdn, exposePort, type, serviceSetting, version } = input;
+ if (fqdn) fqdn = fqdn.toLowerCase();
+ if (exposePort) exposePort = Number(exposePort);
+ type = fixType(type);
+
+ const data = {
+ fqdn,
+ name,
+ exposePort,
+ version
+ };
+ const templates = await getTemplates();
+ const service = await prisma.service.findUnique({ where: { id } });
+ const foundTemplate = templates.find((t) => fixType(t.type) === fixType(service.type));
+ for (const setting of serviceSetting) {
+ let { id: settingId, name, value, changed = false, isNew = false, variableName } = setting;
+ if (value) {
+ if (changed) {
+ await prisma.serviceSetting.update({ where: { id: settingId }, data: { value } });
+ }
+ if (isNew) {
+ if (!variableName) {
+ variableName = foundTemplate?.variables.find((v) => v.name === name).id;
+ }
+ await prisma.serviceSetting.create({
+ data: { name, value, variableName, service: { connect: { id } } }
+ });
+ }
+ }
+ }
+ await prisma.service.update({
+ where: { id },
+ data
+ });
+ }),
+ createSecret: privateProcedure
+ .input(
+ z.object({
+ id: z.string(),
+ name: z.string(),
+ value: z.string(),
+ isBuildSecret: z.boolean().optional(),
+ isPRMRSecret: z.boolean().optional(),
+ isNew: z.boolean().optional()
+ })
+ )
+ .mutation(async ({ input }) => {
+ let { id, name, value, isNew } = input;
+ if (isNew) {
+ const found = await prisma.serviceSecret.findFirst({ where: { name, serviceId: id } });
+ if (found) {
+ throw `Secret ${name} already exists.`;
+ } else {
+ value = encrypt(value.trim());
+ await prisma.serviceSecret.create({
+ data: { name, value, service: { connect: { id } } }
+ });
+ }
+ } else {
+ value = encrypt(value.trim());
+ const found = await prisma.serviceSecret.findFirst({ where: { serviceId: id, name } });
+
+ if (found) {
+ await prisma.serviceSecret.updateMany({
+ where: { serviceId: id, name },
+ data: { value }
+ });
+ } else {
+ await prisma.serviceSecret.create({
+ data: { name, value, service: { connect: { id } } }
+ });
+ }
+ }
+ }),
+ getSecrets: privateProcedure.input(z.object({ id: z.string() })).query(async ({ input, ctx }) => {
+ const { id } = input;
+ const teamId = ctx.user?.teamId;
+ const service = await getServiceFromDB({ id, teamId });
+ let secrets = await prisma.serviceSecret.findMany({
+ where: { serviceId: id },
+ orderBy: { createdAt: 'desc' }
+ });
+ const templates = await getTemplates();
+ if (!templates) throw new Error('No templates found. Please contact support.');
+ const foundTemplate = templates.find((t) => fixType(t.type) === service.type);
+ secrets = secrets.map((secret) => {
+ const foundVariable = foundTemplate?.variables?.find((v) => v.name === secret.name) || null;
+ if (foundVariable) {
+ secret.readOnly = foundVariable.readOnly;
+ }
+ secret.value = decrypt(secret.value);
+ return secret;
+ });
+
+ return {
+ success: true,
+ data: {
+ secrets
+ }
+ };
+ }),
+ wordpress: privateProcedure
+ .input(z.object({ id: z.string(), ftpEnabled: z.boolean() }))
+ .mutation(async ({ input, ctx }) => {
+ const { id } = input;
+ const teamId = ctx.user?.teamId;
+ const {
+ service: {
+ destinationDocker: { engine, remoteEngine, remoteIpAddress }
+ }
+ } = await prisma.wordpress.findUnique({
+ where: { serviceId: id },
+ include: { service: { include: { destinationDocker: true } } }
+ });
+
+ const publicPort = await getFreePublicPort({ id, remoteEngine, engine, remoteIpAddress });
+
+ let ftpUser = cuid();
+ let ftpPassword = generatePassword({});
+
+ const hostkeyDir = isDev ? '/tmp/hostkeys' : '/app/ssl/hostkeys';
+ try {
+ const data = await prisma.wordpress.update({
+ where: { serviceId: id },
+ data: { ftpEnabled },
+ include: { service: { include: { destinationDocker: true } } }
+ });
+ const {
+ service: { destinationDockerId, destinationDocker },
+ ftpPublicPort,
+ ftpUser: user,
+ ftpPassword: savedPassword,
+ ftpHostKey,
+ ftpHostKeyPrivate
+ } = data;
+ const { network, engine } = destinationDocker;
+ if (ftpEnabled) {
+ if (user) ftpUser = user;
+ if (savedPassword) ftpPassword = decrypt(savedPassword);
+
+ // TODO: rewrite these to usable without shell
+ const { stdout: password } = await executeCommand({
+ command: `echo ${ftpPassword} | openssl passwd -1 -stdin`,
+ shell: true
+ });
+ if (destinationDockerId) {
+ try {
+ await fs.stat(hostkeyDir);
+ } catch (error) {
+ await executeCommand({ command: `mkdir -p ${hostkeyDir}` });
+ }
+ if (!ftpHostKey) {
+ await executeCommand({
+ command: `ssh-keygen -t ed25519 -f ssh_host_ed25519_key -N "" -q -f ${hostkeyDir}/${id}.ed25519`
+ });
+ const { stdout: ftpHostKey } = await executeCommand({
+ command: `cat ${hostkeyDir}/${id}.ed25519`
+ });
+ await prisma.wordpress.update({
+ where: { serviceId: id },
+ data: { ftpHostKey: encrypt(ftpHostKey) }
+ });
+ } else {
+ await executeCommand({
+ command: `echo "${decrypt(ftpHostKey)}" > ${hostkeyDir}/${id}.ed25519`,
+ shell: true
+ });
+ }
+ if (!ftpHostKeyPrivate) {
+ await executeCommand({
+ command: `ssh-keygen -t rsa -b 4096 -N "" -f ${hostkeyDir}/${id}.rsa`
+ });
+ const { stdout: ftpHostKeyPrivate } = await executeCommand({
+ command: `cat ${hostkeyDir}/${id}.rsa`
+ });
+ await prisma.wordpress.update({
+ where: { serviceId: id },
+ data: { ftpHostKeyPrivate: encrypt(ftpHostKeyPrivate) }
+ });
+ } else {
+ await executeCommand({
+ command: `echo "${decrypt(ftpHostKeyPrivate)}" > ${hostkeyDir}/${id}.rsa`,
+ shell: true
+ });
+ }
+
+ await prisma.wordpress.update({
+ where: { serviceId: id },
+ data: {
+ ftpPublicPort: publicPort,
+ ftpUser: user ? undefined : ftpUser,
+ ftpPassword: savedPassword ? undefined : encrypt(ftpPassword)
+ }
+ });
+
+ try {
+ const { found: isRunning } = await checkContainer({
+ dockerId: destinationDocker.id,
+ container: `${id}-ftp`
+ });
+ if (isRunning) {
+ await executeCommand({
+ dockerId: destinationDocker.id,
+ command: `docker stop -t 0 ${id}-ftp && docker rm ${id}-ftp`,
+ shell: true
+ });
+ }
+ } catch (error) {}
+ const volumes = [
+ `${id}-wordpress-data:/home/${ftpUser}/wordpress`,
+ `${
+ isDev ? hostkeyDir : '/var/lib/docker/volumes/coolify-ssl-certs/_data/hostkeys'
+ }/${id}.ed25519:/etc/ssh/ssh_host_ed25519_key`,
+ `${
+ isDev ? hostkeyDir : '/var/lib/docker/volumes/coolify-ssl-certs/_data/hostkeys'
+ }/${id}.rsa:/etc/ssh/ssh_host_rsa_key`,
+ `${
+ isDev ? hostkeyDir : '/var/lib/docker/volumes/coolify-ssl-certs/_data/hostkeys'
+ }/${id}.sh:/etc/sftp.d/chmod.sh`
+ ];
+
+ const compose = {
+ version: '3.8',
+ services: {
+ [`${id}-ftp`]: {
+ image: `atmoz/sftp:alpine`,
+ command: `'${ftpUser}:${password.replace('\n', '').replace(/\$/g, '$$$')}:e:33'`,
+ extra_hosts: ['host.docker.internal:host-gateway'],
+ container_name: `${id}-ftp`,
+ volumes,
+ networks: [network],
+ depends_on: [],
+ restart: 'always'
+ }
+ },
+ networks: {
+ [network]: {
+ external: true
+ }
+ },
+ volumes: {
+ [`${id}-wordpress-data`]: {
+ external: true,
+ name: `${id}-wordpress-data`
+ }
+ }
+ };
+ await fs.writeFile(
+ `${hostkeyDir}/${id}.sh`,
+ `#!/bin/bash\nchmod 600 /etc/ssh/ssh_host_ed25519_key /etc/ssh/ssh_host_rsa_key\nuserdel -f xfs\nchown -R 33:33 /home/${ftpUser}/wordpress/`
+ );
+ await executeCommand({ command: `chmod +x ${hostkeyDir}/${id}.sh` });
+ await fs.writeFile(`${hostkeyDir}/${id}-docker-compose.yml`, yaml.dump(compose));
+ await executeCommand({
+ dockerId: destinationDocker.id,
+ command: `docker compose -f ${hostkeyDir}/${id}-docker-compose.yml up -d`
+ });
+ }
+ return {
+ publicPort,
+ ftpUser,
+ ftpPassword
+ };
+ } else {
+ await prisma.wordpress.update({
+ where: { serviceId: id },
+ data: { ftpPublicPort: null }
+ });
+ try {
+ await executeCommand({
+ dockerId: destinationDocker.id,
+ command: `docker stop -t 0 ${id}-ftp && docker rm ${id}-ftp`,
+ shell: true
+ });
+ } catch (error) {
+ //
+ }
+ await stopTcpHttpProxy(id, destinationDocker, ftpPublicPort);
+ }
+ } catch ({ status, message }) {
+ throw message;
+ } finally {
+ try {
+ await executeCommand({
+ command: `rm -fr ${hostkeyDir}/${id}-docker-compose.yml ${hostkeyDir}/${id}.ed25519 ${hostkeyDir}/${id}.ed25519.pub ${hostkeyDir}/${id}.rsa ${hostkeyDir}/${id}.rsa.pub ${hostkeyDir}/${id}.sh`
+ });
+ } catch (error) {}
+ }
+ }),
+ start: privateProcedure.input(z.object({ id: z.string() })).mutation(async ({ input, ctx }) => {
+ const { id } = input;
+ const teamId = ctx.user?.teamId;
+ const service = await getServiceFromDB({ id, teamId });
+ const arm = isARM(service.arch);
+ const { type, destinationDockerId, destinationDocker, persistentStorage, exposePort } = service;
+
+ const { workdir } = await createDirectories({ repository: type, buildId: id });
+ const template: any = await parseAndFindServiceTemplates(service, workdir, true);
+ const network = destinationDockerId && destinationDocker.network;
+ const config = {};
+ for (const s in template.services) {
+ let newEnvironments = [];
+ if (arm) {
+ if (template.services[s]?.environmentArm?.length > 0) {
+ for (const environment of template.services[s].environmentArm) {
+ let [env, ...value] = environment.split('=');
+ value = value.join('=');
+ if (!value.startsWith('$$secret') && value !== '') {
+ newEnvironments.push(`${env}=${value}`);
+ }
+ }
+ }
+ } else {
+ if (template.services[s]?.environment?.length > 0) {
+ for (const environment of template.services[s].environment) {
+ let [env, ...value] = environment.split('=');
+ value = value.join('=');
+ if (!value.startsWith('$$secret') && value !== '') {
+ newEnvironments.push(`${env}=${value}`);
+ }
+ }
+ }
+ }
+ const secrets = await verifyAndDecryptServiceSecrets(id);
+ for (const secret of secrets) {
+ const { name, value } = secret;
+ if (value) {
+ const foundEnv = !!template.services[s].environment?.find((env) =>
+ env.startsWith(`${name}=`)
+ );
+ const foundNewEnv = !!newEnvironments?.find((env) => env.startsWith(`${name}=`));
+ if (foundEnv && !foundNewEnv) {
+ newEnvironments.push(`${name}=${value}`);
+ }
+ if (!foundEnv && !foundNewEnv && s === id) {
+ newEnvironments.push(`${name}=${value}`);
+ }
+ }
+ }
+ const customVolumes = await prisma.servicePersistentStorage.findMany({
+ where: { serviceId: id }
+ });
+ let volumes = new Set();
+ if (arm) {
+ template.services[s]?.volumesArm &&
+ template.services[s].volumesArm.length > 0 &&
+ template.services[s].volumesArm.forEach((v) => volumes.add(v));
+ } else {
+ template.services[s]?.volumes &&
+ template.services[s].volumes.length > 0 &&
+ template.services[s].volumes.forEach((v) => volumes.add(v));
+ }
+
+ // Workaround: old plausible analytics service wrong volume id name
+ if (service.type === 'plausibleanalytics' && service.plausibleAnalytics?.id) {
+ let temp = Array.from(volumes);
+ temp.forEach((a) => {
+ const t = a.replace(service.id, service.plausibleAnalytics.id);
+ volumes.delete(a);
+ volumes.add(t);
+ });
+ }
+
+ if (customVolumes.length > 0) {
+ for (const customVolume of customVolumes) {
+ const { volumeName, path, containerId } = customVolume;
+ if (
+ volumes &&
+ volumes.size > 0 &&
+ !volumes.has(`${volumeName}:${path}`) &&
+ containerId === service
+ ) {
+ volumes.add(`${volumeName}:${path}`);
+ }
+ }
+ }
+ let ports = [];
+ if (template.services[s].proxy?.length > 0) {
+ for (const proxy of template.services[s].proxy) {
+ if (proxy.hostPort) {
+ ports.push(`${proxy.hostPort}:${proxy.port}`);
+ }
+ }
+ } else {
+ if (template.services[s].ports?.length === 1) {
+ for (const port of template.services[s].ports) {
+ if (exposePort) {
+ ports.push(`${exposePort}:${port}`);
+ }
+ }
+ }
+ }
+ let image = template.services[s].image;
+ if (arm && template.services[s].imageArm) {
+ image = template.services[s].imageArm;
+ }
+ config[s] = {
+ container_name: s,
+ build: template.services[s].build || undefined,
+ command: template.services[s].command,
+ entrypoint: template.services[s]?.entrypoint,
+ image,
+ expose: template.services[s].ports,
+ ports: ports.length > 0 ? ports : undefined,
+ volumes: Array.from(volumes),
+ environment: newEnvironments,
+ depends_on: template.services[s]?.depends_on,
+ ulimits: template.services[s]?.ulimits,
+ cap_drop: template.services[s]?.cap_drop,
+ cap_add: template.services[s]?.cap_add,
+ labels: makeLabelForServices(type),
+ ...defaultComposeConfiguration(network)
+ };
+ // Generate files for builds
+ if (template.services[s]?.files?.length > 0) {
+ if (!config[s].build) {
+ config[s].build = {
+ context: workdir,
+ dockerfile: `Dockerfile.${s}`
+ };
+ }
+ let Dockerfile = `
+ FROM ${template.services[s].image}`;
+ for (const file of template.services[s].files) {
+ const { location, content } = file;
+ const source = path.join(workdir, location);
+ await fs.mkdir(path.dirname(source), { recursive: true });
+ await fs.writeFile(source, content);
+ Dockerfile += `
+ COPY .${location} ${location}`;
+ }
+ await fs.writeFile(`${workdir}/Dockerfile.${s}`, Dockerfile);
+ }
+ }
+ const { volumeMounts } = persistentVolumes(id, persistentStorage, config);
+ const composeFile = {
+ version: '3.8',
+ services: config,
+ networks: {
+ [network]: {
+ external: true
+ }
+ },
+ volumes: volumeMounts
+ };
+ const composeFileDestination = `${workdir}/docker-compose.yaml`;
+ await fs.writeFile(composeFileDestination, yaml.dump(composeFile));
+ // TODO: TODO!
+ let fastify = null;
+ await startServiceContainers(fastify, id, teamId, destinationDocker.id, composeFileDestination);
+
+ // Workaround: Stop old minio proxies
+ if (service.type === 'minio') {
+ try {
+ const { stdout: containers } = await executeCommand({
+ dockerId: destinationDocker.id,
+ command: `docker container ls -a --filter 'name=${id}-' --format {{.ID}}`
+ });
+ if (containers) {
+ const containerArray = containers.split('\n');
+ if (containerArray.length > 0) {
+ for (const container of containerArray) {
+ await executeCommand({
+ dockerId: destinationDockerId,
+ command: `docker stop -t 0 ${container}`
+ });
+ await executeCommand({
+ dockerId: destinationDockerId,
+ command: `docker rm --force ${container}`
+ });
+ }
+ }
+ }
+ } catch (error) {}
+ try {
+ const { stdout: containers } = await executeCommand({
+ dockerId: destinationDocker.id,
+ command: `docker container ls -a --filter 'name=${id}-' --format {{.ID}}`
+ });
+ if (containers) {
+ const containerArray = containers.split('\n');
+ if (containerArray.length > 0) {
+ for (const container of containerArray) {
+ await executeCommand({
+ dockerId: destinationDockerId,
+ command: `docker stop -t 0 ${container}`
+ });
+ await executeCommand({
+ dockerId: destinationDockerId,
+ command: `docker rm --force ${container}`
+ });
+ }
+ }
+ }
+ } catch (error) {}
+ }
+ }),
+ stop: privateProcedure.input(z.object({ id: z.string() })).mutation(async ({ input, ctx }) => {
+ const { id } = input;
+ const teamId = ctx.user?.teamId;
+ const { destinationDockerId } = await getServiceFromDB({ id, teamId });
+ if (destinationDockerId) {
+ const { stdout: containers } = await executeCommand({
+ dockerId: destinationDockerId,
+ command: `docker ps -a --filter 'label=com.docker.compose.project=${id}' --format {{.ID}}`
+ });
+ if (containers) {
+ const containerArray = containers.split('\n');
+ if (containerArray.length > 0) {
+ for (const container of containerArray) {
+ await executeCommand({
+ dockerId: destinationDockerId,
+ command: `docker stop -t 0 ${container}`
+ });
+ await executeCommand({
+ dockerId: destinationDockerId,
+ command: `docker rm --force ${container}`
+ });
+ }
+ }
+ }
+ return {};
+ }
+ }),
+ getServices: privateProcedure
+ .input(z.object({ id: z.string() }))
+ .query(async ({ input, ctx }) => {
+ const { id } = input;
+ const teamId = ctx.user?.teamId;
+ const service = await getServiceFromDB({ id, teamId });
+ if (!service) {
+ throw { status: 404, message: 'Service not found.' };
+ }
+ let template = {};
+ let tags = [];
+ if (service.type) {
+ template = await parseAndFindServiceTemplates(service);
+ tags = await getTags(service.type);
+ }
+ return {
+ success: true,
+ data: {
+ settings: await listSettings(),
+ service,
+ template,
+ tags
+ }
+ };
+ }),
+ status: privateProcedure.input(z.object({ id: z.string() })).query(async ({ ctx, input }) => {
+ const id = input.id;
+ const teamId = ctx.user?.teamId;
+ if (!teamId) {
+ throw { status: 400, message: 'Team not found.' };
+ }
+ const service = await getServiceFromDB({ id, teamId });
+ const { destinationDockerId } = service;
+ let payload = {};
+ if (destinationDockerId) {
+ const { stdout: containers } = await executeCommand({
+ dockerId: service.destinationDocker.id,
+ command: `docker ps -a --filter "label=com.docker.compose.project=${id}" --format '{{json .}}'`
+ });
+ if (containers) {
+ const containersArray = containers.trim().split('\n');
+ if (containersArray.length > 0 && containersArray[0] !== '') {
+ const templates = await getTemplates();
+ let template = templates.find((t: { type: string }) => t.type === service.type);
+ const templateStr = JSON.stringify(template);
+ if (templateStr) {
+ template = JSON.parse(templateStr.replaceAll('$$id', service.id));
+ }
+ for (const container of containersArray) {
+ let isRunning = false;
+ let isExited = false;
+ let isRestarting = false;
+ let isExcluded = false;
+ const containerObj = JSON.parse(container);
+ const exclude = template?.services[containerObj.Names]?.exclude;
+ if (exclude) {
+ payload[containerObj.Names] = {
+ status: {
+ isExcluded: true,
+ isRunning: false,
+ isExited: false,
+ isRestarting: false
+ }
+ };
+ continue;
+ }
+
+ const status = containerObj.State;
+ if (status === 'running') {
+ isRunning = true;
+ }
+ if (status === 'exited') {
+ isExited = true;
+ }
+ if (status === 'restarting') {
+ isRestarting = true;
+ }
+ payload[containerObj.Names] = {
+ status: {
+ isExcluded,
+ isRunning,
+ isExited,
+ isRestarting
+ }
+ };
+ }
+ }
+ }
+ }
+ return payload;
+ }),
+ cleanup: privateProcedure.query(async ({ ctx }) => {
+ const teamId = ctx.user?.teamId;
+ let services = await prisma.service.findMany({
+ where: { teams: { some: { id: teamId === '0' ? undefined : teamId } } },
+ include: { destinationDocker: true, teams: true }
+ });
+ for (const service of services) {
+ if (!service.fqdn) {
+ if (service.destinationDockerId) {
+ const { stdout: containers } = await executeCommand({
+ dockerId: service.destinationDockerId,
+ command: `docker ps -a --filter 'label=com.docker.compose.project=${service.id}' --format {{.ID}}`
+ });
+ if (containers) {
+ const containerArray = containers.split('\n');
+ if (containerArray.length > 0) {
+ for (const container of containerArray) {
+ await executeCommand({
+ dockerId: service.destinationDockerId,
+ command: `docker stop -t 0 ${container}`
+ });
+ await executeCommand({
+ dockerId: service.destinationDockerId,
+ command: `docker rm --force ${container}`
+ });
+ }
+ }
+ }
+ }
+ await removeService({ id: service.id });
+ }
+ }
+ }),
+ delete: privateProcedure
+ .input(z.object({ force: z.boolean(), id: z.string() }))
+ .mutation(async ({ input }) => {
+ // todo: check if user is allowed to delete service
+ const { id } = input;
+ await prisma.serviceSecret.deleteMany({ where: { serviceId: id } });
+ await prisma.serviceSetting.deleteMany({ where: { serviceId: id } });
+ await prisma.servicePersistentStorage.deleteMany({ where: { serviceId: id } });
+ await prisma.meiliSearch.deleteMany({ where: { serviceId: id } });
+ await prisma.fider.deleteMany({ where: { serviceId: id } });
+ await prisma.ghost.deleteMany({ where: { serviceId: id } });
+ await prisma.umami.deleteMany({ where: { serviceId: id } });
+ await prisma.hasura.deleteMany({ where: { serviceId: id } });
+ await prisma.plausibleAnalytics.deleteMany({ where: { serviceId: id } });
+ await prisma.minio.deleteMany({ where: { serviceId: id } });
+ await prisma.vscodeserver.deleteMany({ where: { serviceId: id } });
+ await prisma.wordpress.deleteMany({ where: { serviceId: id } });
+ await prisma.glitchTip.deleteMany({ where: { serviceId: id } });
+ await prisma.moodle.deleteMany({ where: { serviceId: id } });
+ await prisma.appwrite.deleteMany({ where: { serviceId: id } });
+ await prisma.searxng.deleteMany({ where: { serviceId: id } });
+ await prisma.weblate.deleteMany({ where: { serviceId: id } });
+ await prisma.taiga.deleteMany({ where: { serviceId: id } });
+
+ await prisma.service.delete({ where: { id } });
+ return {};
+ })
+});
+
+export async function getServiceFromDB({
+ id,
+ teamId
+}: {
+ id: string;
+ teamId: string;
+}): Promise {
+ const settings = await prisma.setting.findFirst();
+ const body = await prisma.service.findFirst({
+ where: { id, teams: { some: { id: teamId === '0' ? undefined : teamId } } },
+ include: {
+ destinationDocker: true,
+ persistentStorage: true,
+ serviceSecret: true,
+ serviceSetting: true,
+ wordpress: true,
+ plausibleAnalytics: true
+ }
+ });
+ if (!body) {
+ return null;
+ }
+ // body.type = fixType(body.type);
+
+ if (body?.serviceSecret.length > 0) {
+ body.serviceSecret = body.serviceSecret.map((s) => {
+ s.value = decrypt(s.value);
+ return s;
+ });
+ }
+ if (body.wordpress) {
+ body.wordpress.ftpPassword = decrypt(body.wordpress.ftpPassword);
+ }
+
+ return { ...body, settings };
+}
diff --git a/apps/server/src/trpc/routers/services/lib.ts b/apps/server/src/trpc/routers/services/lib.ts
new file mode 100644
index 000000000..ad785e58e
--- /dev/null
+++ b/apps/server/src/trpc/routers/services/lib.ts
@@ -0,0 +1,376 @@
+import { asyncSleep, decrypt, fixType, generateRangeArray, getDomain, getTemplates } from '../../../lib/common';
+import bcrypt from 'bcryptjs';
+import { prisma } from '../../../prisma';
+import crypto from 'crypto';
+import { executeCommand } from '../../../lib/executeCommand';
+
+export async function parseAndFindServiceTemplates(
+ service: any,
+ workdir?: string,
+ isDeploy: boolean = false
+) {
+ const templates = await getTemplates();
+ const foundTemplate = templates.find((t) => fixType(t.type) === service.type);
+ let parsedTemplate = {};
+ if (foundTemplate) {
+ if (!isDeploy) {
+ for (const [key, value] of Object.entries(foundTemplate.services)) {
+ const realKey = key.replace('$$id', service.id);
+ let name = value.name;
+ if (!name) {
+ if (Object.keys(foundTemplate.services).length === 1) {
+ name = foundTemplate.name || service.name.toLowerCase();
+ } else {
+ if (key === '$$id') {
+ name =
+ foundTemplate.name || key.replaceAll('$$id-', '') || service.name.toLowerCase();
+ } else {
+ name = key.replaceAll('$$id-', '') || service.name.toLowerCase();
+ }
+ }
+ }
+ parsedTemplate[realKey] = {
+ value,
+ name,
+ documentation:
+ value.documentation || foundTemplate.documentation || 'https://docs.coollabs.io',
+ image: value.image,
+ files: value?.files,
+ environment: [],
+ fqdns: [],
+ hostPorts: [],
+ proxy: {}
+ };
+ if (value.environment?.length > 0) {
+ for (const env of value.environment) {
+ let [envKey, ...envValue] = env.split('=');
+ envValue = envValue.join('=');
+ let variable = null;
+ if (foundTemplate?.variables) {
+ variable =
+ foundTemplate?.variables.find((v) => v.name === envKey) ||
+ foundTemplate?.variables.find((v) => v.id === envValue);
+ }
+ if (variable) {
+ const id = variable.id.replaceAll('$$', '');
+ const label = variable?.label;
+ const description = variable?.description;
+ const defaultValue = variable?.defaultValue;
+ const main = variable?.main || '$$id';
+ const type = variable?.type || 'input';
+ const placeholder = variable?.placeholder || '';
+ const readOnly = variable?.readOnly || false;
+ const required = variable?.required || false;
+ if (envValue.startsWith('$$config') || variable?.showOnConfiguration) {
+ if (envValue.startsWith('$$config_coolify')) {
+ continue;
+ }
+ parsedTemplate[realKey].environment.push({
+ id,
+ name: envKey,
+ value: envValue,
+ main,
+ label,
+ description,
+ defaultValue,
+ type,
+ placeholder,
+ required,
+ readOnly
+ });
+ }
+ }
+ }
+ }
+ if (value?.proxy && value.proxy.length > 0) {
+ for (const proxyValue of value.proxy) {
+ if (proxyValue.domain) {
+ const variable = foundTemplate?.variables.find((v) => v.id === proxyValue.domain);
+ if (variable) {
+ const { id, name, label, description, defaultValue, required = false } = variable;
+ const found = await prisma.serviceSetting.findFirst({
+ where: { serviceId: service.id, variableName: proxyValue.domain }
+ });
+ parsedTemplate[realKey].fqdns.push({
+ id,
+ name,
+ value: found?.value || '',
+ label,
+ description,
+ defaultValue,
+ required
+ });
+ }
+ }
+ if (proxyValue.hostPort) {
+ const variable = foundTemplate?.variables.find((v) => v.id === proxyValue.hostPort);
+ if (variable) {
+ const { id, name, label, description, defaultValue, required = false } = variable;
+ const found = await prisma.serviceSetting.findFirst({
+ where: { serviceId: service.id, variableName: proxyValue.hostPort }
+ });
+ parsedTemplate[realKey].hostPorts.push({
+ id,
+ name,
+ value: found?.value || '',
+ label,
+ description,
+ defaultValue,
+ required
+ });
+ }
+ }
+ }
+ }
+ }
+ } else {
+ parsedTemplate = foundTemplate;
+ }
+ let strParsedTemplate = JSON.stringify(parsedTemplate);
+
+ // replace $$id and $$workdir
+ strParsedTemplate = strParsedTemplate.replaceAll('$$id', service.id);
+ strParsedTemplate = strParsedTemplate.replaceAll(
+ '$$core_version',
+ service.version || foundTemplate.defaultVersion
+ );
+
+ // replace $$workdir
+ if (workdir) {
+ strParsedTemplate = strParsedTemplate.replaceAll('$$workdir', workdir);
+ }
+
+ // replace $$config
+ if (service.serviceSetting.length > 0) {
+ for (const setting of service.serviceSetting) {
+ const { value, variableName } = setting;
+ const regex = new RegExp(`\\$\\$config_${variableName.replace('$$config_', '')}\"`, 'gi');
+ if (value === '$$generate_fqdn') {
+ strParsedTemplate = strParsedTemplate.replaceAll(regex, service.fqdn + '"' || '' + '"');
+ } else if (value === '$$generate_fqdn_slash') {
+ strParsedTemplate = strParsedTemplate.replaceAll(regex, service.fqdn + '/' + '"');
+ } else if (value === '$$generate_domain') {
+ strParsedTemplate = strParsedTemplate.replaceAll(regex, getDomain(service.fqdn) + '"');
+ } else if (service.destinationDocker?.network && value === '$$generate_network') {
+ strParsedTemplate = strParsedTemplate.replaceAll(
+ regex,
+ service.destinationDocker.network + '"'
+ );
+ } else {
+ strParsedTemplate = strParsedTemplate.replaceAll(regex, value + '"');
+ }
+ }
+ }
+
+ // replace $$secret
+ if (service.serviceSecret.length > 0) {
+ for (const secret of service.serviceSecret) {
+ let { name, value } = secret;
+ name = name.toLowerCase();
+ const regexHashed = new RegExp(`\\$\\$hashed\\$\\$secret_${name}`, 'gi');
+ const regex = new RegExp(`\\$\\$secret_${name}`, 'gi');
+ if (value) {
+ strParsedTemplate = strParsedTemplate.replaceAll(
+ regexHashed,
+ bcrypt.hashSync(value.replaceAll('"', '\\"'), 10)
+ );
+ strParsedTemplate = strParsedTemplate.replaceAll(regex, value.replaceAll('"', '\\"'));
+ } else {
+ strParsedTemplate = strParsedTemplate.replaceAll(regexHashed, '');
+ strParsedTemplate = strParsedTemplate.replaceAll(regex, '');
+ }
+ }
+ }
+ parsedTemplate = JSON.parse(strParsedTemplate);
+ }
+ return parsedTemplate;
+}
+export function generatePassword({
+ length = 24,
+ symbols = false,
+ isHex = false
+}: { length?: number; symbols?: boolean; isHex?: boolean } | null): string {
+ if (isHex) {
+ return crypto.randomBytes(length).toString('hex');
+ }
+ const password = generator.generate({
+ length,
+ numbers: true,
+ strict: true,
+ symbols
+ });
+
+ return password;
+}
+
+export async function getFreePublicPort({ id, remoteEngine, engine, remoteIpAddress }) {
+ const { default: isReachable } = await import('is-port-reachable');
+ const data = await prisma.setting.findFirst();
+ const { minPort, maxPort } = data;
+ if (remoteEngine) {
+ const dbUsed = await (
+ await prisma.database.findMany({
+ where: {
+ publicPort: { not: null },
+ id: { not: id },
+ destinationDocker: { remoteIpAddress }
+ },
+ select: { publicPort: true }
+ })
+ ).map((a) => a.publicPort);
+ const wpFtpUsed = await (
+ await prisma.wordpress.findMany({
+ where: {
+ ftpPublicPort: { not: null },
+ id: { not: id },
+ service: { destinationDocker: { remoteIpAddress } }
+ },
+ select: { ftpPublicPort: true }
+ })
+ ).map((a) => a.ftpPublicPort);
+ const wpUsed = await (
+ await prisma.wordpress.findMany({
+ where: {
+ mysqlPublicPort: { not: null },
+ id: { not: id },
+ service: { destinationDocker: { remoteIpAddress } }
+ },
+ select: { mysqlPublicPort: true }
+ })
+ ).map((a) => a.mysqlPublicPort);
+ const minioUsed = await (
+ await prisma.minio.findMany({
+ where: {
+ publicPort: { not: null },
+ id: { not: id },
+ service: { destinationDocker: { remoteIpAddress } }
+ },
+ select: { publicPort: true }
+ })
+ ).map((a) => a.publicPort);
+ const usedPorts = [...dbUsed, ...wpFtpUsed, ...wpUsed, ...minioUsed];
+ const range = generateRangeArray(minPort, maxPort);
+ const availablePorts = range.filter((port) => !usedPorts.includes(port));
+ for (const port of availablePorts) {
+ const found = await isReachable(port, { host: remoteIpAddress });
+ if (!found) {
+ return port;
+ }
+ }
+ return false;
+ } else {
+ const dbUsed = await (
+ await prisma.database.findMany({
+ where: { publicPort: { not: null }, id: { not: id }, destinationDocker: { engine } },
+ select: { publicPort: true }
+ })
+ ).map((a) => a.publicPort);
+ const wpFtpUsed = await (
+ await prisma.wordpress.findMany({
+ where: {
+ ftpPublicPort: { not: null },
+ id: { not: id },
+ service: { destinationDocker: { engine } }
+ },
+ select: { ftpPublicPort: true }
+ })
+ ).map((a) => a.ftpPublicPort);
+ const wpUsed = await (
+ await prisma.wordpress.findMany({
+ where: {
+ mysqlPublicPort: { not: null },
+ id: { not: id },
+ service: { destinationDocker: { engine } }
+ },
+ select: { mysqlPublicPort: true }
+ })
+ ).map((a) => a.mysqlPublicPort);
+ const minioUsed = await (
+ await prisma.minio.findMany({
+ where: {
+ publicPort: { not: null },
+ id: { not: id },
+ service: { destinationDocker: { engine } }
+ },
+ select: { publicPort: true }
+ })
+ ).map((a) => a.publicPort);
+ const usedPorts = [...dbUsed, ...wpFtpUsed, ...wpUsed, ...minioUsed];
+ const range = generateRangeArray(minPort, maxPort);
+ const availablePorts = range.filter((port) => !usedPorts.includes(port));
+ for (const port of availablePorts) {
+ const found = await isReachable(port, { host: 'localhost' });
+ if (!found) {
+ return port;
+ }
+ }
+ return false;
+ }
+}
+
+export async function verifyAndDecryptServiceSecrets(id: string) {
+ const secrets = await prisma.serviceSecret.findMany({ where: { serviceId: id } })
+ let decryptedSecrets = secrets.map(secret => {
+ const { name, value } = secret
+ if (value) {
+ let rawValue = decrypt(value)
+ rawValue = rawValue.replaceAll(/\$/gi, '$$$')
+ return { name, value: rawValue }
+ }
+ return { name, value }
+
+ })
+ return decryptedSecrets
+}
+
+export function persistentVolumes(id, persistentStorage, config) {
+ let volumeSet = new Set();
+ if (Object.keys(config).length > 0) {
+ for (const [key, value] of Object.entries(config)) {
+ if (value.volumes) {
+ for (const volume of value.volumes) {
+ if (!volume.startsWith('/')) {
+ volumeSet.add(volume);
+ }
+ }
+ }
+ }
+ }
+ const volumesArray = Array.from(volumeSet);
+ const persistentVolume =
+ persistentStorage?.map((storage) => {
+ return `${id}${storage.path.replace(/\//gi, '-')}:${storage.path}`;
+ }) || [];
+
+ let volumes = [...persistentVolume];
+ if (volumesArray) volumes = [...volumesArray, ...volumes];
+ const composeVolumes =
+ (volumes.length > 0 &&
+ volumes.map((volume) => {
+ return {
+ [`${volume.split(':')[0]}`]: {
+ name: volume.split(':')[0]
+ }
+ };
+ })) ||
+ [];
+
+ const volumeMounts = Object.assign({}, ...composeVolumes) || {};
+ return { volumeMounts };
+}
+
+export async function startServiceContainers(fastify, id, teamId, dockerId, composeFileDestination) {
+ try {
+ // fastify.io.to(teamId).emit(`start-service`, { serviceId: id, state: 'Pulling images...' })
+ await executeCommand({ dockerId, command: `docker compose -f ${composeFileDestination} pull` })
+ } catch (error) { }
+ // fastify.io.to(teamId).emit(`start-service`, { serviceId: id, state: 'Building images...' })
+ await executeCommand({ dockerId, command: `docker compose -f ${composeFileDestination} build --no-cache` })
+ // fastify.io.to(teamId).emit(`start-service`, { serviceId: id, state: 'Creating containers...' })
+ await executeCommand({ dockerId, command: `docker compose -f ${composeFileDestination} create` })
+ // fastify.io.to(teamId).emit(`start-service`, { serviceId: id, state: 'Starting containers...' })
+ await executeCommand({ dockerId, command: `docker compose -f ${composeFileDestination} start` })
+ await asyncSleep(1000);
+ await executeCommand({ dockerId, command: `docker compose -f ${composeFileDestination} up -d` })
+ // fastify.io.to(teamId).emit(`start-service`, { serviceId: id, state: 0 })
+}
\ No newline at end of file
diff --git a/apps/server/tags.json b/apps/server/tags.json
new file mode 100644
index 000000000..5d4ef05cd
--- /dev/null
+++ b/apps/server/tags.json
@@ -0,0 +1,1013 @@
+[
+ { "name": "directus-postgresql", "image": "directus/directus", "tags": ["9.22"] },
+ { "name": "whoogle", "image": "benbusby/whoogle-search", "tags": ["0.8.1"] },
+ { "name": "libretranslate", "image": "libretranslate/libretranslate", "tags": ["v1.3.8"] },
+ {
+ "name": "appsmith",
+ "image": "appsmith/appsmith-ce",
+ "tags": [
+ "v1.9.1",
+ "v1.8.15",
+ "v1.8.12",
+ "v1.8.10",
+ "v1.8.9",
+ "v1.8.7",
+ "v1.8.5",
+ "v1.8.3",
+ "v1.8.0",
+ "v1.7.13",
+ "v1.7.11",
+ "v1.7.8",
+ "v1.7.6",
+ "v1.7.4",
+ "v1.7.2",
+ "v1.7.1",
+ "v1.6.22",
+ "v1.6.20",
+ "v1.6.19",
+ "v1.6.17",
+ "v1.6.15",
+ "v1.6.13",
+ "v1.6.11",
+ "v1.6.9",
+ "v1.6.7",
+ "v1.6.5",
+ "v1.6.3",
+ "v1.6.1",
+ "v1.5.30",
+ "v1.5.28"
+ ]
+ },
+ {
+ "name": "appwrite",
+ "image": "appwrite/appwrite",
+ "tags": [
+ "1.2.0",
+ "1.1.2",
+ "1.1.0",
+ "1.0.3",
+ "1.0.1",
+ "1.0.0",
+ "0.15.2",
+ "0.15.0",
+ "0.14.2",
+ "0.14.0",
+ "0.13.4",
+ "0.13.2",
+ "0.13.0",
+ "0.12.3",
+ "0.12.1",
+ "0.12.0",
+ "0.11.2",
+ "0.11.0",
+ "0.10.4",
+ "0.10.2",
+ "0.10.0",
+ "0.9.3",
+ "0.9.1",
+ "0.8.0",
+ "0.7.1",
+ "0.6.2",
+ "0.6.0",
+ "0.5.2",
+ "0.5.0",
+ "0.3.1"
+ ]
+ },
+ {
+ "name": "fider",
+ "image": "getfider/fider",
+ "tags": [
+ "stable",
+ "master",
+ "main",
+ "dev",
+ "SHA_ee6e83cfaadadaa56ab76e089e01f5631af3506f",
+ "SHA_deb4f9b4f561d890d8a80e6872fea9a98a265cc6",
+ "SHA_d5cc307909d43447200483d76b5db74d8ed8349e",
+ "SHA_d1674476577a7fd3c88fc29f91c3f35f5bd6a260",
+ "SHA_d107cbb157abca6576110080736213efe0955cff",
+ "SHA_c9c55b2f5b33a76015241b97e03cfac1254b42a7",
+ "SHA_bcf451a3cb02d5c8a489fd30309249296057b084",
+ "SHA_bbfe419639514f949a042807addf0fde7d4de225",
+ "SHA_adc3afc4c7bcf96931a5f90cab65c282d860dbfd",
+ "SHA_ab5283ae95334f10b5041402dce79e333c472015",
+ "SHA_a3f4cb5ed0a4ee2d726705fc426636364aac17a1",
+ "SHA_a18224142bf51bc6463c3d22f45f62287902e9a6",
+ "SHA_8e5cff30d95963eaee2587488d351e0d658c8195",
+ "SHA_8cabe2817ce7ccaf2f0a9fdbb1b5d3411de87f81",
+ "SHA_7851f9da566132d87fa2a63004e78c3bc9c09c6c",
+ "SHA_6c0f2bed1754e9d579eb9575129a6e3dbc529c32",
+ "SHA_603508c8790d6a6fb1e852df1a58ead8e5b3ea6c",
+ "SHA_55efacf164a4749b50ee68ae8925e7dc9dfa3a0c",
+ "SHA_4bdd291ce61e5f5dfc063fa1b2d9be8c9ff1d4c4",
+ "SHA_3fba9cb6a9ceab0c78c6cff3220610f591f657cb",
+ "SHA_3d635b57606a9885babe91fe975b11429e0f2c38",
+ "SHA_3b794edbd9789a8aa38ecd3714bc536a675d3058",
+ "SHA_3570c454ad3252b690608f7bf8051737d8519f8a",
+ "SHA_263e2709fd145f3ea511e5557e170102899995b0",
+ "SHA_255c30ed012fc4c39ffc97efc1d3b00425b17c72",
+ "SHA_17f92b16ef790003338f0926fc8d791a9a61333c"
+ ]
+ },
+ {
+ "name": "ghost-mariadb",
+ "image": "bitnami/ghost",
+ "tags": [
+ "5.28.0",
+ "5.27.0",
+ "5.26.4",
+ "5.26.3",
+ "5.26.2",
+ "5.26.1",
+ "5.26.0",
+ "5.25.5",
+ "5.25.4",
+ "5.25.3",
+ "5.25.2",
+ "5.25.1",
+ "5.25.0",
+ "5.24.2",
+ "5.24.1",
+ "5.24.0",
+ "5.23.0",
+ "5.22.11",
+ "5.22.10",
+ "5.22.9",
+ "5.22.8",
+ "5.22.7",
+ "5.22.6",
+ "5.22.5",
+ "5.22.4",
+ "5.22.3",
+ "5.22.2",
+ "5.22.1",
+ "5.22.0",
+ "5.21.0",
+ "4.48.8"
+ ]
+ },
+ {
+ "name": "ghost-mysql",
+ "image": "library/ghost",
+ "tags": [
+ "5.28.0",
+ "5.27.0",
+ "5.26.4",
+ "5.26.3",
+ "5.26.2",
+ "5.26.1",
+ "5.25.5",
+ "5.25.3",
+ "5.25.2",
+ "5.25.1",
+ "5.25.0",
+ "5.24.2",
+ "5.24.1",
+ "5.23.0",
+ "5.22.11",
+ "5.22.10",
+ "5.22.9",
+ "5.22.8",
+ "5.22.4",
+ "5.22.1",
+ "5.20.0",
+ "5.19.3",
+ "5.19.0",
+ "5.18.0",
+ "5.17.2",
+ "5.17.1",
+ "5.17.0",
+ "5.16.2",
+ "5.14.2",
+ "5.14.1"
+ ]
+ },
+ {
+ "name": "ghost-only",
+ "image": "library/ghost",
+ "tags": [
+ "5.28.0",
+ "5.27.0",
+ "5.26.4",
+ "5.26.3",
+ "5.26.2",
+ "5.26.1",
+ "5.25.5",
+ "5.25.3",
+ "5.25.2",
+ "5.25.1",
+ "5.25.0",
+ "5.24.2",
+ "5.24.1",
+ "5.23.0",
+ "5.22.11",
+ "5.22.10",
+ "5.22.9",
+ "5.22.8",
+ "5.22.4",
+ "5.22.1",
+ "5.20.0",
+ "5.19.3",
+ "5.19.0",
+ "5.18.0",
+ "5.17.2",
+ "5.17.1",
+ "5.17.0",
+ "5.16.2",
+ "5.14.2",
+ "5.14.1"
+ ]
+ },
+ {
+ "name": "gitea",
+ "image": "gitea/gitea",
+ "tags": [
+ "1.18.0",
+ "1.17.4",
+ "1.17.3",
+ "1.17.2",
+ "1.17.1",
+ "1.17.0",
+ "1.16.9",
+ "1.16.8",
+ "1.16.7",
+ "1.16.6",
+ "1.16.5",
+ "1.16.4",
+ "1.16.3",
+ "1.16.2",
+ "1.16.1",
+ "1.16.0",
+ "1.15.11",
+ "1.15.10",
+ "1.15.9",
+ "1.15.8",
+ "1.15.7",
+ "1.15.6",
+ "1.15.5",
+ "1.15.4",
+ "1.15.3",
+ "1.15.2",
+ "1.15.1",
+ "1.15.0",
+ "1.14.7",
+ "1.14.6"
+ ]
+ },
+ {
+ "name": "glitchtip",
+ "image": "glitchtip/glitchtip",
+ "tags": [
+ "v3.0.2",
+ "v3.0.0",
+ "v2.0.7",
+ "v2.0.5",
+ "v2.0.2",
+ "v2.0.0",
+ "v1.12.4",
+ "v1.12.2",
+ "v1.12.0",
+ "v1.10.3",
+ "v1.10.1",
+ "v1.9.2",
+ "v1.9.0",
+ "v1.8.4",
+ "v1.8.2",
+ "v1.8.0",
+ "v1.7.1",
+ "v1.6.4",
+ "v1.6.2",
+ "v1.6.0",
+ "v1.5.3",
+ "v1.5.1",
+ "v1.4.1",
+ "v1.3.3",
+ "v1.3.1",
+ "v1.2.6",
+ "v1.2.4",
+ "v1.2.2",
+ "v1.2.0",
+ "v1.1.2"
+ ]
+ },
+ {
+ "name": "grafana",
+ "image": "grafana/grafana",
+ "tags": [
+ "9.3.2",
+ "9.3.1",
+ "9.3.0",
+ "9.2.8",
+ "9.2.7",
+ "9.2.6",
+ "9.2.5",
+ "9.2.4",
+ "9.2.3",
+ "9.2.2",
+ "9.2.1",
+ "9.2.0",
+ "9.1.8",
+ "9.1.7",
+ "9.1.6",
+ "9.1.5",
+ "9.1.4",
+ "9.1.3",
+ "9.1.2",
+ "9.1.1",
+ "9.1.0",
+ "9.0.9",
+ "9.0.8",
+ "9.0.7",
+ "9.0.6",
+ "9.0.5",
+ "9.0.4",
+ "9.0.3",
+ "9.0.2",
+ "9.0.1"
+ ]
+ },
+ {
+ "name": "hasura",
+ "image": "hasura/graphql-engine",
+ "tags": [
+ "v2.16.1",
+ "v2.16.0",
+ "v2.15.2",
+ "v2.14.1",
+ "v2.13.2",
+ "v2.12.1",
+ "v2.11.3",
+ "v2.10.2",
+ "v2.9.0",
+ "v2.8.4",
+ "v2.8.3",
+ "v2.8.2",
+ "v2.8.1",
+ "v2.8.0",
+ "v2.7.0",
+ "v2.6.2",
+ "v2.6.1",
+ "v2.6.0",
+ "v2.5.2",
+ "v2.5.1",
+ "v2.5.0",
+ "v2.4.0",
+ "v2.3.1",
+ "v2.3.0",
+ "v2.2.2",
+ "v2.2.1",
+ "v2.2.0",
+ "v2.1.1",
+ "v2.1.0",
+ "v2.0.10"
+ ]
+ },
+ {
+ "name": "keycloak",
+ "image": "quay.io/keycloak/keycloak",
+ "tags": [
+ "9.0.3",
+ "9.0.0",
+ "8.0.1",
+ "7.0.0",
+ "6.0.1",
+ "6.0.0",
+ "20.0.2",
+ "20.0.1",
+ "20.0.0",
+ "19.0.3",
+ "19.0.1",
+ "19.0.0",
+ "18.0.1",
+ "18.0.0",
+ "17.0.1",
+ "17.0.0",
+ "16.1.0",
+ "15.1.1",
+ "15.0.2",
+ "15.0.0",
+ "13.0.1",
+ "12.0.4",
+ "12.0.2",
+ "12.0.0",
+ "11.0.2",
+ "11.0.0",
+ "10.0.1"
+ ]
+ },
+ {
+ "name": "languagetool",
+ "image": "silviof/docker-languagetool",
+ "tags": ["latest", "6.0", "5.8", "5.7", "5.6", "5.5", "5.4", "5.3"]
+ },
+ {
+ "name": "lavalink",
+ "image": "fredboat/lavalink",
+ "tags": [
+ "v3.7",
+ "v3.6",
+ "v3-vda0b3a4b3916a7b1a2b79702de1143c3a6939810-SNAPSHOT",
+ "v3-vc92690c425390bd20f6c51643c67ba79ab85b7e0-SNAPSHOT",
+ "v3-vab81dcd46adf3e8a961dd57eacd2a1bde1233e6c-SNAPSHOT",
+ "v3-v9c9432704d6a4badfcbd06a57597c54bed8f4326-SNAPSHOT",
+ "v3-v3.0",
+ "v3-v3",
+ "v3-v124f8fae7dab299f9cdf1cb4c1715be455497286-SNAPSHOT",
+ "v3-",
+ "v3",
+ "v2.0.1",
+ "v2.0",
+ "v2",
+ "update-udpqueue-vb4a439d6147dbd8641ea4f265e8efc9f1e16e2d3-SNAPSHOT",
+ "update-udpqueue-",
+ "update-udpqueue",
+ "revert-713-fix-error-for-loading-jda-nas",
+ "refactor-github-actions",
+ "patch-update-lp",
+ "patch-update-github-actions",
+ "patch-more-configurable-github-actions",
+ "patch-lavaplayer-update",
+ "patch-lavaplayer-bump",
+ "patch-build-number",
+ "next-api-vd4db194cac7a839a3899857f1f6d7b910369309d-SNAPSHOT",
+ "next-api-vc2e018d5ffef54b2d17244b3d213e31723a084d6-SNAPSHOT",
+ "next-api-v42cb5f7c58e98d1911e87bffb35aee0a235b85f8-SNAPSHOT",
+ "next-api-v31a243bda80badbd7d643f68fc1f87e99639060f-SNAPSHOT",
+ "next-api-v17f6884434c2d70d1704b2322a951d9f07af8865-SNAPSHOT"
+ ]
+ },
+ {
+ "name": "meilisearch",
+ "image": "getmeili/meilisearch",
+ "tags": [
+ "v0.30.5",
+ "v0.30.3",
+ "v0.30.1",
+ "v0.30.0",
+ "v0.29.3",
+ "v0.29.1",
+ "v0.29.0",
+ "v0.28.1",
+ "v0.28.0",
+ "v0.27.1",
+ "v0.27.0",
+ "v0.26.1",
+ "v0.26.0",
+ "v0.25.1",
+ "v0.25.0",
+ "v0.23.1",
+ "v0.23.0",
+ "v0.21.1",
+ "v0.21.0",
+ "v0.20.0",
+ "v0.19.0",
+ "v0.18.1",
+ "v0.18.0",
+ "v0.17.0",
+ "v0.16.0",
+ "0.14.1",
+ "v0.14.1",
+ "v0.14.0",
+ "v0.12.0",
+ "v0.11.0"
+ ]
+ },
+ {
+ "name": "minio",
+ "image": "minio/minio",
+ "tags": [
+ "RELEASE.2023-01-06T18-11-18Z",
+ "RELEASE.2023-01-02T09-40-09Z",
+ "RELEASE.2022-12-12T19-27-27Z",
+ "RELEASE.2022-12-07T00-56-37Z",
+ "RELEASE.2022-12-02T19-19-22Z",
+ "RELEASE.2022-11-29T23-40-49Z",
+ "RELEASE.2022-11-26T22-43-32Z",
+ "RELEASE.2022-11-17T23-20-09Z",
+ "RELEASE.2022-11-11T03-44-20Z",
+ "RELEASE.2022-11-10T18-20-21Z",
+ "RELEASE.2022-11-08T05-27-07Z",
+ "RELEASE.2022-10-29T06-21-33Z",
+ "RELEASE.2022-10-24T18-35-07Z.hotfix.7906ac5be",
+ "RELEASE.2022-10-24T18-35-07Z",
+ "RELEASE.2022-10-21T22-37-48Z",
+ "RELEASE.2022-10-20T00-55-09Z",
+ "RELEASE.2022-10-15T19-57-03Z",
+ "RELEASE.2022-10-08T20-11-00Z",
+ "RELEASE.2022-10-05T14-58-27Z",
+ "RELEASE.2022-10-02T19-29-29Z",
+ "RELEASE.2022-09-25T15-44-53Z",
+ "RELEASE.2022-09-22T18-57-27Z",
+ "RELEASE.2022-09-17T00-09-45Z.hotfix.f76e5da9f",
+ "RELEASE.2022-09-17T00-09-45Z.fips",
+ "RELEASE.2022-09-07T22-25-02Z.fips",
+ "RELEASE.2022-09-01T23-53-36Z.fips",
+ "RELEASE.2022-08-26T19-53-15Z.fips",
+ "RELEASE.2022-08-25T07-17-05Z.fips",
+ "RELEASE.2022-08-22T23-53-06Z.hotfix.5fa3967bb",
+ "RELEASE.2022-08-22T23-53-06Z"
+ ]
+ },
+ {
+ "name": "n8n",
+ "image": "n8nio/n8n",
+ "tags": [
+ "0.210.1",
+ "0.210.0",
+ "0.209.4",
+ "0.209.3",
+ "0.209.2",
+ "0.209.1",
+ "0.209.0",
+ "0.208.1",
+ "0.208.0",
+ "0.207.1",
+ "0.207.0",
+ "0.206.1",
+ "0.205.0",
+ "0.204.0",
+ "0.203.1",
+ "0.202.1",
+ "0.202.0",
+ "0.201.0",
+ "0.200.1",
+ "0.199.0",
+ "0.198.1",
+ "0.198.0",
+ "0.197.1",
+ "0.197.0",
+ "0.196.0",
+ "0.195.5",
+ "0.195.4",
+ "0.195.3",
+ "0.195.2",
+ "0.195.1"
+ ]
+ },
+ {
+ "name": "nocodb",
+ "image": "nocodb/nocodb",
+ "tags": [
+ "0.100.1",
+ "0.99.1",
+ "0.98.4",
+ "0.98.2",
+ "0.98.0",
+ "0.96.4",
+ "0.96.2",
+ "0.96.0",
+ "0.92.3",
+ "0.91.10",
+ "0.91.9",
+ "0.91.7",
+ "0.91.0",
+ "0.90.10",
+ "0.90.7",
+ "0.90.4",
+ "0.90.2",
+ "0.90.0",
+ "0.84.15",
+ "0.84.12",
+ "0.84.8",
+ "0.84.6",
+ "0.84.2",
+ "0.84.1",
+ "0.83.6",
+ "0.83.3",
+ "0.83.1",
+ "0.82.0",
+ "0.81.0",
+ "0.11.46"
+ ]
+ },
+ {
+ "name": "openblocks",
+ "image": "openblocksdev/openblocks-ce",
+ "tags": ["latest", "heroku", "beta", "1.1.3", "1.1.2", "1.1.1", "1.1.0", "1.0.21"]
+ },
+ {
+ "name": "plausibleanalytics-arm",
+ "image": "plausible/analytics",
+ "tags": [
+ "v1.5.1",
+ "v1.5.0-rc.2",
+ "v1.5.0-rc.1",
+ "v1.5.0",
+ "v1.5",
+ "v1.4.4",
+ "v1.4.3",
+ "v1.4.2",
+ "v1.4.1",
+ "v1.4.0.rc.0",
+ "v1.4.0-rc.0",
+ "v1.4.0",
+ "v1.4",
+ "v1.3.0-rc.1",
+ "v1.3.0-rc.0",
+ "v1.3.0",
+ "v1.3",
+ "v1.2.1",
+ "v1.2.0",
+ "v1.2-rc.1",
+ "v1.2-rc.0",
+ "v1.2",
+ "v1.1.1",
+ "v1.1.0",
+ "v1.1",
+ "v1.0.0",
+ "v1.0",
+ "v1",
+ "stable",
+ "master"
+ ]
+ },
+ {
+ "name": "plausibleanalytics",
+ "image": "plausible/analytics",
+ "tags": [
+ "v1.5.1",
+ "v1.5.0-rc.2",
+ "v1.5.0-rc.1",
+ "v1.5.0",
+ "v1.5",
+ "v1.4.4",
+ "v1.4.3",
+ "v1.4.2",
+ "v1.4.1",
+ "v1.4.0.rc.0",
+ "v1.4.0-rc.0",
+ "v1.4.0",
+ "v1.4",
+ "v1.3.0-rc.1",
+ "v1.3.0-rc.0",
+ "v1.3.0",
+ "v1.3",
+ "v1.2.1",
+ "v1.2.0",
+ "v1.2-rc.1",
+ "v1.2-rc.0",
+ "v1.2",
+ "v1.1.1",
+ "v1.1.0",
+ "v1.1",
+ "v1.0.0",
+ "v1.0",
+ "v1",
+ "stable",
+ "master"
+ ]
+ },
+ {
+ "name": "pocketbase",
+ "image": "coollabsio/pocketbase",
+ "tags": [
+ "0.8.0-arm64",
+ "0.8.0-amd64",
+ "0.8.0-aarch64",
+ "0.8.0",
+ "0.10.2-arm64",
+ "0.10.2-amd64",
+ "0.10.2-aarch64",
+ "0.10.2"
+ ]
+ },
+ {
+ "name": "searxng",
+ "image": "searxng/searxng",
+ "tags": [
+ "2023.01.09-afd71a6c",
+ "2023.01.09-a90ed481",
+ "2023.01.08-54e63839",
+ "2023.01.08-4e735b28",
+ "2023.01.08-217395b8",
+ "2023.01.08-0c429d70",
+ "2023.01.07-cb7b0916",
+ "2023.01.07-a98c5156",
+ "2023.01.07-633ba8b1",
+ "2023.01.07-4e355564",
+ "2023.01.06-b241015e",
+ "2023.01.06-269a72ee",
+ "2023.01.05-aba969cc",
+ "2022.12.30-b6d98be7",
+ "2022.12.30-647a0aa9",
+ "2022.12.30-17516290",
+ "2022.12.29-d531f893",
+ "2022.12.29-9b31976c",
+ "2022.12.29-76cd808a",
+ "2022.12.29-3ec58b06",
+ "2022.12.29-174e6851",
+ "2022.12.26-0d489617",
+ "2022.12.23-e8f72d70",
+ "2022.12.23-a2d506d4",
+ "2022.12.22-d75ae7c8",
+ "2022.12.16-f5bd73d9",
+ "2022.12.16-b9274821",
+ "2022.12.16-42ca37a6",
+ "2022.12.16-2a51c856",
+ "2022.12.16-0dac581c"
+ ]
+ },
+ {
+ "name": "trilium",
+ "image": "zadam/trilium",
+ "tags": [
+ "0.57.4",
+ "0.57.2",
+ "0.56.1",
+ "0.55.1",
+ "0.54.2",
+ "0.53.2",
+ "0.52.4",
+ "0.52.2",
+ "0.51.2",
+ "0.50.3",
+ "0.50.1",
+ "0.49.5",
+ "0.49.3",
+ "0.48.9",
+ "0.48.7",
+ "0.48.4",
+ "0.48.2",
+ "0.47.8",
+ "0.47.6",
+ "0.47.4",
+ "0.47.2",
+ "0.46.7",
+ "0.46.5",
+ "0.45.10",
+ "0.45.9",
+ "0.45.7",
+ "0.45.5",
+ "0.45.3",
+ "0.44.8",
+ "0.44.6"
+ ]
+ },
+ {
+ "name": "umami-postgresql",
+ "image": "ghcr.io/umami-software/umami",
+ "tags": [
+ "postgresql-v1.39.5",
+ "postgresql-v1.39.4",
+ "postgresql-v1.39.3",
+ "postgresql-v1.39.2",
+ "postgresql-v1.39.1",
+ "postgresql-v1.39.0",
+ "postgresql-v1.38.0",
+ "postgresql-v1.37.0",
+ "postgresql-v1.36.1",
+ "postgresql-v1.36.0",
+ "postgresql-v1.35.0",
+ "postgresql-v1.34.0",
+ "postgresql-v1.33.3",
+ "postgresql-latest",
+ "mysql-v1.39.5",
+ "mysql-v1.39.4",
+ "mysql-v1.39.3",
+ "mysql-v1.39.2",
+ "mysql-v1.39.1",
+ "mysql-v1.39.0",
+ "mysql-v1.38.0",
+ "mysql-v1.37.0",
+ "mysql-v1.36.1",
+ "mysql-v1.36.0",
+ "mysql-v1.35.0",
+ "mysql-v1.34.0",
+ "mysql-v1.33.3",
+ "mysql-latest"
+ ]
+ },
+ {
+ "name": "umami",
+ "image": "ghcr.io/umami-software/umami",
+ "tags": [
+ "postgresql-v1.39.5",
+ "postgresql-v1.39.4",
+ "postgresql-v1.39.3",
+ "postgresql-v1.39.2",
+ "postgresql-v1.39.1",
+ "postgresql-v1.39.0",
+ "postgresql-v1.38.0",
+ "postgresql-v1.37.0",
+ "postgresql-v1.36.1",
+ "postgresql-v1.36.0",
+ "postgresql-v1.35.0",
+ "postgresql-v1.34.0",
+ "postgresql-v1.33.3",
+ "postgresql-latest",
+ "mysql-v1.39.5",
+ "mysql-v1.39.4",
+ "mysql-v1.39.3",
+ "mysql-v1.39.2",
+ "mysql-v1.39.1",
+ "mysql-v1.39.0",
+ "mysql-v1.38.0",
+ "mysql-v1.37.0",
+ "mysql-v1.36.1",
+ "mysql-v1.36.0",
+ "mysql-v1.35.0",
+ "mysql-v1.34.0",
+ "mysql-v1.33.3",
+ "mysql-latest"
+ ]
+ },
+ {
+ "name": "uptimekuma",
+ "image": "louislam/uptime-kuma",
+ "tags": [
+ "1.19.4",
+ "1.19.3",
+ "1.19.2",
+ "1.19.1",
+ "1.19.0",
+ "1.18.5",
+ "1.18.4",
+ "1.18.3",
+ "1.18.2",
+ "1.18.1",
+ "1.18.0",
+ "1.17.1",
+ "1.17.0",
+ "1.16.1",
+ "1.16.0",
+ "1.15.1",
+ "1.15.0",
+ "1.14.1",
+ "1.14.0",
+ "1.13.2",
+ "1.13.1",
+ "1.13.0",
+ "1.12.1",
+ "1.11.4",
+ "1.11.3",
+ "1.11.2",
+ "1.11.1",
+ "1.11.0",
+ "1.10.2",
+ "1.10.1"
+ ]
+ },
+ {
+ "name": "vaultwarden",
+ "image": "vaultwarden/server",
+ "tags": [
+ "1.27.0",
+ "1.26.0",
+ "1.25.2",
+ "1.25.1",
+ "1.25.0",
+ "1.24.0",
+ "1.23.1",
+ "1.23.0",
+ "1.22.2",
+ "1.22.1",
+ "1.22.0",
+ "1.21.0"
+ ]
+ },
+ {
+ "name": "vscodeserver",
+ "image": "codercom/code-server",
+ "tags": [
+ "4.9.1",
+ "4.9.0",
+ "4.8.3",
+ "4.8.2",
+ "4.8.1",
+ "4.8.0",
+ "4.7.0",
+ "4.6.0",
+ "4.5.1",
+ "4.4.0",
+ "4.2.0",
+ "4.0.2",
+ "3.11.1",
+ "3.10.2",
+ "3.10.0",
+ "3.9.3",
+ "3.9.1",
+ "3.8.1",
+ "3.7.4",
+ "3.7.2",
+ "3.7.0",
+ "3.6.1",
+ "3.5.0",
+ "3.4.0",
+ "3.3.0",
+ "3.2.0",
+ "3.1.1",
+ "3.1.0",
+ "3.0.2",
+ "3.0.0"
+ ]
+ },
+ {
+ "name": "weblate",
+ "image": "weblate/weblate",
+ "tags": [
+ "latest",
+ "edge-2023-01-10-1df5c9dd96a6d8650f6881942fecbe33e1884295",
+ "edge-2023-01-09-7029b7b6c630be7cdac07d1629573dd2b81bc05f",
+ "edge-2023-01-09-4b05a878aa25b2c544a4e77027769b5934ec561f",
+ "edge-2023-01-07-df50259ff209720b0fd3c983bd7a5d01b564149c",
+ "edge-2023-01-07-719b3034de0ed369cd63554ea652f11142b9a540",
+ "edge-2023-01-07-14d4aec6cd8e1e6e0b7c1dc3a9cf4a74ccfc5e37",
+ "edge-2023-01-07-00f2d980c4388d799ba0df3a27c10bf941b7edd3",
+ "edge-2023-01-04-e92fe933b22e36e92f6de57a0ecb16752852d815",
+ "edge-2023-01-04-4c413c6ba33c39a6b7f3238f255bc09c69e96345",
+ "edge-2023-01-02-fd57652cce9dd2a12c7ff1dc644f5a969e57ea76",
+ "edge-2023-01-02-738d270784bca0cfaaef59e6cfb8c307f68a9939",
+ "edge-2023-01-02-3f6a7a183bbda4dc2e8d7e468370adc6f9e50527",
+ "edge-2023-01-01-5580a7a4755bf71403c85999fb4dff2078293403",
+ "edge-2022-12-29-8f422f23930880809a26d1207f9e43315ef54ad2",
+ "edge-2022-12-28-375fd99195711641246ccd09e3ce394d6928eaef",
+ "edge-2022-12-25-358c8ce6071f2781ae027bbc3a46d906ce08d9e7",
+ "edge-2022-12-24-3e1503494ce06ad6ff32f02db1a7d59224e5c860",
+ "edge-2022-12-21-cac4b09f943fe97700e3a33b7caf23277d2fcc11",
+ "edge-2022-12-21-3a8dd1bf66a7295f3512346bc1c97d55c5649dcf",
+ "edge-2022-12-16-e93caa3b014543b716b946f2c7fbf4a8f9be6099",
+ "edge-2022-12-16-318a467d2e529a081e9ea9dbad993c1736ff1a00",
+ "edge-2022-12-16-1af41ec4bd3838f967d88b68dec8195419e01e6f",
+ "edge-2022-12-16-02e9d020b01d004655c3af20c68a30f6c4645c1a",
+ "edge-2022-12-15-a6af1384a0831b17c43da7262f80d0cfbc766835",
+ "edge-2022-12-15-a1c9f77b301a9e23fc05ef2adc4694cceb632c25",
+ "edge-2022-12-15-1305f7115ef79b75e638b097772680d9cadbd4d0",
+ "edge-2022-12-14-b400145f05687e647bd4c8192be99f7f04373fb5",
+ "edge-2022-12-12-c0db193a3baacd107c5f2c28c6e0af89c3d5afa3",
+ "edge-2022-12-09-647d40c67cf405870ba71a01584a42cfaec5915f"
+ ]
+ },
+ {
+ "name": "wordpress-only",
+ "image": "library/wordpress",
+ "tags": [
+ "php8.2-fpm-alpine",
+ "php8.2-fpm",
+ "php8.2-apache",
+ "php8.2",
+ "php8.1-fpm-alpine",
+ "php8.1-fpm",
+ "php8.1-apache",
+ "php8.1",
+ "php8.0-fpm-alpine",
+ "php8.0-fpm",
+ "php8.0-apache",
+ "php8.0",
+ "php7.4-fpm-alpine",
+ "php7.4-fpm",
+ "php7.4-apache",
+ "php7.4",
+ "php7.3-fpm-alpine",
+ "php7.3-fpm",
+ "php7.3-apache",
+ "php7.3",
+ "php7.2-fpm-alpine",
+ "php7.2-fpm",
+ "php7.2-apache",
+ "php7.2",
+ "php7.1-fpm-alpine",
+ "php7.1-fpm",
+ "php7.1-apache",
+ "php7.1",
+ "php7.0-fpm-alpine",
+ "php7.0-fpm"
+ ]
+ },
+ {
+ "name": "wordpress",
+ "image": "library/wordpress",
+ "tags": [
+ "php8.2-fpm-alpine",
+ "php8.2-fpm",
+ "php8.2-apache",
+ "php8.2",
+ "php8.1-fpm-alpine",
+ "php8.1-fpm",
+ "php8.1-apache",
+ "php8.1",
+ "php8.0-fpm-alpine",
+ "php8.0-fpm",
+ "php8.0-apache",
+ "php8.0",
+ "php7.4-fpm-alpine",
+ "php7.4-fpm",
+ "php7.4-apache",
+ "php7.4",
+ "php7.3-fpm-alpine",
+ "php7.3-fpm",
+ "php7.3-apache",
+ "php7.3",
+ "php7.2-fpm-alpine",
+ "php7.2-fpm",
+ "php7.2-apache",
+ "php7.2",
+ "php7.1-fpm-alpine",
+ "php7.1-fpm",
+ "php7.1-apache",
+ "php7.1",
+ "php7.0-fpm-alpine",
+ "php7.0-fpm"
+ ]
+ }
+]
diff --git a/apps/server/templates.json b/apps/server/templates.json
new file mode 100644
index 000000000..fc378ecb0
--- /dev/null
+++ b/apps/server/templates.json
@@ -0,0 +1 @@
+[{"templateVersion":"1.0.0","defaultVersion":"9.22","documentation":"https://docs.directus.io/getting-started/introduction.html","type":"directus-postgresql","name":"Directus","subname":"(PostgreSQL)","description":"Directus is a free and open-source headless CMS framework for managing custom SQL-based databases.","labels":["CMS","headless"],"services":{"$$id":{"name":"Directus","depends_on":["$$id-postgresql","$$id-redis"],"image":"directus/directus:$$core_version","volumes":["$$id-uploads:/directus/uploads","$$id-database:/directus/database","$$id-extensions:/directus/extensions"],"environment":["KEY=$$secret_key","SECRET=$$secret_secret","DB_CLIENT=pg","DB_CONNECTION_STRING=$$secret_db_connection_string","CACHE_ENABLED=true","CACHE_STORE=redis","CACHE_REDIS=$$secret_cache_redis","ADMIN_EMAIL=$$config_admin_email","ADMIN_PASSWORD=$$secret_admin_password","CACHE_AUTO_PURGE=true","PUBLIC_URL=$$config_public_url"],"ports":["8055"]},"$$id-postgresql":{"name":"Directus PostgreSQL","depends_on":[],"image":"postgres:14-alpine","volumes":["$$id-postgresql-data:/var/lib/postgresql/data"],"environment":["POSTGRES_USER=$$config_postgres_user","POSTGRES_PASSWORD=$$secret_postgres_password","POSTGRES_DB=$$config_postgres_db"],"ports":[]},"$$id-redis":{"name":"Directus Redis","depends_on":[],"image":"redis:7.0.4-alpine","command":"--maxmemory 512mb --maxmemory-policy allkeys-lru --maxmemory-samples 5","volumes":["$$id-redis:/data"],"environment":[]}},"variables":[{"id":"$$config_public_url","name":"PUBLIC_URL","label":"Public URL","defaultValue":"$$generate_fqdn","description":""},{"id":"$$secret_db_connection_string","name":"DB_CONNECTION_STRING","label":"Directus Database Url","defaultValue":"postgresql://$$config_postgres_user:$$secret_postgres_password@$$id-postgresql:5432/$$config_postgres_db","description":""},{"id":"$$config_postgres_db","main":"$$id-postgresql","name":"POSTGRES_DB","label":"Database","defaultValue":"directus","description":""},{"id":"$$config_postgres_user","main":"$$id-postgresql","name":"POSTGRES_USER","label":"User","defaultValue":"$$generate_username","description":""},{"id":"$$secret_postgres_password","main":"$$id-postgresql","name":"POSTGRES_PASSWORD","label":"Password","defaultValue":"$$generate_password","description":"","showOnConfiguration":true},{"id":"$$secret_cache_redis","name":"CACHE_REDIS","label":"Redis Url","defaultValue":"redis://$$id-redis:6379","description":""},{"id":"$$config_admin_email","name":"ADMIN_EMAIL","label":"Initial Admin Email","defaultValue":"admin@example.com","description":"The email address of the first user that is automatically created. You can change it later in Directus."},{"id":"$$secret_admin_password","name":"ADMIN_PASSWORD","label":"Initial Admin Password","defaultValue":"$$generate_password","description":"The password of the first user that is automatically created.","showOnConfiguration":true},{"id":"$$secret_key","name":"KEY","label":"Key","defaultValue":"$$generate_password","description":"Unique identifier for the project.","showOnConfiguration":true},{"id":"$$secret_secret","name":"SECRET","label":"Secret","defaultValue":"$$generate_password","description":"Secret string for the project.","showOnConfiguration":true}]},{"templateVersion":"1.0.0","defaultVersion":"v1.3.8","documentation":"https://github.com/LibreTranslate/LibreTranslate","description":"Free and Open Source Machine Translation API. 100% self-hosted, offline capable and easy to setup.","type":"libretranslate","name":"Libretranslate","labels":["translator","argos","python","libretranslate"],"services":{"$$id":{"name":"Libretranslate","image":"libretranslate/libretranslate:$$core_version","environment":["LT_HOST=0.0.0.0","LT_SUGGESTIONS=true","LT_CHAR_LIMIT=$$config_lt_char_limit","LT_REQ_LIMIT=$$config_lt_req_limit","LT_BATCH_LIMIT=$$config_lt_batch_limit","LT_GA_ID=$$config_lt_ga_id","LT_DISABLE_WEB_UI=$$config_lt_web_ui"],"volumes":["$$id-libretranslate:/libretranslate"],"ports":["5000"]}},"variables":[{"id":"$$config_lt_char_limit","name":"LT_CHAR_LIMIT","label":"Char limit","defaultValue":"5000","description":"Set character limit."},{"id":"$$config_lt_req_limit","name":"LT_REQ_LIMIT","label":"Request limit","defaultValue":"5000","description":"Set maximum number of requests per minute per client."},{"id":"$$config_lt_batch_limit","name":"LT_BATCH_LIMIT","label":"Batch Limit","defaultValue":"5000","description":"Set maximum number of texts to translate in a batch request."},{"id":"$$config_lt_ga_id","name":"LT_GA_ID","label":"Google Analytics ID","defaultValue":"","description":"Enable Google Analytics on the API client page by providing an ID"},{"id":"$$config_lt_web_ui","name":"LT_DISABLE_WEB_UI","label":"Web UI","defaultValue":"false","description":"Disable or enable web ui. True or false."}]},{"templateVersion":"1.0.0","defaultVersion":"0.8.1","documentation":"https://github.com/benbusby/whoogle-search","type":"whoogle","name":"Whoogle Search","description":"A self-hosted, ad-free, privacy-respecting metasearch engine","labels":["search","google"],"services":{"$$id":{"name":"Whoogle Search","documentation":"https://github.com/benbusby/whoogle-search","depends_on":[],"image":"benbusby/whoogle-search:$$core_version","cap_drop":["ALL"],"environment":["WHOOGLE_USER=$$config_whoogle_username","WHOOGLE_PASS=$$secret_whoogle_password","WHOOGLE_CONFIG_PREFERENCES_KEY=$$secret_whoogle_preferences_key"],"ulimits":{"nofile":{"soft":262144,"hard":262144}},"ports":["5000"]}},"variables":[{"id":"$$config_whoogle_username","name":"WHOOGLE_USER","label":"Whoogle User","defaultValue":"$$generate_username","description":"Username to log into Whoogle"},{"id":"$$secret_whoogle_password","name":"WHOOGLE_PASSWORD","label":"Whoogle Password","defaultValue":"$$generate_password","description":"Password to log into Whoogle","showOnConfiguration":true},{"id":"$$secret_whoogle_preferences_key","name":"WHOOGLE_CONFIG_PREFERENCES_KEY","label":"Whoogle preferences key","defaultValue":"$$generate_password","description":"password to encrypt preferences"}]},{"templateVersion":"1.0.0","defaultVersion":"1.1.3","documentation":"https://docs.openblocks.dev/","type":"openblocks","name":"Openblocks","description":"The Open Source Retool Alternative","services":{"$$id":{"image":"openblocksdev/openblocks-ce:$$core_version","volumes":["$$id-stacks-data:/openblocks-stacks"],"ports":["3000"]}}},{"templateVersion":"1.0.0","defaultVersion":"0.10.2","documentation":"https://pocketbase.io/docs/","type":"pocketbase","name":"Pocketbase","description":"Open Source realtime backend in 1 file","services":{"$$id":{"image":"coollabsio/pocketbase:$$core_version","volumes":["$$id-data:/app/pb_data"],"ports":["8080"]}}},{"templateVersion":"1.0.0","defaultVersion":"v1.5.1","documentation":"https://plausible.io/doc/","type":"plausibleanalytics-arm","name":"Plausible Analytics (ARM)","description":"A lightweight and open-source website analytics tool.","labels":["analytics","statistics","plausible","gdpr","no-cookie","google analytics"],"services":{"$$id":{"name":"Plausible Analytics","command":"sh -c \"sleep 10 && /entrypoint.sh db createdb && /entrypoint.sh db migrate && /entrypoint.sh db init-admin && /entrypoint.sh run\"","depends_on":["$$id-postgresql","$$id-clickhouse"],"image":"plausible/analytics:$$core_version","environment":["ADMIN_USER_EMAIL=$$config_admin_user_email","ADMIN_USER_NAME=$$config_admin_user_name","ADMIN_USER_PWD=$$secret_admin_user_pwd","BASE_URL=$$config_base_url","SECRET_KEY_BASE=$$secret_secret_key_base","DISABLE_AUTH=$$config_disable_auth","DISABLE_REGISTRATION=$$config_disable_registration","DATABASE_URL=$$secret_database_url","CLICKHOUSE_DATABASE_URL=$$secret_clickhouse_database_url"],"ports":["8000"]},"$$id-postgresql":{"name":"PostgreSQL","image":"postgres:14-alpine","volumes":["$$id-postgresql-data:/var/lib/postgresql/data"],"environment":["POSTGRES_PASSWORD=$$secret_postgres_password","POSTGRES_USER=$$config_postgres_user","POSTGRES_DB=$$config_postgres_db"]},"$$id-clickhouse":{"name":"Clickhouse","volumes":["$$id-clickhouse-data:/var/lib/clickhouse"],"image":"clickhouse/clickhouse-server:22.6-alpine","ulimits":{"nofile":{"soft":262144,"hard":262144}},"files":[{"location":"/etc/clickhouse-server/users.d/logging.xml","content":"warning true "},{"location":"/etc/clickhouse-server/config.d/logging.xml","content":"0 0 "},{"location":"/docker-entrypoint-initdb.d/init.query","content":"CREATE DATABASE IF NOT EXISTS plausible;"},{"location":"/docker-entrypoint-initdb.d/init-db.sh","content":"clickhouse client --queries-file /docker-entrypoint-initdb.d/init.query"}]}},"variables":[{"id":"$$config_base_url","name":"BASE_URL","label":"Base URL","defaultValue":"$$generate_fqdn","description":"You must set this to the FQDN of the Plausible Analytics instance. This is used to generate the links to the Plausible Analytics instance."},{"id":"$$secret_database_url","name":"DATABASE_URL","label":"Database URL for PostgreSQL","defaultValue":"postgresql://$$config_postgres_user:$$secret_postgres_password@$$id-postgresql:5432/$$config_postgres_db","description":""},{"id":"$$secret_clickhouse_database_url","name":"CLICKHOUSE_DATABASE_URL","label":"Database URL for Clickhouse","defaultValue":"http://$$id-clickhouse:8123/plausible","description":""},{"id":"$$config_admin_user_email","name":"ADMIN_USER_EMAIL","label":"Admin Email Address","defaultValue":"admin@example.com","description":"This is the admin email. Please change it."},{"id":"$$config_admin_user_name","name":"ADMIN_USER_NAME","label":"Admin User Name","defaultValue":"$$generate_username","description":"This is the admin username. Please change it."},{"id":"$$secret_admin_user_pwd","name":"ADMIN_USER_PWD","label":"Admin User Password","defaultValue":"$$generate_password","description":"This is the admin password. Please change it.","showOnConfiguration":true},{"id":"$$secret_secret_key_base","name":"SECRET_KEY_BASE","label":"Secret Key Base","defaultValue":"$$generate_hex(64)","description":""},{"id":"$$config_disable_auth","name":"DISABLE_AUTH","label":"Authentication","defaultValue":"false","description":""},{"id":"$$config_disable_registration","name":"DISABLE_REGISTRATION","label":"Registration","defaultValue":"true","description":""},{"id":"$$config_postgres_user","main":"$$id-postgresql","name":"POSTGRES_USER","label":"PostgreSQL Username","defaultValue":"postgresql","description":""},{"id":"$$secret_postgres_password","main":"$$id-postgresql","name":"POSTGRES_PASSWORD","label":"PostgreSQL Password","defaultValue":"$$generate_password","description":"","showOnConfiguration":true},{"id":"$$config_postgres_db","main":"$$id-postgresql","name":"POSTGRES_DB","label":"PostgreSQL Database","defaultValue":"plausible","description":""},{"id":"$$config_scriptName","name":"SCRIPT_NAME","label":"Custom Script Name","defaultValue":"plausible.js","description":"This is the default script name."}]},{"templateVersion":"1.0.0","defaultVersion":"1.17","documentation":"https://docs.gitea.io","type":"gitea","name":"Gitea","description":"Gitea is a community managed lightweight code hosting solution written in Go.","labels":["storage","git"],"services":{"$$id":{"name":"Gitea","documentation":"https://docs.gitea.io","image":"gitea/gitea:$$core_version","volumes":["$$id-data:/data","/etc/timezone:/etc/timezone:ro","/etc/localtime:/etc/localtime:ro"],"environment":["USER_UID=1000","USER_GID=1000","DOMAIN=$$config_domain","SSH_DOMAIN=$$config_ssh_domain","ROOT_URL=$$config_root_url","SECRET_KEY=$$secret_secret_key","INTERNAL_TOKEN=$$secret_internal_token","SSH_PORT=22","START_SSH_SERVER=$$config_start_ssh_server"],"ports":["3000","22"],"proxy":[{"port":"22","hostPort":"$$config_hostport_ssh"}]}},"variables":[{"id":"$$config_hostport_ssh","name":"SSH_PORT","label":"SSH Port","defaultValue":"8022","description":"","required":true},{"id":"$$config_domain","name":"DOMAIN","label":"Domain","defaultValue":"$$generate_domain","description":""},{"id":"$$config_ssh_domain","name":"SSH_DOMAIN","label":"SSH Domain","defaultValue":"$$generate_domain","description":""},{"id":"$$config_start_ssh_server","name":"START_SSH_SERVER","label":"Start SSH Server","defaultValue":"true","description":""},{"id":"$$config_root_url","name":"ROOT_URL","label":"Root URL of Gitea","defaultValue":"$$generate_fqdn_slash","description":""},{"id":"$$secret_secret_key","name":"SECRET_KEY","label":"Secret Key","defaultValue":"$$generate_hex(32)","description":""},{"id":"$$secret_internal_token","name":"INTERNAL_TOKEN","label":"Internal JWT Token","defaultValue":"$$generate_token","description":""}]},{"templateVersion":"1.0.0","defaultVersion":"20.0","documentation":"https://www.keycloak.org/documentation","type":"keycloak","name":"Keycloak","description":"Keycloak provides user federation, strong authentication, user management, fine-grained authorization, and more.","labels":["authentication","authorization","oidconnect","saml2"],"services":{"$$id":{"name":"Keycloak","command":"start --db=postgres --features=token-exchange --import-realm","depends_on":["$$id-postgresql"],"image":"quay.io/keycloak/keycloak:$$core_version","volumes":["$$id-import:/opt/keycloak/data/import"],"environment":["KC_HEALTH_ENABLED=true","KC_PROXY=edge","KC_DB=postgres","KC_HOSTNAME=$$config_keycloak_domain","KEYCLOAK_ADMIN=$$config_admin_user","KEYCLOAK_ADMIN_PASSWORD=$$secret_keycloak_admin_password","KC_DB_PASSWORD=$$secret_postgres_password","KC_DB_USERNAME=$$config_postgres_user","KC_DB_URL=$$secret_keycloak_database_url"],"ports":["8080"]},"$$id-postgresql":{"name":"PostgreSQL","depends_on":[],"image":"postgres:14-alpine","volumes":["$$id-postgresql-data:/var/lib/postgresql/data"],"environment":["POSTGRES_USER=$$config_postgres_user","POSTGRES_PASSWORD=$$secret_postgres_password","POSTGRES_DB=$$config_postgres_db"],"ports":[]}},"variables":[{"id":"$$config_keycloak_domain","name":"KEYCLOAK_DOMAIN","label":"Keycloak Domain","defaultValue":"$$generate_domain","description":""},{"id":"$$secret_keycloak_database_url","name":"KEYCLOAK_DATABASE_URL","label":"Keycloak Database Url","defaultValue":"jdbc:postgresql://$$id-postgresql:5432/$$config_postgres_db","description":""},{"id":"$$config_admin_user","name":"KEYCLOAK_ADMIN","label":"Keycloak Admin User","defaultValue":"$$generate_username","description":""},{"id":"$$secret_keycloak_admin_password","name":"KEYCLOAK_ADMIN_PASSWORD","label":"Keycloak Admin Password","defaultValue":"$$generate_password","description":"","showOnConfiguration":true},{"id":"$$config_postgres_user","main":"$$id-postgresql","name":"POSTGRES_USER","label":"PostgreSQL User","defaultValue":"$$generate_username","description":""},{"id":"$$secret_postgres_password","main":"$$id-postgresql","name":"POSTGRES_PASSWORD","label":"PostgreSQL Password","defaultValue":"$$generate_password","description":"","showOnConfiguration":true},{"id":"$$config_postgres_db","main":"$$id-postgresql","name":"POSTGRES_DB","label":"PostgreSQL Database","defaultValue":"keycloak","description":""}]},{"templateVersion":"1.0.0","defaultVersion":"v3.7","documentation":"https://github.com/freyacodes/Lavalink","description":"Standalone audio sending node based on Lavaplayer.","type":"lavalink","name":"Lavalink","labels":["discord","discord bot","audio","lavalink","jda"],"services":{"$$id":{"name":"Lavalink","image":"fredboat/lavalink:$$core_version","environment":[],"volumes":["$$id-lavalink:/lavalink"],"ports":["$$config_port"],"files":[{"location":"/opt/Lavalink/application.yml","content":"server:\n port: 2333\n address: 0.0.0.0\nlavalink:\n server:\n password: \"$$secret_password\"\n sources:\n youtube: true\n bandcamp: true\n soundcloud: true\n twitch: true\n vimeo: true\n http: true\n local: false\n\nlogging:\n file:\n path: ./logs/\n\n level:\n root: INFO\n lavalink: INFO\n\n logback:\n rollingpolicy:\n max-file-size: 1GB\n max-history: 30"}]}},"variables":[{"id":"$$secret_password","name":"PASSWORD","label":"Password","defaultValue":"$$generate_password","required":true}]},{"templateVersion":"1.0.0","defaultVersion":"v1.8.9","documentation":"https://docs.appsmith.com/getting-started/setup/instance-configuration/","type":"appsmith","name":"Appsmith","description":"Fastest way to build internal apps over any database or API.","services":{"$$id":{"image":"appsmith/appsmith-ce:$$core_version","environment":["APPSMITH_MAIL_ENABLED=$$config_appsmith_mail_enabled","APPSMITH_DISABLE_TELEMETRY=$$config_appsmith_disable_telemetry","APPSMITH_DISABLE_INTERCOM=$$config_appsmith_disable_intercom"],"volumes":["$$id-stacks-data:/appsmith-stacks"],"ports":["80"]}},"variables":[{"id":"$$config_appsmith_mail_enabled","name":"APPSMITH_MAIL_ENABLED","label":"Enable Mail","defaultValue":"false","description":""},{"id":"$$config_appsmith_disable_telemetry","name":"APPSMITH_DISABLE_TELEMETRY","label":"Disable Telemetry","defaultValue":"true","description":""},{"id":"$$config_appsmith_disable_intercom","name":"APPSMITH_DISABLE_INTERCOM","label":"Disable Intercom","defaultValue":"true","description":""}]},{"templateVersion":"1.0.0","defaultVersion":"0.57.4","documentation":"https://hub.docker.com/r/zadam/trilium","description":"A hierarchical note taking application with focus on building large personal knowledge bases.","labels":["personal","knowledge","notes","wiki"],"type":"trilium","name":"Trilium Notes","services":{"$$id":{"image":"zadam/trilium:$$core_version","environment":[],"volumes":["$$id-trilium:/home/node/trilium-data"],"ports":["8080"]}},"variables":[]},{"templateVersion":"1.0.0","defaultVersion":"1.18.5","documentation":"https://hub.docker.com/r/louislam/uptime-kuma","description":"A free & fancy self-hosted monitoring tool.","labels":["uptime"],"type":"uptimekuma","name":"UptimeKuma","services":{"$$id":{"image":"louislam/uptime-kuma:$$core_version","environment":[],"volumes":["$$id-uptimekuma:/app/data"],"ports":["3001"]}},"variables":[]},{"templateVersion":"1.0.0","defaultVersion":"5.8","documentation":"https://hub.docker.com/r/silviof/docker-languagetool","description":"A multilingual grammar, style and spell checker.","type":"languagetool","name":"LanguageTool","services":{"$$id":{"image":"silviof/docker-languagetool:$$core_version","environment":[],"volumes":["$$id-ngrams:/ngrams"],"ports":["8010"]}},"variables":[]},{"templateVersion":"1.0.0","defaultVersion":"1.26.0","documentation":"https://hub.docker.com/r/vaultwarden/server","description":"Bitwarden compatible server written in Rust.","type":"vaultwarden","name":"VaultWarden","labels":["bitwarden","password manager"],"services":{"$$id":{"image":"vaultwarden/server:$$core_version","environment":[],"volumes":["$$id-data:/data"],"ports":["80"]}},"variables":[]},{"templateVersion":"1.0.0","defaultVersion":"9.3.1","documentation":"https://hub.docker.com/r/grafana/grafana","type":"grafana","name":"Grafana","description":"Grafana allows you to query, visualize, alert on and understand your metrics.","labels":["monitoring","metrics","dashboard"],"services":{"$$id":{"image":"grafana/grafana:$$core_version","environment":[],"volumes":["$$id-config:/etc/grafana","$$id-grafana:/var/lib/grafana"],"ports":["3000"]}},"variables":[]},{"templateVersion":"1.0.0","defaultVersion":"1.1.2","documentation":"https://appwrite.io/docs","type":"appwrite","name":"Appwrite","description":"Secure Backend Server for Web, Mobile & Flutter Developers.","labels":["serverless","backend","storage","api"],"services":{"$$id":{"image":"appwrite/appwrite:$$core_version","environment":["_APP_ENV=$$config__app_env","_APP_WORKER_PER_CORE=$$config__app_worker_per_core","_APP_LOCALE=$$config__app_locale","_APP_CONSOLE_WHITELIST_ROOT=$$config__app_console_whitelist_root","_APP_CONSOLE_WHITELIST_EMAILS=$$config__app_console_whitelist_emails","_APP_CONSOLE_WHITELIST_IPS=$$config__app_console_whitelist_ips","_APP_SYSTEM_EMAIL_NAME=$$config__app_system_email_name","_APP_SYSTEM_EMAIL_ADDRESS=$$config__app_system_email_address","_APP_SYSTEM_SECURITY_EMAIL_ADDRESS=$$config__app_system_security_email_address","_APP_SYSTEM_RESPONSE_FORMAT=$$config__app_system_response_format","_APP_OPTIONS_ABUSE=$$config__app_options_abuse","_APP_OPTIONS_FORCE_HTTPS=$$config__app_options_force_https","_APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1","_APP_DOMAIN=$$config__app_domain","_APP_DOMAIN_TARGET=$$config__app_domain_target","_APP_REDIS_HOST=$$config__app_redis_host","_APP_REDIS_PORT=$$config__app_redis_port","_APP_REDIS_USER=$$config__app_redis_user","_APP_REDIS_PASS=$$secret__app_redis_pass","_APP_DB_HOST=$$config__app_db_host","_APP_DB_PORT=$$config__app_db_port","_APP_DB_SCHEMA=$$config__app_db_schema","_APP_DB_USER=$$config__app_db_user","_APP_DB_PASS=$$secret__app_db_pass","_APP_SMTP_HOST=$$config__app_smtp_host","_APP_SMTP_PORT=$$config__app_smtp_port","_APP_SMTP_SECURE=$$config__app_smtp_secure","_APP_SMTP_USERNAME=$$config__app_smtp_username","_APP_SMTP_PASSWORD=$$secret__app_smtp_password","_APP_USAGE_STATS=$$config__app_usage_stats","_APP_INFLUXDB_HOST=$$config__app_influxdb_host","_APP_INFLUXDB_PORT=$$config__app_influxdb_port","_APP_STORAGE_LIMIT=$$config__app_storage_limit","_APP_STORAGE_PREVIEW_LIMIT=$$config__app_storage_preview_limit","_APP_STORAGE_ANTIVIRUS=$$config__app_storage_antivirus_enabled","_APP_STORAGE_ANTIVIRUS_HOST=$$config__app_storage_antivirus_host","_APP_STORAGE_ANTIVIRUS_PORT=$$config__app_storage_antivirus_port","_APP_STORAGE_DEVICE=$$config__app_storage_device","_APP_STORAGE_S3_ACCESS_KEY=$$secret__app_storage_s3_access_key","_APP_STORAGE_S3_SECRET=$$secret__app_storage_s3_secret","_APP_STORAGE_S3_REGION=$$config__app_storage_s3_region","_APP_STORAGE_S3_BUCKET=$$config__app_storage_s3_bucket","_APP_STORAGE_DO_SPACES_ACCESS_KEY=$$secret__app_storage_do_spaces_access_key","_APP_STORAGE_DO_SPACES_SECRET=$$secret__app_storage_do_spaces_secret","_APP_STORAGE_DO_SPACES_REGION=$$config__app_storage_do_spaces_region","_APP_STORAGE_DO_SPACES_BUCKET=$$config__app_storage_do_spaces_bucket","_APP_STORAGE_BACKBLAZE_ACCESS_KEY=$$secret__app_storage_backblaze_access_key","_APP_STORAGE_BACKBLAZE_SECRET=$$secret__app_storage_backblaze_secret","_APP_STORAGE_BACKBLAZE_REGION=$$config__app_storage_backblaze_region","_APP_STORAGE_BACKBLAZE_BUCKET=$$config__app_storage_backblaze_bucket","_APP_STORAGE_LINODE_ACCESS_KEY=$$secret__app_storage_linode_access_key","_APP_STORAGE_LINODE_SECRET=$$secret__app_storage_linode_secret","_APP_STORAGE_LINODE_REGION=$$config__app_storage_linode_region","_APP_STORAGE_LINODE_BUCKET=$$config__app_storage_linode_bucket","_APP_STORAGE_WASABI_ACCESS_KEY=$$secret__app_storage_wasabi_access_key","_APP_STORAGE_WASABI_SECRET=$$secret__app_storage_wasabi_secret","_APP_STORAGE_WASABI_REGION=$$config__app_storage_wasabi_region","_APP_STORAGE_WASABI_BUCKET=$$config__app_storage_wasabi_bucket","_APP_FUNCTIONS_SIZE_LIMIT=$$config__app_functions_size_limit","_APP_FUNCTIONS_TIMEOUT=$$config__app_functions_timeout","_APP_FUNCTIONS_BUILD_TIMEOUT=$$config__app_functions_build_timeout","_APP_FUNCTIONS_CONTAINERS=$$config__app_functions_containers","_APP_FUNCTIONS_CPUS=$$config__app_functions_cpus","_APP_FUNCTIONS_MEMORY=$$config__app_functions_memory_allocated","_APP_FUNCTIONS_MEMORY_SWAP=$$config__app_functions_memory_swap","_APP_FUNCTIONS_RUNTIMES=$$config__app_functions_runtimes","_APP_EXECUTOR_SECRET=$$secret__app_executor_secret","_APP_EXECUTOR_HOST=$$config__app_executor_host","_APP_LOGGING_PROVIDER=$$config__app_logging_provider","_APP_LOGGING_CONFIG=$$config__app_logging_config","_APP_STATSD_HOST=$$config__app_statsd_host","_APP_STATSD_PORT=$$config__app_statsd_port","_APP_MAINTENANCE_INTERVAL=$$config__app_maintenance_interval","_APP_MAINTENANCE_RETENTION_EXECUTION=$$config__app_maintenance_retention_execution","_APP_MAINTENANCE_RETENTION_CACHE=$$config__app_maintenance_retention_cache","_APP_MAINTENANCE_RETENTION_ABUSE=$$config__app_maintenance_retention_abuse","_APP_MAINTENANCE_RETENTION_AUDIT=$$config__app_maintenance_retention_audit","_APP_SMS_PROVIDER=$$config__app_sms_provider","_APP_SMS_FROM=$$config__app_sms_from","OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network"],"volumes":["$$id-uploads:/storage/uploads","$$id-cache:/storage/cache","$$id-config:/storage/config","$$id-certificates:/storage/certificates","$$id-functions:/storage/functions"],"ports":["80"],"proxy":[{"port":"80"}]},"$$id-executor":{"image":"appwrite/appwrite:$$core_version","environment":["_APP_ENV=$$config__app_env","_APP_FUNCTIONS_TIMEOUT=$$config__app_functions_timeout","_APP_FUNCTIONS_BUILD_TIMEOUT=$$config__app_functions_build_timeout","_APP_FUNCTIONS_CONTAINERS=$$config__app_functions_containers","_APP_FUNCTIONS_RUNTIMES=$$config__app_functions_runtimes","_APP_FUNCTIONS_CPUS=$$config__app_functions_cpus","_APP_FUNCTIONS_MEMORY=$$config__app_functions_memory_allocated","_APP_FUNCTIONS_MEMORY_SWAP=$$config__app_functions_memory_swap","_APP_FUNCTIONS_INACTIVE_THRESHOLD=$$config__app_functions_inactive_threshold","_APP_EXECUTOR_SECRET=$$secret__app_executor_secret","_APP_LOGGING_PROVIDER=$$config__app_logging_provider","_APP_LOGGING_CONFIG=$$config__app_logging_config","_APP_STORAGE_DEVICE=$$config__app_storage_device","_APP_STORAGE_S3_ACCESS_KEY=$$secret__app_storage_s3_access_key","_APP_STORAGE_S3_SECRET=$$secret__app_storage_s3_secret","_APP_STORAGE_S3_REGION=$$config__app_storage_s3_region","_APP_STORAGE_S3_BUCKET=$$config__app_storage_s3_bucket","_APP_STORAGE_DO_SPACES_ACCESS_KEY=$$secret__app_storage_do_spaces_access_key","_APP_STORAGE_DO_SPACES_SECRET=$$secret__app_storage_do_spaces_secret","_APP_STORAGE_DO_SPACES_REGION=$$config__app_storage_do_spaces_region","_APP_STORAGE_DO_SPACES_BUCKET=$$config__app_storage_do_spaces_bucket","_APP_STORAGE_BACKBLAZE_ACCESS_KEY=$$secret__app_storage_backblaze_access_key","_APP_STORAGE_BACKBLAZE_SECRET=$$secret__app_storage_backblaze_secret","_APP_STORAGE_BACKBLAZE_REGION=$$config__app_storage_backblaze_region","_APP_STORAGE_BACKBLAZE_BUCKET=$$config__app_storage_backblaze_bucket","_APP_STORAGE_LINODE_ACCESS_KEY=$$secret__app_storage_linode_access_key","_APP_STORAGE_LINODE_SECRET=$$secret__app_storage_linode_secret","_APP_STORAGE_LINODE_REGION=$$config__app_storage_linode_region","_APP_STORAGE_LINODE_BUCKET=$$config__app_storage_linode_bucket","_APP_STORAGE_WASABI_ACCESS_KEY=$$secret__app_storage_wasabi_access_key","_APP_STORAGE_WASABI_SECRET=$$secret__app_storage_wasabi_secret","_APP_STORAGE_WASABI_REGION=$$config__app_storage_wasabi_region","_APP_STORAGE_WASABI_BUCKET=$$config__app_storage_wasabi_bucket","DOCKERHUB_PULL_USERNAME=$$config_dockerhub_pull_username","DOCKERHUB_PULL_PASSWORD=$$secret_dockerhub_pull_password","OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network"],"volumes":["$$id-functions:/storage/functions","$$id-builds:/storage/builds","/var/run/docker.sock:/var/run/docker.sock","/tmp:/tmp:rw"],"entrypoint":"executor"},"$$id-influxdb":{"image":"appwrite/influxdb:1.5.0","environment":[],"volumes":["$$id-influxdb:/var/lib/influxdb"]},"$$id-maintenance":{"image":"appwrite/appwrite:$$core_version","environment":["_APP_ENV=$$config__app_env","_APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1","_APP_DOMAIN=$$config__app_domain","_APP_DOMAIN_TARGET=$$config__app_domain_target","_APP_REDIS_HOST=$$config__app_redis_host","_APP_REDIS_PORT=$$config__app_redis_port","_APP_REDIS_USER=$$config__app_redis_user","_APP_REDIS_PASS=$$secret__app_redis_pass","_APP_DB_HOST=$$config__app_db_host","_APP_DB_PORT=$$config__app_db_port","_APP_DB_SCHEMA=$$config__app_db_schema","_APP_DB_USER=$$config__app_db_user","_APP_DB_PASS=$$secret__app_db_pass","_APP_MAINTENANCE_INTERVAL=$$config__app_maintenance_interval","_APP_MAINTENANCE_RETENTION_EXECUTION=$$config__app_maintenance_retention_execution","_APP_MAINTENANCE_RETENTION_CACHE=$$config__app_maintenance_retention_cache","_APP_MAINTENANCE_RETENTION_ABUSE=$$config__app_maintenance_retention_abuse","_APP_MAINTENANCE_RETENTION_AUDIT=$$config__app_maintenance_retention_audit","OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network"],"volumes":[],"entrypoint":"maintenance"},"$$id-mariadb":{"image":"mariadb:10.7","command":"--innodb-flush-method fsync","environment":["MARIADB_ROOT_PASSWORD=$$secret__app_db_root_pass","MARIADB_DATABASE=$$config__app_db_schema","MARIADB_USER=$$config__app_db_user","MARIADB_PASSWORD=$$secret__app_db_pass","OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network"],"volumes":["$$id-mariadb:/var/lib/mysql"]},"$$id-realtime":{"image":"appwrite/appwrite:$$core_version","environment":["_APP_ENV=$$config__app_env","_APP_WORKER_PER_CORE=$$config__app_worker_per_core","_APP_OPTIONS_ABUSE=$$config__app_options_abuse","_APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1","_APP_REDIS_HOST=$$config__app_redis_host","_APP_REDIS_PORT=$$config__app_redis_port","_APP_DB_HOST=$$config__app_db_host","_APP_DB_PORT=$$config__app_db_port","_APP_DB_SCHEMA=$$config__app_db_schema","_APP_DB_USER=$$config__app_db_user","_APP_DB_PASS=$$secret__app_db_pass","_APP_USAGE_STATS=$$config__app_usage_stats","_APP_LOGGING_PROVIDER=$$config__app_logging_provider","_APP_LOGGING_CONFIG=$$config__app_logging_config","OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network"],"volumes":[],"entrypoint":"realtime","proxy":[{"port":"80","pathPrefix":"/v1/realtime"}]},"$$id-redis":{"image":"redis:7.0.4-alpine","command":"--maxmemory 512mb --maxmemory-policy allkeys-lru --maxmemory-samples 5","environment":[],"volumes":["$$id-redis:/data"]},"$$id-schedule":{"image":"appwrite/appwrite:$$core_version","environment":["_APP_ENV=$$config__app_env","_APP_REDIS_HOST=$$config__app_redis_host","_APP_REDIS_PORT=$$config__app_redis_port","_APP_REDIS_USER=$$config__app_redis_user","_APP_REDIS_PASS=$$secret__app_redis_pass","OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network"],"volumes":[],"entrypoint":"schedule"},"$$id-telegraf":{"image":"appwrite/telegraf:1.4.0","environment":["_APP_INFLUXDB_HOST=$$config__app_influxdb_host","_APP_INFLUXDB_PORT=$$config__app_influxdb_port","OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network"],"volumes":["$$id-influxdb:/var/lib/influxdb"]},"$$id-usage-database":{"image":"appwrite/appwrite:$$core_version","environment":["_APP_ENV=$$config__app_env","_APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1","_APP_DB_HOST=$$config__app_db_host","_APP_DB_PORT=$$config__app_db_port","_APP_DB_SCHEMA=$$config__app_db_schema","_APP_DB_USER=$$config__app_db_user","_APP_DB_PASS=$$secret__app_db_pass","_APP_INFLUXDB_HOST=$$config__app_influxdb_host","_APP_INFLUXDB_PORT=$$config__app_influxdb_port","_APP_USAGE_TIMESERIES_INTERVAL=$$config__app_usage_timeseries_interval","_APP_USAGE_DATABASE_INTERVAL=$$config__app_usage_database_interval","_APP_REDIS_HOST=$$config__app_redis_host","_APP_REDIS_PORT=$$config__app_redis_port","_APP_REDIS_USER=$$config__app_redis_user","_APP_REDIS_PASS=$$secret__app_redis_pass","_APP_LOGGING_PROVIDER=$$config__app_logging_provider","_APP_LOGGING_CONFIG=$$config__app_logging_config","OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network"],"volumes":[],"entrypoint":"usage --type database"},"$$id-usage":{"image":"appwrite/appwrite:$$core_version","environment":["_APP_ENV=$$config__app_env","_APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1","_APP_DB_HOST=$$config__app_db_host","_APP_DB_PORT=$$config__app_db_port","_APP_DB_SCHEMA=$$config__app_db_schema","_APP_DB_USER=$$config__app_db_user","_APP_DB_PASS=$$secret__app_db_pass","_APP_INFLUXDB_HOST=$$config__app_influxdb_host","_APP_INFLUXDB_PORT=$$config__app_influxdb_port","_APP_USAGE_TIMESERIES_INTERVAL=$$config__app_usage_timeseries_interval","_APP_USAGE_DATABASE_INTERVAL=$$config__app_usage_database_interval","_APP_REDIS_HOST=$$config__app_redis_host","_APP_REDIS_PORT=$$config__app_redis_port","_APP_REDIS_USER=$$config__app_redis_user","_APP_REDIS_PASS=$$secret__app_redis_pass","_APP_LOGGING_PROVIDER=$$config__app_logging_provider","_APP_LOGGING_CONFIG=$$config__app_logging_config","OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network"],"volumes":[],"entrypoint":"usage --type timeseries"},"$$id-worker-audits":{"image":"appwrite/appwrite:$$core_version","environment":["_APP_ENV=$$config__app_env","_APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1","_APP_REDIS_HOST=$$config__app_redis_host","_APP_REDIS_PORT=$$config__app_redis_port","_APP_REDIS_USER=$$config__app_redis_user","_APP_REDIS_PASS=$$secret__app_redis_pass","_APP_DB_HOST=$$config__app_db_host","_APP_DB_PORT=$$config__app_db_port","_APP_DB_SCHEMA=$$config__app_db_schema","_APP_DB_USER=$$config__app_db_user","_APP_DB_PASS=$$secret__app_db_pass","_APP_LOGGING_PROVIDER=$$config__app_logging_provider","_APP_LOGGING_CONFIG=$$config__app_logging_config","OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network"],"volumes":[],"entrypoint":"worker-audits"},"$$id-worker-builds":{"image":"appwrite/appwrite:$$core_version","environment":["_APP_ENV=$$config__app_env","_APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1","_APP_EXECUTOR_SECRET=$$secret__app_executor_secret","_APP_EXECUTOR_HOST=$$config__app_executor_host","_APP_REDIS_HOST=$$config__app_redis_host","_APP_REDIS_PORT=$$config__app_redis_port","_APP_REDIS_USER=$$config__app_redis_user","_APP_REDIS_PASS=$$secret__app_redis_pass","_APP_DB_HOST=$$config__app_db_host","_APP_DB_PORT=$$config__app_db_port","_APP_DB_SCHEMA=$$config__app_db_schema","_APP_DB_USER=$$config__app_db_user","_APP_DB_PASS=$$secret__app_db_pass","_APP_LOGGING_PROVIDER=$$config__app_logging_provider","_APP_LOGGING_CONFIG=$$config__app_logging_config","OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network"],"volumes":[],"entrypoint":"worker-builds"},"$$id-worker-certificates":{"image":"appwrite/appwrite:$$core_version","environment":["_APP_ENV=$$config__app_env","_APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1","_APP_DOMAIN=$$config__app_domain","_APP_DOMAIN_TARGET=$$config__app_domain_target","_APP_SYSTEM_SECURITY_EMAIL_ADDRESS=$$config__app_system_security_email_address","_APP_REDIS_HOST=$$config__app_redis_host","_APP_REDIS_PORT=$$config__app_redis_port","_APP_REDIS_USER=$$config__app_redis_user","_APP_REDIS_PASS=$$secret__app_redis_pass","_APP_DB_HOST=$$config__app_db_host","_APP_DB_PORT=$$config__app_db_port","_APP_DB_SCHEMA=$$config__app_db_schema","_APP_DB_USER=$$config__app_db_user","_APP_DB_PASS=$$secret__app_db_pass","_APP_LOGGING_PROVIDER=$$config__app_logging_provider","_APP_LOGGING_CONFIG=$$config__app_logging_config","OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network"],"volumes":["$$id-config:/storage/config","$$id-certificates:/storage/certificates"],"entrypoint":"worker-certificates"},"$$id-worker-databases":{"image":"appwrite/appwrite:$$core_version","environment":["_APP_ENV=$$config__app_env","_APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1","_APP_REDIS_HOST=$$config__app_redis_host","_APP_REDIS_PORT=$$config__app_redis_port","_APP_REDIS_USER=$$config__app_redis_user","_APP_REDIS_PASS=$$secret__app_redis_pass","_APP_DB_HOST=$$config__app_db_host","_APP_DB_PORT=$$config__app_db_port","_APP_DB_SCHEMA=$$config__app_db_schema","_APP_DB_USER=$$config__app_db_user","_APP_DB_PASS=$$secret__app_db_pass","_APP_LOGGING_PROVIDER=$$config__app_logging_provider","_APP_LOGGING_CONFIG=$$config__app_logging_config","OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network"],"volumes":[],"entrypoint":"worker-databases"},"$$id-worker-deletes":{"image":"appwrite/appwrite:$$core_version","environment":["_APP_ENV=$$config__app_env","_APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1","_APP_REDIS_HOST=$$config__app_redis_host","_APP_REDIS_PORT=$$config__app_redis_port","_APP_REDIS_USER=$$config__app_redis_user","_APP_REDIS_PASS=$$secret__app_redis_pass","_APP_DB_HOST=$$config__app_db_host","_APP_DB_PORT=$$config__app_db_port","_APP_DB_SCHEMA=$$config__app_db_schema","_APP_DB_USER=$$config__app_db_user","_APP_DB_PASS=$$secret__app_db_pass","_APP_STORAGE_DEVICE=$$config__app_storage_device","_APP_STORAGE_S3_ACCESS_KEY=$$secret__app_storage_s3_access_key","_APP_STORAGE_S3_SECRET=$$secret__app_storage_s3_secret","_APP_STORAGE_S3_REGION=$$config__app_storage_s3_region","_APP_STORAGE_S3_BUCKET=$$config__app_storage_s3_bucket","_APP_STORAGE_DO_SPACES_ACCESS_KEY=$$secret__app_storage_do_spaces_access_key","_APP_STORAGE_DO_SPACES_SECRET=$$secret__app_storage_do_spaces_secret","_APP_STORAGE_DO_SPACES_REGION=$$config__app_storage_do_spaces_region","_APP_STORAGE_DO_SPACES_BUCKET=$$config__app_storage_do_spaces_bucket","_APP_STORAGE_BACKBLAZE_ACCESS_KEY=$$secret__app_storage_backblaze_access_key","_APP_STORAGE_BACKBLAZE_SECRET=$$secret__app_storage_backblaze_secret","_APP_STORAGE_BACKBLAZE_REGION=$$config__app_storage_backblaze_region","_APP_STORAGE_BACKBLAZE_BUCKET=$$config__app_storage_backblaze_bucket","_APP_STORAGE_LINODE_ACCESS_KEY=$$secret__app_storage_linode_access_key","_APP_STORAGE_LINODE_SECRET=$$secret__app_storage_linode_secret","_APP_STORAGE_LINODE_REGION=$$config__app_storage_linode_region","_APP_STORAGE_LINODE_BUCKET=$$config__app_storage_linode_bucket","_APP_STORAGE_WASABI_ACCESS_KEY=$$secret__app_storage_wasabi_access_key","_APP_STORAGE_WASABI_SECRET=$$secret__app_storage_wasabi_secret","_APP_STORAGE_WASABI_REGION=$$config__app_storage_wasabi_region","_APP_STORAGE_WASABI_BUCKET=$$config__app_storage_wasabi_bucket","_APP_LOGGING_PROVIDER=$$config__app_logging_provider","_APP_LOGGING_CONFIG=$$config__app_logging_config","_APP_EXECUTOR_SECRET=$$secret__app_executor_secret","_APP_EXECUTOR_HOST=$$config__app_executor_host","OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network"],"volumes":["$$id-uploads:/storage/uploads","$$id-cache:/storage/cache","$$id-functions:/storage/functions","$$id-builds:/storage/builds","$$id-certificates:/storage/certificates"],"entrypoint":"worker-deletes"},"$$id-worker-functions":{"image":"appwrite/appwrite:$$core_version","environment":["_APP_ENV=$$config__app_env","_APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1","_APP_REDIS_HOST=$$config__app_redis_host","_APP_REDIS_PORT=$$config__app_redis_port","_APP_REDIS_USER=$$config__app_redis_user","_APP_REDIS_PASS=$$secret__app_redis_pass","_APP_DB_HOST=$$config__app_db_host","_APP_DB_PORT=$$config__app_db_port","_APP_DB_SCHEMA=$$config__app_db_schema","_APP_DB_USER=$$config__app_db_user","_APP_DB_PASS=$$secret__app_db_pass","_APP_FUNCTIONS_TIMEOUT=$$config__app_functions_timeout","_APP_EXECUTOR_SECRET=$$secret__app_executor_secret","_APP_EXECUTOR_HOST=$$config__app_executor_host","_APP_USAGE_STATS=$$config__app_usage_stats","DOCKERHUB_PULL_USERNAME=$$config_dockerhub_pull_username","DOCKERHUB_PULL_PASSWORD=$$secret_dockerhub_pull_password","OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network"],"volumes":[],"entrypoint":"worker-functions"},"$$id-worker-mails":{"image":"appwrite/appwrite:$$core_version","environment":["_APP_ENV=$$config__app_env","_APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1","_APP_SYSTEM_EMAIL_NAME=$$config__app_system_email_name","_APP_SYSTEM_EMAIL_ADDRESS=$$config__app_system_email_address","_APP_REDIS_HOST=$$config__app_redis_host","_APP_REDIS_PORT=$$config__app_redis_port","_APP_REDIS_USER=$$config__app_redis_user","_APP_REDIS_PASS=$$secret__app_redis_pass","_APP_SMTP_HOST=$$config__app_smtp_host","_APP_SMTP_PORT=$$config__app_smtp_port","_APP_SMTP_SECURE=$$config__app_smtp_secure","_APP_SMTP_USERNAME=$$config__app_smtp_username","_APP_SMTP_PASSWORD=$$secret__app_smtp_password","_APP_LOGGING_PROVIDER=$$config__app_logging_provider","_APP_LOGGING_CONFIG=$$config__app_logging_config","OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network"],"volumes":[],"entrypoint":"worker-mails"},"$$id-worker-messaging":{"image":"appwrite/appwrite:$$core_version","environment":["_APP_ENV=$$config__app_env","_APP_REDIS_HOST=$$config__app_redis_host","_APP_REDIS_PORT=$$config__app_redis_port","_APP_REDIS_USER=$$config__app_redis_user","_APP_REDIS_PASS=$$secret__app_redis_pass","_APP_SMS_PROVIDER=$$config__app_sms_provider","_APP_SMS_FROM=$$config__app_sms_from","_APP_LOGGING_PROVIDER=$$config__app_logging_provider","_APP_LOGGING_CONFIG=$$config__app_logging_config","OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network"],"volumes":[],"entrypoint":"worker-messaging"},"$$id-worker-webhooks":{"image":"appwrite/appwrite:$$core_version","environment":["_APP_ENV=$$config__app_env","_APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1","_APP_SYSTEM_SECURITY_EMAIL_ADDRESS=$$config__app_system_security_email_address","_APP_REDIS_HOST=$$config__app_redis_host","_APP_REDIS_PORT=$$config__app_redis_port","_APP_REDIS_USER=$$config__app_redis_user","_APP_REDIS_PASS=$$secret__app_redis_pass","_APP_LOGGING_PROVIDER=$$config__app_logging_provider","_APP_LOGGING_CONFIG=$$config__app_logging_config","OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network"],"volumes":[],"entrypoint":"worker-webhooks"}},"variables":[{"id":"$$config__app_influxdb_host","name":"_APP_INFLUXDB_HOST","label":"InfluxDB | _APP_INFLUXDB_HOST","defaultValue":"$$id-influxdb","description":""},{"id":"$$config__app_influxdb_port","name":"_APP_INFLUXDB_PORT","label":"InfluxDB | _APP_INFLUXDB_PORT","defaultValue":"8086","description":"InfluxDB server TCP port."},{"id":"$$config__app_env","name":"_APP_ENV","label":"General | _APP_ENV","defaultValue":"production","description":"Set your server running environment."},{"id":"$$config__app_worker_per_core","name":"_APP_WORKER_PER_CORE","label":"General | _APP_WORKER_PER_CORE","defaultValue":"6","description":"Internal Worker per core for the API, Realtime and Executor containers. Can be configured to optimize performance."},{"id":"$$config__app_locale","name":"_APP_LOCALE","label":"General | _APP_LOCALE","defaultValue":"en","description":"Set your Appwrite's locale. By default, the locale is set to 'en'."},{"id":"$$config__app_console_whitelist_root","name":"_APP_CONSOLE_WHITELIST_ROOT","label":"General | _APP_CONSOLE_WHITELIST_ROOT","defaultValue":"enabled","description":"This option allows you to disable the creation of new users on the Appwrite console. When enabled only 1 user will be able to use the registration form. New users can be added by inviting them to your project. By default this option is enabled."},{"id":"$$config__app_console_whitelist_emails","name":"_APP_CONSOLE_WHITELIST_EMAILS","label":"General | _APP_CONSOLE_WHITELIST_EMAILS","defaultValue":"","description":"This option allows you to limit creation of new users on the Appwrite console. This option is very useful for small teams or sole developers. To enable it, pass a list of allowed email addresses separated by a comma."},{"id":"$$config__app_console_whitelist_ips","name":"_APP_CONSOLE_WHITELIST_IPS","label":"General | _APP_CONSOLE_WHITELIST_IPS","defaultValue":"","description":"This last option allows you to limit creation of users in Appwrite console for users sharing the same set of IP addresses. This option is very useful for team working with a VPN service or a company IP.\\n\\nTo enable/activate this option, pass a list of allowed IP addresses separated by a comma."},{"id":"$$config__app_system_email_name","name":"_APP_SYSTEM_EMAIL_NAME","label":"General | _APP_SYSTEM_EMAIL_NAME","defaultValue":"Appwrite","description":"This is the sender name value that will appear on email messages sent to developers from the Appwrite console. You can use url encoded strings for spaces and special chars."},{"id":"$$config__app_system_email_address","name":"_APP_SYSTEM_EMAIL_ADDRESS","label":"General | _APP_SYSTEM_EMAIL_ADDRESS","defaultValue":"team@appwrite.io","description":"This is the sender email address that will appear on email messages sent to developers from the Appwrite console. You should choose an email address that is allowed to be used from your SMTP server to avoid the server email ending in the users' SPAM folders."},{"id":"$$config__app_system_security_email_address","name":"_APP_SYSTEM_SECURITY_EMAIL_ADDRESS","label":"General | _APP_SYSTEM_SECURITY_EMAIL_ADDRESS","defaultValue":"certs@appwrite.io","description":"This is the email address used to issue SSL certificates for custom domains or the user agent in your webhooks payload."},{"id":"$$config__app_system_response_format","name":"_APP_SYSTEM_RESPONSE_FORMAT","label":"General | _APP_SYSTEM_RESPONSE_FORMAT","defaultValue":"","description":"Use this environment variable to set the default Appwrite HTTP response format to support an older version of Appwrite. This option is useful to overcome breaking changes between versions. You can also use the X-Appwrite-Response-Format HTTP request header to overwrite the response for a specific request. This variable accepts any valid Appwrite version. To use the current version format, leave the value of the variable empty."},{"id":"$$config__app_options_abuse","name":"_APP_OPTIONS_ABUSE","label":"General | _APP_OPTIONS_ABUSE","defaultValue":"enabled","description":"Allows you to disable abuse checks and API rate limiting. By default, set to 'enabled'. To cancel the abuse checking, set to 'disabled'. It is not recommended to disable this check-in a production environment."},{"id":"$$config__app_options_force_https","name":"_APP_OPTIONS_FORCE_HTTPS","label":"General | _APP_OPTIONS_FORCE_HTTPS","defaultValue":"disabled","description":"Allows you to force HTTPS connection to your API. This feature redirects any HTTP call to HTTPS and adds the 'Strict-Transport-Security' header to all HTTP responses."},{"id":"$$secret__app_openssl_key_v1","name":"_APP_OPENSSL_KEY_V1","label":"General | _APP_OPENSSL_KEY_V1","defaultValue":"$$generate_hex(256)","description":"This is your server private secret key that is used to encrypt all sensitive data on your server. Appwrite server encrypts all secret data on your server like webhooks, HTTP passwords, user sessions, and storage files. Keep it a secret and have a backup for it."},{"id":"$$config__app_domain","name":"_APP_DOMAIN","label":"General | _APP_DOMAIN","defaultValue":"$$generate_domain","description":"Your Appwrite domain address. When setting a public suffix domain, Appwrite will attempt to issue a valid SSL certificate automatically. When used with a dev domain, Appwrite will assign a self-signed SSL certificate. The default value is 'localhost'."},{"id":"$$config__app_domain_target","name":"_APP_DOMAIN_TARGET","label":"General | _APP_DOMAIN_TARGET","defaultValue":"$$generate_fqdn","description":"A DNS A record hostname to serve as a CNAME target for your Appwrite custom domains. You can use the same value as used for the Appwrite '_APP_DOMAIN' variable. The default value is 'localhost'."},{"id":"$$config__app_redis_host","name":"_APP_REDIS_HOST","label":"Redis | _APP_REDIS_HOST","defaultValue":"$$id-redis","description":""},{"id":"$$config__app_redis_port","name":"_APP_REDIS_PORT","label":"Redis | _APP_REDIS_PORT","defaultValue":"6379","description":"Redis server TCP port."},{"id":"$$config__app_redis_user","name":"_APP_REDIS_USER","label":"Redis | _APP_REDIS_USER","defaultValue":"","description":"Redis server user. This is an optional variable. Default value is an empty string."},{"id":"$$secret__app_redis_pass","name":"_APP_REDIS_PASS","label":"Redis | _APP_REDIS_PASS","defaultValue":"","description":"Redis server password. This is an optional variable. Default value is an empty string."},{"id":"$$config__app_db_host","name":"_APP_DB_HOST","label":"MariaDB | _APP_DB_HOST","defaultValue":"$$id-mariadb","description":""},{"id":"$$config__app_db_port","name":"_APP_DB_PORT","label":"MariaDB | _APP_DB_PORT","defaultValue":"3306","description":"MariaDB server TCP port."},{"id":"$$config__app_db_schema","name":"_APP_DB_SCHEMA","label":"MariaDB | _APP_DB_SCHEMA","defaultValue":"appwrite","description":"MariaDB server database schema."},{"id":"$$config__app_db_user","name":"_APP_DB_USER","label":"MariaDB | _APP_DB_USER","defaultValue":"user","description":"MariaDB server user name."},{"id":"$$secret__app_db_root_pass","name":"MARIADB_ROOT_PASSWORD","label":"MariaDB | MARIADB_ROOT_PASSWORD","defaultValue":"$$generate_hex(16)","description":"MariaDB server root user password."},{"id":"$$secret__app_db_pass","name":"_APP_DB_PASS","label":"MariaDB | _APP_DB_PASS","defaultValue":"$$generate_hex(16)","description":"MariaDB server user password."},{"id":"$$config__app_smtp_host","name":"_APP_SMTP_HOST","label":"SMTP | _APP_SMTP_HOST","defaultValue":"","description":"SMTP server host name address. Use an empty string to disable all mail sending from the server. The default value for this variable is an empty string."},{"id":"$$config__app_smtp_port","name":"_APP_SMTP_PORT","label":"SMTP | _APP_SMTP_PORT","defaultValue":"","description":"SMTP server TCP port. Empty by default."},{"id":"$$config__app_smtp_secure","name":"_APP_SMTP_SECURE","label":"SMTP | _APP_SMTP_SECURE","defaultValue":"","description":"SMTP secure connection protocol. Empty by default, change to 'tls' if running on a secure connection."},{"id":"$$config__app_smtp_username","name":"_APP_SMTP_USERNAME","label":"SMTP | _APP_SMTP_USERNAME","defaultValue":"","description":"SMTP server user name. Empty by default."},{"id":"$$secret__app_smtp_password","name":"_APP_SMTP_PASSWORD","label":"SMTP | _APP_SMTP_PASSWORD","defaultValue":"","description":"SMTP server user password. Empty by default."},{"id":"$$config__app_usage_stats","name":"_APP_USAGE_STATS","label":"General | _APP_USAGE_STATS","defaultValue":"enabled","description":"This variable allows you to disable the collection and displaying of usage stats. This value is set to 'enabled' by default, to disable the usage stats set the value to 'disabled'. When disabled, it's recommended to turn off the Worker Usage, Influxdb and Telegraf containers for better resource usage."},{"id":"$$config__app_storage_limit","name":"_APP_STORAGE_LIMIT","label":"Storage | _APP_STORAGE_LIMIT","defaultValue":"30000000","description":"Maximum file size allowed for file upload. The default value is 30MB. You should pass your size limit value in bytes."},{"id":"$$config__app_storage_preview_limit","name":"_APP_STORAGE_PREVIEW_LIMIT","label":"Storage | _APP_STORAGE_PREVIEW_LIMIT","defaultValue":"20000000","description":"Maximum file size allowed for file image preview. The default value is 20MB. You should pass your size limit value in bytes."},{"id":"$$config__app_storage_antivirus_enabled","name":"_APP_STORAGE_ANTIVIRUS","label":"Storage | _APP_STORAGE_ANTIVIRUS","defaultValue":"disabled","description":"This variable allows you to disable the internal anti-virus scans. This value is set to 'disabled' by default, to enable the scans set the value to 'enabled'. Before enabling, you must add the ClamAV service and depend on it on main Appwrite service."},{"id":"$$config__app_storage_antivirus_host","name":"_APP_STORAGE_ANTIVIRUS_HOST","label":"Storage | _APP_STORAGE_ANTIVIRUS_HOST","defaultValue":"clamav","description":"ClamAV server host name address."},{"id":"$$config__app_storage_antivirus_port","name":"_APP_STORAGE_ANTIVIRUS_PORT","label":"Storage | _APP_STORAGE_ANTIVIRUS_PORT","defaultValue":"3310","description":"ClamAV server TCP port."},{"id":"$$config__app_storage_device","name":"_APP_STORAGE_DEVICE","label":"Storage | _APP_STORAGE_DEVICE","defaultValue":"Local","description":"Select default storage device. The default value is 'Local'. List of supported adapters are 'Local', 'S3', 'DOSpaces', 'Backblaze', 'Linode' and 'Wasabi'."},{"id":"$$secret__app_storage_s3_access_key","name":"_APP_STORAGE_S3_ACCESS_KEY","label":"Storage | _APP_STORAGE_S3_ACCESS_KEY","defaultValue":"","description":"AWS S3 storage access key. Required when the storage adapter is set to S3. You can get your access key from your AWS console."},{"id":"$$secret__app_storage_s3_secret","name":"_APP_STORAGE_S3_SECRET","label":"Storage | _APP_STORAGE_S3_SECRET","defaultValue":"","description":"AWS S3 storage secret key. Required when the storage adapter is set to S3. You can get your secret key from your AWS console."},{"id":"$$config__app_storage_s3_region","name":"_APP_STORAGE_S3_REGION","label":"Storage | _APP_STORAGE_S3_REGION","defaultValue":"us-east-1","description":"AWS S3 storage region. Required when storage adapter is set to S3. You can find your region info for your bucket from AWS console."},{"id":"$$config__app_storage_s3_bucket","name":"_APP_STORAGE_S3_BUCKET","label":"Storage | _APP_STORAGE_S3_BUCKET","defaultValue":"","description":"AWS S3 storage bucket. Required when storage adapter is set to S3. You can create buckets in your AWS console."},{"id":"$$secret__app_storage_do_spaces_access_key","name":"_APP_STORAGE_DO_SPACES_ACCESS_KEY","label":"Storage | _APP_STORAGE_DO_SPACES_ACCESS_KEY","defaultValue":"","description":"DigitalOcean spaces access key. Required when the storage adapter is set to DOSpaces. You can get your access key from your DigitalOcean console."},{"id":"$$secret__app_storage_do_spaces_secret","name":"_APP_STORAGE_DO_SPACES_SECRET","label":"Storage | _APP_STORAGE_DO_SPACES_SECRET","defaultValue":"","description":"DigitalOcean spaces secret key. Required when the storage adapter is set to DOSpaces. You can get your secret key from your DigitalOcean console."},{"id":"$$config__app_storage_do_spaces_region","name":"_APP_STORAGE_DO_SPACES_REGION","label":"Storage | _APP_STORAGE_DO_SPACES_REGION","defaultValue":"us-east-1","description":"DigitalOcean spaces region. Required when storage adapter is set to DOSpaces. You can find your region info for your space from DigitalOcean console."},{"id":"$$config__app_storage_do_spaces_bucket","name":"_APP_STORAGE_DO_SPACES_BUCKET","label":"Storage | _APP_STORAGE_DO_SPACES_BUCKET","defaultValue":"","description":"DigitalOcean spaces bucket. Required when storage adapter is set to DOSpaces. You can create spaces in your DigitalOcean console."},{"id":"$$secret__app_storage_backblaze_access_key","name":"_APP_STORAGE_BACKBLAZE_ACCESS_KEY","label":"Storage | _APP_STORAGE_BACKBLAZE_ACCESS_KEY","defaultValue":"","description":"Backblaze access key. Required when the storage adapter is set to Backblaze. Your Backblaze keyID will be your access key. You can get your keyID from your Backblaze console."},{"id":"$$secret__app_storage_backblaze_secret","name":"_APP_STORAGE_BACKBLAZE_SECRET","label":"Storage | _APP_STORAGE_BACKBLAZE_SECRET","defaultValue":"","description":"Backblaze secret key. Required when the storage adapter is set to Backblaze. Your Backblaze applicationKey will be your secret key. You can get your applicationKey from your Backblaze console."},{"id":"$$config__app_storage_backblaze_region","name":"_APP_STORAGE_BACKBLAZE_REGION","label":"Storage | _APP_STORAGE_BACKBLAZE_REGION","defaultValue":"us-west-004","description":"Backblaze region. Required when storage adapter is set to Backblaze. You can find your region info from your Backblaze console."},{"id":"$$config__app_storage_backblaze_bucket","name":"_APP_STORAGE_BACKBLAZE_BUCKET","label":"Storage | _APP_STORAGE_BACKBLAZE_BUCKET","defaultValue":"","description":"Backblaze bucket. Required when storage adapter is set to Backblaze. You can create your bucket from your Backblaze console."},{"id":"$$secret__app_storage_linode_access_key","name":"_APP_STORAGE_LINODE_ACCESS_KEY","label":"Storage | _APP_STORAGE_LINODE_ACCESS_KEY","defaultValue":"","description":"Linode object storage access key. Required when the storage adapter is set to Linode. You can get your access key from your Linode console."},{"id":"$$secret__app_storage_linode_secret","name":"_APP_STORAGE_LINODE_SECRET","label":"Storage | _APP_STORAGE_LINODE_SECRET","defaultValue":"","description":"Linode object storage secret key. Required when the storage adapter is set to Linode. You can get your secret key from your Linode console."},{"id":"$$config__app_storage_linode_region","name":"_APP_STORAGE_LINODE_REGION","label":"Storage | _APP_STORAGE_LINODE_REGION","defaultValue":"eu-central-1","description":"Linode object storage region. Required when storage adapter is set to Linode. You can find your region info from your Linode console."},{"id":"$$config__app_storage_linode_bucket","name":"_APP_STORAGE_LINODE_BUCKET","label":"Storage | _APP_STORAGE_LINODE_BUCKET","defaultValue":"","description":"Linode object storage bucket. Required when storage adapter is set to Linode. You can create buckets in your Linode console."},{"id":"$$secret__app_storage_wasabi_access_key","name":"_APP_STORAGE_WASABI_ACCESS_KEY","label":"Storage | _APP_STORAGE_WASABI_ACCESS_KEY","defaultValue":"","description":"Wasabi access key. Required when the storage adapter is set to Wasabi. You can get your access key from your Wasabi console."},{"id":"$$secret__app_storage_wasabi_secret","name":"_APP_STORAGE_WASABI_SECRET","label":"Storage | _APP_STORAGE_WASABI_SECRET","defaultValue":"","description":"Wasabi secret key. Required when the storage adapter is set to Wasabi. You can get your secret key from your Wasabi console."},{"id":"$$config__app_storage_wasabi_region","name":"_APP_STORAGE_WASABI_REGION","label":"Storage | _APP_STORAGE_WASABI_REGION","defaultValue":"eu-central-1","description":"Wasabi region. Required when storage adapter is set to Wasabi. You can find your region info from your Wasabi console."},{"id":"$$config__app_storage_wasabi_bucket","name":"_APP_STORAGE_WASABI_BUCKET","label":"Storage | _APP_STORAGE_WASABI_BUCKET","defaultValue":"","description":"Wasabi bucket. Required when storage adapter is set to Wasabi. You can create buckets in your Wasabi console."},{"id":"$$config__app_functions_size_limit","name":"_APP_FUNCTIONS_SIZE_LIMIT","label":"Functions | _APP_FUNCTIONS_SIZE_LIMIT","defaultValue":"30000000","description":"The maximum size deployment in bytes. The default value is 30MB."},{"id":"$$config__app_functions_timeout","name":"_APP_FUNCTIONS_TIMEOUT","label":"Functions | _APP_FUNCTIONS_TIMEOUT","defaultValue":"900","description":"The maximum number of seconds allowed as a timeout value when creating a new function. The default value is 900 seconds."},{"id":"$$config__app_functions_build_timeout","name":"_APP_FUNCTIONS_BUILD_TIMEOUT","label":"Functions | _APP_FUNCTIONS_BUILD_TIMEOUT","defaultValue":"900","description":"The maximum number of seconds allowed as a timeout value when building a new function. The default value is 900 seconds."},{"id":"$$config__app_functions_containers","name":"_APP_FUNCTIONS_CONTAINERS","label":"Functions | _APP_FUNCTIONS_CONTAINERS","defaultValue":"10","description":"The maximum number of containers Appwrite is allowed to keep alive in the background for function environments. Running containers allow faster execution time as there is no need to recreate each container every time a function gets executed. The default value is 10."},{"id":"$$config__app_functions_cpus","name":"_APP_FUNCTIONS_CPUS","label":"Functions | _APP_FUNCTIONS_CPUS","defaultValue":"","description":"The maximum number of CPU core a single cloud function is allowed to use. Please note that setting a value higher than available cores will result in a function error, which might result in an error. The default value is empty. When it's empty, CPU limit will be disabled."},{"id":"$$config__app_functions_memory_allocated","name":"_APP_FUNCTIONS_MEMORY","label":"Functions | _APP_FUNCTIONS_MEMORY","defaultValue":"","description":"The maximum amount of memory a single cloud function is allowed to use in megabytes. The default value is empty. When it's empty, memory limit will be disabled."},{"id":"$$config__app_functions_memory_swap","name":"_APP_FUNCTIONS_MEMORY_SWAP","label":"Functions | _APP_FUNCTIONS_MEMORY_SWAP","defaultValue":"","description":"The maximum amount of swap memory a single cloud function is allowed to use in megabytes. The default value is empty. When it's empty, swap memory limit will be disabled."},{"id":"$$config__app_functions_runtimes","name":"_APP_FUNCTIONS_RUNTIMES","label":"Functions | _APP_FUNCTIONS_RUNTIMES","defaultValue":"node-18.0","description":"This option allows you to limit the available environments for cloud functions. This option is very useful for low-cost servers to safe disk space.\nTo enable/activate this option, pass a list of allowed environments separated by a comma.\nCurrently, supported environments are: node-14.5, node-16.0, node-18.0, php-8.0, php-8.1, ruby-3.0, ruby-3.1, python-3.8, python-3.9, python-3.10, deno-1.21, deno-1.24, dart-2.15, dart-2.16, dart-2.17, dotnet-3.1, dotnet-6.0, java-8.0, java-11.0, java-17.0, java-18.0, swift-5.5, kotlin-1.6, cpp-17.0"},{"id":"$$secret__app_executor_secret","name":"_APP_EXECUTOR_SECRET","label":"Functions | _APP_EXECUTOR_SECRET","defaultValue":"$$generate_hex(16)","description":"The secret key used by Appwrite to communicate with the function executor."},{"id":"$$config__app_executor_host","name":"_APP_EXECUTOR_HOST","label":"","defaultValue":"http://$$id-executor/v1","description":""},{"id":"$$config__app_logging_provider","name":"_APP_LOGGING_PROVIDER","label":"General | _APP_LOGGING_PROVIDER","defaultValue":"","description":"This variable allows you to enable logging errors to 3rd party providers. This value is empty by default, to enable the logger set the value to one of 'sentry', 'raygun', 'appsignal', 'logowl'"},{"id":"$$config__app_logging_config","name":"_APP_LOGGING_CONFIG","label":"General | _APP_LOGGING_CONFIG","defaultValue":"","description":"This variable configures authentication to 3rd party error logging providers. If using Sentry, this should be 'SENTRY_API_KEY;SENTRY_APP_ID'. If using Raygun, this should be Raygun API key. If using AppSignal, this should be AppSignal API key. If using LogOwl, this should be LogOwl Service Ticket."},{"id":"$$config__app_statsd_host","name":"_APP_STATSD_HOST","label":"","defaultValue":"$$id-telegraf","description":""},{"id":"$$config__app_statsd_port","name":"_APP_STATSD_PORT","label":"StatsD | _APP_STATSD_PORT","defaultValue":"8125","description":"StatsD server TCP port."},{"id":"$$config__app_maintenance_interval","name":"_APP_MAINTENANCE_INTERVAL","label":"Functions | _APP_MAINTENANCE_INTERVAL","defaultValue":"86400","description":"Interval value containing the number of seconds that the Appwrite maintenance process should wait before executing system cleanups and optimizations. The default value is 86400 seconds (1 day)."},{"id":"$$config__app_maintenance_retention_execution","name":"_APP_MAINTENANCE_RETENTION_EXECUTION","label":"Functions | _APP_MAINTENANCE_RETENTION_EXECUTION","defaultValue":"1209600","description":"The maximum duration (in seconds) upto which to retain execution logs. The default value is 1209600 seconds (14 days)."},{"id":"$$config__app_maintenance_retention_cache","name":"_APP_MAINTENANCE_RETENTION_CACHE","label":"Functions | _APP_MAINTENANCE_RETENTION_CACHE","defaultValue":"2592000","description":"The maximum duration (in seconds) upto which to retain cached files. The default value is 2592000 seconds (30 days)."},{"id":"$$config__app_maintenance_retention_abuse","name":"_APP_MAINTENANCE_RETENTION_ABUSE","label":"Functions | _APP_MAINTENANCE_RETENTION_ABUSE","defaultValue":"86400","description":"The maximum duration (in seconds) upto which to retain abuse logs. The default value is 86400 seconds (1 day)."},{"id":"$$config__app_maintenance_retention_audit","name":"_APP_MAINTENANCE_RETENTION_AUDIT","label":"Functions | _APP_MAINTENANCE_RETENTION_AUDIT","defaultValue":"1209600","description":"The maximum duration (in seconds) upto which to retain audit logs. The default value is 1209600 seconds (14 days)."},{"id":"$$config__app_sms_provider","name":"_APP_SMS_PROVIDER","label":"Phone | _APP_SMS_PROVIDER","defaultValue":"","description":"Provider used for delivering SMS for Phone authentication. Use the following format: 'sms://[USER]:[SECRET]@[PROVIDER]'. Available providers are twilio, text-magic, telesign, msg91, and vonage."},{"id":"$$config__app_sms_from","name":"_APP_SMS_FROM","label":"Phone | _APP_SMS_FROM","defaultValue":"","description":"Phone number used for sending out messages. Must start with a leading '+' and maximum of 15 digits without spaces (+123456789)."},{"id":"$$config__app_functions_inactive_threshold","name":"_APP_FUNCTIONS_INACTIVE_THRESHOLD","label":"Functions | _APP_FUNCTIONS_INACTIVE_THRESHOLD","defaultValue":"60","description":"The minimum time a function can be inactive before it's container is shutdown and put to sleep. The default value is 60 seconds"},{"id":"$$config_open_runtimes_network","name":"OPEN_RUNTIMES_NETWORK","label":"","defaultValue":"$$generate_network","description":""},{"id":"$$config_dockerhub_pull_username","name":"DOCKERHUB_PULL_USERNAME","label":"Functions | DOCKERHUB_PULL_USERNAME","defaultValue":"","description":"The username for hub.docker.com. This variable is used to pull images from hub.docker.com."},{"id":"$$secret_dockerhub_pull_password","name":"DOCKERHUB_PULL_PASSWORD","label":"Functions | DOCKERHUB_PULL_PASSWORD","defaultValue":"","description":"The password for hub.docker.com. This variable is used to pull images from hub.docker.com."},{"id":"$$config__app_usage_timeseries_interval","name":"_APP_USAGE_TIMESERIES_INTERVAL","label":"General | _APP_USAGE_TIMESERIES_INTERVAL","defaultValue":"30","description":"Interval value containing the number of seconds that the Appwrite usage process should wait before aggregating stats and syncing it to mariadb from InfluxDB. The default value is 30 seconds."},{"id":"$$config__app_usage_database_interval","name":"_APP_USAGE_DATABASE_INTERVAL","label":"General | _APP_USAGE_DATABASE_INTERVAL","defaultValue":"900","description":"Interval value containing the number of seconds that the Appwrite usage process should wait before aggregating stats from data in Appwrite Database. The default value is 15 minutes."}]},{"templateVersion":"1.0.0","defaultVersion":"latest","documentation":"https://docs.weblate.org/en/latest/admin/install/docker.html","description":"A copylefted libre software web-based continuous localization system.","type":"weblate","name":"Weblate","labels":["translate","localization"],"services":{"$$id":{"name":"Weblate","depends_on":["$$id-postgresql","$$id-redis"],"image":"weblate/weblate:$$core_version","volumes":["$$id-data:/app/data"],"environment":["WEBLATE_SITE_DOMAIN=$$config_weblate_site_domain","WEBLATE_ADMIN_PASSWORD=$$secret_weblate_admin_password","POSTGRES_PASSWORD=$$secret_postgres_password","POSTGRES_USER=$$config_postgres_user","POSTGRES_DATABASE=$$config_postgres_db","POSTGRES_HOST=$$id-postgresql","POSTGRES_PORT=5432","REDIS_HOST=$$id-redis"],"ports":["8080"]},"$$id-postgresql":{"name":"PostgreSQL","depends_on":[],"image":"postgres:14-alpine","volumes":["$$id-postgresql-data:/var/lib/postgresql/data"],"environment":["POSTGRES_USER=$$config_postgres_user","POSTGRES_PASSWORD=$$secret_postgres_password","POSTGRES_DB=$$config_postgres_db"],"ports":[]},"$$id-redis":{"name":"Redis","depends_on":[],"image":"redis:7-alpine","volumes":["$$id-redis-data:/data"],"environment":[],"ports":[]}},"variables":[{"id":"$$config_weblate_site_domain","name":"WEBLATE_SITE_DOMAIN","label":"Weblate Domain","defaultValue":"$$generate_domain","description":""},{"id":"$$secret_weblate_admin_password","name":"WEBLATE_ADMIN_PASSWORD","label":"Weblate Admin Password","defaultValue":"$$generate_password","description":"","showOnConfiguration":true},{"id":"$$config_postgres_user","main":"$$id-postgresql","name":"POSTGRES_USER","label":"PostgreSQL User","defaultValue":"$$generate_username","description":""},{"id":"$$secret_postgres_password","main":"$$id-postgresql","name":"POSTGRES_PASSWORD","label":"PostgreSQL Password","defaultValue":"$$generate_password","description":"","showOnConfiguration":true},{"id":"$$config_postgres_db","main":"$$id-postgresql","name":"POSTGRES_DB","label":"PostgreSQL Database","defaultValue":"weblate","description":""}]},{"templateVersion":"1.0.0","defaultVersion":"2022.12.12-966e9c3c","documentation":"https://docs.searxng.org/","type":"searxng","name":"SearXNG","description":"Free internet metasearch engine which aggregates results from more than 70 search services.","services":{"$$id":{"name":"SearXNG","depends_on":["$$id-redis"],"image":"searxng/searxng:$$core_version","volumes":["$$id-searxng:/etc/searxng"],"environment":["SEARXNG_BASE_URL=$$config_searxng_base_url"],"ports":["8080"],"cap_drop":["ALL"],"cap_add":["CHOWN","SETGID","SETUID","DAC_OVERRIDE"],"files":[{"location":"/etc/searxng/settings.yml","content":"\n # see https://docs.searxng.org/admin/engines/settings.html#use-default-settings\n use_default_settings: true\n server:\n secret_key: $$secret_secret_key\n limiter: true\n image_proxy: true\n ui:\n static_use_hash: true\n redis:\n url: redis://:$$secret_redis_password@$$id-redis:6379/0"}]},"$$id-redis":{"name":"Redis","command":"redis-server --requirepass $$secret_redis_password --save \"\" --appendonly \"no\"","depends_on":[],"image":"redis:7-alpine","volumes":["$$id-redis-data:/data"],"environment":["REDIS_PASSWORD=$$secret_redis_password"],"ports":[],"cap_drop":["ALL"],"cap_add":["SETGID","SETUID","DAC_OVERRIDE"]}},"variables":[{"id":"$$config_searxng_base_url","name":"SEARXNG_BASE_URL","label":"SearXNG Base URL","defaultValue":"$$generate_fqdn","description":""},{"id":"$$secret_secret_key","name":"SECRET_KEY","label":"Secret Key","defaultValue":"$$generate_hex(64)","description":""},{"id":"$$secret_redis_password","name":"REDIS_PASSWORD","label":"Redis Password","defaultValue":"$$generate_password","description":""}]},{"templateVersion":"1.0.0","defaultVersion":"v3.0.0","documentation":"https://glitchtip.com/documentation","type":"glitchtip","name":"GlitchTip","description":"Simple, open source error tracking.","labels":["sentry","bugsnag"],"services":{"$$id":{"name":"GlitchTip","depends_on":["$$id-postgresql","$$id-redis"],"image":"glitchtip/glitchtip:$$core_version","volumes":[],"environment":["PORT=$$config_port","GLITCHTIP_DOMAIN=$$config_glitchtip_domain","SECRET_KEY=$$secret_secret_key","DATABASE_URL=$$secret_database_url","REDIS_URL=$$secret_redis_url","DEFAULT_FROM_EMAIL=$$config_default_from_email","EMAIL_URL=$$secret_email_url","EMAIL_HOST=$$config_email_host","EMAIL_PORT=$$config_email_port","EMAIL_HOST_USER=$$config_email_host_user","EMAIL_HOST_PASSWORD=$$secret_email_host_password","EMAIL_USE_TLS=$$config_email_use_tls","EMAIL_USE_SSL=$$config_email_use_ssl","EMAIL_BACKEND=$$config_email_backend","MAILGUN_API_KEY=$$secret_mailgun_api_key","SENDGRID_API_KEY=$$secret_sendgrid_api_key","ENABLE_OPEN_USER_REGISTRATION=$$config_enable_open_user_registration","DJANGO_SUPERUSER_EMAIL=$$config_django_superuser_email","DJANGO_SUPERUSER_PASSWORD=$$secret_django_superuser_password","DJANGO_SUPERUSER_USERNAME=$$config_django_superuser_username","CELERY_WORKER_CONCURRENCY=$$config_celery_worker_concurrency"],"ports":["8000"]},"$$id-worker":{"name":"Celery Worker","command":"./bin/run-celery-with-beat.sh","depends_on":["$$id-postgresql","$$id-redis"],"image":"glitchtip/glitchtip:$$core_version","environment":["GLITCHTIP_DOMAIN=$$config_glitchtip_domain","SECRET_KEY=$$secret_secret_key","DATABASE_URL=$$secret_database_url","REDIS_URL=$$secret_redis_url","DEFAULT_FROM_EMAIL=$$config_default_from_email","EMAIL_URL=$$secret_email_url","CELERY_WORKER_CONCURRENCY=$$config_celery_worker_concurrency"],"ports":[]},"$$id-migrate":{"exclude":true,"name":"Migrate","command":"./manage.py migrate","depends_on":["$$id-postgresql","$$id-redis"],"image":"glitchtip/glitchtip:$$core_version","environment":["GLITCHTIP_DOMAIN=$$config_glitchtip_domain","SECRET_KEY=$$secret_secret_key","DATABASE_URL=$$secret_database_url","REDIS_URL=$$secret_redis_url","DEFAULT_FROM_EMAIL=$$config_default_from_email","EMAIL_URL=$$secret_email_url"],"ports":[]},"$$id-postgresql":{"name":"PostgreSQL","depends_on":[],"image":"postgres:14-alpine","volumes":["$$id-postgresql-data:/var/lib/postgresql/data"],"environment":["POSTGRES_USER=$$config_postgres_user","POSTGRES_PASSWORD=$$secret_postgres_password","POSTGRES_DB=$$config_postgres_db"],"ports":[]},"$$id-redis":{"name":"Redis","depends_on":[],"image":"redis:7-alpine","volumes":["$$id-postgresql-redis-data:/data"],"environment":[],"ports":[]}},"variables":[{"id":"$$config_django_superuser_username","name":"DJANGO_SUPERUSER_USERNAME","label":"Django Superuser Username","defaultValue":"$$generate_username","description":""},{"id":"$$secret_django_superuser_password","name":"DJANGO_SUPERUSER_PASSWORD","label":"Django Superuser Password","defaultValue":"$$generate_password","description":"","showOnConfiguration":true},{"id":"$$config_port","name":"PORT","label":"GlitchTip Port","defaultValue":"8000","description":""},{"id":"$$config_celery_worker_concurrency","main":"$$id-worker","name":"CELERY_WORKER_CONCURRENCY","label":"Celery Worker Concurrency","defaultValue":"2","description":""},{"id":"$$config_glitchtip_domain","name":"GLITCHTIP_DOMAIN","label":"GlitchTip Domain","defaultValue":"$$generate_fqdn","description":""},{"id":"$$secret_email_url","name":"EMAIL_URL","label":"SMTP Email URL","defaultValue":"smtp://$$config_email_host_user:$$secret_email_host_password@$$config_email_host:$$config_email_port","description":""},{"id":"$$secret_database_url","name":"DATABASE_URL","label":"Database URL for PostgreSQL","defaultValue":"postgresql://$$config_postgres_user:$$secret_postgres_password@$$id-postgresql:5432/$$config_postgres_db","description":""},{"id":"$$secret_redis_url","name":"REDIS_URL","label":"Redis URL","defaultValue":"redis://$$id-redis:6379/0","description":""},{"id":"$$config_default_from_email","name":"DEFAULT_FROM_EMAIL","label":"Default Email Address","defaultValue":"noreply@example.com","description":""},{"id":"$$config_email_host","name":"EMAIL_HOST","label":"Email SMTP Host","defaultValue":"","description":""},{"id":"$$config_email_port","name":"EMAIL_PORT","label":"Email SMTP Port","defaultValue":"25","description":""},{"id":"$$config_email_host_user","name":"EMAIL_HOST_USER","label":"Email SMTP User","defaultValue":"","description":""},{"id":"$$secret_email_host_password","name":"EMAIL_HOST_PASSWORD","label":"Email SMTP Password","defaultValue":"","description":""},{"id":"$$config_email_use_tls","name":"EMAIL_USE_TLS","label":"Email Use TLS","defaultValue":"false","description":""},{"id":"$$config_email_use_ssl","name":"EMAIL_USE_SSL","label":"Email Use SSL","defaultValue":"false","description":""},{"id":"$$secret_email_smtp_password","name":"EMAIL_SMTP_PASSWORD","label":"SMTP Password","defaultValue":"","description":""},{"id":"$$config_email_backend","name":"EMAIL_BACKEND","label":"Email Backend","defaultValue":"","description":""},{"id":"$$secret_mailgun_api_key","name":"MAILGUN_API_KEY","label":"Mailgun API Key","defaultValue":"","description":"","showOnConfiguration":true},{"id":"$$secret_sendgrid_api_key","name":"SENDGRID_API_KEY","label":"Sendgrid API Key","defaultValue":"","description":"","showOnConfiguration":true},{"id":"$$config_enable_open_user_registration","name":"ENABLE_OPEN_USER_REGISTRATION","label":"Enable Open User Registration","defaultValue":"true","description":""},{"id":"$$config_django_superuser_email","name":"DJANGO_SUPERUSER_EMAIL","label":"Django Superuser Email","defaultValue":"noreply@example.com","description":""},{"id":"$$config_postgres_user","main":"$$id-postgresql","name":"POSTGRES_USER","label":"PostgreSQL User","defaultValue":"$$generate_username","description":""},{"id":"$$secret_postgres_password","main":"$$id-postgresql","name":"POSTGRES_PASSWORD","label":"PostgreSQL Password","defaultValue":"$$generate_password","description":""},{"id":"$$config_postgres_db","main":"$$id-postgresql","name":"POSTGRES_DB","label":"PostgreSQL Database","defaultValue":"glitchtip","description":""}]},{"templateVersion":"1.0.0","defaultVersion":"v2.16.0","documentation":"https://hasura.io/docs/latest/index/","type":"hasura","name":"Hasura","description":"Instant realtime GraphQL APIs on any Postgres application, existing or new.","labels":["graphql","database"],"services":{"$$id":{"name":"Hasura","depends_on":["$$id-postgresql"],"image":"hasura/graphql-engine:$$core_version","volumes":[],"environment":["HASURA_GRAPHQL_ENABLE_CONSOLE=$$config_hasura_graphql_enable_console","HASURA_GRAPHQL_METADATA_DATABASE_URL=$$secret_hasura_graphql_metadata_database_url","HASURA_GRAPHQL_ADMIN_SECRET=$$secret_hasura_graphql_admin_secret"],"ports":["8080"]},"$$id-postgresql":{"name":"PostgreSQL","depends_on":[],"image":"postgres:12-alpine","volumes":["$$id-postgresql-data:/var/lib/postgresql/data"],"environment":["POSTGRES_USER=$$config_postgres_user","POSTGRES_PASSWORD=$$secret_postgres_password","POSTGRES_DB=$$config_postgres_db"],"ports":[]}},"variables":[{"id":"$$config_hasura_graphql_enable_console","name":"HASURA_GRAPHQL_ENABLE_CONSOLE","label":"Enable Hasura Console","defaultValue":"true","description":""},{"id":"$$secret_hasura_graphql_metadata_database_url","name":"HASURA_GRAPHQL_METADATA_DATABASE_URL","label":"Hasura Metadata Database URL","defaultValue":"postgresql://$$config_postgres_user:$$secret_postgres_password@$$id-postgresql:5432/$$config_postgres_db","description":""},{"id":"$$secret_hasura_graphql_admin_secret","name":"HASURA_GRAPHQL_ADMIN_SECRET","label":"Hasura Admin Password","defaultValue":"$$generate_password","description":"","showOnConfiguration":true},{"id":"$$config_postgres_user","name":"POSTGRES_USER","label":"PostgreSQL User","defaultValue":"$$generate_username","description":""},{"id":"$$secret_postgres_password","name":"POSTGRES_PASSWORD","label":"PostgreSQL Password","defaultValue":"$$generate_password","description":""},{"id":"$$config_postgres_db","name":"POSTGRES_DB","label":"PostgreSQL Database","defaultValue":"hasura","description":""}]},{"templateVersion":"1.0.0","defaultVersion":"postgresql-v1.39.5","documentation":"https://umami.is/docs/getting-started","type":"umami-postgresql","name":"Umami","subname":"(PostgreSQL)","description":"A simple, easy to use, self-hosted web analytics solution.","services":{"$$id":{"name":"Umami","depends_on":["$$id-postgresql"],"image":"ghcr.io/umami-software/umami:$$core_version","volumes":[],"environment":["ADMIN_PASSWORD=$$secret_admin_password","DATABASE_URL=$$secret_database_url","DATABASE_TYPE=$$config_database_type","HASH_SALT=$$secret_hash_salt"],"ports":["3000"]},"$$id-postgresql":{"name":"PostgreSQL","depends_on":[],"image":"postgres:12-alpine","volumes":["$$id-postgresql-data:/var/lib/postgresql/data"],"environment":["POSTGRES_USER=$$config_postgres_user","POSTGRES_PASSWORD=$$secret_postgres_password","POSTGRES_DB=$$config_postgres_db"],"ports":[],"files":[{"location":"/docker-entrypoint-initdb.d/schema.postgresql.sql","content":"\n -- CreateTable\n CREATE TABLE \"account\" (\n \"user_id\" SERIAL NOT NULL,\n \"username\" VARCHAR(255) NOT NULL,\n \"password\" VARCHAR(60) NOT NULL,\n \"is_admin\" BOOLEAN NOT NULL DEFAULT false,\n \"created_at\" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,\n \"updated_at\" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,\n\n PRIMARY KEY (\"user_id\")\n );\n\n -- CreateTable\n CREATE TABLE \"event\" (\n \"event_id\" SERIAL NOT NULL,\n \"website_id\" INTEGER NOT NULL,\n \"session_id\" INTEGER NOT NULL,\n \"created_at\" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,\n \"url\" VARCHAR(500) NOT NULL,\n \"event_type\" VARCHAR(50) NOT NULL,\n \"event_value\" VARCHAR(50) NOT NULL,\n\n PRIMARY KEY (\"event_id\")\n );\n\n -- CreateTable\n CREATE TABLE \"pageview\" (\n \"view_id\" SERIAL NOT NULL,\n \"website_id\" INTEGER NOT NULL,\n \"session_id\" INTEGER NOT NULL,\n \"created_at\" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,\n \"url\" VARCHAR(500) NOT NULL,\n \"referrer\" VARCHAR(500),\n\n PRIMARY KEY (\"view_id\")\n );\n\n -- CreateTable\n CREATE TABLE \"session\" (\n \"session_id\" SERIAL NOT NULL,\n \"session_uuid\" UUID NOT NULL,\n \"website_id\" INTEGER NOT NULL,\n \"created_at\" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,\n \"hostname\" VARCHAR(100),\n \"browser\" VARCHAR(20),\n \"os\" VARCHAR(20),\n \"device\" VARCHAR(20),\n \"screen\" VARCHAR(11),\n \"language\" VARCHAR(35),\n \"country\" CHAR(2),\n\n PRIMARY KEY (\"session_id\")\n );\n\n -- CreateTable\n CREATE TABLE \"website\" (\n \"website_id\" SERIAL NOT NULL,\n \"website_uuid\" UUID NOT NULL,\n \"user_id\" INTEGER NOT NULL,\n \"name\" VARCHAR(100) NOT NULL,\n \"domain\" VARCHAR(500),\n \"share_id\" VARCHAR(64),\n \"created_at\" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,\n\n PRIMARY KEY (\"website_id\")\n );\n\n -- CreateIndex\n CREATE UNIQUE INDEX \"account.username_unique\" ON \"account\"(\"username\");\n\n -- CreateIndex\n CREATE INDEX \"event_created_at_idx\" ON \"event\"(\"created_at\");\n\n -- CreateIndex\n CREATE INDEX \"event_session_id_idx\" ON \"event\"(\"session_id\");\n\n -- CreateIndex\n CREATE INDEX \"event_website_id_idx\" ON \"event\"(\"website_id\");\n\n -- CreateIndex\n CREATE INDEX \"pageview_created_at_idx\" ON \"pageview\"(\"created_at\");\n\n -- CreateIndex\n CREATE INDEX \"pageview_session_id_idx\" ON \"pageview\"(\"session_id\");\n\n -- CreateIndex\n CREATE INDEX \"pageview_website_id_created_at_idx\" ON \"pageview\"(\"website_id\", \"created_at\");\n\n -- CreateIndex\n CREATE INDEX \"pageview_website_id_idx\" ON \"pageview\"(\"website_id\");\n\n -- CreateIndex\n CREATE INDEX \"pageview_website_id_session_id_created_at_idx\" ON \"pageview\"(\"website_id\", \"session_id\", \"created_at\");\n\n -- CreateIndex\n CREATE UNIQUE INDEX \"session.session_uuid_unique\" ON \"session\"(\"session_uuid\");\n\n -- CreateIndex\n CREATE INDEX \"session_created_at_idx\" ON \"session\"(\"created_at\");\n\n -- CreateIndex\n CREATE INDEX \"session_website_id_idx\" ON \"session\"(\"website_id\");\n\n -- CreateIndex\n CREATE UNIQUE INDEX \"website.website_uuid_unique\" ON \"website\"(\"website_uuid\");\n\n -- CreateIndex\n CREATE UNIQUE INDEX \"website.share_id_unique\" ON \"website\"(\"share_id\");\n\n -- CreateIndex\n CREATE INDEX \"website_user_id_idx\" ON \"website\"(\"user_id\");\n\n -- AddForeignKey\n ALTER TABLE \"event\" ADD FOREIGN KEY (\"session_id\") REFERENCES \"session\"(\"session_id\") ON DELETE CASCADE ON UPDATE CASCADE;\n\n -- AddForeignKey\n ALTER TABLE \"event\" ADD FOREIGN KEY (\"website_id\") REFERENCES \"website\"(\"website_id\") ON DELETE CASCADE ON UPDATE CASCADE;\n\n -- AddForeignKey\n ALTER TABLE \"pageview\" ADD FOREIGN KEY (\"session_id\") REFERENCES \"session\"(\"session_id\") ON DELETE CASCADE ON UPDATE CASCADE;\n\n -- AddForeignKey\n ALTER TABLE \"pageview\" ADD FOREIGN KEY (\"website_id\") REFERENCES \"website\"(\"website_id\") ON DELETE CASCADE ON UPDATE CASCADE;\n\n -- AddForeignKey\n ALTER TABLE \"session\" ADD FOREIGN KEY (\"website_id\") REFERENCES \"website\"(\"website_id\") ON DELETE CASCADE ON UPDATE CASCADE;\n\n -- AddForeignKey\n ALTER TABLE \"website\" ADD FOREIGN KEY (\"user_id\") REFERENCES \"account\"(\"user_id\") ON DELETE CASCADE ON UPDATE CASCADE;\n\n insert into account (username, password, is_admin) values ('admin', '$$hashed$$secret_admin_password', true);"}]}},"variables":[{"id":"$$secret_database_url","name":"DATABASE_URL","label":"Database URL for PostgreSQL","defaultValue":"postgresql://$$config_postgres_user:$$secret_postgres_password@$$id-postgresql:5432/$$config_postgres_db","description":""},{"id":"$$secret_hash_salt","name":"HASH_SALT","label":"Hash Salt","defaultValue":"$$generate_hex(64)","description":""},{"id":"$$config_database_type","name":"DATABASE_TYPE","label":"Database Type","defaultValue":"postgresql","description":""},{"id":"$$config_postgres_user","name":"POSTGRES_USER","label":"PostgreSQL User","defaultValue":"$$generate_username","description":""},{"id":"$$secret_postgres_password","name":"POSTGRES_PASSWORD","label":"PostgreSQL Password","defaultValue":"$$generate_password","description":""},{"id":"$$config_postgres_db","name":"POSTGRES_DB","label":"PostgreSQL Database","defaultValue":"umami","description":""},{"id":"$$secret_admin_password","name":"ADMIN_PASSWORD","label":"Initial Admin Password","defaultValue":"$$generate_password","description":"","showOnConfiguration":true}]},{"templateVersion":"1.0.0","ignore":true,"defaultVersion":"postgresql-v1.39.5","documentation":"https://umami.is/docs/getting-started","type":"umami","name":"Umami","subname":"(PostgreSQL)","description":"A simple, easy to use, self-hosted web analytics solution.","services":{"$$id":{"name":"Umami","depends_on":["$$id-postgresql"],"image":"ghcr.io/umami-software/umami:$$core_version","volumes":[],"environment":["ADMIN_PASSWORD=$$secret_admin_password","DATABASE_URL=$$secret_database_url","DATABASE_TYPE=$$config_database_type","HASH_SALT=$$secret_hash_salt"],"ports":["3000"]},"$$id-postgresql":{"name":"PostgreSQL","depends_on":[],"image":"postgres:12-alpine","volumes":["$$id-postgresql-data:/var/lib/postgresql/data"],"environment":["POSTGRES_USER=$$config_postgres_user","POSTGRES_PASSWORD=$$secret_postgres_password","POSTGRES_DB=$$config_postgres_db"],"ports":[],"files":[{"location":"/docker-entrypoint-initdb.d/schema.postgresql.sql","content":"\n -- CreateTable\n CREATE TABLE \"account\" (\n \"user_id\" SERIAL NOT NULL,\n \"username\" VARCHAR(255) NOT NULL,\n \"password\" VARCHAR(60) NOT NULL,\n \"is_admin\" BOOLEAN NOT NULL DEFAULT false,\n \"created_at\" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,\n \"updated_at\" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,\n\n PRIMARY KEY (\"user_id\")\n );\n\n -- CreateTable\n CREATE TABLE \"event\" (\n \"event_id\" SERIAL NOT NULL,\n \"website_id\" INTEGER NOT NULL,\n \"session_id\" INTEGER NOT NULL,\n \"created_at\" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,\n \"url\" VARCHAR(500) NOT NULL,\n \"event_type\" VARCHAR(50) NOT NULL,\n \"event_value\" VARCHAR(50) NOT NULL,\n\n PRIMARY KEY (\"event_id\")\n );\n\n -- CreateTable\n CREATE TABLE \"pageview\" (\n \"view_id\" SERIAL NOT NULL,\n \"website_id\" INTEGER NOT NULL,\n \"session_id\" INTEGER NOT NULL,\n \"created_at\" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,\n \"url\" VARCHAR(500) NOT NULL,\n \"referrer\" VARCHAR(500),\n\n PRIMARY KEY (\"view_id\")\n );\n\n -- CreateTable\n CREATE TABLE \"session\" (\n \"session_id\" SERIAL NOT NULL,\n \"session_uuid\" UUID NOT NULL,\n \"website_id\" INTEGER NOT NULL,\n \"created_at\" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,\n \"hostname\" VARCHAR(100),\n \"browser\" VARCHAR(20),\n \"os\" VARCHAR(20),\n \"device\" VARCHAR(20),\n \"screen\" VARCHAR(11),\n \"language\" VARCHAR(35),\n \"country\" CHAR(2),\n\n PRIMARY KEY (\"session_id\")\n );\n\n -- CreateTable\n CREATE TABLE \"website\" (\n \"website_id\" SERIAL NOT NULL,\n \"website_uuid\" UUID NOT NULL,\n \"user_id\" INTEGER NOT NULL,\n \"name\" VARCHAR(100) NOT NULL,\n \"domain\" VARCHAR(500),\n \"share_id\" VARCHAR(64),\n \"created_at\" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,\n\n PRIMARY KEY (\"website_id\")\n );\n\n -- CreateIndex\n CREATE UNIQUE INDEX \"account.username_unique\" ON \"account\"(\"username\");\n\n -- CreateIndex\n CREATE INDEX \"event_created_at_idx\" ON \"event\"(\"created_at\");\n\n -- CreateIndex\n CREATE INDEX \"event_session_id_idx\" ON \"event\"(\"session_id\");\n\n -- CreateIndex\n CREATE INDEX \"event_website_id_idx\" ON \"event\"(\"website_id\");\n\n -- CreateIndex\n CREATE INDEX \"pageview_created_at_idx\" ON \"pageview\"(\"created_at\");\n\n -- CreateIndex\n CREATE INDEX \"pageview_session_id_idx\" ON \"pageview\"(\"session_id\");\n\n -- CreateIndex\n CREATE INDEX \"pageview_website_id_created_at_idx\" ON \"pageview\"(\"website_id\", \"created_at\");\n\n -- CreateIndex\n CREATE INDEX \"pageview_website_id_idx\" ON \"pageview\"(\"website_id\");\n\n -- CreateIndex\n CREATE INDEX \"pageview_website_id_session_id_created_at_idx\" ON \"pageview\"(\"website_id\", \"session_id\", \"created_at\");\n\n -- CreateIndex\n CREATE UNIQUE INDEX \"session.session_uuid_unique\" ON \"session\"(\"session_uuid\");\n\n -- CreateIndex\n CREATE INDEX \"session_created_at_idx\" ON \"session\"(\"created_at\");\n\n -- CreateIndex\n CREATE INDEX \"session_website_id_idx\" ON \"session\"(\"website_id\");\n\n -- CreateIndex\n CREATE UNIQUE INDEX \"website.website_uuid_unique\" ON \"website\"(\"website_uuid\");\n\n -- CreateIndex\n CREATE UNIQUE INDEX \"website.share_id_unique\" ON \"website\"(\"share_id\");\n\n -- CreateIndex\n CREATE INDEX \"website_user_id_idx\" ON \"website\"(\"user_id\");\n\n -- AddForeignKey\n ALTER TABLE \"event\" ADD FOREIGN KEY (\"session_id\") REFERENCES \"session\"(\"session_id\") ON DELETE CASCADE ON UPDATE CASCADE;\n\n -- AddForeignKey\n ALTER TABLE \"event\" ADD FOREIGN KEY (\"website_id\") REFERENCES \"website\"(\"website_id\") ON DELETE CASCADE ON UPDATE CASCADE;\n\n -- AddForeignKey\n ALTER TABLE \"pageview\" ADD FOREIGN KEY (\"session_id\") REFERENCES \"session\"(\"session_id\") ON DELETE CASCADE ON UPDATE CASCADE;\n\n -- AddForeignKey\n ALTER TABLE \"pageview\" ADD FOREIGN KEY (\"website_id\") REFERENCES \"website\"(\"website_id\") ON DELETE CASCADE ON UPDATE CASCADE;\n\n -- AddForeignKey\n ALTER TABLE \"session\" ADD FOREIGN KEY (\"website_id\") REFERENCES \"website\"(\"website_id\") ON DELETE CASCADE ON UPDATE CASCADE;\n\n -- AddForeignKey\n ALTER TABLE \"website\" ADD FOREIGN KEY (\"user_id\") REFERENCES \"account\"(\"user_id\") ON DELETE CASCADE ON UPDATE CASCADE;\n\n insert into account (username, password, is_admin) values ('admin', '$$hashed$$secret_admin_password', true);"}]}},"variables":[{"id":"$$secret_database_url","name":"DATABASE_URL","label":"Database URL for PostgreSQL","defaultValue":"postgresql://$$config_postgres_user:$$secret_postgres_password@$$id-postgresql:5432/$$config_postgres_db","description":""},{"id":"$$secret_hash_salt","name":"HASH_SALT","label":"Hash Salt","defaultValue":"$$generate_hex(64)","description":""},{"id":"$$config_database_type","name":"DATABASE_TYPE","label":"Database Type","defaultValue":"postgresql","description":""},{"id":"$$config_postgres_user","name":"POSTGRES_USER","label":"PostgreSQL User","defaultValue":"$$generate_username","description":""},{"id":"$$secret_postgres_password","name":"POSTGRES_PASSWORD","label":"PostgreSQL Password","defaultValue":"$$generate_password","description":""},{"id":"$$config_postgres_db","name":"POSTGRES_DB","label":"PostgreSQL Database","defaultValue":"umami","description":""},{"id":"$$secret_admin_password","name":"ADMIN_PASSWORD","label":"Initial Admin Password","defaultValue":"$$generate_password","description":"","showOnConfiguration":true}]},{"templateVersion":"1.0.0","defaultVersion":"v0.30.1","documentation":"https://docs.meilisearch.com/learn/getting_started/quick_start.html","type":"meilisearch","name":"MeiliSearch","description":"A lightning Fast, Ultra Relevant, and Typo-Tolerant Search Engine.","services":{"$$id":{"name":"MeiliSearch","documentation":"https://docs.meilisearch.com/","depends_on":[],"image":"getmeili/meilisearch:$$core_version","volumes":["$$id-datams:/meili_data/data.ms","$$id-data:/meili_data","$$id-snapshot:/snapshot","$$id-dump:/dumps"],"environment":["MEILI_MASTER_KEY=$$secret_meili_master_key"],"ports":["7700"]}},"variables":[{"id":"$$secret_meili_master_key","name":"MEILI_MASTER_KEY","label":"Master Key","defaultValue":"$$generate_hex(64)","description":"","showOnConfiguration":true}]},{"templateVersion":"1.0.0","ignore":true,"defaultVersion":"latest","documentation":"https://docs.ghost.org","arch":"amd64","type":"ghost-mariadb","name":"Ghost","subname":"(MariaDB)","description":"Free and open source blogging platform.","labels":["cms","blog"],"services":{"$$id":{"name":"Ghost","depends_on":["$$id-mariadb"],"image":"bitnami/ghost:$$core_version","volumes":["$$id-ghost:/bitnami/ghost"],"environment":["url=$$config_url","GHOST_HOST=$$config_ghost_host","GHOST_ENABLE_HTTPS=$$config_ghost_enable_https","GHOST_EMAIL=$$config_ghost_email","GHOST_PASSWORD=$$secret_ghost_password","GHOST_DATABASE_HOST=$$config_ghost_database_host","GHOST_DATABASE_USER=$$config_mariadb_user","GHOST_DATABASE_PASSWORD=$$secret_ghost_database_password","GHOST_DATABASE_NAME=$$config_mariadb_database","GHOST_DATABASE_PORT_NUMBER=3306"],"ports":["2368"]},"$$id-mariadb":{"name":"MariaDB","depends_on":[],"image":"bitnami/mariadb:latest","volumes":["$$id-mariadb:/bitnami/mariadb"],"environment":["MARIADB_USER=$$config_mariadb_user","MARIADB_PASSWORD=$$secret_mariadb_password","MARIADB_DATABASE=$$config_mariadb_database","MARIADB_ROOT_USER=$$config_mariadb_root_user","MARIADB_ROOT_PASSWORD=$$secret_mariadb_root_password"],"ports":[]}},"variables":[{"id":"$$config_url","name":"url","label":"URL","defaultValue":"$$generate_fqdn","description":""},{"id":"$$config_ghost_host","name":"GHOST_HOST","label":"Ghost Host","defaultValue":"$$generate_domain","description":""},{"id":"$$config_ghost_enable_https","name":"GHOST_ENABLE_HTTPS","label":"Ghost Enable HTTPS","defaultValue":"no","description":""},{"id":"$$config_ghost_email","name":"GHOST_EMAIL","label":"Ghost Default Email","defaultValue":"admin@example.com","description":""},{"id":"$$secret_ghost_password","name":"GHOST_PASSWORD","label":"Ghost Default Password","defaultValue":"$$generate_password","description":"","showOnConfiguration":true},{"id":"$$config_ghost_database_host","name":"GHOST_DATABASE_HOST","label":"Ghost Database Host","defaultValue":"$$id-mariadb","description":""},{"id":"$$config_ghost_database_user","name":"GHOST_DATABASE_USER","label":"MariaDB User","defaultValue":"$$config_mariadb_user","description":""},{"id":"$$secret_ghost_database_password","name":"GHOST_DATABASE_PASSWORD","label":"MariaDB Password","defaultValue":"$$secret_mariadb_password","description":""},{"id":"$$config_ghost_database_name","name":"GHOST_DATABASE_NAME","label":"MariaDB Database","defaultValue":"$$config_mariadb_database","description":""},{"id":"$$config_mariadb_user","name":"MARIADB_USER","label":"MariaDB User","defaultValue":"$$generate_username","description":""},{"id":"$$secret_mariadb_password","name":"MARIADB_PASSWORD","label":"MariaDB Password","defaultValue":"$$generate_password","description":""},{"id":"$$config_mariadb_database","name":"MARIADB_DATABASE","label":"MariaDB Database","defaultValue":"ghost","description":""},{"id":"$$config_mariadb_root_user","name":"MARIADB_ROOT_USER","label":"MariaDB Root User","defaultValue":"$$generate_username","description":""},{"id":"$$secret_mariadb_root_password","name":"MARIADB_ROOT_PASSWORD","label":"MariaDB Root Password","defaultValue":"$$generate_password","description":""}]},{"templateVersion":"1.0.0","defaultVersion":"5.25.3","documentation":"https://docs.ghost.org","type":"ghost-only","name":"Ghost","subname":"(without Database)","description":"Free and open source blogging platform.","services":{"$$id":{"name":"Ghost","image":"ghost:$$core_version","volumes":["$$id-ghost:/var/lib/ghost/content"],"environment":["url=$$config_url","database__client=$$config_database__client","database__connection__host=$$config_database__connection__host","database__connection__user=$$config_database__connection__user","database__connection__password=$$secret_database__connection__password","database__connection__database=$$config_database__connection__database"],"ports":["2368"]}},"variables":[{"id":"$$config_url","name":"url","label":"URL","defaultValue":"$$generate_fqdn","description":""},{"id":"$$config_database__client","name":"database__client","label":"Database Client","defaultValue":"mysql","description":"","required":true},{"id":"$$config_database__connection__host","name":"database__connection__host","label":"Database Host","defaultValue":"","description":"","required":true,"placeholder":"db.coolify.io"},{"id":"$$config_database__connection__user","name":"database__connection__user","label":"Database User","defaultValue":"","description":"","placeholder":"ghost","required":true},{"id":"$$secret_database__connection__password","name":"database__connection__password","label":"Database Password","defaultValue":"","description":"","placeholder":"superSecretP4ssword","showOnConfiguration":true,"required":true},{"id":"$$config_database__connection__database","name":"database__connection__database","label":"Database Name","defaultValue":"","description":"","placeholder":"ghost_db","required":true}]},{"templateVersion":"1.0.0","defaultVersion":"5.25.3","documentation":"https://docs.ghost.org","type":"ghost-mysql","name":"Ghost","subname":"(MySQL)","description":"Ghost is a free and open source blogging platform.","services":{"$$id":{"name":"Ghost","depends_on":["$$id-mysql"],"image":"ghost:$$core_version","volumes":["$$id-ghost:/var/lib/ghost/content"],"environment":["url=$$config_url","database__client=$$config_database__client","database__connection__host=$$config_database__connection__host","database__connection__user=$$config_mysql_user","database__connection__password=$$secret_mysql_password","database__connection__database=$$config_mysql_database"],"ports":["2368"]},"$$id-mysql":{"name":"MySQL","depends_on":[],"image":"mysql:8.0","volumes":["$$id-mysql:/var/lib/mysql"],"environment":["MYSQL_USER=$$config_mysql_user","MYSQL_PASSWORD=$$secret_mysql_password","MYSQL_DATABASE=$$config_mysql_database","MYSQL_ROOT_PASSWORD=$$secret_mysql_root_password"],"ports":[]}},"variables":[{"id":"$$config_url","name":"url","label":"URL","defaultValue":"$$generate_fqdn","description":""},{"id":"$$config_database__client","name":"database__client","label":"Database Client","defaultValue":"mysql","description":"","readOnly":true},{"id":"$$config_database__connection__host","name":"database__connection__host","label":"Database Host","defaultValue":"$$id-mysql","description":""},{"id":"$$config_mysql_user","main":"$$id-mysql","name":"MYSQL_USER","label":"MySQL User","defaultValue":"$$generate_username","description":""},{"id":"$$secret_mysql_password","main":"$$id-mysql","name":"MYSQL_PASSWORD","label":"MySQL Password","defaultValue":"$$generate_password","description":""},{"id":"$$config_mysql_database","main":"$$id-mysql","name":"MYSQL_DATABASE","label":"MySQL Database","defaultValue":"ghost","description":""},{"id":"$$secret_mysql_root_password","name":"MYSQL_ROOT_PASSWORD","label":"MySQL Root Password","defaultValue":"$$generate_password","description":""}]},{"templateVersion":"1.0.0","defaultVersion":"php8.1","documentation":"https://wordpress.org/","type":"wordpress","name":"WordPress","subname":"(MySQL)","description":"A content management system based on PHP.","labels":["wordpress","php","cms"],"services":{"$$id":{"name":"WordPress","depends_on":["$$id-mysql"],"image":"wordpress:$$core_version","volumes":["$$id-wordpress-data:/var/www/html"],"environment":["WORDPRESS_DB_HOST=$$config_wordpress_db_host","WORDPRESS_DB_USER=$$config_mysql_user","WORDPRESS_DB_PASSWORD=$$secret_mysql_password","WORDPRESS_DB_NAME=$$config_mysql_database","WORDPRESS_CONFIG_EXTRA=$$config_wordpress_config_extra"],"ports":["80"]},"$$id-mysql":{"name":"MySQL","depends_on":[],"image":"bitnami/mysql:5.7","imageArm":"mysql:8.0","volumes":["$$id-mysql-data:/bitnami/mysql/data"],"volumesArm":["$$id-mysql-data:/var/lib/mysql"],"environment":["MYSQL_ROOT_PASSWORD=$$secret_mysql_root_password","MYSQL_ROOT_USER=$$config_mysql_root_user","MYSQL_DATABASE=$$config_mysql_database","MYSQL_USER=$$config_mysql_user","MYSQL_PASSWORD=$$secret_mysql_password"]}},"variables":[{"id":"$$config_wordpress_db_host","name":"WORDPRESS_DB_HOST","label":"Database Host","defaultValue":"$$id-mysql","description":"","readOnly":true},{"id":"$$config_wordpress_config_extra","name":"WORDPRESS_CONFIG_EXTRA","label":"WordPress Config Extra","defaultValue":"","description":"","type":"textarea","placeholder":"define('WP_DEBUG', true);\ndefine('WP_DEBUG_LOG', true);\ndefine('WP_DEBUG_DISPLAY', false);\n@ini_set('display_errors', 0);\n"},{"id":"$$secret_mysql_root_password","name":"MYSQL_ROOT_PASSWORD","label":"MySQL Root Password","defaultValue":"$$generate_password","description":"","readOnly":true},{"id":"$$config_mysql_root_user","name":"MYSQL_ROOT_USER","label":"MySQL Root User","defaultValue":"$$generate_username","description":"","readOnly":true},{"id":"$$config_mysql_database","name":"MYSQL_DATABASE","label":"MySQL Database","defaultValue":"wordpress","description":"","readOnly":true},{"id":"$$config_mysql_user","name":"MYSQL_USER","label":"MySQL User","defaultValue":"$$generate_username","description":"","readOnly":true},{"id":"$$secret_mysql_password","name":"MYSQL_PASSWORD","label":"MySQL Password","defaultValue":"$$generate_password","description":"","readOnly":true}]},{"templateVersion":"1.0.0","defaultVersion":"php8.1","documentation":"https://wordpress.org/","type":"wordpress-only","name":"WordPress","subname":"(without DB)","description":"A content management system based on PHP.","labels":["wordpress","php","cms"],"services":{"$$id":{"name":"WordPress","image":"wordpress:$$core_version","volumes":["$$id-wordpress-data:/var/www/html"],"environment":["WORDPRESS_DB_HOST=$$config_wordpress_db_host","WORDPRESS_DB_PORT=$$config_wordpress_db_port","WORDPRESS_DB_USER=$$config_wordpress_db_user","WORDPRESS_DB_PASSWORD=$$secret_wordpress_db_password","WORDPRESS_DB_NAME=$$config_wordpress_db_name","WORDPRESS_CONFIG_EXTRA=$$config_wordpress_config_extra"],"ports":["80"]}},"variables":[{"id":"$$config_wordpress_db_host","name":"WORDPRESS_DB_HOST","label":"Database Host","defaultValue":"","description":"","placeholder":"db.coollabs.io","required":true},{"id":"$$config_wordpress_db_port","name":"WORDPRESS_DB_PORT","label":"Database Port","defaultValue":"","description":"","placeholder":"3306","required":true},{"id":"$$config_wordpress_db_user","name":"WORDPRESS_DB_USER","label":"Database User","defaultValue":"","description":"","placeholder":"wordpress","required":true},{"id":"$$secret_wordpress_db_password","name":"WORDPRESS_DB_PASSWORD","label":"Database Password","defaultValue":"","description":"","placeholder":"supers3cr3tpassw0rd!","required":true,"showOnConfiguration":true},{"id":"$$config_wordpress_db_name","name":"WORDPRESS_DB_NAME","label":"Database Name","defaultValue":"","description":"","placeholder":"wordpress","required":true},{"id":"$$config_wordpress_config_extra","name":"WORDPRESS_CONFIG_EXTRA","label":"Extra Config","defaultValue":"","description":"","type":"textarea","placeholder":"define('WP_DEBUG', true);\ndefine('WP_DEBUG_LOG', true);\ndefine('WP_DEBUG_DISPLAY', false);\n@ini_set('display_errors', 0);\n"}]},{"templateVersion":"1.0.0","defaultVersion":"4.9.0","documentation":"https://coder.com/docs/coder-oss/latest","type":"vscodeserver","name":"VSCode Server","description":"Visual Studio Code on a remote server, accessible through the browser.","labels":["vscode","ide"],"services":{"$$id":{"name":"VSCode Server","depends_on":[],"image":"codercom/code-server:$$core_version","volumes":["$$id-config-data:/home/coder/.local/share/code-server","$$id-vscodeserver-data:/home/coder","$$id-keys-directory:/root/.ssh","$$id-theme-and-plugin-directory:/root/.local/share/code-server"],"environment":["PASSWORD=$$secret_password"],"ports":["8080"]}},"variables":[{"id":"$$secret_password","name":"PASSWORD","label":"Password","defaultValue":"$$generate_password","description":"","showOnConfiguration":true}]},{"templateVersion":"1.0.0","defaultVersion":"RELEASE.2022-12-12T19-27-27Z","documentation":"https://min.io/docs/minio","type":"minio","name":"MinIO","description":"A cloud storage server compatible with Amazon S3.","labels":["storage","s3"],"services":{"$$id":{"name":"MinIO","command":"server /data --console-address :9001","depends_on":[],"image":"minio/minio:$$core_version","volumes":["$$id-minio-data:/data","$$id-data-write:/files"],"environment":["MINIO_SERVER_URL=$$config_coolify_fqdn_minio_console","MINIO_BROWSER_REDIRECT_URL=$$config_minio_browser_redirect_url","MINIO_DOMAIN=$$config_minio_domain","MINIO_ROOT_USER=$$config_minio_root_user","MINIO_ROOT_PASSWORD=$$secret_minio_root_password"],"ports":["9000","9001"],"proxy":[{"port":"9000","domain":"$$config_coolify_fqdn_minio_console"},{"port":"9001"}]}},"variables":[{"id":"$$config_coolify_fqdn_minio_console","name":"MINIO_SERVER_URL","label":"MinIO Server URL","defaultValue":"","description":"Specify the URL hostname the MinIO Console should use for connecting to the MinIO Server.","required":true},{"id":"$$config_minio_browser_redirect_url","name":"MINIO_BROWSER_REDIRECT_URL","label":"Browser Redirect URL","defaultValue":"$$generate_fqdn","description":""},{"id":"$$config_minio_domain","name":"MINIO_DOMAIN","label":"Domain","defaultValue":"$$generate_domain","description":""},{"id":"$$config_minio_root_user","name":"MINIO_ROOT_USER","label":"Root User","defaultValue":"$$generate_username","description":""},{"id":"$$secret_minio_root_password","name":"MINIO_ROOT_PASSWORD","label":"Root User Password","defaultValue":"$$generate_password","description":"","showOnConfiguration":true}]},{"templateVersion":"1.0.0","defaultVersion":"0.21.1","documentation":"https://fider.io/docs","type":"fider","name":"Fider","description":"A platform to collect and organize customer feedback.","labels":["suggestion","feedback"],"services":{"$$id":{"name":"Fider","image":"getfider/fider:$$core_version","depends_on":["$$id-postgresql"],"environment":["BASE_URL=$$config_base_url","DATABASE_URL=$$secret_database_url","JWT_SECRET=$$secret_jwt_secret","EMAIL_NOREPLY=$$config_email_noreply","EMAIL_MAILGUN_API=$$secret_email_mailgun_api","EMAIL_MAILGUN_REGION=$$config_email_mailgun_region","EMAIL_MAILGUN_DOMAIN=$$config_email_mailgun_domain","EMAIL_SMTP_HOST=$$config_email_smtp_host","EMAIL_SMTP_PORT=$$config_email_smtp_port","EMAIL_SMTP_USER=$$config_email_smtp_user","EMAIL_SMTP_PASSWORD=$$secret_email_smtp_password","EMAIL_SMTP_ENABLE_STARTTLS=$$config_email_smtp_enable_starttls"],"ports":["3000"]},"$$id-postgresql":{"name":"PostgreSQL","depends_on":[],"image":"postgres:12-alpine","volumes":["$$id-postgresql-data:/var/lib/postgresql/data"],"environment":["POSTGRES_USER=$$config_postgres_user","POSTGRES_PASSWORD=$$secret_postgres_password","POSTGRES_DB=$$config_postgres_db"]}},"variables":[{"id":"$$config_base_url","name":"BASE_URL","label":"Base URL","defaultValue":"$$generate_fqdn","description":""},{"id":"$$secret_database_url","name":"DATABASE_URL","label":"Database URL for PostgreSQL","defaultValue":"postgresql://$$config_postgres_user:$$secret_postgres_password@$$id-postgresql:5432/$$config_postgres_db?sslmode=disable","description":""},{"id":"$$secret_jwt_secret","name":"JWT_SECRET","label":"JWT Secret","defaultValue":"$$generate_hex(64)","description":""},{"id":"$$config_email_noreply","name":"EMAIL_NOREPLY","label":"No Reply Email Address","defaultValue":"noreply@example.com","description":""},{"id":"$$secret_email_mailgun_api","name":"EMAIL_MAILGUN_API","label":"Mailgun API Key","defaultValue":"","description":"","showOnConfiguration":true},{"id":"$$config_email_mailgun_region","name":"EMAIL_MAILGUN_REGION","label":"Mailgun Region","defaultValue":"EU","description":""},{"id":"$$config_email_mailgun_domain","name":"EMAIL_MAILGUN_DOMAIN","label":"Mailgun Domain","defaultValue":"","description":""},{"id":"$$config_email_smtp_host","name":"EMAIL_SMTP_HOST","label":"SMTP Host","defaultValue":"","description":""},{"id":"$$config_email_smtp_port","name":"EMAIL_SMTP_PORT","label":"SMTP Port","defaultValue":"587","description":""},{"id":"$$config_email_smtp_user","name":"EMAIL_SMTP_USER","label":"SMTP User","defaultValue":"","description":""},{"id":"$$secret_email_smtp_password","name":"EMAIL_SMTP_PASSWORD","label":"SMTP Password","defaultValue":"","description":"","showOnConfiguration":true},{"id":"$$config_email_smtp_enable_starttls","name":"EMAIL_SMTP_ENABLE_STARTTLS","label":"SMTP Enable StartTLS","defaultValue":"false","description":""},{"id":"$$config_postgres_user","name":"POSTGRES_USER","label":"PostgreSQL User","defaultValue":"$$generate_username","description":""},{"id":"$$secret_postgres_password","name":"POSTGRES_PASSWORD","label":"PostgreSQL Password","defaultValue":"$$generate_password","description":""},{"id":"$$config_postgres_db","name":"POSTGRES_DB","label":"PostgreSQL Database","defaultValue":"$$generate_username","description":""}]},{"templateVersion":"1.0.0","defaultVersion":"0.207.0","documentation":"https://docs.n8n.io","type":"n8n","name":"n8n.io","description":"A free and open node based Workflow Automation Tool.","labels":["workflow","automation","ifttt","zapier","nodered"],"services":{"$$id":{"name":"N8n","depends_on":[],"image":"n8nio/n8n:$$core_version","volumes":["$$id-data:/root/.n8n","$$id-data-write:/files","/var/run/docker.sock:/var/run/docker.sock"],"environment":["WEBHOOK_URL=$$config_webhook_url"],"ports":["5678"]}},"variables":[{"id":"$$config_webhook_url","name":"WEBHOOK_URL","label":"Webhook URL","defaultValue":"$$generate_fqdn","description":""}]},{"templateVersion":"1.0.0","defaultVersion":"stable","documentation":"https://plausible.io/doc/","arch":"amd64","type":"plausibleanalytics","name":"Plausible Analytics","description":"A lightweight and open-source website analytics tool.","labels":["analytics","statistics","plausible","gdpr","no-cookie","google analytics"],"services":{"$$id":{"name":"Plausible Analytics","command":"sh -c \"sleep 10 && /entrypoint.sh db createdb && /entrypoint.sh db migrate && /entrypoint.sh db init-admin && /entrypoint.sh run\"","depends_on":["$$id-postgresql","$$id-clickhouse"],"image":"plausible/analytics:$$core_version","environment":["ADMIN_USER_EMAIL=$$config_admin_user_email","ADMIN_USER_NAME=$$config_admin_user_name","ADMIN_USER_PWD=$$secret_admin_user_pwd","BASE_URL=$$config_base_url","SECRET_KEY_BASE=$$secret_secret_key_base","DISABLE_AUTH=$$config_disable_auth","DISABLE_REGISTRATION=$$config_disable_registration","DATABASE_URL=$$secret_database_url","CLICKHOUSE_DATABASE_URL=$$secret_clickhouse_database_url"],"ports":["8000"]},"$$id-postgresql":{"name":"PostgreSQL","image":"bitnami/postgresql:13","volumes":["$$id-postgresql-data:/bitnami/postgresql"],"environment":["POSTGRESQL_PASSWORD=$$secret_postgresql_password","POSTGRESQL_USERNAME=$$config_postgresql_username","POSTGRESQL_DATABASE=$$config_postgresql_database"]},"$$id-clickhouse":{"name":"Clickhouse","volumes":["$$id-clickhouse-data:/var/lib/clickhouse"],"image":"clickhouse/clickhouse-server:22.6-alpine","ulimits":{"nofile":{"soft":262144,"hard":262144}},"files":[{"location":"/etc/clickhouse-server/users.d/logging.xml","content":"warning true "},{"location":"/etc/clickhouse-server/config.d/logging.xml","content":"0 0 "},{"location":"/docker-entrypoint-initdb.d/init.query","content":"CREATE DATABASE IF NOT EXISTS plausible;"},{"location":"/docker-entrypoint-initdb.d/init-db.sh","content":"clickhouse client --queries-file /docker-entrypoint-initdb.d/init.query"}]}},"variables":[{"id":"$$config_base_url","name":"BASE_URL","label":"Base URL","defaultValue":"$$generate_fqdn","description":"You must set this to the FQDN of the Plausible Analytics instance. This is used to generate the links to the Plausible Analytics instance."},{"id":"$$secret_database_url","name":"DATABASE_URL","label":"Database URL for PostgreSQL","defaultValue":"postgresql://$$config_postgresql_username:$$secret_postgresql_password@$$id-postgresql:5432/$$config_postgresql_database","description":""},{"id":"$$secret_clickhouse_database_url","name":"CLICKHOUSE_DATABASE_URL","label":"Database URL for Clickhouse","defaultValue":"http://$$id-clickhouse:8123/plausible","description":""},{"id":"$$config_admin_user_email","name":"ADMIN_USER_EMAIL","label":"Admin Email Address","defaultValue":"admin@example.com","description":"This is the admin email. Please change it."},{"id":"$$config_admin_user_name","name":"ADMIN_USER_NAME","label":"Admin User Name","defaultValue":"$$generate_username","description":"This is the admin username. Please change it."},{"id":"$$secret_admin_user_pwd","name":"ADMIN_USER_PWD","label":"Admin User Password","defaultValue":"$$generate_password","description":"This is the admin password. Please change it.","showOnConfiguration":true},{"id":"$$secret_secret_key_base","name":"SECRET_KEY_BASE","label":"Secret Key Base","defaultValue":"$$generate_hex(64)","description":""},{"id":"$$config_disable_auth","name":"DISABLE_AUTH","label":"Authentication","defaultValue":"false","description":""},{"id":"$$config_disable_registration","name":"DISABLE_REGISTRATION","label":"Registration","defaultValue":"true","description":""},{"id":"$$config_postgresql_username","main":"$$id-postgresql","name":"POSTGRESQL_USERNAME","label":"PostgreSQL Username","defaultValue":"postgresql","description":""},{"id":"$$secret_postgresql_password","main":"$$id-postgresql","name":"POSTGRESQL_PASSWORD","label":"PostgreSQL Password","defaultValue":"$$generate_password","description":"","showOnConfiguration":true},{"id":"$$config_postgresql_database","main":"$$id-postgresql","name":"POSTGRESQL_DATABASE","label":"PostgreSQL Database","defaultValue":"plausible","description":""},{"id":"$$config_scriptName","name":"SCRIPT_NAME","label":"Custom Script Name","defaultValue":"plausible.js","description":"This is the default script name."}]},{"templateVersion":"1.0.0","defaultVersion":"0.99.1","documentation":"https://docs.nocodb.com","type":"nocodb","name":"NocoDB","description":"Turns any MySQL, PostgreSQL, SQL Server, SQLite & MariaDB into a smart-spreadsheet.","labels":["database","airtable","spreadsheet"],"services":{"$$id":{"name":"NocoDB","image":"nocodb/nocodb:$$core_version","environment":["PORT=$$config_port","NC_DB=$$config_nc_db","DATABASE_URL=$$secret_database_url","NC_PUBLIC_URL=$$config_public_url","NC_AUTH_JWT_SECRET=$$secret_auth_jwt_secret","NC_SENTRY_DSN=$$secret_sentry_dsn","NC_CONNECT_TO_EXTERNAL_DB_DISABLED=$$config_connect_to_external_db_disabled","NC_DISABLE_TELE=$$config_disable_tele"],"volumes":["$$id-data:/usr/app/data"],"ports":["8080"]}},"variables":[{"id":"$$config_nc_db","name":"NC_DB","label":"Database","defaultValue":"","description":"MySQL, PostgreSQL and MSSQL connection urls supported. If absent: A local SQLite will be created in root folder."},{"id":"$$config_port","name":"PORT","label":"Port","defaultValue":"8080","description":""},{"id":"$$secret_database_url","name":"DATABASE_URL","label":"Database URL","defaultValue":"","description":"JDBC URL Format. Can be used instead of NC_DB. Used in 1-Click Heroku deployment."},{"id":"$$config_public_url","name":"NC_PUBLIC_URL","label":"Public URL","defaultValue":"","description":"Used for sending Email invitations. If absent: Best guess from http request params."},{"id":"$$secret_auth_jwt_secret","name":"NC_AUTH_JWT_SECRET","label":"Auth JWT Secret","defaultValue":"$$generate_hex(64)","description":"JWT secret used for auth and storing other secrets. If absent: A Random secret will be generated."},{"id":"$$secret_sentry_dsn","name":"NC_SENTRY_DSN","label":"Sentry DSN","defaultValue":"","description":"For Sentry monitoring."},{"id":"$$config_connect_to_external_db_disabled","name":"NC_CONNECT_TO_EXTERNAL_DB_DISABLED","label":"Disable External Database","defaultValue":"0","description":"Disable Project creation with external database. (Enter \"1\" to disable)."},{"id":"$$config_disable_tele","name":"NC_DISABLE_TELE","label":"NocoDB Disable Telemetry","defaultValue":"1","description":"Disable telemetry (Enter \"1\" to disable)."}]}]
\ No newline at end of file