An all-databases MySQL/MariaDB restore also restored the mysql system
database, so after the next restart the root and app passwords were the
source ones and the MariaDB health check failed. The restore now skips mysql,
sys, performance_schema and information_schema by default. The new option
"Restore users and privileges" (restore_mysql_users in the API) keeps the
old behaviour.
- database import: add keep_owners (restore PostgreSQL owners and
privileges) and sqlite_database (pick the target SQLite file) to the
API, OpenAPI spec, and import form
- oauth: require password confirmation and support team selection on
OAuth login
- remote process: send team broadcast events to the team of the server
that ran the process instead of the causer's user id
- servers API: handle the legacy build server setting
- compose: support parent bind paths and volume driver options
- dns: improve record hints and provider management
- notifications: fix throttling and missing backup notifications
- ui: rework the confirmation modal
- add feature and unit tests for the new behavior
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.
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>
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.
- Stop the application on every server, also when one server is not functional.
- Write file mounts on every server of the application, not only on the main server.
- Deploy the exact commit, rollback flag and image tag of the main deployment to the
additional servers, so a rollback reverts all servers.
- Pull the pushed image on additional servers for inline Dockerfile applications
instead of building it again on each server.
- Fail multi-server deployments without a Docker image name, also from webhooks and the API.
- Send one deployment notification after all servers finish (parent_deployment_uuid).
- Block persistent volumes on multi-server applications (API, Livewire, SQLite connect)
and warn in the deployment log for existing applications that have both.
- Remove dead code in push_to_docker_registry().
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Imports store their cleanup data (names and paths, no credentials)
on the activity. When Coolify fails an import after a restart or as
stale, it queues a stop of the restore inside the database container
(only processes of that operation and their children, bottom-up so
the database server is not affected) and the normal cleanup.
- The cleanup runs once per import, and a stopped CoolifyTask does
not run again when the queue retries it.
- The stop message stays on the activity: RunRemoteProcess saves the
process id at start from the stored properties and keeps a stop
status at the end, and CoolifyTask::failed() keeps the message.
- Regenerate the OpenAPI spec (409 for database start, restart, and
import, plus earlier API changes that were missing).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Move service application and database settings into an embedded modal with a footer, subtitle helper, and Docker restart-count control. Accept max_restart_count on the service applications API, cap compose YAML collection aliases, and tighten status, backup, and database sidebar layouts.
Move database import temp/container cleanup into a queued listener with retries, and clear the import running state on failed restore starts. Tighten Cloudflare replace/delete to the current server IP and owning resource, notify when DNS jobs fail, and pass domain-removal confirmation through remove-by-key. Document import request oneOf schemas without extra properties.
Allow single-database PostgreSQL imports to drop matching objects before restore. The API and import form accept replace_existing, which adds --clean --if-exists to pg_restore, and pg_restore now uses --exit-on-error.
Replace min-h-screen with min-height: 100dvh on body for correct
mobile viewport height, and point the auth shell radial glow at
--color-coollabs instead of --color-accent. Add branding CSS tests.
Users can upload and remove profile pictures on the profile page.
Admins choose local or instance S3 storage in advanced settings.
Avatars are compressed to JPEG and served via a private cached route.
Make start/stop/restart, deploy, enable/disable, and server validate
POST-only, with GET returning 405. Server validate accepts optional
install and uses ValidateAndInstallServerJob. Update OpenAPI and tests.
Expose DELETE for application, database, and service storage backup
schedules (with OpenAPI docs), reject storage deletes while schedules
exist, skip retention cleanup when no limits are set, and remove S3
archives using the execution’s S3 storage.
Add polymorphic volume backup scheduling for persistent volumes and directories, expose schedule management via API, and reorganize backup configuration and execution views.
Persist DigitalOcean, Hetzner, and Vultr servers before public IP
assignment, then backfill placeholder addresses from provider state.
Treat partial Sentinel snapshots as non-authoritative and document the
destinations API with OpenAPI schemas.
Require IPv6 when public IPv4 is disabled, constrain cloud token
lookup by team and provider during deletion, and encode Vultr instance IDs
in API paths.
Normalize tag names before attaching them, reject names that are too short
after sanitization, and return 404 when removing tags not attached to the
resource.
Adds a per-team unique tag-name index and migrates duplicate tags onto the
kept record before creating the constraint.
Expose is_preview_deployments_enabled in the application create API
schema and validation, and skip deployment configuration column casts on
sqlite migrations.
Clamp log line counts, parse timestamp flags consistently, and filter
service subcontainers by Coolify labels. Document log endpoint timestamp
parameters and database/service log routes in OpenAPI.
Skip Docker healthcheck configuration when standalone database health checks are disabled, and document default health check settings in the database API schema.