From 79a169f53e3bc5164292e17bc159737293207812 Mon Sep 17 00:00:00 2001 From: Telokis <6382729+Telokis@users.noreply.github.com> Date: Sun, 11 Aug 2024 15:18:11 +0200 Subject: [PATCH 01/37] Add initial docker-compose.yaml for Pterodactyl --- public/svgs/pterodactyl.png | Bin 0 -> 32004 bytes templates/compose/pterodactyl.yaml | 157 +++++++++++++++++++++++++++++ 2 files changed, 157 insertions(+) create mode 100644 public/svgs/pterodactyl.png create mode 100644 templates/compose/pterodactyl.yaml diff --git a/public/svgs/pterodactyl.png b/public/svgs/pterodactyl.png new file mode 100644 index 0000000000000000000000000000000000000000..a5addb87c5cf70b426a5a13a563a677088cad3a3 GIT binary patch literal 32004 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

MZBCd6fS^X@TN}n= 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 Ke1)t<@c#oi$r%~| literal 0 HcmV?d00001 diff --git a/templates/compose/pterodactyl.yaml b/templates/compose/pterodactyl.yaml new file mode 100644 index 000000000..436065a40 --- /dev/null +++ b/templates/compose/pterodactyl.yaml @@ -0,0 +1,157 @@ +# documentation: https://pterodactyl.io/ +# slogan: Pterodactyl is a free, open-source game server management panel +# tags: game, game server, management, panel, minecraft +# logo: svgs/pterodactyl.png +# port: 80 + +services: + mariadb: + image: mariadb:10.5 + restart: unless-stopped + command: --default-authentication-plugin=mysql_native_password + healthcheck: + test: + ["CMD-SHELL", "healthcheck.sh --connect --innodb_initialized || exit 1"] + start_period: 10s + interval: 10s + timeout: 1s + retries: 3 + environment: + - SERVICE_PASSWORD_MYSQL + - MYSQL_ROOT_PASSWORD=$SERVICE_PASSWORD_MYSQLROOT + - MYSQL_DATABASE=panel + - MYSQL_USER=pterodactyl + - MYSQL_PASSWORD=$SERVICE_PASSWORD_MYSQL + volumes: + - pterodactyl-db:/var/lib/mysql + + redis: + image: redis:alpine + restart: unless-stopped + healthcheck: + test: ["CMD-SHELL", "redis-cli ping || exit 1"] + interval: 10s + timeout: 1s + retries: 3 + + pterodactyl: + image: ghcr.io/pterodactyl/panel:latest + restart: unless-stopped + volumes: + - "panel-var:/app/var/" + - "panel-nginx:/etc/nginx/http.d/" + - "panel-certs:/etc/letsencrypt/" + - "panel-logs:/app/storage/logs" + healthcheck: + test: ["CMD-SHELL", "curl -sf http://localhost:80 || exit 1"] + interval: 10s + timeout: 1s + retries: 3 + environment: + - SERVICE_FQDN_PTERODACTYL + + - APP_ENV=production + - APP_ENVIRONMENT_ONLY=false + - APP_URL=${PTERODACTYL_PUBLIC_FQDN:-$SERVICE_FQDN_PTERODACTYL} + - APP_TIMEZONE=${TIMEZONE:-UTC} + - APP_SERVICE_AUTHOR=$APP_SERVICE_AUTHOR + - LOG_LEVEL=${LOG_LEVEL:-debug} + + - CACHE_DRIVER=redis + - SESSION_DRIVER=redis + - QUEUE_DRIVER=redis + - REDIS_HOST=redis + + - DB_HOST=mariadb + - DB_PORT=3306 + - DB_PASSWORD=$SERVICE_PASSWORD_MYSQL + + - MAIL_FROM=$MAIL_FROM + - MAIL_DRIVER=$MAIL_DRIVER + - MAIL_HOST=$MAIL_HOST + - MAIL_PORT=$MAIL_PORT + - MAIL_USERNAME=$MAIL_USERNAME + - MAIL_PASSWORD=$MAIL_PASSWORD + - MAIL_ENCRYPTION=$MAIL_ENCRYPTION + + wings: + image: ghcr.io/pterodactyl/wings:latest + restart: unless-stopped + environment: + - TZ=${TIMEZONE:-UTC} + - WINGS_USERNAME=pterodactyl + healthcheck: + test: ["CMD", "curl", "-sf http://localhost:8080"] + interval: 10s + timeout: 1s + retries: 3 + volumes: + - "/var/run/docker.sock:/var/run/docker.sock" + - "/var/lib/docker/containers/:/var/lib/docker/containers/" + - "wings-lib:/var/lib/pterodactyl/" + - "wings-logs:/var/log/pterodactyl/" + + - type: bind + source: ./etc/config.yml + target: /etc/pterodactyl/config.yml + content: | + docker: + network: + interface: 172.28.0.1 + dns: + - 1.1.1.1 + - 1.0.0.1 + name: pterodactyl_nw + ispn: false + driver: "" + network_mode: pterodactyl_nw + is_internal: false + enable_icc: true + network_mtu: 1500 + interfaces: + v4: + subnet: 172.28.0.0/16 + gateway: 172.28.0.1 + v6: + subnet: fdba:17c8:6c94::/64 + gateway: fdba:17c8:6c94::1011 + +volumes: + panel-var: + panel-nginx: + panel-certs: + panel-logs: + wings-lib: + wings-logs: + pterodactyl-db: +# Instructions: +# - Wait for the Pterodactyl service to be healthy (can take a few minutes) +# - Use the command `php artisan p:user:make --no-interaction --admin=1 --email= --username= --name-first= --name-last= --password=` in the Pterodactyl container to create an admin user. +# - Login to the panel using the created user +# - Go to the Admin panel (Cog icon at the top) +# - Go to "Locations" on the left +# - Create a new location +# - Go to "Nodes" on the left +# - Create a new node +# - Specify a temporary FQDN like "localhost" +# - /!\ Check "Use HTTP Connection" /!\ +# - Go to the "Configuration" tab of your newly created node +# - Copy the configuration file +# - In Coolify go to the "Storage" menu for your resource. +# - Find the big text area associated with `config.yml` for Wings +# - Paste the configuration at the top of this file, above `docker:` +# - Edit the line `remote: ''` to `remote: 'http://pterodactyl'` +# - Save the file +# - On the Pterodactyl panel for the node, go to the "Settings" tab +# - Change the "Fully Qualified Domain Name" from `localhost` to `wings` +# - Go to the "About" tab and confirm that the "Information" section shows the "Daemon Version" properly. + +# +----------+--------------------------------------+ +# | Field | Value | +# +----------+--------------------------------------+ +# | UUID | 6b3083ca-274b-4a77-b88f-6fbf5e4f286f | +# | Email | telokis@example.com | +# | Username | telokis | +# | Name | Telo Kis | +# | Admin | Yes | +# +----------+--------------------------------------+ From de6be8c840f7737a6f51e8cd5f620f0e6c47fecc Mon Sep 17 00:00:00 2001 From: Telokis <6382729+Telokis@users.noreply.github.com> Date: Sun, 11 Aug 2024 21:06:24 +0200 Subject: [PATCH 02/37] Fix a lot of small mistakes --- templates/compose/pterodactyl.yaml | 45 +++--------------------------- 1 file changed, 4 insertions(+), 41 deletions(-) diff --git a/templates/compose/pterodactyl.yaml b/templates/compose/pterodactyl.yaml index 436065a40..19315b4ce 100644 --- a/templates/compose/pterodactyl.yaml +++ b/templates/compose/pterodactyl.yaml @@ -41,7 +41,6 @@ services: - "panel-var:/app/var/" - "panel-nginx:/etc/nginx/http.d/" - "panel-certs:/etc/letsencrypt/" - - "panel-logs:/app/storage/logs" healthcheck: test: ["CMD-SHELL", "curl -sf http://localhost:80 || exit 1"] interval: 10s @@ -54,7 +53,7 @@ services: - APP_ENVIRONMENT_ONLY=false - APP_URL=${PTERODACTYL_PUBLIC_FQDN:-$SERVICE_FQDN_PTERODACTYL} - APP_TIMEZONE=${TIMEZONE:-UTC} - - APP_SERVICE_AUTHOR=$APP_SERVICE_AUTHOR + - APP_SERVICE_AUTHOR=${APP_SERVICE_AUTHOR:-author@example.com} - LOG_LEVEL=${LOG_LEVEL:-debug} - CACHE_DRIVER=redis @@ -78,17 +77,14 @@ services: image: ghcr.io/pterodactyl/wings:latest restart: unless-stopped environment: + - SERVICE_FQDN_WINGS_8080 - TZ=${TIMEZONE:-UTC} - WINGS_USERNAME=pterodactyl - healthcheck: - test: ["CMD", "curl", "-sf http://localhost:8080"] - interval: 10s - timeout: 1s - retries: 3 volumes: - "/var/run/docker.sock:/var/run/docker.sock" - "/var/lib/docker/containers/:/var/lib/docker/containers/" - - "wings-lib:/var/lib/pterodactyl/" + - "/var/lib/pterodactyl/:/var/lib/pterodactyl/" # See https://discord.com/channels/122900397965705216/493443725012500490/1272195151309045902 + - "/tmp/pterodactyl/:/tmp/pterodactyl/" # See https://discord.com/channels/122900397965705216/493443725012500490/1272195151309045902 - "wings-logs:/var/log/pterodactyl/" - type: bind @@ -120,38 +116,5 @@ volumes: panel-var: panel-nginx: panel-certs: - panel-logs: - wings-lib: wings-logs: pterodactyl-db: -# Instructions: -# - Wait for the Pterodactyl service to be healthy (can take a few minutes) -# - Use the command `php artisan p:user:make --no-interaction --admin=1 --email= --username= --name-first= --name-last= --password=` in the Pterodactyl container to create an admin user. -# - Login to the panel using the created user -# - Go to the Admin panel (Cog icon at the top) -# - Go to "Locations" on the left -# - Create a new location -# - Go to "Nodes" on the left -# - Create a new node -# - Specify a temporary FQDN like "localhost" -# - /!\ Check "Use HTTP Connection" /!\ -# - Go to the "Configuration" tab of your newly created node -# - Copy the configuration file -# - In Coolify go to the "Storage" menu for your resource. -# - Find the big text area associated with `config.yml` for Wings -# - Paste the configuration at the top of this file, above `docker:` -# - Edit the line `remote: ''` to `remote: 'http://pterodactyl'` -# - Save the file -# - On the Pterodactyl panel for the node, go to the "Settings" tab -# - Change the "Fully Qualified Domain Name" from `localhost` to `wings` -# - Go to the "About" tab and confirm that the "Information" section shows the "Daemon Version" properly. - -# +----------+--------------------------------------+ -# | Field | Value | -# +----------+--------------------------------------+ -# | UUID | 6b3083ca-274b-4a77-b88f-6fbf5e4f286f | -# | Email | telokis@example.com | -# | Username | telokis | -# | Name | Telo Kis | -# | Admin | Yes | -# +----------+--------------------------------------+ From 81e9c6d8a3c02229bef75f586acadfc357a1400f Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Fri, 22 Nov 2024 17:26:28 +0100 Subject: [PATCH 03/37] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0a3ce0132..e834ecb34 100644 --- a/README.md +++ b/README.md @@ -150,7 +150,7 @@ By subscribing to the cloud version, you get the Coolify server for the same pri | Andras Bacsai | Peak | |------------|------------| | Andras Bacsai | Peak Labs | -| | | +| | | # Repo Activity From 8a5a67813c3cc48d21bbbcf999199b3d8d72d168 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Fri, 22 Nov 2024 17:29:02 +0100 Subject: [PATCH 04/37] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e834ecb34..a3ea4a272 100644 --- a/README.md +++ b/README.md @@ -147,10 +147,10 @@ By subscribing to the cloud version, you get the Coolify server for the same pri # Core Maintainers -| Andras Bacsai | Peak | +| Andras Bacsai | 🏔️ Peak | |------------|------------| | Andras Bacsai | Peak Labs | -| | | +| | | # Repo Activity From cfbe21feccbfb815feefb8034f1d4de38b842790 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Fri, 22 Nov 2024 17:29:30 +0100 Subject: [PATCH 05/37] Revert "Update README.md" This reverts commit 8a5a67813c3cc48d21bbbcf999199b3d8d72d168. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a3ea4a272..e834ecb34 100644 --- a/README.md +++ b/README.md @@ -147,10 +147,10 @@ By subscribing to the cloud version, you get the Coolify server for the same pri # Core Maintainers -| Andras Bacsai | 🏔️ Peak | +| Andras Bacsai | Peak | |------------|------------| | Andras Bacsai | Peak Labs | -| | | +| | | # Repo Activity From 6497514f4ebab60959627cbac04d7378700d8119 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Fri, 22 Nov 2024 17:29:52 +0100 Subject: [PATCH 06/37] Reapply "Update README.md" This reverts commit cfbe21feccbfb815feefb8034f1d4de38b842790. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e834ecb34..a3ea4a272 100644 --- a/README.md +++ b/README.md @@ -147,10 +147,10 @@ By subscribing to the cloud version, you get the Coolify server for the same pri # Core Maintainers -| Andras Bacsai | Peak | +| Andras Bacsai | 🏔️ Peak | |------------|------------| | Andras Bacsai | Peak Labs | -| | | +| | | # Repo Activity From e97a122d6360beff054e7875c75f4f447487378e Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Fri, 22 Nov 2024 17:34:42 +0100 Subject: [PATCH 07/37] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a3ea4a272..8f0df0bda 100644 --- a/README.md +++ b/README.md @@ -149,7 +149,7 @@ By subscribing to the cloud version, you get the Coolify server for the same pri | Andras Bacsai | 🏔️ Peak | |------------|------------| -| Andras Bacsai | Peak Labs | +| Andras Bacsai | peaklabs-dev | | | | # Repo Activity From db9804cbe630e64eec64551c7f0a06dfaacff09b Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 27 Nov 2024 08:07:42 +0100 Subject: [PATCH 08/37] version++ --- config/constants.php | 2 +- versions.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/constants.php b/config/constants.php index 9ad6dda71..c947635be 100644 --- a/config/constants.php +++ b/config/constants.php @@ -2,7 +2,7 @@ return [ 'coolify' => [ - 'version' => '4.0.0-beta.373', + 'version' => '4.0.0-beta.374', 'self_hosted' => env('SELF_HOSTED', true), 'autoupdate' => env('AUTOUPDATE'), 'base_config_path' => env('BASE_CONFIG_PATH', '/data/coolify'), diff --git a/versions.json b/versions.json index 089cdc992..8175f7bae 100644 --- a/versions.json +++ b/versions.json @@ -1,10 +1,10 @@ { "coolify": { "v4": { - "version": "4.0.0-beta.373" + "version": "4.0.0-beta.374" }, "nightly": { - "version": "4.0.0-beta.374" + "version": "4.0.0-beta.375" }, "helper": { "version": "1.0.4" From 0d6c21d77b3bd7d10f5ec7d8734ec87d557c8a71 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 27 Nov 2024 08:07:54 +0100 Subject: [PATCH 09/37] fix: application view loading --- .../Project/Application/Configuration.php | 43 +++++++++++-------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/app/Livewire/Project/Application/Configuration.php b/app/Livewire/Project/Application/Configuration.php index d4ec8f581..5e7f83772 100644 --- a/app/Livewire/Project/Application/Configuration.php +++ b/app/Livewire/Project/Application/Configuration.php @@ -16,24 +16,33 @@ class Configuration extends Component public function mount() { - $project = currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first(); - if (! $project) { - return redirect()->route('dashboard'); - } - $environment = $project->load(['environments'])->environments->where('name', request()->route('environment_name'))->first()->load(['applications']); - if (! $environment) { - return redirect()->route('dashboard'); - } - $application = $environment->applications->where('uuid', request()->route('application_uuid'))->first(); - if (! $application) { - return redirect()->route('dashboard'); - } + $project = currentTeam() + ->projects() + ->select('id', 'uuid', 'team_id') + ->where('uuid', request()->route('project_uuid')) + ->firstOrFail(); + + $environment = $project->environments() + ->select('id', 'name', 'project_id') + ->where('name', request()->route('environment_name')) + ->firstOrFail(); + + $application = $environment->applications() + ->with(['destination']) + ->where('uuid', request()->route('application_uuid')) + ->firstOrFail(); + $this->application = $application; - $mainServer = $this->application->destination->server; - $servers = Server::ownedByCurrentTeam()->get(); - $this->servers = $servers->filter(function ($server) use ($mainServer) { - return $server->id != $mainServer->id; - }); + + if ($application->destination && $application->destination->server) { + $mainServer = $application->destination->server; + $this->servers = Server::ownedByCurrentTeam() + ->select('id', 'name') + ->where('id', '!=', $mainServer->id) + ->get(); + } else { + $this->servers = collect(); + } } public function render() From 29217ff03f48e4b0218eac48f21398c70573723e Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Wed, 27 Nov 2024 14:33:24 +0100 Subject: [PATCH 10/37] fix: postiz service For some reason, Postiz hardcodes username for Postgres and Redis in their code, so we have to use their usernames to make it work. --- templates/compose/postiz.yaml | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/templates/compose/postiz.yaml b/templates/compose/postiz.yaml index 278bd12c6..503d0f67e 100644 --- a/templates/compose/postiz.yaml +++ b/templates/compose/postiz.yaml @@ -13,9 +13,8 @@ services: - FRONTEND_URL=${SERVICE_FQDN_POSTIZ} - NEXT_PUBLIC_BACKEND_URL=${SERVICE_FQDN_POSTIZ}/api - JWT_SECRET=${SERVICE_PASSWORD_JWTSECRET} - - DATABASE_URL=postgresql://${SERVICE_USER_POSTGRESQL}:${SERVICE_PASSWORD_POSTGRESQL}@postgres:5432/${POSTGRESQL_DATABASE:-postiz-db} - # Changed Redis URL to use default username - - REDIS_URL=redis://${SERVICE_USER_REDIS}:${SERVICE_PASSWORD_REDIS}@redis:6379 + - DATABASE_URL=postgresql://postgres:${SERVICE_PASSWORD_POSTGRESQL}@postgres:5432/${POSTGRESQL_DATABASE:-postiz-db} + - REDIS_URL=redis://default:${SERVICE_PASSWORD_REDIS}@redis:6379 - BACKEND_INTERNAL_URL=http://localhost:3000 # Cloudflare R2 Settings @@ -75,7 +74,7 @@ services: # Misc Settings - NEXT_PUBLIC_DISCORD_SUPPORT=${NEXT_PUBLIC_DISCORD_SUPPORT} - NEXT_PUBLIC_POLOTNO=${NEXT_PUBLIC_POLOTNO} - - IS_GENERAL=${IS_GENERAL:-true} + - IS_GENERAL=true - NX_ADD_PLUGINS=${NX_ADD_PLUGINS:-false} # Payment Settings @@ -106,13 +105,11 @@ services: volumes: - postiz_postgresql_data:/var/lib/postgresql/data environment: - - POSTGRES_USER=${SERVICE_USER_POSTGRESQL} + - POSTGRES_USER=postgres - POSTGRES_PASSWORD=${SERVICE_PASSWORD_POSTGRESQL} - POSTGRES_DB=${POSTGRESQL_DATABASE:-postiz-db} healthcheck: - test: - - CMD-SHELL - - pg_isready -U ${SERVICE_USER_POSTGRESQL} -d ${POSTGRESQL_DATABASE:-postiz-db} + test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB:-postiz-db}"] interval: 5s timeout: 20s retries: 10 @@ -121,7 +118,6 @@ services: image: redis:7.2 environment: - REDIS_PASSWORD=${SERVICE_PASSWORD_REDIS} - - REDIS_USER=${SERVICE_USER_REDIS} command: redis-server --requirepass ${SERVICE_PASSWORD_REDIS} volumes: - postiz_redis_data:/data From e7e00e230647d835a8de0bd3573ced82ee77cfb9 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 27 Nov 2024 14:49:47 +0100 Subject: [PATCH 11/37] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8f0df0bda..dac48d127 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ Special thanks to our biggest sponsors! ### Special Sponsors -![image](https://github.com/user-attachments/assets/152bd1e0-e0c1-4d47-8a4f-0eb3700d2e61) +![image](https://github.com/user-attachments/assets/726fb63e-c3b8-4260-b3ac-06780605ec5d) * [CCCareers](https://cccareers.org/) - A career development platform connecting coding bootcamp graduates with job opportunities in the tech industry. * [Hetzner](http://htznr.li/CoolifyXHetzner) - A German web hosting company offering affordable dedicated servers, cloud services, and web hosting solutions. @@ -50,6 +50,7 @@ Special thanks to our biggest sponsors! * [QuantCDN](https://www.quantcdn.io/?ref=coolify.io) - A content delivery network (CDN) optimizing website performance through global content distribution. * [Arcjet](https://arcjet.com/?ref=coolify.io) - A cloud-based platform providing real-time protection against API abuse and bot attacks. * [SupaGuide](https://supa.guide/?ref=coolify.io) - A comprehensive resource hub offering guides and tutorials for web development using Supabase. +* [GoldenVM](https://billing.goldenvm.com/?ref=coolify.io) - A cloud hosting provider offering scalable infrastructure solutions for businesses of all sizes. * [Tigris](https://tigrisdata.com/?ref=coolify.io) - A fully managed serverless object storage service compatible with Amazon S3 API. Offers high performance, scalability, and built-in search capabilities for efficient data management. * [Advin](https://coolify.ad.vin/?ref=coolify.io) - A digital advertising agency specializing in programmatic advertising and data-driven marketing strategies. * [Treive](https://trieve.ai/?ref=coolify.io) - An AI-powered search and discovery platform for enhancing information retrieval in large datasets. @@ -90,7 +91,6 @@ Special thanks to our biggest sponsors! Paweł Pierścionek Michael Mazurczak Formbricks -Adith Suhas StartupFame Jonas Jaeger JP From daa2700b1c4679637206f52502476240e79e1c79 Mon Sep 17 00:00:00 2001 From: Luna Midori <118759930+lunamidori5@users.noreply.github.com> Date: Wed, 27 Nov 2024 22:37:18 -0800 Subject: [PATCH 12/37] Added support for Endeavour OS as arch --- scripts/install.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/install.sh b/scripts/install.sh index 3f1bec0c4..1a039f64f 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -83,6 +83,11 @@ if [ "$OS_TYPE" = "manjaro" ] || [ "$OS_TYPE" = "manjaro-arm" ]; then OS_TYPE="arch" fi +# Check if the OS is Endeavour OS, if so, change it to arch +if [ "$OS_TYPE" = "endeavouros" ]; then + OS_TYPE="arch" +fi + # Check if the OS is Asahi Linux, if so, change it to fedora if [ "$OS_TYPE" = "fedora-asahi-remix" ]; then OS_TYPE="fedora" From 0bc823108dfd02a0cddc97b46b74a9f5b4c7e8c8 Mon Sep 17 00:00:00 2001 From: kleintonno <116087195+kleintonno@users.noreply.github.com> Date: Thu, 28 Nov 2024 10:40:44 +0100 Subject: [PATCH 13/37] fix deploy selection in applications source menu --- resources/views/livewire/project/application/source.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/livewire/project/application/source.blade.php b/resources/views/livewire/project/application/source.blade.php index 4095c63e0..4aab498e9 100644 --- a/resources/views/livewire/project/application/source.blade.php +++ b/resources/views/livewire/project/application/source.blade.php @@ -43,7 +43,7 @@

Select another Private Key

