- 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>
- server_settings gets patch_check_result (JSON), patch_check_error,
patch_checked_at, and patch_check_frequency.
- The patches page shows the saved result and "Last checked" on load.
"Check for updates" queues ServerPatchCheckJob (manual) instead of
running SSH in the Livewire request. The job saves the result and
broadcasts ServerPatchCheckFinished on the server team channel; the
page reloads the saved result (with a 10 s poll as a fallback).
- A finished package update (callEventOnFinish) queues a new check on
the server side, so the page no longer depends on the browser.
ServerPackageUpdated is removed.
- The check frequency is a server setting (cron or preset, at most once
per hour). Empty keeps the staggered weekly default.
- The failure notification is sent only when the state changes from ok
to error, not on every check.
- Page access needs viewSecurity and every action needs update on the
loaded server; a member gets 403. Updates accept only a package from
the saved result.
- Server transfer: the frequency moves, the last result stays on the
source (runtime).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Enable Fortify passkeys (laravel/passkeys) with the @laravel/passkeys
client. Users can sign in with a passkey, confirm sensitive actions with
one, and add, rename, and delete passkeys on the Profile page.
- Resolve the relying party for each request from the instance URL, then
APP_URL, then localhost. Passkey routes return 404 on other hosts.
- Add the is_passkey_enabled instance setting (Settings > Advanced).
- Use a hex user handle (laravel/passkeys-server#41).
- Rate limit the passkey routes by client IP.
- Record audit events for registered, verified, and deleted passkeys.
Count invalid keys, tokens, and deleted webhooks in a new failure_count column
on each notification settings table, like servers.unreachable_count. After 3
failures in a row the channel is disabled and the team is told by instance
email and its other channels. Rate limits and server errors are retried and
not counted; test notifications never count.
Move all git examples into ApplicationSeeder on railpack, using the
reorganized coollabsio/coolify-examples main branch, and drop the
separate Railpack Examples project. Add DEV_SEED_IP to set the IP for
seeded sslip.io domains (e.g. a Tailscale IP).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Applications and service applications can now use the server resolver,
no resolver ("none"), or a custom resolver name. This allows servers
that mix Let's Encrypt domains with domains that use their own
certificates, such as Cloudflare Origin CA. The setting is available in
the UI and the API.
Closes#12138
Set the resolver to null when saved Traefik configuration has no active letsencrypt resolver. Preserve existing settings for active or unknown configurations and log parsing failures.
Add regression coverage for missing, active, unknown, and malformed configurations.
Coolify always added tls.certresolver=letsencrypt to generated HTTPS
routers, so Traefik logged errors when the proxy used its own
certificates (for example Cloudflare Origin CA) without that resolver.
Add a server setting (default letsencrypt) in the proxy page and API.
An empty value omits the resolver from resource labels, the Coolify
dashboard routes, and the catch-all router.
Closes#12138
- Stop the Redis username accessor from creating REDIS_USERNAME on read
- Keep source values when cloning applications (no duplicate NIXPACKS_NODE_VERSION)
- Match exact keys when adding default database environment variables
- Write content files before database containers start
- Resolve the database proxy upstream through Docker DNS on each connection
- Remove existing duplicate REDIS_USERNAME and NIXPACKS_NODE_VERSION rows
Store server IPs in one form (no brackets, short lower-case IPv6) and
write each address in the form its context needs:
- URLs and host:port (Sentinel, database URLs, SFTP backup download,
DNS servers, SMTP, webhook base URLs, links, health checks) get
brackets through formatHostForUrl().
- Traefik Host() rules use the address without brackets, so IPv6
domains no longer return 404; saved labels are fixed at deploy.
Caddy keeps the brackets.
- SSH keeps the plain address.
- Hetzner gives an IPv6 /64 network; IPv6-only servers now get the
server address (prefix::1) instead of the unusable prefix::64.
- sslip labels, registry image names with an IPv6 host, the API domain
list, allowlist matching and duplicate checks handle IPv6.
A migration normalizes stored IPv6 server addresses, repairs Hetzner
servers saved as ::64 that are not reachable, and adds brackets to
saved Sentinel URLs.
Allow full, anonymized, or disabled IP recording per server through the UI
and API, and pass the selected mode to Sentinel. Adapt traffic breakdowns
to the effective IP mode, including views that aggregate multiple servers.
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.
- Update tests whose expectations no longer matched intended changes
(GitHub App redirect, wildcard domains, container IDs, nightly
install folders, localhost metadata, Sentinel restart on save)
- Seed the instance settings the 2FA profile test needs
- Run the global Pest hooks for all test folders and release the
Laravel application after each test, so tests do not leak state
- Replace a class alias mock that broke later tests
- Generate factory names that always pass name validation; Faker names
with apostrophes or short words made form tests fail at random