This commit is contained in:
Andras Bacsai 2022-11-02 15:19:20 +01:00
parent 923241ce1e
commit 2e713b459e
11 changed files with 243 additions and 93 deletions

View File

@ -1,3 +1,59 @@
- templateVersion: 1.0.0
defaultVersion: 0.56.2
type: trilium
name: Trilium Notes
services:
$$id:
image: zadam/trilium:$$core_version
environment: []
volumes:
- $$id-trilium:/home/node/trilium-data
ports:
- '8080'
variables: []
documentation: https://hub.docker.com/r/zadam/trilium
- templateVersion: 1.0.0
defaultVersion: 1.9.2
type: uptimekuma
name: UptimeKuma
services:
$$id:
image: louislam/uptime-kuma:$$core_version
environment: []
volumes:
- $$id-uptimekuma:/app/data
ports:
- '3001'
variables: []
documentation: https://hub.docker.com/r/louislam/uptime-kuma
- templateVersion: 1.0.0
defaultVersion: 5.8
type: languagetool
name: LanguageTool
services:
$$id:
image: silviof/docker-languagetool:$$core_version
environment: []
volumes:
- $$id-ngrams:/ngrams
ports:
- '8010'
variables: []
documentation: https://hub.docker.com/r/silviof/docker-languagetool
- templateVersion: 1.0.0
defaultVersion: 1.26.0
type: vaultwarden
name: VaultWarden
services:
$$id:
image: vaultwarden/server:$$core_version
environment: []
volumes:
- $$id-data:/data
ports:
- '80'
variables: []
documentation: https://hub.docker.com/r/vaultwarden/server
- templateVersion: 1.0.0 - templateVersion: 1.0.0
defaultVersion: 9.2.3 defaultVersion: 9.2.3
type: grafana type: grafana
@ -39,8 +95,8 @@
- _APP_OPTIONS_ABUSE=$$config__app_options_abuse - _APP_OPTIONS_ABUSE=$$config__app_options_abuse
- _APP_OPTIONS_FORCE_HTTPS=$$config__app_options_force_https - _APP_OPTIONS_FORCE_HTTPS=$$config__app_options_force_https
- _APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1 - _APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1
- _APP_DOMAIN=$$generate_fqdn - _APP_DOMAIN=$$config__app_domain
- _APP_DOMAIN_TARGET=$$generate_fqdn - _APP_DOMAIN_TARGET=$$config__app_domain_target
- _APP_REDIS_HOST=$$config__app_redis_host - _APP_REDIS_HOST=$$config__app_redis_host
- _APP_REDIS_PORT=$$config__app_redis_port - _APP_REDIS_PORT=$$config__app_redis_port
- _APP_REDIS_USER=$$config__app_redis_user - _APP_REDIS_USER=$$config__app_redis_user
@ -170,8 +226,8 @@
environment: environment:
- _APP_ENV=$$config__app_env - _APP_ENV=$$config__app_env
- _APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1 - _APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1
- _APP_DOMAIN=$$generate_fqdn - _APP_DOMAIN=$$config__app_domain
- _APP_DOMAIN_TARGET=$$generate_fqdn - _APP_DOMAIN_TARGET=$$config__app_domain_target
- _APP_REDIS_HOST=$$config__app_redis_host - _APP_REDIS_HOST=$$config__app_redis_host
- _APP_REDIS_PORT=$$config__app_redis_port - _APP_REDIS_PORT=$$config__app_redis_port
- _APP_REDIS_USER=$$config__app_redis_user - _APP_REDIS_USER=$$config__app_redis_user
@ -272,7 +328,7 @@
- OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network - OPEN_RUNTIMES_NETWORK=$$config_open_runtimes_network
volumes: [] volumes: []
entrypoint: usage --type database entrypoint: usage --type database
"$$id-usage-timeseries": "$$id-usage":
image: appwrite/appwrite:$$core_version image: appwrite/appwrite:$$core_version
environment: environment:
- _APP_ENV=$$config__app_env - _APP_ENV=$$config__app_env
@ -340,8 +396,8 @@
environment: environment:
- _APP_ENV=$$config__app_env - _APP_ENV=$$config__app_env
- _APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1 - _APP_OPENSSL_KEY_V1=$$secret__app_openssl_key_v1
- _APP_DOMAIN=$$generate_fqdn - _APP_DOMAIN=$$config__app_domain
- _APP_DOMAIN_TARGET=$$generate_fqdn - _APP_DOMAIN_TARGET=$$config__app_domain_target
- _APP_SYSTEM_SECURITY_EMAIL_ADDRESS=$$config__app_system_security_email_address - _APP_SYSTEM_SECURITY_EMAIL_ADDRESS=$$config__app_system_security_email_address
- _APP_REDIS_HOST=$$config__app_redis_host - _APP_REDIS_HOST=$$config__app_redis_host
- _APP_REDIS_PORT=$$config__app_redis_port - _APP_REDIS_PORT=$$config__app_redis_port
@ -503,7 +559,7 @@
- id: "$$secret__app_db_root_pass" - id: "$$secret__app_db_root_pass"
name: MARIADB_ROOT_PASSWORD name: MARIADB_ROOT_PASSWORD
label: MariaDB | _APP_DB_ROOT_PASS label: MariaDB | _APP_DB_ROOT_PASS
defaultValue: "$$generate_hex(16)" defaultValue: $$generate_hex(16)
description: MariaDB server root password. description: MariaDB server root password.
- id: "$$config__app_db_schema" - id: "$$config__app_db_schema"
name: MARIADB_DATABASE name: MARIADB_DATABASE
@ -518,7 +574,7 @@
- id: "$$secret__app_db_pass" - id: "$$secret__app_db_pass"
name: MARIADB_PASSWORD name: MARIADB_PASSWORD
label: MariaDB | _APP_DB_PASS label: MariaDB | _APP_DB_PASS
defaultValue: "$$generate_hex(16)" defaultValue: $$generate_hex(16)
description: MariaDB server user password. description: MariaDB server user password.
- id: "$$config__app_influxdb_host" - id: "$$config__app_influxdb_host"
name: _APP_INFLUXDB_HOST name: _APP_INFLUXDB_HOST
@ -622,18 +678,18 @@
sensitive data on your server. Appwrite server encrypts all secret data on your sensitive data on your server. Appwrite server encrypts all secret data on your
server like webhooks, HTTP passwords, user sessions, and storage files. Keep server like webhooks, HTTP passwords, user sessions, and storage files. Keep
it a secret and have a backup for it. it a secret and have a backup for it.
- id: "$$generate_fqdn" - id: "$$config__app_domain"
name: _APP_DOMAIN name: _APP_DOMAIN
label: General | _APP_DOMAIN label: General | _APP_DOMAIN
defaultValue: localhost defaultValue: $$generate_domain
description: Your Appwrite domain address. When setting a public suffix domain, description: Your Appwrite domain address. When setting a public suffix domain,
Appwrite will attempt to issue a valid SSL certificate automatically. When used 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 with a dev domain, Appwrite will assign a self-signed SSL certificate. The default
value is 'localhost'. value is 'localhost'.
- id: "$$generate_fqdn" - id: "$$config__app_domain_target"
name: _APP_DOMAIN_TARGET name: _APP_DOMAIN_TARGET
label: General | _APP_DOMAIN_TARGET label: General | _APP_DOMAIN_TARGET
defaultValue: localhost defaultValue: $$generate_fqdn
description: A DNS A record hostname to serve as a CNAME target for your Appwrite 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' custom domains. You can use the same value as used for the Appwrite '_APP_DOMAIN'
variable. The default value is 'localhost'. variable. The default value is 'localhost'.
@ -1214,12 +1270,12 @@
image: 'glitchtip/glitchtip:$$core_version' image: 'glitchtip/glitchtip:$$core_version'
volumes: [] volumes: []
environment: environment:
- PORT=3000
- GLITCHTIP_DOMAIN=$$config_glitchtip_domain - GLITCHTIP_DOMAIN=$$config_glitchtip_domain
- SECRET_KEY=$$secret_secret_key - SECRET_KEY=$$secret_secret_key
- DATABASE_URL=$$secret_database_url - DATABASE_URL=$$secret_database_url
- REDIS_URL=$$secret_redis_url - REDIS_URL=$$secret_redis_url
- DEFAULT_FROM_EMAIL=$$config_default_from_email - DEFAULT_FROM_EMAIL=$$config_default_from_email
- EMAIL_URL=$$secret_email_url
- EMAIL_HOST=$$config_email_host - EMAIL_HOST=$$config_email_host
- EMAIL_PORT=$$config_email_port - EMAIL_PORT=$$config_email_port
- EMAIL_HOST_USER=$$config_email_host_user - EMAIL_HOST_USER=$$config_email_host_user
@ -1233,8 +1289,41 @@
- DJANGO_SUPERUSER_EMAIL=$$config_django_superuser_email - DJANGO_SUPERUSER_EMAIL=$$config_django_superuser_email
- DJANGO_SUPERUSER_PASSWORD=$$secret_django_superuser_password - DJANGO_SUPERUSER_PASSWORD=$$secret_django_superuser_password
- DJANGO_SUPERUSER_USERNAME=$$config_django_superuser_username - DJANGO_SUPERUSER_USERNAME=$$config_django_superuser_username
- CELERY_WORKER_CONCURRENCY=$$config_celery_worker_concurrency
ports: ports:
- '8000' - '8080'
$$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: $$id-postgresql:
name: PostgreSQL name: PostgreSQL
depends_on: [] depends_on: []
@ -1255,11 +1344,23 @@
environment: [] environment: []
ports: [] ports: []
variables: variables:
- id: $$config_celery_worker_concurrency
main: $$id-worker
name: CELERY_WORKER_CONCURRENCY
label: Celery Worker Concurrency
defaultValue: '2'
description: ''
- id: $$config_glitchtip_domain - id: $$config_glitchtip_domain
name: GLITCHTIP_DOMAIN name: GLITCHTIP_DOMAIN
label: GlitchTip Domain label: GlitchTip Domain
defaultValue: $$generate_fqdn defaultValue: $$generate_fqdn
description: '' 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 - id: $$secret_database_url
name: DATABASE_URL name: DATABASE_URL
label: Database URL for PostgreSQL label: Database URL for PostgreSQL
@ -1321,11 +1422,13 @@
label: Mailgun API Key label: Mailgun API Key
defaultValue: '' defaultValue: ''
description: '' description: ''
showOnConfiguration: true
- id: $$secret_sendgrid_api_key - id: $$secret_sendgrid_api_key
name: SENDGRID_API_KEY name: SENDGRID_API_KEY
label: Sendgrid API Key label: Sendgrid API Key
defaultValue: '' defaultValue: ''
description: '' description: ''
showOnConfiguration: true
- id: $$config_enable_open_user_registration - id: $$config_enable_open_user_registration
name: ENABLE_OPEN_USER_REGISTRATION name: ENABLE_OPEN_USER_REGISTRATION
label: Enable Open User Registration label: Enable Open User Registration
@ -1334,12 +1437,12 @@
- id: $$config_django_superuser_email - id: $$config_django_superuser_email
name: DJANGO_SUPERUSER_EMAIL name: DJANGO_SUPERUSER_EMAIL
label: Django Superuser Email label: Django Superuser Email
defaultValue: '' defaultValue: noreply@example.com
description: '' description: ''
- id: $$config_django_superuser_username - id: $$config_django_superuser_username
name: DJANGO_SUPERUSER_USERNAME name: DJANGO_SUPERUSER_USERNAME
label: Django Superuser Username label: Django Superuser Username
defaultValue: '' defaultValue: $$generate_username
description: '' description: ''
- id: $$secret_django_superuser_password - id: $$secret_django_superuser_password
name: DJANGO_SUPERUSER_PASSWORD name: DJANGO_SUPERUSER_PASSWORD
@ -1356,13 +1459,13 @@
main: $$id-postgresql main: $$id-postgresql
name: POSTGRES_PASSWORD name: POSTGRES_PASSWORD
label: PostgreSQL Password label: PostgreSQL Password
defaultValue: '' defaultValue: $$generate_password
description: '' description: ''
- id: $$config_postgres_db - id: $$config_postgres_db
main: $$id-postgresql main: $$id-postgresql
name: POSTGRES_DB name: POSTGRES_DB
label: PostgreSQL Database label: PostgreSQL Database
defaultValue: hasura defaultValue: glitchtip
description: '' description: ''
- templateVersion: 1.0.0 - templateVersion: 1.0.0
defaultVersion: v2.13.0 defaultVersion: v2.13.0
@ -1429,8 +1532,8 @@
description: '' description: ''
- templateVersion: 1.0.0 - templateVersion: 1.0.0
defaultVersion: postgresql-v1.38.0 defaultVersion: postgresql-v1.38.0
type: umami type: umami-postgresql
name: Umami name: Umami (PostgreSQL)
description: >- description: >-
Umami is a simple, easy to use, self-hosted web analytics solution. The goal Umami is a simple, easy to use, self-hosted web analytics solution. The goal
is to provide you with a friendly privacy-focused alternative to Google is to provide you with a friendly privacy-focused alternative to Google
@ -1446,7 +1549,7 @@
environment: environment:
- ADMIN_PASSWORD=$$secret_admin_password - ADMIN_PASSWORD=$$secret_admin_password
- DATABASE_URL=$$secret_database_url - DATABASE_URL=$$secret_database_url
- DATABASE_TYPE=postgresql - DATABASE_TYPE=$$config_database_type
- HASH_SALT=$$secret_hash_salt - HASH_SALT=$$secret_hash_salt
ports: ports:
- '3000' - '3000'
@ -1610,6 +1713,11 @@
label: Hash Salt label: Hash Salt
defaultValue: $$generate_hex(64) defaultValue: $$generate_hex(64)
description: '' description: ''
- id: $$config_database_type
name: DATABASE_TYPE
label: Database Type
defaultValue: 'postgresql'
description: ''
- id: $$config_postgres_user - id: $$config_postgres_user
name: POSTGRES_USER name: POSTGRES_USER
label: PostgreSQL User label: PostgreSQL User
@ -1711,7 +1819,7 @@
- id: $$config_ghost_host - id: $$config_ghost_host
name: GHOST_HOST name: GHOST_HOST
label: Ghost Host label: Ghost Host
defaultValue: '' defaultValue: $$generate_domain
description: '' description: ''
- id: $$config_ghost_enable_https - id: $$config_ghost_enable_https
name: GHOST_ENABLE_HTTPS name: GHOST_ENABLE_HTTPS
@ -1728,6 +1836,7 @@
label: Ghost Default Password label: Ghost Default Password
defaultValue: $$generate_password defaultValue: $$generate_password
description: '' description: ''
showOnConfiguration: true
- id: $$config_ghost_database_host - id: $$config_ghost_database_host
name: GHOST_DATABASE_HOST name: GHOST_DATABASE_HOST
label: Ghost Database Host label: Ghost Database Host
@ -1879,7 +1988,7 @@
- templateVersion: 1.0.0 - templateVersion: 1.0.0
defaultVersion: php8.1 defaultVersion: php8.1
type: wordpress-only type: wordpress-only
name: WordPress (without MySQL) name: WordPress Only (No Database)
description: WordPress is a content management system based on PHP without MySQL. description: WordPress is a content management system based on PHP without MySQL.
services: services:
$$id: $$id:
@ -2148,7 +2257,7 @@
description: '' description: ''
- templateVersion: 1.0.0 - templateVersion: 1.0.0
defaultVersion: 0.198.1 defaultVersion: 0.198.1
type: n8nio type: n8n
name: n8n.io name: n8n.io
description: n8n is a free and open node based Workflow Automation Tool. description: n8n is a free and open node based Workflow Automation Tool.
services: services:

