Merge branch 'next' into feat/add-http-basic-auth

This commit is contained in:
Andras Bacsai
2025-04-22 21:18:43 +02:00
committed by GitHub
31 changed files with 334 additions and 334 deletions

View File

@@ -6,17 +6,18 @@ All notable changes to this project will be documented in this file.
### 🐛 Bug Fixes ### 🐛 Bug Fixes
- *(parser)* Transform associative array labels into key=value format for better compatibility - *(navbar)* Update error message link to use route for environment variables navigation
- *(redis)* Update username and password input handling to clarify database sync requirements - Unsend template
- *(source)* Update connected source display to handle cases with no source connected - Replace ports with expose
- *(templates)* Update Unsend compose configuration for improved service integration
### 🚜 Refactor ### 🚜 Refactor
- *(source)* Conditionally display connected source and change source options based on private key presence - *(jobs)* Update WithoutOverlapping middleware to use expireAfter for better queue management
### ⚙️ Miscellaneous Tasks ### 📚 Documentation
- *(versions)* Bump coolify version to 4.0.0-beta.409 in configuration files - Update changelog
## [4.0.0-beta.408] - 2025-04-14 ## [4.0.0-beta.408] - 2025-04-14
@@ -24,6 +25,8 @@ All notable changes to this project will be documented in this file.
- *(OpenApi)* Enhance OpenAPI specifications by adding UUID parameters for application, project, and service updates; improve deployment listing with pagination parameters; update command signature for OpenApi generation - *(OpenApi)* Enhance OpenAPI specifications by adding UUID parameters for application, project, and service updates; improve deployment listing with pagination parameters; update command signature for OpenApi generation
- *(subscription)* Enhance subscription management with loading states and Stripe status checks - *(subscription)* Enhance subscription management with loading states and Stripe status checks
- *(readme)* Add new sponsors Supadata AI and WZ-IT to the README
- *(core)* Enable magic env variables for compose based applications
### 🐛 Bug Fixes ### 🐛 Bug Fixes
@@ -33,6 +36,11 @@ All notable changes to this project will be documented in this file.
- *(mongodb)* Also apply custom config when SSL is enabled - *(mongodb)* Also apply custom config when SSL is enabled
- *(templates)* Correct casing of denoKV references in service templates and YAML files - *(templates)* Correct casing of denoKV references in service templates and YAML files
- *(deployment)* Handle missing destination in deployment process to prevent errors - *(deployment)* Handle missing destination in deployment process to prevent errors
- *(parser)* Transform associative array labels into key=value format for better compatibility
- *(redis)* Update username and password input handling to clarify database sync requirements
- *(source)* Update connected source display to handle cases with no source connected
- *(application)* Append base directory to git branch URLs for improved path handling
- *(templates)* Correct casing of "denokv" to "denoKV" in service templates JSON
### 💼 Other ### 💼 Other
@@ -44,6 +52,7 @@ All notable changes to this project will be documented in this file.
- *(Dockerfile)* Remove service generation command from the build process to streamline Dockerfile and improve build efficiency - *(Dockerfile)* Remove service generation command from the build process to streamline Dockerfile and improve build efficiency
- *(navbar-delete-team)* Simplify modal confirmation layout and enhance button styling for better user experience - *(navbar-delete-team)* Simplify modal confirmation layout and enhance button styling for better user experience
- *(Server)* Remove debug logging from isReachableChanged method to clean up code and improve performance - *(Server)* Remove debug logging from isReachableChanged method to clean up code and improve performance
- *(source)* Conditionally display connected source and change source options based on private key presence
### 📚 Documentation ### 📚 Documentation
@@ -56,6 +65,9 @@ All notable changes to this project will be documented in this file.
- *(versions)* Update nightly version to 4.0.0-beta.410 - *(versions)* Update nightly version to 4.0.0-beta.410
- *(pre-commit)* Remove OpenAPI generation command from pre-commit hook - *(pre-commit)* Remove OpenAPI generation command from pre-commit hook
- *(versions)* Update realtime version to 1.0.7 and bump dependencies in package.json - *(versions)* Update realtime version to 1.0.7 and bump dependencies in package.json
- *(versions)* Bump coolify version to 4.0.0-beta.409 in configuration files
- *(versions)* Bump coolify version to 4.0.0-beta.410 and update nightly version to 4.0.0-beta.411 in configuration files
- *(templates)* Update plausible and clickhouse images to latest versions and remove mail service
## [4.0.0-beta.407] - 2025-04-09 ## [4.0.0-beta.407] - 2025-04-09

183
README.md
View File

