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.
Connection URLs of KeyDB, Dragonfly and Redis queried their password
variables once per database, so the database list API ran extra queries
for every database.
- Read REDIS_PASSWORD and REDIS_USERNAME from the loaded relation
- Load the variables once per type in the database list and the
environment details API
v4.3.23 started Redis with the stored REDIS_PASSWORD value as it is and
unquoted, and the connection URLs used the same value. 4.4.0 resolved a
shared variable reference for the start command only, so after the first
restart the server password changed and no longer matched the URLs.
- Add legacy_password_quoting to standalone_redis; existing databases
keep the v4.3.23 server password
- New databases resolve REDIS_PASSWORD (local, shared or remote secret)
and quote it in the start command
- Connection URLs use the same password as the server
- Hide the flag in the API, as for KeyDB and Dragonfly
Since 50268139b the API returned 422 for custom_internal_name without
is_consistent_container_name_enabled. v4.3.23 accepted it, so clients
such as `coolify app update --custom-internal-name` broke.
- A custom_internal_name sent without the flag turns the flag on, the
same rule as the migration for existing applications
- Keep the 422 only when the request sends the flag as false
A pull request id above 2147483647 caused a database error and a 500.
- Previews store: validate max 2147483647 (422)
- /deploy: return 400 for pr or pull_request_id out of range
- Preview show, logs, update, and delete: return 422 for ids out of range
- Document the maximum in the OpenAPI spec
Container names use custom_internal_name only when consistent container
naming is on. The API accepted the name and then ignored it.
- Return 422 with a message that says to set
is_consistent_container_name_enabled to true
- Accept the name when the request or the application turns the setting on
- Document the requirement in the OpenAPI spec
An import with source=server reads a file at an absolute path on the
server, but it needed only the write ability.
- Return 403 without the deploy or root ability, the same as other host
paths outside the resource directory
Allow validated host file and directory mounts outside resource directories
while protecting external paths from deletion.
Clean up cancelled deployment containers and clear tracked process IDs.
Preserve legacy KeyDB and Dragonfly password parsing, accept server backup
paths without extension restrictions, and allow Compose variable proxy ports.
Different database types can share an id, so the database list showed
backup configs of other databases.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- References to locked (shown once) shared variables keep their reference
text in the UI, copy action, and API instead of the locked value.
- Remove the saved proxy configuration and validation logs from nested
servers (for example destination.server) in API responses unless the
token can read sensitive data.
- The services list API now applies removeSensitiveData to every service.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Try to remove every volume and always delete the configuration
directory (it holds the .env with secrets), then report the volumes that
failed.
- Delete volume backup schedules also when a service is removed from
Coolify only.
- The delete API no longer claims the server is unreachable when the
caller asked to delete from Coolify only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Uploading and starting a database import overwrites data, so a deploy
token is no longer enough. Import activity IDs must be numeric.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Return database import output from the API only when the token has
read:sensitive and the user can update the resource. Otherwise the
output field is null.
Give the temporary PostgreSQL restore databases random suffixes. Before
restoring, check that neither name is already taken instead of dropping
any database that already uses it. The old database is no longer
dropped before the swap, so unrelated databases are left alone.
Add API tests for output visibility by role and token ability. Add
restore script tests that run against stateful PostgreSQL client stubs.
New SQLite backup schedules copied the database's file list at creation,
so files added later were never backed up. Schedules created in the UI
or the API without an explicit file list now store none, and the backup
job resolves the current files at run time. An explicit choice is still
stored. Existing schedules are not changed.
- 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>
- 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>
Reject delete_from_provider values that are not booleans, and reject the
request when the team has no token for a linked cloud provider. Before,
both cases removed the server from Coolify but kept the cloud VM running.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Delete Blade components, component classes, Livewire components and
views that nothing uses after the redesign.
- Delete tests that only compare Blade/CSS source text; keep the source
checks for authorization gates, stable wire:key values and escaping.
- Update stale tests to the current UI and behaviour.
- Update DESIGN.md to the current navigation and layout.
- Add a lesson: test behaviour, not source markup.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Caddy 2.7.6, shipped in the caddy-docker-proxy 2.8 image, rejects the
whole Caddyfile when it contains log_append. Add
Server::caddySupportsLogAppend(), which reads the image from the applied
proxy configuration. Traffic analytics labels now add log_append only
when the server runs 2.9 or newer and has no pending proxy change.
- Change the default Caddy proxy image from 2.8-alpine to 2.13-alpine
- ProxyPortParser now validates Docker Compose port ranges and random
host ports. It returns only fixed host ports for the availability
check and has a clearer validation message
- After mkdir, chown only root-owned files and remove other-user access
from the top directory only. Files owned by container users and the
modes of mounted files no longer change
- Add tests for log_append support and the new parser/sudo behaviour
- Note in the lessons file that tests must flush the Server identity map
between dataset cases
Use the shared Docker container-name rules for custom internal names
in the API and Advanced settings form. Quote container names in
deployment inspect, log, and stop commands.
S3-compatible and legacy buckets may include uppercase letters. Relax the bucket name pattern, validation messages, and tests so those names are accepted while still rejecting invalid characters and formats.
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.
Remove the enable/disable toggle from the server UI, logs page, and
Sentinel API so is_sentinel_enabled is derived and read-only. Enable
existing regular servers via migration, start Sentinel after validate-
and-install, and drop the daily ServerManagerJob restart.
Centralize scp-style Git URL parsing so user@host:path (including custom
usernames and embedded ports) is accepted and converted to HTTPS for
public clones, API create, webhooks, validation, and commit/branch links.