600 Commits
Author SHA1 Message Date
Andras BacsaiandClaude Opus 5.5 dbc3fb91bf fix(cdn): fetch versions.json once per hour, spread evenly across instances
- Retry CDN requests only for transient errors and honor Retry-After
  (Cloudflare error 1200 sends 60 s), with jitter.
- Read helper and Sentinel versions from the local versions.json, which
  the hourly update check refreshes, instead of fetching per job/server.
- Replace the random 0-600 s delay with a stable per-instance offset
  inside the cron interval (max 1 h).
- Manual update checks and upgrades make one CDN attempt only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 18:10:48 +02:00
Andras BacsaiandClaude Opus 5.5 b1f2abf868 fix(cloud): refresh local versions.json hourly on every node
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 17:18:56 +02:00
Andras Bacsai 666ae60c2c Merge remote-tracking branch 'origin/main' into release/v4.5 2026-10-21 16:49:31 +02:00
Andras Bacsai d404da904f feat(app-key): re-encrypt stored secrets after key rotation 2026-10-21 16:47:51 +02:00
🏔️ Peak ff642008f1 fix(security): releease v4.4.7 (#12257) 2026-10-21 16:18:27 +02:00
peaklabs-dev eeda30719f feat(cdn): add patch.sh to sync:cdn 2026-10-21 16:16:13 +02:00
Andras BacsaiandClaude Opus 5.5 65a7bd5c05 chore: merge main into release/v4.5
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 13:37:20 +02:00
Andras BacsaiandClaude Opus 5.5 63153aa8b4 fix(cloud): rework unsubscribed team cleanup and account deletion (#12210)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 17:32:16 +02:00
e3d4411ff2 chore: merge main into release/v4.5 (#12192)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Furox <177975472+Furox-Art@users.noreply.github.com>
Co-authored-by: johandenhollander <johan.den.hollander@finalist.nl>
Co-authored-by: João Cruz <161638790+SrJooJ@users.noreply.github.com>
Co-authored-by: Saim Hashmi <hashmisaim037@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-18 23:43:20 +02:00
Andras BacsaiandClaude Opus 5.5 7c14c0098e feat(server-transfer): run instance migration as a background job (#12180)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 22:03:45 +02:00
Andras BacsaiandClaude Opus 5.5 21dc34ae61 fix(scheduler): spread CDN update checks over a random delay
All instances share the same default update cron, so they request the
CDN at the same second and Cloudflare rejects the burst (error 1200).
Queue the CDN fetching jobs with a random 0-600s delay to spread the load.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 21:38:39 +02:00
Andras BacsaiandClaude Opus 5.5 d4d8bba514 docs(backups): add multi-destination S3 planning notes (#11789)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 15:10:34 +02:00
github-actions[bot] 42f4ad9795 Merge remote-tracking branch 'origin/main' into next 2026-10-07 07:54:43 +00:00
Andras Bacsai 407c384b09 feat(backups): add configurable missing volume backup alerts
Check enabled volume backup schedules hourly and notify teams when no
execution occurs within the configured number of days. Expose the alert
threshold in the UI and API, with alerts disabled by default.

Route volume backup results and warnings to the appropriate Telegram
backup threads.
2026-10-07 09:37:35 +02:00
github-actions[bot] c67c026bb7 Merge remote-tracking branch 'origin/main' into next 2026-10-06 21:20:02 +00:00
Andras Bacsai d54c03730d feat(scheduler): make scheduled job dispatch mode configurable
Default to sequential dispatch on self-hosted instances and concurrent
per-type dispatch on Coolify Cloud. Allow SCHEDULED_JOBS_DISPATCH_MODE
to override the default, falling back for invalid values.

Cover defaults, overrides, and fallback behavior in scheduler tests.
2026-10-06 23:16:40 +02:00
github-actions[bot] 76a8bf16b4 Merge remote-tracking branch 'origin/main' into next 2026-10-06 11:18:51 +00:00
Andras Bacsai 5e92a7267c fix(cleanup): prune audit events in batches and delete old finished runner executions 2026-10-06 12:56:57 +02:00
github-actions[bot] c956551c81 Merge remote-tracking branch 'origin/main' into next 2026-10-06 08:47:53 +00:00
Andras Bacsai 460bb67d63 fix(server): avoid a burst of patch and Sentinel checks after the upgrade
The per-server schedules reused the cache keys of the old schedule, so
every server ran these checks at once on the first run after the
upgrade. New keys start fresh, so each server runs at its own slot.
2026-10-06 10:29:04 +02:00
github-actions[bot] 4914d6c760 Merge remote-tracking branch 'origin/main' into next 2026-10-04 19:31:07 +00:00
Andras Bacsai cfe9e0eee0 fix(settings): load instance backup page without a backup schedule
/settings/backup returned 500 when the coolify-db resource existed without
a scheduled backup. Configure backup now reuses the existing coolify-db and
creates only the missing schedule for the root team, without forcing id 0.

Closes #12074
2026-10-04 20:33:22 +02:00
🏔️ Peak 5f413cd7af chore(deps): add laravel vet an update composer dependencies (#12084) 2026-10-04 20:18:54 +02:00
Andras Bacsai 9f7697d501 feat(cleanup): purge stale unsubscribed teams (#11668) 2026-10-04 12:13:41 +02:00
peaklabs-dev c298c22f99 chore(deps): upgrade swagger-php to v6 2026-10-03 22:59:20 +02:00
Andras Bacsai a3ed963aed fix(server): stagger Sentinel version and patch checks per server
Servers no longer all connect at minute 0. The hourly Sentinel check uses
a per-server minute, and the weekly patch check uses a per-server time on
Sunday between 04:00 and 23:59.
2026-10-03 21:25:00 +02:00
Andras BacsaiandClaude Opus 5.5 476ba3c6ab fix(database-import): delete staged API uploads that were never imported
Add an hourly cleanup:database-import-uploads command that removes staged
import uploads older than a day, while holding the import lock of the
database so a running import keeps its file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 16:00:29 +02:00
Andras BacsaiandClaude Opus 5.5 332a970b27 feat(cdn): add Cloudflare cache purge to sync:cdn
Add a --purge option that purges the synced CDN files (and the legacy
/coolify-nightly/ paths for nightly) from the Cloudflare cache, and remind
the operator to run it after the CDN pull request is deployed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 16:00:29 +02:00
Andras Bacsai a14ef2d4ee chore(cdn): remove BunnyCDN sync and rename sync:bunny to sync:cdn
CDN files are synced through the coollabs-cdn GitHub repository only.
Remove the --bunny direct upload path, the BUNNY_API_KEY and
BUNNY_STORAGE_API_KEY settings, and rename the command to sync:cdn.
2026-10-02 11:36:04 +02:00
Andras Bacsai f575b2d179 feat(scheduler): run one scheduled job dispatcher for each schedule type
The scheduler ran one dispatcher for database backups, tasks, volume backups,
and Docker cleanups after each other. A slow type, for example many tasks due
at the same minute, made the whole run longer, and the shared overlap lock
then made all types skip the next minute.

Run `scheduled:dispatch --type=<type>` every minute for backups, tasks,
volume-backups, and docker-cleanups. Each type runs in its own background
process with its own scheduler and job overlap locks, and publishes and
recovers only the deliveries of its own job type. Running the command without
a type still processes all types.
2026-10-02 09:19:54 +02:00
Andras Bacsai a218e8cdc6 fix(scheduler): make scheduled:diagnostics read-only and show the real state
The command called shouldRunCronNow() with the dedup keys, and that helper
writes the key it checks. For server-check, server-storage-check, and
server-patch-check these are the keys of ServerManagerJob, so running the
command in a minute when a check was due made the real check skip that run.

It also read cache keys for backups, tasks, and Docker cleanups that the
scheduled job manager no longer uses. Read scheduled_job_states instead, and
list open and failed deliveries, where an old "enqueued" row shows a queued
job that was lost.
2026-10-02 08:07:30 +02:00
Andras Bacsai 50be16be8f revert(scheduler): go back to the cron scan and keep the reliability fixes
The missed daily backups on Coolify Cloud came from Redis evicting queue keys
(allkeys-lfu on a full instance), not from the scan of all schedules. The
next_run_at design (452259aac, 5c5740533) did not prevent that, and it added
stored state that must be kept in sync on every frequency, timezone, and server
change. It was not released, so remove it:
- revert next_run_at, its model hooks, the "Next run" UI, and the diagnostics
  changes; restore scheduled_job_states and the queue overlap lock
- a new migration removes the next_run_at columns and creates
  scheduled_job_states again where the removed migration already ran

Keep the changes that fix real problems:
- run the manager every minute from the scheduler with `scheduled:dispatch`,
  so a busy queue cannot delay it past the catch-up window
- load the server chain of scheduled backups with each chunk, which removes
  about 7,000 queries per run on Coolify Cloud
- catch Throwable for each schedule, so one broken schedule does not stop the
  others
- publish database and volume backups again when their queued job was not
  started after 60 minutes (for example, lost in Redis); log lost tasks and
  Docker cleanups as missed. A lost backup is not run again when a newer
  occurrence of the same schedule exists.
2026-10-02 08:05:18 +02:00
Andras Bacsai b8bc197b17 fix(oauth): key non-OIDC identities by provider instance
GitLab, Authentik, Zitadel, Clerk and Azure identities were keyed by the
provider name only, so a user with the same subject on another instance
could sign in as the linked user after the base URL or tenant changed.
The issuer column now stores the normalized instance, existing rows are
backfilled from the current settings, and oauth:rekey handles host renames.
2026-09-30 18:10:10 +02:00
Andras BacsaiandClaude Opus 5.5 fd85b740f5 feat(github-runners): add ephemeral self-hosted runners on build servers (#12054)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 12:13:11 +02:00
Andras Bacsai 99c840922c fix(notifications): throttle repeated notifications per resource
High disk usage notifications were sent every ~10 minutes on Coolify Cloud
because the cache rate limiter did not hold across Sentinel-triggered checks.

- Add a notification_throttles table and NotificationThrottle helper that
  atomically records when a notification was sent for a resource.
- Add the ThrottledNotification contract; Team::notify() skips a throttled
  notification that was already sent within its interval.
- High disk usage: configurable per-server interval
  (server_disk_usage_notification_interval_hours, default 24h) in
  Server > Advanced and the servers API.
- Container restarted (coolify-proxy, database TCP proxy): at most one
  notification per hour per server/database during a restart loop.
- Move the unreachable and missing-backup markers into the new table and
  migrate existing data (servers.unreachable_notification_sent and
  scheduled_database_backups.missing_backup_notification_sent_at).
- Regenerate OpenAPI files.
2026-09-29 11:29:39 +02:00
Andras BacsaiandClaude Opus 5.5 3d763c1577 refactor(server-transfer): always claim on import and drop remote claim file
Import now always claims the server and rebinds Sentinel. Remove the
SSH-written ownership file, the write_remote/rebind_sentinel/claim
options, and the POST /servers/{uuid}/claim endpoint. The migrator now
fails when the target cannot take management. Disabling management
records transfer.management_disabled so the server shows as
transferable, and the transfer and import pages are simplified.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 10:56:11 +02:00
Andras BacsaiandClaude Opus 5.5 639a07e4cb feat(s3): revalidate unusable S3 storages hourly
Re-test S3 storages marked unusable every hour so a storage that becomes
reachable again is usable without manual action. Failures keep the
storage unusable and reuse the existing once-per-outage email.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 10:16:09 +02:00
Andras Bacsai 452259aacc feat(scheduler): dispatch scheduled jobs by their stored next run time
The scheduled job manager checked every enabled schedule each minute and
evaluated its cron expression in PHP. On Coolify Cloud one run took more than
60 seconds, so runs overlapped and minutes were skipped.

Each schedule now stores its next due time:
- next_run_at on scheduled database backups, scheduled tasks, and volume
  backups, and docker_cleanup_next_run_at on server settings (UTC, indexed)
- model hooks calculate it when a schedule is created or its frequency or
  enabled flag changes; a server timezone change or a move to another server
  calculates it again for the affected schedules

The `scheduled:dispatch` command runs the manager every minute from the
scheduler, not from a queue. It selects only due rows and claims each
occurrence with an atomic update of next_run_at, together with its delivery
record, so parallel runs on several nodes never dispatch it twice.
- database and volume backups run once when they are late; tasks and Docker
  cleanups more than 10 minutes late are logged as missed
- a local time that occurs two times when the clocks go back runs once
- the migration continues each schedule after its last recorded occurrence and
  drops scheduled_job_states

Show the next run, in the server timezone, on the database backup, scheduled
task, volume backup, and Docker cleanup pages, or "Invalid frequency" when the
frequency cannot be calculated. scheduled:diagnostics now lists overdue
schedules and open deliveries.

Remove workarounds that are no longer needed: the queue overlap lock and its
stale-lock repair, the catch-up window, and debug-only logs.
2026-09-29 10:07:23 +02:00
Andras BacsaiandClaude Opus 5.5 dd7ad91ba2 fix(cleanup): delete old rows in batches and report the real count
cleanup:database used orderBy()->skip(10)->delete(). Laravel drops the offset
in a DELETE, so it deleted all old rows anyway, and the count query with the
offset printed 0 on PostgreSQL. Count without the offset, delete in batches of
1000 rows so a large table is not locked by one long DELETE, and write the
output through the command so it is captured.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 11:50:32 +02:00
Andras Bacsai 5f6fb5dcc2 feat(dev): run localhost dev server in a Lima VM on macOS
Add a Lima backend to scripts/dev. Auto mode picks it on macOS when
limactl (Lima >= 2.0) is installed, and COOLIFY_DEV_SERVER_BACKEND=lima
forces it. Lima VMs are named coolify-dev-<slot>-<profile>. Coolify
connects to them through Lima's forwarded SSH port on
host.docker.internal, and only guest ports 80/443 are forwarded to
the host.

dev:qemu:seed now takes --ip and --port options, so the seeded server
can use a forwarded SSH address instead of the profile IP.

Add tests for the Lima start flow and for seeding with an overridden
address, and document the macOS setup in AGENTS.md.
2026-09-28 09:45:29 +02:00
Andras Bacsai 5b61467e73 fix(proxy): flag Traefik restart after TLS certificate deletion (#12015) 2026-09-28 09:35:27 +02:00
Andras BacsaiandClaude Opus 5.5 2c6e221db5 feat(dns): release orphaned managed DNS records on a schedule
An hourly command releases managed DNS records whose references all point
to missing or deleted resources, or that have no references after a grace
period. Each record goes through the per-hostname lock and re-check, so a
hostname that a user adds back is kept. An empty reference list no longer
deletes all references of a record.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 21:09:13 +02:00
🏔️ Peak edcb884266 Merge branch 'main' into feat/add-sqlite-database 2026-09-26 21:32:43 +02:00
Andras BacsaiandClaude Opus 5.5 a8117f9114 fix(databases): unblock interrupted imports and prevent double starts
- A Coolify restart now fails queued or running database imports, so
  they no longer block all later imports with 409.
- An import without progress for the SSH command timeout plus 30
  minutes (at least 2 hours) is stale and no longer blocks.
- The import sets its operation property when the activity is created,
  so a worker cannot save the activity without it.
- Start and restart refuse a second operation while a start, restart,
  or import is in progress, in the UI, the API (409), and actions.
- DatabaseStartJob runs only while its activity is still queued and
  the newest one, and holds a lock per database during the commands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 10:40:53 +02:00
peaklabs-dev 5261785c69 Merge remote-tracking branch 'origin/next' into feat/add-sqlite-database 2026-09-25 22:47:29 +02:00
Andras Bacsai 554b79e8dd feat: add Traefik ACME cert UI and shared managed DNS record ownership
- Proxy: list and delete Traefik ACME certificates from the server proxy
  page via new TraefikAcmeService and Get/DeleteTraefikCertificate actions
- DNS: track ownership and cross-resource references for managed DNS
  records so records are only deleted when no longer referenced; release
  records asynchronously on resource deletion via ReleaseManagedDnsRecordsJob
  and ManagedDnsRecordCleanup; harden Cloudflare provider deletion results
- Databases: fail closed on start when prerequisites or the CA certificate
  are missing (DatabaseStartException, Server::ensureCaCertificate) and
  clean up stale start activities via ResourceStartActivity
- Webhooks: throttle repeated manual webhook signature failures for
  GitHub, GitLab, Gitea and Bitbucket
- Deployments: improve compose build-context handling and compose file
  load error reporting
- Install scripts: rework terminal UI output in install.sh (stable and
  nightly)
- Misc: settings sidebar accordion fixes, log drain toggle rollback,
  add Serverside to README sponsors
- Add migrations and tests covering the above
2026-09-25 19:00:00 +02:00
Andras BacsaiandClaude Opus 5.5 338f1f837f feat(dev): run one isolated dev instance per git branch
Merge scripts/dev-instances into scripts/dev. Each branch gets its own
Compose project, container, volumes, port block, libvirt network, and
KVM VMs, so stop and start reuse the same data and worktrees do not
collide.

- Name instances after the branch; keep slots and APP_KEYs in the main
  checkout's .dev-instances/ so they survive worktree removal
- Reuse existing QEMU VMs instead of recreating them; add dev:qemu --fresh
- Give each instance an isolated libvirt network (10.221.<slot>.0/24)
  and VM names coolify-dev-<branch>--<profile>
- Publish per-instance browser ports and publish them with tailscale
  serve when APP_URL is a tailnet host
- Add urls, exec, logs, container, destroy, and teardown commands; run
  teardown from jean.json before Jean deletes a worktree
- Fix Reverb/terminal browser ports and the testing-host alias in the
  instance compose file
- Keep fresh worktree instances working: pre-create laravel.log, log the
  host dev:qemu call to stderr, and stop Vite from watching vendor/

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 11:55:49 +02:00
peaklabs-dev 6c65df0b68 feat(commands): include sqlite in cleanup and delete commands 2026-09-24 19:03:43 +02:00
Andras Bacsai f35de6b3b2 feat(dev): support KVM-backed localhost development servers 2026-09-24 13:04:44 +02:00
Andras Bacsai a29f02fbb1 Merge remote-tracking branch 'origin/main' into pr-11443-next
# Conflicts:
#	openapi.json
#	openapi.yaml
#	resources/views/livewire/project/application/heading.blade.php
#	resources/views/livewire/project/service/heading.blade.php
2026-09-19 17:44:44 +02:00