2464 Commits
Author SHA1 Message Date
Andras Bacsai 0bf7719491 feat(cloudflared): add tunnel updates with background container restart
Add an authorized update button with activity logs to pull the latest image and recreate the tunnel container in the background.

Persist new Compose files under /data/coolify/cloudflared and support existing /tmp configurations. Cover updates, missing configuration, and member restrictions with tests.
2026-10-07 14:54:17 +02:00
Andras Bacsai d08c082d07 Merge remote-tracking branch 'origin/main' 2026-10-07 13:31:27 +02:00
Andras Bacsai 81045b2dc2 fix(compose): deploy large Compose files such as Sentry self-hosted
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
2026-10-07 13:30:42 +02:00
Andras Bacsai 522ed390ce feat(search): add settings search to the command palette (#12111) 2026-10-07 13:24:21 +02:00
Andras Bacsai 38861e1394 feat(github-runners): support deployment and build servers (#12109) 2026-10-07 12:45:08 +02:00
Andras Bacsai 575bfaa085 feat(analytics): add configurable client IP storage modes
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.
2026-10-07 12:35:22 +02:00
Andras Bacsai 407c384b09 feat(backups): add configurable missing volume backup alerts
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.
2026-10-07 09:37:35 +02:00
Andras Bacsai aa16cfb420 fix(servers): change the server role only through its checked flow 2026-10-06 12:56:57 +02:00
Andras Bacsai f1d3883ab2 fix(servers): authorize every Docker images request 2026-10-06 12:56:57 +02:00
Andras Bacsai 78f52310e5 fix(dns): only create or replace records for the resource's own domains 2026-10-06 12:56:50 +02:00
Andras Bacsai 116806df1b fix(compose): allow content files outside the resource directory again
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
2026-10-06 11:03:39 +02:00
Andras Bacsai 06b5a708b8 refactor(traffic): remove fallbacks for unreleased Sentinel builds
Every released Sentinel with traffic analytics (1.0.0 and later) has
the dashboard and series routes and the requests, bytes_in and app
fields, so the fallbacks for builds without them are not needed.

- Keep "no data" handling for Sentinel without traffic routes (0.0.x)
- Keep the resource-scope fallback, which Sentinel 1.0.1 needs
2026-10-06 10:29:04 +02:00
Andras Bacsai c5bcb31f73 fix(databases): import from the source the user selected
A staged upload always won over a server path, so an old upload that
was never imported could be restored instead of the chosen file.

- Record the selected source (checked server file or finished upload)
  and import only from it
- Delete a stale staged upload when another source is used
2026-10-06 10:29:04 +02:00
Andras Bacsai c3a8a44e46 fix(audit): log security resource changes under the resource team
Integration token, cloud provider token and cloud-init script edits
were audit-logged under the session team. After a team switch in
another tab, the owning team missed the entry and the other team saw
the resource name.

- Use the team of the edited resource for every audit row
- Remove credentials, query and fragment from secret manager base URLs
  in the audit log
2026-10-06 10:29:04 +02:00
Andras Bacsai e1f9e6fb39 fix(ui): deny members on cloud tokens and OAuth settings without a 500
- /security/cloud-tokens returns 403 for members instead of crashing
  on a null token list
- /settings/oauth redirects non-admins to the dashboard; it used the
  missing route "home" and a wrong redirect return type
2026-10-06 06:59:22 +02:00
Andras Bacsai 93e7fa7f34 feat(dashboard): show pending team invitations
Login no longer accepts invitations, so the dashboard lists the
unexpired invitations for the user's email with a link to the
invitation page, where the user accepts them.
2026-10-05 23:42:01 +02:00
Andras Bacsai 58fb36544a fix(ui): lock the server-built domain state of applications and services
The domain rows of applications and previews, and the DNS validation
flags of application and service domains, were not locked. A user
could change them from the browser to skip the DNS check or store
fake DNS results.
2026-10-05 23:42:01 +02:00
Andras Bacsai 0798f84c2c fix(auth): protect the root user and owners from deletion by admins
An admin of the root team could delete the root user (id 0) and the
owners of the root team from the user list.

- Never delete the root user here
- Refuse a user whose root-team role is higher than the caller's
- Refuse the caller's own account; the profile has its own flow
2026-10-05 23:42:01 +02:00
Andras Bacsai 6cc6f1081d fix(deployments): advance the queue on all servers after a cancel
- 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
2026-10-05 23:10:52 +02:00
Andras Bacsai b08383805c fix(sentinel): prevent concurrent starts and duplicate restarts (#12100) 2026-10-05 21:56:17 +02:00
Andras Bacsai babe43da32 fix(audit): return 403 on the audit log without a session team
When the user had no session team (for example after removal from the
team), the audit log page threw an error and returned 500.

- Return 403 when there is no session team or the user is not an admin
2026-10-05 21:23:36 +02:00
Andras Bacsai a331f91c49 fix(ui): validate secret manager settings and lock server-built lists
- SecretManagerLinks: validate settings when the integration token
  changes, and save only validated keys
- Service Domains: lock domainRows
- Server DockerImages: lock images
2026-10-05 21:23:29 +02:00
Andras Bacsai 379838251b fix(auth): use the resource team in database import, SQLite, and tokens
These paths used the session team after the resource was loaded. After a
team switch in another tab they used the wrong team or denied access.

- ImportForm: use the database team for the server, S3 storages, and
  the import
- SQLite ConnectApplication: list applications of the database team
- IntegrationTokenPolicy: check admin of the token team for view,
  update, and delete
2026-10-05 21:22:33 +02:00
Andras Bacsai 3987f97a8e fix(subscription): require team admin for billing actions
Subscription actions ran on the session team without a role check. A user
who switched the session to a team where they are only a member could
cancel, refund, or change that team's subscription.

- Lock the team id at mount and require admin or owner of that team
- Check the locked team and the role again in every billing action
- Reject actions after the session switched to another team
2026-10-05 17:04:05 +02:00
Andras Bacsai 0da202b39d fix: protect restores, preview imports, and analytics access 2026-10-05 17:02:56 +02:00
Andras Bacsai 35c38b1dde fix(database): reject blocked starts before queueing operations
Check start prerequisites in database and deploy APIs and MCP controls.
Return HTTP 422 for blocked API starts and restarts. Show restart notices
and open UI logs only after an operation is queued.

Add API regression tests for blocked ClickHouse starts and restarts.
2026-10-05 14:59:59 +02:00
Andras Bacsai 88efc0716e fix: enforce resource team isolation and preserve ClickHouse data
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.
2026-10-05 14:23:04 +02:00
Andras Bacsai 439ee6faea fix: restrict proxy content access and scope backup storage to owners
- Hide proxy configuration contents from users without update permission.
- Select and validate backup S3 storage against the resource's team.
- Keep scheduled branch syncs green while a conflict PR remains open.
- Document external mount permissions and Sentinel traffic limits.
- Add regression coverage for authorization and backup storage selection.
2026-10-05 13:20:19 +02:00
Andras Bacsai 4227ec6ebf fix(storage): require deploy permission for external host writes
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.
2026-10-05 12:03:37 +02:00
Andras Bacsai 2aead9c914 refactor(analytics): remove application traffic overview card 2026-10-05 11:28:03 +02:00
Andras Bacsai 554bd354bf fix: support host storage paths and clean up cancelled deployments
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.
2026-10-05 11:08:52 +02:00
Andras Bacsai 774e6bf178 feat(account): add self-service deletion and cancellation flow (#12088) 2026-10-05 09:17:10 +02:00
Andras Bacsai cfe9e0eee0 fix(settings): load instance backup page without a backup schedule
/settings/backup returned 500 when the coolify-db resource existed without
a scheduled backup. Configure backup now reuses the existing coolify-db and
creates only the missing schedule for the root team, without forcing id 0.

Closes #12074
2026-10-04 20:33:22 +02:00
Andras Bacsai 16a8c7999d feat(audit): log account, resource, and instance settings changes
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.
2026-10-04 17:32:50 +02:00
Andras Bacsai 15b64d6c56 Move proxy TLS certificates to a separate page 2026-10-04 12:35:54 +02:00
Andras Bacsai 4c2253c2ad fix(previews): restrict PR loading and status updates to GitHub Apps
Add Application::isGithubAppSource(), which checks that the source is a
GithubApp, and use it in place of is_github_based() for pull request
status updates in ApplicationDeploymentJob and for the "Load pull
requests" action in the previews view.

Previews::load_prs now throws an error for non-GitHub App sources
instead of calling the GitHub API with a GitLab or other source. Also
adds a test checking that GitLab sources don't show or load GitHub pull
requests.
2026-10-04 12:29:48 +02:00
Andras Bacsai c2f63c8f10 fix(server): remove redundant SSH work from server checks
- ServerCheckJob uses the stored reachability state instead of a second SSH
  probe. One failed probe no longer marks the server unreachable without
  UNREACHABLE_THRESHOLD or marks all its resources exited.
- Do not dispatch ServerCheckJob for build servers and Swarm workers.
- Check cloud provider state every 5 minutes instead of every minute.
- ServerPatchCheckJob uses isFunctional() and drops the unused retries.
- Delete the unused ServerCleanupMux job.
- Disable SSH multiplexing per command. The global config change stayed in
  the queue worker, so later jobs (also deployments) ran without mux.
2026-10-04 00:51:58 +02:00
Andras Bacsai 22900b6d12 fix(proxy): stop automatic proxy network reconnects on status checks
Remove the periodic ConnectProxyToNetworksJob dispatch from
PushServerUpdateJob, the synchronous connect in ServerCheckJob when the
proxy is found running, and the connect-on-add in the server
Destinations component. Drop the now-unused
proxy.connect_networks_interval_seconds config option.

Replace the rate-limit/interval tests with a test asserting that no
jobs are pushed when the proxy is running.
2026-10-04 00:36:28 +02:00
Andras Bacsai c3b32322eb fix(volume-backups): back off failed container and S3 recovery
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.
2026-10-03 21:25:11 +02:00
Andras BacsaiandClaude Opus 5.5 43b7405c4c fix(security): authorize integration token creation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 16:01:10 +02:00
Andras BacsaiandClaude Opus 5.5 aa2592b17c fix(security): stop leaking locked shared variables and proxy secrets
- 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>
2026-10-02 16:01:00 +02:00
Andras BacsaiandClaude Opus 5.5 a5ec854e35 fix(services): resolve the old denoKV template key to deno-kv
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>
2026-10-02 16:00:52 +02:00
Andras Bacsai 50be16be8f revert(scheduler): go back to the cron scan and keep the reliability fixes
The missed daily backups on Coolify Cloud came from Redis evicting queue keys
(allkeys-lfu on a full instance), not from the scan of all schedules. The
next_run_at design (452259aac, 5c5740533) did not prevent that, and it added
stored state that must be kept in sync on every frequency, timezone, and server
change. It was not released, so remove it:
- revert next_run_at, its model hooks, the "Next run" UI, and the diagnostics
  changes; restore scheduled_job_states and the queue overlap lock
- a new migration removes the next_run_at columns and creates
  scheduled_job_states again where the removed migration already ran

Keep the changes that fix real problems:
- run the manager every minute from the scheduler with `scheduled:dispatch`,
  so a busy queue cannot delay it past the catch-up window
- load the server chain of scheduled backups with each chunk, which removes
  about 7,000 queries per run on Coolify Cloud
- catch Throwable for each schedule, so one broken schedule does not stop the
  others
- publish database and volume backups again when their queued job was not
  started after 60 minutes (for example, lost in Redis); log lost tasks and
  Docker cleanups as missed. A lost backup is not run again when a newer
  occurrence of the same schedule exists.
2026-10-02 08:05:18 +02:00
Andras Bacsai 0ed423aaac feat(webhooks): require 16 characters for new manual webhook secrets
New or changed manual webhook secrets (GitHub, GitLab, Bitbucket,
Gitea) must have at least 16 characters, in the Webhooks page and in
the application API. Stored secrets keep working: an unchanged value
passes, and an empty value still disables the webhook. Each secret
field gets a Generate button that fills a random 40-character secret;
the user saves it after adding it to the Git provider.
2026-10-01 20:31:00 +02:00
Andras Bacsai 7a4709da69 fix(ui): scope env refreshes, block duplicate container names, use a confirm modal
- refreshEnvs is now sent only to the environment variable list, and
  rows no longer listen to it, so adding or removing variables cannot
  queue an update for a removed row ("Snapshot missing"). Locking a row
  refreshes that row directly; the compose editor gets its own event.
- saveCustomName() no longer saves a custom container name that another
  application on the server already uses; it restores the stored value.
- Cancelling a GitHub runner uses the Coolify confirmation modal instead
  of a native browser dialog.
2026-10-01 20:31:00 +02:00
Andras Bacsai 3379f85c0a fix(security): authorize import file checks and Vultr status refresh
ImportForm::checkFile() and checkS3File() ran without authorization, so
a member with view access could check whether paths exist on the server
or probe S3. They now require update access, like the restore actions.
Server\Show::checkVultrInstanceStatus() now requires view access, like
the Hetzner and DigitalOcean checks.
2026-10-01 20:31:00 +02:00
Andras Bacsai fed15ff1b0 fix(backups): back up every SQLite file unless the user picks some
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.
2026-10-01 20:31:00 +02:00
Andras Bacsai bcc07dd47e feat(github-runners): allow public repositories and refuse pull request jobs by default
The runner group was limited to private repositories, so jobs from
public repositories never got a runner: Coolify still started a runner
for each matching job, which then waited idle until its timeout.

The runner group now allows every repository of the organization,
public ones too; existing private groups are updated. GitHub gives a
runner any queued job with matching labels, so pull request jobs are
refused inside the runner: a job-started hook fails jobs from
pull_request, pull_request_target and review events before any step
runs, and fails closed when the event is unknown. A new runner setting,
off by default, allows pull request jobs; the settings page then warns
to require approval for fork pull request workflows on GitHub.
2026-10-01 08:14:30 +02:00
Andras Bacsai d1cf3e6ef1 fix(secrets): keep the secret manager source when cloning resources
Cloning an application, database, service or environment did not copy
the secret manager link, so variables with remote secret references
failed on the next deployment with "no secret manager source is
configured".

Clones now get a copy of the link when the integration token belongs to
the clone's team. Server transfer does not export integration tokens or
links; the export now warns which resources need the token and link
again on the target instance.
2026-10-01 07:16:45 +02:00
Andras Bacsai 8d7469230c fix(secrets): skip remote secret names that are not valid variable keys
Import all stopped at the first remote secret whose name is not a valid
environment variable key (for example db-password in Vault or
Infisical). The key setter threw, so the import was partial, no audit
entry was written, the variable list did not refresh, and the user saw
only a generic error.

Invalid names are now skipped and listed in the result toast and the
audit entry, and the rest are imported. Browse marks invalid names and
offers no add action for them, and adding one shows a clear error. The
refreshEnvs event now goes only to the environment variable list.
2026-10-01 07:16:45 +02:00