The root setup window and the scanner disk usage checked is_int() on
cached values, but the Redis store returns numbers as strings. The
setup window was closed right after each start.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
- Treat a commit value on the preview endpoint as a preview change
- Update the API docs, the MCP tool description, and the change file
- Add a test case
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The backup upload returned a hard-coded 500 when the database uuid was
unknown or belonged to another team. It now returns 404 with the same
JSON error shape that the import form reads.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Drop the RejectPublishedAppKey middleware and its registration in the
HTTP kernel, so requests are no longer refused with a 503 when APP_KEY
or APP_PREVIOUS_KEYS matches a key shipped in the repository.
Rename PublishedAppKeyTest to DecryptWithoutClassesTest and keep only
the checks that Sentinel tokens and team channel payloads are decrypted
without unserializing objects.
- 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
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>
- Show a clear message when team-wide write access is needed to use
team credentials.
- Reset the S3 selection on the backup page when a change is not allowed.
- Do not save database backups to S3 when the API request does not
send save_s3, as the API documentation says.
Change the standalone_redis image column default to
valkey/valkey:9-alpine. Existing databases keep their current image.
Update the API docs, OpenAPI specs and image helper text to name Valkey
as the default and redis:8 as the Redis example.
Also restyle the status badges and database image cards on the new
resource page.
Raise the Reverb max request size and store the remembered list view
cookies unencrypted, so the WebSocket handshake no longer fails with 413
and live updates (like proxy restart logs) reach the browser.
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>
- Return 429 after 30 failed (401/403/404) requests per minute for one
token or IP, also for unknown API routes (API_FAILED_REQUEST_RATE_LIMIT)
- Notify the team once a day when a token reaches the limit
- Deduplicate ability_denied and scope_denied audit events for 5 minutes
- Send Retry-After: 300 when the server is not functional
- Send Retry-After: 3600 when the push token cannot be decrypted
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>
- Reply 410 for deleted servers and 402 for unpaid teams, with Retry-After
- Remove the Sentinel container of unpaid servers once a day, and before a server is deleted
- Record server_not_found and subscription_unpaid push failures once per hour
- Audit scheduled task API updates only for fields that really changed
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add gitea_app_uuid to the allowed fields for application create and
update endpoints, with string validation on update, so Gitea App
sources can be set through the API.
Add a test checking that a closed GitLab merge request on the manual
webhook closes the matching preview and loads only applications of
that repository.
The API and MCP saved names and descriptions that the UI rejects, so the
resource could not be saved in the UI after that. Applications, services,
databases, servers, and private keys now use the UI name and description
rules on create and update, with the UI error messages.
Closes#12466
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>
The deploy endpoint now checks the deploy permission before it creates a
preview or changes its image tag, not only before it queues the deployment.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
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.
Stop calling /zen before each installation token request. A short
network problem to GitHub failed deployments with a cURL timeout on
/zen. assertGithubClockInSync now takes the failed response and reads
its Date header, so the "System time is out of sync" error still shows
when GitHub rejects the JWT.
Call it on failed JWT requests in the webhook installation check, the
permission job, the source connection test, and the server transfer
checklist. Remove the /zen fakes from the tests.
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>
The domain check of the transfer checklist resolved the server host name
with gethostbynamel(), which returns IPv4 only, so a domain that points to
an IPv6-only server was reported as pointing to another address. Resolve A
and AAAA records and compare normalized addresses. The Cloud SSH probe now
also resolves AAAA records when a host name has no A record.
Closes#12397
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Every channel has a block of its own, every version after this one reads only these blocks
- Every stable sync also fills the coolify and traefik keys older instances read
- An instance keeps a copy of versions.json and reads upstream.json of the image until it has one
- Require write access on the target environment to clone or move a resource
- Check read access on shared variables before a reference is added or resolved
- Limit team credentials, git sources, and imports of other backups to team-wide writers
- Require the delete level for backup, volume, storage, and task deletes
- Require create access for previews, new projects, and git sources
- Use the token team for the access scope, and check team-wide access on Livewire updates
- Require instance admin to toggle the API and MCP server
- Hide server pickers and broadcast details from members without access
- Check read access on the project or environment for shared variables
pages, the canvas, and the sidebar, not only navigation access
- Require team-wide read for the server shared variables canvas API
- Open the environment variable editor read-only when the value is hidden
- Show the integration tokens button only to users who can open it
- Show disabled confirmation buttons as disabled, not as danger buttons