Merge branch 'next' into feat/add-http-basic-auth
This commit is contained in:
24
CHANGELOG.md
24
CHANGELOG.md
@@ -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
183
README.md
@@ -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
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
* [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 award–winning 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>
|
||||||
|
@@ -2562,10 +2562,6 @@ class ApplicationsController extends Controller
|
|||||||
])->setStatusCode(201);
|
])->setStatusCode(201);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json([
|
|
||||||
'message' => 'Something went wrong.',
|
|
||||||
], 500);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[OA\Delete(
|
#[OA\Delete(
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
|
@@ -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 {
|
||||||
|
@@ -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
|
||||||
|
@@ -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) {}
|
||||||
|
@@ -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
|
||||||
|
@@ -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) {}
|
||||||
|
@@ -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) {}
|
||||||
|
@@ -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();
|
||||||
|
@@ -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) {
|
||||||
|
@@ -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);
|
||||||
|
@@ -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;
|
||||||
|
@@ -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';
|
||||||
|
@@ -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');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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;
|
||||||
|
@@ -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(),
|
||||||
|
@@ -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),
|
||||||
|
@@ -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"
|
||||||
},
|
},
|
||||||
|
@@ -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:
|
||||||
|
@@ -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"
|
||||||
|
@@ -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>
|
||||||
|
@@ -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">
|
||||||
|
@@ -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>
|
||||||
|
@@ -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']);
|
||||||
|
@@ -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
|
||||||
|
@@ -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
|
||||||
|
@@ -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",
|
||||||
|
@@ -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"
|
||||||
|
Reference in New Issue
Block a user