@foreach ($privateKeys as $key) - {{ $key->name }} + {{ $key->name }} @endforeach
From 64ac17926245e60eb34ebdd19adb80c4807c38a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Tremblay=20Lefran=C3=A7ois?= Date: Thu, 28 Nov 2024 07:54:54 -0500 Subject: [PATCH 14/37] added overseer --- public/svgs/overseerr.svg | 15 +++++++++++++++ templates/compose/overseerr.yaml | 30 ++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 public/svgs/overseerr.svg create mode 100644 templates/compose/overseerr.yaml diff --git a/public/svgs/overseerr.svg b/public/svgs/overseerr.svg new file mode 100644 index 000000000..030df6a82 --- /dev/null +++ b/public/svgs/overseerr.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/templates/compose/overseerr.yaml b/templates/compose/overseerr.yaml new file mode 100644 index 000000000..8bf3a8666 --- /dev/null +++ b/templates/compose/overseerr.yaml @@ -0,0 +1,30 @@ +# documentation: https://docs.overseerr.dev/getting-started/installation#docker +# slogan: Overseerr is a request management and media discovery tool built to work with your existing Plex ecosystem. +# tags: media,request,plex,sonarr,radarr +# logo: svgs/overseerr.svg +# port: 5055 + +services: + overseerr: + image: sctx/overseerr:latest + environment: + - SERVICE_FQDN_OVERSEERR_5055 + - PUID=1000 + - PGID=1000 + - TZ=${TZ:-America/Toronto} + volumes: + - overseerr-config:/app/config + healthcheck: + test: + [ + "CMD", + "wget", + "--tries", + "1", + "--no-verbose", + "--spider", + "http://localhost:5055/api/v1/status", + ] + interval: 2s + timeout: 10s + retries: 15 From 5bc0e24d51cd4e5d4168818a437f703a9ca191a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Tremblay=20Lefran=C3=A7ois?= Date: Thu, 28 Nov 2024 08:03:06 -0500 Subject: [PATCH 15/37] fixed svg size --- public/svgs/overseerr.svg | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/public/svgs/overseerr.svg b/public/svgs/overseerr.svg index 030df6a82..8116787c2 100644 --- a/public/svgs/overseerr.svg +++ b/public/svgs/overseerr.svg @@ -1,15 +1,6 @@ - - - - - - - - - - - - - - - \ No newline at end of file + + + + + + From 246b137e6124b8c37afb42de3babc61ab904a1df Mon Sep 17 00:00:00 2001 From: Darren Sisson Date: Fri, 29 Nov 2024 14:07:47 +0000 Subject: [PATCH 16/37] fix formbricks template --- templates/compose/formbricks.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/templates/compose/formbricks.yaml b/templates/compose/formbricks.yaml index b0729284a..dde216b80 100644 --- a/templates/compose/formbricks.yaml +++ b/templates/compose/formbricks.yaml @@ -12,10 +12,10 @@ services: - WEBAPP_URL=$SERVICE_FQDN_FORMBRICKS - DATABASE_URL=postgres://$SERVICE_USER_POSTGRESQL:$SERVICE_PASSWORD_POSTGRESQL@postgresql:5432/${POSTGRESQL_DATABASE:-formbricks} - POSTGRES_PASSWORD=${SERVICE_PASSWORD_POSTGRESQL} - - NEXTAUTH_SECRET=$SERVICE_BASE64_64_NEXTAUTH + - NEXTAUTH_SECRET=$SERVICE_BASE64_NEXTAUTH - NEXTAUTH_URL=$SERVICE_FQDN_FORMBRICKS - - ENCRYPTION_KEY=$SERVICE_BASE64_64_ENCRYPTION - - CRON_SECRET=$SERVICE_BASE64_64_CRON + - ENCRYPTION_KEY=$SERVICE_BASE64_ENCRYPTION + - CRON_SECRET=$SERVICE_BASE64_CRON - ENTERPRISE_LICENSE_KEY=${ENTERPRISE_LICENSE_KEY} - MAIL_FROM=${MAIL_FROM:-test@example.com} - SMTP_HOST=${SMTP_HOST:-test.example.com} @@ -59,7 +59,7 @@ services: - REDIS_URL=${REDIS_URL} - REDIS_HTTP_URL=${REDIS_HTTP_URL} - DEFAULT_ORGANIZATION_ID=${DEFAULT_ORGANIZATION_ID} - - DEFAULT_ORGANIZATION_ROLE=${DEFAULT_ORGANIZATION_ROLE:-admin} + - DEFAULT_ORGANIZATION_ROLE=${DEFAULT_ORGANIZATION_ROLE:-owner} volumes: - formbricks-uploads:/apps/web/uploads/ depends_on: @@ -72,7 +72,7 @@ services: retries: 15 postgresql: - image: postgres:16-alpine + image: pgvector/pgvector:pg16 volumes: - formbricks-postgresql-data:/var/lib/postgresql/data environment: From eb3f2442bb3f121b861dce2126518b1908e40c82 Mon Sep 17 00:00:00 2001 From: Darren Sisson Date: Fri, 29 Nov 2024 15:57:48 +0000 Subject: [PATCH 17/37] fix budibase template --- templates/compose/budibase.yaml | 45 +++++++++++++++------------------ 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/templates/compose/budibase.yaml b/templates/compose/budibase.yaml index 516fefd68..a5ecb8fbb 100644 --- a/templates/compose/budibase.yaml +++ b/templates/compose/budibase.yaml @@ -9,11 +9,11 @@ services: image: budibase.docker.scarf.sh/budibase/apps environment: - SELF_HOSTED=1 - - COUCH_DB_URL=http://$SERVICE_USER_BUDIBASE_COUCHDB:$SERVICE_PASSWORD_BUDIBASE_COUCHDB@couchdb-service:5984 + - COUCH_DB_URL=http://$SERVICE_USER_COUCHDB:$SERVICE_PASSWORD_COUCHDB@couchdb-service:5984 - WORKER_URL=http://worker-service:4003 - MINIO_URL=http://minio-service:9000 - - MINIO_ACCESS_KEY=$SERVICE_USER_BUDIBASE_MINIO - - MINIO_SECRET_KEY=$SERVICE_PASSWORD_BUDIBASE_MINIO + - MINIO_ACCESS_KEY=$SERVICE_USER_MINIO + - MINIO_SECRET_KEY=$SERVICE_PASSWORD_MINIO - INTERNAL_API_KEY=$SERVICE_BASE64_128_BUDIBASE - BUDIBASE_ENVIRONMENT=${BUDIBASE_ENVIRONMENT:-PRODUCTION} - PORT=4002 @@ -22,14 +22,14 @@ services: - LOG_LEVEL=info - ENABLE_ANALYTICS=${ENABLE_ANALYTICS:-true} - REDIS_URL=redis-service:6379 - - REDIS_PASSWORD=$SERVICE_PASSWORD_BUDIBASE_REDIS + - REDIS_PASSWORD=$SERVICE_PASSWORD_REDIS - BB_ADMIN_USER_EMAIL= - BB_ADMIN_USER_PASSWORD= depends_on: - worker-service - redis-service healthcheck: - test: ["CMD", "curl", "-f", "http://app-service:4002"] + test: ["CMD", "wget", "--spider", "-qO-", "http://localhost:4002/health"] interval: 15s timeout: 15s retries: 5 @@ -43,21 +43,21 @@ services: - CLUSTER_PORT=10000 - API_ENCRYPTION_KEY=$SERVICE_BASE64_64_BUDIBASE - JWT_SECRET=$SERVICE_BASE64_64_BUDIBASE - - MINIO_ACCESS_KEY=$SERVICE_USER_BUDIBASE_MINIO - - MINIO_SECRET_KEY=$SERVICE_PASSWORD_BUDIBASE_MINIO + - MINIO_ACCESS_KEY=$SERVICE_USER_MINIO + - MINIO_SECRET_KEY=$SERVICE_PASSWORD_MINIO - MINIO_URL=http://minio-service:9000 - APPS_URL=http://app-service:4002 - - COUCH_DB_USERNAME=$SERVICE_USER_BUDIBASE_COUCHDB - - COUCH_DB_PASSWORD=$SERVICE_PASSWORD_BUDIBASE_COUCHDB - - COUCH_DB_URL=http://$SERVICE_USER_BUDIBASE_COUCHDB:$SERVICE_PASSWORD_BUDIBASE_COUCHDB@couchdb-service:5984 + - COUCH_DB_USERNAME=$SERVICE_USER_COUCHDB + - COUCH_DB_PASSWORD=$SERVICE_PASSWORD_COUCHDB + - COUCH_DB_URL=http://$SERVICE_USER_COUCHDB:$SERVICE_PASSWORD_COUCHDB@couchdb-service:5984 - INTERNAL_API_KEY=$SERVICE_BASE64_128_BUDIBASE - REDIS_URL=redis-service:6379 - - REDIS_PASSWORD=$SERVICE_PASSWORD_BUDIBASE_REDIS + - REDIS_PASSWORD=$SERVICE_PASSWORD_REDIS depends_on: - redis-service - minio-service healthcheck: - test: ["CMD", "curl", "-f", "http://worker-service:4003"] + test: ["CMD", "wget", "--spider", "-qO-", "http://localhost:4003/health"] interval: 15s timeout: 15s retries: 5 @@ -68,8 +68,8 @@ services: volumes: - minio_data:/data environment: - - MINIO_ACCESS_KEY=$SERVICE_USER_BUDIBASE_MINIO - - MINIO_SECRET_KEY=$SERVICE_PASSWORD_BUDIBASE_MINIO + - MINIO_ROOT_USER=$SERVICE_USER_MINIO + - MINIO_ROOT_PASSWORD=$SERVICE_PASSWORD_MINIO - MINIO_BROWSER=off command: server /data --console-address ":9001" healthcheck: @@ -105,8 +105,8 @@ services: couchdb-service: image: budibase/couchdb environment: - - COUCHDB_PASSWORD=$SERVICE_PASSWORD_BUDIBASE_COUCHDB - - COUCHDB_USER=$SERVICE_USER_BUDIBASE_COUCHDB + - COUCHDB_PASSWORD=$SERVICE_PASSWORD_COUCHDB + - COUCHDB_USER=$SERVICE_USER_COUCHDB - TARGETBUILD=docker-compose healthcheck: test: ["CMD", "curl", "-f", "http://localhost:5984/"] @@ -119,12 +119,12 @@ services: redis-service: image: redis - command: redis-server --requirepass "$SERVICE_PASSWORD_BUDIBASE_REDIS" + command: redis-server --requirepass "$SERVICE_PASSWORD_REDIS" volumes: - redis_data:/data healthcheck: test: - ["CMD", "redis-cli", "-a", "$SERVICE_PASSWORD_BUDIBASE_REDIS", "ping"] + ["CMD", "redis-cli", "-a", "$SERVICE_PASSWORD_REDIS", "ping"] interval: 15s timeout: 15s retries: 5 @@ -138,13 +138,8 @@ services: command: --debug --http-api-update bbapps bbworker bbproxy environment: - WATCHTOWER_HTTP_API=true - - WATCHTOWER_HTTP_API_TOKEN=$SERVICE_PASSWORD_BUDIBASE_WATCHTOWER + - WATCHTOWER_HTTP_API_TOKEN=$SERVICE_PASSWORD_WATCHTOWER - WATCHTOWER_CLEANUP=true labels: - "com.centurylinklabs.watchtower.enable=false" - healthcheck: - test: ["CMD", "curl", "-f", "http://watchtower-service:8080"] - interval: 15s - timeout: 15s - retries: 5 - start_period: 10s + exclude_from_hc: true From f6c0a92e95eb40a86b1b7a2415449c9dcdf763dd Mon Sep 17 00:00:00 2001 From: Mahmudul Hasan Sayan Date: Sun, 1 Dec 2024 10:10:40 +0600 Subject: [PATCH 18/37] Added kvm devices information in macos.yaml --- templates/compose/macos.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/templates/compose/macos.yaml b/templates/compose/macos.yaml index 70cebc144..018c55602 100644 --- a/templates/compose/macos.yaml +++ b/templates/compose/macos.yaml @@ -12,6 +12,8 @@ services: environment: - SERVICE_FQDN_MACOS_8006 - VERSION=15 + devices: + - /dev/kvm:/dev/kvm cap_add: - NET_ADMIN stop_grace_period: 2m From a8a5e29862ce5c124d2250b4204f21f95da02b17 Mon Sep 17 00:00:00 2001 From: Mahmudul Hasan Sayan Date: Sun, 1 Dec 2024 10:11:22 +0600 Subject: [PATCH 19/37] Added kvm devices information in windows.yaml --- templates/compose/windows.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/templates/compose/windows.yaml b/templates/compose/windows.yaml index ddbc4c3dc..f95f60797 100644 --- a/templates/compose/windows.yaml +++ b/templates/compose/windows.yaml @@ -12,6 +12,8 @@ services: environment: - SERVICE_FQDN_WINDOWS_8006 - VERSION=11 + devices: + - /dev/kvm:/dev/kvm cap_add: - NET_ADMIN stop_grace_period: 2m From 99fcd98e639a5c79583fea0c4977c444dbbd1e8d Mon Sep 17 00:00:00 2001 From: Oliver Frost Date: Sun, 1 Dec 2024 14:51:47 +0700 Subject: [PATCH 20/37] Added slogan to be included, when searching resources --- resources/views/livewire/project/new/select.blade.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/views/livewire/project/new/select.blade.php b/resources/views/livewire/project/new/select.blade.php index bc31d4530..323191bfd 100644 --- a/resources/views/livewire/project/new/select.blade.php +++ b/resources/views/livewire/project/new/select.blade.php @@ -169,7 +169,8 @@ } const filtered = Object.values(items).filter(item => { return (item.name?.toLowerCase().includes(searchLower) || - item.description?.toLowerCase().includes(searchLower)) + item.description?.toLowerCase().includes(searchLower) || + item.slogan?.toLowerCase().includes(searchLower)) }) return isSort ? filtered.sort(sortFn) : filtered; }, From 062c198d1dd503843074f2bbde2c080d1da3963d Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 2 Dec 2024 08:08:09 +0100 Subject: [PATCH 21/37] test zoom out --- resources/css/app.css | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/resources/css/app.css b/resources/css/app.css index 1195a3058..c3d46cc04 100644 --- a/resources/css/app.css +++ b/resources/css/app.css @@ -4,9 +4,23 @@ @tailwind components; @tailwind utilities; +html { + font-size: 93.75%; +} + +:root { + --vh: 1vh; +} + +@screen lg { + html { + font-size: 87.5%; + } +} + html, body { - @apply h-full bg-neutral-50 text-neutral-800 dark:bg-base dark:text-neutral-400; + @apply h-full bg-neutral-50 text-neutral-800 dark:bg-base dark:text-neutral-400 w-full; } body { From 428ba67cc0171a46b298f0f130bb9f44a634229d Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Mon, 2 Dec 2024 12:22:49 +0100 Subject: [PATCH 22/37] Disable Windows and MacOS Windows and MacOS templates need KVM to work, the problem is that KVM is only available on Linux. The second problem is that KVM needs to be installed on the host server, but most Coolify users use a VPS to host it, and almost all VPS providers block KVM access or installation on the host because the hole server is already KVM virtualized. --- templates/compose/macos.yaml | 1 + templates/compose/windows.yaml | 1 + 2 files changed, 2 insertions(+) diff --git a/templates/compose/macos.yaml b/templates/compose/macos.yaml index 018c55602..ab05cece5 100644 --- a/templates/compose/macos.yaml +++ b/templates/compose/macos.yaml @@ -1,3 +1,4 @@ +# ignore: true # documentation: https://github.com/dockur/macos # slogan: Run macOS in a containerized environment. # tags: macos, virtualization, container, os diff --git a/templates/compose/windows.yaml b/templates/compose/windows.yaml index f95f60797..f1d2a8573 100644 --- a/templates/compose/windows.yaml +++ b/templates/compose/windows.yaml @@ -1,3 +1,4 @@ +# ignore: true # documentation: https://github.com/dockur/windows # slogan: Run Windows in a containerized environment. # tags: windows, virtualization, container, os From d7703efcdc53c8b915b5cf3f42212e2e34557d75 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 2 Dec 2024 13:12:25 +0100 Subject: [PATCH 23/37] optimize db query --- .../Project/Application/Configuration.php | 31 ++++++++----------- 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/app/Livewire/Project/Application/Configuration.php b/app/Livewire/Project/Application/Configuration.php index 5e7f83772..cce3bdd39 100644 --- a/app/Livewire/Project/Application/Configuration.php +++ b/app/Livewire/Project/Application/Configuration.php @@ -16,29 +16,24 @@ class Configuration extends Component public function mount() { - $project = currentTeam() - ->projects() - ->select('id', 'uuid', 'team_id') - ->where('uuid', request()->route('project_uuid')) - ->firstOrFail(); - - $environment = $project->environments() - ->select('id', 'name', 'project_id') - ->where('name', request()->route('environment_name')) - ->firstOrFail(); - - $application = $environment->applications() - ->with(['destination']) + $this->application = Application::query() + ->whereHas('environment.project', function ($query) { + $query->where('team_id', currentTeam()->id) + ->where('uuid', request()->route('project_uuid')); + }) + ->whereHas('environment', function ($query) { + $query->where('name', request()->route('environment_name')); + }) ->where('uuid', request()->route('application_uuid')) + ->with(['destination' => function ($query) { + $query->select('id', 'server_id'); + }]) ->firstOrFail(); - $this->application = $application; - - if ($application->destination && $application->destination->server) { - $mainServer = $application->destination->server; + if ($this->application->destination && $this->application->destination->server_id) { $this->servers = Server::ownedByCurrentTeam() ->select('id', 'name') - ->where('id', '!=', $mainServer->id) + ->where('id', '!=', $this->application->destination->server_id) ->get(); } else { $this->servers = collect(); From 8b634252d12afeda75af7ad91039c4149e58de94 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Mon, 2 Dec 2024 14:13:09 +0100 Subject: [PATCH 24/37] Update service-templates.json --- templates/service-templates.json | 49 ++++++++++++-------------------- 1 file changed, 18 insertions(+), 31 deletions(-) diff --git a/templates/service-templates.json b/templates/service-templates.json index 36a2cf4d9..0fff92f86 100644 --- a/templates/service-templates.json +++ b/templates/service-templates.json @@ -233,7 +233,7 @@ "budibase": { "documentation": "https://docs.budibase.com/docs/docker-compose?utm_source=coolify.io", "slogan": "Low code platform for building business apps and workflows in minutes. Supports PostgreSQL, MySQL, MSSQL, MongoDB, Rest API, Docker, K8s, and more.", - "compose": "c2VydmljZXM6CiAgYXBwLXNlcnZpY2U6CiAgICBpbWFnZTogYnVkaWJhc2UuZG9ja2VyLnNjYXJmLnNoL2J1ZGliYXNlL2FwcHMKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFTEZfSE9TVEVEPTEKICAgICAgLSAnQ09VQ0hfREJfVVJMPWh0dHA6Ly8kU0VSVklDRV9VU0VSX0JVRElCQVNFX0NPVUNIREI6JFNFUlZJQ0VfUEFTU1dPUkRfQlVESUJBU0VfQ09VQ0hEQkBjb3VjaGRiLXNlcnZpY2U6NTk4NCcKICAgICAgLSAnV09SS0VSX1VSTD1odHRwOi8vd29ya2VyLXNlcnZpY2U6NDAwMycKICAgICAgLSAnTUlOSU9fVVJMPWh0dHA6Ly9taW5pby1zZXJ2aWNlOjkwMDAnCiAgICAgIC0gTUlOSU9fQUNDRVNTX0tFWT0kU0VSVklDRV9VU0VSX0JVRElCQVNFX01JTklPCiAgICAgIC0gTUlOSU9fU0VDUkVUX0tFWT0kU0VSVklDRV9QQVNTV09SRF9CVURJQkFTRV9NSU5JTwogICAgICAtIElOVEVSTkFMX0FQSV9LRVk9JFNFUlZJQ0VfQkFTRTY0XzEyOF9CVURJQkFTRQogICAgICAtICdCVURJQkFTRV9FTlZJUk9OTUVOVD0ke0JVRElCQVNFX0VOVklST05NRU5UOi1QUk9EVUNUSU9OfScKICAgICAgLSBQT1JUPTQwMDIKICAgICAgLSBBUElfRU5DUllQVElPTl9LRVk9JFNFUlZJQ0VfQkFTRTY0XzY0X0JVRElCQVNFCiAgICAgIC0gSldUX1NFQ1JFVD0kU0VSVklDRV9CQVNFNjRfNjRfQlVESUJBU0UKICAgICAgLSBMT0dfTEVWRUw9aW5mbwogICAgICAtICdFTkFCTEVfQU5BTFlUSUNTPSR7RU5BQkxFX0FOQUxZVElDUzotdHJ1ZX0nCiAgICAgIC0gJ1JFRElTX1VSTD1yZWRpcy1zZXJ2aWNlOjYzNzknCiAgICAgIC0gUkVESVNfUEFTU1dPUkQ9JFNFUlZJQ0VfUEFTU1dPUkRfQlVESUJBU0VfUkVESVMKICAgICAgLSBCQl9BRE1JTl9VU0VSX0VNQUlMPQogICAgICAtIEJCX0FETUlOX1VTRVJfUEFTU1dPUkQ9CiAgICBkZXBlbmRzX29uOgogICAgICAtIHdvcmtlci1zZXJ2aWNlCiAgICAgIC0gcmVkaXMtc2VydmljZQogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIGN1cmwKICAgICAgICAtICctZicKICAgICAgICAtICdodHRwOi8vYXBwLXNlcnZpY2U6NDAwMicKICAgICAgaW50ZXJ2YWw6IDE1cwogICAgICB0aW1lb3V0OiAxNXMKICAgICAgcmV0cmllczogNQogICAgICBzdGFydF9wZXJpb2Q6IDEwcwogIHdvcmtlci1zZXJ2aWNlOgogICAgaW1hZ2U6IGJ1ZGliYXNlLmRvY2tlci5zY2FyZi5zaC9idWRpYmFzZS93b3JrZXIKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFTEZfSE9TVEVEPTEKICAgICAgLSBQT1JUPTQwMDMKICAgICAgLSBDTFVTVEVSX1BPUlQ9MTAwMDAKICAgICAgLSBBUElfRU5DUllQVElPTl9LRVk9JFNFUlZJQ0VfQkFTRTY0XzY0X0JVRElCQVNFCiAgICAgIC0gSldUX1NFQ1JFVD0kU0VSVklDRV9CQVNFNjRfNjRfQlVESUJBU0UKICAgICAgLSBNSU5JT19BQ0NFU1NfS0VZPSRTRVJWSUNFX1VTRVJfQlVESUJBU0VfTUlOSU8KICAgICAgLSBNSU5JT19TRUNSRVRfS0VZPSRTRVJWSUNFX1BBU1NXT1JEX0JVRElCQVNFX01JTklPCiAgICAgIC0gJ01JTklPX1VSTD1odHRwOi8vbWluaW8tc2VydmljZTo5MDAwJwogICAgICAtICdBUFBTX1VSTD1odHRwOi8vYXBwLXNlcnZpY2U6NDAwMicKICAgICAgLSBDT1VDSF9EQl9VU0VSTkFNRT0kU0VSVklDRV9VU0VSX0JVRElCQVNFX0NPVUNIREIKICAgICAgLSBDT1VDSF9EQl9QQVNTV09SRD0kU0VSVklDRV9QQVNTV09SRF9CVURJQkFTRV9DT1VDSERCCiAgICAgIC0gJ0NPVUNIX0RCX1VSTD1odHRwOi8vJFNFUlZJQ0VfVVNFUl9CVURJQkFTRV9DT1VDSERCOiRTRVJWSUNFX1BBU1NXT1JEX0JVRElCQVNFX0NPVUNIREJAY291Y2hkYi1zZXJ2aWNlOjU5ODQnCiAgICAgIC0gSU5URVJOQUxfQVBJX0tFWT0kU0VSVklDRV9CQVNFNjRfMTI4X0JVRElCQVNFCiAgICAgIC0gJ1JFRElTX1VSTD1yZWRpcy1zZXJ2aWNlOjYzNzknCiAgICAgIC0gUkVESVNfUEFTU1dPUkQ9JFNFUlZJQ0VfUEFTU1dPUkRfQlVESUJBU0VfUkVESVMKICAgIGRlcGVuZHNfb246CiAgICAgIC0gcmVkaXMtc2VydmljZQogICAgICAtIG1pbmlvLXNlcnZpY2UKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBjdXJsCiAgICAgICAgLSAnLWYnCiAgICAgICAgLSAnaHR0cDovL3dvcmtlci1zZXJ2aWNlOjQwMDMnCiAgICAgIGludGVydmFsOiAxNXMKICAgICAgdGltZW91dDogMTVzCiAgICAgIHJldHJpZXM6IDUKICAgICAgc3RhcnRfcGVyaW9kOiAxMHMKICBtaW5pby1zZXJ2aWNlOgogICAgaW1hZ2U6IG1pbmlvL21pbmlvCiAgICB2b2x1bWVzOgogICAgICAtICdtaW5pb19kYXRhOi9kYXRhJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gTUlOSU9fQUNDRVNTX0tFWT0kU0VSVklDRV9VU0VSX0JVRElCQVNFX01JTklPCiAgICAgIC0gTUlOSU9fU0VDUkVUX0tFWT0kU0VSVklDRV9QQVNTV09SRF9CVURJQkFTRV9NSU5JTwogICAgICAtIE1JTklPX0JST1dTRVI9b2ZmCiAgICBjb21tYW5kOiAnc2VydmVyIC9kYXRhIC0tY29uc29sZS1hZGRyZXNzICI6OTAwMSInCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gY3VybAogICAgICAgIC0gJy1mJwogICAgICAgIC0gJ2h0dHA6Ly9sb2NhbGhvc3Q6OTAwMC9taW5pby9oZWFsdGgvbGl2ZScKICAgICAgaW50ZXJ2YWw6IDMwcwogICAgICB0aW1lb3V0OiAyMHMKICAgICAgcmV0cmllczogMwogIHByb3h5LXNlcnZpY2U6CiAgICBpbWFnZTogYnVkaWJhc2UvcHJveHkKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9CVURJQkFTRV8xMDAwMAogICAgICAtIFBST1hZX1JBVEVfTElNSVRfV0VCSE9PS1NfUEVSX1NFQ09ORD0xMAogICAgICAtIFBST1hZX1JBVEVfTElNSVRfQVBJX1BFUl9TRUNPTkQ9MjAKICAgICAgLSAnQVBQU19VUFNUUkVBTV9VUkw9aHR0cDovL2FwcC1zZXJ2aWNlOjQwMDInCiAgICAgIC0gJ1dPUktFUl9VUFNUUkVBTV9VUkw9aHR0cDovL3dvcmtlci1zZXJ2aWNlOjQwMDMnCiAgICAgIC0gJ01JTklPX1VQU1RSRUFNX1VSTD1odHRwOi8vbWluaW8tc2VydmljZTo5MDAwJwogICAgICAtICdDT1VDSERCX1VQU1RSRUFNX1VSTD1odHRwOi8vY291Y2hkYi1zZXJ2aWNlOjU5ODQnCiAgICAgIC0gJ1dBVENIVE9XRVJfVVBTVFJFQU1fVVJMPWh0dHA6Ly93YXRjaHRvd2VyLXNlcnZpY2U6ODA4MCcKICAgICAgLSBSRVNPTFZFUj0xMjcuMC4wLjExCiAgICBkZXBlbmRzX29uOgogICAgICAtIG1pbmlvLXNlcnZpY2UKICAgICAgLSB3b3JrZXItc2VydmljZQogICAgICAtIGFwcC1zZXJ2aWNlCiAgICAgIC0gY291Y2hkYi1zZXJ2aWNlCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gY3VybAogICAgICAgIC0gJy1mJwogICAgICAgIC0gJ2h0dHA6Ly9sb2NhbGhvc3Q6MTAwMDAvJwogICAgICBpbnRlcnZhbDogMTVzCiAgICAgIHRpbWVvdXQ6IDE1cwogICAgICByZXRyaWVzOiA1CiAgICAgIHN0YXJ0X3BlcmlvZDogMTBzCiAgY291Y2hkYi1zZXJ2aWNlOgogICAgaW1hZ2U6IGJ1ZGliYXNlL2NvdWNoZGIKICAgIGVudmlyb25tZW50OgogICAgICAtIENPVUNIREJfUEFTU1dPUkQ9JFNFUlZJQ0VfUEFTU1dPUkRfQlVESUJBU0VfQ09VQ0hEQgogICAgICAtIENPVUNIREJfVVNFUj0kU0VSVklDRV9VU0VSX0JVRElCQVNFX0NPVUNIREIKICAgICAgLSBUQVJHRVRCVUlMRD1kb2NrZXItY29tcG9zZQogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIGN1cmwKICAgICAgICAtICctZicKICAgICAgICAtICdodHRwOi8vbG9jYWxob3N0OjU5ODQvJwogICAgICBpbnRlcnZhbDogMTVzCiAgICAgIHRpbWVvdXQ6IDE1cwogICAgICByZXRyaWVzOiA1CiAgICAgIHN0YXJ0X3BlcmlvZDogMTBzCiAgICB2b2x1bWVzOgogICAgICAtICdjb3VjaGRiM19kYXRhOi9vcHQvY291Y2hkYi9kYXRhJwogIHJlZGlzLXNlcnZpY2U6CiAgICBpbWFnZTogcmVkaXMKICAgIGNvbW1hbmQ6ICdyZWRpcy1zZXJ2ZXIgLS1yZXF1aXJlcGFzcyAiJFNFUlZJQ0VfUEFTU1dPUkRfQlVESUJBU0VfUkVESVMiJwogICAgdm9sdW1lczoKICAgICAgLSAncmVkaXNfZGF0YTovZGF0YScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSByZWRpcy1jbGkKICAgICAgICAtICctYScKICAgICAgICAtICRTRVJWSUNFX1BBU1NXT1JEX0JVRElCQVNFX1JFRElTCiAgICAgICAgLSBwaW5nCiAgICAgIGludGVydmFsOiAxNXMKICAgICAgdGltZW91dDogMTVzCiAgICAgIHJldHJpZXM6IDUKICAgICAgc3RhcnRfcGVyaW9kOiAxMHMKICB3YXRjaHRvd2VyLXNlcnZpY2U6CiAgICByZXN0YXJ0OiBhbHdheXMKICAgIGltYWdlOiBjb250YWlucnJyL3dhdGNodG93ZXIKICAgIHZvbHVtZXM6CiAgICAgIC0gJy92YXIvcnVuL2RvY2tlci5zb2NrOi92YXIvcnVuL2RvY2tlci5zb2NrJwogICAgY29tbWFuZDogJy0tZGVidWcgLS1odHRwLWFwaS11cGRhdGUgYmJhcHBzIGJid29ya2VyIGJicHJveHknCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBXQVRDSFRPV0VSX0hUVFBfQVBJPXRydWUKICAgICAgLSBXQVRDSFRPV0VSX0hUVFBfQVBJX1RPS0VOPSRTRVJWSUNFX1BBU1NXT1JEX0JVRElCQVNFX1dBVENIVE9XRVIKICAgICAgLSBXQVRDSFRPV0VSX0NMRUFOVVA9dHJ1ZQogICAgbGFiZWxzOgogICAgICAtIGNvbS5jZW50dXJ5bGlua2xhYnMud2F0Y2h0b3dlci5lbmFibGU9ZmFsc2UKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBjdXJsCiAgICAgICAgLSAnLWYnCiAgICAgICAgLSAnaHR0cDovL3dhdGNodG93ZXItc2VydmljZTo4MDgwJwogICAgICBpbnRlcnZhbDogMTVzCiAgICAgIHRpbWVvdXQ6IDE1cwogICAgICByZXRyaWVzOiA1CiAgICAgIHN0YXJ0X3BlcmlvZDogMTBzCg==", + "compose": "c2VydmljZXM6CiAgYXBwLXNlcnZpY2U6CiAgICBpbWFnZTogYnVkaWJhc2UuZG9ja2VyLnNjYXJmLnNoL2J1ZGliYXNlL2FwcHMKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFTEZfSE9TVEVEPTEKICAgICAgLSAnQ09VQ0hfREJfVVJMPWh0dHA6Ly8kU0VSVklDRV9VU0VSX0NPVUNIREI6JFNFUlZJQ0VfUEFTU1dPUkRfQ09VQ0hEQkBjb3VjaGRiLXNlcnZpY2U6NTk4NCcKICAgICAgLSAnV09SS0VSX1VSTD1odHRwOi8vd29ya2VyLXNlcnZpY2U6NDAwMycKICAgICAgLSAnTUlOSU9fVVJMPWh0dHA6Ly9taW5pby1zZXJ2aWNlOjkwMDAnCiAgICAgIC0gTUlOSU9fQUNDRVNTX0tFWT0kU0VSVklDRV9VU0VSX01JTklPCiAgICAgIC0gTUlOSU9fU0VDUkVUX0tFWT0kU0VSVklDRV9QQVNTV09SRF9NSU5JTwogICAgICAtIElOVEVSTkFMX0FQSV9LRVk9JFNFUlZJQ0VfQkFTRTY0XzEyOF9CVURJQkFTRQogICAgICAtICdCVURJQkFTRV9FTlZJUk9OTUVOVD0ke0JVRElCQVNFX0VOVklST05NRU5UOi1QUk9EVUNUSU9OfScKICAgICAgLSBQT1JUPTQwMDIKICAgICAgLSBBUElfRU5DUllQVElPTl9LRVk9JFNFUlZJQ0VfQkFTRTY0XzY0X0JVRElCQVNFCiAgICAgIC0gSldUX1NFQ1JFVD0kU0VSVklDRV9CQVNFNjRfNjRfQlVESUJBU0UKICAgICAgLSBMT0dfTEVWRUw9aW5mbwogICAgICAtICdFTkFCTEVfQU5BTFlUSUNTPSR7RU5BQkxFX0FOQUxZVElDUzotdHJ1ZX0nCiAgICAgIC0gJ1JFRElTX1VSTD1yZWRpcy1zZXJ2aWNlOjYzNzknCiAgICAgIC0gUkVESVNfUEFTU1dPUkQ9JFNFUlZJQ0VfUEFTU1dPUkRfUkVESVMKICAgICAgLSBCQl9BRE1JTl9VU0VSX0VNQUlMPQogICAgICAtIEJCX0FETUlOX1VTRVJfUEFTU1dPUkQ9CiAgICBkZXBlbmRzX29uOgogICAgICAtIHdvcmtlci1zZXJ2aWNlCiAgICAgIC0gcmVkaXMtc2VydmljZQogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIHdnZXQKICAgICAgICAtICctLXNwaWRlcicKICAgICAgICAtICctcU8tJwogICAgICAgIC0gJ2h0dHA6Ly9sb2NhbGhvc3Q6NDAwMi9oZWFsdGgnCiAgICAgIGludGVydmFsOiAxNXMKICAgICAgdGltZW91dDogMTVzCiAgICAgIHJldHJpZXM6IDUKICAgICAgc3RhcnRfcGVyaW9kOiAxMHMKICB3b3JrZXItc2VydmljZToKICAgIGltYWdlOiBidWRpYmFzZS5kb2NrZXIuc2NhcmYuc2gvYnVkaWJhc2Uvd29ya2VyCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRUxGX0hPU1RFRD0xCiAgICAgIC0gUE9SVD00MDAzCiAgICAgIC0gQ0xVU1RFUl9QT1JUPTEwMDAwCiAgICAgIC0gQVBJX0VOQ1JZUFRJT05fS0VZPSRTRVJWSUNFX0JBU0U2NF82NF9CVURJQkFTRQogICAgICAtIEpXVF9TRUNSRVQ9JFNFUlZJQ0VfQkFTRTY0XzY0X0JVRElCQVNFCiAgICAgIC0gTUlOSU9fQUNDRVNTX0tFWT0kU0VSVklDRV9VU0VSX01JTklPCiAgICAgIC0gTUlOSU9fU0VDUkVUX0tFWT0kU0VSVklDRV9QQVNTV09SRF9NSU5JTwogICAgICAtICdNSU5JT19VUkw9aHR0cDovL21pbmlvLXNlcnZpY2U6OTAwMCcKICAgICAgLSAnQVBQU19VUkw9aHR0cDovL2FwcC1zZXJ2aWNlOjQwMDInCiAgICAgIC0gQ09VQ0hfREJfVVNFUk5BTUU9JFNFUlZJQ0VfVVNFUl9DT1VDSERCCiAgICAgIC0gQ09VQ0hfREJfUEFTU1dPUkQ9JFNFUlZJQ0VfUEFTU1dPUkRfQ09VQ0hEQgogICAgICAtICdDT1VDSF9EQl9VUkw9aHR0cDovLyRTRVJWSUNFX1VTRVJfQ09VQ0hEQjokU0VSVklDRV9QQVNTV09SRF9DT1VDSERCQGNvdWNoZGItc2VydmljZTo1OTg0JwogICAgICAtIElOVEVSTkFMX0FQSV9LRVk9JFNFUlZJQ0VfQkFTRTY0XzEyOF9CVURJQkFTRQogICAgICAtICdSRURJU19VUkw9cmVkaXMtc2VydmljZTo2Mzc5JwogICAgICAtIFJFRElTX1BBU1NXT1JEPSRTRVJWSUNFX1BBU1NXT1JEX1JFRElTCiAgICBkZXBlbmRzX29uOgogICAgICAtIHJlZGlzLXNlcnZpY2UKICAgICAgLSBtaW5pby1zZXJ2aWNlCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gd2dldAogICAgICAgIC0gJy0tc3BpZGVyJwogICAgICAgIC0gJy1xTy0nCiAgICAgICAgLSAnaHR0cDovL2xvY2FsaG9zdDo0MDAzL2hlYWx0aCcKICAgICAgaW50ZXJ2YWw6IDE1cwogICAgICB0aW1lb3V0OiAxNXMKICAgICAgcmV0cmllczogNQogICAgICBzdGFydF9wZXJpb2Q6IDEwcwogIG1pbmlvLXNlcnZpY2U6CiAgICBpbWFnZTogbWluaW8vbWluaW8KICAgIHZvbHVtZXM6CiAgICAgIC0gJ21pbmlvX2RhdGE6L2RhdGEnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBNSU5JT19ST09UX1VTRVI9JFNFUlZJQ0VfVVNFUl9NSU5JTwogICAgICAtIE1JTklPX1JPT1RfUEFTU1dPUkQ9JFNFUlZJQ0VfUEFTU1dPUkRfTUlOSU8KICAgICAgLSBNSU5JT19CUk9XU0VSPW9mZgogICAgY29tbWFuZDogJ3NlcnZlciAvZGF0YSAtLWNvbnNvbGUtYWRkcmVzcyAiOjkwMDEiJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIGN1cmwKICAgICAgICAtICctZicKICAgICAgICAtICdodHRwOi8vbG9jYWxob3N0OjkwMDAvbWluaW8vaGVhbHRoL2xpdmUnCiAgICAgIGludGVydmFsOiAzMHMKICAgICAgdGltZW91dDogMjBzCiAgICAgIHJldHJpZXM6IDMKICBwcm94eS1zZXJ2aWNlOgogICAgaW1hZ2U6IGJ1ZGliYXNlL3Byb3h5CiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX0ZRRE5fQlVESUJBU0VfMTAwMDAKICAgICAgLSBQUk9YWV9SQVRFX0xJTUlUX1dFQkhPT0tTX1BFUl9TRUNPTkQ9MTAKICAgICAgLSBQUk9YWV9SQVRFX0xJTUlUX0FQSV9QRVJfU0VDT05EPTIwCiAgICAgIC0gJ0FQUFNfVVBTVFJFQU1fVVJMPWh0dHA6Ly9hcHAtc2VydmljZTo0MDAyJwogICAgICAtICdXT1JLRVJfVVBTVFJFQU1fVVJMPWh0dHA6Ly93b3JrZXItc2VydmljZTo0MDAzJwogICAgICAtICdNSU5JT19VUFNUUkVBTV9VUkw9aHR0cDovL21pbmlvLXNlcnZpY2U6OTAwMCcKICAgICAgLSAnQ09VQ0hEQl9VUFNUUkVBTV9VUkw9aHR0cDovL2NvdWNoZGItc2VydmljZTo1OTg0JwogICAgICAtICdXQVRDSFRPV0VSX1VQU1RSRUFNX1VSTD1odHRwOi8vd2F0Y2h0b3dlci1zZXJ2aWNlOjgwODAnCiAgICAgIC0gUkVTT0xWRVI9MTI3LjAuMC4xMQogICAgZGVwZW5kc19vbjoKICAgICAgLSBtaW5pby1zZXJ2aWNlCiAgICAgIC0gd29ya2VyLXNlcnZpY2UKICAgICAgLSBhcHAtc2VydmljZQogICAgICAtIGNvdWNoZGItc2VydmljZQogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIGN1cmwKICAgICAgICAtICctZicKICAgICAgICAtICdodHRwOi8vbG9jYWxob3N0OjEwMDAwLycKICAgICAgaW50ZXJ2YWw6IDE1cwogICAgICB0aW1lb3V0OiAxNXMKICAgICAgcmV0cmllczogNQogICAgICBzdGFydF9wZXJpb2Q6IDEwcwogIGNvdWNoZGItc2VydmljZToKICAgIGltYWdlOiBidWRpYmFzZS9jb3VjaGRiCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBDT1VDSERCX1BBU1NXT1JEPSRTRVJWSUNFX1BBU1NXT1JEX0NPVUNIREIKICAgICAgLSBDT1VDSERCX1VTRVI9JFNFUlZJQ0VfVVNFUl9DT1VDSERCCiAgICAgIC0gVEFSR0VUQlVJTEQ9ZG9ja2VyLWNvbXBvc2UKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBjdXJsCiAgICAgICAgLSAnLWYnCiAgICAgICAgLSAnaHR0cDovL2xvY2FsaG9zdDo1OTg0LycKICAgICAgaW50ZXJ2YWw6IDE1cwogICAgICB0aW1lb3V0OiAxNXMKICAgICAgcmV0cmllczogNQogICAgICBzdGFydF9wZXJpb2Q6IDEwcwogICAgdm9sdW1lczoKICAgICAgLSAnY291Y2hkYjNfZGF0YTovb3B0L2NvdWNoZGIvZGF0YScKICByZWRpcy1zZXJ2aWNlOgogICAgaW1hZ2U6IHJlZGlzCiAgICBjb21tYW5kOiAncmVkaXMtc2VydmVyIC0tcmVxdWlyZXBhc3MgIiRTRVJWSUNFX1BBU1NXT1JEX1JFRElTIicKICAgIHZvbHVtZXM6CiAgICAgIC0gJ3JlZGlzX2RhdGE6L2RhdGEnCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gcmVkaXMtY2xpCiAgICAgICAgLSAnLWEnCiAgICAgICAgLSAkU0VSVklDRV9QQVNTV09SRF9SRURJUwogICAgICAgIC0gcGluZwogICAgICBpbnRlcnZhbDogMTVzCiAgICAgIHRpbWVvdXQ6IDE1cwogICAgICByZXRyaWVzOiA1CiAgICAgIHN0YXJ0X3BlcmlvZDogMTBzCiAgd2F0Y2h0b3dlci1zZXJ2aWNlOgogICAgcmVzdGFydDogYWx3YXlzCiAgICBpbWFnZTogY29udGFpbnJyci93YXRjaHRvd2VyCiAgICB2b2x1bWVzOgogICAgICAtICcvdmFyL3J1bi9kb2NrZXIuc29jazovdmFyL3J1bi9kb2NrZXIuc29jaycKICAgIGNvbW1hbmQ6ICctLWRlYnVnIC0taHR0cC1hcGktdXBkYXRlIGJiYXBwcyBiYndvcmtlciBiYnByb3h5JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gV0FUQ0hUT1dFUl9IVFRQX0FQST10cnVlCiAgICAgIC0gV0FUQ0hUT1dFUl9IVFRQX0FQSV9UT0tFTj0kU0VSVklDRV9QQVNTV09SRF9XQVRDSFRPV0VSCiAgICAgIC0gV0FUQ0hUT1dFUl9DTEVBTlVQPXRydWUKICAgIGxhYmVsczoKICAgICAgLSBjb20uY2VudHVyeWxpbmtsYWJzLndhdGNodG93ZXIuZW5hYmxlPWZhbHNlCiAgICBleGNsdWRlX2Zyb21faGM6IHRydWUK", "tags": [ "budibase", "low-code", @@ -851,7 +851,7 @@ "formbricks": { "documentation": "https://formbricks.com/docs/self-hosting/configuration?utm_source=coolify.io", "slogan": "Open Source Survey Platform", - "compose": "c2VydmljZXM6CiAgZm9ybWJyaWNrczoKICAgIGltYWdlOiAnZ2hjci5pby9mb3JtYnJpY2tzL2Zvcm1icmlja3M6bGF0ZXN0JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX0ZPUk1CUklDS1NfMzAwMAogICAgICAtIFdFQkFQUF9VUkw9JFNFUlZJQ0VfRlFETl9GT1JNQlJJQ0tTCiAgICAgIC0gJ0RBVEFCQVNFX1VSTD1wb3N0Z3JlczovLyRTRVJWSUNFX1VTRVJfUE9TVEdSRVNRTDokU0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU1FMQHBvc3RncmVzcWw6NTQzMi8ke1BPU1RHUkVTUUxfREFUQUJBU0U6LWZvcm1icmlja3N9JwogICAgICAtICdQT1NUR1JFU19QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVNRTH0nCiAgICAgIC0gTkVYVEFVVEhfU0VDUkVUPSRTRVJWSUNFX0JBU0U2NF82NF9ORVhUQVVUSAogICAgICAtIE5FWFRBVVRIX1VSTD0kU0VSVklDRV9GUUROX0ZPUk1CUklDS1MKICAgICAgLSBFTkNSWVBUSU9OX0tFWT0kU0VSVklDRV9CQVNFNjRfNjRfRU5DUllQVElPTgogICAgICAtIENST05fU0VDUkVUPSRTRVJWSUNFX0JBU0U2NF82NF9DUk9OCiAgICAgIC0gJ0VOVEVSUFJJU0VfTElDRU5TRV9LRVk9JHtFTlRFUlBSSVNFX0xJQ0VOU0VfS0VZfScKICAgICAgLSAnTUFJTF9GUk9NPSR7TUFJTF9GUk9NOi10ZXN0QGV4YW1wbGUuY29tfScKICAgICAgLSAnU01UUF9IT1NUPSR7U01UUF9IT1NUOi10ZXN0LmV4YW1wbGUuY29tfScKICAgICAgLSAnU01UUF9QT1JUPSR7U01UUF9QT1JUOi01ODd9JwogICAgICAtICdTTVRQX1VTRVI9JHtTTVRQX1VTRVI6LXRlc3R9JwogICAgICAtICdTTVRQX1BBU1NXT1JEPSR7U01UUF9QQVNTV09SRDotdGVzdH0nCiAgICAgIC0gJ1NNVFBfU0VDVVJFX0VOQUJMRUQ9JHtTTVRQX1NFQ1VSRV9FTkFCTEVEOi0wfScKICAgICAgLSAnU01UUF9SRUpFQ1RfVU5BVVRIT1JJWkVEX1RMUz0ke1NNVFBfUkVKRUNUX1VOQVVUSE9SSVpFRF9UTFM6LTF9JwogICAgICAtICdTSE9SVF9VUkxfQkFTRT0ke1NIT1JUX1VSTF9CQVNFfScKICAgICAgLSAnRU1BSUxfVkVSSUZJQ0FUSU9OX0RJU0FCTEVEPSR7RU1BSUxfVkVSSUZJQ0FUSU9OX0RJU0FCTEVEOi0xfScKICAgICAgLSAnUEFTU1dPUkRfUkVTRVRfRElTQUJMRUQ9JHtQQVNTV09SRF9SRVNFVF9ESVNBQkxFRDotMX0nCiAgICAgIC0gJ0VNQUlMX0FVVEhfRElTQUJMRUQ9JHtFTUFJTF9BVVRIX0RJU0FCTEVEOi0wfScKICAgICAgLSAnSU5WSVRFX0RJU0FCTEVEPSR7SU5WSVRFX0RJU0FCTEVEOi0wfScKICAgICAgLSAnQVNTRVRfUFJFRklYX1VSTD0ke0FTU0VUX1BSRUZJWF9VUkx9JwogICAgICAtICdVTlNQTEFTSF9BQ0NFU1NfS0VZPSR7VU5TUExBU0hfQUNDRVNTX0tFWX0nCiAgICAgIC0gJ0dJVEhVQl9JRD0ke0dJVEhVQl9JRH0nCiAgICAgIC0gJ0dJVEhVQl9TRUNSRVQ9JHtHSVRIVUJfU0VDUkVUfScKICAgICAgLSAnR09PR0xFX0NMSUVOVF9JRD0ke0dPT0dMRV9DTElFTlRfSUR9JwogICAgICAtICdHT09HTEVfQ0xJRU5UX1NFQ1JFVD0ke0dPT0dMRV9DTElFTlRfU0VDUkVUfScKICAgICAgLSAnQVpVUkVBRF9DTElFTlRfSUQ9JHtBWlVSRUFEX0NMSUVOVF9JRH0nCiAgICAgIC0gJ0FaVVJFQURfQ0xJRU5UX1NFQ1JFVD0ke0FaVVJFQURfQ0xJRU5UX1NFQ1JFVH0nCiAgICAgIC0gJ0FaVVJFQURfVEVOQU5UX0lEPSR7QVpVUkVBRF9URU5BTlRfSUR9JwogICAgICAtICdPSURDX0NMSUVOVF9JRD0ke09JRENfQ0xJRU5UX0lEfScKICAgICAgLSAnT0lEQ19DTElFTlRfU0VDUkVUPSR7T0lEQ19DTElFTlRfU0VDUkVUfScKICAgICAgLSAnT0lEQ19JU1NVRVI9JHtPSURDX0lTU1VFUn0nCiAgICAgIC0gJ09JRENfRElTUExBWV9OQU1FPSR7T0lEQ19ESVNQTEFZX05BTUV9JwogICAgICAtICdPSURDX1NJR05JTkdfQUxHT1JJVEhNPSR7T0lEQ19TSUdOSU5HX0FMR09SSVRITX0nCiAgICAgIC0gJ05PVElPTl9PQVVUSF9DTElFTlRfSUQ9JHtOT1RJT05fT0FVVEhfQ0xJRU5UX0lEfScKICAgICAgLSAnTk9USU9OX09BVVRIX0NMSUVOVF9TRUNSRVQ9JHtOT1RJT05fT0FVVEhfQ0xJRU5UX1NFQ1JFVH0nCiAgICAgIC0gJ0dPT0dMRV9TSEVFVFNfQ0xJRU5UX0lEPSR7R09PR0xFX1NIRUVUU19DTElFTlRfSUR9JwogICAgICAtICdHT09HTEVfU0hFRVRTX0NMSUVOVF9TRUNSRVQ9JHtHT09HTEVfU0hFRVRTX0NMSUVOVF9TRUNSRVR9JwogICAgICAtICdHT09HTEVfU0hFRVRTX1JFRElSRUNUX1VSTD0ke0dPT0dMRV9TSEVFVFNfUkVESVJFQ1RfVVJMfScKICAgICAgLSAnQUlSVEFCTEVfQ0xJRU5UX0lEPSR7QUlSVEFCTEVfQ0xJRU5UX0lEfScKICAgICAgLSAnU0xBQ0tfQ0xJRU5UX0lEPSR7U0xBQ0tfQ0xJRU5UX0lEfScKICAgICAgLSAnU0xBQ0tfQ0xJRU5UX1NFQ1JFVD0ke1NMQUNLX0NMSUVOVF9TRUNSRVR9JwogICAgICAtICdQUklWQUNZX1VSTD0ke1BSSVZBQ1lfVVJMfScKICAgICAgLSAnVEVSTVNfVVJMPSR7VEVSTVNfVVJMfScKICAgICAgLSAnSU1QUklOVF9VUkw9JHtJTVBSSU5UX1VSTH0nCiAgICAgIC0gJ1JBVEVfTElNSVRJTkdfRElTQUJMRUQ9JHtSQVRFX0xJTUlUSU5HX0RJU0FCTEVEOi0wfScKICAgICAgLSAnT1BFTlRFTEVNRVRSWV9MSVNURU5FUl9VUkw9JHtPUEVOVEVMRU1FVFJZX0xJU1RFTkVSX1VSTH0nCiAgICAgIC0gJ1JFRElTX1VSTD0ke1JFRElTX1VSTH0nCiAgICAgIC0gJ1JFRElTX0hUVFBfVVJMPSR7UkVESVNfSFRUUF9VUkx9JwogICAgICAtICdERUZBVUxUX09SR0FOSVpBVElPTl9JRD0ke0RFRkFVTFRfT1JHQU5JWkFUSU9OX0lEfScKICAgICAgLSAnREVGQVVMVF9PUkdBTklaQVRJT05fUk9MRT0ke0RFRkFVTFRfT1JHQU5JWkFUSU9OX1JPTEU6LWFkbWlufScKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2Zvcm1icmlja3MtdXBsb2FkczovYXBwcy93ZWIvdXBsb2Fkcy8nCiAgICBkZXBlbmRzX29uOgogICAgICBwb3N0Z3Jlc3FsOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gY3VybAogICAgICAgIC0gJy1mJwogICAgICAgIC0gJ2h0dHA6Ly8xMjcuMC4wLjE6MzAwMCcKICAgICAgaW50ZXJ2YWw6IDJzCiAgICAgIHRpbWVvdXQ6IDEwcwogICAgICByZXRyaWVzOiAxNQogIHBvc3RncmVzcWw6CiAgICBpbWFnZTogJ3Bvc3RncmVzOjE2LWFscGluZScKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2Zvcm1icmlja3MtcG9zdGdyZXNxbC1kYXRhOi92YXIvbGliL3Bvc3RncmVzcWwvZGF0YScKICAgIGVudmlyb25tZW50OgogICAgICAtICdQT1NUR1JFU19VU0VSPSR7U0VSVklDRV9VU0VSX1BPU1RHUkVTUUx9JwogICAgICAtICdQT1NUR1JFU19QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVNRTH0nCiAgICAgIC0gJ1BPU1RHUkVTX0RCPSR7UE9TVEdSRVNRTF9EQVRBQkFTRTotZm9ybWJyaWNrc30nCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ3BnX2lzcmVhZHkgLVUgJCR7UE9TVEdSRVNfVVNFUn0gLWQgJCR7UE9TVEdSRVNfREJ9JwogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogMjBzCiAgICAgIHJldHJpZXM6IDEwCg==", + "compose": "c2VydmljZXM6CiAgZm9ybWJyaWNrczoKICAgIGltYWdlOiAnZ2hjci5pby9mb3JtYnJpY2tzL2Zvcm1icmlja3M6bGF0ZXN0JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX0ZPUk1CUklDS1NfMzAwMAogICAgICAtIFdFQkFQUF9VUkw9JFNFUlZJQ0VfRlFETl9GT1JNQlJJQ0tTCiAgICAgIC0gJ0RBVEFCQVNFX1VSTD1wb3N0Z3JlczovLyRTRVJWSUNFX1VTRVJfUE9TVEdSRVNRTDokU0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU1FMQHBvc3RncmVzcWw6NTQzMi8ke1BPU1RHUkVTUUxfREFUQUJBU0U6LWZvcm1icmlja3N9JwogICAgICAtICdQT1NUR1JFU19QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVNRTH0nCiAgICAgIC0gTkVYVEFVVEhfU0VDUkVUPSRTRVJWSUNFX0JBU0U2NF9ORVhUQVVUSAogICAgICAtIE5FWFRBVVRIX1VSTD0kU0VSVklDRV9GUUROX0ZPUk1CUklDS1MKICAgICAgLSBFTkNSWVBUSU9OX0tFWT0kU0VSVklDRV9CQVNFNjRfRU5DUllQVElPTgogICAgICAtIENST05fU0VDUkVUPSRTRVJWSUNFX0JBU0U2NF9DUk9OCiAgICAgIC0gJ0VOVEVSUFJJU0VfTElDRU5TRV9LRVk9JHtFTlRFUlBSSVNFX0xJQ0VOU0VfS0VZfScKICAgICAgLSAnTUFJTF9GUk9NPSR7TUFJTF9GUk9NOi10ZXN0QGV4YW1wbGUuY29tfScKICAgICAgLSAnU01UUF9IT1NUPSR7U01UUF9IT1NUOi10ZXN0LmV4YW1wbGUuY29tfScKICAgICAgLSAnU01UUF9QT1JUPSR7U01UUF9QT1JUOi01ODd9JwogICAgICAtICdTTVRQX1VTRVI9JHtTTVRQX1VTRVI6LXRlc3R9JwogICAgICAtICdTTVRQX1BBU1NXT1JEPSR7U01UUF9QQVNTV09SRDotdGVzdH0nCiAgICAgIC0gJ1NNVFBfU0VDVVJFX0VOQUJMRUQ9JHtTTVRQX1NFQ1VSRV9FTkFCTEVEOi0wfScKICAgICAgLSAnU01UUF9SRUpFQ1RfVU5BVVRIT1JJWkVEX1RMUz0ke1NNVFBfUkVKRUNUX1VOQVVUSE9SSVpFRF9UTFM6LTF9JwogICAgICAtICdTSE9SVF9VUkxfQkFTRT0ke1NIT1JUX1VSTF9CQVNFfScKICAgICAgLSAnRU1BSUxfVkVSSUZJQ0FUSU9OX0RJU0FCTEVEPSR7RU1BSUxfVkVSSUZJQ0FUSU9OX0RJU0FCTEVEOi0xfScKICAgICAgLSAnUEFTU1dPUkRfUkVTRVRfRElTQUJMRUQ9JHtQQVNTV09SRF9SRVNFVF9ESVNBQkxFRDotMX0nCiAgICAgIC0gJ0VNQUlMX0FVVEhfRElTQUJMRUQ9JHtFTUFJTF9BVVRIX0RJU0FCTEVEOi0wfScKICAgICAgLSAnSU5WSVRFX0RJU0FCTEVEPSR7SU5WSVRFX0RJU0FCTEVEOi0wfScKICAgICAgLSAnQVNTRVRfUFJFRklYX1VSTD0ke0FTU0VUX1BSRUZJWF9VUkx9JwogICAgICAtICdVTlNQTEFTSF9BQ0NFU1NfS0VZPSR7VU5TUExBU0hfQUNDRVNTX0tFWX0nCiAgICAgIC0gJ0dJVEhVQl9JRD0ke0dJVEhVQl9JRH0nCiAgICAgIC0gJ0dJVEhVQl9TRUNSRVQ9JHtHSVRIVUJfU0VDUkVUfScKICAgICAgLSAnR09PR0xFX0NMSUVOVF9JRD0ke0dPT0dMRV9DTElFTlRfSUR9JwogICAgICAtICdHT09HTEVfQ0xJRU5UX1NFQ1JFVD0ke0dPT0dMRV9DTElFTlRfU0VDUkVUfScKICAgICAgLSAnQVpVUkVBRF9DTElFTlRfSUQ9JHtBWlVSRUFEX0NMSUVOVF9JRH0nCiAgICAgIC0gJ0FaVVJFQURfQ0xJRU5UX1NFQ1JFVD0ke0FaVVJFQURfQ0xJRU5UX1NFQ1JFVH0nCiAgICAgIC0gJ0FaVVJFQURfVEVOQU5UX0lEPSR7QVpVUkVBRF9URU5BTlRfSUR9JwogICAgICAtICdPSURDX0NMSUVOVF9JRD0ke09JRENfQ0xJRU5UX0lEfScKICAgICAgLSAnT0lEQ19DTElFTlRfU0VDUkVUPSR7T0lEQ19DTElFTlRfU0VDUkVUfScKICAgICAgLSAnT0lEQ19JU1NVRVI9JHtPSURDX0lTU1VFUn0nCiAgICAgIC0gJ09JRENfRElTUExBWV9OQU1FPSR7T0lEQ19ESVNQTEFZX05BTUV9JwogICAgICAtICdPSURDX1NJR05JTkdfQUxHT1JJVEhNPSR7T0lEQ19TSUdOSU5HX0FMR09SSVRITX0nCiAgICAgIC0gJ05PVElPTl9PQVVUSF9DTElFTlRfSUQ9JHtOT1RJT05fT0FVVEhfQ0xJRU5UX0lEfScKICAgICAgLSAnTk9USU9OX09BVVRIX0NMSUVOVF9TRUNSRVQ9JHtOT1RJT05fT0FVVEhfQ0xJRU5UX1NFQ1JFVH0nCiAgICAgIC0gJ0dPT0dMRV9TSEVFVFNfQ0xJRU5UX0lEPSR7R09PR0xFX1NIRUVUU19DTElFTlRfSUR9JwogICAgICAtICdHT09HTEVfU0hFRVRTX0NMSUVOVF9TRUNSRVQ9JHtHT09HTEVfU0hFRVRTX0NMSUVOVF9TRUNSRVR9JwogICAgICAtICdHT09HTEVfU0hFRVRTX1JFRElSRUNUX1VSTD0ke0dPT0dMRV9TSEVFVFNfUkVESVJFQ1RfVVJMfScKICAgICAgLSAnQUlSVEFCTEVfQ0xJRU5UX0lEPSR7QUlSVEFCTEVfQ0xJRU5UX0lEfScKICAgICAgLSAnU0xBQ0tfQ0xJRU5UX0lEPSR7U0xBQ0tfQ0xJRU5UX0lEfScKICAgICAgLSAnU0xBQ0tfQ0xJRU5UX1NFQ1JFVD0ke1NMQUNLX0NMSUVOVF9TRUNSRVR9JwogICAgICAtICdQUklWQUNZX1VSTD0ke1BSSVZBQ1lfVVJMfScKICAgICAgLSAnVEVSTVNfVVJMPSR7VEVSTVNfVVJMfScKICAgICAgLSAnSU1QUklOVF9VUkw9JHtJTVBSSU5UX1VSTH0nCiAgICAgIC0gJ1JBVEVfTElNSVRJTkdfRElTQUJMRUQ9JHtSQVRFX0xJTUlUSU5HX0RJU0FCTEVEOi0wfScKICAgICAgLSAnT1BFTlRFTEVNRVRSWV9MSVNURU5FUl9VUkw9JHtPUEVOVEVMRU1FVFJZX0xJU1RFTkVSX1VSTH0nCiAgICAgIC0gJ1JFRElTX1VSTD0ke1JFRElTX1VSTH0nCiAgICAgIC0gJ1JFRElTX0hUVFBfVVJMPSR7UkVESVNfSFRUUF9VUkx9JwogICAgICAtICdERUZBVUxUX09SR0FOSVpBVElPTl9JRD0ke0RFRkFVTFRfT1JHQU5JWkFUSU9OX0lEfScKICAgICAgLSAnREVGQVVMVF9PUkdBTklaQVRJT05fUk9MRT0ke0RFRkFVTFRfT1JHQU5JWkFUSU9OX1JPTEU6LW93bmVyfScKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2Zvcm1icmlja3MtdXBsb2FkczovYXBwcy93ZWIvdXBsb2Fkcy8nCiAgICBkZXBlbmRzX29uOgogICAgICBwb3N0Z3Jlc3FsOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gY3VybAogICAgICAgIC0gJy1mJwogICAgICAgIC0gJ2h0dHA6Ly8xMjcuMC4wLjE6MzAwMCcKICAgICAgaW50ZXJ2YWw6IDJzCiAgICAgIHRpbWVvdXQ6IDEwcwogICAgICByZXRyaWVzOiAxNQogIHBvc3RncmVzcWw6CiAgICBpbWFnZTogJ3BndmVjdG9yL3BndmVjdG9yOnBnMTYnCiAgICB2b2x1bWVzOgogICAgICAtICdmb3JtYnJpY2tzLXBvc3RncmVzcWwtZGF0YTovdmFyL2xpYi9wb3N0Z3Jlc3FsL2RhdGEnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnUE9TVEdSRVNfVVNFUj0ke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU1FMfScKICAgICAgLSAnUE9TVEdSRVNfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTUUx9JwogICAgICAtICdQT1NUR1JFU19EQj0ke1BPU1RHUkVTUUxfREFUQUJBU0U6LWZvcm1icmlja3N9JwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICdwZ19pc3JlYWR5IC1VICQke1BPU1RHUkVTX1VTRVJ9IC1kICQke1BPU1RHUkVTX0RCfScKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDIwcwogICAgICByZXRyaWVzOiAxMAo=", "tags": [ "form", "builder", @@ -1580,20 +1580,6 @@ "logo": "svgs/logto_dark.svg", "minversion": "0.0.0" }, - "macos": { - "documentation": "https://github.com/dockur/macos?utm_source=coolify.io", - "slogan": "Run macOS in a containerized environment.", - "compose": "c2VydmljZXM6CiAgbWFjb3M6CiAgICBpbWFnZTogZG9ja3Vyci9tYWNvcwogICAgdm9sdW1lczoKICAgICAgLSAnbWFjb3Mtc3RvcmFnZTovc3RvcmFnZScKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9NQUNPU184MDA2CiAgICAgIC0gVkVSU0lPTj0xNQogICAgY2FwX2FkZDoKICAgICAgLSBORVRfQURNSU4KICAgIHN0b3BfZ3JhY2VfcGVyaW9kOiAybQogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIG5jCiAgICAgICAgLSAnLXonCiAgICAgICAgLSAxMjcuMC4wLjEKICAgICAgICAtICc4MDA2JwogICAgICBpbnRlcnZhbDogMnMKICAgICAgdGltZW91dDogMTBzCiAgICAgIHJldHJpZXM6IDEwCg==", - "tags": [ - "macos", - "virtualization", - "container", - "os" - ], - "logo": "svgs/macos.svg", - "minversion": "0.0.0", - "port": "8006" - }, "mailpit": { "documentation": "https://mailpit.axllent.org/docs/?utm_source=coolify.io", "slogan": "Email & SMTP testing tool with API for developers", @@ -2101,6 +2087,21 @@ "minversion": "0.0.0", "port": "80" }, + "overseerr": { + "documentation": "https://docs.overseerr.dev/getting-started/installation#docker?utm_source=coolify.io", + "slogan": "Overseerr is a request management and media discovery tool built to work with your existing Plex ecosystem.", + "compose": "c2VydmljZXM6CiAgb3ZlcnNlZXJyOgogICAgaW1hZ2U6ICdzY3R4L292ZXJzZWVycjpsYXRlc3QnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX0ZRRE5fT1ZFUlNFRVJSXzUwNTUKICAgICAgLSBQVUlEPTEwMDAKICAgICAgLSBQR0lEPTEwMDAKICAgICAgLSAnVFo9JHtUWjotQW1lcmljYS9Ub3JvbnRvfScKICAgIHZvbHVtZXM6CiAgICAgIC0gJ292ZXJzZWVyci1jb25maWc6L2FwcC9jb25maWcnCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gd2dldAogICAgICAgIC0gJy0tdHJpZXMnCiAgICAgICAgLSAnMScKICAgICAgICAtICctLW5vLXZlcmJvc2UnCiAgICAgICAgLSAnLS1zcGlkZXInCiAgICAgICAgLSAnaHR0cDovL2xvY2FsaG9zdDo1MDU1L2FwaS92MS9zdGF0dXMnCiAgICAgIGludGVydmFsOiAycwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMTUK", + "tags": [ + "media", + "request", + "plex", + "sonarr", + "radarr" + ], + "logo": "svgs/overseerr.svg", + "minversion": "0.0.0", + "port": "5055" + }, "owncloud": { "documentation": "https://owncloud.com/docs?utm_source=coolify.io", "slogan": "OwnCloud with Open Web UI integrates file management with a powerful, user-friendly interface.", @@ -2244,7 +2245,7 @@ "postiz": { "documentation": "https://docs.postiz.com?utm_source=coolify.io", "slogan": "Open source social media scheduling tool.", - "compose": "c2VydmljZXM6CiAgcG9zdGl6OgogICAgaW1hZ2U6ICdnaGNyLmlvL2dpdHJvb21ocS9wb3N0aXotYXBwOmxhdGVzdCcKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9QT1NUSVpfNTAwMAogICAgICAtICdNQUlOX1VSTD0ke1NFUlZJQ0VfRlFETl9QT1NUSVp9JwogICAgICAtICdGUk9OVEVORF9VUkw9JHtTRVJWSUNFX0ZRRE5fUE9TVElafScKICAgICAgLSAnTkVYVF9QVUJMSUNfQkFDS0VORF9VUkw9JHtTRVJWSUNFX0ZRRE5fUE9TVElafS9hcGknCiAgICAgIC0gJ0pXVF9TRUNSRVQ9JHtTRVJWSUNFX1BBU1NXT1JEX0pXVFNFQ1JFVH0nCiAgICAgIC0gJ0RBVEFCQVNFX1VSTD1wb3N0Z3Jlc3FsOi8vJHtTRVJWSUNFX1VTRVJfUE9TVEdSRVNRTH06JHtTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTUUx9QHBvc3RncmVzOjU0MzIvJHtQT1NUR1JFU1FMX0RBVEFCQVNFOi1wb3N0aXotZGJ9JwogICAgICAtICdSRURJU19VUkw9cmVkaXM6Ly8ke1NFUlZJQ0VfVVNFUl9SRURJU306JHtTRVJWSUNFX1BBU1NXT1JEX1JFRElTfUByZWRpczo2Mzc5JwogICAgICAtICdCQUNLRU5EX0lOVEVSTkFMX1VSTD1odHRwOi8vbG9jYWxob3N0OjMwMDAnCiAgICAgIC0gJ0NMT1VERkxBUkVfQUNDT1VOVF9JRD0ke0NMT1VERkxBUkVfQUNDT1VOVF9JRH0nCiAgICAgIC0gJ0NMT1VERkxBUkVfQUNDRVNTX0tFWT0ke0NMT1VERkxBUkVfQUNDRVNTX0tFWX0nCiAgICAgIC0gJ0NMT1VERkxBUkVfU0VDUkVUX0FDQ0VTU19LRVk9JHtDTE9VREZMQVJFX1NFQ1JFVF9BQ0NFU1NfS0VZfScKICAgICAgLSAnQ0xPVURGTEFSRV9CVUNLRVROQU1FPSR7Q0xPVURGTEFSRV9CVUNLRVROQU1FfScKICAgICAgLSAnQ0xPVURGTEFSRV9CVUNLRVRfVVJMPSR7Q0xPVURGTEFSRV9CVUNLRVRfVVJMfScKICAgICAgLSAnQ0xPVURGTEFSRV9SRUdJT049JHtDTE9VREZMQVJFX1JFR0lPTn0nCiAgICAgIC0gJ1NUT1JBR0VfUFJPVklERVI9JHtTVE9SQUdFX1BST1ZJREVSOi1sb2NhbH0nCiAgICAgIC0gJ1VQTE9BRF9ESVJFQ1RPUlk9JHtVUExPQURfRElSRUNUT1JZOi0vdXBsb2Fkc30nCiAgICAgIC0gJ05FWFRfUFVCTElDX1VQTE9BRF9ESVJFQ1RPUlk9JHtORVhUX1BVQkxJQ19VUExPQURfRElSRUNUT1JZOi0vdXBsb2Fkc30nCiAgICAgIC0gJ05FWFRfUFVCTElDX1VQTE9BRF9TVEFUSUNfRElSRUNUT1JZPSR7TkVYVF9QVUJMSUNfVVBMT0FEX1NUQVRJQ19ESVJFQ1RPUll9JwogICAgICAtICdSRVNFTkRfQVBJX0tFWT0ke1JFU0VORF9BUElfS0VZfScKICAgICAgLSAnRU1BSUxfRlJPTV9BRERSRVNTPSR7RU1BSUxfRlJPTV9BRERSRVNTfScKICAgICAgLSAnRU1BSUxfRlJPTV9OQU1FPSR7RU1BSUxfRlJPTV9OQU1FfScKICAgICAgLSAnWF9BUElfS0VZPSR7U0VSVklDRV9YX0FQSX0nCiAgICAgIC0gJ1hfQVBJX1NFQ1JFVD0ke1NFUlZJQ0VfWF9TRUNSRVR9JwogICAgICAtICdMSU5LRURJTl9DTElFTlRfSUQ9JHtTRVJWSUNFX0xJTktFRElOX0lEfScKICAgICAgLSAnTElOS0VESU5fQ0xJRU5UX1NFQ1JFVD0ke1NFUlZJQ0VfTElOS0VESU5fU0VDUkVUfScKICAgICAgLSAnUkVERElUX0NMSUVOVF9JRD0ke1NFUlZJQ0VfUkVERElUX0FQSX0nCiAgICAgIC0gJ1JFRERJVF9DTElFTlRfU0VDUkVUPSR7U0VSVklDRV9SRURESVRfU0VDUkVUfScKICAgICAgLSAnR0lUSFVCX0NMSUVOVF9JRD0ke1NFUlZJQ0VfR0lUSFVCX0lEfScKICAgICAgLSAnR0lUSFVCX0NMSUVOVF9TRUNSRVQ9JHtTRVJWSUNFX0dJVEhVQl9TRUNSRVR9JwogICAgICAtICdUSFJFQURTX0FQUF9JRD0ke1NFUlZJQ0VfVEhSRUFEU19JRH0nCiAgICAgIC0gJ1RIUkVBRFNfQVBQX1NFQ1JFVD0ke1NFUlZJQ0VfVEhSRUFEU19TRUNSRVR9JwogICAgICAtICdGQUNFQk9PS19BUFBfSUQ9JHtTRVJWSUNFX0ZBQ0VCT09LX0lEfScKICAgICAgLSAnRkFDRUJPT0tfQVBQX1NFQ1JFVD0ke1NFUlZJQ0VfRkFDRUJPT0tfU0VDUkVUfScKICAgICAgLSAnWU9VVFVCRV9DTElFTlRfSUQ9JHtTRVJWSUNFX1lPVVRVQkVfSUR9JwogICAgICAtICdZT1VUVUJFX0NMSUVOVF9TRUNSRVQ9JHtTRVJWSUNFX1lPVVRVQkVfU0VDUkVUfScKICAgICAgLSAnVElLVE9LX0NMSUVOVF9JRD0ke1NFUlZJQ0VfVElLVE9LX0lEfScKICAgICAgLSAnVElLVE9LX0NMSUVOVF9TRUNSRVQ9JHtTRVJWSUNFX1RJS1RPS19TRUNSRVR9JwogICAgICAtICdQSU5URVJFU1RfQ0xJRU5UX0lEPSR7U0VSVklDRV9QSU5URVJFU1RfSUR9JwogICAgICAtICdQSU5URVJFU1RfQ0xJRU5UX1NFQ1JFVD0ke1NFUlZJQ0VfUElOVEVSRVNUX1NFQ1JFVH0nCiAgICAgIC0gJ0RSSUJCQkxFX0NMSUVOVF9JRD0ke1NFUlZJQ0VfRFJJQkJMRV9JRH0nCiAgICAgIC0gJ0RSSUJCQkxFX0NMSUVOVF9TRUNSRVQ9JHtTRVJWSUNFX0RSSUJCTEVfU0VDUkVUfScKICAgICAgLSAnRElTQ09SRF9DTElFTlRfSUQ9JHtTRVJWSUNFX0RJU0NPUkRfSUR9JwogICAgICAtICdESVNDT1JEX0NMSUVOVF9TRUNSRVQ9JHtTRVJWSUNFX0RJU0NPUkRfU0VDUkVUfScKICAgICAgLSAnRElTQ09SRF9CT1RfVE9LRU5fSUQ9JHtTRVJWSUNFX0RJU0NPUkRfVE9LRU59JwogICAgICAtICdTTEFDS19JRD0ke1NFUlZJQ0VfU0xBQ0tfSUR9JwogICAgICAtICdTTEFDS19TRUNSRVQ9JHtTRVJWSUNFX1NMQUNLX1NFQ1JFVH0nCiAgICAgIC0gJ1NMQUNLX1NJR05JTkdfU0VDUkVUPSR7U0xBQ0tfU0lHTklOR19TRUNSRVR9JwogICAgICAtICdNQVNUT0RPTl9DTElFTlRfSUQ9JHtTRVJWSUNFX01BU1RPRE9OX0lEfScKICAgICAgLSAnTUFTVE9ET05fQ0xJRU5UX1NFQ1JFVD0ke1NFUlZJQ0VfTUFTVE9ET05fU0VDUkVUfScKICAgICAgLSAnQkVFSElJVkVfQVBJX0tFWT0ke1NFUlZJQ0VfQkVFSElJVkVfS0VZfScKICAgICAgLSAnQkVFSElJVkVfUFVCTElDQVRJT05fSUQ9JHtTRVJWSUNFX0JFRUhJSVZFX1BVQklEfScKICAgICAgLSAnT1BFTkFJX0FQSV9LRVk9JHtTRVJWSUNFX09QRU5BSV9LRVl9JwogICAgICAtICdORVhUX1BVQkxJQ19ESVNDT1JEX1NVUFBPUlQ9JHtORVhUX1BVQkxJQ19ESVNDT1JEX1NVUFBPUlR9JwogICAgICAtICdORVhUX1BVQkxJQ19QT0xPVE5PPSR7TkVYVF9QVUJMSUNfUE9MT1ROT30nCiAgICAgIC0gJ0lTX0dFTkVSQUw9JHtJU19HRU5FUkFMOi10cnVlfScKICAgICAgLSAnTlhfQUREX1BMVUdJTlM9JHtOWF9BRERfUExVR0lOUzotZmFsc2V9JwogICAgICAtICdGRUVfQU1PVU5UPSR7RkVFX0FNT1VOVDotMC4wNX0nCiAgICAgIC0gJ1NUUklQRV9QVUJMSVNIQUJMRV9LRVk9JHtTVFJJUEVfUFVCTElTSEFCTEVfS0VZfScKICAgICAgLSAnU1RSSVBFX1NFQ1JFVF9LRVk9JHtTVFJJUEVfU0VDUkVUX0tFWX0nCiAgICAgIC0gJ1NUUklQRV9TSUdOSU5HX0tFWT0ke1NUUklQRV9TSUdOSU5HX0tFWX0nCiAgICAgIC0gJ1NUUklQRV9TSUdOSU5HX0tFWV9DT05ORUNUPSR7U1RSSVBFX1NJR05JTkdfS0VZX0NPTk5FQ1R9JwogICAgdm9sdW1lczoKICAgICAgLSAncG9zdGl6X2NvbmZpZzovY29uZmlnLycKICAgICAgLSAncG9zdGl6X3VwbG9hZHM6L3VwbG9hZHMvJwogICAgZGVwZW5kc19vbjoKICAgICAgcG9zdGdyZXM6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgICAgcmVkaXM6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAnd2dldCAtcU8tIGh0dHA6Ly8xMjcuMC4wLjE6NTAwMC8nCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiAyMHMKICAgICAgcmV0cmllczogMTAKICBwb3N0Z3JlczoKICAgIGltYWdlOiAncG9zdGdyZXM6MTQuNScKICAgIHZvbHVtZXM6CiAgICAgIC0gJ3Bvc3Rpel9wb3N0Z3Jlc3FsX2RhdGE6L3Zhci9saWIvcG9zdGdyZXNxbC9kYXRhJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ1BPU1RHUkVTX1VTRVI9JHtTRVJWSUNFX1VTRVJfUE9TVEdSRVNRTH0nCiAgICAgIC0gJ1BPU1RHUkVTX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU1FMfScKICAgICAgLSAnUE9TVEdSRVNfREI9JHtQT1NUR1JFU1FMX0RBVEFCQVNFOi1wb3N0aXotZGJ9JwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICdwZ19pc3JlYWR5IC1VICR7U0VSVklDRV9VU0VSX1BPU1RHUkVTUUx9IC1kICR7UE9TVEdSRVNRTF9EQVRBQkFTRTotcG9zdGl6LWRifScKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDIwcwogICAgICByZXRyaWVzOiAxMAogIHJlZGlzOgogICAgaW1hZ2U6ICdyZWRpczo3LjInCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnUkVESVNfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX1JFRElTfScKICAgICAgLSAnUkVESVNfVVNFUj0ke1NFUlZJQ0VfVVNFUl9SRURJU30nCiAgICBjb21tYW5kOiAncmVkaXMtc2VydmVyIC0tcmVxdWlyZXBhc3MgJHtTRVJWSUNFX1BBU1NXT1JEX1JFRElTfScKICAgIHZvbHVtZXM6CiAgICAgIC0gJ3Bvc3Rpel9yZWRpc19kYXRhOi9kYXRhJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIHJlZGlzLWNsaQogICAgICAgIC0gJy1hJwogICAgICAgIC0gJyR7U0VSVklDRV9QQVNTV09SRF9SRURJU30nCiAgICAgICAgLSBwaW5nCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMjAK", + "compose": "c2VydmljZXM6CiAgcG9zdGl6OgogICAgaW1hZ2U6ICdnaGNyLmlvL2dpdHJvb21ocS9wb3N0aXotYXBwOmxhdGVzdCcKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9QT1NUSVpfNTAwMAogICAgICAtICdNQUlOX1VSTD0ke1NFUlZJQ0VfRlFETl9QT1NUSVp9JwogICAgICAtICdGUk9OVEVORF9VUkw9JHtTRVJWSUNFX0ZRRE5fUE9TVElafScKICAgICAgLSAnTkVYVF9QVUJMSUNfQkFDS0VORF9VUkw9JHtTRVJWSUNFX0ZRRE5fUE9TVElafS9hcGknCiAgICAgIC0gJ0pXVF9TRUNSRVQ9JHtTRVJWSUNFX1BBU1NXT1JEX0pXVFNFQ1JFVH0nCiAgICAgIC0gJ0RBVEFCQVNFX1VSTD1wb3N0Z3Jlc3FsOi8vcG9zdGdyZXM6JHtTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTUUx9QHBvc3RncmVzOjU0MzIvJHtQT1NUR1JFU1FMX0RBVEFCQVNFOi1wb3N0aXotZGJ9JwogICAgICAtICdSRURJU19VUkw9cmVkaXM6Ly9kZWZhdWx0OiR7U0VSVklDRV9QQVNTV09SRF9SRURJU31AcmVkaXM6NjM3OScKICAgICAgLSAnQkFDS0VORF9JTlRFUk5BTF9VUkw9aHR0cDovL2xvY2FsaG9zdDozMDAwJwogICAgICAtICdDTE9VREZMQVJFX0FDQ09VTlRfSUQ9JHtDTE9VREZMQVJFX0FDQ09VTlRfSUR9JwogICAgICAtICdDTE9VREZMQVJFX0FDQ0VTU19LRVk9JHtDTE9VREZMQVJFX0FDQ0VTU19LRVl9JwogICAgICAtICdDTE9VREZMQVJFX1NFQ1JFVF9BQ0NFU1NfS0VZPSR7Q0xPVURGTEFSRV9TRUNSRVRfQUNDRVNTX0tFWX0nCiAgICAgIC0gJ0NMT1VERkxBUkVfQlVDS0VUTkFNRT0ke0NMT1VERkxBUkVfQlVDS0VUTkFNRX0nCiAgICAgIC0gJ0NMT1VERkxBUkVfQlVDS0VUX1VSTD0ke0NMT1VERkxBUkVfQlVDS0VUX1VSTH0nCiAgICAgIC0gJ0NMT1VERkxBUkVfUkVHSU9OPSR7Q0xPVURGTEFSRV9SRUdJT059JwogICAgICAtICdTVE9SQUdFX1BST1ZJREVSPSR7U1RPUkFHRV9QUk9WSURFUjotbG9jYWx9JwogICAgICAtICdVUExPQURfRElSRUNUT1JZPSR7VVBMT0FEX0RJUkVDVE9SWTotL3VwbG9hZHN9JwogICAgICAtICdORVhUX1BVQkxJQ19VUExPQURfRElSRUNUT1JZPSR7TkVYVF9QVUJMSUNfVVBMT0FEX0RJUkVDVE9SWTotL3VwbG9hZHN9JwogICAgICAtICdORVhUX1BVQkxJQ19VUExPQURfU1RBVElDX0RJUkVDVE9SWT0ke05FWFRfUFVCTElDX1VQTE9BRF9TVEFUSUNfRElSRUNUT1JZfScKICAgICAgLSAnUkVTRU5EX0FQSV9LRVk9JHtSRVNFTkRfQVBJX0tFWX0nCiAgICAgIC0gJ0VNQUlMX0ZST01fQUREUkVTUz0ke0VNQUlMX0ZST01fQUREUkVTU30nCiAgICAgIC0gJ0VNQUlMX0ZST01fTkFNRT0ke0VNQUlMX0ZST01fTkFNRX0nCiAgICAgIC0gJ1hfQVBJX0tFWT0ke1NFUlZJQ0VfWF9BUEl9JwogICAgICAtICdYX0FQSV9TRUNSRVQ9JHtTRVJWSUNFX1hfU0VDUkVUfScKICAgICAgLSAnTElOS0VESU5fQ0xJRU5UX0lEPSR7U0VSVklDRV9MSU5LRURJTl9JRH0nCiAgICAgIC0gJ0xJTktFRElOX0NMSUVOVF9TRUNSRVQ9JHtTRVJWSUNFX0xJTktFRElOX1NFQ1JFVH0nCiAgICAgIC0gJ1JFRERJVF9DTElFTlRfSUQ9JHtTRVJWSUNFX1JFRERJVF9BUEl9JwogICAgICAtICdSRURESVRfQ0xJRU5UX1NFQ1JFVD0ke1NFUlZJQ0VfUkVERElUX1NFQ1JFVH0nCiAgICAgIC0gJ0dJVEhVQl9DTElFTlRfSUQ9JHtTRVJWSUNFX0dJVEhVQl9JRH0nCiAgICAgIC0gJ0dJVEhVQl9DTElFTlRfU0VDUkVUPSR7U0VSVklDRV9HSVRIVUJfU0VDUkVUfScKICAgICAgLSAnVEhSRUFEU19BUFBfSUQ9JHtTRVJWSUNFX1RIUkVBRFNfSUR9JwogICAgICAtICdUSFJFQURTX0FQUF9TRUNSRVQ9JHtTRVJWSUNFX1RIUkVBRFNfU0VDUkVUfScKICAgICAgLSAnRkFDRUJPT0tfQVBQX0lEPSR7U0VSVklDRV9GQUNFQk9PS19JRH0nCiAgICAgIC0gJ0ZBQ0VCT09LX0FQUF9TRUNSRVQ9JHtTRVJWSUNFX0ZBQ0VCT09LX1NFQ1JFVH0nCiAgICAgIC0gJ1lPVVRVQkVfQ0xJRU5UX0lEPSR7U0VSVklDRV9ZT1VUVUJFX0lEfScKICAgICAgLSAnWU9VVFVCRV9DTElFTlRfU0VDUkVUPSR7U0VSVklDRV9ZT1VUVUJFX1NFQ1JFVH0nCiAgICAgIC0gJ1RJS1RPS19DTElFTlRfSUQ9JHtTRVJWSUNFX1RJS1RPS19JRH0nCiAgICAgIC0gJ1RJS1RPS19DTElFTlRfU0VDUkVUPSR7U0VSVklDRV9USUtUT0tfU0VDUkVUfScKICAgICAgLSAnUElOVEVSRVNUX0NMSUVOVF9JRD0ke1NFUlZJQ0VfUElOVEVSRVNUX0lEfScKICAgICAgLSAnUElOVEVSRVNUX0NMSUVOVF9TRUNSRVQ9JHtTRVJWSUNFX1BJTlRFUkVTVF9TRUNSRVR9JwogICAgICAtICdEUklCQkJMRV9DTElFTlRfSUQ9JHtTRVJWSUNFX0RSSUJCTEVfSUR9JwogICAgICAtICdEUklCQkJMRV9DTElFTlRfU0VDUkVUPSR7U0VSVklDRV9EUklCQkxFX1NFQ1JFVH0nCiAgICAgIC0gJ0RJU0NPUkRfQ0xJRU5UX0lEPSR7U0VSVklDRV9ESVNDT1JEX0lEfScKICAgICAgLSAnRElTQ09SRF9DTElFTlRfU0VDUkVUPSR7U0VSVklDRV9ESVNDT1JEX1NFQ1JFVH0nCiAgICAgIC0gJ0RJU0NPUkRfQk9UX1RPS0VOX0lEPSR7U0VSVklDRV9ESVNDT1JEX1RPS0VOfScKICAgICAgLSAnU0xBQ0tfSUQ9JHtTRVJWSUNFX1NMQUNLX0lEfScKICAgICAgLSAnU0xBQ0tfU0VDUkVUPSR7U0VSVklDRV9TTEFDS19TRUNSRVR9JwogICAgICAtICdTTEFDS19TSUdOSU5HX1NFQ1JFVD0ke1NMQUNLX1NJR05JTkdfU0VDUkVUfScKICAgICAgLSAnTUFTVE9ET05fQ0xJRU5UX0lEPSR7U0VSVklDRV9NQVNUT0RPTl9JRH0nCiAgICAgIC0gJ01BU1RPRE9OX0NMSUVOVF9TRUNSRVQ9JHtTRVJWSUNFX01BU1RPRE9OX1NFQ1JFVH0nCiAgICAgIC0gJ0JFRUhJSVZFX0FQSV9LRVk9JHtTRVJWSUNFX0JFRUhJSVZFX0tFWX0nCiAgICAgIC0gJ0JFRUhJSVZFX1BVQkxJQ0FUSU9OX0lEPSR7U0VSVklDRV9CRUVISUlWRV9QVUJJRH0nCiAgICAgIC0gJ09QRU5BSV9BUElfS0VZPSR7U0VSVklDRV9PUEVOQUlfS0VZfScKICAgICAgLSAnTkVYVF9QVUJMSUNfRElTQ09SRF9TVVBQT1JUPSR7TkVYVF9QVUJMSUNfRElTQ09SRF9TVVBQT1JUfScKICAgICAgLSAnTkVYVF9QVUJMSUNfUE9MT1ROTz0ke05FWFRfUFVCTElDX1BPTE9UTk99JwogICAgICAtIElTX0dFTkVSQUw9dHJ1ZQogICAgICAtICdOWF9BRERfUExVR0lOUz0ke05YX0FERF9QTFVHSU5TOi1mYWxzZX0nCiAgICAgIC0gJ0ZFRV9BTU9VTlQ9JHtGRUVfQU1PVU5UOi0wLjA1fScKICAgICAgLSAnU1RSSVBFX1BVQkxJU0hBQkxFX0tFWT0ke1NUUklQRV9QVUJMSVNIQUJMRV9LRVl9JwogICAgICAtICdTVFJJUEVfU0VDUkVUX0tFWT0ke1NUUklQRV9TRUNSRVRfS0VZfScKICAgICAgLSAnU1RSSVBFX1NJR05JTkdfS0VZPSR7U1RSSVBFX1NJR05JTkdfS0VZfScKICAgICAgLSAnU1RSSVBFX1NJR05JTkdfS0VZX0NPTk5FQ1Q9JHtTVFJJUEVfU0lHTklOR19LRVlfQ09OTkVDVH0nCiAgICB2b2x1bWVzOgogICAgICAtICdwb3N0aXpfY29uZmlnOi9jb25maWcvJwogICAgICAtICdwb3N0aXpfdXBsb2FkczovdXBsb2Fkcy8nCiAgICBkZXBlbmRzX29uOgogICAgICBwb3N0Z3JlczoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgICByZWRpczoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICd3Z2V0IC1xTy0gaHR0cDovLzEyNy4wLjAuMTo1MDAwLycKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDIwcwogICAgICByZXRyaWVzOiAxMAogIHBvc3RncmVzOgogICAgaW1hZ2U6ICdwb3N0Z3JlczoxNC41JwogICAgdm9sdW1lczoKICAgICAgLSAncG9zdGl6X3Bvc3RncmVzcWxfZGF0YTovdmFyL2xpYi9wb3N0Z3Jlc3FsL2RhdGEnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBQT1NUR1JFU19VU0VSPXBvc3RncmVzCiAgICAgIC0gJ1BPU1RHUkVTX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU1FMfScKICAgICAgLSAnUE9TVEdSRVNfREI9JHtQT1NUR1JFU1FMX0RBVEFCQVNFOi1wb3N0aXotZGJ9JwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICdwZ19pc3JlYWR5IC1VICQke1BPU1RHUkVTX1VTRVJ9IC1kICQke1BPU1RHUkVTX0RCOi1wb3N0aXotZGJ9JwogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogMjBzCiAgICAgIHJldHJpZXM6IDEwCiAgcmVkaXM6CiAgICBpbWFnZTogJ3JlZGlzOjcuMicKICAgIGVudmlyb25tZW50OgogICAgICAtICdSRURJU19QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfUkVESVN9JwogICAgY29tbWFuZDogJ3JlZGlzLXNlcnZlciAtLXJlcXVpcmVwYXNzICR7U0VSVklDRV9QQVNTV09SRF9SRURJU30nCiAgICB2b2x1bWVzOgogICAgICAtICdwb3N0aXpfcmVkaXNfZGF0YTovZGF0YScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSByZWRpcy1jbGkKICAgICAgICAtICctYScKICAgICAgICAtICcke1NFUlZJQ0VfUEFTU1dPUkRfUkVESVN9JwogICAgICAgIC0gcGluZwogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogMTBzCiAgICAgIHJldHJpZXM6IDIwCg==", "tags": [ "post everywhere", "social media", @@ -2958,20 +2959,6 @@ "minversion": "0.0.0", "port": "8000" }, - "windows": { - "documentation": "https://github.com/dockur/windows?utm_source=coolify.io", - "slogan": "Run Windows in a containerized environment.", - "compose": "c2VydmljZXM6CiAgd2luZG93czoKICAgIGltYWdlOiBkb2NrdXJyL3dpbmRvd3MKICAgIHZvbHVtZXM6CiAgICAgIC0gJ3dpbmRvd3Mtc3RvcmFnZTovc3RvcmFnZScKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9XSU5ET1dTXzgwMDYKICAgICAgLSBWRVJTSU9OPTExCiAgICBjYXBfYWRkOgogICAgICAtIE5FVF9BRE1JTgogICAgc3RvcF9ncmFjZV9wZXJpb2Q6IDJtCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gbmMKICAgICAgICAtICcteicKICAgICAgICAtIDEyNy4wLjAuMQogICAgICAgIC0gJzgwMDYnCiAgICAgIGludGVydmFsOiAycwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMTAK", - "tags": [ - "windows", - "virtualization", - "container", - "os" - ], - "logo": "svgs/windows.svg", - "minversion": "0.0.0", - "port": "8006" - }, "wireguard-easy": { "documentation": "https://github.com/wg-easy/wg-easy?utm_source=coolify.io", "slogan": "The easiest way to run WireGuard VPN + Web-based Admin UI.", From 3c5c0fddbaf22faa1fce98def1ffc4bb2fe2ed40 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Mon, 2 Dec 2024 19:06:25 +0100 Subject: [PATCH 25/37] automate some things for Pterodactyl --- templates/compose/pterodactyl.yaml | 49 +++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/templates/compose/pterodactyl.yaml b/templates/compose/pterodactyl.yaml index 19315b4ce..ea64de47a 100644 --- a/templates/compose/pterodactyl.yaml +++ b/templates/compose/pterodactyl.yaml @@ -1,3 +1,4 @@ +# ignore: true # documentation: https://pterodactyl.io/ # slogan: Pterodactyl is a free, open-source game server management panel # tags: game, game server, management, panel, minecraft @@ -41,6 +42,37 @@ services: - "panel-var:/app/var/" - "panel-nginx:/etc/nginx/http.d/" - "panel-certs:/etc/letsencrypt/" + - type: bind + source: ./etc/entrypoint.sh + target: /entrypoint.sh + mode: "0755" + content: | + #!/bin/sh + set -e + + echo "Waiting for services to be ready..." + sleep 30 + + echo "Setting logs permissions..." + chown -R nginx: /app/storage/logs/ + + if ! php artisan p:user:list | grep -q "$ADMIN_EMAIL"; then + echo "Creating admin user..." + php artisan p:user:make --no-interaction \ + --admin=1 \ + --email="$ADMIN_EMAIL" \ + --username="$ADMIN_USERNAME" \ + --name-first="$ADMIN_FIRSTNAME" \ + --name-last="$ADMIN_LASTNAME" \ + --password="$ADMIN_PASSWORD" + echo "Admin user created" + else + echo "Admin user already exists, skipping creation" + fi + + exec supervisord -c --nodaemon + + command: ["/entrypoint.sh"] healthcheck: test: ["CMD-SHELL", "curl -sf http://localhost:80 || exit 1"] interval: 10s @@ -48,23 +80,25 @@ services: retries: 3 environment: - SERVICE_FQDN_PTERODACTYL - + - ADMIN_EMAIL=${ADMIN_EMAIL:-admin@example.com} + - ADMIN_USERNAME=${SERVICE_USER_ADMIN} + - ADMIN_FIRSTNAME=${ADMIN_FIRSTNAME:-Admin} + - ADMIN_LASTNAME=${ADMIN_LASTNAME:-User} + - ADMIN_PASSWORD=${SERVICE_PASSWORD_ADMIN} + - PTERODACTYL_HTTPS=${PTERODACTYL_HTTPS:-false} - APP_ENV=production - APP_ENVIRONMENT_ONLY=false - APP_URL=${PTERODACTYL_PUBLIC_FQDN:-$SERVICE_FQDN_PTERODACTYL} - APP_TIMEZONE=${TIMEZONE:-UTC} - APP_SERVICE_AUTHOR=${APP_SERVICE_AUTHOR:-author@example.com} - LOG_LEVEL=${LOG_LEVEL:-debug} - - CACHE_DRIVER=redis - SESSION_DRIVER=redis - QUEUE_DRIVER=redis - REDIS_HOST=redis - - DB_HOST=mariadb - DB_PORT=3306 - DB_PASSWORD=$SERVICE_PASSWORD_MYSQL - - MAIL_FROM=$MAIL_FROM - MAIL_DRIVER=$MAIL_DRIVER - MAIL_HOST=$MAIL_HOST @@ -111,10 +145,3 @@ services: v6: subnet: fdba:17c8:6c94::/64 gateway: fdba:17c8:6c94::1011 - -volumes: - panel-var: - panel-nginx: - panel-certs: - wings-logs: - pterodactyl-db: From b08f32508c1919d8f7da89522dc325ffcf427048 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Tremblay=20Lefran=C3=A7ois?= Date: Mon, 2 Dec 2024 13:14:00 -0500 Subject: [PATCH 26/37] added sonarr --- public/svgs/sonarr.svg | 1 + templates/compose/sonarr.yaml | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 public/svgs/sonarr.svg create mode 100644 templates/compose/sonarr.yaml diff --git a/public/svgs/sonarr.svg b/public/svgs/sonarr.svg new file mode 100644 index 000000000..91c04e289 --- /dev/null +++ b/public/svgs/sonarr.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/templates/compose/sonarr.yaml b/templates/compose/sonarr.yaml new file mode 100644 index 000000000..c2ac3e270 --- /dev/null +++ b/templates/compose/sonarr.yaml @@ -0,0 +1,24 @@ +# documentation: https://hub.docker.com/r/linuxserver/sonarr +# slogan: Sonarr⁠ (formerly NZBdrone) is a PVR for usenet and bittorrent users. It can monitor multiple RSS feeds for new episodes of your favorite shows and will grab, sort and rename them. It can also be configured to automatically upgrade the quality of files already downloaded when a better quality format becomes available. +# tags: media, server, tv +# logo: svgs/sonarr.svg +# port: 8989 + +services: + sonarr: + image: lscr.io/linuxserver/sonarr:latest + environment: + - SERVICE_FQDN_SONARR_8989 + - _APP_URL=$SERVICE_FQDN_SONARR + - PUID=1000 + - PGID=1000 + - TZ=${TZ:-America/Toronto} + volumes: + - sonarr-config:/config + # - sonarr-tv:/tv #optional + # - downloads:/downloads #optional + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8989/ping"] + interval: 2s + timeout: 10s + retries: 15 From 63fb9e9f40843adc60caadbee0bbe403f0bc84b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Tremblay=20Lefran=C3=A7ois?= Date: Mon, 2 Dec 2024 13:18:35 -0500 Subject: [PATCH 27/37] added radarr --- public/svgs/radarr.svg | 1 + templates/compose/radarr.yaml | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 public/svgs/radarr.svg create mode 100644 templates/compose/radarr.yaml diff --git a/public/svgs/radarr.svg b/public/svgs/radarr.svg new file mode 100644 index 000000000..93a4c9232 --- /dev/null +++ b/public/svgs/radarr.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/templates/compose/radarr.yaml b/templates/compose/radarr.yaml new file mode 100644 index 000000000..2795582a6 --- /dev/null +++ b/templates/compose/radarr.yaml @@ -0,0 +1,24 @@ +# documentation: https://hub.docker.com/r/linuxserver/radarr +# slogan: Radarr⁠ - A fork of Sonarr to work with movies à la Couchpotato. +# tags: media, server, movies +# logo: svgs/radarr.svg +# port: 7878 + +services: + radarr: + image: lscr.io/linuxserver/radarr:latest + environment: + - SERVICE_FQDN_RADARR_7878 + - _APP_URL=$SERVICE_FQDN_RADARR + - PUID=1000 + - PGID=1000 + - TZ=${TZ:-America/Toronto} + volumes: + - radarr-config:/config + # - radarr-movies:/movies #optional + # - downloads:/downloads #optional + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:7878/ping"] + interval: 2s + timeout: 10s + retries: 15 From 59fe9de1c932e06e189c5fe8c2d16e8b0ebfc6c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Tremblay=20Lefran=C3=A7ois?= Date: Mon, 2 Dec 2024 13:23:55 -0500 Subject: [PATCH 28/37] added prowlarr --- public/svgs/prowlarr.svg | 1 + templates/compose/prowlarr.yaml | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 public/svgs/prowlarr.svg create mode 100644 templates/compose/prowlarr.yaml diff --git a/public/svgs/prowlarr.svg b/public/svgs/prowlarr.svg new file mode 100644 index 000000000..a1a5a8ce3 --- /dev/null +++ b/public/svgs/prowlarr.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/templates/compose/prowlarr.yaml b/templates/compose/prowlarr.yaml new file mode 100644 index 000000000..f173ee1ca --- /dev/null +++ b/templates/compose/prowlarr.yaml @@ -0,0 +1,22 @@ +# documentation: https://hub.docker.com/r/linuxserver/prowlarr +# slogan: Prowlarr⁠ is a indexer manager/proxy built on the popular arr .net/reactjs base stack to integrate with your various PVR apps. Prowlarr supports both Torrent Trackers and Usenet Indexers. It integrates seamlessly with Sonarr, Radarr, Lidarr, and Readarr offering complete management of your indexers with no per app Indexer setup required (we do it all). +# tags: media, server, movies, tv, indexer, torrent, nzb, usenet +# logo: svgs/prowlarr.svg +# port: 9696 + +services: + prowlarr: + image: lscr.io/linuxserver/prowlarr:latest + environment: + - SERVICE_FQDN_PROWLARR_9696 + - _APP_URL=$SERVICE_FQDN_PROWLARR + - PUID=1000 + - PGID=1000 + - TZ=${TZ:-America/Toronto} + volumes: + - prowlarr-config:/config + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:9696/ping"] + interval: 2s + timeout: 10s + retries: 15 From f9143d0500af40d27d3a0d354f5e901169040644 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Mon, 2 Dec 2024 21:14:56 +0100 Subject: [PATCH 29/37] Update service-templates.json --- templates/service-templates.json | 44 ++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/templates/service-templates.json b/templates/service-templates.json index 0fff92f86..363fe511f 100644 --- a/templates/service-templates.json +++ b/templates/service-templates.json @@ -2285,6 +2285,24 @@ "minversion": "0.0.0", "port": "8080" }, + "prowlarr": { + "documentation": "https://hub.docker.com/r/linuxserver/prowlarr?utm_source=coolify.io", + "slogan": "Prowlarr\u2060 is a indexer manager/proxy built on the popular arr .net/reactjs base stack to integrate with your various PVR apps. Prowlarr supports both Torrent Trackers and Usenet Indexers. It integrates seamlessly with Sonarr, Radarr, Lidarr, and Readarr offering complete management of your indexers with no per app Indexer setup required (we do it all).", + "compose": "c2VydmljZXM6CiAgcHJvd2xhcnI6CiAgICBpbWFnZTogJ2xzY3IuaW8vbGludXhzZXJ2ZXIvcHJvd2xhcnI6bGF0ZXN0JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX1BST1dMQVJSXzk2OTYKICAgICAgLSBfQVBQX1VSTD0kU0VSVklDRV9GUUROX1BST1dMQVJSCiAgICAgIC0gUFVJRD0xMDAwCiAgICAgIC0gUEdJRD0xMDAwCiAgICAgIC0gJ1RaPSR7VFo6LUFtZXJpY2EvVG9yb250b30nCiAgICB2b2x1bWVzOgogICAgICAtICdwcm93bGFyci1jb25maWc6L2NvbmZpZycKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBjdXJsCiAgICAgICAgLSAnLWYnCiAgICAgICAgLSAnaHR0cDovL2xvY2FsaG9zdDo5Njk2L3BpbmcnCiAgICAgIGludGVydmFsOiAycwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMTUK", + "tags": [ + "media", + "server", + "movies", + "tv", + "indexer", + "torrent", + "nzb", + "usenet" + ], + "logo": "svgs/prowlarr.svg", + "minversion": "0.0.0", + "port": "9696" + }, "qbittorrent": { "documentation": "https://docs.linuxserver.io/images/docker-qbittorrent/?utm_source=coolify.io", "slogan": "The qBittorrent project aims to provide an open-source software alternative to \u03bcTorrent.", @@ -2333,6 +2351,19 @@ "minversion": "0.0.0", "port": "15672" }, + "radarr": { + "documentation": "https://hub.docker.com/r/linuxserver/radarr?utm_source=coolify.io", + "slogan": "Radarr\u2060 - A fork of Sonarr to work with movies \u00e0 la Couchpotato.", + "compose": "c2VydmljZXM6CiAgcmFkYXJyOgogICAgaW1hZ2U6ICdsc2NyLmlvL2xpbnV4c2VydmVyL3JhZGFycjpsYXRlc3QnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX0ZRRE5fUkFEQVJSXzc4NzgKICAgICAgLSBfQVBQX1VSTD0kU0VSVklDRV9GUUROX1JBREFSUgogICAgICAtIFBVSUQ9MTAwMAogICAgICAtIFBHSUQ9MTAwMAogICAgICAtICdUWj0ke1RaOi1BbWVyaWNhL1Rvcm9udG99JwogICAgdm9sdW1lczoKICAgICAgLSAncmFkYXJyLWNvbmZpZzovY29uZmlnJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIGN1cmwKICAgICAgICAtICctZicKICAgICAgICAtICdodHRwOi8vbG9jYWxob3N0Ojc4NzgvcGluZycKICAgICAgaW50ZXJ2YWw6IDJzCiAgICAgIHRpbWVvdXQ6IDEwcwogICAgICByZXRyaWVzOiAxNQo=", + "tags": [ + "media", + "server", + "movies" + ], + "logo": "svgs/radarr.svg", + "minversion": "0.0.0", + "port": "7878" + }, "reactive-resume": { "documentation": "https://rxresu.me/?utm_source=coolify.io", "slogan": "A one-of-a-kind resume builder that keeps your privacy in mind.", @@ -2473,6 +2504,19 @@ "minversion": "0.0.0", "port": "6001" }, + "sonarr": { + "documentation": "https://hub.docker.com/r/linuxserver/sonarr?utm_source=coolify.io", + "slogan": "Sonarr\u2060 (formerly NZBdrone) is a PVR for usenet and bittorrent users. It can monitor multiple RSS feeds for new episodes of your favorite shows and will grab, sort and rename them. It can also be configured to automatically upgrade the quality of files already downloaded when a better quality format becomes available.", + "compose": "c2VydmljZXM6CiAgc29uYXJyOgogICAgaW1hZ2U6ICdsc2NyLmlvL2xpbnV4c2VydmVyL3NvbmFycjpsYXRlc3QnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX0ZRRE5fU09OQVJSXzg5ODkKICAgICAgLSBfQVBQX1VSTD0kU0VSVklDRV9GUUROX1NPTkFSUgogICAgICAtIFBVSUQ9MTAwMAogICAgICAtIFBHSUQ9MTAwMAogICAgICAtICdUWj0ke1RaOi1BbWVyaWNhL1Rvcm9udG99JwogICAgdm9sdW1lczoKICAgICAgLSAnc29uYXJyLWNvbmZpZzovY29uZmlnJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIGN1cmwKICAgICAgICAtICctZicKICAgICAgICAtICdodHRwOi8vbG9jYWxob3N0Ojg5ODkvcGluZycKICAgICAgaW50ZXJ2YWw6IDJzCiAgICAgIHRpbWVvdXQ6IDEwcwogICAgICByZXRyaWVzOiAxNQo=", + "tags": [ + "media", + "server", + "tv" + ], + "logo": "svgs/sonarr.svg", + "minversion": "0.0.0", + "port": "8989" + }, "statusnook": { "documentation": "https://statusnook.com?utm_source=coolify.io", "slogan": "Effortlessly deploy a status page and start monitoring endpoints in minutes", From a776871b22ffdb6d5c577f5f5dd3bde93f763888 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Mon, 2 Dec 2024 21:35:04 +0100 Subject: [PATCH 30/37] disable coder see #4431 --- templates/compose/coder.yaml | 1 + templates/service-templates.json | 15 --------------- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/templates/compose/coder.yaml b/templates/compose/coder.yaml index fec22b5bf..717cff03c 100644 --- a/templates/compose/coder.yaml +++ b/templates/compose/coder.yaml @@ -1,3 +1,4 @@ +# ignore: true # documentation: https://coder.com/docs # slogan: Coder is an open-source platform for creating and managing cloud development environments on your infrastructure, with the tools and IDEs your developers already love. # tags: coder,development,environment,self-hosted,postgres diff --git a/templates/service-templates.json b/templates/service-templates.json index 363fe511f..222ca1601 100644 --- a/templates/service-templates.json +++ b/templates/service-templates.json @@ -418,21 +418,6 @@ "minversion": "0.0.0", "port": "8443" }, - "coder": { - "documentation": "https://coder.com/docs?utm_source=coolify.io", - "slogan": "Coder is an open-source platform for creating and managing cloud development environments on your infrastructure, with the tools and IDEs your developers already love.", - "compose": "c2VydmljZXM6CiAgY29kZXI6CiAgICBpbWFnZTogJ2doY3IuaW8vY29kZXIvY29kZXI6bGF0ZXN0JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX0NPREVSXzcwODAKICAgICAgLSAnQ09ERVJfUEdfQ09OTkVDVElPTl9VUkw9cG9zdGdyZXNxbDovLyR7U0VSVklDRV9VU0VSX1BPU1RHUkVTfToke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9QGNvZGVyLWRhdGFiYXNlLyR7UE9TVEdSRVNfREI6LWNvZGVyLWRifT9zc2xtb2RlPWRpc2FibGUnCiAgICAgIC0gJ0NPREVSX0hUVFBfQUREUkVTUz0wLjAuMC4wOjcwODAnCiAgICAgIC0gJ0NPREVSX0FDQ0VTU19VUkw9JHtTRVJWSUNFX0ZRRE5fQ09ERVJ9JwogICAgdm9sdW1lczoKICAgICAgLSAnL3Zhci9ydW4vZG9ja2VyLnNvY2s6L3Zhci9ydW4vZG9ja2VyLnNvY2snCiAgICBkZXBlbmRzX29uOgogICAgICBjb2Rlci1kYXRhYmFzZToKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIHdnZXQKICAgICAgICAtICctcScKICAgICAgICAtICctLXNwaWRlcicKICAgICAgICAtICdodHRwOi8vbG9jYWxob3N0OjcwODAnCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiAyMHMKICAgICAgcmV0cmllczogMTAKICBjb2Rlci1kYXRhYmFzZToKICAgIGltYWdlOiAncG9zdGdyZXM6MTYuNC1hbHBpbmUnCiAgICBlbnZpcm9ubWVudDoKICAgICAgUE9TVEdSRVNfVVNFUjogJyR7U0VSVklDRV9VU0VSX1BPU1RHUkVTfScKICAgICAgUE9TVEdSRVNfUEFTU1dPUkQ6ICcke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9JwogICAgICBQT1NUR1JFU19EQjogJyR7UE9TVEdSRVNfREI6LWNvZGVyLWRifScKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2NvZGVyLXBvc3RncmVzLWRhdGE6L3Zhci9saWIvcG9zdGdyZXNxbC9kYXRhJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICdwZ19pc3JlYWR5IC1VICR7UE9TVEdSRVNfVVNFUjotdXNlcm5hbWV9IC1kICR7UE9TVEdSRVNfREI6LWNvZGVyfScKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDVzCiAgICAgIHJldHJpZXM6IDUK", - "tags": [ - "coder", - "development", - "environment", - "self-hosted", - "postgres" - ], - "logo": "svgs/coder.svg", - "minversion": "0.0.0", - "port": "7080" - }, "cryptgeon": { "documentation": "https://github.com/cupcakearmy/cryptgeon?utm_source=coolify.io", "slogan": "Secure note / file sharing service inspired by PrivNote.", From d1a1ecbe28ce128173473bd6ba63158d8462455c Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 2 Dec 2024 22:01:15 +0100 Subject: [PATCH 31/37] fix: only able to select the right keys --- app/Livewire/Boarding/Index.php | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/app/Livewire/Boarding/Index.php b/app/Livewire/Boarding/Index.php index b6c799c4e..eadabba7c 100644 --- a/app/Livewire/Boarding/Index.php +++ b/app/Livewire/Boarding/Index.php @@ -172,13 +172,7 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA== public function getProxyType() { - // Set Default Proxy Type $this->selectProxy(ProxyTypes::TRAEFIK->value); - // $proxyTypeSet = $this->createdServer->proxy->type; - // if (!$proxyTypeSet) { - // $this->currentState = 'select-proxy'; - // return; - // } $this->getProjects(); } @@ -189,7 +183,7 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA== return; } - $this->createdPrivateKey = PrivateKey::find($this->selectedExistingPrivateKey); + $this->createdPrivateKey = PrivateKey::where('team_id', currentTeam()->id)->where('id', $this->selectedExistingPrivateKey)->first(); $this->privateKey = $this->createdPrivateKey->private_key; $this->currentState = 'create-server'; } From ec1312a3f8895ac2768ec2c79dceaa30acb2ecc8 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 2 Dec 2024 22:12:02 +0100 Subject: [PATCH 32/37] able to change zoom --- resources/css/app.css | 16 +-------- resources/views/components/navbar.blade.php | 39 +++++++++++++++++++-- 2 files changed, 37 insertions(+), 18 deletions(-) diff --git a/resources/css/app.css b/resources/css/app.css index c3d46cc04..32d476c1a 100644 --- a/resources/css/app.css +++ b/resources/css/app.css @@ -4,20 +4,6 @@ @tailwind components; @tailwind utilities; -html { - font-size: 93.75%; -} - -:root { - --vh: 1vh; -} - -@screen lg { - html { - font-size: 87.5%; - } -} - html, body { @apply h-full bg-neutral-50 text-neutral-800 dark:bg-base dark:text-neutral-400 w-full; @@ -336,4 +322,4 @@ section { .dz-button { @apply w-full p-4 py-10 my-4 font-bold bg-white border dark:border-coolgray-400 dark:text-white dark:bg-transparent hover:dark:bg-coolgray-400; -} +} \ No newline at end of file diff --git a/resources/views/components/navbar.blade.php b/resources/views/components/navbar.blade.php index f635a6787..7d343c645 100644 --- a/resources/views/components/navbar.blade.php +++ b/resources/views/components/navbar.blade.php @@ -7,8 +7,13 @@ } window.location.reload(); }, + setZoom(zoom) { + localStorage.setItem('zoom', zoom); + window.location.reload(); + }, init() { this.full = localStorage.getItem('pageWidth'); + this.zoom = localStorage.getItem('zoom'); window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => { const userSettings = localStorage.getItem('theme'); if (userSettings !== 'system') { @@ -21,6 +26,7 @@ } }); this.queryTheme(); + this.checkZoom(); }, setTheme(type) { this.theme = type; @@ -44,6 +50,30 @@ this.theme = 'system'; document.documentElement.classList.remove('dark'); } + }, + checkZoom() { + if (this.zoom === null) { + this.setZoom(100); + } + if (this.zoom === '90') { + const style = document.createElement('style'); + style.textContent = ` + html { + font-size: 93.75%; + } + + :root { + --vh: 1vh; + } + + @media (min-width: 1024px) { + html { + font-size: 87.5%; + } + } + `; + document.head.appendChild(style); + } } }">
@@ -69,7 +99,7 @@
-
Color
+
Color
@@ -78,6 +108,9 @@ x-show="full === 'full'">Center +
Zoom
+ +
@@ -163,8 +196,8 @@ class="{{ request()->is('storages*') ? 'menu-item-active menu-item' : 'menu-item' }}" href="{{ route('storage.index') }}"> - + From 7f449c3b729c9d89b3c7c86383ba5197fdca1fd8 Mon Sep 17 00:00:00 2001 From: peaklabs-dev <122374094+peaklabs-dev@users.noreply.github.com> Date: Mon, 2 Dec 2024 22:37:11 +0100 Subject: [PATCH 33/37] fix: test email should not be required --- app/Livewire/Notifications/Email.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Livewire/Notifications/Email.php b/app/Livewire/Notifications/Email.php index fcedf1305..c4e4aae14 100644 --- a/app/Livewire/Notifications/Email.php +++ b/app/Livewire/Notifications/Email.php @@ -73,8 +73,8 @@ class Email extends Component #[Validate(['nullable', 'string'])] public ?string $resendApiKey = null; - #[Validate(['required', 'email'])] - public string $testEmailAddress = ''; + #[Validate(['nullable', 'email'])] + public ?string $testEmailAddress = null; public function mount() { From 58988d3686cafe60b30a8c5679772a38f39cb3ad Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 2 Dec 2024 22:49:41 +0100 Subject: [PATCH 34/37] fix: a few inputs --- app/Actions/Docker/GetContainersStatus.php | 10 +- app/Actions/Server/ServerCheck.php | 8 +- .../Api/ApplicationsController.php | 55 +++++- .../Controllers/Api/DatabasesController.php | 21 ++- .../Controllers/Api/ServicesController.php | 4 +- app/Jobs/PushServerUpdateJob.php | 2 +- app/Models/BaseModel.php | 13 ++ app/Models/StandalonePostgresql.php | 16 +- app/Models/Team.php | 7 + bootstrap/helpers/shared.php | 156 ++++++++++-------- 10 files changed, 190 insertions(+), 102 deletions(-) diff --git a/app/Actions/Docker/GetContainersStatus.php b/app/Actions/Docker/GetContainersStatus.php index 8aae910a9..e9f577e06 100644 --- a/app/Actions/Docker/GetContainersStatus.php +++ b/app/Actions/Docker/GetContainersStatus.php @@ -179,7 +179,7 @@ class GetContainersStatus })->first(); if (! $foundTcpProxy) { StartDatabaseProxy::run($database); - // $this->server->team?->notify(new ContainerRestarted("TCP Proxy for {$database->name}", $this->server)); + // $this->server->team?->notify(new ContainerRestarted("TCP Proxy for database", $this->server)); } } } else { @@ -260,7 +260,7 @@ class GetContainersStatus $environmentName = data_get($service, 'environment.name'); if ($projectUuid && $serviceUuid && $environmentName) { - $url = base_url().'/project/'.$projectUuid.'/'.$environmentName.'/service/'.$serviceUuid; + $url = base_url() . '/project/' . $projectUuid . '/' . $environmentName . '/service/' . $serviceUuid; } else { $url = null; } @@ -286,7 +286,7 @@ class GetContainersStatus $environment = data_get($application, 'environment.name'); if ($projectUuid && $applicationUuid && $environment) { - $url = base_url().'/project/'.$projectUuid.'/'.$environment.'/application/'.$applicationUuid; + $url = base_url() . '/project/' . $projectUuid . '/' . $environment . '/application/' . $applicationUuid; } else { $url = null; } @@ -311,7 +311,7 @@ class GetContainersStatus $applicationUuid = data_get($preview, 'application.uuid'); if ($projectUuid && $applicationUuid && $environmentName) { - $url = base_url().'/project/'.$projectUuid.'/'.$environmentName.'/application/'.$applicationUuid; + $url = base_url() . '/project/' . $projectUuid . '/' . $environmentName . '/application/' . $applicationUuid; } else { $url = null; } @@ -336,7 +336,7 @@ class GetContainersStatus $databaseUuid = data_get($database, 'uuid'); if ($projectUuid && $databaseUuid && $environmentName) { - $url = base_url().'/project/'.$projectUuid.'/'.$environmentName.'/database/'.$databaseUuid; + $url = base_url() . '/project/' . $projectUuid . '/' . $environmentName . '/database/' . $databaseUuid; } else { $url = null; } diff --git a/app/Actions/Server/ServerCheck.php b/app/Actions/Server/ServerCheck.php index 5f9a1e357..35b4996b4 100644 --- a/app/Actions/Server/ServerCheck.php +++ b/app/Actions/Server/ServerCheck.php @@ -51,7 +51,6 @@ class ServerCheck $containerReplicates = null; $this->isSentinel = true; - } else { ['containers' => $this->containers, 'containerReplicates' => $containerReplicates] = $this->server->getContainers(); // ServerStorageCheckJob::dispatch($this->server); @@ -148,7 +147,6 @@ class ServerCheck } else { $labels = Arr::undot(data_get($container, 'Config.Labels')); } - } $managed = data_get($labels, 'coolify.managed'); if (! $managed) { @@ -215,7 +213,7 @@ class ServerCheck if ($isPublic) { $foundTcpProxy = $this->containers->filter(function ($value, $key) use ($uuid) { if ($this->isSentinel) { - return data_get($value, 'name') === $uuid.'-proxy'; + return data_get($value, 'name') === $uuid . '-proxy'; } else { if ($this->server->isSwarm()) { @@ -247,7 +245,7 @@ class ServerCheck if ($isPublic) { $foundTcpProxy = $this->containers->filter(function ($value, $key) use ($uuid) { if ($this->isSentinel) { - return data_get($value, 'name') === $uuid.'-proxy'; + return data_get($value, 'name') === $uuid . '-proxy'; } else { if ($this->server->isSwarm()) { return data_get($value, 'Spec.Name') === "coolify-proxy_$uuid"; @@ -259,7 +257,7 @@ class ServerCheck })->first(); if (! $foundTcpProxy) { StartDatabaseProxy::run($database); - // $this->server->team?->notify(new ContainerRestarted("TCP Proxy for {$database->name}", $this->server)); + // $this->server->team?->notify(new ContainerRestarted("TCP Proxy for database", $this->server)); } } } diff --git a/app/Http/Controllers/Api/ApplicationsController.php b/app/Http/Controllers/Api/ApplicationsController.php index c69640970..614208c78 100644 --- a/app/Http/Controllers/Api/ApplicationsController.php +++ b/app/Http/Controllers/Api/ApplicationsController.php @@ -1591,16 +1591,32 @@ class ApplicationsController extends Controller } $domains = $request->domains; if ($request->has('domains') && $server->isProxyShouldRun()) { - $errors = []; + $uuid = $request->uuid; $fqdn = $request->domains; $fqdn = str($fqdn)->replaceEnd(',', '')->trim(); $fqdn = str($fqdn)->replaceStart(',', '')->trim(); - $application->fqdn = $fqdn; - if (! $application->settings->is_container_label_readonly_enabled) { - $customLabels = str(implode('|coolify|', generateLabelsApplication($application)))->replace('|coolify|', "\n"); - $application->custom_labels = base64_encode($customLabels); + $errors = []; + $fqdn = str($fqdn)->trim()->explode(',')->map(function ($domain) use (&$errors) { + $domain = trim($domain); + if (filter_var($domain, FILTER_VALIDATE_URL) === false || !preg_match('/^https?:\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,}/', $domain)) { + $errors[] = 'Invalid domain: '.$domain; + } + return $domain; + }); + if (count($errors) > 0) { + return response()->json([ + 'message' => 'Validation failed.', + 'errors' => $errors, + ], 422); + } + if (checkIfDomainIsAlreadyUsed($fqdn, $teamId, $uuid)) { + return response()->json([ + 'message' => 'Validation failed.', + 'errors' => [ + 'domains' => 'One of the domain is already used.', + ], + ], 422); } - $request->offsetUnset('domains'); } $dockerComposeDomainsJson = collect(); @@ -2811,3 +2827,30 @@ class ApplicationsController extends Controller } } } + + $fqdn = str($fqdn)->replaceStart(',', '')->trim(); + $errors = []; + $fqdn = str($fqdn)->trim()->explode(',')->map(function ($domain) use (&$errors) { + if (filter_var($domain, FILTER_VALIDATE_URL) === false) { + $errors[] = 'Invalid domain: ' . $domain; + } + + return str($domain)->trim()->lower(); + }); + if (count($errors) > 0) { + return response()->json([ + 'message' => 'Validation failed.', + 'errors' => $errors, + ], 422); + } + if (checkIfDomainIsAlreadyUsed($fqdn, $teamId, $uuid)) { + return response()->json([ + 'message' => 'Validation failed.', + 'errors' => [ + 'domains' => 'One of the domain is already used.', + ], + ], 422); + } + } + } +} diff --git a/app/Http/Controllers/Api/DatabasesController.php b/app/Http/Controllers/Api/DatabasesController.php index ce658d2a2..9366e6300 100644 --- a/app/Http/Controllers/Api/DatabasesController.php +++ b/app/Http/Controllers/Api/DatabasesController.php @@ -1557,7 +1557,8 @@ class DatabasesController extends Controller ] ) ), - ]), + ] + ), new OA\Response( response: 401, ref: '#/components/responses/401', @@ -1632,9 +1633,11 @@ class DatabasesController extends Controller type: 'object', properties: [ 'message' => ['type' => 'string', 'example' => 'Database starting request queued.'], - ]) + ] + ) ), - ]), + ] + ), new OA\Response( response: 401, ref: '#/components/responses/401', @@ -1708,9 +1711,11 @@ class DatabasesController extends Controller type: 'object', properties: [ 'message' => ['type' => 'string', 'example' => 'Database stopping request queued.'], - ]) + ] + ) ), - ]), + ] + ), new OA\Response( response: 401, ref: '#/components/responses/401', @@ -1784,9 +1789,11 @@ class DatabasesController extends Controller type: 'object', properties: [ 'message' => ['type' => 'string', 'example' => 'Database restaring request queued.'], - ]) + ] + ) ), - ]), + ] + ), new OA\Response( response: 401, ref: '#/components/responses/401', diff --git a/app/Http/Controllers/Api/ServicesController.php b/app/Http/Controllers/Api/ServicesController.php index bf90322e2..abf8a24af 100644 --- a/app/Http/Controllers/Api/ServicesController.php +++ b/app/Http/Controllers/Api/ServicesController.php @@ -308,7 +308,7 @@ class ServicesController extends Controller } if ($oneClickService) { $service_payload = [ - 'name' => "$oneClickServiceName-".str()->random(10), + 'name' => "$oneClickServiceName-" . str()->random(10), 'docker_compose_raw' => base64_decode($oneClickService), 'environment_id' => $environment->id, 'service_type' => $oneClickServiceName, @@ -320,7 +320,7 @@ class ServicesController extends Controller data_set($service_payload, 'connect_to_docker_network', true); } $service = Service::create($service_payload); - $service->name = "$oneClickServiceName-".$service->uuid; + $service->name = "$oneClickServiceName-" . $service->uuid; $service->save(); if ($oneClickDotEnvs?->count() > 0) { $oneClickDotEnvs->each(function ($value) use ($service) { diff --git a/app/Jobs/PushServerUpdateJob.php b/app/Jobs/PushServerUpdateJob.php index 24f8d1e6b..fa146ff96 100644 --- a/app/Jobs/PushServerUpdateJob.php +++ b/app/Jobs/PushServerUpdateJob.php @@ -280,7 +280,7 @@ class PushServerUpdateJob implements ShouldBeEncrypted, ShouldQueue })->first(); if (! $tcpProxyContainerFound) { StartDatabaseProxy::dispatch($database); - $this->server->team?->notify(new ContainerRestarted("TCP Proxy for {$database->name}", $this->server)); + $this->server->team?->notify(new ContainerRestarted("TCP Proxy for database", $this->server)); } else { } } diff --git a/app/Models/BaseModel.php b/app/Models/BaseModel.php index 17201ea6e..500c34fb6 100644 --- a/app/Models/BaseModel.php +++ b/app/Models/BaseModel.php @@ -2,6 +2,7 @@ namespace App\Models; +use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Model; use Visus\Cuid2\Cuid2; @@ -18,4 +19,16 @@ abstract class BaseModel extends Model } }); } + public function name(): Attribute + { + return new Attribute( + get: fn() => sanitize_string($this->getRawOriginal('name')), + ); + } + public function image(): Attribute + { + return new Attribute( + get: fn() => sanitize_string($this->getRawOriginal('image')), + ); + } } diff --git a/app/Models/StandalonePostgresql.php b/app/Models/StandalonePostgresql.php index 4a457a6cf..99cc8a55b 100644 --- a/app/Models/StandalonePostgresql.php +++ b/app/Models/StandalonePostgresql.php @@ -25,7 +25,7 @@ class StandalonePostgresql extends BaseModel { static::created(function ($database) { LocalPersistentVolume::create([ - 'name' => 'postgres-data-'.$database->uuid, + 'name' => 'postgres-data-' . $database->uuid, 'mount_path' => '/var/lib/postgresql/data', 'host_path' => null, 'resource_id' => $database->id, @@ -48,7 +48,7 @@ class StandalonePostgresql extends BaseModel public function workdir() { - return database_configuration_dir()."/{$this->uuid}"; + return database_configuration_dir() . "/{$this->uuid}"; } protected function serverStatus(): Attribute @@ -65,7 +65,7 @@ class StandalonePostgresql extends BaseModel $server = data_get($this, 'destination.server'); $workdir = $this->workdir(); if (str($workdir)->endsWith($this->uuid)) { - instant_remote_process(['rm -rf '.$this->workdir()], $server, false); + instant_remote_process(['rm -rf ' . $this->workdir()], $server, false); } } @@ -82,7 +82,7 @@ class StandalonePostgresql extends BaseModel public function isConfigurationChanged(bool $save = false) { - $newConfigHash = $this->image.$this->ports_mappings.$this->postgres_initdb_args.$this->postgres_host_auth_method; + $newConfigHash = $this->image . $this->ports_mappings . $this->postgres_initdb_args . $this->postgres_host_auth_method; $newConfigHash .= json_encode($this->environment_variables()->get('value')->sort()); $newConfigHash = md5($newConfigHash); $oldConfigHash = data_get($this, 'config_hash'); @@ -186,14 +186,14 @@ class StandalonePostgresql extends BaseModel public function portsMappings(): Attribute { return Attribute::make( - set: fn ($value) => $value === '' ? null : $value, + set: fn($value) => $value === '' ? null : $value, ); } public function portsMappingsArray(): Attribute { return Attribute::make( - get: fn () => is_null($this->ports_mappings) + get: fn() => is_null($this->ports_mappings) ? [] : explode(',', $this->ports_mappings), @@ -208,7 +208,7 @@ class StandalonePostgresql extends BaseModel public function databaseType(): Attribute { return new Attribute( - get: fn () => $this->type(), + get: fn() => $this->type(), ); } @@ -220,7 +220,7 @@ class StandalonePostgresql extends BaseModel protected function internalDbUrl(): Attribute { return new Attribute( - get: fn () => "postgres://{$this->postgres_user}:{$this->postgres_password}@{$this->uuid}:5432/{$this->postgres_db}", + get: fn() => "postgres://{$this->postgres_user}:{$this->postgres_password}@{$this->uuid}:5432/{$this->postgres_db}", ); } diff --git a/app/Models/Team.php b/app/Models/Team.php index e21aa3a25..76d89fb8e 100644 --- a/app/Models/Team.php +++ b/app/Models/Team.php @@ -127,6 +127,13 @@ class Team extends Model implements SendsDiscord, SendsEmail ]; } + public function name(): Attribute + { + return new Attribute( + get: fn() => sanitize_string($this->getRawOriginal('name')), + ); + } + public function getRecepients($notification) { $recipients = data_get($notification, 'emails', null); diff --git a/bootstrap/helpers/shared.php b/bootstrap/helpers/shared.php index 1a943cd73..ddc578400 100644 --- a/bootstrap/helpers/shared.php +++ b/bootstrap/helpers/shared.php @@ -67,31 +67,51 @@ function base_configuration_dir(): string } function application_configuration_dir(): string { - return base_configuration_dir().'/applications'; + return base_configuration_dir() . '/applications'; } function service_configuration_dir(): string { - return base_configuration_dir().'/services'; + return base_configuration_dir() . '/services'; } function database_configuration_dir(): string { - return base_configuration_dir().'/databases'; + return base_configuration_dir() . '/databases'; } function database_proxy_dir($uuid): string { - return base_configuration_dir()."/databases/$uuid/proxy"; + return base_configuration_dir() . "/databases/$uuid/proxy"; } function backup_dir(): string { - return base_configuration_dir().'/backups'; + return base_configuration_dir() . '/backups'; } function metrics_dir(): string { - return base_configuration_dir().'/metrics'; + return base_configuration_dir() . '/metrics'; +} + +function sanitize_string(string $input): string +{ + // Remove any HTML/PHP tags + $sanitized = strip_tags($input); + + // Convert special characters to HTML entities + $sanitized = htmlspecialchars($sanitized, ENT_QUOTES | ENT_HTML5, 'UTF-8'); + + // Remove any control characters + $sanitized = preg_replace('/[\x00-\x1F\x7F]/u', '', $sanitized); + + // Trim whitespace + $sanitized = trim($sanitized); + + return $sanitized; } function generate_readme_file(string $name, string $updated_at): string { + $name = sanitize_string($name); + $updated_at = sanitize_string($updated_at); + return "Resource name: $name\nLatest Deployment Date: $updated_at"; } @@ -122,8 +142,8 @@ function refreshSession(?Team $team = null): void $team = User::find(Auth::id())->teams->first(); } } - Cache::forget('team:'.Auth::id()); - Cache::remember('team:'.Auth::id(), 3600, function () use ($team) { + Cache::forget('team:' . Auth::id()); + Cache::remember('team:' . Auth::id(), 3600, function () use ($team) { return $team; }); session(['currentTeam' => $team]); @@ -155,7 +175,7 @@ function handleError(?Throwable $error = null, ?Livewire\Component $livewire = n $message = null; } if ($customErrorMessage) { - $message = $customErrorMessage.' '.$message; + $message = $customErrorMessage . ' ' . $message; } if (isset($livewire)) { @@ -410,7 +430,7 @@ function send_user_an_email(MailMessage $mail, string $email, ?string $cc = null Mail::send( [], [], - fn (Message $message) => $message + fn(Message $message) => $message ->to($email) ->replyTo($email) ->cc($cc) @@ -421,7 +441,7 @@ function send_user_an_email(MailMessage $mail, string $email, ?string $cc = null Mail::send( [], [], - fn (Message $message) => $message + fn(Message $message) => $message ->to($email) ->subject($mail->subject) ->html((string) $mail->render()) @@ -657,19 +677,19 @@ function queryResourcesByUuid(string $uuid) function generateTagDeployWebhook($tag_name) { $baseUrl = base_url(); - $api = Url::fromString($baseUrl).'/api/v1'; + $api = Url::fromString($baseUrl) . '/api/v1'; $endpoint = "/deploy?tag=$tag_name"; - return $api.$endpoint; + return $api . $endpoint; } function generateDeployWebhook($resource) { $baseUrl = base_url(); - $api = Url::fromString($baseUrl).'/api/v1'; + $api = Url::fromString($baseUrl) . '/api/v1'; $endpoint = '/deploy'; $uuid = data_get($resource, 'uuid'); - return $api.$endpoint."?uuid=$uuid&force=false"; + return $api . $endpoint . "?uuid=$uuid&force=false"; } function generateGitManualWebhook($resource, $type) { @@ -679,7 +699,7 @@ function generateGitManualWebhook($resource, $type) if ($resource->getMorphClass() === \App\Models\Application::class) { $baseUrl = base_url(); - return Url::fromString($baseUrl)."/webhooks/source/$type/events/manual"; + return Url::fromString($baseUrl) . "/webhooks/source/$type/events/manual"; } return null; @@ -1047,7 +1067,7 @@ function validate_dns_entry(string $fqdn, Server $server) $query = new DNSQuery($dns_server); $results = $query->query($host, $type); if ($results === false || $query->hasError()) { - ray('Error: '.$query->getLasterror()); + ray('Error: ' . $query->getLasterror()); } else { foreach ($results as $result) { if ($result->getType() == $type) { @@ -1057,7 +1077,7 @@ function validate_dns_entry(string $fqdn, Server $server) break; } if ($result->getData() === $ip) { - ray($host.' has IP address '.$result->getData()); + ray($host . ' has IP address ' . $result->getData()); ray($result->getString()); $found_matching_ip = true; break; @@ -1105,15 +1125,15 @@ function checkIfDomainIsAlreadyUsed(Collection|array $domains, ?string $teamId = $applications = Application::ownedByCurrentTeamAPI($teamId)->get(['fqdn', 'uuid']); $serviceApplications = ServiceApplication::ownedByCurrentTeamAPI($teamId)->get(['fqdn', 'uuid']); if ($uuid) { - $applications = $applications->filter(fn ($app) => $app->uuid !== $uuid); - $serviceApplications = $serviceApplications->filter(fn ($app) => $app->uuid !== $uuid); + $applications = $applications->filter(fn($app) => $app->uuid !== $uuid); + $serviceApplications = $serviceApplications->filter(fn($app) => $app->uuid !== $uuid); } $domainFound = false; foreach ($applications as $app) { if (is_null($app->fqdn)) { continue; } - $list_of_domains = collect(explode(',', $app->fqdn))->filter(fn ($fqdn) => $fqdn !== ''); + $list_of_domains = collect(explode(',', $app->fqdn))->filter(fn($fqdn) => $fqdn !== ''); foreach ($list_of_domains as $domain) { if (str($domain)->endsWith('/')) { $domain = str($domain)->beforeLast('/'); @@ -1132,7 +1152,7 @@ function checkIfDomainIsAlreadyUsed(Collection|array $domains, ?string $teamId = if (str($app->fqdn)->isEmpty()) { continue; } - $list_of_domains = collect(explode(',', $app->fqdn))->filter(fn ($fqdn) => $fqdn !== ''); + $list_of_domains = collect(explode(',', $app->fqdn))->filter(fn($fqdn) => $fqdn !== ''); foreach ($list_of_domains as $domain) { if (str($domain)->endsWith('/')) { $domain = str($domain)->beforeLast('/'); @@ -1182,7 +1202,7 @@ function check_domain_usage(ServiceApplication|Application|null $resource = null }); $apps = Application::all(); foreach ($apps as $app) { - $list_of_domains = collect(explode(',', $app->fqdn))->filter(fn ($fqdn) => $fqdn !== ''); + $list_of_domains = collect(explode(',', $app->fqdn))->filter(fn($fqdn) => $fqdn !== ''); foreach ($list_of_domains as $domain) { if (str($domain)->endsWith('/')) { $domain = str($domain)->beforeLast('/'); @@ -1201,7 +1221,7 @@ function check_domain_usage(ServiceApplication|Application|null $resource = null } $apps = ServiceApplication::all(); foreach ($apps as $app) { - $list_of_domains = collect(explode(',', $app->fqdn))->filter(fn ($fqdn) => $fqdn !== ''); + $list_of_domains = collect(explode(',', $app->fqdn))->filter(fn($fqdn) => $fqdn !== ''); foreach ($list_of_domains as $domain) { if (str($domain)->endsWith('/')) { $domain = str($domain)->beforeLast('/'); @@ -1258,7 +1278,7 @@ function parseCommandsByLineForSudo(Collection $commands, Server $server): array $commands = $commands->map(function ($line) use ($server) { if (Str::startsWith($line, 'sudo mkdir -p')) { - return "$line && sudo chown -R $server->user:$server->user ".Str::after($line, 'sudo mkdir -p').' && sudo chmod -R o-rwx '.Str::after($line, 'sudo mkdir -p'); + return "$line && sudo chown -R $server->user:$server->user " . Str::after($line, 'sudo mkdir -p') . ' && sudo chmod -R o-rwx ' . Str::after($line, 'sudo mkdir -p'); } return $line; @@ -1290,7 +1310,7 @@ function parseLineForSudo(string $command, Server $server): string $command = "sudo $command"; } if (Str::startsWith($command, 'sudo mkdir -p')) { - $command = "$command && sudo chown -R $server->user:$server->user ".Str::after($command, 'sudo mkdir -p').' && sudo chmod -R o-rwx '.Str::after($command, 'sudo mkdir -p'); + $command = "$command && sudo chown -R $server->user:$server->user " . Str::after($command, 'sudo mkdir -p') . ' && sudo chmod -R o-rwx ' . Str::after($command, 'sudo mkdir -p'); } if (str($command)->contains('$(') || str($command)->contains('`')) { $command = str($command)->replace('$(', '$(sudo ')->replace('`', '`sudo ')->value(); @@ -1427,9 +1447,9 @@ function parseServiceVolumes($serviceVolumes, $resource, $topLevelVolumes, $pull return $volume; } if (get_class($resource) === \App\Models\Application::class) { - $dir = base_configuration_dir().'/applications/'.$resource->uuid; + $dir = base_configuration_dir() . '/applications/' . $resource->uuid; } else { - $dir = base_configuration_dir().'/services/'.$resource->service->uuid; + $dir = base_configuration_dir() . '/services/' . $resource->service->uuid; } if ($source->startsWith('.')) { @@ -1439,7 +1459,7 @@ function parseServiceVolumes($serviceVolumes, $resource, $topLevelVolumes, $pull $source = $source->replaceFirst('~', $dir); } if ($pull_request_id !== 0) { - $source = $source."-pr-$pull_request_id"; + $source = $source . "-pr-$pull_request_id"; } if (! $resource?->settings?->is_preserve_repository_enabled || $foundConfig?->is_based_on_git) { LocalFileVolume::updateOrCreate( @@ -1897,7 +1917,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal if (! $isDatabase) { if ($savedService->fqdn) { - data_set($savedService, 'fqdn', $savedService->fqdn.','.$fqdn); + data_set($savedService, 'fqdn', $savedService->fqdn . ',' . $fqdn); } else { data_set($savedService, 'fqdn', $fqdn); } @@ -1957,7 +1977,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal if (Str::lower($forService) === $serviceName) { $fqdn = generateFqdn($resource->server, $containerName); } else { - $fqdn = generateFqdn($resource->server, Str::lower($forService).'-'.$resource->uuid); + $fqdn = generateFqdn($resource->server, Str::lower($forService) . '-' . $resource->uuid); } if ($port) { $fqdn = "$fqdn:$port"; @@ -2299,7 +2319,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal $name = $volume->before(':'); $mount = $volume->after(':'); if ($name->startsWith('.') || $name->startsWith('~')) { - $dir = base_configuration_dir().'/applications/'.$resource->uuid; + $dir = base_configuration_dir() . '/applications/' . $resource->uuid; if ($name->startsWith('.')) { $name = $name->replaceFirst('.', $dir); } @@ -2307,12 +2327,12 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal $name = $name->replaceFirst('~', $dir); } if ($pull_request_id !== 0) { - $name = $name."-pr-$pull_request_id"; + $name = $name . "-pr-$pull_request_id"; } $volume = str("$name:$mount"); } else { if ($pull_request_id !== 0) { - $name = $name."-pr-$pull_request_id"; + $name = $name . "-pr-$pull_request_id"; $volume = str("$name:$mount"); if ($topLevelVolumes->has($name)) { $v = $topLevelVolumes->get($name); @@ -2351,7 +2371,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal $name = $volume->before(':'); $mount = $volume->after(':'); if ($pull_request_id !== 0) { - $name = $name."-pr-$pull_request_id"; + $name = $name . "-pr-$pull_request_id"; } $volume = str("$name:$mount"); } @@ -2362,7 +2382,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal $read_only = data_get($volume, 'read_only'); if ($source && $target) { if ((str($source)->startsWith('.') || str($source)->startsWith('~'))) { - $dir = base_configuration_dir().'/applications/'.$resource->uuid; + $dir = base_configuration_dir() . '/applications/' . $resource->uuid; if (str($source, '.')) { $source = str($source)->replaceFirst('.', $dir); } @@ -2370,21 +2390,21 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal $source = str($source)->replaceFirst('~', $dir); } if ($pull_request_id !== 0) { - $source = $source."-pr-$pull_request_id"; + $source = $source . "-pr-$pull_request_id"; } if ($read_only) { - data_set($volume, 'source', $source.':'.$target.':ro'); + data_set($volume, 'source', $source . ':' . $target . ':ro'); } else { - data_set($volume, 'source', $source.':'.$target); + data_set($volume, 'source', $source . ':' . $target); } } else { if ($pull_request_id !== 0) { - $source = $source."-pr-$pull_request_id"; + $source = $source . "-pr-$pull_request_id"; } if ($read_only) { - data_set($volume, 'source', $source.':'.$target.':ro'); + data_set($volume, 'source', $source . ':' . $target . ':ro'); } else { - data_set($volume, 'source', $source.':'.$target); + data_set($volume, 'source', $source . ':' . $target); } if (! str($source)->startsWith('/')) { if ($topLevelVolumes->has($source)) { @@ -2423,7 +2443,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal $name = $volume->before(':'); $mount = $volume->after(':'); if ($name->startsWith('.') || $name->startsWith('~')) { - $dir = base_configuration_dir().'/applications/'.$resource->uuid; + $dir = base_configuration_dir() . '/applications/' . $resource->uuid; if ($name->startsWith('.')) { $name = $name->replaceFirst('.', $dir); } @@ -2431,13 +2451,13 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal $name = $name->replaceFirst('~', $dir); } if ($pull_request_id !== 0) { - $name = $name."-pr-$pull_request_id"; + $name = $name . "-pr-$pull_request_id"; } $volume = str("$name:$mount"); } else { if ($pull_request_id !== 0) { $uuid = $resource->uuid; - $name = $uuid."-$name-pr-$pull_request_id"; + $name = $uuid . "-$name-pr-$pull_request_id"; $volume = str("$name:$mount"); if ($topLevelVolumes->has($name)) { $v = $topLevelVolumes->get($name); @@ -2456,7 +2476,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal } } else { $uuid = $resource->uuid; - $name = str($uuid."-$name"); + $name = str($uuid . "-$name"); $volume = str("$name:$mount"); if ($topLevelVolumes->has($name->value())) { $v = $topLevelVolumes->get($name->value()); @@ -2479,7 +2499,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal $name = $volume->before(':'); $mount = $volume->after(':'); if ($pull_request_id !== 0) { - $name = $name."-pr-$pull_request_id"; + $name = $name . "-pr-$pull_request_id"; } $volume = str("$name:$mount"); } @@ -2491,7 +2511,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal if ($source && $target) { $uuid = $resource->uuid; if ((str($source)->startsWith('.') || str($source)->startsWith('~') || str($source)->startsWith('/'))) { - $dir = base_configuration_dir().'/applications/'.$resource->uuid; + $dir = base_configuration_dir() . '/applications/' . $resource->uuid; if (str($source, '.')) { $source = str($source)->replaceFirst('.', $dir); } @@ -2499,20 +2519,20 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal $source = str($source)->replaceFirst('~', $dir); } if ($read_only) { - data_set($volume, 'source', $source.':'.$target.':ro'); + data_set($volume, 'source', $source . ':' . $target . ':ro'); } else { - data_set($volume, 'source', $source.':'.$target); + data_set($volume, 'source', $source . ':' . $target); } } else { if ($pull_request_id === 0) { - $source = $uuid."-$source"; + $source = $uuid . "-$source"; } else { - $source = $uuid."-$source-pr-$pull_request_id"; + $source = $uuid . "-$source-pr-$pull_request_id"; } if ($read_only) { - data_set($volume, 'source', $source.':'.$target.':ro'); + data_set($volume, 'source', $source . ':' . $target . ':ro'); } else { - data_set($volume, 'source', $source.':'.$target); + data_set($volume, 'source', $source . ':' . $target); } if (! str($source)->startsWith('/')) { if ($topLevelVolumes->has($source)) { @@ -2547,7 +2567,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal if ($pull_request_id !== 0 && count($serviceDependencies) > 0) { $serviceDependencies = $serviceDependencies->map(function ($dependency) use ($pull_request_id) { - return $dependency."-pr-$pull_request_id"; + return $dependency . "-pr-$pull_request_id"; }); data_set($service, 'depends_on', $serviceDependencies->toArray()); } @@ -2720,7 +2740,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal if (Str::lower($forService) === $serviceName) { $fqdn = generateFqdn($server, $containerName); } else { - $fqdn = generateFqdn($server, Str::lower($forService).'-'.$resource->uuid); + $fqdn = generateFqdn($server, Str::lower($forService) . '-' . $resource->uuid); } if ($port) { $fqdn = "$fqdn:$port"; @@ -2924,7 +2944,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal }); if ($pull_request_id !== 0) { $services->each(function ($service, $serviceName) use ($pull_request_id, $services) { - $services[$serviceName."-pr-$pull_request_id"] = $service; + $services[$serviceName . "-pr-$pull_request_id"] = $service; data_forget($services, $serviceName); }); } @@ -3352,22 +3372,22 @@ function newParser(Application|Service $resource, int $pull_request_id = 0, ?int } if ($type->value() === 'bind') { if ($source->value() === '/var/run/docker.sock') { - $volume = $source->value().':'.$target->value(); + $volume = $source->value() . ':' . $target->value(); } elseif ($source->value() === '/tmp' || $source->value() === '/tmp/') { - $volume = $source->value().':'.$target->value(); + $volume = $source->value() . ':' . $target->value(); } else { if ((int) $resource->compose_parsing_version >= 4) { if ($isApplication) { - $mainDirectory = str(base_configuration_dir().'/applications/'.$uuid); + $mainDirectory = str(base_configuration_dir() . '/applications/' . $uuid); } elseif ($isService) { - $mainDirectory = str(base_configuration_dir().'/services/'.$uuid); + $mainDirectory = str(base_configuration_dir() . '/services/' . $uuid); } } else { - $mainDirectory = str(base_configuration_dir().'/applications/'.$uuid); + $mainDirectory = str(base_configuration_dir() . '/applications/' . $uuid); } $source = replaceLocalSource($source, $mainDirectory); if ($isApplication && $isPullRequest) { - $source = $source."-pr-$pullRequestId"; + $source = $source . "-pr-$pullRequestId"; } LocalFileVolume::updateOrCreate( [ @@ -3387,12 +3407,12 @@ function newParser(Application|Service $resource, int $pull_request_id = 0, ?int if (isDev()) { if ((int) $resource->compose_parsing_version >= 4) { if ($isApplication) { - $source = $source->replace($mainDirectory, '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/applications/'.$uuid); + $source = $source->replace($mainDirectory, '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/applications/' . $uuid); } elseif ($isService) { - $source = $source->replace($mainDirectory, '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/services/'.$uuid); + $source = $source->replace($mainDirectory, '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/services/' . $uuid); } } else { - $source = $source->replace($mainDirectory, '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/applications/'.$uuid); + $source = $source->replace($mainDirectory, '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/applications/' . $uuid); } } $volume = "$source:$target"; @@ -4061,7 +4081,7 @@ function isEmailRateLimited(string $limiterKey, int $decaySeconds = 3600, ?calla $limiterKey, $maxAttempts = 0, function () use (&$rateLimited, &$limiterKey, $callbackOnSuccess) { - isDev() && loggy('Rate limit not reached for '.$limiterKey); + isDev() && loggy('Rate limit not reached for ' . $limiterKey); $rateLimited = false; if ($callbackOnSuccess) { @@ -4071,7 +4091,7 @@ function isEmailRateLimited(string $limiterKey, int $decaySeconds = 3600, ?calla $decaySeconds, ); if (! $executed) { - isDev() && loggy('Rate limit reached for '.$limiterKey.'. Rate limiter will be disabled for '.$decaySeconds.' seconds.'); + isDev() && loggy('Rate limit reached for ' . $limiterKey . '. Rate limiter will be disabled for ' . $decaySeconds . ' seconds.'); $rateLimited = true; } From 319c3023dcf4e47f1d7919287b3a91393af45178 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Mon, 2 Dec 2024 22:49:55 +0100 Subject: [PATCH 35/37] fix --- app/Actions/Docker/GetContainersStatus.php | 8 +- app/Actions/Server/ServerCheck.php | 4 +- .../Controllers/Api/ServicesController.php | 4 +- app/Jobs/PushServerUpdateJob.php | 2 +- app/Models/BaseModel.php | 6 +- app/Models/StandalonePostgresql.php | 16 +-- app/Models/Team.php | 2 +- bootstrap/helpers/shared.php | 136 +++++++++--------- 8 files changed, 90 insertions(+), 88 deletions(-) diff --git a/app/Actions/Docker/GetContainersStatus.php b/app/Actions/Docker/GetContainersStatus.php index e9f577e06..706356930 100644 --- a/app/Actions/Docker/GetContainersStatus.php +++ b/app/Actions/Docker/GetContainersStatus.php @@ -260,7 +260,7 @@ class GetContainersStatus $environmentName = data_get($service, 'environment.name'); if ($projectUuid && $serviceUuid && $environmentName) { - $url = base_url() . '/project/' . $projectUuid . '/' . $environmentName . '/service/' . $serviceUuid; + $url = base_url().'/project/'.$projectUuid.'/'.$environmentName.'/service/'.$serviceUuid; } else { $url = null; } @@ -286,7 +286,7 @@ class GetContainersStatus $environment = data_get($application, 'environment.name'); if ($projectUuid && $applicationUuid && $environment) { - $url = base_url() . '/project/' . $projectUuid . '/' . $environment . '/application/' . $applicationUuid; + $url = base_url().'/project/'.$projectUuid.'/'.$environment.'/application/'.$applicationUuid; } else { $url = null; } @@ -311,7 +311,7 @@ class GetContainersStatus $applicationUuid = data_get($preview, 'application.uuid'); if ($projectUuid && $applicationUuid && $environmentName) { - $url = base_url() . '/project/' . $projectUuid . '/' . $environmentName . '/application/' . $applicationUuid; + $url = base_url().'/project/'.$projectUuid.'/'.$environmentName.'/application/'.$applicationUuid; } else { $url = null; } @@ -336,7 +336,7 @@ class GetContainersStatus $databaseUuid = data_get($database, 'uuid'); if ($projectUuid && $databaseUuid && $environmentName) { - $url = base_url() . '/project/' . $projectUuid . '/' . $environmentName . '/database/' . $databaseUuid; + $url = base_url().'/project/'.$projectUuid.'/'.$environmentName.'/database/'.$databaseUuid; } else { $url = null; } diff --git a/app/Actions/Server/ServerCheck.php b/app/Actions/Server/ServerCheck.php index 35b4996b4..75b8501f3 100644 --- a/app/Actions/Server/ServerCheck.php +++ b/app/Actions/Server/ServerCheck.php @@ -213,7 +213,7 @@ class ServerCheck if ($isPublic) { $foundTcpProxy = $this->containers->filter(function ($value, $key) use ($uuid) { if ($this->isSentinel) { - return data_get($value, 'name') === $uuid . '-proxy'; + return data_get($value, 'name') === $uuid.'-proxy'; } else { if ($this->server->isSwarm()) { @@ -245,7 +245,7 @@ class ServerCheck if ($isPublic) { $foundTcpProxy = $this->containers->filter(function ($value, $key) use ($uuid) { if ($this->isSentinel) { - return data_get($value, 'name') === $uuid . '-proxy'; + return data_get($value, 'name') === $uuid.'-proxy'; } else { if ($this->server->isSwarm()) { return data_get($value, 'Spec.Name') === "coolify-proxy_$uuid"; diff --git a/app/Http/Controllers/Api/ServicesController.php b/app/Http/Controllers/Api/ServicesController.php index abf8a24af..bf90322e2 100644 --- a/app/Http/Controllers/Api/ServicesController.php +++ b/app/Http/Controllers/Api/ServicesController.php @@ -308,7 +308,7 @@ class ServicesController extends Controller } if ($oneClickService) { $service_payload = [ - 'name' => "$oneClickServiceName-" . str()->random(10), + 'name' => "$oneClickServiceName-".str()->random(10), 'docker_compose_raw' => base64_decode($oneClickService), 'environment_id' => $environment->id, 'service_type' => $oneClickServiceName, @@ -320,7 +320,7 @@ class ServicesController extends Controller data_set($service_payload, 'connect_to_docker_network', true); } $service = Service::create($service_payload); - $service->name = "$oneClickServiceName-" . $service->uuid; + $service->name = "$oneClickServiceName-".$service->uuid; $service->save(); if ($oneClickDotEnvs?->count() > 0) { $oneClickDotEnvs->each(function ($value) use ($service) { diff --git a/app/Jobs/PushServerUpdateJob.php b/app/Jobs/PushServerUpdateJob.php index fa146ff96..e9fcb2f37 100644 --- a/app/Jobs/PushServerUpdateJob.php +++ b/app/Jobs/PushServerUpdateJob.php @@ -280,7 +280,7 @@ class PushServerUpdateJob implements ShouldBeEncrypted, ShouldQueue })->first(); if (! $tcpProxyContainerFound) { StartDatabaseProxy::dispatch($database); - $this->server->team?->notify(new ContainerRestarted("TCP Proxy for database", $this->server)); + $this->server->team?->notify(new ContainerRestarted('TCP Proxy for database', $this->server)); } else { } } diff --git a/app/Models/BaseModel.php b/app/Models/BaseModel.php index 500c34fb6..79801987b 100644 --- a/app/Models/BaseModel.php +++ b/app/Models/BaseModel.php @@ -19,16 +19,18 @@ abstract class BaseModel extends Model } }); } + public function name(): Attribute { return new Attribute( - get: fn() => sanitize_string($this->getRawOriginal('name')), + get: fn () => sanitize_string($this->getRawOriginal('name')), ); } + public function image(): Attribute { return new Attribute( - get: fn() => sanitize_string($this->getRawOriginal('image')), + get: fn () => sanitize_string($this->getRawOriginal('image')), ); } } diff --git a/app/Models/StandalonePostgresql.php b/app/Models/StandalonePostgresql.php index 99cc8a55b..4a457a6cf 100644 --- a/app/Models/StandalonePostgresql.php +++ b/app/Models/StandalonePostgresql.php @@ -25,7 +25,7 @@ class StandalonePostgresql extends BaseModel { static::created(function ($database) { LocalPersistentVolume::create([ - 'name' => 'postgres-data-' . $database->uuid, + 'name' => 'postgres-data-'.$database->uuid, 'mount_path' => '/var/lib/postgresql/data', 'host_path' => null, 'resource_id' => $database->id, @@ -48,7 +48,7 @@ class StandalonePostgresql extends BaseModel public function workdir() { - return database_configuration_dir() . "/{$this->uuid}"; + return database_configuration_dir()."/{$this->uuid}"; } protected function serverStatus(): Attribute @@ -65,7 +65,7 @@ class StandalonePostgresql extends BaseModel $server = data_get($this, 'destination.server'); $workdir = $this->workdir(); if (str($workdir)->endsWith($this->uuid)) { - instant_remote_process(['rm -rf ' . $this->workdir()], $server, false); + instant_remote_process(['rm -rf '.$this->workdir()], $server, false); } } @@ -82,7 +82,7 @@ class StandalonePostgresql extends BaseModel public function isConfigurationChanged(bool $save = false) { - $newConfigHash = $this->image . $this->ports_mappings . $this->postgres_initdb_args . $this->postgres_host_auth_method; + $newConfigHash = $this->image.$this->ports_mappings.$this->postgres_initdb_args.$this->postgres_host_auth_method; $newConfigHash .= json_encode($this->environment_variables()->get('value')->sort()); $newConfigHash = md5($newConfigHash); $oldConfigHash = data_get($this, 'config_hash'); @@ -186,14 +186,14 @@ class StandalonePostgresql extends BaseModel public function portsMappings(): Attribute { return Attribute::make( - set: fn($value) => $value === '' ? null : $value, + set: fn ($value) => $value === '' ? null : $value, ); } public function portsMappingsArray(): Attribute { return Attribute::make( - get: fn() => is_null($this->ports_mappings) + get: fn () => is_null($this->ports_mappings) ? [] : explode(',', $this->ports_mappings), @@ -208,7 +208,7 @@ class StandalonePostgresql extends BaseModel public function databaseType(): Attribute { return new Attribute( - get: fn() => $this->type(), + get: fn () => $this->type(), ); } @@ -220,7 +220,7 @@ class StandalonePostgresql extends BaseModel protected function internalDbUrl(): Attribute { return new Attribute( - get: fn() => "postgres://{$this->postgres_user}:{$this->postgres_password}@{$this->uuid}:5432/{$this->postgres_db}", + get: fn () => "postgres://{$this->postgres_user}:{$this->postgres_password}@{$this->uuid}:5432/{$this->postgres_db}", ); } diff --git a/app/Models/Team.php b/app/Models/Team.php index 76d89fb8e..6ba044349 100644 --- a/app/Models/Team.php +++ b/app/Models/Team.php @@ -130,7 +130,7 @@ class Team extends Model implements SendsDiscord, SendsEmail public function name(): Attribute { return new Attribute( - get: fn() => sanitize_string($this->getRawOriginal('name')), + get: fn () => sanitize_string($this->getRawOriginal('name')), ); } diff --git a/bootstrap/helpers/shared.php b/bootstrap/helpers/shared.php index ddc578400..d64b5ab6e 100644 --- a/bootstrap/helpers/shared.php +++ b/bootstrap/helpers/shared.php @@ -67,27 +67,27 @@ function base_configuration_dir(): string } function application_configuration_dir(): string { - return base_configuration_dir() . '/applications'; + return base_configuration_dir().'/applications'; } function service_configuration_dir(): string { - return base_configuration_dir() . '/services'; + return base_configuration_dir().'/services'; } function database_configuration_dir(): string { - return base_configuration_dir() . '/databases'; + return base_configuration_dir().'/databases'; } function database_proxy_dir($uuid): string { - return base_configuration_dir() . "/databases/$uuid/proxy"; + return base_configuration_dir()."/databases/$uuid/proxy"; } function backup_dir(): string { - return base_configuration_dir() . '/backups'; + return base_configuration_dir().'/backups'; } function metrics_dir(): string { - return base_configuration_dir() . '/metrics'; + return base_configuration_dir().'/metrics'; } function sanitize_string(string $input): string @@ -142,8 +142,8 @@ function refreshSession(?Team $team = null): void $team = User::find(Auth::id())->teams->first(); } } - Cache::forget('team:' . Auth::id()); - Cache::remember('team:' . Auth::id(), 3600, function () use ($team) { + Cache::forget('team:'.Auth::id()); + Cache::remember('team:'.Auth::id(), 3600, function () use ($team) { return $team; }); session(['currentTeam' => $team]); @@ -175,7 +175,7 @@ function handleError(?Throwable $error = null, ?Livewire\Component $livewire = n $message = null; } if ($customErrorMessage) { - $message = $customErrorMessage . ' ' . $message; + $message = $customErrorMessage.' '.$message; } if (isset($livewire)) { @@ -430,7 +430,7 @@ function send_user_an_email(MailMessage $mail, string $email, ?string $cc = null Mail::send( [], [], - fn(Message $message) => $message + fn (Message $message) => $message ->to($email) ->replyTo($email) ->cc($cc) @@ -441,7 +441,7 @@ function send_user_an_email(MailMessage $mail, string $email, ?string $cc = null Mail::send( [], [], - fn(Message $message) => $message + fn (Message $message) => $message ->to($email) ->subject($mail->subject) ->html((string) $mail->render()) @@ -677,19 +677,19 @@ function queryResourcesByUuid(string $uuid) function generateTagDeployWebhook($tag_name) { $baseUrl = base_url(); - $api = Url::fromString($baseUrl) . '/api/v1'; + $api = Url::fromString($baseUrl).'/api/v1'; $endpoint = "/deploy?tag=$tag_name"; - return $api . $endpoint; + return $api.$endpoint; } function generateDeployWebhook($resource) { $baseUrl = base_url(); - $api = Url::fromString($baseUrl) . '/api/v1'; + $api = Url::fromString($baseUrl).'/api/v1'; $endpoint = '/deploy'; $uuid = data_get($resource, 'uuid'); - return $api . $endpoint . "?uuid=$uuid&force=false"; + return $api.$endpoint."?uuid=$uuid&force=false"; } function generateGitManualWebhook($resource, $type) { @@ -699,7 +699,7 @@ function generateGitManualWebhook($resource, $type) if ($resource->getMorphClass() === \App\Models\Application::class) { $baseUrl = base_url(); - return Url::fromString($baseUrl) . "/webhooks/source/$type/events/manual"; + return Url::fromString($baseUrl)."/webhooks/source/$type/events/manual"; } return null; @@ -1067,7 +1067,7 @@ function validate_dns_entry(string $fqdn, Server $server) $query = new DNSQuery($dns_server); $results = $query->query($host, $type); if ($results === false || $query->hasError()) { - ray('Error: ' . $query->getLasterror()); + ray('Error: '.$query->getLasterror()); } else { foreach ($results as $result) { if ($result->getType() == $type) { @@ -1077,7 +1077,7 @@ function validate_dns_entry(string $fqdn, Server $server) break; } if ($result->getData() === $ip) { - ray($host . ' has IP address ' . $result->getData()); + ray($host.' has IP address '.$result->getData()); ray($result->getString()); $found_matching_ip = true; break; @@ -1125,15 +1125,15 @@ function checkIfDomainIsAlreadyUsed(Collection|array $domains, ?string $teamId = $applications = Application::ownedByCurrentTeamAPI($teamId)->get(['fqdn', 'uuid']); $serviceApplications = ServiceApplication::ownedByCurrentTeamAPI($teamId)->get(['fqdn', 'uuid']); if ($uuid) { - $applications = $applications->filter(fn($app) => $app->uuid !== $uuid); - $serviceApplications = $serviceApplications->filter(fn($app) => $app->uuid !== $uuid); + $applications = $applications->filter(fn ($app) => $app->uuid !== $uuid); + $serviceApplications = $serviceApplications->filter(fn ($app) => $app->uuid !== $uuid); } $domainFound = false; foreach ($applications as $app) { if (is_null($app->fqdn)) { continue; } - $list_of_domains = collect(explode(',', $app->fqdn))->filter(fn($fqdn) => $fqdn !== ''); + $list_of_domains = collect(explode(',', $app->fqdn))->filter(fn ($fqdn) => $fqdn !== ''); foreach ($list_of_domains as $domain) { if (str($domain)->endsWith('/')) { $domain = str($domain)->beforeLast('/'); @@ -1152,7 +1152,7 @@ function checkIfDomainIsAlreadyUsed(Collection|array $domains, ?string $teamId = if (str($app->fqdn)->isEmpty()) { continue; } - $list_of_domains = collect(explode(',', $app->fqdn))->filter(fn($fqdn) => $fqdn !== ''); + $list_of_domains = collect(explode(',', $app->fqdn))->filter(fn ($fqdn) => $fqdn !== ''); foreach ($list_of_domains as $domain) { if (str($domain)->endsWith('/')) { $domain = str($domain)->beforeLast('/'); @@ -1202,7 +1202,7 @@ function check_domain_usage(ServiceApplication|Application|null $resource = null }); $apps = Application::all(); foreach ($apps as $app) { - $list_of_domains = collect(explode(',', $app->fqdn))->filter(fn($fqdn) => $fqdn !== ''); + $list_of_domains = collect(explode(',', $app->fqdn))->filter(fn ($fqdn) => $fqdn !== ''); foreach ($list_of_domains as $domain) { if (str($domain)->endsWith('/')) { $domain = str($domain)->beforeLast('/'); @@ -1221,7 +1221,7 @@ function check_domain_usage(ServiceApplication|Application|null $resource = null } $apps = ServiceApplication::all(); foreach ($apps as $app) { - $list_of_domains = collect(explode(',', $app->fqdn))->filter(fn($fqdn) => $fqdn !== ''); + $list_of_domains = collect(explode(',', $app->fqdn))->filter(fn ($fqdn) => $fqdn !== ''); foreach ($list_of_domains as $domain) { if (str($domain)->endsWith('/')) { $domain = str($domain)->beforeLast('/'); @@ -1278,7 +1278,7 @@ function parseCommandsByLineForSudo(Collection $commands, Server $server): array $commands = $commands->map(function ($line) use ($server) { if (Str::startsWith($line, 'sudo mkdir -p')) { - return "$line && sudo chown -R $server->user:$server->user " . Str::after($line, 'sudo mkdir -p') . ' && sudo chmod -R o-rwx ' . Str::after($line, 'sudo mkdir -p'); + return "$line && sudo chown -R $server->user:$server->user ".Str::after($line, 'sudo mkdir -p').' && sudo chmod -R o-rwx '.Str::after($line, 'sudo mkdir -p'); } return $line; @@ -1310,7 +1310,7 @@ function parseLineForSudo(string $command, Server $server): string $command = "sudo $command"; } if (Str::startsWith($command, 'sudo mkdir -p')) { - $command = "$command && sudo chown -R $server->user:$server->user " . Str::after($command, 'sudo mkdir -p') . ' && sudo chmod -R o-rwx ' . Str::after($command, 'sudo mkdir -p'); + $command = "$command && sudo chown -R $server->user:$server->user ".Str::after($command, 'sudo mkdir -p').' && sudo chmod -R o-rwx '.Str::after($command, 'sudo mkdir -p'); } if (str($command)->contains('$(') || str($command)->contains('`')) { $command = str($command)->replace('$(', '$(sudo ')->replace('`', '`sudo ')->value(); @@ -1447,9 +1447,9 @@ function parseServiceVolumes($serviceVolumes, $resource, $topLevelVolumes, $pull return $volume; } if (get_class($resource) === \App\Models\Application::class) { - $dir = base_configuration_dir() . '/applications/' . $resource->uuid; + $dir = base_configuration_dir().'/applications/'.$resource->uuid; } else { - $dir = base_configuration_dir() . '/services/' . $resource->service->uuid; + $dir = base_configuration_dir().'/services/'.$resource->service->uuid; } if ($source->startsWith('.')) { @@ -1459,7 +1459,7 @@ function parseServiceVolumes($serviceVolumes, $resource, $topLevelVolumes, $pull $source = $source->replaceFirst('~', $dir); } if ($pull_request_id !== 0) { - $source = $source . "-pr-$pull_request_id"; + $source = $source."-pr-$pull_request_id"; } if (! $resource?->settings?->is_preserve_repository_enabled || $foundConfig?->is_based_on_git) { LocalFileVolume::updateOrCreate( @@ -1917,7 +1917,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal if (! $isDatabase) { if ($savedService->fqdn) { - data_set($savedService, 'fqdn', $savedService->fqdn . ',' . $fqdn); + data_set($savedService, 'fqdn', $savedService->fqdn.','.$fqdn); } else { data_set($savedService, 'fqdn', $fqdn); } @@ -1977,7 +1977,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal if (Str::lower($forService) === $serviceName) { $fqdn = generateFqdn($resource->server, $containerName); } else { - $fqdn = generateFqdn($resource->server, Str::lower($forService) . '-' . $resource->uuid); + $fqdn = generateFqdn($resource->server, Str::lower($forService).'-'.$resource->uuid); } if ($port) { $fqdn = "$fqdn:$port"; @@ -2319,7 +2319,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal $name = $volume->before(':'); $mount = $volume->after(':'); if ($name->startsWith('.') || $name->startsWith('~')) { - $dir = base_configuration_dir() . '/applications/' . $resource->uuid; + $dir = base_configuration_dir().'/applications/'.$resource->uuid; if ($name->startsWith('.')) { $name = $name->replaceFirst('.', $dir); } @@ -2327,12 +2327,12 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal $name = $name->replaceFirst('~', $dir); } if ($pull_request_id !== 0) { - $name = $name . "-pr-$pull_request_id"; + $name = $name."-pr-$pull_request_id"; } $volume = str("$name:$mount"); } else { if ($pull_request_id !== 0) { - $name = $name . "-pr-$pull_request_id"; + $name = $name."-pr-$pull_request_id"; $volume = str("$name:$mount"); if ($topLevelVolumes->has($name)) { $v = $topLevelVolumes->get($name); @@ -2371,7 +2371,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal $name = $volume->before(':'); $mount = $volume->after(':'); if ($pull_request_id !== 0) { - $name = $name . "-pr-$pull_request_id"; + $name = $name."-pr-$pull_request_id"; } $volume = str("$name:$mount"); } @@ -2382,7 +2382,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal $read_only = data_get($volume, 'read_only'); if ($source && $target) { if ((str($source)->startsWith('.') || str($source)->startsWith('~'))) { - $dir = base_configuration_dir() . '/applications/' . $resource->uuid; + $dir = base_configuration_dir().'/applications/'.$resource->uuid; if (str($source, '.')) { $source = str($source)->replaceFirst('.', $dir); } @@ -2390,21 +2390,21 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal $source = str($source)->replaceFirst('~', $dir); } if ($pull_request_id !== 0) { - $source = $source . "-pr-$pull_request_id"; + $source = $source."-pr-$pull_request_id"; } if ($read_only) { - data_set($volume, 'source', $source . ':' . $target . ':ro'); + data_set($volume, 'source', $source.':'.$target.':ro'); } else { - data_set($volume, 'source', $source . ':' . $target); + data_set($volume, 'source', $source.':'.$target); } } else { if ($pull_request_id !== 0) { - $source = $source . "-pr-$pull_request_id"; + $source = $source."-pr-$pull_request_id"; } if ($read_only) { - data_set($volume, 'source', $source . ':' . $target . ':ro'); + data_set($volume, 'source', $source.':'.$target.':ro'); } else { - data_set($volume, 'source', $source . ':' . $target); + data_set($volume, 'source', $source.':'.$target); } if (! str($source)->startsWith('/')) { if ($topLevelVolumes->has($source)) { @@ -2443,7 +2443,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal $name = $volume->before(':'); $mount = $volume->after(':'); if ($name->startsWith('.') || $name->startsWith('~')) { - $dir = base_configuration_dir() . '/applications/' . $resource->uuid; + $dir = base_configuration_dir().'/applications/'.$resource->uuid; if ($name->startsWith('.')) { $name = $name->replaceFirst('.', $dir); } @@ -2451,13 +2451,13 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal $name = $name->replaceFirst('~', $dir); } if ($pull_request_id !== 0) { - $name = $name . "-pr-$pull_request_id"; + $name = $name."-pr-$pull_request_id"; } $volume = str("$name:$mount"); } else { if ($pull_request_id !== 0) { $uuid = $resource->uuid; - $name = $uuid . "-$name-pr-$pull_request_id"; + $name = $uuid."-$name-pr-$pull_request_id"; $volume = str("$name:$mount"); if ($topLevelVolumes->has($name)) { $v = $topLevelVolumes->get($name); @@ -2476,7 +2476,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal } } else { $uuid = $resource->uuid; - $name = str($uuid . "-$name"); + $name = str($uuid."-$name"); $volume = str("$name:$mount"); if ($topLevelVolumes->has($name->value())) { $v = $topLevelVolumes->get($name->value()); @@ -2499,7 +2499,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal $name = $volume->before(':'); $mount = $volume->after(':'); if ($pull_request_id !== 0) { - $name = $name . "-pr-$pull_request_id"; + $name = $name."-pr-$pull_request_id"; } $volume = str("$name:$mount"); } @@ -2511,7 +2511,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal if ($source && $target) { $uuid = $resource->uuid; if ((str($source)->startsWith('.') || str($source)->startsWith('~') || str($source)->startsWith('/'))) { - $dir = base_configuration_dir() . '/applications/' . $resource->uuid; + $dir = base_configuration_dir().'/applications/'.$resource->uuid; if (str($source, '.')) { $source = str($source)->replaceFirst('.', $dir); } @@ -2519,20 +2519,20 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal $source = str($source)->replaceFirst('~', $dir); } if ($read_only) { - data_set($volume, 'source', $source . ':' . $target . ':ro'); + data_set($volume, 'source', $source.':'.$target.':ro'); } else { - data_set($volume, 'source', $source . ':' . $target); + data_set($volume, 'source', $source.':'.$target); } } else { if ($pull_request_id === 0) { - $source = $uuid . "-$source"; + $source = $uuid."-$source"; } else { - $source = $uuid . "-$source-pr-$pull_request_id"; + $source = $uuid."-$source-pr-$pull_request_id"; } if ($read_only) { - data_set($volume, 'source', $source . ':' . $target . ':ro'); + data_set($volume, 'source', $source.':'.$target.':ro'); } else { - data_set($volume, 'source', $source . ':' . $target); + data_set($volume, 'source', $source.':'.$target); } if (! str($source)->startsWith('/')) { if ($topLevelVolumes->has($source)) { @@ -2567,7 +2567,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal if ($pull_request_id !== 0 && count($serviceDependencies) > 0) { $serviceDependencies = $serviceDependencies->map(function ($dependency) use ($pull_request_id) { - return $dependency . "-pr-$pull_request_id"; + return $dependency."-pr-$pull_request_id"; }); data_set($service, 'depends_on', $serviceDependencies->toArray()); } @@ -2740,7 +2740,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal if (Str::lower($forService) === $serviceName) { $fqdn = generateFqdn($server, $containerName); } else { - $fqdn = generateFqdn($server, Str::lower($forService) . '-' . $resource->uuid); + $fqdn = generateFqdn($server, Str::lower($forService).'-'.$resource->uuid); } if ($port) { $fqdn = "$fqdn:$port"; @@ -2944,7 +2944,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal }); if ($pull_request_id !== 0) { $services->each(function ($service, $serviceName) use ($pull_request_id, $services) { - $services[$serviceName . "-pr-$pull_request_id"] = $service; + $services[$serviceName."-pr-$pull_request_id"] = $service; data_forget($services, $serviceName); }); } @@ -3372,22 +3372,22 @@ function newParser(Application|Service $resource, int $pull_request_id = 0, ?int } if ($type->value() === 'bind') { if ($source->value() === '/var/run/docker.sock') { - $volume = $source->value() . ':' . $target->value(); + $volume = $source->value().':'.$target->value(); } elseif ($source->value() === '/tmp' || $source->value() === '/tmp/') { - $volume = $source->value() . ':' . $target->value(); + $volume = $source->value().':'.$target->value(); } else { if ((int) $resource->compose_parsing_version >= 4) { if ($isApplication) { - $mainDirectory = str(base_configuration_dir() . '/applications/' . $uuid); + $mainDirectory = str(base_configuration_dir().'/applications/'.$uuid); } elseif ($isService) { - $mainDirectory = str(base_configuration_dir() . '/services/' . $uuid); + $mainDirectory = str(base_configuration_dir().'/services/'.$uuid); } } else { - $mainDirectory = str(base_configuration_dir() . '/applications/' . $uuid); + $mainDirectory = str(base_configuration_dir().'/applications/'.$uuid); } $source = replaceLocalSource($source, $mainDirectory); if ($isApplication && $isPullRequest) { - $source = $source . "-pr-$pullRequestId"; + $source = $source."-pr-$pullRequestId"; } LocalFileVolume::updateOrCreate( [ @@ -3407,12 +3407,12 @@ function newParser(Application|Service $resource, int $pull_request_id = 0, ?int if (isDev()) { if ((int) $resource->compose_parsing_version >= 4) { if ($isApplication) { - $source = $source->replace($mainDirectory, '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/applications/' . $uuid); + $source = $source->replace($mainDirectory, '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/applications/'.$uuid); } elseif ($isService) { - $source = $source->replace($mainDirectory, '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/services/' . $uuid); + $source = $source->replace($mainDirectory, '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/services/'.$uuid); } } else { - $source = $source->replace($mainDirectory, '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/applications/' . $uuid); + $source = $source->replace($mainDirectory, '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/applications/'.$uuid); } } $volume = "$source:$target"; @@ -4081,7 +4081,7 @@ function isEmailRateLimited(string $limiterKey, int $decaySeconds = 3600, ?calla $limiterKey, $maxAttempts = 0, function () use (&$rateLimited, &$limiterKey, $callbackOnSuccess) { - isDev() && loggy('Rate limit not reached for ' . $limiterKey); + isDev() && loggy('Rate limit not reached for '.$limiterKey); $rateLimited = false; if ($callbackOnSuccess) { @@ -4091,7 +4091,7 @@ function isEmailRateLimited(string $limiterKey, int $decaySeconds = 3600, ?calla $decaySeconds, ); if (! $executed) { - isDev() && loggy('Rate limit reached for ' . $limiterKey . '. Rate limiter will be disabled for ' . $decaySeconds . ' seconds.'); + isDev() && loggy('Rate limit reached for '.$limiterKey.'. Rate limiter will be disabled for '.$decaySeconds.' seconds.'); $rateLimited = true; } From f7ef339ec3f6e5568dbad3fb7220affea58a3e90 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 3 Dec 2024 12:21:09 +0100 Subject: [PATCH 36/37] Improve notification message for TCP Proxy container restart to include database name --- app/Jobs/PushServerUpdateJob.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Jobs/PushServerUpdateJob.php b/app/Jobs/PushServerUpdateJob.php index e9fcb2f37..24f8d1e6b 100644 --- a/app/Jobs/PushServerUpdateJob.php +++ b/app/Jobs/PushServerUpdateJob.php @@ -280,7 +280,7 @@ class PushServerUpdateJob implements ShouldBeEncrypted, ShouldQueue })->first(); if (! $tcpProxyContainerFound) { StartDatabaseProxy::dispatch($database); - $this->server->team?->notify(new ContainerRestarted('TCP Proxy for database', $this->server)); + $this->server->team?->notify(new ContainerRestarted("TCP Proxy for {$database->name}", $this->server)); } else { } } From 669293afc1b3f7190a43b279fb62a5118bb9039d Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 3 Dec 2024 12:22:27 +0100 Subject: [PATCH 37/37] disable success notifications for now --- app/Jobs/ApplicationDeploymentJob.php | 2 +- app/Jobs/DatabaseBackupJob.php | 2 +- app/Models/Server.php | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index 6a66bb56d..41909fa30 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -2400,7 +2400,7 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf"); if (! $this->only_this_server) { $this->deploy_to_additional_destinations(); } - $this->application->environment->project->team?->notify(new DeploymentSuccess($this->application, $this->deployment_uuid, $this->preview)); + //$this->application->environment->project->team?->notify(new DeploymentSuccess($this->application, $this->deployment_uuid, $this->preview)); } } diff --git a/app/Jobs/DatabaseBackupJob.php b/app/Jobs/DatabaseBackupJob.php index 89674b255..ee702202f 100644 --- a/app/Jobs/DatabaseBackupJob.php +++ b/app/Jobs/DatabaseBackupJob.php @@ -306,7 +306,7 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue if ($this->backup->save_s3) { $this->upload_to_s3(); } - $this->team?->notify(new BackupSuccess($this->backup, $this->database, $database)); + //$this->team?->notify(new BackupSuccess($this->backup, $this->database, $database)); $this->backup_log->update([ 'status' => 'success', 'message' => $this->backup_output, diff --git a/app/Models/Server.php b/app/Models/Server.php index 27c2b9b99..83b91b254 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -1039,7 +1039,7 @@ $schema://$host { $this->unreachable_notification_sent = false; $this->save(); $this->refresh(); - $this->team->notify(new Reachable($this)); + // $this->team->notify(new Reachable($this)); } public function sendUnreachableNotification() @@ -1047,7 +1047,7 @@ $schema://$host { $this->unreachable_notification_sent = true; $this->save(); $this->refresh(); - $this->team->notify(new Unreachable($this)); + // $this->team->notify(new Unreachable($this)); } public function validateConnection(bool $justCheckingNewKey = false)