From c6a2d1fe0ab8942bfc792e099f1804397e69fc3f Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Thu, 23 Oct 2025 10:07:33 +0200 Subject: [PATCH] Fix stale lock issue causing scheduled tasks to stop (#4539) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Problem Scheduled tasks, backups, and auto-updates stopped working after 1-2 months with error: MaxAttemptsExceededException: App\Jobs\ScheduledJobManager has been attempted too many times. Root cause: ScheduledJobManager used WithoutOverlapping with only releaseAfter(60), causing locks without expiration (TTL=-1) that persisted indefinitely when jobs hung or processes crashed. ## Solution ### Part 1: Prevention (Future Locks) - Added expireAfter(60) to ScheduledJobManager middleware - Lock now auto-expires after 60 seconds (matches everyMinute schedule) - Changed from releaseAfter(60) to expireAfter(60)->dontRelease() - Follows Laravel best practices and matches other Coolify jobs ### Part 2: Recovery (Existing Locks) - Enhanced cleanup:redis command with --clear-locks flag - Scans Redis for stale locks (TTL=-1) and removes them - Called automatically during app:init on startup/upgrade - Provides immediate recovery for affected instances ## Changes - app/Jobs/ScheduledJobManager.php: Added expireAfter(60)->dontRelease() - app/Console/Commands/CleanupRedis.php: Added cleanupCacheLocks() method - app/Console/Commands/Init.php: Auto-clear locks on startup - tests/Unit/ScheduledJobManagerLockTest.php: Test to prevent regression - STALE_LOCK_FIX.md: Complete documentation ## Testing - Unit tests pass (2 tests, 8 assertions) - Code formatted with Pint - Matches pattern used by CleanupInstanceStuffsJob 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- STALE_LOCK_FIX.md | 154 +++++++++++++++++++ app/Console/Commands/CleanupRedis.php | 64 +++++++- app/Console/Commands/Init.php | 2 +- app/Jobs/ScheduledJobManager.php | 3 +- templates/service-templates-latest.json | 171 +++++++++++++++++---- templates/service-templates.json | 171 +++++++++++++++++---- tests/Unit/ScheduledJobManagerLockTest.php | 60 ++++++++ 7 files changed, 557 insertions(+), 68 deletions(-) create mode 100644 STALE_LOCK_FIX.md create mode 100644 tests/Unit/ScheduledJobManagerLockTest.php diff --git a/STALE_LOCK_FIX.md b/STALE_LOCK_FIX.md new file mode 100644 index 000000000..c80eca76a --- /dev/null +++ b/STALE_LOCK_FIX.md @@ -0,0 +1,154 @@ +# Fix for Stale Lock Issue in ScheduledJobManager + +## Issue +GitHub Issue: #4539 - Scheduled tasks not executing on schedule + +### Symptoms +- Scheduled tasks stop executing after working for weeks/months +- Backups don't run +- Auto-updates don't work +- Error in Horizon: `Illuminate\Queue\MaxAttemptsExceededException: App\Jobs\ScheduledJobManager has been attempted too many times` +- Running `horizon:clear`, `cleanup:redis`, `schedule:clear-cache` doesn't fix the problem + +## Root Cause + +The `ScheduledJobManager` was using `WithoutOverlapping` middleware with only `releaseAfter(60)`: + +```php +(new WithoutOverlapping('scheduled-job-manager')) + ->releaseAfter(60) +``` + +**Problems with this approach:** + +1. **No automatic lock expiration**: Without `expireAfter()`, locks persist indefinitely if: + - Process hangs or becomes unresponsive + - Job takes longer than expected + - Unexpected termination occurs + +2. **Race condition with releaseAfter()**: + - Job acquires lock + - Job gets stuck/hangs + - After 60s, job is released back to queue + - New attempt can't acquire lock (still held by hung process) + - Repeats until MaxAttemptsExceededException + +3. **Against Laravel best practices**: Laravel docs explicitly recommend using `expireAfter()` to prevent stale locks + +## Solution + +This fix has two parts: + +### Part 1: Prevention (Fix Future Locks) + +Changed the middleware to match the pattern used by other Coolify jobs: + +```php +// File: app/Jobs/ScheduledJobManager.php +(new WithoutOverlapping('scheduled-job-manager')) + ->expireAfter(60) // Lock expires after 1 minute (matches job frequency) + ->dontRelease() // Don't re-queue on lock conflict +``` + +### Part 2: Recovery (Clear Existing Stale Locks) + +Enhanced `cleanup:redis` command to clear existing stale locks: + +```php +// File: app/Console/Commands/CleanupRedis.php +// Added --clear-locks flag +php artisan cleanup:redis --clear-locks +``` + +**What it does:** +- Scans Redis for `laravel-queue-overlap` keys (WithoutOverlapping locks) +- Checks TTL of each lock +- Deletes locks with TTL = -1 (no expiration = stale!) +- Skips active locks that have proper expiration +- Called automatically during `app:init` (on Coolify startup/update) + +### Why This Works + +✅ **Auto-expiring locks**: Lock automatically expires after 60 seconds, even if: + - Process crashes + - Job hangs + - Network issues occur + +✅ **No retry storms**: `dontRelease()` prevents failed jobs from being re-queued repeatedly + +✅ **Consistent pattern**: Matches other Coolify jobs like: + - `DockerCleanupJob`: `expireAfter(600)->dontRelease()` + - `ServerCheckJob`: `expireAfter(60)->dontRelease()` + - `RestartProxyJob`: `expireAfter(60)->dontRelease()` + +✅ **Laravel recommended**: Follows official Laravel documentation for preventing stale locks + +### Why 60 Seconds? + +- Job runs **every minute** (`everyMinute()` schedule) +- Matches the job frequency (1:1 ratio) +- Matches `CleanupInstanceStuffsJob` pattern (also runs frequently with 60s expiry) +- Allows next cycle to run if current job hangs +- Still reasonable timeout to prevent long-held locks + +## Testing + +### Manual Lock Key Inspection + +To check for locks in Redis: + +```bash +docker exec -it coolify-redis redis-cli +SELECT 0 +KEYS *laravel-queue-overlap*ScheduledJobManager* +``` + +Full key format: +``` +coolify_development_database_coolify_development_cache_laravel-queue-overlap:App\Jobs\ScheduledJobManager:scheduled-job-manager +``` + +Check TTL: +```bash +TTL "" +``` + +- `-1` = No expiration (STALE LOCK - the bug!) +- `-2` = Key doesn't exist +- Positive number = Seconds until expiration (GOOD!) + +### Testing the Fix + +Created test jobs to demonstrate the fix: +- `TestStaleLockJob.php` - Uses broken pattern (`releaseAfter` only) +- `TestFixedLockJob.php` - Uses fixed pattern (`expireAfter` + `dontRelease`) + +## Impact + +This fix will: +- ✅ **Immediate recovery**: Existing stale locks cleared on upgrade/restart +- ✅ **Future prevention**: New locks auto-expire, preventing issue recurrence +- ✅ **Self-recovery**: System can recover from transient issues automatically +- ✅ **Zero manual intervention**: No need for users to manually clear locks +- ✅ **Reliable operations**: Backups, tasks, and auto-updates run consistently + +## Files Modified + +1. **app/Jobs/ScheduledJobManager.php** + - Changed middleware to use `expireAfter(120)->dontRelease()` + +2. **app/Console/Commands/CleanupRedis.php** + - Added `--clear-locks` flag + - Added `cleanupCacheLocks()` method + +3. **app/Console/Commands/Init.php** + - Updated to call `cleanup:redis --clear-locks` on startup + +4. **tests/Unit/ScheduledJobManagerLockTest.php** + - New unit test to prevent regression + +## References + +- Laravel Docs: https://laravel.com/docs/12.x/queues#preventing-job-overlaps +- GitHub Issue: https://github.com/coollabsio/coolify/issues/4539 +- Related Pattern: All other Coolify jobs use `expireAfter()->dontRelease()` diff --git a/app/Console/Commands/CleanupRedis.php b/app/Console/Commands/CleanupRedis.php index a13cda0b8..9cbe221bf 100644 --- a/app/Console/Commands/CleanupRedis.php +++ b/app/Console/Commands/CleanupRedis.php @@ -7,9 +7,9 @@ class CleanupRedis extends Command { - protected $signature = 'cleanup:redis {--dry-run : Show what would be deleted without actually deleting} {--skip-overlapping : Skip overlapping queue cleanup}'; + protected $signature = 'cleanup:redis {--dry-run : Show what would be deleted without actually deleting} {--skip-overlapping : Skip overlapping queue cleanup} {--clear-locks : Clear stale WithoutOverlapping locks}'; - protected $description = 'Cleanup Redis (Horizon jobs, metrics, overlapping queues, and related data)'; + protected $description = 'Cleanup Redis (Horizon jobs, metrics, overlapping queues, cache locks, and related data)'; public function handle() { @@ -56,6 +56,13 @@ public function handle() $deletedCount += $overlappingCleaned; } + // Clean up stale cache locks (WithoutOverlapping middleware) + if ($this->option('clear-locks')) { + $this->info('Cleaning up stale cache locks...'); + $locksCleaned = $this->cleanupCacheLocks($dryRun); + $deletedCount += $locksCleaned; + } + if ($dryRun) { $this->info("DRY RUN: Would delete {$deletedCount} out of {$totalKeys} keys"); } else { @@ -273,4 +280,57 @@ private function deduplicateQueueContents($redis, $queueKey, $dryRun) return $cleanedCount; } + + private function cleanupCacheLocks(bool $dryRun): int + { + $cleanedCount = 0; + + // Use the default Redis connection (database 0) where cache locks are stored + $redis = Redis::connection('default'); + + // Get all keys matching WithoutOverlapping lock pattern + $allKeys = $redis->keys('*'); + $lockKeys = []; + + foreach ($allKeys as $key) { + // Match cache lock keys: they contain 'laravel-queue-overlap' + if (str_contains($key, 'laravel-queue-overlap')) { + $lockKeys[] = $key; + } + } + + if (empty($lockKeys)) { + $this->info(' No cache locks found.'); + + return 0; + } + + $this->info(' Found '.count($lockKeys).' cache lock(s)'); + + foreach ($lockKeys as $lockKey) { + // Check TTL to identify stale locks + $ttl = $redis->ttl($lockKey); + + // TTL = -1 means no expiration (stale lock!) + // TTL = -2 means key doesn't exist + // TTL > 0 means lock is valid and will expire + if ($ttl === -1) { + if ($dryRun) { + $this->warn(" Would delete STALE lock (no expiration): {$lockKey}"); + } else { + $redis->del($lockKey); + $this->info(" ✓ Deleted STALE lock: {$lockKey}"); + } + $cleanedCount++; + } elseif ($ttl > 0) { + $this->line(" Skipping active lock (expires in {$ttl}s): {$lockKey}"); + } + } + + if ($cleanedCount === 0) { + $this->info(' No stale locks found (all locks have expiration set)'); + } + + return $cleanedCount; + } } diff --git a/app/Console/Commands/Init.php b/app/Console/Commands/Init.php index 6e8d18f61..4bc818f0a 100644 --- a/app/Console/Commands/Init.php +++ b/app/Console/Commands/Init.php @@ -73,7 +73,7 @@ public function handle() $this->cleanupUnusedNetworkFromCoolifyProxy(); try { - $this->call('cleanup:redis'); + $this->call('cleanup:redis', ['--clear-locks' => true]); } catch (\Throwable $e) { echo "Error in cleanup:redis command: {$e->getMessage()}\n"; } diff --git a/app/Jobs/ScheduledJobManager.php b/app/Jobs/ScheduledJobManager.php index 18ca0008c..9937444b8 100644 --- a/app/Jobs/ScheduledJobManager.php +++ b/app/Jobs/ScheduledJobManager.php @@ -52,7 +52,8 @@ public function middleware(): array { return [ (new WithoutOverlapping('scheduled-job-manager')) - ->releaseAfter(60), // Release the lock after 60 seconds if job fails + ->expireAfter(60) // Lock expires after 1 minute to prevent stale locks + ->dontRelease(), // Don't re-queue on lock conflict ]; } diff --git a/templates/service-templates-latest.json b/templates/service-templates-latest.json index 7e4d63682..03ac03d1a 100644 --- a/templates/service-templates-latest.json +++ b/templates/service-templates-latest.json @@ -1730,6 +1730,25 @@ "minversion": "0.0.0", "port": "7575" }, + "home-assistant": { + "documentation": "https://www.home-assistant.io/installation/linux#docker-compose?utm_source=coolify.io", + "slogan": "Open source home automation that puts local control and privacy first.", + "compose": "c2VydmljZXM6CiAgaG9tZWFzc2lzdGFudDoKICAgIGltYWdlOiAnZ2hjci5pby9ob21lLWFzc2lzdGFudC9ob21lLWFzc2lzdGFudDoyMDI1LjEwLjInCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX1VSTF9IT01FQVNTSVNUQU5UXzgxMjMKICAgICAgLSAnVFo9JHtUWjotVVRDfScKICAgICAgLSAnRElTQUJMRV9KRU1BTExPQz0ke0RJU0FCTEVfSkVNQUxMT0M6LWZhbHNlfScKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2hvbWVhc3Npc3RhbnQtY29uZmlnOi9jb25maWcnCiAgICAgIC0gJy9ydW4vZGJ1czovcnVuL2RidXM6cm8nCiAgICAgIC0KICAgICAgICB0eXBlOiBiaW5kCiAgICAgICAgc291cmNlOiAuL2NvbmZpZ3VyYXRpb24ueWFtbAogICAgICAgIHRhcmdldDogL2NvbmZpZy9jb25maWd1cmF0aW9uLnlhbWwKICAgICAgICBjb250ZW50OiAiIyBMb2FkcyBkZWZhdWx0IHNldCBvZiBpbnRlZ3JhdGlvbnMuIERvIG5vdCByZW1vdmUuXG5kZWZhdWx0X2NvbmZpZzpcblxuIyBDb25maWd1cmF0aW9uIGZvciByZXZlcnNlIHByb3h5IHN1cHBvcnQgKHJlcXVpcmVkIGZvciBDb29saWZ5KVxuaHR0cDpcbiAgdXNlX3hfZm9yd2FyZGVkX2ZvcjogdHJ1ZVxuICB0cnVzdGVkX3Byb3hpZXM6XG4gICAgLSAxMC4wLjAuMC84XG4gICAgLSAxNzIuMTYuMC4wLzEyXG4gICAgLSAxOTIuMTY4LjAuMC8xNlxuICBpcF9iYW5fZW5hYmxlZDogdHJ1ZVxuICBsb2dpbl9hdHRlbXB0c190aHJlc2hvbGQ6IDUiCiAgICBwcml2aWxlZ2VkOiB0cnVlCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gY3VybAogICAgICAgIC0gJy1mJwogICAgICAgIC0gJ2h0dHA6Ly9sb2NhbGhvc3Q6ODEyMycKICAgICAgaW50ZXJ2YWw6IDMwcwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMwogICAgICBzdGFydF9wZXJpb2Q6IDYwcwo=", + "tags": [ + "home-automation", + "iot", + "smart-home", + "automation", + "domotics", + "mqtt", + "zigbee", + "zwave" + ], + "category": "automation", + "logo": "svgs/home-assistant.svg", + "minversion": "0.0.0", + "port": "8123" + }, "homebox": { "documentation": "https://github.com/sysadminsmedia/homebox?utm_source=coolify.io", "slogan": "Homebox is the inventory and organization system built for the Home User.", @@ -2440,6 +2459,23 @@ "minversion": "0.0.0", "port": "3000" }, + "metamcp": { + "documentation": "https://github.com/metatool-ai/metamcp?utm_source=coolify.io", + "slogan": "MCP Aggregator, Orchestrator, Middleware, Gateway in one app", + "compose": "c2VydmljZXM6CiAgYXBwOgogICAgaW1hZ2U6ICdnaGNyLmlvL21ldGF0b29sLWFpL21ldGFtY3A6Mi40JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9VUkxfTUVUQU1DUF8xMjAwOAogICAgICAtICdQT1NUR1JFU19IT1NUPSR7UE9TVEdSRVNfSE9TVDotcG9zdGdyZXN9JwogICAgICAtICdQT1NUR1JFU19QT1JUPSR7UE9TVEdSRVNfUE9SVDotNTQzMn0nCiAgICAgIC0gJ1BPU1RHUkVTX1VTRVI9JHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9JwogICAgICAtICdQT1NUR1JFU19QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9JwogICAgICAtICdQT1NUR1JFU19EQj0ke1BPU1RHUkVTX0RCOi1tZXRhbWNwX2RifScKICAgICAgLSAnREFUQUJBU0VfVVJMPXBvc3RncmVzcWw6Ly8ke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU306JHtTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTfUAke1BPU1RHUkVTX0hPU1Q6LXBvc3RncmVzfToke1BPU1RHUkVTX1BPUlQ6LTU0MzJ9LyR7UE9TVEdSRVNfREI6LW1ldGFtY3BfZGJ9JwogICAgICAtICdBUFBfVVJMPSR7U0VSVklDRV9VUkxfTUVUQU1DUH0nCiAgICAgIC0gJ05FWFRfUFVCTElDX0FQUF9VUkw9JHtTRVJWSUNFX1VSTF9NRVRBTUNQfScKICAgICAgLSAnQkVUVEVSX0FVVEhfU0VDUkVUPSR7U0VSVklDRV9QQVNTV09SRF9BVVRIfScKICAgICAgLSAnVFJBTlNGT1JNX0xPQ0FMSE9TVF9UT19ET0NLRVJfSU5URVJOQUw9JHtUUkFOU0ZPUk1fTE9DQUxIT1NUX1RPX0RPQ0tFUl9JTlRFUk5BTDotdHJ1ZX0nCiAgICBkZXBlbmRzX29uOgogICAgICBwb3N0Z3JlczoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIGN1cmwKICAgICAgICAtICctZicKICAgICAgICAtICdodHRwOi8vbG9jYWxob3N0OjEyMDA4L2hlYWx0aCcKICAgICAgaW50ZXJ2YWw6IDEwcwogICAgICB0aW1lb3V0OiA1cwogICAgICByZXRyaWVzOiA1CiAgcG9zdGdyZXM6CiAgICBpbWFnZTogJ3Bvc3RncmVzOjE2LWFscGluZScKICAgIGVudmlyb25tZW50OgogICAgICAtICdQT1NUR1JFU19EQj0ke1BPU1RHUkVTX0RCOi1tZXRhbWNwX2RifScKICAgICAgLSAnUE9TVEdSRVNfVVNFUj0ke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU30nCiAgICAgIC0gJ1BPU1RHUkVTX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU30nCiAgICB2b2x1bWVzOgogICAgICAtICdwb3N0Z3Jlc19kYXRhOi92YXIvbGliL3Bvc3RncmVzcWwvZGF0YScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAncGdfaXNyZWFkeSAtVSAke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU30gLWQgJHtQT1NUR1JFU19EQjotbWV0YW1jcF9kYn0nCiAgICAgIGludGVydmFsOiAxMHMKICAgICAgdGltZW91dDogNXMKICAgICAgcmV0cmllczogNQo=", + "tags": [ + "mcp", + "ai", + "sse", + "aggregator", + "orchestrator", + "middleware" + ], + "category": "mcp", + "logo": "svgs/metamcp.png", + "minversion": "0.0.0", + "port": "12008" + }, "metube": { "documentation": "https://github.com/alexta69/metube?utm_source=coolify.io", "slogan": "A web GUI for youtube-dl with playlist support. It enables you to effortlessly download videos from YouTube and dozens of other sites.", @@ -3218,38 +3254,6 @@ "minversion": "0.0.0", "port": "80" }, - "pingvinshare-with-clamav": { - "documentation": "https://github.com/stonith404/pingvin-share?utm_source=coolify.io", - "slogan": "A self-hosted file sharing platform that combines lightness and beauty, perfect for seamless and efficient file sharing.", - "compose": "c2VydmljZXM6CiAgcGluZ3ZpbnNoYXJlOgogICAgaW1hZ2U6IGdoY3IuaW8vc3Rvbml0aDQwNC9waW5ndmluLXNoYXJlCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX1VSTF9QSU5HVklOU0hBUkVfMzAwMAogICAgICAtICdUUlVTVF9QUk9YWT0ke1RSVVNUX1BST1hZOi10cnVlfScKICAgIHZvbHVtZXM6CiAgICAgIC0gJ3Bpbmd2aW5zaGFyZV9kYXRhOi9vcHQvYXBwL2JhY2tlbmQvZGF0YScKICAgICAgLSAncGluZ3ZpbnNoYXJlX2ltYWdlczovb3B0L2FwcC9mcm9udGVuZC9wdWJsaWMvaW1nJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICd3Z2V0IC0tcXVpZXQgLS10cmllcz0xIC0tc3BpZGVyIGh0dHA6Ly9sb2NhbGhvc3Q6MzAwMC9hcGkvaGVhbHRoIHx8IGV4aXQgMScKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDIwcwogICAgICByZXRyaWVzOiAxMAogICAgZGVwZW5kc19vbjoKICAgICAgY2xhbWF2OgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgY2xhbWF2OgogICAgaW1hZ2U6IGNsYW1hdi9jbGFtYXYKICAgIHBsYXRmb3JtOiBsaW51eC9hbWQ2NAo=", - "tags": [ - "self-hosted", - "file-sharing", - "files", - "cloud", - "sharing" - ], - "category": "storage", - "logo": "svgs/pingvinshare.svg", - "minversion": "0.0.0", - "port": "3000" - }, - "pingvinshare": { - "documentation": "https://github.com/stonith404/pingvin-share?utm_source=coolify.io", - "slogan": "A self-hosted file sharing platform that combines lightness and beauty, perfect for seamless and efficient file sharing.", - "compose": "c2VydmljZXM6CiAgcGluZ3ZpbnNoYXJlOgogICAgaW1hZ2U6IGdoY3IuaW8vc3Rvbml0aDQwNC9waW5ndmluLXNoYXJlCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX1VSTF9QSU5HVklOU0hBUkVfMzAwMAogICAgICAtICdUUlVTVF9QUk9YWT0ke1RSVVNUX1BST1hZOi10cnVlfScKICAgIHZvbHVtZXM6CiAgICAgIC0gJ3Bpbmd2aW5zaGFyZV9kYXRhOi9vcHQvYXBwL2JhY2tlbmQvZGF0YScKICAgICAgLSAncGluZ3ZpbnNoYXJlX2ltYWdlczovb3B0L2FwcC9mcm9udGVuZC9wdWJsaWMvaW1nJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICd3Z2V0IC0tcXVpZXQgLS10cmllcz0xIC0tc3BpZGVyIGh0dHA6Ly9sb2NhbGhvc3Q6MzAwMC9hcGkvaGVhbHRoIHx8IGV4aXQgMScKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDIwcwogICAgICByZXRyaWVzOiAxMAo=", - "tags": [ - "self-hosted", - "file-sharing", - "files", - "cloud", - "sharing" - ], - "category": "storage", - "logo": "svgs/pingvinshare.svg", - "minversion": "0.0.0", - "port": "3000" - }, "plane": { "documentation": "https://docs.plane.so/self-hosting/methods/docker-compose?utm_source=coolify.io", "slogan": "The open source project management tool", @@ -3302,6 +3306,45 @@ "minversion": "0.0.0", "port": "3000" }, + "pocket-id-with-postgresql": { + "documentation": "https://pocket-id.org/docs/setup/installation?utm_source=coolify.io", + "slogan": "A simple and secure OIDC provider with passkey authentication", + "compose": "c2VydmljZXM6CiAgcG9ja2V0LWlkOgogICAgaW1hZ2U6ICdnaGNyLmlvL3BvY2tldC1pZC9wb2NrZXQtaWQ6djEuMTMnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX1VSTF9QT0NLRVRJRF8xNDExCiAgICAgIC0gJ0FQUF9VUkw9JHtTRVJWSUNFX1VSTF9QT0NLRVRJRH0nCiAgICAgIC0gJ1RSVVNUX1BST1hZPSR7VFJVU1RfUFJPWFk6LXRydWV9JwogICAgICAtIERCX1BST1ZJREVSPXBvc3RncmVzCiAgICAgIC0gJ0RCX0NPTk5FQ1RJT05fU1RSSU5HPXBvc3RncmVzcWw6Ly8ke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU1FMfToke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVNRTH1AcG9zdGdyZXNxbDo1NDMyLyR7UE9TVEdSRVNfREI6LXBvY2tldGlkfScKICAgICAgLSAnRU5DUllQVElPTl9LRVk9JHtTRVJWSUNFX1BBU1NXT1JEXzY0X1BPQ0tFVElEfScKICAgICAgLSAnS0VZU19TVE9SQUdFPSR7S0VZU19TVE9SQUdFOi1kYXRhYmFzZX0nCiAgICAgIC0gJ01BWE1JTkRfTElDRU5TRV9LRVk9JHtNQVhNSU5EX0xJQ0VOU0VfS0VZfScKICAgICAgLSAnU01UUF9IT1NUPSR7U01UUF9IT1NUfScKICAgICAgLSAnU01UUF9QT1JUPSR7U01UUF9QT1JUOi01ODd9JwogICAgICAtICdTTVRQX0ZST009JHtTTVRQX0ZST019JwogICAgICAtICdTTVRQX1VTRVI9JHtTTVRQX1VTRVJ9JwogICAgICAtICdTTVRQX1BBU1NXT1JEPSR7U01UUF9QQVNTV09SRH0nCiAgICAgIC0gJ1NNVFBfVExTPSR7U01UUF9UTFM6LXN0YXJ0dGxzfScKICAgICAgLSAnU01UUF9TS0lQX0NFUlRfVkVSSUZZPSR7U01UUF9TS0lQX0NFUlRfVkVSSUZZOi1mYWxzZX0nCiAgICAgIC0gJ0VNQUlMX0xPR0lOX05PVElGSUNBVElPTl9FTkFCTEVEPSR7RU1BSUxfTE9HSU5fTk9USUZJQ0FUSU9OX0VOQUJMRUQ6LWZhbHNlfScKICAgICAgLSAnRU1BSUxfT05FX1RJTUVfQUNDRVNTX0FTX0FETUlOX0VOQUJMRUQ9JHtFTUFJTF9PTkVfVElNRV9BQ0NFU1NfQVNfQURNSU5fRU5BQkxFRDotZmFsc2V9JwogICAgICAtICdFTUFJTF9BUElfS0VZX0VYUElSQVRJT05fRU5BQkxFRD0ke0VNQUlMX0FQSV9LRVlfRVhQSVJBVElPTl9FTkFCTEVEOi1mYWxzZX0nCiAgICAgIC0gJ1BVSUQ9JHtQVUlEOi0xMDAwfScKICAgICAgLSAnUEdJRD0ke1BHSUQ6LTEwMDB9JwogICAgdm9sdW1lczoKICAgICAgLSAncG9ja2V0LWlkLWRhdGE6L2FwcC9kYXRhJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIC9hcHAvcG9ja2V0LWlkCiAgICAgICAgLSBoZWFsdGhjaGVjawogICAgICBpbnRlcnZhbDogMzBzCiAgICAgIHRpbWVvdXQ6IDVzCiAgICAgIHJldHJpZXM6IDMKICAgICAgc3RhcnRfcGVyaW9kOiAxMHMKICAgIGRlcGVuZHNfb246CiAgICAgIHBvc3RncmVzcWw6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICBwb3N0Z3Jlc3FsOgogICAgaW1hZ2U6ICdwb3N0Z3JlczoxNi1hbHBpbmUnCiAgICB2b2x1bWVzOgogICAgICAtICdwb2NrZXQtaWQtcG9zdGdyZXNxbC1kYXRhOi92YXIvbGliL3Bvc3RncmVzcWwvZGF0YScKICAgIGVudmlyb25tZW50OgogICAgICAtICdQT1NUR1JFU19VU0VSPSR7U0VSVklDRV9VU0VSX1BPU1RHUkVTUUx9JwogICAgICAtICdQT1NUR1JFU19QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVNRTH0nCiAgICAgIC0gJ1BPU1RHUkVTX0RCPSR7UE9TVEdSRVNfREI6LXBvY2tldGlkfScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAncGdfaXNyZWFkeSAtVSAkJHtQT1NUR1JFU19VU0VSfSAtZCAkJHtQT1NUR1JFU19EQn0nCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiAyMHMKICAgICAgcmV0cmllczogMTAK", + "tags": [ + "identity", + "oidc", + "oauth", + "passkey", + "webauthn", + "authentication", + "sso", + "openid", + "postgresql" + ], + "category": "auth", + "logo": "svgs/pocketid-logo.png", + "minversion": "0.0.0", + "port": "1411" + }, + "pocket-id": { + "documentation": "https://pocket-id.org/docs/setup/installation?utm_source=coolify.io", + "slogan": "A simple and secure OIDC provider with passkey authentication", + "compose": "c2VydmljZXM6CiAgcG9ja2V0LWlkOgogICAgaW1hZ2U6ICdnaGNyLmlvL3BvY2tldC1pZC9wb2NrZXQtaWQ6djEuMTMnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX1VSTF9QT0NLRVRJRF8xNDExCiAgICAgIC0gJ0FQUF9VUkw9JHtTRVJWSUNFX1VSTF9QT0NLRVRJRH0nCiAgICAgIC0gJ1RSVVNUX1BST1hZPSR7VFJVU1RfUFJPWFk6LXRydWV9JwogICAgICAtICdNQVhNSU5EX0xJQ0VOU0VfS0VZPSR7TUFYTUlORF9MSUNFTlNFX0tFWX0nCiAgICAgIC0gJ1NNVFBfSE9TVD0ke1NNVFBfSE9TVH0nCiAgICAgIC0gJ1NNVFBfUE9SVD0ke1NNVFBfUE9SVDotNTg3fScKICAgICAgLSAnU01UUF9GUk9NPSR7U01UUF9GUk9NfScKICAgICAgLSAnU01UUF9VU0VSPSR7U01UUF9VU0VSfScKICAgICAgLSAnU01UUF9QQVNTV09SRD0ke1NNVFBfUEFTU1dPUkR9JwogICAgICAtICdTTVRQX1RMUz0ke1NNVFBfVExTOi1zdGFydHRsc30nCiAgICAgIC0gJ1NNVFBfU0tJUF9DRVJUX1ZFUklGWT0ke1NNVFBfU0tJUF9DRVJUX1ZFUklGWTotZmFsc2V9JwogICAgICAtICdFTUFJTF9MT0dJTl9OT1RJRklDQVRJT05fRU5BQkxFRD0ke0VNQUlMX0xPR0lOX05PVElGSUNBVElPTl9FTkFCTEVEOi1mYWxzZX0nCiAgICAgIC0gJ0VNQUlMX09ORV9USU1FX0FDQ0VTU19BU19BRE1JTl9FTkFCTEVEPSR7RU1BSUxfT05FX1RJTUVfQUNDRVNTX0FTX0FETUlOX0VOQUJMRUQ6LWZhbHNlfScKICAgICAgLSAnRU1BSUxfQVBJX0tFWV9FWFBJUkFUSU9OX0VOQUJMRUQ9JHtFTUFJTF9BUElfS0VZX0VYUElSQVRJT05fRU5BQkxFRDotZmFsc2V9JwogICAgICAtICdQVUlEPSR7UFVJRDotMTAwMH0nCiAgICAgIC0gJ1BHSUQ9JHtQR0lEOi0xMDAwfScKICAgIHZvbHVtZXM6CiAgICAgIC0gJ3BvY2tldC1pZC1kYXRhOi9hcHAvZGF0YScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSAvYXBwL3BvY2tldC1pZAogICAgICAgIC0gaGVhbHRoY2hlY2sKICAgICAgaW50ZXJ2YWw6IDMwcwogICAgICB0aW1lb3V0OiA1cwogICAgICByZXRyaWVzOiAzCiAgICAgIHN0YXJ0X3BlcmlvZDogMTBzCg==", + "tags": [ + "identity", + "oidc", + "oauth", + "passkey", + "webauthn", + "authentication", + "sso", + "openid" + ], + "category": "auth", + "logo": "svgs/pocketid-logo.png", + "minversion": "0.0.0", + "port": "1411" + }, "pocketbase": { "documentation": "https://pocketbase.io/docs/?utm_source=coolify.io", "slogan": "Open Source backend for your next SaaS and Mobile app in 1 file", @@ -3554,6 +3597,22 @@ "minversion": "0.0.0", "port": "8000" }, + "redis-insight": { + "documentation": "https://redis.io/docs/latest/operate/redisinsight/?utm_source=coolify.io", + "slogan": "Redis Insight lets you do both GUI- and CLI-based interactions in a fully-featured desktop GUI client.", + "compose": "c2VydmljZXM6CiAgcmVkaXNpbnNpZ2h0OgogICAgaW1hZ2U6ICdyZWRpcy9yZWRpc2luc2lnaHQ6Mi43MCcKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfVVJMX1JFRElTSU5TSUdIVF81NTQwCiAgICAgIC0gUklfQVBQX0hPU1Q9MC4wLjAuMAogICAgICAtIFJJX0FQUF9QT1JUPTU1NDAKICAgICAgLSAnUklfRU5DUllQVElPTl9LRVk9JHtTRVJWSUNFX1BBU1NXT1JEX1JJX0VOQ1JZUFRJT05fS0VZfScKICAgICAgLSAnUklfTE9HX0xFVkVMPSR7UklfTE9HX0xFVkVMOi1pbmZvfScKICAgICAgLSAnUklfRklMRVNfTE9HR0VSPSR7UklfRklMRVNfTE9HR0VSOi10cnVlfScKICAgICAgLSAnUklfU1RET1VUX0xPR0dFUj0ke1JJX1NURE9VVF9MT0dHRVI6LXRydWV9JwogICAgdm9sdW1lczoKICAgICAgLSAncmVkaXNfaW5zaWdodF9kYXRhOi9kYXRhJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIHdnZXQKICAgICAgICAtICctLXNwaWRlcicKICAgICAgICAtICdodHRwOi8vbG9jYWxob3N0OjU1NDAnCiAgICAgIGludGVydmFsOiAxMHMKICAgICAgcmV0cmllczogMwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgc3RhcnRfcGVyaW9kOiAxMHMK", + "tags": [ + "redis", + "gui", + "database", + "monitoring", + "analytics" + ], + "category": "database,observability,developer-tools", + "logo": "svgs/redisinsight.png", + "minversion": "0.0.0", + "port": "5540" + }, "redlib": { "documentation": "https://github.com/redlib-org/redlib?utm_source=coolify.io", "slogan": "An alternative private front-end to Reddit, with its origins in Libreddit.", @@ -3567,6 +3626,23 @@ "minversion": "0.0.0", "port": "8080" }, + "rivet-engine": { + "documentation": "https://www.rivet.dev/docs?utm_source=coolify.io", + "slogan": "Build and scale stateful workloads with long-lived processes", + "compose": "c2VydmljZXM6CiAgcml2ZXQtZW5naW5lOgogICAgaW1hZ2U6ICdyaXZldGtpdC9lbmdpbmU6MjUuOC4wJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9VUkxfUklWRVRfNjQyMAogICAgICAtICdSSVZFVF9fQVVUSF9fQURNSU5fVE9LRU49JHtTRVJWSUNFX1BBU1NXT1JEX1JJVkVUfScKICAgICAgLSAnUklWRVRfX1BPU1RHUkVTX19VUkw9cG9zdGdyZXNxbDovLyRTRVJWSUNFX1VTRVJfUE9TVEdSRVNRTDokU0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU1FMQHBvc3RncmVzcWw6NTQzMi8ke1BPU1RHUkVTUUxfREFUQUJBU0Utcml2ZXR9JwogICAgZGVwZW5kc19vbjoKICAgICAgcG9zdGdyZXNxbDoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIGN1cmwKICAgICAgICAtICctZicKICAgICAgICAtICdodHRwOi8vMTI3LjAuMC4xOjY0MjAvaGVhbHRoJwogICAgICBpbnRlcnZhbDogMnMKICAgICAgdGltZW91dDogMTBzCiAgICAgIHJldHJpZXM6IDEwCiAgICAgIHN0YXJ0X3BlcmlvZDogMzBzCiAgcG9zdGdyZXNxbDoKICAgIGltYWdlOiAncG9zdGdyZXM6MTctYWxwaW5lJwogICAgdm9sdW1lczoKICAgICAgLSAncml2ZXQtcG9zdGdyZXNxbC1kYXRhOi92YXIvbGliL3Bvc3RncmVzcWwvZGF0YScKICAgIGVudmlyb25tZW50OgogICAgICAtICdQT1NUR1JFU19VU0VSPSR7U0VSVklDRV9VU0VSX1BPU1RHUkVTUUx9JwogICAgICAtICdQT1NUR1JFU19QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVNRTH0nCiAgICAgIC0gJ1BPU1RHUkVTX0RCPSR7UE9TVEdSRVNRTF9EQVRBQkFTRS1yaXZldH0nCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ3BnX2lzcmVhZHkgLVUgJCR7UE9TVEdSRVNfVVNFUn0gLWQgJCR7UE9TVEdSRVNfREJ9JwogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogMjBzCiAgICAgIHJldHJpZXM6IDEwCg==", + "tags": [ + "stateful", + "actors", + "realtime", + "backend", + "serverless", + "postgresql" + ], + "category": "development", + "logo": "svgs/rivet.svg", + "minversion": "0.0.0", + "port": "6420" + }, "rocketchat": { "documentation": "https://github.com/RocketChat/Rocket.Chat?utm_source=coolify.io", "slogan": "Self-hosted, secure and highly customizable open-source communication platform for organizations with sophisticated security and privacy concerns.", @@ -3706,6 +3782,20 @@ "minversion": "0.0.0", "port": "8080" }, + "siyuan": { + "documentation": "https://github.com/siyuan-note/siyuan?utm_source=coolify.io", + "slogan": "A privacy-first, self-hosted, fully open source personal knowledge management software, written in typescript and golang.", + "compose": "c2VydmljZXM6CiAgc2l5dWFuOgogICAgaW1hZ2U6ICdiM2xvZy9zaXl1YW46djMuMy41JwogICAgdm9sdW1lczoKICAgICAgLSAnc2l5dWFuX3dvcmtzcGFjZTovc2l5dWFuL3dvcmtzcGFjZScKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfVVJMX1NJWVVBTl82ODA2CiAgICAgIC0gJ1RaPSR7VFo6LVVUQ30nCiAgICAgIC0gUFVJRD0xMDAwCiAgICAgIC0gUEdJRD0xMDAwCiAgICAgIC0gJ1NJWVVBTl9BQ0NFU1NfQVVUSF9DT0RFPSR7U0VSVklDRV9QQVNTV09SRF9TSVlVQU59JwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIHdnZXQKICAgICAgICAtICctLXNwaWRlcicKICAgICAgICAtICctLXF1aWV0JwogICAgICAgIC0gJ2h0dHA6Ly8xMjcuMC4wLjE6NjgwNi9hcGkvc3lzdGVtL3ZlcnNpb24nCiAgICAgIGludGVydmFsOiAxNXMKICAgICAgdGltZW91dDogMTBzCiAgICAgIHJldHJpZXM6IDUKICAgICAgc3RhcnRfcGVyaW9kOiAyMHMK", + "tags": [ + "note-taking", + "markdown", + "pkm" + ], + "category": null, + "logo": "svgs/siyuan.svg", + "minversion": "0.0.0", + "port": "6806" + }, "slash": { "documentation": "https://github.com/yourselfhosted/slash?utm_source=coolify.io", "slogan": "An open source, self-hosted links shortener and sharing platform.", @@ -3769,6 +3859,23 @@ "minversion": "0.0.0", "port": "8989" }, + "sparkyfitness": { + "documentation": "https://codewithcj.github.io/SparkyFitness/?utm_source=coolify.io", + "slogan": "SparkyFitness is a comprehensive fitness tracking and management application designed to help users monitor their nutrition, exercise, and body measurements. It provides tools for daily progress tracking, goal setting, and insightful reports to support a healthy lifestyle.", + "compose": "c2VydmljZXM6CiAgc3Bhcmt5Zml0bmVzcy1mcm9udGVuZDoKICAgIGltYWdlOiAnY29kZXdpdGhjai9zcGFya3lmaXRuZXNzOnYwLjE1LjcuMycKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfVVJMX1NQQVJLWUZJVE5FU1NfODAKICAgIGRlcGVuZHNfb246CiAgICAgIC0gc3Bhcmt5Zml0bmVzcy1zZXJ2ZXIKICBzcGFya3lmaXRuZXNzLXNlcnZlcjoKICAgIGltYWdlOiAnY29kZXdpdGhjai9zcGFya3lmaXRuZXNzX3NlcnZlcjp2MC4xNS43LjMnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnU1BBUktZX0ZJVE5FU1NfTE9HX0xFVkVMPSR7U1BBUktZX0ZJVE5FU1NfTE9HX0xFVkVMOi1pbmZvfScKICAgICAgLSAnU1BBUktZX0ZJVE5FU1NfREJfVVNFUj0ke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU30nCiAgICAgIC0gU1BBUktZX0ZJVE5FU1NfREJfSE9TVD1zcGFya3lmaXRuZXNzLWRiCiAgICAgIC0gJ1NQQVJLWV9GSVRORVNTX0RCX05BTUU9JHtTUEFSS1lfRklUTkVTU19EQl9OQU1FOi1zcGFya3lmaXRuZXNzfScKICAgICAgLSAnU1BBUktZX0ZJVE5FU1NfREJfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTfScKICAgICAgLSAnU1BBUktZX0ZJVE5FU1NfREJfUE9SVD0ke1NQQVJLWV9GSVRORVNTX0RCX1BPUlQ6LTU0MzJ9JwogICAgICAtICdTUEFSS1lfRklUTkVTU19BUElfRU5DUllQVElPTl9LRVk9JHtTRVJWSUNFX1BBU1NXT1JEXzY0X1NFUlZFUkFQSUVOQ1JZUFRJT05LRVl9JwogICAgICAtICdKV1RfU0VDUkVUPSR7U0VSVklDRV9QQVNTV09SRF82NF9TRVJWRVJKV1RTRUNSRVR9JwogICAgICAtICdTUEFSS1lfRklUTkVTU19GUk9OVEVORF9VUkw9JHtTRVJWSUNFX1VSTF9TUEFSS1lGSVRORVNTXzgwfScKICAgICAgLSAnU1BBUktZX0ZJVE5FU1NfRElTQUJMRV9TSUdOVVA9JHtTUEFSS1lfRklUTkVTU19ESVNBQkxFX1NJR05VUDotZmFsc2V9JwogICAgICAtICdTUEFSS1lfRklUTkVTU19BRE1JTl9FTUFJTD0ke1NQQVJLWV9GSVRORVNTX0FETUlOX0VNQUlMOi1hZG1pbkBleGFtcGxlLmNvbX0nCiAgICAgIC0gJ1NQQVJLWV9GSVRORVNTX0VNQUlMX0hPU1Q9JHtTUEFSS1lfRklUTkVTU19FTUFJTF9IT1NUOi1zbXRwLmdtYWlsLmNvbX0nCiAgICAgIC0gJ1NQQVJLWV9GSVRORVNTX0VNQUlMX1BPUlQ9JHtTUEFSS1lfRklUTkVTU19FTUFJTF9QT1JUOi01ODd9JwogICAgICAtICdTUEFSS1lfRklUTkVTU19FTUFJTF9TRUNVUkU9JHtTUEFSS1lfRklUTkVTU19FTUFJTF9TRUNVUkU6LWZhbHNlfScKICAgICAgLSAnU1BBUktZX0ZJVE5FU1NfRU1BSUxfVVNFUj0ke1NQQVJLWV9GSVRORVNTX0VNQUlMX1VTRVJ9JwogICAgICAtICdTUEFSS1lfRklUTkVTU19FTUFJTF9QQVNTPSR7U1BBUktZX0ZJVE5FU1NfRU1BSUxfUEFTU30nCiAgICAgIC0gJ1NQQVJLWV9GSVRORVNTX0VNQUlMX0ZST009JHtTUEFSS1lfRklUTkVTU19FTUFJTF9GUk9NOi0iU3Bhcmt5IEZpdG5lc3MgPG5vcmVwbHlAc3Bhcmt5Zml0bmVzcy5jb20+In0nCiAgICBkZXBlbmRzX29uOgogICAgICAtIHNwYXJreWZpdG5lc3MtZGIKICAgIHZvbHVtZXM6CiAgICAgIC0gJ3NwYXJreWZpdG5lc3Mtc2VydmVyLWJhY2t1cDovYXBwL1NwYXJreUZpdG5lc3NTZXJ2ZXIvYmFja3VwJwogICAgICAtICdzcGFya3lmaXRuZXNzLXNlcnZlci11cGxvYWRzOi9hcHAvU3Bhcmt5Rml0bmVzc1NlcnZlci91cGxvYWRzJwogIHNwYXJreWZpdG5lc3MtZGI6CiAgICBpbWFnZTogJ3Bvc3RncmVzOjE1LWFscGluZScKICAgIGVudmlyb25tZW50OgogICAgICAtICdQT1NUR1JFU19EQj0ke1NQQVJLWV9GSVRORVNTX0RCX05BTUU6LXNwYXJreWZpdG5lc3N9JwogICAgICAtICdQT1NUR1JFU19VU0VSPSR7U0VSVklDRV9VU0VSX1BPU1RHUkVTfScKICAgICAgLSAnUE9TVEdSRVNfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTfScKICAgICAgLSAnUE9TVEdSRVNfUE9SVD0ke1NQQVJLWV9GSVRORVNTX0RCX1BPUlQ6LTU0MzJ9JwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICdwZ19pc3JlYWR5IC1VICQke1BPU1RHUkVTX1VTRVJ9IC1kICQke1BPU1RHUkVTX0RCfScKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDIwcwogICAgICByZXRyaWVzOiAxMAogICAgdm9sdW1lczoKICAgICAgLSAnc3Bhcmt5Zml0bmVzcy1kYi1wb3N0Z3Jlc3FsOi92YXIvbGliL3Bvc3RncmVzcWwvZGF0YScK", + "tags": [ + "sparkyfitness", + "fitness", + "health", + "nutrition", + "exercise", + "body measurements" + ], + "category": "health", + "logo": "svgs/sparkyfitness.svg", + "minversion": "0.0.0", + "port": "80" + }, "statusnook": { "documentation": "https://statusnook.com?utm_source=coolify.io", "slogan": "Effortlessly deploy a status page and start monitoring endpoints in minutes", diff --git a/templates/service-templates.json b/templates/service-templates.json index 45c31583f..4dcc3140b 100644 --- a/templates/service-templates.json +++ b/templates/service-templates.json @@ -1730,6 +1730,25 @@ "minversion": "0.0.0", "port": "7575" }, + "home-assistant": { + "documentation": "https://www.home-assistant.io/installation/linux#docker-compose?utm_source=coolify.io", + "slogan": "Open source home automation that puts local control and privacy first.", + "compose": "c2VydmljZXM6CiAgaG9tZWFzc2lzdGFudDoKICAgIGltYWdlOiAnZ2hjci5pby9ob21lLWFzc2lzdGFudC9ob21lLWFzc2lzdGFudDoyMDI1LjEwLjInCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX0ZRRE5fSE9NRUFTU0lTVEFOVF84MTIzCiAgICAgIC0gJ1RaPSR7VFo6LVVUQ30nCiAgICAgIC0gJ0RJU0FCTEVfSkVNQUxMT0M9JHtESVNBQkxFX0pFTUFMTE9DOi1mYWxzZX0nCiAgICB2b2x1bWVzOgogICAgICAtICdob21lYXNzaXN0YW50LWNvbmZpZzovY29uZmlnJwogICAgICAtICcvcnVuL2RidXM6L3J1bi9kYnVzOnJvJwogICAgICAtCiAgICAgICAgdHlwZTogYmluZAogICAgICAgIHNvdXJjZTogLi9jb25maWd1cmF0aW9uLnlhbWwKICAgICAgICB0YXJnZXQ6IC9jb25maWcvY29uZmlndXJhdGlvbi55YW1sCiAgICAgICAgY29udGVudDogIiMgTG9hZHMgZGVmYXVsdCBzZXQgb2YgaW50ZWdyYXRpb25zLiBEbyBub3QgcmVtb3ZlLlxuZGVmYXVsdF9jb25maWc6XG5cbiMgQ29uZmlndXJhdGlvbiBmb3IgcmV2ZXJzZSBwcm94eSBzdXBwb3J0IChyZXF1aXJlZCBmb3IgQ29vbGlmeSlcbmh0dHA6XG4gIHVzZV94X2ZvcndhcmRlZF9mb3I6IHRydWVcbiAgdHJ1c3RlZF9wcm94aWVzOlxuICAgIC0gMTAuMC4wLjAvOFxuICAgIC0gMTcyLjE2LjAuMC8xMlxuICAgIC0gMTkyLjE2OC4wLjAvMTZcbiAgaXBfYmFuX2VuYWJsZWQ6IHRydWVcbiAgbG9naW5fYXR0ZW1wdHNfdGhyZXNob2xkOiA1IgogICAgcHJpdmlsZWdlZDogdHJ1ZQogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIGN1cmwKICAgICAgICAtICctZicKICAgICAgICAtICdodHRwOi8vbG9jYWxob3N0OjgxMjMnCiAgICAgIGludGVydmFsOiAzMHMKICAgICAgdGltZW91dDogMTBzCiAgICAgIHJldHJpZXM6IDMKICAgICAgc3RhcnRfcGVyaW9kOiA2MHMK", + "tags": [ + "home-automation", + "iot", + "smart-home", + "automation", + "domotics", + "mqtt", + "zigbee", + "zwave" + ], + "category": "automation", + "logo": "svgs/home-assistant.svg", + "minversion": "0.0.0", + "port": "8123" + }, "homebox": { "documentation": "https://github.com/sysadminsmedia/homebox?utm_source=coolify.io", "slogan": "Homebox is the inventory and organization system built for the Home User.", @@ -2440,6 +2459,23 @@ "minversion": "0.0.0", "port": "3000" }, + "metamcp": { + "documentation": "https://github.com/metatool-ai/metamcp?utm_source=coolify.io", + "slogan": "MCP Aggregator, Orchestrator, Middleware, Gateway in one app", + "compose": "c2VydmljZXM6CiAgYXBwOgogICAgaW1hZ2U6ICdnaGNyLmlvL21ldGF0b29sLWFpL21ldGFtY3A6Mi40JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX01FVEFNQ1BfMTIwMDgKICAgICAgLSAnUE9TVEdSRVNfSE9TVD0ke1BPU1RHUkVTX0hPU1Q6LXBvc3RncmVzfScKICAgICAgLSAnUE9TVEdSRVNfUE9SVD0ke1BPU1RHUkVTX1BPUlQ6LTU0MzJ9JwogICAgICAtICdQT1NUR1JFU19VU0VSPSR7U0VSVklDRV9VU0VSX1BPU1RHUkVTfScKICAgICAgLSAnUE9TVEdSRVNfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTfScKICAgICAgLSAnUE9TVEdSRVNfREI9JHtQT1NUR1JFU19EQjotbWV0YW1jcF9kYn0nCiAgICAgIC0gJ0RBVEFCQVNFX1VSTD1wb3N0Z3Jlc3FsOi8vJHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9OiR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU31AJHtQT1NUR1JFU19IT1NUOi1wb3N0Z3Jlc306JHtQT1NUR1JFU19QT1JUOi01NDMyfS8ke1BPU1RHUkVTX0RCOi1tZXRhbWNwX2RifScKICAgICAgLSAnQVBQX1VSTD0ke1NFUlZJQ0VfRlFETl9NRVRBTUNQfScKICAgICAgLSAnTkVYVF9QVUJMSUNfQVBQX1VSTD0ke1NFUlZJQ0VfRlFETl9NRVRBTUNQfScKICAgICAgLSAnQkVUVEVSX0FVVEhfU0VDUkVUPSR7U0VSVklDRV9QQVNTV09SRF9BVVRIfScKICAgICAgLSAnVFJBTlNGT1JNX0xPQ0FMSE9TVF9UT19ET0NLRVJfSU5URVJOQUw9JHtUUkFOU0ZPUk1fTE9DQUxIT1NUX1RPX0RPQ0tFUl9JTlRFUk5BTDotdHJ1ZX0nCiAgICBkZXBlbmRzX29uOgogICAgICBwb3N0Z3JlczoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIGN1cmwKICAgICAgICAtICctZicKICAgICAgICAtICdodHRwOi8vbG9jYWxob3N0OjEyMDA4L2hlYWx0aCcKICAgICAgaW50ZXJ2YWw6IDEwcwogICAgICB0aW1lb3V0OiA1cwogICAgICByZXRyaWVzOiA1CiAgcG9zdGdyZXM6CiAgICBpbWFnZTogJ3Bvc3RncmVzOjE2LWFscGluZScKICAgIGVudmlyb25tZW50OgogICAgICAtICdQT1NUR1JFU19EQj0ke1BPU1RHUkVTX0RCOi1tZXRhbWNwX2RifScKICAgICAgLSAnUE9TVEdSRVNfVVNFUj0ke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU30nCiAgICAgIC0gJ1BPU1RHUkVTX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU30nCiAgICB2b2x1bWVzOgogICAgICAtICdwb3N0Z3Jlc19kYXRhOi92YXIvbGliL3Bvc3RncmVzcWwvZGF0YScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAncGdfaXNyZWFkeSAtVSAke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU30gLWQgJHtQT1NUR1JFU19EQjotbWV0YW1jcF9kYn0nCiAgICAgIGludGVydmFsOiAxMHMKICAgICAgdGltZW91dDogNXMKICAgICAgcmV0cmllczogNQo=", + "tags": [ + "mcp", + "ai", + "sse", + "aggregator", + "orchestrator", + "middleware" + ], + "category": "mcp", + "logo": "svgs/metamcp.png", + "minversion": "0.0.0", + "port": "12008" + }, "metube": { "documentation": "https://github.com/alexta69/metube?utm_source=coolify.io", "slogan": "A web GUI for youtube-dl with playlist support. It enables you to effortlessly download videos from YouTube and dozens of other sites.", @@ -3218,38 +3254,6 @@ "minversion": "0.0.0", "port": "80" }, - "pingvinshare-with-clamav": { - "documentation": "https://github.com/stonith404/pingvin-share?utm_source=coolify.io", - "slogan": "A self-hosted file sharing platform that combines lightness and beauty, perfect for seamless and efficient file sharing.", - "compose": "c2VydmljZXM6CiAgcGluZ3ZpbnNoYXJlOgogICAgaW1hZ2U6IGdoY3IuaW8vc3Rvbml0aDQwNC9waW5ndmluLXNoYXJlCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX0ZRRE5fUElOR1ZJTlNIQVJFXzMwMDAKICAgICAgLSAnVFJVU1RfUFJPWFk9JHtUUlVTVF9QUk9YWTotdHJ1ZX0nCiAgICB2b2x1bWVzOgogICAgICAtICdwaW5ndmluc2hhcmVfZGF0YTovb3B0L2FwcC9iYWNrZW5kL2RhdGEnCiAgICAgIC0gJ3Bpbmd2aW5zaGFyZV9pbWFnZXM6L29wdC9hcHAvZnJvbnRlbmQvcHVibGljL2ltZycKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAnd2dldCAtLXF1aWV0IC0tdHJpZXM9MSAtLXNwaWRlciBodHRwOi8vbG9jYWxob3N0OjMwMDAvYXBpL2hlYWx0aCB8fCBleGl0IDEnCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiAyMHMKICAgICAgcmV0cmllczogMTAKICAgIGRlcGVuZHNfb246CiAgICAgIGNsYW1hdjoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogIGNsYW1hdjoKICAgIGltYWdlOiBjbGFtYXYvY2xhbWF2CiAgICBwbGF0Zm9ybTogbGludXgvYW1kNjQK", - "tags": [ - "self-hosted", - "file-sharing", - "files", - "cloud", - "sharing" - ], - "category": "storage", - "logo": "svgs/pingvinshare.svg", - "minversion": "0.0.0", - "port": "3000" - }, - "pingvinshare": { - "documentation": "https://github.com/stonith404/pingvin-share?utm_source=coolify.io", - "slogan": "A self-hosted file sharing platform that combines lightness and beauty, perfect for seamless and efficient file sharing.", - "compose": "c2VydmljZXM6CiAgcGluZ3ZpbnNoYXJlOgogICAgaW1hZ2U6IGdoY3IuaW8vc3Rvbml0aDQwNC9waW5ndmluLXNoYXJlCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX0ZRRE5fUElOR1ZJTlNIQVJFXzMwMDAKICAgICAgLSAnVFJVU1RfUFJPWFk9JHtUUlVTVF9QUk9YWTotdHJ1ZX0nCiAgICB2b2x1bWVzOgogICAgICAtICdwaW5ndmluc2hhcmVfZGF0YTovb3B0L2FwcC9iYWNrZW5kL2RhdGEnCiAgICAgIC0gJ3Bpbmd2aW5zaGFyZV9pbWFnZXM6L29wdC9hcHAvZnJvbnRlbmQvcHVibGljL2ltZycKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAnd2dldCAtLXF1aWV0IC0tdHJpZXM9MSAtLXNwaWRlciBodHRwOi8vbG9jYWxob3N0OjMwMDAvYXBpL2hlYWx0aCB8fCBleGl0IDEnCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiAyMHMKICAgICAgcmV0cmllczogMTAK", - "tags": [ - "self-hosted", - "file-sharing", - "files", - "cloud", - "sharing" - ], - "category": "storage", - "logo": "svgs/pingvinshare.svg", - "minversion": "0.0.0", - "port": "3000" - }, "plane": { "documentation": "https://docs.plane.so/self-hosting/methods/docker-compose?utm_source=coolify.io", "slogan": "The open source project management tool", @@ -3302,6 +3306,45 @@ "minversion": "0.0.0", "port": "3000" }, + "pocket-id-with-postgresql": { + "documentation": "https://pocket-id.org/docs/setup/installation?utm_source=coolify.io", + "slogan": "A simple and secure OIDC provider with passkey authentication", + "compose": "c2VydmljZXM6CiAgcG9ja2V0LWlkOgogICAgaW1hZ2U6ICdnaGNyLmlvL3BvY2tldC1pZC9wb2NrZXQtaWQ6djEuMTMnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX0ZRRE5fUE9DS0VUSURfMTQxMQogICAgICAtICdBUFBfVVJMPSR7U0VSVklDRV9GUUROX1BPQ0tFVElEfScKICAgICAgLSAnVFJVU1RfUFJPWFk9JHtUUlVTVF9QUk9YWTotdHJ1ZX0nCiAgICAgIC0gREJfUFJPVklERVI9cG9zdGdyZXMKICAgICAgLSAnREJfQ09OTkVDVElPTl9TVFJJTkc9cG9zdGdyZXNxbDovLyR7U0VSVklDRV9VU0VSX1BPU1RHUkVTUUx9OiR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU1FMfUBwb3N0Z3Jlc3FsOjU0MzIvJHtQT1NUR1JFU19EQjotcG9ja2V0aWR9JwogICAgICAtICdFTkNSWVBUSU9OX0tFWT0ke1NFUlZJQ0VfUEFTU1dPUkRfNjRfUE9DS0VUSUR9JwogICAgICAtICdLRVlTX1NUT1JBR0U9JHtLRVlTX1NUT1JBR0U6LWRhdGFiYXNlfScKICAgICAgLSAnTUFYTUlORF9MSUNFTlNFX0tFWT0ke01BWE1JTkRfTElDRU5TRV9LRVl9JwogICAgICAtICdTTVRQX0hPU1Q9JHtTTVRQX0hPU1R9JwogICAgICAtICdTTVRQX1BPUlQ9JHtTTVRQX1BPUlQ6LTU4N30nCiAgICAgIC0gJ1NNVFBfRlJPTT0ke1NNVFBfRlJPTX0nCiAgICAgIC0gJ1NNVFBfVVNFUj0ke1NNVFBfVVNFUn0nCiAgICAgIC0gJ1NNVFBfUEFTU1dPUkQ9JHtTTVRQX1BBU1NXT1JEfScKICAgICAgLSAnU01UUF9UTFM9JHtTTVRQX1RMUzotc3RhcnR0bHN9JwogICAgICAtICdTTVRQX1NLSVBfQ0VSVF9WRVJJRlk9JHtTTVRQX1NLSVBfQ0VSVF9WRVJJRlk6LWZhbHNlfScKICAgICAgLSAnRU1BSUxfTE9HSU5fTk9USUZJQ0FUSU9OX0VOQUJMRUQ9JHtFTUFJTF9MT0dJTl9OT1RJRklDQVRJT05fRU5BQkxFRDotZmFsc2V9JwogICAgICAtICdFTUFJTF9PTkVfVElNRV9BQ0NFU1NfQVNfQURNSU5fRU5BQkxFRD0ke0VNQUlMX09ORV9USU1FX0FDQ0VTU19BU19BRE1JTl9FTkFCTEVEOi1mYWxzZX0nCiAgICAgIC0gJ0VNQUlMX0FQSV9LRVlfRVhQSVJBVElPTl9FTkFCTEVEPSR7RU1BSUxfQVBJX0tFWV9FWFBJUkFUSU9OX0VOQUJMRUQ6LWZhbHNlfScKICAgICAgLSAnUFVJRD0ke1BVSUQ6LTEwMDB9JwogICAgICAtICdQR0lEPSR7UEdJRDotMTAwMH0nCiAgICB2b2x1bWVzOgogICAgICAtICdwb2NrZXQtaWQtZGF0YTovYXBwL2RhdGEnCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gL2FwcC9wb2NrZXQtaWQKICAgICAgICAtIGhlYWx0aGNoZWNrCiAgICAgIGludGVydmFsOiAzMHMKICAgICAgdGltZW91dDogNXMKICAgICAgcmV0cmllczogMwogICAgICBzdGFydF9wZXJpb2Q6IDEwcwogICAgZGVwZW5kc19vbjoKICAgICAgcG9zdGdyZXNxbDoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogIHBvc3RncmVzcWw6CiAgICBpbWFnZTogJ3Bvc3RncmVzOjE2LWFscGluZScKICAgIHZvbHVtZXM6CiAgICAgIC0gJ3BvY2tldC1pZC1wb3N0Z3Jlc3FsLWRhdGE6L3Zhci9saWIvcG9zdGdyZXNxbC9kYXRhJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ1BPU1RHUkVTX1VTRVI9JHtTRVJWSUNFX1VTRVJfUE9TVEdSRVNRTH0nCiAgICAgIC0gJ1BPU1RHUkVTX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU1FMfScKICAgICAgLSAnUE9TVEdSRVNfREI9JHtQT1NUR1JFU19EQjotcG9ja2V0aWR9JwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICdwZ19pc3JlYWR5IC1VICQke1BPU1RHUkVTX1VTRVJ9IC1kICQke1BPU1RHUkVTX0RCfScKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDIwcwogICAgICByZXRyaWVzOiAxMAo=", + "tags": [ + "identity", + "oidc", + "oauth", + "passkey", + "webauthn", + "authentication", + "sso", + "openid", + "postgresql" + ], + "category": "auth", + "logo": "svgs/pocketid-logo.png", + "minversion": "0.0.0", + "port": "1411" + }, + "pocket-id": { + "documentation": "https://pocket-id.org/docs/setup/installation?utm_source=coolify.io", + "slogan": "A simple and secure OIDC provider with passkey authentication", + "compose": "c2VydmljZXM6CiAgcG9ja2V0LWlkOgogICAgaW1hZ2U6ICdnaGNyLmlvL3BvY2tldC1pZC9wb2NrZXQtaWQ6djEuMTMnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX0ZRRE5fUE9DS0VUSURfMTQxMQogICAgICAtICdBUFBfVVJMPSR7U0VSVklDRV9GUUROX1BPQ0tFVElEfScKICAgICAgLSAnVFJVU1RfUFJPWFk9JHtUUlVTVF9QUk9YWTotdHJ1ZX0nCiAgICAgIC0gJ01BWE1JTkRfTElDRU5TRV9LRVk9JHtNQVhNSU5EX0xJQ0VOU0VfS0VZfScKICAgICAgLSAnU01UUF9IT1NUPSR7U01UUF9IT1NUfScKICAgICAgLSAnU01UUF9QT1JUPSR7U01UUF9QT1JUOi01ODd9JwogICAgICAtICdTTVRQX0ZST009JHtTTVRQX0ZST019JwogICAgICAtICdTTVRQX1VTRVI9JHtTTVRQX1VTRVJ9JwogICAgICAtICdTTVRQX1BBU1NXT1JEPSR7U01UUF9QQVNTV09SRH0nCiAgICAgIC0gJ1NNVFBfVExTPSR7U01UUF9UTFM6LXN0YXJ0dGxzfScKICAgICAgLSAnU01UUF9TS0lQX0NFUlRfVkVSSUZZPSR7U01UUF9TS0lQX0NFUlRfVkVSSUZZOi1mYWxzZX0nCiAgICAgIC0gJ0VNQUlMX0xPR0lOX05PVElGSUNBVElPTl9FTkFCTEVEPSR7RU1BSUxfTE9HSU5fTk9USUZJQ0FUSU9OX0VOQUJMRUQ6LWZhbHNlfScKICAgICAgLSAnRU1BSUxfT05FX1RJTUVfQUNDRVNTX0FTX0FETUlOX0VOQUJMRUQ9JHtFTUFJTF9PTkVfVElNRV9BQ0NFU1NfQVNfQURNSU5fRU5BQkxFRDotZmFsc2V9JwogICAgICAtICdFTUFJTF9BUElfS0VZX0VYUElSQVRJT05fRU5BQkxFRD0ke0VNQUlMX0FQSV9LRVlfRVhQSVJBVElPTl9FTkFCTEVEOi1mYWxzZX0nCiAgICAgIC0gJ1BVSUQ9JHtQVUlEOi0xMDAwfScKICAgICAgLSAnUEdJRD0ke1BHSUQ6LTEwMDB9JwogICAgdm9sdW1lczoKICAgICAgLSAncG9ja2V0LWlkLWRhdGE6L2FwcC9kYXRhJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIC9hcHAvcG9ja2V0LWlkCiAgICAgICAgLSBoZWFsdGhjaGVjawogICAgICBpbnRlcnZhbDogMzBzCiAgICAgIHRpbWVvdXQ6IDVzCiAgICAgIHJldHJpZXM6IDMKICAgICAgc3RhcnRfcGVyaW9kOiAxMHMK", + "tags": [ + "identity", + "oidc", + "oauth", + "passkey", + "webauthn", + "authentication", + "sso", + "openid" + ], + "category": "auth", + "logo": "svgs/pocketid-logo.png", + "minversion": "0.0.0", + "port": "1411" + }, "pocketbase": { "documentation": "https://pocketbase.io/docs/?utm_source=coolify.io", "slogan": "Open Source backend for your next SaaS and Mobile app in 1 file", @@ -3554,6 +3597,22 @@ "minversion": "0.0.0", "port": "8000" }, + "redis-insight": { + "documentation": "https://redis.io/docs/latest/operate/redisinsight/?utm_source=coolify.io", + "slogan": "Redis Insight lets you do both GUI- and CLI-based interactions in a fully-featured desktop GUI client.", + "compose": "c2VydmljZXM6CiAgcmVkaXNpbnNpZ2h0OgogICAgaW1hZ2U6ICdyZWRpcy9yZWRpc2luc2lnaHQ6Mi43MCcKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9SRURJU0lOU0lHSFRfNTU0MAogICAgICAtIFJJX0FQUF9IT1NUPTAuMC4wLjAKICAgICAgLSBSSV9BUFBfUE9SVD01NTQwCiAgICAgIC0gJ1JJX0VOQ1JZUFRJT05fS0VZPSR7U0VSVklDRV9QQVNTV09SRF9SSV9FTkNSWVBUSU9OX0tFWX0nCiAgICAgIC0gJ1JJX0xPR19MRVZFTD0ke1JJX0xPR19MRVZFTDotaW5mb30nCiAgICAgIC0gJ1JJX0ZJTEVTX0xPR0dFUj0ke1JJX0ZJTEVTX0xPR0dFUjotdHJ1ZX0nCiAgICAgIC0gJ1JJX1NURE9VVF9MT0dHRVI9JHtSSV9TVERPVVRfTE9HR0VSOi10cnVlfScKICAgIHZvbHVtZXM6CiAgICAgIC0gJ3JlZGlzX2luc2lnaHRfZGF0YTovZGF0YScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSB3Z2V0CiAgICAgICAgLSAnLS1zcGlkZXInCiAgICAgICAgLSAnaHR0cDovL2xvY2FsaG9zdDo1NTQwJwogICAgICBpbnRlcnZhbDogMTBzCiAgICAgIHJldHJpZXM6IDMKICAgICAgdGltZW91dDogMTBzCiAgICAgIHN0YXJ0X3BlcmlvZDogMTBzCg==", + "tags": [ + "redis", + "gui", + "database", + "monitoring", + "analytics" + ], + "category": "database,observability,developer-tools", + "logo": "svgs/redisinsight.png", + "minversion": "0.0.0", + "port": "5540" + }, "redlib": { "documentation": "https://github.com/redlib-org/redlib?utm_source=coolify.io", "slogan": "An alternative private front-end to Reddit, with its origins in Libreddit.", @@ -3567,6 +3626,23 @@ "minversion": "0.0.0", "port": "8080" }, + "rivet-engine": { + "documentation": "https://www.rivet.dev/docs?utm_source=coolify.io", + "slogan": "Build and scale stateful workloads with long-lived processes", + "compose": "c2VydmljZXM6CiAgcml2ZXQtZW5naW5lOgogICAgaW1hZ2U6ICdyaXZldGtpdC9lbmdpbmU6MjUuOC4wJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX1JJVkVUXzY0MjAKICAgICAgLSAnUklWRVRfX0FVVEhfX0FETUlOX1RPS0VOPSR7U0VSVklDRV9QQVNTV09SRF9SSVZFVH0nCiAgICAgIC0gJ1JJVkVUX19QT1NUR1JFU19fVVJMPXBvc3RncmVzcWw6Ly8kU0VSVklDRV9VU0VSX1BPU1RHUkVTUUw6JFNFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVNRTEBwb3N0Z3Jlc3FsOjU0MzIvJHtQT1NUR1JFU1FMX0RBVEFCQVNFLXJpdmV0fScKICAgIGRlcGVuZHNfb246CiAgICAgIHBvc3RncmVzcWw6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBjdXJsCiAgICAgICAgLSAnLWYnCiAgICAgICAgLSAnaHR0cDovLzEyNy4wLjAuMTo2NDIwL2hlYWx0aCcKICAgICAgaW50ZXJ2YWw6IDJzCiAgICAgIHRpbWVvdXQ6IDEwcwogICAgICByZXRyaWVzOiAxMAogICAgICBzdGFydF9wZXJpb2Q6IDMwcwogIHBvc3RncmVzcWw6CiAgICBpbWFnZTogJ3Bvc3RncmVzOjE3LWFscGluZScKICAgIHZvbHVtZXM6CiAgICAgIC0gJ3JpdmV0LXBvc3RncmVzcWwtZGF0YTovdmFyL2xpYi9wb3N0Z3Jlc3FsL2RhdGEnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnUE9TVEdSRVNfVVNFUj0ke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU1FMfScKICAgICAgLSAnUE9TVEdSRVNfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTUUx9JwogICAgICAtICdQT1NUR1JFU19EQj0ke1BPU1RHUkVTUUxfREFUQUJBU0Utcml2ZXR9JwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICdwZ19pc3JlYWR5IC1VICQke1BPU1RHUkVTX1VTRVJ9IC1kICQke1BPU1RHUkVTX0RCfScKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDIwcwogICAgICByZXRyaWVzOiAxMAo=", + "tags": [ + "stateful", + "actors", + "realtime", + "backend", + "serverless", + "postgresql" + ], + "category": "development", + "logo": "svgs/rivet.svg", + "minversion": "0.0.0", + "port": "6420" + }, "rocketchat": { "documentation": "https://github.com/RocketChat/Rocket.Chat?utm_source=coolify.io", "slogan": "Self-hosted, secure and highly customizable open-source communication platform for organizations with sophisticated security and privacy concerns.", @@ -3706,6 +3782,20 @@ "minversion": "0.0.0", "port": "8080" }, + "siyuan": { + "documentation": "https://github.com/siyuan-note/siyuan?utm_source=coolify.io", + "slogan": "A privacy-first, self-hosted, fully open source personal knowledge management software, written in typescript and golang.", + "compose": "c2VydmljZXM6CiAgc2l5dWFuOgogICAgaW1hZ2U6ICdiM2xvZy9zaXl1YW46djMuMy41JwogICAgdm9sdW1lczoKICAgICAgLSAnc2l5dWFuX3dvcmtzcGFjZTovc2l5dWFuL3dvcmtzcGFjZScKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9TSVlVQU5fNjgwNgogICAgICAtICdUWj0ke1RaOi1VVEN9JwogICAgICAtIFBVSUQ9MTAwMAogICAgICAtIFBHSUQ9MTAwMAogICAgICAtICdTSVlVQU5fQUNDRVNTX0FVVEhfQ09ERT0ke1NFUlZJQ0VfUEFTU1dPUkRfU0lZVUFOfScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSB3Z2V0CiAgICAgICAgLSAnLS1zcGlkZXInCiAgICAgICAgLSAnLS1xdWlldCcKICAgICAgICAtICdodHRwOi8vMTI3LjAuMC4xOjY4MDYvYXBpL3N5c3RlbS92ZXJzaW9uJwogICAgICBpbnRlcnZhbDogMTVzCiAgICAgIHRpbWVvdXQ6IDEwcwogICAgICByZXRyaWVzOiA1CiAgICAgIHN0YXJ0X3BlcmlvZDogMjBzCg==", + "tags": [ + "note-taking", + "markdown", + "pkm" + ], + "category": null, + "logo": "svgs/siyuan.svg", + "minversion": "0.0.0", + "port": "6806" + }, "slash": { "documentation": "https://github.com/yourselfhosted/slash?utm_source=coolify.io", "slogan": "An open source, self-hosted links shortener and sharing platform.", @@ -3769,6 +3859,23 @@ "minversion": "0.0.0", "port": "8989" }, + "sparkyfitness": { + "documentation": "https://codewithcj.github.io/SparkyFitness/?utm_source=coolify.io", + "slogan": "SparkyFitness is a comprehensive fitness tracking and management application designed to help users monitor their nutrition, exercise, and body measurements. It provides tools for daily progress tracking, goal setting, and insightful reports to support a healthy lifestyle.", + "compose": "c2VydmljZXM6CiAgc3Bhcmt5Zml0bmVzcy1mcm9udGVuZDoKICAgIGltYWdlOiAnY29kZXdpdGhjai9zcGFya3lmaXRuZXNzOnYwLjE1LjcuMycKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9TUEFSS1lGSVRORVNTXzgwCiAgICBkZXBlbmRzX29uOgogICAgICAtIHNwYXJreWZpdG5lc3Mtc2VydmVyCiAgc3Bhcmt5Zml0bmVzcy1zZXJ2ZXI6CiAgICBpbWFnZTogJ2NvZGV3aXRoY2ovc3Bhcmt5Zml0bmVzc19zZXJ2ZXI6djAuMTUuNy4zJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ1NQQVJLWV9GSVRORVNTX0xPR19MRVZFTD0ke1NQQVJLWV9GSVRORVNTX0xPR19MRVZFTDotaW5mb30nCiAgICAgIC0gJ1NQQVJLWV9GSVRORVNTX0RCX1VTRVI9JHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9JwogICAgICAtIFNQQVJLWV9GSVRORVNTX0RCX0hPU1Q9c3Bhcmt5Zml0bmVzcy1kYgogICAgICAtICdTUEFSS1lfRklUTkVTU19EQl9OQU1FPSR7U1BBUktZX0ZJVE5FU1NfREJfTkFNRTotc3Bhcmt5Zml0bmVzc30nCiAgICAgIC0gJ1NQQVJLWV9GSVRORVNTX0RCX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU30nCiAgICAgIC0gJ1NQQVJLWV9GSVRORVNTX0RCX1BPUlQ9JHtTUEFSS1lfRklUTkVTU19EQl9QT1JUOi01NDMyfScKICAgICAgLSAnU1BBUktZX0ZJVE5FU1NfQVBJX0VOQ1JZUFRJT05fS0VZPSR7U0VSVklDRV9QQVNTV09SRF82NF9TRVJWRVJBUElFTkNSWVBUSU9OS0VZfScKICAgICAgLSAnSldUX1NFQ1JFVD0ke1NFUlZJQ0VfUEFTU1dPUkRfNjRfU0VSVkVSSldUU0VDUkVUfScKICAgICAgLSAnU1BBUktZX0ZJVE5FU1NfRlJPTlRFTkRfVVJMPSR7U0VSVklDRV9GUUROX1NQQVJLWUZJVE5FU1NfODB9JwogICAgICAtICdTUEFSS1lfRklUTkVTU19ESVNBQkxFX1NJR05VUD0ke1NQQVJLWV9GSVRORVNTX0RJU0FCTEVfU0lHTlVQOi1mYWxzZX0nCiAgICAgIC0gJ1NQQVJLWV9GSVRORVNTX0FETUlOX0VNQUlMPSR7U1BBUktZX0ZJVE5FU1NfQURNSU5fRU1BSUw6LWFkbWluQGV4YW1wbGUuY29tfScKICAgICAgLSAnU1BBUktZX0ZJVE5FU1NfRU1BSUxfSE9TVD0ke1NQQVJLWV9GSVRORVNTX0VNQUlMX0hPU1Q6LXNtdHAuZ21haWwuY29tfScKICAgICAgLSAnU1BBUktZX0ZJVE5FU1NfRU1BSUxfUE9SVD0ke1NQQVJLWV9GSVRORVNTX0VNQUlMX1BPUlQ6LTU4N30nCiAgICAgIC0gJ1NQQVJLWV9GSVRORVNTX0VNQUlMX1NFQ1VSRT0ke1NQQVJLWV9GSVRORVNTX0VNQUlMX1NFQ1VSRTotZmFsc2V9JwogICAgICAtICdTUEFSS1lfRklUTkVTU19FTUFJTF9VU0VSPSR7U1BBUktZX0ZJVE5FU1NfRU1BSUxfVVNFUn0nCiAgICAgIC0gJ1NQQVJLWV9GSVRORVNTX0VNQUlMX1BBU1M9JHtTUEFSS1lfRklUTkVTU19FTUFJTF9QQVNTfScKICAgICAgLSAnU1BBUktZX0ZJVE5FU1NfRU1BSUxfRlJPTT0ke1NQQVJLWV9GSVRORVNTX0VNQUlMX0ZST006LSJTcGFya3kgRml0bmVzcyA8bm9yZXBseUBzcGFya3lmaXRuZXNzLmNvbT4ifScKICAgIGRlcGVuZHNfb246CiAgICAgIC0gc3Bhcmt5Zml0bmVzcy1kYgogICAgdm9sdW1lczoKICAgICAgLSAnc3Bhcmt5Zml0bmVzcy1zZXJ2ZXItYmFja3VwOi9hcHAvU3Bhcmt5Rml0bmVzc1NlcnZlci9iYWNrdXAnCiAgICAgIC0gJ3NwYXJreWZpdG5lc3Mtc2VydmVyLXVwbG9hZHM6L2FwcC9TcGFya3lGaXRuZXNzU2VydmVyL3VwbG9hZHMnCiAgc3Bhcmt5Zml0bmVzcy1kYjoKICAgIGltYWdlOiAncG9zdGdyZXM6MTUtYWxwaW5lJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ1BPU1RHUkVTX0RCPSR7U1BBUktZX0ZJVE5FU1NfREJfTkFNRTotc3Bhcmt5Zml0bmVzc30nCiAgICAgIC0gJ1BPU1RHUkVTX1VTRVI9JHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9JwogICAgICAtICdQT1NUR1JFU19QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9JwogICAgICAtICdQT1NUR1JFU19QT1JUPSR7U1BBUktZX0ZJVE5FU1NfREJfUE9SVDotNTQzMn0nCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ3BnX2lzcmVhZHkgLVUgJCR7UE9TVEdSRVNfVVNFUn0gLWQgJCR7UE9TVEdSRVNfREJ9JwogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogMjBzCiAgICAgIHJldHJpZXM6IDEwCiAgICB2b2x1bWVzOgogICAgICAtICdzcGFya3lmaXRuZXNzLWRiLXBvc3RncmVzcWw6L3Zhci9saWIvcG9zdGdyZXNxbC9kYXRhJwo=", + "tags": [ + "sparkyfitness", + "fitness", + "health", + "nutrition", + "exercise", + "body measurements" + ], + "category": "health", + "logo": "svgs/sparkyfitness.svg", + "minversion": "0.0.0", + "port": "80" + }, "statusnook": { "documentation": "https://statusnook.com?utm_source=coolify.io", "slogan": "Effortlessly deploy a status page and start monitoring endpoints in minutes", diff --git a/tests/Unit/ScheduledJobManagerLockTest.php b/tests/Unit/ScheduledJobManagerLockTest.php new file mode 100644 index 000000000..3f3ae593a --- /dev/null +++ b/tests/Unit/ScheduledJobManagerLockTest.php @@ -0,0 +1,60 @@ +middleware(); + + // Assert middleware exists + expect($middleware)->toBeArray() + ->and($middleware)->toHaveCount(1); + + $overlappingMiddleware = $middleware[0]; + + // Assert it's a WithoutOverlapping instance + expect($overlappingMiddleware)->toBeInstanceOf(WithoutOverlapping::class); + + // Use reflection to check private properties + $reflection = new ReflectionClass($overlappingMiddleware); + + // Check expireAfter is set (should be 60 seconds - matches job frequency) + $expiresAfterProperty = $reflection->getProperty('expiresAfter'); + $expiresAfterProperty->setAccessible(true); + $expiresAfter = $expiresAfterProperty->getValue($overlappingMiddleware); + + expect($expiresAfter)->toBe(60) + ->and($expiresAfter)->toBeGreaterThan(0, 'expireAfter must be set to prevent stale locks'); + + // Check releaseAfter is NOT set (we use dontRelease) + $releaseAfterProperty = $reflection->getProperty('releaseAfter'); + $releaseAfterProperty->setAccessible(true); + $releaseAfter = $releaseAfterProperty->getValue($overlappingMiddleware); + + expect($releaseAfter)->toBeNull('releaseAfter should be null when using dontRelease()'); + + // Check the lock key + $keyProperty = $reflection->getProperty('key'); + $keyProperty->setAccessible(true); + $key = $keyProperty->getValue($overlappingMiddleware); + + expect($key)->toBe('scheduled-job-manager'); +}); + +it('prevents stale locks by ensuring expireAfter is always set', function () { + $job = new ScheduledJobManager; + $middleware = $job->middleware(); + + $overlappingMiddleware = $middleware[0]; + $reflection = new ReflectionClass($overlappingMiddleware); + + $expiresAfterProperty = $reflection->getProperty('expiresAfter'); + $expiresAfterProperty->setAccessible(true); + $expiresAfter = $expiresAfterProperty->getValue($overlappingMiddleware); + + // Critical check: expireAfter MUST be set to prevent GitHub issue #4539 + expect($expiresAfter)->not->toBeNull( + 'expireAfter() is required to prevent stale locks (see GitHub #4539)' + ); +});