- 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>
ServerValidated and ServerPatchCheckFinished used broadcastAs(), so Echo
listeners without a leading dot never matched them. Close the validation
dialog that a background job opened when the job finishes.
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.
BuildKit keys every RUN step on the --add-host names, so a container
that joins or leaves the network between two builds rebuilt all layers.
Leave out database backup and S3 import helpers, Sentinel, and the
proxy error page container.
Closes#12452
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Updating the image of a service named like "api.test" wrote a nested
"test" key into the "api" service, because data_get/data_set split the
name on dots. Use array key paths instead. Also refuse service names that
Docker cannot use as a container name prefix, with a clear error on save.
Closes#12456
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
GitHub rejects new RSA SSH keys smaller than 3072 bits, and phpseclib
made 2048-bit keys by default, so new RSA deploy keys from Coolify
could not authenticate.
Closes#12461
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>
Compute accent text per page and sidebar surface to reach 4.5:1, move fill shades away from their text, pick the fill text by exact WCAG contrast, show the real fill in the preview, and use the theme surface for light custom wells.
Closes#12468
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Account menu entries, including Log out, now follow the sidebar text color
when a custom theme sidebar uses the other light/dark scheme than the page.
In the 3D style, the current page label keeps the sidebar text color,
because that row has no Selected fill.
Closes#12467
Remove the obsolete -webkit-overflow-scrolling: touch rule from the
table and log scroll containers in app.css, and the matching inline
styles from the scrollable bodies of modals, dialogs, the global
search create modals, the domain settings, subscription and upgrade
views. Modern iOS Safari scrolls with momentum by default, so these
declarations no longer did anything.
- 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).
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>
- Add an albums service for public links, with its own domain
- Pull images from ghcr.io/ente (ghcr.io/ente-io denies pulls)
- Generate a URL-safe JWT secret, so Museum can decode it
- With S3: use the routed MINIO_SERVER_URL as the S3 endpoint, allow
all CORS origins, and drop the SMTP defaults
Closes#7405
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Odoo keeps its data in databases that the user creates in Odoo, so the
POSTGRES_DB=postgres database that the backup used was empty. Also show the
sections of the edit backup schedule modal without nested cards.
Closes#7555
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 the Coolify default variables sent no project,
environment, or service to the drain. The fluentd driver now also sends
the Coolify container labels; the built-in configs use them as a
fallback and add coolify.service_name.
Closes#8415
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Variables saved before exact escaping wrote JSON objects and arrays
without quotes. A multi-line JSON value broke the .env file, so Docker
Compose stopped the deployment. These values now use exact escaping,
which gives the container the same value as before beta.463.
Closes#8279
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Read the running version from the container that answers the status request, not from the old page state, so the modal shows success as soon as the new version is up. Hide all Livewire error pages while an upgrade runs.
Closes#8024
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
BuildKit lets the Docker CLI in the helper fetch the registry token, and
the helper trusts only its own CAs. Behind a TLS-inspecting proxy, builds
failed with x509 errors although the server trusts the proxy CA. Mount
the server CA bundle read-only into the helper.
Closes#7568
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
A preview renames its services to <name>-pr-<id>, so services that call
each other by their Compose names failed to start. Add the original name as an alias on the preview network.
Closes#8030
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>