@@ -29,99 +29,6 @@ You can find the installation script source [here](./scripts/install.sh).
Contact us at [coolify.io/docs/contact](https://coolify.io/docs/contact). Contact us at [coolify.io/docs/contact](https://coolify.io/docs/contact).
# Donations
To stay completely free and open-source, with no feature behind the paywall and evolve the project, we need your help. If you like Coolify, please consider donating to help us fund the project's future development.
[coolify.io/sponsorships](https://coolify.io/sponsorships)
Thank you so much!
Special thanks to our biggest sponsors!
### Special Sponsors
![image](https://github.com/user-attachments/assets/6022bc9c-8435-4d14-9497-8be230ed8cb1)
* [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.
* [Logto](https://logto.io/?ref=coolify) - An open-source authentication and authorization solution for building secure login systems and managing user identities.
* [Tolgee](https://tolgee.io/?ref=coolify) - Developer & translator friendly web-based localization platform.
* [BC Direct](https://bc.direct/?ref=coolify.io) - A digital marketing agency specializing in e-commerce solutions and online business growth strategies.
* [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.
* [Convex](https://convex.link/coolify.io) - Convex is the open-source reactive database for web app developers.
* [Cloudify.ro](https://cloudify.ro/?ref=coolify.io) - A cloud hosting provider offering scalable infrastructure solutions for businesses of all sizes.
* [Syntaxfm](https://syntax.fm/?ref=coolify.io) - Podcast for web developers.
* [PFGlabs](https://pfglabs.com/?ref=coolify.io) - Build real project with Golang.
* [Treive](https://trieve.ai/?ref=coolify.io) - An AI-powered search and discovery platform for enhancing information retrieval in large datasets.
* [Blacksmith](https://blacksmith.sh/?ref=coolify.io) - A cloud-native platform for automating infrastructure provisioning and management across multiple cloud providers.
* [Brand Dev](https://brand.dev/?ref=coolify.io) - The #1 Brand API for B2B software startups - instantly pull logos, fonts, descriptions, social links, slogans, and so much more from any domain via a single api call.
* [Jobscollider](https://jobscollider.com/remote-jobs?ref=coolify.io) - A job search platform connecting professionals with remote work opportunities across various industries.
* [Hostinger](https://www.hostinger.com/vps/coolify-hosting?ref=coolify.io) - A web hosting provider offering affordable hosting solutions, domain registration, and website building tools.
* [Glueops](https://www.glueops.dev/?ref=coolify.io) - A DevOps consulting company providing infrastructure automation and cloud optimization services.
* [Ubicloud](https://ubicloud.com/?ref=coolify.io) - An open-source alternative to hyperscale cloud providers, offering high-performance cloud computing services.
* [Juxtdigital](https://juxtdigital.dev/?ref=coolify.io) - A digital agency offering web development, design, and digital marketing services for businesses.
* [Saasykit](https://saasykit.com/?ref=coolify.io) - A Laravel-based boilerplate providing essential components and features for building SaaS applications quickly.
* [Massivegrid](https://massivegrid.com/?ref=coolify.io) - A cloud hosting provider offering scalable infrastructure solutions for businesses of all sizes.
* [LiquidWeb](https://liquidweb.com/?utm_source=coolify.io) - A Fast web hosting provider.
## Github Sponsors ($40+)
<a href="https://serpapi.com/?ref=coolify.io"><img width="60px" alt="SerpAPI" src="https://github.com/serpapi.png"/></a>
<a href="https://typebot.io/?ref=coolify.io"><img src="https://pbs.twimg.com/profile_images/1509194008366657543/9I-C7uWT_400x400.jpg" width="60px" alt="typebot"/></a>
<a href="https://www.runpod.io/?ref=coolify.io">
<svg style="width:60px;height:60px;background:#fff;" xmlns="http://www.w3.org/2000/svg" version="1.0" viewBox="0 0 200 200"><g><path d="M74.5 51.1c-25.4 14.9-27 16-29.6 20.2-1.8 3-1.9 5.3-1.9 32.3 0 21.7.3 29.4 1.3 30.6 1.9 2.5 46.7 27.9 48.5 27.6 1.5-.3 1.7-3.1 2-27.7.2-21.9 0-27.8-1.1-29.5-.8-1.2-9.9-6.8-20.2-12.6-10.3-5.8-19.4-11.5-20.2-12.7-1.8-2.6-.9-5.9 1.8-7.4 1.6-.8 6.3 0 21.8 4C87.8 78.7 98 81 99.6 81c4.4 0 49.9-25.9 49.9-28.4 0-1.6-3.4-2.8-24-8.2-13.2-3.5-25.1-6.3-26.5-6.3-1.4.1-12.4 5.9-24.5 13z"></path><path d="m137.2 68.1-3.3 2.1 6.3 3.7c3.5 2 6.3 4.3 6.3 5.1 0 .9-8 6.1-19.4 12.6-10.6 6-20 11.9-20.7 12.9-1.2 1.6-1.4 7.2-1.2 29.4.3 24.8.5 27.6 2 27.9 1.8.3 46.6-25.1 48.6-27.6.9-1.2 1.2-8.8 1.2-30.2s-.3-29-1.2-30.2c-1.6-1.9-12.1-7.8-13.9-7.8-.8 0-2.9 1-4.7 2.1z"></path></g></svg></a>
<a href="https://lightspeed.run/?ref=coolify.io"><img src="https://github.com/lightspeedrun.png" width="60px" alt="Lightspeed.run"/></a>
<a href="https://dartnode.com/?ref=coolify.io"><img src="https://github.com/DartNode-com.png" width="60px" alt="DartNode"/></a>
<a href="https://www.flint.sh/en/home?ref=coolify.io"> <img src="https://github.com/Flint-company.png" width="60px" alt="FlintCompany"/></a>
<a href="https://americancloud.com/?ref=coolify.io"><img src="https://github.com/American-Cloud.png" width="60px" alt="American Cloud"/></a>
<a href="https://cryptojobslist.com/?ref=coolify.io"><img src="https://github.com/cryptojobslist.png" width="60px" alt="CryptoJobsList" /></a>
<a href="https://codext.link/coolify-io?ref=coolify.io"><img src="./other/logos/codext.jpg" width="60px" alt="Codext" /></a>
<a href="https://x.com/mrsmith9ja?ref=coolify.io"><img width="60px" alt="Thompson Edolo" src="https://github.com/verygreenboi.png"/></a>
<a href="https://www.uxwizz.com/?ref=coolify.io"><img width="60px" alt="UXWizz" src="https://github.com/UXWizz.png"/></a>
<a href="https://github.com/Flowko"><img src="https://barrad.me/_ipx/f_webp&s_300x300/younes.jpg" width="60px" alt="Younes Barrad" /></a>
<a href="https://github.com/automazeio"><img src="https://github.com/automazeio.png" width="60px" alt="Automaze" /></a>
<a href="https://github.com/corentinclichy"><img src="https://github.com/corentinclichy.png" width="60px" alt="Corentin Clichy" /></a>
<a href="https://github.com/Niki2k1"><img src="https://github.com/Niki2k1.png" width="60px" alt="Niklas Lausch" /></a>
<a href="https://github.com/pixelinfinito"><img src="https://github.com/pixelinfinito.png" width="60px" alt="Pixel Infinito" /></a>
<a href="https://github.com/whitesidest"><img src="https://avatars.githubusercontent.com/u/12365916?s=52&v=4" width="60px" alt="Tyler Whitesides" /></a>
<a href="https://github.com/aniftyco"><img src="https://github.com/aniftyco.png" width="60px" alt="NiftyCo" /></a>
<a href="https://github.com/iujlaki"><img src="https://github.com/iujlaki.png" width="60px" alt="Imre Ujlaki" /></a>
<a href="https://il.ly"><img src="https://github.com/Illyism.png" width="60px" alt="Ilias Ism" /></a>
<a href="https://www.breakcold.com/?utm_source=coolify.io"><img src="https://github.com/breakcold.png" width="60px" alt="Breakcold" /></a>
<a href="https://github.com/urtho"><img src="https://github.com/urtho.png" width="60px" alt="Paweł Pierścionek" /></a>
<a href="https://github.com/monocursive"><img src="https://github.com/monocursive.png" width="60px" alt="Michael Mazurczak" /></a>
<a href="https://formbricks.com/?utm_source=coolify.io"><img src="https://github.com/formbricks.png" width="60px" alt="Formbricks" /></a>
<a href="https://startupfa.me?utm_source=coolify.io"><img src="https://github.com/startupfame.png" width="60px" alt="StartupFame" /></a>
<a href="https://bsky.app/profile/jyc.dev"><img src="https://github.com/jycouet.png" width="60px" alt="jyc.dev" /></a>
<a href="https://bitlaunch.io/?utm_source=coolify.io"><img src="https://github.com/bitlaunchio.png" width="60px" alt="BitLaunch" /></a>
<a href="https://internetgarden.co/?utm_source=coolify.io"><img src="./other/logos/internetgarden.ico" width="60px" alt="Internet Garden" /></a>
<a href="https://jonasjaeger.com?utm_source=coolify.io"><img src="https://github.com/toxin20.png" width="60px" alt="Jonas Jaeger" /></a>
<a href="https://github.com/therealjp?utm_source=coolify.io"><img src="https://github.com/therealjp.png" width="60px" alt="JP" /></a>
<a href="https://evercam.io/?utm_source=coolify.io"><img src="https://github.com/evercam.png" width="60px" alt="Evercam" /></a>
<a href="https://web3.career/?utm_source=coolify.io"><img src="https://web3.career/favicon1.png" width="60px" alt="Web3 Career" /></a>
## Organizations
<a href="https://opencollective.com/coollabsio/organization/0/website"><img src="https://opencollective.com/coollabsio/organization/0/avatar.svg"></a>
<a href="https://opencollective.com/coollabsio/organization/1/website"><img src="https://opencollective.com/coollabsio/organization/1/avatar.svg"></a>
<a href="https://opencollective.com/coollabsio/organization/2/website"><img src="https://opencollective.com/coollabsio/organization/2/avatar.svg"></a>
<a href="https://opencollective.com/coollabsio/organization/3/website"><img src="https://opencollective.com/coollabsio/organization/3/avatar.svg"></a>
<a href="https://opencollective.com/coollabsio/organization/4/website"><img src="https://opencollective.com/coollabsio/organization/4/avatar.svg"></a>
<a href="https://opencollective.com/coollabsio/organization/5/website"><img src="https://opencollective.com/coollabsio/organization/5/avatar.svg"></a>
<a href="https://opencollective.com/coollabsio/organization/6/website"><img src="https://opencollective.com/coollabsio/organization/6/avatar.svg"></a>
<a href="https://opencollective.com/coollabsio/organization/7/website"><img src="https://opencollective.com/coollabsio/organization/7/avatar.svg"></a>
<a href="https://opencollective.com/coollabsio/organization/8/website"><img src="https://opencollective.com/coollabsio/organization/8/avatar.svg"></a>
<a href="https://opencollective.com/coollabsio/organization/9/website"><img src="https://opencollective.com/coollabsio/organization/9/avatar.svg"></a>
## Individuals
<a href="https://opencollective.com/coollabsio"><img src="https://opencollective.com/coollabsio/individuals.svg?width=890"></a>
# Cloud # Cloud
If you do not want to self-host Coolify, there is a paid cloud version available: [app.coolify.io](https://app.coolify.io) If you do not want to self-host Coolify, there is a paid cloud version available: [app.coolify.io](https://app.coolify.io)
@@ -137,6 +44,96 @@ By subscribing to the cloud version, you get the Coolify server for the same pri
- Better support - Better support
- Less maintenance for you - Less maintenance for you
# Donations
To stay completely free and open-source, with no feature behind the paywall and evolve the project, we need your help. If you like Coolify, please consider donating to help us fund the project's future development.
[coolify.io/sponsorships](https://coolify.io/sponsorships)
Thank you so much!
## Big Sponsors
* [GlueOps](https://www.glueops.dev?ref=coolify.io) - DevOps automation and infrastructure management
* [Algora](https://algora.io?ref=coolify.io) - Open source contribution platform
* [Ubicloud](https://www.ubicloud.com?ref=coolify.io) - Open source cloud infrastructure platform
* [LiquidWeb](https://liquidweb.com?ref=coolify.io) - Premium managed hosting solutions
* [Convex](https://convex.link/coolify.io) - Open-source reactive database for web app developers
* [Arcjet](https://arcjet.com?ref=coolify.io) - Advanced web security and performance solutions
* [SaasyKit](https://saasykit.com?ref=coolify.io) - Complete SaaS starter kit for developers
* [SupaGuide](https://supa.guide?ref=coolify.io) - Your comprehensive guide to Supabase
* [Logto](https://logto.io?ref=coolify.io) - The better identity infrastructure for developers
* [Trieve](https://trieve.ai?ref=coolify.io) - AI-powered search and analytics
* [Supadata AI](https://supadata.ai/?ref=coolify.io) - Scrape YouTube, web, and files. Get AI-ready, clean data
* [Darweb](https://darweb.nl/?ref=coolify.io) - Design. Develop. Deliver. Specialized in 3D CPQ Solutions
* [Hetzner](http://htznr.li/CoolifyXHetzner) - Server, cloud, hosting, and data center solutions
* [COMIT](https://comit.international?ref=coolify.io) - New York Times awardwinning contractor
* [Blacksmith](https://blacksmith.sh?ref=coolify.io) - Infrastructure automation platform
* [WZ-IT](https://wz-it.com/?ref=coolify.io) - German agency for customised cloud solutions
* [BC Direct](https://bc.direct?ref=coolify.io) - Your trusted technology consulting partner
* [Tigris](https://www.tigrisdata.com?ref=coolify.io) - Modern developer data platform
* [Hostinger](https://www.hostinger.com/vps/coolify-hosting?ref=coolify.io) - Web hosting and VPS solutions
* [QuantCDN](https://www.quantcdn.io?ref=coolify.io) - Enterprise-grade content delivery network
* [PFGLabs](https://pfglabs.com?ref=coolify.io) - Build Real Projects with Golang
* [JobsCollider](https://jobscollider.com/remote-jobs?ref=coolify.io) - 30,000+ remote jobs for developers
* [Juxtdigital](https://juxtdigital.com?ref=coolify.io) - Digital transformation and web solutions
* [Cloudify.ro](https://cloudify.ro?ref=coolify.io) - Cloud hosting solutions
* [CodeRabbit](https://coderabbit.ai?ref=coolify.io) - Cut Code Review Time & Bugs in Half
* [American Cloud](https://americancloud.com?ref=coolify.io) - US-based cloud infrastructure services
* [MassiveGrid](https://massivegrid.com?ref=coolify.io) - Enterprise cloud hosting solutions
* [Syntax.fm](https://syntax.fm?ref=coolify.io) - Podcast for web developers
* [Tolgee](https://tolgee.io?ref=coolify.io) - The open source localization platform
* [CompAI](https://www.trycomp.ai?ref=coolify.io) - Open source compliance automation platform
* [GoldenVM](https://billing.goldenvm.com?ref=coolify.io) - Premium virtual machine hosting solutions
## Small Sponsors
<a href="https://www.uxwizz.com/?utm_source=coolify.io"><img width="60px" alt="UXWizz" src="https://github.com/UXWizz.png"/></a>
<a href="https://evercam.io/?utm_source=coolify.io"><img width="60px" alt="Evercam" src="https://github.com/evercam.png"/></a>
<a href="https://github.com/iujlaki"><img width="60px" alt="Imre Ujlaki" src="https://github.com/iujlaki.png"/></a>
<a href="https://bsky.app/profile/jyc.dev"><img width="60px" alt="jyc.dev" src="https://github.com/jycouet.png"/></a>
<a href="https://github.com/therealjp?utm_source=coolify.io"><img width="60px" alt="TheRealJP" src="https://github.com/therealjp.png"/></a>
<a href="https://360creators.com/?utm_source=coolify.io"><img width="60px" alt="360Creators" src="https://opencollective-production.s3.us-west-1.amazonaws.com/account-avatar/503e0953-bff7-4296-b4cc-5e36d40eecc0/icon-360creators.png"/></a>
<a href="https://github.com/aniftyco"><img width="60px" alt="NiftyCo" src="https://github.com/aniftyco.png"/></a>
<a href="https://dry.software/?utm_source=coolify.io"><img width="60px" alt="Dry Software" src="https://github.com/dry-software.png"/></a>
<a href="https://lightspeed.run/?utm_source=coolify.io"><img width="60px" alt="Lightspeed.run" src="https://github.com/lightspeedrun.png"/></a>
<a href="https://linkdr.com?utm_source=coolify.io"><img width="60px" alt="LinkDr" src="https://github.com/LLM-Inc.png"/></a>
<a href="http://gravitywiz.com/?utm_source=coolify.io"><img width="60px" alt="Gravity Wiz" src="https://github.com/gravitywiz.png"/></a>
<a href="https://bitlaunch.io/?utm_source=coolify.io"><img width="60px" alt="BitLaunch" src="https://github.com/bitlaunchio.png"/></a>
<a href="https://bestforandroid.com/?utm_source=coolify.io"><img width="60px" alt="Best for Android" src="https://github.com/bestforandroid.png"/></a>
<a href="https://il.ly/?utm_source=coolify.io"><img width="60px" alt="Ilias Ism" src="https://github.com/Illyism.png"/></a>
<a href="https://formbricks.com/?utm_source=coolify.io"><img width="60px" alt="Formbricks" src="https://github.com/formbricks.png"/></a>
<a href="https://www.serversearcher.com/"><img width="60px" alt="Server Searcher" src="https://github.com/serversearcher.png"/></a>
<a href="https://www.reshot.ai/?utm_source=coolify.io"><img width="60px" alt="Reshot" src="https://coolify.io/images/reshotai.png"/></a>
<a href="https://cirun.io/?utm_source=coolify.io"><img width="60px" alt="Cirun" src="https://coolify.io/images/cirun-logo.png"/></a>
<a href="https://typebot.io/?utm_source=coolify.io"><img width="60px" alt="Typebot" src="https://cdn.bsky.app/img/avatar/plain/did:plc:gwxcta3pccyim4z5vuultdqx/bafkreig23hci7e2qpdxicsshnuzujbcbcgmydxhbybkewszdezhdodv42m@jpeg"/></a>
<a href="https://cccareers.org/?utm_source=coolify.io"><img width="60px" alt="Creating Coding Careers" src="https://github.com/cccareers.png"/></a>
<a href="https://internetgarden.co/?utm_source=coolify.io"><img width="60px" alt="Internet Garden" src="https://coolify.io/images/internetgarden.ico"/></a>
<a href="https://web3.career/?utm_source=coolify.io"><img width="60px" alt="Web3 Jobs" src="https://coolify.io/images/web3jobs.png"/></a>
<a href="https://codext.link/coolify-io?utm_source=coolify.io"><img width="60px" alt="Codext" src="https://coolify.io/images/codext.jpg"/></a>
<a href="https://github.com/monocursive"><img width="60px" alt="Michael Mazurczak" src="https://github.com/monocursive.png"/></a>
<a href="https://fider.io/?utm_source=coolify.io"><img width="60px" alt="Fider" src="https://github.com/getfider.png"/></a>
<a href="https://www.flint.sh/en/home?utm_source=coolify.io"><img width="60px" alt="Flint" src="https://github.com/Flint-company.png"/></a>
<a href="https://github.com/urtho"><img width="60px" alt="Paweł Pierścionek" src="https://github.com/urtho.png"/></a>
<a href="https://www.runpod.io/?utm_source=coolify.io"><img width="60px" alt="RunPod" src="https://coolify.io/images/runpod.svg"/></a>
<a href="https://dartnode.com/?utm_source=coolify.io"><img width="60px" alt="DartNode" src="https://github.com/dartnode.png"/></a>
<a href="https://github.com/whitesidest"><img width="60px" alt="Tyler Whitesides" src="https://avatars.githubusercontent.com/u/12365916?s=52&v=4"/></a>
<a href="https://serpapi.com/?utm_source=coolify.io"><img width="60px" alt="SerpAPI" src="https://github.com/serpapi.png"/></a>
<a href="https://aquarela.io"><img width="60px" alt="Aquarela" src="https://github.com/aquarela-io.png"/></a>
<a href="https://cryptojobslist.com/?utm_source=coolify.io"><img width="60px" alt="Crypto Jobs List" src="https://github.com/cryptojobslist.png"/></a>
<a href="https://www.youtube.com/@AlfredNutile?utm_source=coolify.io"><img width="60px" alt="Alfred Nutile" src="https://github.com/alnutile.png"/></a>
<a href="https://startupfa.me?utm_source=coolify.io"><img width="60px" alt="Startup Fame" src="https://github.com/startupfame.png"/></a>
<a href="https://barrad.me/?utm_source=coolify.io"><img width="60px" alt="Younes Barrad" src="https://github.com/Flowko.png"/></a>
<a href="https://jonasjaeger.com?utm_source=coolify.io"><img width="60px" alt="Jonas Jaeger" src="https://github.com/toxin20.png"/></a>
<a href="https://pixel.ao/?utm_source=coolify.io"><img width="60px" alt="Pixel Infinito" src="https://github.com/pixelinfinito.png"/></a>
<a href="https://github.com/corentinclichy"><img width="60px" alt="Corentin Clichy" src="https://github.com/corentinclichy.png"/></a>
<a href="https://x.com/mrsmith9ja?utm_source=coolify.io"><img width="60px" alt="Thompson Edolo" src="https://github.com/verygreenboi.png"/></a>
<a href="https://devhuset.no?utm_source=coolify.io"><img width="60px" alt="Devhuset" src="https://github.com/devhuset.png"/></a>
<a href="https://arvensis.systems/?utm_source=coolify.io"><img width="60px" alt="Arvensis Systems" src="https://coolify.io/images/arvensis.png"/></a>
<a href="https://github.com/Niki2k1"><img width="60px" alt="Niklas Lausch" src="https://github.com/Niki2k1.png"/></a>
<a href="https://capgo.app/?utm_source=coolify.io"><img width="60px" alt="Cap-go" src="https://github.com/cap-go.png"/></a>
...and many more at [GitHub Sponsors](https://github.com/sponsors/coollabsio)
# Recognitions # Recognitions
<p> <p>

View File

@@ -2562,10 +2562,6 @@ class ApplicationsController extends Controller
])->setStatusCode(201); ])->setStatusCode(201);
} }
} }
return response()->json([
'message' => 'Something went wrong.',
], 500);
} }
#[OA\Delete( #[OA\Delete(

View File

@@ -809,6 +809,6 @@ class ServersController extends Controller
} }
ValidateServer::dispatch($server); ValidateServer::dispatch($server);
return response()->json(['message' => 'Validation started.']); return response()->json(['message' => 'Validation started.'], 201);
} }
} }

View File

@@ -380,6 +380,9 @@ class ServicesController extends Controller
$service = new Service; $service = new Service;
$result = $this->upsert_service($request, $service, $teamId); $result = $this->upsert_service($request, $service, $teamId);
if ($result instanceof \Illuminate\Http\JsonResponse) {
return $result;
}
return response()->json(serializeApiResponse($result))->setStatusCode(201); return response()->json(serializeApiResponse($result))->setStatusCode(201);
} else { } else {
@@ -608,12 +611,14 @@ class ServicesController extends Controller
} }
$service = Service::whereRelation('environment.project.team', 'id', $teamId)->whereUuid($request->uuid)->first(); $service = Service::whereRelation('environment.project.team', 'id', $teamId)->whereUuid($request->uuid)->first();
if (! $service) { if (! $service) {
return response()->json(['message' => 'Service not found.'], 404); return response()->json(['message' => 'Service not found.'], 404);
} }
$result = $this->upsert_service($request, $service, $teamId); $result = $this->upsert_service($request, $service, $teamId);
if ($result instanceof \Illuminate\Http\JsonResponse) {
return $result;
}
return response()->json(serializeApiResponse($result))->setStatusCode(200); return response()->json(serializeApiResponse($result))->setStatusCode(200);
} }

View File

@@ -1377,6 +1377,17 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
private function check_git_if_build_needed() private function check_git_if_build_needed()
{ {
if ($this->source->getMorphClass() === \App\Models\GithubApp::class && $this->source->is_public === false) {
$repository = githubApi($this->source, "repos/{$this->customRepository}");
$data = data_get($repository, 'data');
if (isset($data->id)) {
$repository_project_id = $data->id;
if (blank($this->application->repository_project_id) || $this->application->repository_project_id !== $repository_project_id) {
$this->application->repository_project_id = $repository_project_id;
$this->application->save();
}
}
}
$this->generate_git_import_commands(); $this->generate_git_import_commands();
$local_branch = $this->branch; $local_branch = $this->branch;
if ($this->pull_request_id !== 0) { if ($this->pull_request_id !== 0) {
@@ -1712,25 +1723,6 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
$labels = $labels->filter(function ($value, $key) { $labels = $labels->filter(function ($value, $key) {
return ! Str::startsWith($value, 'coolify.'); return ! Str::startsWith($value, 'coolify.');
}); });
$found_caddy_labels = $labels->filter(function ($value, $key) {
return Str::startsWith($value, 'caddy_');
});
if ($found_caddy_labels->count() === 0) {
if ($this->pull_request_id !== 0) {
$domains = str(data_get($this->preview, 'fqdn'))->explode(',');
} else {
$domains = str(data_get($this->application, 'fqdn'))->explode(',');
}
$labels = $labels->merge(fqdnLabelsForCaddy(
network: $this->application->destination->network,
uuid: $this->application->uuid,
domains: $domains,
onlyPort: $onlyPort,
is_force_https_enabled: $this->application->isForceHttpsEnabled(),
is_gzip_enabled: $this->application->isGzipEnabled(),
is_stripprefix_enabled: $this->application->isStripprefixEnabled()
));
}
$this->application->custom_labels = base64_encode($labels->implode("\n")); $this->application->custom_labels = base64_encode($labels->implode("\n"));
$this->application->save(); $this->application->save();
} else { } else {

View File

@@ -17,11 +17,13 @@ class CleanupInstanceStuffsJob implements ShouldBeEncrypted, ShouldBeUnique, Sho
{ {
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $timeout = 60;
public function __construct() {} public function __construct() {}
public function middleware(): array public function middleware(): array
{ {
return [(new WithoutOverlapping('cleanup-instance-stuffs'))->dontRelease()]; return [(new WithoutOverlapping('cleanup-instance-stuffs'))->expireAfter(60)];
} }
public function handle(): void public function handle(): void

View File

@@ -31,7 +31,7 @@ class DockerCleanupJob implements ShouldBeEncrypted, ShouldQueue
public function middleware(): array public function middleware(): array
{ {
return [(new WithoutOverlapping($this->server->uuid))->dontRelease()]; return [(new WithoutOverlapping($this->server->uuid))->expireAfter(600)];
} }
public function __construct(public Server $server, public bool $manualCleanup = false) {} public function __construct(public Server $server, public bool $manualCleanup = false) {}

View File

@@ -71,7 +71,7 @@ class PushServerUpdateJob implements ShouldBeEncrypted, ShouldQueue
public function middleware(): array public function middleware(): array
{ {
return [(new WithoutOverlapping($this->server->uuid))->dontRelease()]; return [(new WithoutOverlapping($this->server->uuid))->expireAfter(30)];
} }
public function backoff(): int public function backoff(): int

View File

@@ -24,7 +24,7 @@ class RestartProxyJob implements ShouldBeEncrypted, ShouldQueue
public function middleware(): array public function middleware(): array
{ {
return [(new WithoutOverlapping($this->server->uuid))->dontRelease()]; return [(new WithoutOverlapping($this->server->uuid))->expireAfter(60)];
} }
public function __construct(public Server $server) {} public function __construct(public Server $server) {}

View File

@@ -28,7 +28,7 @@ class ServerCheckJob implements ShouldBeEncrypted, ShouldQueue
public function middleware(): array public function middleware(): array
{ {
return [(new WithoutOverlapping($this->server->uuid))->dontRelease()]; return [(new WithoutOverlapping($this->server->uuid))->expireAfter(60)];
} }
public function __construct(public Server $server) {} public function __construct(public Server $server) {}

View File

@@ -111,6 +111,7 @@ class Source extends Component
$this->application->update([ $this->application->update([
'source_id' => $sourceId, 'source_id' => $sourceId,
'source_type' => $sourceType, 'source_type' => $sourceType,
'repository_project_id' => null,
]); ]);
$this->application->refresh(); $this->application->refresh();
$this->getSources(); $this->getSources();

View File

@@ -236,15 +236,6 @@ class All extends Component
return 0; return 0;
} }
// Check for system variables that shouldn't be deleted
foreach ($variablesToDelete as $envVar) {
if ($this->isProtectedEnvironmentVariable($envVar->key)) {
$this->dispatch('error', "Cannot delete system environment variable '{$envVar->key}'.");
return 0;
}
}
// Check if any of these variables are used in Docker Compose // Check if any of these variables are used in Docker Compose
if ($this->resource->type() === 'service' || $this->resource->build_pack === 'dockercompose') { if ($this->resource->type() === 'service' || $this->resource->build_pack === 'dockercompose') {
foreach ($variablesToDelete as $envVar) { foreach ($variablesToDelete as $envVar) {

View File

@@ -178,13 +178,6 @@ class Show extends Component
public function delete() public function delete()
{ {
try { try {
// Check if the variable is protected
if ($this->isProtectedEnvironmentVariable($this->env->key)) {
$this->dispatch('error', "Cannot delete system environment variable '{$this->env->key}'.");
return;
}
// Check if the variable is used in Docker Compose // Check if the variable is used in Docker Compose
if ($this->type === 'service' || $this->type === 'application' && $this->env->resource()?->docker_compose) { if ($this->type === 'service' || $this->type === 'application' && $this->env->resource()?->docker_compose) {
[$isUsed, $reason] = $this->isEnvironmentVariableUsedInDockerCompose($this->env->key, $this->env->resource()?->docker_compose); [$isUsed, $reason] = $this->isEnvironmentVariableUsedInDockerCompose($this->env->key, $this->env->resource()?->docker_compose);

View File

@@ -458,22 +458,23 @@ class Application extends BaseModel
{ {
return Attribute::make( return Attribute::make(
get: function () { get: function () {
$base_dir = $this->base_directory ?? '/';
if (! is_null($this->source?->html_url) && ! is_null($this->git_repository) && ! is_null($this->git_branch)) { if (! is_null($this->source?->html_url) && ! is_null($this->git_repository) && ! is_null($this->git_branch)) {
if (str($this->git_repository)->contains('bitbucket')) { if (str($this->git_repository)->contains('bitbucket')) {
return "{$this->source->html_url}/{$this->git_repository}/src/{$this->git_branch}"; return "{$this->source->html_url}/{$this->git_repository}/src/{$this->git_branch}{$base_dir}";
} }
return "{$this->source->html_url}/{$this->git_repository}/tree/{$this->git_branch}"; return "{$this->source->html_url}/{$this->git_repository}/tree/{$this->git_branch}{$base_dir}";
} }
// Convert the SSH URL to HTTPS URL // Convert the SSH URL to HTTPS URL
if (strpos($this->git_repository, 'git@') === 0) { if (strpos($this->git_repository, 'git@') === 0) {
$git_repository = str_replace(['git@', ':', '.git'], ['', '/', ''], $this->git_repository); $git_repository = str_replace(['git@', ':', '.git'], ['', '/', ''], $this->git_repository);
if (str($this->git_repository)->contains('bitbucket')) { if (str($this->git_repository)->contains('bitbucket')) {
return "https://{$git_repository}/src/{$this->git_branch}"; return "https://{$git_repository}/src/{$this->git_branch}{$base_dir}";
} }
return "https://{$git_repository}/tree/{$this->git_branch}"; return "https://{$git_repository}/tree/{$this->git_branch}{$base_dir}";
} }
return $this->git_repository; return $this->git_repository;

View File

@@ -492,11 +492,7 @@ $schema://$host {
if ($proxyType === ProxyTypes::TRAEFIK->value) { if ($proxyType === ProxyTypes::TRAEFIK->value) {
// Do nothing // Do nothing
} elseif ($proxyType === ProxyTypes::CADDY->value) { } elseif ($proxyType === ProxyTypes::CADDY->value) {
if (isDev()) { $proxy_path = $proxy_path.'/caddy';
$proxy_path = '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/proxy/caddy';
} else {
$proxy_path = $proxy_path.'/caddy';
}
} elseif ($proxyType === ProxyTypes::NGINX->value) { } elseif ($proxyType === ProxyTypes::NGINX->value) {
if (isDev()) { if (isDev()) {
$proxy_path = '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/proxy/nginx'; $proxy_path = '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/proxy/nginx';

View File

@@ -141,6 +141,6 @@ class ServiceDatabase extends BaseModel
str($this->databaseType())->contains('postgres') || str($this->databaseType())->contains('postgres') ||
str($this->databaseType())->contains('postgis') || str($this->databaseType())->contains('postgis') ||
str($this->databaseType())->contains('mariadb') || str($this->databaseType())->contains('mariadb') ||
str($this->databaseType())->contains('mongodb'); str($this->databaseType())->contains('mongo');
} }
} }

View File

@@ -729,8 +729,10 @@ function isDatabaseImage(?string $image = null)
$image = str($image)->append(':latest'); $image = str($image)->append(':latest');
} }
$imageName = $image->before(':'); $imageName = $image->before(':');
if (collect(DATABASE_DOCKER_IMAGES)->contains($imageName)) { foreach (DATABASE_DOCKER_IMAGES as $database_docker_image) {
return true; if (str($imageName)->contains($database_docker_image)) {
return true;
}
} }
return false; return false;

View File

@@ -3014,168 +3014,159 @@ function newParser(Application|Service $resource, int $pull_request_id = 0, ?int
$savedService->image = $image; $savedService->image = $image;
$savedService->save(); $savedService->save();
} }
}
$environment = collect(data_get($service, 'environment', []));
$buildArgs = collect(data_get($service, 'build.args', []));
$environment = $environment->merge($buildArgs);
$environment = collect(data_get($service, 'environment', [])); // convert environment variables to one format
$buildArgs = collect(data_get($service, 'build.args', [])); $environment = convertToKeyValueCollection($environment);
$environment = $environment->merge($buildArgs);
// convert environment variables to one format // Add Coolify defined environments
$environment = convertToKeyValueCollection($environment); $allEnvironments = $resource->environment_variables()->get(['key', 'value']);
// Add Coolify defined environments $allEnvironments = $allEnvironments->mapWithKeys(function ($item) {
$allEnvironments = $resource->environment_variables()->get(['key', 'value']); return [$item['key'] => $item['value']];
});
// filter and add magic environments
foreach ($environment as $key => $value) {
// Get all SERVICE_ variables from keys and values
$key = str($key);
$value = str($value);
$allEnvironments = $allEnvironments->mapWithKeys(function ($item) { $regex = '/\$(\{?([a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*)\}?)/';
return [$item['key'] => $item['value']]; preg_match_all($regex, $value, $valueMatches);
}); if (count($valueMatches[1]) > 0) {
// filter and add magic environments foreach ($valueMatches[1] as $match) {
foreach ($environment as $key => $value) { $match = replaceVariables($match);
// Get all SERVICE_ variables from keys and values if ($match->startsWith('SERVICE_')) {
$key = str($key); if ($magicEnvironments->has($match->value())) {
$value = str($value); continue;
$regex = '/\$(\{?([a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*)\}?)/';
preg_match_all($regex, $value, $valueMatches);
if (count($valueMatches[1]) > 0) {
foreach ($valueMatches[1] as $match) {
$match = replaceVariables($match);
if ($match->startsWith('SERVICE_')) {
if ($magicEnvironments->has($match->value())) {
continue;
}
$magicEnvironments->put($match->value(), '');
} }
} $magicEnvironments->put($match->value(), '');
}
// Get magic environments where we need to preset the FQDN
if ($key->startsWith('SERVICE_FQDN_')) {
// SERVICE_FQDN_APP or SERVICE_FQDN_APP_3000
if (substr_count(str($key)->value(), '_') === 3) {
$fqdnFor = $key->after('SERVICE_FQDN_')->beforeLast('_')->lower()->value();
$port = $key->afterLast('_')->value();
} else {
$fqdnFor = $key->after('SERVICE_FQDN_')->lower()->value();
$port = null;
}
if ($isApplication) {
$fqdn = generateFqdn($server, "{$resource->name}-$uuid");
} elseif ($isService) {
if ($fqdnFor) {
$fqdn = generateFqdn($server, "$fqdnFor-$uuid");
} else {
$fqdn = generateFqdn($server, "{$savedService->name}-$uuid");
}
}
if ($value && get_class($value) === \Illuminate\Support\Stringable::class && $value->startsWith('/')) {
$path = $value->value();
if ($path !== '/') {
$fqdn = "$fqdn$path";
}
}
$fqdnWithPort = $fqdn;
if ($port) {
$fqdnWithPort = "$fqdn:$port";
}
if ($isApplication && is_null($resource->fqdn)) {
data_forget($resource, 'environment_variables');
data_forget($resource, 'environment_variables_preview');
$resource->fqdn = $fqdnWithPort;
$resource->save();
} elseif ($isService && is_null($savedService->fqdn)) {
$savedService->fqdn = $fqdnWithPort;
$savedService->save();
}
if (substr_count(str($key)->value(), '_') === 2) {
$resource->environment_variables()->firstOrCreate([
'key' => $key->value(),
'resourceable_type' => get_class($resource),
'resourceable_id' => $resource->id,
], [
'value' => $fqdn,
'is_build_time' => false,
'is_preview' => false,
]);
}
if (substr_count(str($key)->value(), '_') === 3) {
$newKey = str($key)->beforeLast('_');
$resource->environment_variables()->firstOrCreate([
'key' => $newKey->value(),
'resourceable_type' => get_class($resource),
'resourceable_id' => $resource->id,
], [
'value' => $fqdn,
'is_build_time' => false,
'is_preview' => false,
]);
} }
} }
} }
$allMagicEnvironments = $allMagicEnvironments->merge($magicEnvironments); // Get magic environments where we need to preset the FQDN
if ($magicEnvironments->count() > 0) { if ($key->startsWith('SERVICE_FQDN_')) {
foreach ($magicEnvironments as $key => $value) { // SERVICE_FQDN_APP or SERVICE_FQDN_APP_3000
$key = str($key); if (substr_count(str($key)->value(), '_') === 3) {
$value = replaceVariables($value); $fqdnFor = $key->after('SERVICE_FQDN_')->beforeLast('_')->lower()->value();
$command = parseCommandFromMagicEnvVariable($key); $port = $key->afterLast('_')->value();
$found = $resource->environment_variables()->where('key', $key->value())->where('resourceable_type', get_class($resource))->where('resourceable_id', $resource->id)->first(); } else {
if ($found) { $fqdnFor = $key->after('SERVICE_FQDN_')->lower()->value();
continue; $port = null;
} }
if ($command->value() === 'FQDN') { if ($isApplication) {
$fqdnFor = $key->after('SERVICE_FQDN_')->lower()->value(); $fqdn = generateFqdn($server, "$uuid");
if (str($fqdnFor)->contains('_')) { } elseif ($isService) {
$fqdnFor = str($fqdnFor)->before('_'); if ($fqdnFor) {
} $fqdn = generateFqdn($server, "$fqdnFor-$uuid");
if ($isApplication) {
$fqdn = generateFqdn($server, "{$resource->name}-$uuid");
} elseif ($isService) {
$fqdn = generateFqdn($server, "$fqdnFor-$uuid");
}
$resource->environment_variables()->firstOrCreate([
'key' => $key->value(),
'resourceable_type' => get_class($resource),
'resourceable_id' => $resource->id,
], [
'value' => $fqdn,
'is_build_time' => false,
'is_preview' => false,
]);
} elseif ($command->value() === 'URL') {
$fqdnFor = $key->after('SERVICE_URL_')->lower()->value();
if (str($fqdnFor)->contains('_')) {
$fqdnFor = str($fqdnFor)->before('_');
}
if ($isApplication) {
$fqdn = generateFqdn($server, "{$resource->name}-$uuid");
} elseif ($isService) {
$fqdn = generateFqdn($server, "$fqdnFor-$uuid");
}
$fqdn = str($fqdn)->replace('http://', '')->replace('https://', '');
$resource->environment_variables()->firstOrCreate([
'key' => $key->value(),
'resourceable_type' => get_class($resource),
'resourceable_id' => $resource->id,
], [
'value' => $fqdn,
'is_build_time' => false,
'is_preview' => false,
]);
} else { } else {
$value = generateEnvValue($command, $resource); $fqdn = generateFqdn($server, "{$savedService->name}-$uuid");
$resource->environment_variables()->firstOrCreate([
'key' => $key->value(),
'resourceable_type' => get_class($resource),
'resourceable_id' => $resource->id,
], [
'value' => $value,
'is_build_time' => false,
'is_preview' => false,
]);
} }
} }
if ($value && get_class($value) === \Illuminate\Support\Stringable::class && $value->startsWith('/')) {
$path = $value->value();
if ($path !== '/') {
$fqdn = "$fqdn$path";
}
}
$fqdnWithPort = $fqdn;
if ($port) {
$fqdnWithPort = "$fqdn:$port";
}
if ($isApplication && is_null($resource->fqdn)) {
data_forget($resource, 'environment_variables');
data_forget($resource, 'environment_variables_preview');
$resource->fqdn = $fqdnWithPort;
$resource->save();
} elseif ($isService && is_null($savedService->fqdn)) {
$savedService->fqdn = $fqdnWithPort;
$savedService->save();
}
if (substr_count(str($key)->value(), '_') === 2) {
$resource->environment_variables()->firstOrCreate([
'key' => $key->value(),
'resourceable_type' => get_class($resource),
'resourceable_id' => $resource->id,
], [
'value' => $fqdn,
'is_build_time' => false,
'is_preview' => false,
]);
}
if (substr_count(str($key)->value(), '_') === 3) {
$newKey = str($key)->beforeLast('_');
$resource->environment_variables()->firstOrCreate([
'key' => $newKey->value(),
'resourceable_type' => get_class($resource),
'resourceable_id' => $resource->id,
], [
'value' => $fqdn,
'is_build_time' => false,
'is_preview' => false,
]);
}
}
}
$allMagicEnvironments = $allMagicEnvironments->merge($magicEnvironments);
if ($magicEnvironments->count() > 0) {
foreach ($magicEnvironments as $key => $value) {
$key = str($key);
$value = replaceVariables($value);
$command = parseCommandFromMagicEnvVariable($key);
$found = $resource->environment_variables()->where('key', $key->value())->where('resourceable_type', get_class($resource))->where('resourceable_id', $resource->id)->first();
if ($found) {
continue;
}
if ($command->value() === 'FQDN') {
$fqdnFor = $key->after('SERVICE_FQDN_')->lower()->value();
if (str($fqdnFor)->contains('_')) {
$fqdnFor = str($fqdnFor)->before('_');
}
$fqdn = generateFqdn($server, "$fqdnFor-$uuid");
$resource->environment_variables()->firstOrCreate([
'key' => $key->value(),
'resourceable_type' => get_class($resource),
'resourceable_id' => $resource->id,
], [
'value' => $fqdn,
'is_build_time' => false,
'is_preview' => false,
]);
} elseif ($command->value() === 'URL') {
$fqdnFor = $key->after('SERVICE_URL_')->lower()->value();
if (str($fqdnFor)->contains('_')) {
$fqdnFor = str($fqdnFor)->before('_');
}
$fqdn = generateFqdn($server, "$fqdnFor-$uuid");
$fqdn = str($fqdn)->replace('http://', '')->replace('https://', '');
$resource->environment_variables()->firstOrCreate([
'key' => $key->value(),
'resourceable_type' => get_class($resource),
'resourceable_id' => $resource->id,
], [
'value' => $fqdn,
'is_build_time' => false,
'is_preview' => false,
]);
} else {
$value = generateEnvValue($command, $resource);
$resource->environment_variables()->firstOrCreate([
'key' => $key->value(),
'resourceable_type' => get_class($resource),
'resourceable_id' => $resource->id,
], [
'value' => $value,
'is_build_time' => false,
'is_preview' => false,
]);
}
} }
} }
} }
@@ -3828,7 +3819,6 @@ function newParser(Application|Service $resource, int $pull_request_id = 0, ?int
return $volume; return $volume;
}); });
ray($serviceLabels);
$payload = collect($service)->merge([ $payload = collect($service)->merge([
'container_name' => $containerName, 'container_name' => $containerName,
'restart' => $restart->value(), 'restart' => $restart->value(),

View File

@@ -2,7 +2,7 @@
return [ return [
'coolify' => [ 'coolify' => [
'version' => '4.0.0-beta.409', 'version' => '4.0.0-beta.410',
'helper_version' => '1.0.8', 'helper_version' => '1.0.8',
'realtime_version' => '1.0.7', 'realtime_version' => '1.0.7',
'self_hosted' => env('SELF_HOSTED', true), 'self_hosted' => env('SELF_HOSTED', true),

View File

@@ -7729,6 +7729,12 @@
"type": "string", "type": "string",
"format": "private-key" "format": "private-key"
}, },
"public_key": {
"type": "string"
},
"fingerprint": {
"type": "string"
},
"is_git_related": { "is_git_related": {
"type": "boolean" "type": "boolean"
}, },

View File

@@ -5159,6 +5159,10 @@ components:
private_key: private_key:
type: string type: string
format: private-key format: private-key
public_key:
type: string
fingerprint:
type: string
is_git_related: is_git_related:
type: boolean type: boolean
team_id: team_id:

View File

@@ -1,10 +1,10 @@
{ {
"coolify": { "coolify": {
"v4": { "v4": {
"version": "4.0.0-beta.409" "version": "4.0.0-beta.410"
}, },
"nightly": { "nightly": {
"version": "4.0.0-beta.410" "version": "4.0.0-beta.411"
}, },
"helper": { "helper": {
"version": "1.0.8" "version": "1.0.8"

View File

@@ -81,7 +81,7 @@
</x-modal-confirmation> </x-modal-confirmation>
</div> </div>
@empty @empty
<div class="text-center">No sources found</div> <div>No other sources found</div>
@endforelse @endforelse
</div> </div>
</div> </div>

View File

@@ -20,7 +20,12 @@
</div> </div>
<div class="w-48 pb-2"> <div class="w-48 pb-2">
<x-forms.checkbox instantSave label="Backup Enabled" id="backupEnabled" /> <x-forms.checkbox instantSave label="Backup Enabled" id="backupEnabled" />
<x-forms.checkbox instantSave label="S3 Enabled" id="saveS3" /> @if ($s3s->count() > 0)
<x-forms.checkbox instantSave label="S3 Enabled" id="saveS3" />
@else
<x-forms.checkbox instantSave helper="No validated S3 storage available." label="S3 Enabled" id="saveS3"
disabled />
@endif
</div> </div>
@if ($backup->save_s3) @if ($backup->save_s3)
<div class="pb-6"> <div class="pb-6">

View File

@@ -129,7 +129,7 @@
<div class="flex flex-wrap order-first gap-2 items-center sm:order-last"> <div class="flex flex-wrap order-first gap-2 items-center sm:order-last">
<div class="text-error"> <div class="text-error">
Unable to deploy. <a class="underline font-bold cursor-pointer" Unable to deploy. <a class="underline font-bold cursor-pointer"
@click.prevent="activeTab = 'environment-variables'; window.location.hash = 'environment-variables'"> href="{{ route('project.service.environment-variables', $parameters) }}" wire:navigate>
Required environment variables missing.</a> Required environment variables missing.</a>
</div> </div>
</div> </div>

View File

@@ -16,8 +16,13 @@ use App\Models\Server;
use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Route;
Route::get('/health', [OtherController::class, 'healthcheck']); Route::get('/health', [OtherController::class, 'healthcheck']);
Route::post('/feedback', [OtherController::class, 'feedback']); Route::group([
'prefix' => 'v1',
], function () {
Route::get('/health', [OtherController::class, 'healthcheck']);
});
Route::post('/feedback', [OtherController::class, 'feedback']);
Route::group([ Route::group([
'middleware' => ['auth:sanctum', 'api.ability:write'], 'middleware' => ['auth:sanctum', 'api.ability:write'],
'prefix' => 'v1', 'prefix' => 'v1',
@@ -117,7 +122,7 @@ Route::group([
Route::post('/services', [ServicesController::class, 'create_service'])->middleware(['api.ability:write']); Route::post('/services', [ServicesController::class, 'create_service'])->middleware(['api.ability:write']);
Route::get('/services/{uuid}', [ServicesController::class, 'service_by_uuid'])->middleware(['api.ability:read']); Route::get('/services/{uuid}', [ServicesController::class, 'service_by_uuid'])->middleware(['api.ability:read']);
Route::patch('/services/{uuid}', [ServicesController::class, 'update_by_uuid'])->middleware(['ability:write']); Route::patch('/services/{uuid}', [ServicesController::class, 'update_by_uuid'])->middleware(['api.ability:write']);
Route::delete('/services/{uuid}', [ServicesController::class, 'delete_by_uuid'])->middleware(['api.ability:write']); Route::delete('/services/{uuid}', [ServicesController::class, 'delete_by_uuid'])->middleware(['api.ability:write']);
Route::get('/services/{uuid}/envs', [ServicesController::class, 'envs'])->middleware(['api.ability:read']); Route::get('/services/{uuid}/envs', [ServicesController::class, 'envs'])->middleware(['api.ability:read']);

View File

@@ -6,7 +6,7 @@
services: services:
plausible: plausible:
image: "ghcr.io/plausible/community-edition:v2.1.4" image: "ghcr.io/plausible/community-edition:v3.0.1"
command: 'sh -c "sleep 10 && /entrypoint.sh db createdb && /entrypoint.sh db migrate && /entrypoint.sh run"' command: 'sh -c "sleep 10 && /entrypoint.sh db createdb && /entrypoint.sh db migrate && /entrypoint.sh run"'
environment: environment:
- SERVICE_FQDN_PLAUSIBLE - SERVICE_FQDN_PLAUSIBLE
@@ -17,13 +17,19 @@ services:
- TOTP_VAULT_KEY=${SERVICE_REALBASE64_32_TOTP} - TOTP_VAULT_KEY=${SERVICE_REALBASE64_32_TOTP}
- GOOGLE_CLIENT_ID=${GOOGLE_CLIENT_ID} - GOOGLE_CLIENT_ID=${GOOGLE_CLIENT_ID}
- GOOGLE_CLIENT_SECRET=${GOOGLE_CLIENT_SECRET} - GOOGLE_CLIENT_SECRET=${GOOGLE_CLIENT_SECRET}
- MAILER_ADAPTER=${MAILER_ADAPTER:-Bamboo.LocalAdapter}
- MAILER_EMAIL=${MAILER_EMAIL}
- MAILER_NAME=${MAILER_NAME}
- SMTP_HOST_ADDR=${SMTP_HOST_ADDR}
- SMTP_HOST_PORT=${SMTP_HOST_PORT}
- SMTP_USER_NAME=${SMTP_USER_NAME}
- SMTP_USER_PWD=${SMTP_USER_PWD}
- SMTP_HOST_SSL_ENABLED=${SMTP_HOST_SSL_ENABLED}
depends_on: depends_on:
plausible-db: plausible-db:
condition: service_healthy condition: service_healthy
plausible-events-db: plausible-events-db:
condition: service_healthy condition: service_healthy
mail:
condition: service_healthy
healthcheck: healthcheck:
test: test:
[ [
@@ -39,15 +45,6 @@ services:
retries: 5 retries: 5
start_period: 45s start_period: 45s
mail:
image: bytemark/smtp
platform: linux/amd64
healthcheck:
test: ["CMD-SHELL", "bash -c ':> /dev/tcp/127.0.0.1/25' || exit 1"]
interval: 5s
timeout: 10s
retries: 20
plausible-db: plausible-db:
image: "postgres:16-alpine" image: "postgres:16-alpine"
volumes: volumes:
@@ -63,7 +60,9 @@ services:
retries: 10 retries: 10
plausible-events-db: plausible-events-db:
image: "clickhouse/clickhouse-server:24.3.3.102-alpine" image: "clickhouse/clickhouse-server:24.12-alpine"
environment:
- CLICKHOUSE_SKIP_USER_SETUP=1
volumes: volumes:
- plausible-events-data:/var/lib/clickhouse - plausible-events-data:/var/lib/clickhouse
- type: bind - type: bind

View File

@@ -35,6 +35,8 @@ services:
unsend: unsend:
image: unsend/unsend:latest image: unsend/unsend:latest
expose:
- 3000
environment: environment:
- SERVICE_FQDN_UNSEND_3000 - SERVICE_FQDN_UNSEND_3000
- DATABASE_URL=postgresql://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@postgres:5432/${SERVICE_DB_POSTGRES:-unsend} - DATABASE_URL=postgresql://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@postgres:5432/${SERVICE_DB_POSTGRES:-unsend}
@@ -48,13 +50,14 @@ services:
- REDIS_URL=redis://redis:6379 - REDIS_URL=redis://redis:6379
- NEXT_PUBLIC_IS_CLOUD=${NEXT_PUBLIC_IS_CLOUD:-false} - NEXT_PUBLIC_IS_CLOUD=${NEXT_PUBLIC_IS_CLOUD:-false}
- API_RATE_LIMIT=${API_RATE_LIMIT:-1} - API_RATE_LIMIT=${API_RATE_LIMIT:-1}
- HOSTNAME=0.0.0.0
depends_on: depends_on:
postgres: postgres:
condition: service_healthy condition: service_healthy
redis: redis:
condition: service_healthy condition: service_healthy
healthcheck: healthcheck:
test: [ "CMD-SHELL", "wget -qO- http://127.0.0.1:3000 || exit 1" ] test: [ "CMD-SHELL", "wget -qO- http://unsend:3000 || exit 1" ]
interval: 5s interval: 5s
retries: 10 retries: 10
timeout: 2s timeout: 2s

View File

@@ -563,7 +563,7 @@
"minversion": "0.0.0", "minversion": "0.0.0",
"port": "8080" "port": "8080"
}, },
"denokv": { "denoKV": {
"documentation": "https://docs.deno.com/deploy/kv/manual/?utm_source=coolify.io", "documentation": "https://docs.deno.com/deploy/kv/manual/?utm_source=coolify.io",
"slogan": "The Denoland key-value database", "slogan": "The Denoland key-value database",
"compose": "c2VydmljZXM6CiAgZGVub2t2OgogICAgaW1hZ2U6ICdnaGNyLmlvL2Rlbm9sYW5kL2Rlbm9rdjpsYXRlc3QnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnQUNDRVNTX1RPS0VOPSR7U0VSVklDRV9QQVNTV09SRF9ERU5PS1Z9JwogICAgICAtIFNFUlZJQ0VfRlFETl9ERU5PS1ZfNDUxMgogICAgdm9sdW1lczoKICAgICAgLSAnJHtDT09MSUZZX1ZPTFVNRV9BUFB9Oi9kYXRhJwogICAgY29tbWFuZDogJy0tc3FsaXRlLXBhdGggL2RhdGEvZGVub2t2LnNxbGl0ZSBzZXJ2ZSAtLWFjY2Vzcy10b2tlbiAke1NFUlZJQ0VfUEFTU1dPUkRfREVOT0tWfScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBuYwogICAgICAgIC0gJy16dicKICAgICAgICAtIDEyNy4wLjAuMQogICAgICAgIC0gJzQ1MTInCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiA1cwogICAgICByZXRyaWVzOiAzCg==", "compose": "c2VydmljZXM6CiAgZGVub2t2OgogICAgaW1hZ2U6ICdnaGNyLmlvL2Rlbm9sYW5kL2Rlbm9rdjpsYXRlc3QnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnQUNDRVNTX1RPS0VOPSR7U0VSVklDRV9QQVNTV09SRF9ERU5PS1Z9JwogICAgICAtIFNFUlZJQ0VfRlFETl9ERU5PS1ZfNDUxMgogICAgdm9sdW1lczoKICAgICAgLSAnJHtDT09MSUZZX1ZPTFVNRV9BUFB9Oi9kYXRhJwogICAgY29tbWFuZDogJy0tc3FsaXRlLXBhdGggL2RhdGEvZGVub2t2LnNxbGl0ZSBzZXJ2ZSAtLWFjY2Vzcy10b2tlbiAke1NFUlZJQ0VfUEFTU1dPUkRfREVOT0tWfScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBuYwogICAgICAgIC0gJy16dicKICAgICAgICAtIDEyNy4wLjAuMQogICAgICAgIC0gJzQ1MTInCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiA1cwogICAgICByZXRyaWVzOiAzCg==",
@@ -3083,7 +3083,7 @@
"unsend": { "unsend": {
"documentation": "https://docs.unsend.dev/get-started/self-hosting?utm_source=coolify.io", "documentation": "https://docs.unsend.dev/get-started/self-hosting?utm_source=coolify.io",
"slogan": "Unsend is an open-source alternative to Resend, Sendgrid, Mailgun and Postmark etc.", "slogan": "Unsend is an open-source alternative to Resend, Sendgrid, Mailgun and Postmark etc.",
"compose": "c2VydmljZXM6CiAgcG9zdGdyZXM6CiAgICBpbWFnZTogJ3Bvc3RncmVzOjE2JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ1BPU1RHUkVTX1VTRVI9JHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9JwogICAgICAtICdQT1NUR1JFU19QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9JwogICAgICAtICdQT1NUR1JFU19EQj0ke1NFUlZJQ0VfREJfUE9TVEdSRVM6LXVuc2VuZH0nCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ3BnX2lzcmVhZHkgLVUgJCR7UE9TVEdSRVNfVVNFUn0gLWQgJCR7UE9TVEdSRVNfREJ9JwogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogMjBzCiAgICAgIHJldHJpZXM6IDEwCiAgICB2b2x1bWVzOgogICAgICAtICd1bnNlbmQtcG9zdGdyZXMtZGF0YTovdmFyL2xpYi9wb3N0Z3Jlc3FsL2RhdGEnCiAgcmVkaXM6CiAgICBpbWFnZTogJ3JlZGlzOjcnCiAgICB2b2x1bWVzOgogICAgICAtICd1bnNlbmQtcmVkaXMtZGF0YTovZGF0YScKICAgIGNvbW1hbmQ6CiAgICAgIC0gcmVkaXMtc2VydmVyCiAgICAgIC0gJy0tbWF4bWVtb3J5LXBvbGljeScKICAgICAgLSBub2V2aWN0aW9uCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gcmVkaXMtY2xpCiAgICAgICAgLSBQSU5HCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMjAKICB1bnNlbmQ6CiAgICBpbWFnZTogJ3Vuc2VuZC91bnNlbmQ6bGF0ZXN0JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX1VOU0VORF8zMDAwCiAgICAgIC0gJ0RBVEFCQVNFX1VSTD1wb3N0Z3Jlc3FsOi8vJHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9OiR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU31AcG9zdGdyZXM6NTQzMi8ke1NFUlZJQ0VfREJfUE9TVEdSRVM6LXVuc2VuZH0nCiAgICAgIC0gJ05FWFRBVVRIX1VSTD0ke1NFUlZJQ0VfRlFETl9VTlNFTkR9JwogICAgICAtICdORVhUQVVUSF9TRUNSRVQ9JHtTRVJWSUNFX0JBU0U2NF82NF9ORVhUQVVUSFNFQ1JFVH0nCiAgICAgIC0gJ0FXU19BQ0NFU1NfS0VZPSR7QVdTX0FDQ0VTU19LRVk6P30nCiAgICAgIC0gJ0FXU19TRUNSRVRfS0VZPSR7QVdTX1NFQ1JFVF9LRVk6P30nCiAgICAgIC0gJ0FXU19ERUZBVUxUX1JFR0lPTj0ke0FXU19ERUZBVUxUX1JFR0lPTjo/fScKICAgICAgLSAnR0lUSFVCX0lEPSR7R0lUSFVCX0lEfScKICAgICAgLSAnR0lUSFVCX1NFQ1JFVD0ke0dJVEhVQl9TRUNSRVR9JwogICAgICAtICdSRURJU19VUkw9cmVkaXM6Ly9yZWRpczo2Mzc5JwogICAgICAtICdORVhUX1BVQkxJQ19JU19DTE9VRD0ke05FWFRfUFVCTElDX0lTX0NMT1VEOi1mYWxzZX0nCiAgICAgIC0gJ0FQSV9SQVRFX0xJTUlUPSR7QVBJX1JBVEVfTElNSVQ6LTF9JwogICAgZGVwZW5kc19vbjoKICAgICAgcG9zdGdyZXM6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgICAgcmVkaXM6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAnd2dldCAtcU8tIGh0dHA6Ly8xMjcuMC4wLjE6MzAwMCB8fCBleGl0IDEnCiAgICAgIGludGVydmFsOiA1cwogICAgICByZXRyaWVzOiAxMAogICAgICB0aW1lb3V0OiAycwo=", "compose": "c2VydmljZXM6CiAgcG9zdGdyZXM6CiAgICBpbWFnZTogJ3Bvc3RncmVzOjE2JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ1BPU1RHUkVTX1VTRVI9JHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9JwogICAgICAtICdQT1NUR1JFU19QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9JwogICAgICAtICdQT1NUR1JFU19EQj0ke1NFUlZJQ0VfREJfUE9TVEdSRVM6LXVuc2VuZH0nCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ3BnX2lzcmVhZHkgLVUgJCR7UE9TVEdSRVNfVVNFUn0gLWQgJCR7UE9TVEdSRVNfREJ9JwogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogMjBzCiAgICAgIHJldHJpZXM6IDEwCiAgICB2b2x1bWVzOgogICAgICAtICd1bnNlbmQtcG9zdGdyZXMtZGF0YTovdmFyL2xpYi9wb3N0Z3Jlc3FsL2RhdGEnCiAgcmVkaXM6CiAgICBpbWFnZTogJ3JlZGlzOjcnCiAgICB2b2x1bWVzOgogICAgICAtICd1bnNlbmQtcmVkaXMtZGF0YTovZGF0YScKICAgIGNvbW1hbmQ6CiAgICAgIC0gcmVkaXMtc2VydmVyCiAgICAgIC0gJy0tbWF4bWVtb3J5LXBvbGljeScKICAgICAgLSBub2V2aWN0aW9uCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gcmVkaXMtY2xpCiAgICAgICAgLSBQSU5HCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMjAKICB1bnNlbmQ6CiAgICBpbWFnZTogJ3Vuc2VuZC91bnNlbmQ6bGF0ZXN0JwogICAgZXhwb3NlOgogICAgICAtIDMwMDAKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9VTlNFTkRfMzAwMAogICAgICAtICdEQVRBQkFTRV9VUkw9cG9zdGdyZXNxbDovLyR7U0VSVklDRV9VU0VSX1BPU1RHUkVTfToke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9QHBvc3RncmVzOjU0MzIvJHtTRVJWSUNFX0RCX1BPU1RHUkVTOi11bnNlbmR9JwogICAgICAtICdORVhUQVVUSF9VUkw9JHtTRVJWSUNFX0ZRRE5fVU5TRU5EfScKICAgICAgLSAnTkVYVEFVVEhfU0VDUkVUPSR7U0VSVklDRV9CQVNFNjRfNjRfTkVYVEFVVEhTRUNSRVR9JwogICAgICAtICdBV1NfQUNDRVNTX0tFWT0ke0FXU19BQ0NFU1NfS0VZOj99JwogICAgICAtICdBV1NfU0VDUkVUX0tFWT0ke0FXU19TRUNSRVRfS0VZOj99JwogICAgICAtICdBV1NfREVGQVVMVF9SRUdJT049JHtBV1NfREVGQVVMVF9SRUdJT046P30nCiAgICAgIC0gJ0dJVEhVQl9JRD0ke0dJVEhVQl9JRH0nCiAgICAgIC0gJ0dJVEhVQl9TRUNSRVQ9JHtHSVRIVUJfU0VDUkVUfScKICAgICAgLSAnUkVESVNfVVJMPXJlZGlzOi8vcmVkaXM6NjM3OScKICAgICAgLSAnTkVYVF9QVUJMSUNfSVNfQ0xPVUQ9JHtORVhUX1BVQkxJQ19JU19DTE9VRDotZmFsc2V9JwogICAgICAtICdBUElfUkFURV9MSU1JVD0ke0FQSV9SQVRFX0xJTUlUOi0xfScKICAgICAgLSBIT1NUTkFNRT0wLjAuMC4wCiAgICBkZXBlbmRzX29uOgogICAgICBwb3N0Z3JlczoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgICByZWRpczoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICd3Z2V0IC1xTy0gaHR0cDovL3Vuc2VuZDozMDAwIHx8IGV4aXQgMScKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHJldHJpZXM6IDEwCiAgICAgIHRpbWVvdXQ6IDJzCg==",
"tags": [ "tags": [
"resend", "resend",
"mailer", "mailer",

View File

@@ -1,10 +1,10 @@
{ {
"coolify": { "coolify": {
"v4": { "v4": {
"version": "4.0.0-beta.409" "version": "4.0.0-beta.410"
}, },
"nightly": { "nightly": {
"version": "4.0.0-beta.410" "version": "4.0.0-beta.411"
}, },
"helper": { "helper": {
"version": "1.0.8" "version": "1.0.8"