Sentry self-hosted (getsentry/self-hosted 26.8.0) could not be deployed
as a Docker Compose application. Three separate problems blocked it:
- YAML collection aliases: the first fix raised the limit to 256 only in
Application::oldRawParser(). The safety check added in v4.4.0
(validateDockerComposeForInjection) and all other Compose parse calls
still used the Symfony default of 128, so the Sentry file (133 aliases)
failed with "Maximum number of collection aliases (128) exceeded".
Add parseDockerComposeYaml() and use it for every Compose parse.
- Argument list too long: the deployment job sent the generated Compose
file as base64 inside the SSH command. Linux limits one argument to
128 KiB, and the Sentry file is about 370 KB. execute_remote_command()
now accepts an 'input' key that streams content over SSH stdin, and
the job writes the Compose file with it.
- A list-style build arg without a value (build.args: [SENTRY_IMAGE])
merged into a map environment kept its numeric key, so Docker Compose
rejected the file with "non-string key in ...environment: 0". It now
becomes NAME with no value, as in Compose.
Closes#11725
Count running scheduled tasks, database backups, and volume backups,
excluding runs older than their job timeout. Report scheduled job counts
and keep the progress check active while any scheduled jobs are running.
Keep reserved jobs active and bound missing Horizon records by the server's
deployment timeout. Add regression coverage for active and finished jobs.
Use UTC PostgreSQL sessions and bump the release version to 4.4.1.
Since aabd12737 a Compose bind volume with a content block had to stay
inside the resource directory. Services and Compose applications saved
in v4.3.23 with other paths, and Git Compose files with them, no longer
started or deployed.
Only admins and owners can edit Compose files, and they can already
write any host file with a plain bind mount, so the rule added no
security.
- Write content files to their host path again, as in v4.3.23
- Keep shell escaping and the safe-character checks on volume sources,
so injection attempts are still rejected
- A dispatch failure for one additional server no longer skips the
other servers or the combined notification
- After a deployment fails to dispatch, the queue starts the next
queued deployment; nested queue advances run in a loop, not as
recursion, so repeated failures end
- A queued deployment on a deleted server no longer stops the queue;
one deployment that fails to start does not stop the others
- Cancelling a deployment starts the queued deployments of the same
application on all servers, as a finished deployment does
The sudo parser read everything after `mkdir -p` as the path, so the
ownership step ended up after the last command of the line. For
`mkdir -p /data/coolify/proxy/dynamic && ls ... | head -n 1000`, `head`
got the `find` options and the proxy dynamic configurations failed on
every server with a non-root user.
- Add the ownership step right after the mkdir path; commands after
`&&` or `;` stay unchanged
- Lines with other forms (redirects, `||`, pipes) get no ownership step
Previews of Docker Compose applications used external volumes as
written, so a preview mounted the production volume. Two database
containers on the same data can corrupt it.
- A preview uses {uuid}_<name>-pr-N with a name-only declaration, the
same name as v4.3.23, so old preview volumes are used again
- Production still uses the external volume as written
- Preview cleanup removes the preview volume, never the external one
- Do not show the external volume warning for previews
When a deployment on the primary server finished, deployments of the
same application queued on an additional server did not start. They
waited for the primary deployment, and then no queue event came for
their server.
- Also advance every server that has a queued deployment of the
application; the per-server and per-application limits still apply
When a deployment on an additional server finished, only the queue of
the primary server advanced. Deployments queued on the additional server
could wait with no limit.
- Also advance the queue of the server of the finished deployment
When the job constructor or the dispatch threw (for example, an invalid
registry image name), the deployment stayed in_progress. It blocked
later deployments of the application and used a build slot.
- Mark the deployment failed with fail_undispatchable_deployment()
- Throw the error again, so the UI and API still show it
Service compose and .env content was sent inline in the SSH command.
Linux limits one argument to 128 KiB, so a service with a generated
compose over about 96 KB failed to save or start with "Argument list
too long".
- Add instant_remote_write_file(), which streams content to a remote
tee over SSH stdin (sudo tee for non-root SSH users)
- Add SshMultiplexingHelper::generateSshStdinCommand() with the same
SSH options as generateSshCommand()
- Write the service compose and .env with the new helper
The container lookup matched the pullRequestId label as a substring, so
PR 1 also matched PR 12, 13, and 100. Deploying, closing, or deleting one
preview could stop and remove the containers of other previews.
Scope resource permissions and related records to the owning team across
team switches, cloning, deployments, and resource operations.
Merge ClickHouse volume mounts, preserve anonymous data volumes on stop,
and require adopting current data before starting or restarting.
Fix file storage deletion checks and add regression coverage.
Require deploy or root token access when creating managed mounts outside
resource directories or changing their file contents through the API.
Synchronize KeyDB and Dragonfly passwords with local and shared
REDIS_PASSWORD values while preserving secret manager resolution.
Add audit events for account actions, server and application settings,
services, destinations, storage, backup schedules, and scheduled tasks.
Track changed fields and skip unchanged saves without logging file content.
Add regression coverage for audit events and changed-field detection.
- On cloud, RestartService and RestartServiceApplication now run on the
deployments queue instead of high.
- StartProxy and RestartProxyJob, and the remote processes they start,
now run on the deployments queue.
- Self-hosted still uses the high queue.
- Tests cover the new routing.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- CheckAndStartSentinelJob returns early when the server is not
functional. It now reads the container state with `docker ps --filter`,
so an SSH failure throws and is no longer treated as a missing
container that needs a restart.
- ServerManagerJob only dispatches the Sentinel version check for
functional servers.
- On cloud, ServerPatchCheckJob runs on the maintenance queue and
ServerLimitCheckJob runs on the webhooks queue.
- The default number of cloud maintenance workers goes from 10 to 60.
- excludeCertainErrors drops its unused ignore list and is typed as
`never`.
- Docs and the Horizon config comments are updated, and tests cover the
new behavior.
On cloud, GitHub pull request webhooks and Stripe events now run on a
dedicated `webhooks` queue so a busy `high` queue cannot delay them.
Self-hosted instances keep these jobs on `high`.
- Add webhooks_queue() helper and use it in ProcessGithubPullRequestWebhook
and StripeProcessJob
- Provision a `webhooks` Horizon pool in cloud production, sized by
HORIZON_WEBHOOKS_PROCESSES (default 10)
- Document the new pool, rollout and rollback steps
- Cover pool provisioning and job queue routing in tests
Recovery attempts now back off exponentially, stop after 8 attempts, and
mark the execution as needing attention with a failure category. The
scheduler dispatches at most 100 recovery jobs per run, and a pending S3
cleanup no longer blocks new backups. S3 delete errors now raise with
their cause.
Cloud production now runs one supervisor per queue (deployments, crons,
high, default, maintenance), so a busy queue cannot starve the others.
Add maintenance_queue() for slow Docker cleanups and a shared
horizon.worker_timeout config value. Self-hosted keeps the s6 supervisor.
On cloud, StartService and DeployServiceApplication dispatched their
CoolifyTask on the high queue, so service starts competed with all other
high jobs. remote_process() and CoolifyTask now accept a queue (default
high); start paths pass deployment_queue(). The queued RestartDatabase
action also runs on deployment_queue() instead of the default queue.
The line edits ran on the whole proxy compose file. When another service
had the same labels, the safety check failed and the dashboard fix was
skipped without a warning. Limit the edits to the traefik service block,
so other services stay unchanged and the fix is applied.
A preview volume no longer gets driver_opts that name a host device, so it
does not mount the same folder or disk as the production volume. tmpfs
options are kept.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pipes in single or double quotes (Go templates, sh -c scripts) are text,
so the non-root sudo parser now leaves them unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Ignore status, heartbeat, and check fields that background checks write
during a user request.
- Record repeated unauthenticated failures (failed logins, API auth,
webhook signatures) once per source in a short window.
- An explicit null team_id in the context is kept, so instance events are
not stored on the admin's current team.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Only password-less users from before OAuth identities skip the provider
email verification claim. Otherwise an unverified provider account with
the email of a password user (including root) could sign in as them.
- Build the default callback URL from the instance URL, not the request
Host header, and do not save it during a login.
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>
A renamed template keeps its old key as an alias, so API callers and
services stored with the old key still find the template.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>