View File

@ -113,18 +113,20 @@ export async function migrateServicesToNewTemplate() {
} }
} }
async function appwrite(service: any, template: any) { async function appwrite(service: any, template: any) {
const { opensslKeyV1, executorSecret, mariadbUser, mariadbPassword, mariadbRootUserPassword, mariadbDatabase } = service.appwrite const { opensslKeyV1, executorSecret, mariadbHost, mariadbPort, mariadbUser, mariadbPassword, mariadbRootUserPassword, mariadbDatabase } = service.appwrite
const secrets = [ const secrets = [
`_APP_EXECUTOR_SECRET@@@${executorSecret}`, `_APP_EXECUTOR_SECRET@@@${executorSecret}`,
`_APP_OPENSSL_KEY_V1@@@${opensslKeyV1}`, `_APP_OPENSSL_KEY_V1@@@${opensslKeyV1}`,
`MARIADB_PASSWORD@@@${mariadbPassword}`, `_APP_DB_PASS@@@${mariadbPassword}`,
`MARIADB_ROOT_PASSWORD@@@${mariadbRootUserPassword}`, `_APP_DB_ROOT_PASS@@@${mariadbRootUserPassword}`,
] ]
const settings = [ const settings = [
`MARIADB_USER@@@${mariadbUser}`, `_APP_DB_HOST@@@${mariadbHost}`,
`MARIADB_DATABASE@@@${mariadbDatabase}`, `_APP_DB_PORT@@@${mariadbPort}`,
`_APP_DB_USER@@@${mariadbUser}`,
`_APP_DB_SCHEMA@@@${mariadbDatabase}`,
] ]
await migrateSecrets(secrets, service); await migrateSecrets(secrets, service);
await migrateSettings(settings, service, template); await migrateSettings(settings, service, template);
@ -157,7 +159,6 @@ async function weblate(service: any, template: any) {
} }
async function searxng(service: any, template: any) { async function searxng(service: any, template: any) {
const { secretKey, redisPassword } = service.searxng const { secretKey, redisPassword } = service.searxng
const { fqdn } = service
const secrets = [ const secrets = [
`SECRET_KEY@@@${secretKey}`, `SECRET_KEY@@@${secretKey}`,
@ -165,7 +166,7 @@ async function searxng(service: any, template: any) {
] ]
const settings = [ const settings = [
`SEARXNG_BASE_URL@@@${fqdn || '$$generate_fqdn'}` `SEARXNG_BASE_URL@@@$$generate_fqdn`
] ]
await migrateSettings(settings, service, template); await migrateSettings(settings, service, template);
await migrateSecrets(secrets, service); await migrateSecrets(secrets, service);
@ -180,20 +181,17 @@ async function glitchtip(service: any, template: any) {
const secrets = [ const secrets = [
`POSTGRES_PASSWORD@@@${postgresqlPassword}`, `POSTGRES_PASSWORD@@@${postgresqlPassword}`,
`SECRET_KEY@@@${secretKeyBase}`, `SECRET_KEY@@@${secretKeyBase}`,
`DATABASE_URL@@@${encrypt(`postgres://${postgresqlUser}:${decrypt(postgresqlPassword)}@${id}-postgresql:5432/${postgresqlDatabase}`)}`,
`REDIS_URL@@@${encrypt(`redis://${id}-redis:6379`)}`,
`EMAIL_HOST_PASSWORD@@@${emailSmtpPassword}`,
`MAILGUN_API_KEY@@@${mailgunApiKey}`, `MAILGUN_API_KEY@@@${mailgunApiKey}`,
`SENDGRID_API_KEY@@@${sendgridApiKey}`, `SENDGRID_API_KEY@@@${sendgridApiKey}`,
`DJANGO_SUPERUSER_PASSWORD@@@${defaultPassword}`, `DJANGO_SUPERUSER_PASSWORD@@@${defaultPassword}`,
`EMAIL_URL@@@${encrypt(`smtp://${emailSmtpUser}:${decrypt(emailSmtpPassword)}@${emailSmtpHost}:${emailSmtpPort}`)}`,
`DATABASE_URL@@@${encrypt(`postgres://${postgresqlUser}:${decrypt(postgresqlPassword)}@${id}-postgresql:5432/${postgresqlDatabase}`)}`,
`REDIS_URL@@@${encrypt(`redis://${id}-redis:6379`)}`
] ]
const settings = [ const settings = [
`POSTGRES_USER@@@${postgresqlUser}`, `POSTGRES_USER@@@${postgresqlUser}`,
`POSTGRES_DB@@@${postgresqlDatabase}`, `POSTGRES_DB@@@${postgresqlDatabase}`,
`DEFAULT_FROM_EMAIL@@@${defaultEmailFrom}`, `DEFAULT_FROM_EMAIL@@@${defaultEmailFrom}`,
`EMAIL_HOST@@@${emailSmtpHost}`,
`EMAIL_PORT@@@${emailSmtpPort}`,
`EMAIL_HOST_USER@@@${emailSmtpUser}`,
`EMAIL_USE_TLS@@@${emailSmtpUseTls}`, `EMAIL_USE_TLS@@@${emailSmtpUseTls}`,
`EMAIL_USE_SSL@@@${emailSmtpUseSsl}`, `EMAIL_USE_SSL@@@${emailSmtpUseSsl}`,
`EMAIL_BACKEND@@@${emailBackend}`, `EMAIL_BACKEND@@@${emailBackend}`,
@ -205,7 +203,7 @@ async function glitchtip(service: any, template: any) {
await migrateSecrets(secrets, service); await migrateSecrets(secrets, service);
// Remove old service data // Remove old service data
// await prisma.service.update({ where: { id: service.id }, data: { wordpress: { delete: true } } }) await prisma.service.update({ where: { id: service.id }, data: { type: 'glitchtip' } })
} }
async function hasura(service: any, template: any) { async function hasura(service: any, template: any) {
const { postgresqlUser, postgresqlPassword, postgresqlDatabase, graphQLAdminPassword } = service.hasura const { postgresqlUser, postgresqlPassword, postgresqlDatabase, graphQLAdminPassword } = service.hasura
@ -237,6 +235,7 @@ async function umami(service: any, template: any) {
`DATABASE_URL@@@${encrypt(`postgres://${postgresqlUser}:${decrypt(postgresqlPassword)}@${id}-postgresql:5432/${postgresqlDatabase}`)}`, `DATABASE_URL@@@${encrypt(`postgres://${postgresqlUser}:${decrypt(postgresqlPassword)}@${id}-postgresql:5432/${postgresqlDatabase}`)}`,
] ]
const settings = [ const settings = [
`DATABASE_TYPE@@@postgresql`,
`POSTGRES_USER@@@${postgresqlUser}`, `POSTGRES_USER@@@${postgresqlUser}`,
`POSTGRES_DB@@@${postgresqlDatabase}`, `POSTGRES_DB@@@${postgresqlDatabase}`,
] ]
@ -280,8 +279,8 @@ async function ghost(service: any, template: any) {
`MARIADB_USER@@@${mariadbUser}`, `MARIADB_USER@@@${mariadbUser}`,
`MARIADB_DATABASE@@@${mariadbDatabase}`, `MARIADB_DATABASE@@@${mariadbDatabase}`,
`MARIADB_ROOT_USER@@@${mariadbRootUser}`, `MARIADB_ROOT_USER@@@${mariadbRootUser}`,
`GHOST_HOST@@@${getDomain(fqdn) || '$$generate_fqdn'}`, `GHOST_HOST@@@$$generate_domain`,
`url@@@${fqdn || '$$generate_fqdn'}`, `url@@@$$generate_fqdn`,
`GHOST_ENABLE_HTTPS@@@${isHttps ? 'yes' : 'no'}` `GHOST_ENABLE_HTTPS@@@${isHttps ? 'yes' : 'no'}`
] ]
await migrateSettings(settings, service, template); await migrateSettings(settings, service, template);
@ -355,7 +354,6 @@ async function vscodeserver(service: any, template: any) {
} }
async function minio(service: any, template: any) { async function minio(service: any, template: any) {
const { rootUser, rootUserPassword, apiFqdn } = service.minio const { rootUser, rootUserPassword, apiFqdn } = service.minio
const { fqdn } = service
const secrets = [ const secrets = [
`MINIO_ROOT_PASSWORD@@@${rootUserPassword}`, `MINIO_ROOT_PASSWORD@@@${rootUserPassword}`,
@ -363,8 +361,8 @@ async function minio(service: any, template: any) {
const settings = [ const settings = [
`MINIO_ROOT_USER@@@${rootUser}`, `MINIO_ROOT_USER@@@${rootUser}`,
`MINIO_SERVER_URL@@@${apiFqdn}`, `MINIO_SERVER_URL@@@${apiFqdn}`,
`MINIO_BROWSER_REDIRECT_URL@@@${fqdn || '$$generate_fqdn'}`, `MINIO_BROWSER_REDIRECT_URL@@@$$generate_fqdn`,
`MINIO_DOMAIN@@@${getDomain(fqdn) || '$$generate_fqdn'}`, `MINIO_DOMAIN@@@$$generate_domain`,
] ]
await migrateSettings(settings, service, template); await migrateSettings(settings, service, template);
await migrateSecrets(secrets, service); await migrateSecrets(secrets, service);
@ -374,15 +372,16 @@ async function minio(service: any, template: any) {
} }
async function fider(service: any, template: any) { async function fider(service: any, template: any) {
const { postgresqlUser, postgresqlPassword, postgresqlDatabase, jwtSecret, emailNoreply, emailMailgunApiKey, emailMailgunDomain, emailMailgunRegion, emailSmtpHost, emailSmtpPort, emailSmtpUser, emailSmtpPassword, emailSmtpEnableStartTls } = service.fider const { postgresqlUser, postgresqlPassword, postgresqlDatabase, jwtSecret, emailNoreply, emailMailgunApiKey, emailMailgunDomain, emailMailgunRegion, emailSmtpHost, emailSmtpPort, emailSmtpUser, emailSmtpPassword, emailSmtpEnableStartTls } = service.fider
const { fqdn } = service const { id } = service
const secrets = [ const secrets = [
`JWT_SECRET@@@${jwtSecret}`, `JWT_SECRET@@@${jwtSecret}`,
emailMailgunApiKey && `EMAIL_MAILGUN_API_KEY@@@${emailMailgunApiKey}`, emailMailgunApiKey && `EMAIL_MAILGUN_API@@@${emailMailgunApiKey}`,
emailSmtpPassword && `EMAIL_SMTP_PASSWORD@@@${emailSmtpPassword}`, emailSmtpPassword && `EMAIL_SMTP_PASSWORD@@@${emailSmtpPassword}`,
`POSTGRES_PASSWORD@@@${postgresqlPassword}`, `POSTGRES_PASSWORD@@@${postgresqlPassword}`,
`DATABASE_URL@@@${encrypt(`postgresql://${postgresqlUser}:${decrypt(postgresqlPassword)}@${id}-postgresql:5432/${postgresqlDatabase}?sslmode=disable`)}`
] ]
const settings = [ const settings = [
`BASE_URL@@@${fqdn || '$$generate_fqdn'}`, `BASE_URL@@@$$generate_fqdn`,
`EMAIL_NOREPLY@@@${emailNoreply || 'noreply@example.com'}`, `EMAIL_NOREPLY@@@${emailNoreply || 'noreply@example.com'}`,
`EMAIL_MAILGUN_DOMAIN@@@${emailMailgunDomain || ''}`, `EMAIL_MAILGUN_DOMAIN@@@${emailMailgunDomain || ''}`,
`EMAIL_MAILGUN_REGION@@@${emailMailgunRegion || ''}`, `EMAIL_MAILGUN_REGION@@@${emailMailgunRegion || ''}`,
@ -403,22 +402,22 @@ async function fider(service: any, template: any) {
} }
async function plausibleAnalytics(service: any, template: any) { async function plausibleAnalytics(service: any, template: any) {
const { email, username, password, postgresqlUser, postgresqlPassword, postgresqlDatabase, secretKeyBase, scriptName } = service.plausibleAnalytics; const { email, username, password, postgresqlUser, postgresqlPassword, postgresqlDatabase, secretKeyBase, scriptName } = service.plausibleAnalytics;
const { id, fqdn } = service const { id } = service
const settings = [ const settings = [
`BASE_URL@@@${fqdn || '$$generate_fqdn'}`, `BASE_URL@@@$$generate_fqdn`,
`ADMIN_USER_EMAIL@@@${email}`, `ADMIN_USER_EMAIL@@@${email}`,
`ADMIN_USER_NAME@@@${username}`, `ADMIN_USER_NAME@@@${username}`,
`DISABLE_AUTH@@@false`, `DISABLE_AUTH@@@false`,
`DISABLE_REGISTRATION@@@true`, `DISABLE_REGISTRATION@@@true`,
`POSTGRESQL_USER@@@${postgresqlUser}`, `POSTGRESQL_USERNAME@@@${postgresqlUser}`,
`POSTGRESQL_DATABASE@@@${postgresqlDatabase}`, `POSTGRESQL_DATABASE@@@${postgresqlDatabase}`,
`SCRIPT_NAME@@@${scriptName}`, `SCRIPT_NAME@@@${scriptName}`,
] ]
const secrets = [ const secrets = [
`ADMIN_USER_PWD@@@${password}`, `ADMIN_USER_PWD@@@${password}`,
`SECRET_KEY_BASE@@@${secretKeyBase}`, `SECRET_KEY_BASE@@@${secretKeyBase}`,
`POSTGRES_PASSWORD@@@${postgresqlPassword}`, `POSTGRESQL_PASSWORD@@@${postgresqlPassword}`,
`DATABASE_URL@@@${encrypt(`postgres://${postgresqlUser}:${decrypt(postgresqlPassword)}@${id}-postgresql:5432/${postgresqlDatabase}`)}`, `DATABASE_URL@@@${encrypt(`postgres://${postgresqlUser}:${decrypt(postgresqlPassword)}@${id}-postgresql:5432/${postgresqlDatabase}`)}`,
] ]
await migrateSettings(settings, service, template); await migrateSettings(settings, service, template);
@ -435,8 +434,12 @@ async function migrateSettings(settings: any[], service: any, template: any) {
if (!value || value === 'null') { if (!value || value === 'null') {
continue; continue;
} }
// console.log('Migrating setting', name, value, 'for service', service.id, ', service name:', service.name) let variableName = template.variables.find((v: any) => v.name === name)?.id
const variableName = template.variables.find((v: any) => v.name === name)?.id if (!variableName) {
variableName = `$$config_${name.toLowerCase()}`
}
// console.log('Migrating setting', name, value, 'for service', service.id, ', service name:', service.name, 'variableName: ', variableName)
await prisma.serviceSetting.findFirst({ where: { name, serviceId: service.id } }) || await prisma.serviceSetting.create({ data: { name, value, variableName, service: { connect: { id: service.id } } } }) await prisma.serviceSetting.findFirst({ where: { name, serviceId: service.id } }) || await prisma.serviceSetting.create({ data: { name, value, variableName, service: { connect: { id: service.id } } } })
} }
} }

View File

@ -80,11 +80,28 @@ export async function getServiceStatus(request: FastifyRequest<OnlyId>) {
}); });
const containersArray = containers.trim().split('\n'); const containersArray = containers.trim().split('\n');
if (containersArray.length > 0 && containersArray[0] !== '') { if (containersArray.length > 0 && containersArray[0] !== '') {
const templates = await getTemplates();
let template = templates.find(t => t.type === service.type);
template = JSON.parse(JSON.stringify(template).replaceAll('$$id', service.id));
for (const container of containersArray) { for (const container of containersArray) {
let isRunning = false; let isRunning = false;
let isExited = false; let isExited = false;
let isRestarting = false; let isRestarting = false;
let isExcluded = false;
const containerObj = JSON.parse(container); 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 const status = containerObj.State
if (status === 'running') { if (status === 'running') {
isRunning = true; isRunning = true;
@ -97,11 +114,11 @@ export async function getServiceStatus(request: FastifyRequest<OnlyId>) {
} }
payload[containerObj.Names] = { payload[containerObj.Names] = {
status: { status: {
isExcluded,
isRunning, isRunning,
isExited, isExited,
isRestarting isRestarting
} }
} }
} }
} }
@ -119,8 +136,20 @@ export async function parseAndFindServiceTemplates(service: any, workdir?: strin
if (!isDeploy) { if (!isDeploy) {
for (const [key, value] of Object.entries(foundTemplate.services)) { for (const [key, value] of Object.entries(foundTemplate.services)) {
const realKey = key.replace('$$id', service.id) 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] = { parsedTemplate[realKey] = {
name: value.name, name,
image: value.image, image: value.image,
environment: [], environment: [],
fqdns: [], fqdns: [],
@ -131,23 +160,26 @@ export async function parseAndFindServiceTemplates(service: any, workdir?: strin
let [envKey, ...envValue] = env.split('=') let [envKey, ...envValue] = env.split('=')
envValue = envValue.join("=") envValue = envValue.join("=")
const variable = foundTemplate.variables.find(v => v.name === envKey) || foundTemplate.variables.find(v => v.id === envValue) const variable = foundTemplate.variables.find(v => v.name === envKey) || foundTemplate.variables.find(v => v.id === envValue)
const id = variable.id.replaceAll('$$', '') if (variable) {
const label = variable?.label const id = variable.id.replaceAll('$$', '')
const description = variable?.description const label = variable?.label
const defaultValue = variable?.defaultValue const description = variable?.description
const main = variable?.main || '$$id' const defaultValue = variable?.defaultValue
const type = variable?.type || 'input' const main = variable?.main || '$$id'
const placeholder = variable?.placeholder || '' const type = variable?.type || 'input'
const readonly = variable?.readonly || false const placeholder = variable?.placeholder || ''
const required = variable?.required || false const readonly = variable?.readonly || false
if (envValue.startsWith('$$config') || variable?.showOnConfiguration) { const required = variable?.required || false
if (envValue.startsWith('$$config_coolify')) { if (envValue.startsWith('$$config') || variable?.showOnConfiguration) {
continue if (envValue.startsWith('$$config_coolify')) {
continue
}
parsedTemplate[realKey].environment.push(
{ id, name: envKey, value: envValue, main, label, description, defaultValue, type, placeholder, required, readonly }
)
} }
parsedTemplate[realKey].environment.push(
{ id, name: envKey, value: envValue, main, label, description, defaultValue, type, placeholder, required, readonly }
)
} }
} }
} }
if (value?.proxy && value.proxy.length > 0) { if (value?.proxy && value.proxy.length > 0) {
@ -170,6 +202,7 @@ export async function parseAndFindServiceTemplates(service: any, workdir?: strin
} else { } else {
parsedTemplate = foundTemplate parsedTemplate = foundTemplate
} }
let strParsedTemplate = JSON.stringify(parsedTemplate) let strParsedTemplate = JSON.stringify(parsedTemplate)
// replace $$id and $$workdir // replace $$id and $$workdir
@ -185,17 +218,18 @@ export async function parseAndFindServiceTemplates(service: any, workdir?: strin
if (service.serviceSetting.length > 0) { if (service.serviceSetting.length > 0) {
for (const setting of service.serviceSetting) { for (const setting of service.serviceSetting) {
const { value, variableName } = setting const { value, variableName } = setting
const regex = new RegExp(`\\$\\$config_${variableName.replace('$$config_','')}\\"`, 'gi')
if (variableName.startsWith('$$config_coolify')) { if (variableName.startsWith('$$config_coolify')) {
continue; continue;
} }
if (value === '$$generate_fqdn') { if (value === '$$generate_fqdn') {
strParsedTemplate = strParsedTemplate.replaceAll(variableName, service.fqdn || '') strParsedTemplate = strParsedTemplate.replaceAll(regex, service.fqdn || '' + "\"")
} else if (value === '$$generate_domain') { } else if (value === '$$generate_domain') {
strParsedTemplate = strParsedTemplate.replaceAll(variableName, getDomain(service.fqdn)) strParsedTemplate = strParsedTemplate.replaceAll(regex, getDomain(service.fqdn) + "\"")
} else if (service.destinationDocker?.network && value === '$$generate_network') { } else if (service.destinationDocker?.network && value === '$$generate_network') {
strParsedTemplate = strParsedTemplate.replaceAll(variableName, service.destinationDocker.network) strParsedTemplate = strParsedTemplate.replaceAll(regex, service.destinationDocker.network + "\"")
} else { } else {
strParsedTemplate = strParsedTemplate.replaceAll(variableName, value) strParsedTemplate = strParsedTemplate.replaceAll(regex, value + "\"")
} }
} }
} }
@ -207,8 +241,8 @@ export async function parseAndFindServiceTemplates(service: any, workdir?: strin
const regexHashed = new RegExp(`\\$\\$hashed\\$\\$secret_${name}\\"`, 'gi') const regexHashed = new RegExp(`\\$\\$hashed\\$\\$secret_${name}\\"`, 'gi')
const regex = new RegExp(`\\$\\$secret_${name}\\"`, 'gi') const regex = new RegExp(`\\$\\$secret_${name}\\"`, 'gi')
if (value) { if (value) {
strParsedTemplate = strParsedTemplate.replaceAll(regexHashed, bcrypt.hashSync(value, 10) + "\"") strParsedTemplate = strParsedTemplate.replaceAll(regexHashed, bcrypt.hashSync(value.replaceAll("\"", "\\\""), 10) + "\"")
strParsedTemplate = strParsedTemplate.replaceAll(regex, value + "\"") strParsedTemplate = strParsedTemplate.replaceAll(regex, value.replaceAll("\"", "\\\"") + "\"")
} else { } else {
strParsedTemplate = strParsedTemplate.replaceAll(regexHashed, "\"") strParsedTemplate = strParsedTemplate.replaceAll(regexHashed, "\"")
strParsedTemplate = strParsedTemplate.replaceAll(regex, "\"") strParsedTemplate = strParsedTemplate.replaceAll(regex, "\"")
@ -229,10 +263,11 @@ export async function getService(request: FastifyRequest<OnlyId>) {
throw { status: 404, message: 'Service not found.' } throw { status: 404, message: 'Service not found.' }
} }
let template = {} let template = {}
let tags = []
if (service.type) { if (service.type) {
template = await parseAndFindServiceTemplates(service) template = await parseAndFindServiceTemplates(service)
tags = await getTags(service.type)
} }
const tags = await getTags(service.type)
return { return {
settings: await listSettings(), settings: await listSettings(),
service, service,
@ -240,7 +275,6 @@ export async function getService(request: FastifyRequest<OnlyId>) {
tags tags
} }
} catch ({ status, message }) { } catch ({ status, message }) {
console.log(status, message)
return errorHandler({ status, message }) return errorHandler({ status, message })
} }
} }
@ -291,7 +325,7 @@ export async function saveServiceType(request: FastifyRequest<SaveServiceType>,
} }
} }
if (variable.id.startsWith('$$config_')) { if (variable.id.startsWith('$$config_') || variable.id.startsWith('$$coolify_fqdn_')) {
const found = await prisma.serviceSetting.findFirst({ where: { name: variable.name, serviceId: id } }) const found = await prisma.serviceSetting.findFirst({ where: { name: variable.name, serviceId: id } })
if (!found) { if (!found) {
await prisma.serviceSetting.create({ await prisma.serviceSetting.create({
@ -513,7 +547,6 @@ export async function saveService(request: FastifyRequest<SaveService>, reply: F
}); });
return reply.code(201).send() return reply.code(201).send()
} catch ({ status, message }) { } catch ({ status, message }) {
console.log({ status, message })
return errorHandler({ status, message }) return errorHandler({ status, message })
} }
} }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -2,27 +2,33 @@
export let id: any; export let id: any;
import { status } from '$lib/store'; import { status } from '$lib/store';
let serviceStatus = { let serviceStatus = {
isExcluded: false,
isExited: false, isExited: false,
isRunning: false, isRunning: false,
isRestarting: false, isRestarting: false,
isStopped: false isStopped: false
}; };
$: if (Object.keys($status.service.statuses).length > 0) { $: if (Object.keys($status.service.statuses).length > 0 && $status.service.statuses[id]?.status) {
let { isExited, isRunning, isRestarting } = $status.service.statuses[id].status; let { isExited, isRunning, isRestarting, isExcluded } = $status.service.statuses[id].status;
serviceStatus.isExited = isExited; serviceStatus.isExited = isExited;
serviceStatus.isRunning = isRunning; serviceStatus.isRunning = isRunning;
serviceStatus.isExcluded = isExcluded;
serviceStatus.isRestarting = isRestarting; serviceStatus.isRestarting = isRestarting;
serviceStatus.isStopped = !isExited && !isRunning && !isRestarting; serviceStatus.isStopped = !isExited && !isRunning && !isRestarting;
} else { } else {
serviceStatus.isExited = false; serviceStatus.isExited = false;
serviceStatus.isRunning = false; serviceStatus.isRunning = false;
serviceStatus.isExcluded = false;
serviceStatus.isRestarting = false; serviceStatus.isRestarting = false;
serviceStatus.isStopped = true; serviceStatus.isStopped = true;
} }
</script> </script>
{#if serviceStatus.isRunning} {#if serviceStatus.isExcluded}
<span class="badge font-bold uppercase rounded text-orange-500 mt-2">Excluded</span>
{:else if serviceStatus.isRunning}
<span class="badge font-bold uppercase rounded text-green-500 mt-2">Running</span> <span class="badge font-bold uppercase rounded text-green-500 mt-2">Running</span>
{:else if serviceStatus.isStopped || serviceStatus.isExited} {:else if serviceStatus.isStopped || serviceStatus.isExited}
<span class="badge font-bold uppercase rounded text-red-500 mt-2">Stopped</span> <span class="badge font-bold uppercase rounded text-red-500 mt-2">Stopped</span>

View File

@ -1,8 +1,8 @@
<script lang="ts"> <script lang="ts">
import { Tooltip } from 'flowbite-svelte'; import { Tooltip } from 'flowbite-svelte';
export let placement = 'bottom'; export let placement = 'bottom';
export let color = 'bg-coollabs font-thin text-left'; export let color = 'bg-coollabs font-thin text-left border-none p-4';
export let triggeredBy = '#tooltip-default'; export let triggeredBy = '#tooltip-default';
</script> </script>
<Tooltip {triggeredBy} {placement} arrow={false} {color} style="custom"><slot /></Tooltip> <Tooltip {triggeredBy} {placement} arrow={false} defaultClass={color} style="custom"><slot /></Tooltip>

View File

@ -81,12 +81,11 @@
<span>Logs</span> <span>Logs</span>
</li> </li>
<li <li
class:text-stone-600={$status.service.overallStatus === 'stopped'}
class="rounded" class="rounded"
class:bg-coollabs={$page.url.pathname === `/services/${$page.params.id}/logs`} class:bg-coollabs={$page.url.pathname === `/services/${$page.params.id}/logs`}
> >
<a <a
href={$status.service.overallStatus !== 'stopped' ? `/services/${$page.params.id}/logs` : ''} href={`/services/${$page.params.id}/logs`}
class="no-underline w-full" class="no-underline w-full"
><svg ><svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"

View File

@ -127,7 +127,7 @@
await post(`/services/${id}/wordpress/ftp`, { await post(`/services/${id}/wordpress/ftp`, {
ftpEnabled: false ftpEnabled: false
}); });
service.wordpress?.ftpEnabled && window.location.reload() service.wordpress?.ftpEnabled && window.location.reload();
} }
} catch (error) { } catch (error) {
return errorNotification(error); return errorNotification(error);

View File

@ -34,7 +34,7 @@
if (sure) { if (sure) {
$status.service.initialLoading = true; $status.service.initialLoading = true;
try { try {
if (service.type && $status.service.isRunning) { if (service.type && $status.service.overallStatus !== 'stopped') {
await post(`/services/${service.id}/stop`, {}); await post(`/services/${service.id}/stop`, {});
} }
await del(`/services/${service.id}`, { id: service.id }); await del(`/services/${service.id}`, { id: service.id });
@ -61,6 +61,6 @@
class:hover:bg-red-500={$appSession.isAdmin} class:hover:bg-red-500={$appSession.isAdmin}
class="btn btn-lg btn-error text-sm" class="btn btn-lg btn-error text-sm"
> >
Delete Application Delete Service
</button> </button>
</div> </div>

View File

@ -420,7 +420,7 @@
{#if template[oneService].environment.length > 0} {#if template[oneService].environment.length > 0}
{#each template[oneService].environment as variable} {#each template[oneService].environment as variable}
{#if variable.main === oneService} {#if variable.main === oneService}
<div class="grid grid-cols-2 items-center gap-2" > <div class="grid grid-cols-2 items-center gap-2">
<label class="h-10" for={variable.name} <label class="h-10" for={variable.name}
>{variable.label || variable.name} >{variable.label || variable.name}
{#if variable.description} {#if variable.description}