Grype was killed at the fixed 1 GiB container limit on large images.
- Add the per-server setting image_scan_memory_mb (1, 2, 4 or 8 GB,
default 1 GB) on the Vulnerabilities page and in the
/servers/{uuid}/image-scanning API.
- Set GOMEMLIMIT to 85% of the limit, so Go collects garbage before
the container limit kills the scanner.
- The out-of-memory error now tells the user to raise the limit.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Require the write permission and update policy to open a preview or
change its pull request URL, git type, or docker tag via the API;
deploy-only tokens can only redeploy an existing preview
- Reject rollbacks to commits that are neither a listed rollback image
nor a successful production deployment (GetRollbackImages::allows)
- Validate git_repository with ValidGitRepositoryUrl when it changes on
application update
- Add RejectPublishedAppKey global middleware
- Show a "still starting" message when the root setup window is pending
- Document the new 403 responses and constraints in the OpenAPI spec
- Add tests for the new checks
- Use the limits of the API token in more permission checks.
- Show a clearer message when a token limit blocks a change.
- Describe API tokens with limits in SECURITY.md.
Scanning is now controlled per server and per app. Each server downloads
the Grype database from its default source.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On self-hosted, a validation that connects now clears force_disabled. The unreachable cleanup skips the localhost server, and the server page explains why a server is disabled. Cloud and transferred servers stay disabled.
Closes#12475
An empty port routes to the required port, so it needs no confirmation.
The edit dialog shows the effective port, the warning buttons name the
ports, and domain conflicts ignore the container port.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Restores, downloads, and the import check refuse an SFTP storage without a saved host key.
- Only Validate, Save, Create, and the API validate endpoint save a new key; backup and
revalidation jobs do not.
- An endpoint change or a host key reset marks the storage unusable.
- Save the key only when the endpoint did not change during the connection test.
- Queue a status sync for deployments that Init, fail_undispatchable_deployment, and
superseded cancels change with a query update, so GitHub does not show them as
in progress forever.
- Run SyncGithubDeploymentJob on the default queue with 10 s GitHub request timeouts
and a 100 s job timeout, so a slow GitHub cannot delay deployments.
Anonymize the audit events of a deleted user, store only the ID and
name of other users, and drop the metadata copy of actor_email.
Store URLs without query strings, registries without user info, and
the exception class instead of raw SSH errors.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Set env var version and compose parsing version while creating, so a create writes one row
- Record no rows for the auto-created preview copy of an env var
- Record env and application API updates only with the fields that really changed
- Store no change data for new env vars, and null for empty change data
- Store metadata team_id as an integer
- Drop the unused level and resource indexes of audit_events
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Preview containers (-pr-<id>) came and went with pull requests and
invalidated the build cache of every app on the network. A build server
got the IPs of the deployment server network, which it cannot reach.
Add a per-app setting to turn off network hosts during the build.
Closes#12452
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Disable a scheduled task after at least 5 failed runs in a row with no
success for 3 days, notify the team, and show the reason on the task page.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add GET /gitea-apps, POST /applications/private-gitea-app, and
gitea_app_uuid in PATCH /applications/{uuid}, with OpenAPI docs and MCP tool support.
Closes#12459
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Read compound and fractional durations (1m30s, 1.5m), quoted values,
only the flags before CMD, the escape parser directive, and NONE with
flags. Zero and sub-second values no longer become 0 seconds.
Closes#12455
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Add a hint to failed command messages when the exit code is 255,
which explains that the SSH connection to the server closed before
the command finished.
- Return no services from applicationParser and serviceParser when the
compose `services` key is empty or is not a map, so parsing does not
fail.
- Move Server::getIp() out of the sshEndpointInUse() docblock, where it
was misplaced and broke the class.
- Add tests for the SSH hint, for services keys that are not maps, and
for saved compose variable values that must survive a redeploy
(#6995).
A locked variable used by Docker Compose could not be changed, unlocked,
or deleted, so a lock by mistake had no fix in the UI. A locked value can
now be replaced without showing it. The lock is permanent in the UI, the
API, and MCP, and Lock asks for confirmation.
Closes#6803
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Containers without sh (distroless or scratch images) could not run
scheduled tasks, because Coolify always ran the command with sh -c.
Turn off "Run in a shell" to split the command into arguments and run
it directly. The option is also in the API, the MCP tools, and the
server transfer.
Closes#8244
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The queue counted every running deployment against the deployment server,
and the job picked a build server at random. So the deployment server
limit capped builds on build servers, and the build server limit was
never read. Count each build on the server that runs it, reserve a build
server with a free slot when the deployment starts, and start waiting
deployments of other servers when a build server slot is freed.
Closes#7649
caddy-docker-proxy reloads Caddy whenever any proxied container changes,
and Caddy closes every WebSocket on reload by default. Set
stream_close_delay on app, service, and dashboard reverse_proxy routes.
Closes#7942
The MinIO client rejects endpoints such as `/storage/v1/s3`. Transfers to
these endpoints now use curl with a presigned URL that Coolify signs, for
database backups, volume backups, and S3 restores.
Closes#8530
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Team notifications sent through the instance email settings, the S3
connection error alert, and the channel disabled alert now use the
optional notification from address and name. Account mails keep the
default sender. Remove the unused emails command and its views.
Each new SSH connection opens a systemd-logind session. Some systemd
versions leak closed sessions until the host refuses logins at 8192.
The connection check now opens one new login (the probe), not three.
Closes#9148
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A preview deployment set COOLIFY_BRANCH in three places with three
values: the Compose shell variables used the application branch
(main), the Compose parser used pull/<id>/head, and other build packs
used the fetched refspec (pull/<id>/head:pr-<id>-coolify) or the
application branch. A variable that refers to ${COOLIFY_BRANCH} then
got a different value than the container. All paths now use
Application::coolifyBranch(), which gives pull/<id>/head for previews
and git_branch for production deployments.
Closes#9572
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
S3 storages with a self-signed or private CA certificate failed with
"cURL error 60", because the Coolify container and the backup helper do
not use the CA certificates of the host. The new opt-in setting turns off
the certificate check in the PHP S3 clients and sets MC_INSECURE for mc.
Closes#9762
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Deleting a server with "Delete all resources" (UI) or ?force=true (API)
deleted every application that used the server, also applications that
use it only as an additional destination, for example after Promote.
Server delete now deletes only resources whose main destination is on
the server. Applications that use it only as an additional destination
lose their additional_destinations row for the server, and their
containers on it are stopped (best effort). The check for resources and
the transfer archive path use the same Server::primaryResources().
The delete confirmation lists the resources to delete and the
applications that keep running on another server.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>