- Add an Axiom edge domain setting (default us-east-1) and use the /v1/ingest endpoint, so EU datasets work
- Remove the Highlight drain (service ended) and stop its running containers
- Update Fluent Bit from 2.0 to 5.1 and use the warn log level
- Restart running drains when the generated files change, with the new image pulled before the old container stops
- Show log drain validation errors under their fields
Closes#9898
Add a "Use path-style URLs" setting to S3 storages. It is detected from
the endpoint (Alibaba OSS, Tencent COS, Volcengine/BytePlus TOS), and the
connection test switches to virtual-hosted style when the provider
rejects path-style requests. Backups pass `--path off` to mc.
Closes#10347
Add a Database schema and use it for GET /databases and
GET /databases/{uuid}, type the GET /resources items, and stop
requiring both environment_name and environment_uuid on create
endpoints. KeyDB now returns database_type like the other engines.
Closes#10449
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Only revoke a member's team tokens when the role goes down. Promotions
and ownership transfers on account deletion keep the tokens.
Closes#12342
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The compose parser queued ServerFilesFromServerJob for every volume on
each parse, and pages that only show data parse the Compose file. Each
sync also sent two SSH commands for each file.
- Queue the sync only for a compose deployment, and for each service
resource with file storages when the service starts or deploys.
- Read the compose service names without a parse on the Domains and
scheduled task pages.
- Check all file storages with one remote command, and stop when a
symbolic link, a special file, or an unknown state is at a file path.
- Keep the application path in a file storage when a pull request
preview is parsed. Preview deployments of the current parser write
their `-pr-<id>` copies through LocalFileVolume::forPullRequest().
- Remove the unreachable file sync from the service resource page.
A user database named coolify-db was backed up as the instance database,
which targeted the wrong container. It was also hidden from the server
database list and from status updates.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Refresh the navbar proxy status on the 30 s poll
- Skip Sentinel and server check auto-start while a proxy start or restart runs
- Use the StartProxy commands in RestartProxyJob, so Caddy restarts keep the
maintenance blocks and remove the Traefik logrotate sidecar
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Traefik and Caddy routes of applications now retry a failed connection
on another container, and the rolling update waits a configurable drain
time (default 5 seconds) after the new container is healthy before it
stops the old containers. The wait is skipped when no old container runs
or when the proxy labels changed, because the proxy drops a route that
two containers define differently.
Fixes#8627
The Compose file read uses a sparse clone without a checkout, so submodules
were never cloned. Now only the submodule that contains the Compose file is
cloned, with the credentials of the clone.
Closes#11018
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When "docker version --format json" did not return clean JSON (for
example, text from a shell startup file), validation stored 0.0.0 and
said that Docker was older than version 24. Validation now stores no
version and tells the user to run the command on the server. When the
version is too old, the message shows the detected version.
Closes#11089
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The legacy configuration hash encoded serialized environment variable rows,
so hashes from older versions never matched after an upgrade, and the
fallback compared the configuration with an empty one. Apps without a
deployment snapshot now report no pending changes, and their next
deployment rebuilds the image.
Closes#11101
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Import:
- Check every uuid in a bundle against a strict id format before any
write, and quote the SSH mux socket and key paths in local shell
commands. A bundle uuid could run commands in the Coolify container.
- Validate bundle fqdns, git source URLs, paths, networks, cron
expressions, and database ports; cap the number of items.
- Do not confirm that another team has a uuid.
- Refuse a project icon path with a uuid that is not a plain id.
Claim, finish, and migrate:
- Pass checklist step keys to wire:click with Js::from (stored XSS).
- Link only to https target server URLs.
- Validate target_instance_url in /transfer/complete; never prefill an
unverified URL for a transfer back; scope the transfer-back token to
write+deploy for 1 hour.
- Release on an owner marker only when it is newer than the own claim.
- Do not touch apps that only use the server as an additional
destination when an archive is released or deleted.
- Give Sentinel a new token on claim.
- Add a checklist step to remove the previous instance's SSH key.
- Block a transfer while backups or scheduled tasks run.
- Authorize refreshMigration and PrivateKey checkConnection, clear
tokens from Livewire state, hide migration log/error from members.
Archives:
- Refuse ip, user, port, private key, and Cloudflare tunnel changes.
- Throttle Enable management and require a free server slot for it and
for a transfer back.
- Skip cloud provider calls.
- Re-read force_disabled before each SSH command, so running jobs stop.
- Probe the import check target at the resolved address only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Rate limit the import check probe and refuse private, loopback, and
link-local targets on Cloud.
- Rate limit the SSH validation that an import starts, like other
server validations.
- Count only managed servers for the server limit, the limit check job,
and the subscription page. Archives of transferred servers are left out.
- Do not show the name of another team's archived server in the import check.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Volume backup notifications built links with route(), which uses APP_URL
in queue jobs and gave http://localhost links. Build them from base_url().
Closes#12285
- Skip TrimStrings and ConvertEmptyStringsToNull on the import route; an empty shared variable failed the whole import
- Keep compose parser versions, static ports, legacy variable keys, and only the bundle's variables and destinations
- Give the transfer back token the deploy permission that the import needs
- Move the Cloudflare tunnel DNS record with the server and park it on the source
- Refuse cloud server deletes, power on, tunnel and DNS changes, and scp for archives; skip their backup alerts and provider polling
- Add a column-level round-trip test, archive guard tests, and a live full-coverage transfer test
- Advance the GitLab App sequence in the dev seeder
- Build a valid compose device request (device_ids list, options mapping, blank driver)
- Map --gpus N to count and drop --gpus when GPU settings are enabled
- Validate only changed GPU values so stored legacy values keep working
- Detect NVIDIA GPUs and the container toolkit with the server details
- Show detected GPUs with a refresh button in the application GPU section
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- ServerSetting::patchStatus() summarizes the saved patch check
(updates, security updates, reboot required, error). Results saved
before security and reboot detection count as 0 and false.
- Grid cards show "N security updates", "N updates", "Patch check
failed", and "Reboot required" badges; the table gets a Patches
column from lg. The badge text is searchable.
- The toolbar shows a one-line team summary, for example "Patches: 2
servers with updates · 1 with security updates · 1 needs a reboot".
- Badges and the summary are shown only for servers where the user can
view the security pages (viewSecurity on the server), so members do
not see them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- New server settings: is_auto_security_updates_enabled and
auto_security_updates_time (maintenance window, HH:MM in the time zone
of the server). Both move with a server transfer.
- Debian/Ubuntu: install unattended-upgrades and write
52coolify-unattended-upgrades. `#clear` drops the distro origin lists,
so only the security origins stay (Debian <codename>-security, Ubuntu
<codename>-security, and the Ubuntu Pro ESM security origins). A
drop-in for apt-daily-upgrade.timer sets the time.
https://manpages.debian.org/bookworm/apt/apt.conf.5.en.htmlhttps://github.com/mvo5/unattended-upgrades/blob/master/README.md
- RHEL family: install dnf-automatic (dnf5-plugin-automatic on dnf5),
set upgrade_type = security and apply_updates = yes in
/etc/dnf/automatic.conf, and add a drop-in for dnf-automatic.timer
(dnf4) or dnf5-automatic.timer (dnf5).
https://dnf.readthedocs.io/en/latest/automatic.htmlhttps://dnf5.readthedocs.io/en/latest/dnf5_plugins/automatic.8.html
- Off removes the Coolify files, so the operating system default comes
back. Other package managers show "not supported".
- The schedule and the automatic updates share one form and one
unsaved bar. The remote commands run only when the automatic update
settings change; a failure keeps the old setting.
- Commands are written for non-root SSH users (tee and single sh -c
scripts) and were run in Debian 12, Ubuntu 24.04, Rocky 9, and Fedora
containers as root and as a sudo user.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>