143 Commits
Author SHA1 Message Date
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 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 5805a28872 fix(audit): redact raw credential fields and keep hidden fields excluded
Raw commands, URLs and configuration blobs can contain credentials even
when their field names don't look sensitive. Add a list of these fields
to AuditEvent (git_full_url, build/start commands, database confs,
proxy configuration, compose files, environment variables, etc.). Expose
AuditEvent::isSensitiveField() so redaction and audit change capture use
the same check.

Auditable now excludes a model's class-level $hidden fields as well as
its runtime hidden fields. A field stays out of audit changes even after
makeVisible() is called on the instance.

Add regression tests for credentials embedded in raw fields, database
config on create/delete, nested metadata and proxy configuration, and
hidden fields after makeVisible().
2026-10-04 12:26:37 +02:00
Andras Bacsai 4759b7bcf7 fix(audit): redact object values and isolate change preparation failures 2026-10-04 12:26:06 +02:00
Andras Bacsai 83d19800a6 feat(audit): store encrypted field-level changes on mutations
Record old/new values for auditable create, update, and delete actions, persist them encrypted on audit events, expose them in the API, and let the team audit log expand a field-level before/after view. Sensitive, hidden, and identifier fields stay out of the change payload.
2026-10-04 12:26:00 +02:00
Andras Bacsai 599dc1ca67 fix(ssh): do not replay remote commands that failed on the server
The SSH retry matched connection words in any error output. When `mc alias set`
in a backup upload could not reach S3, its "connection refused" output caused a
retry of the full batch, and the second `docker run --name backup-of-<uuid>`
failed with a name conflict that hid the real error.

- Retry only SSH transport failures: exit code 255, or errors without an exit code.
- Keep the remote exit code on deployment command failures.
- Remove a leftover backup helper container in the same upload batch.

Closes #12059
2026-10-03 20:52:01 +02:00
Andras Bacsai f1f7272494 fix(queue): run service and database start commands on the deployment queue
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.
2026-10-03 20:50:49 +02:00
Andras BacsaiandClaude Opus 5.5 9862f75dc2 fix(audit): reduce audit log noise and keep instance events out of team logs
- 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>
2026-10-02 16:01:10 +02:00
Andras BacsaiandClaude Opus 5.5 9bdbbeef7a fix(secret-manager): use remote secret values exactly and check them before a restart
- Write remote secret values as exact dotenv literals in the service .env
  file and escape "$" where they go directly into a generated compose file
  (environment, start commands, healthchecks).
- Resolve remote secrets before a service or database restart stops the
  running resource, and show the secret manager error instead of a generic
  start failure (new RemoteSecretException).
- Cache fetched key names for the autocomplete and rate limit how often a
  user can contact the secret manager.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 16:00:41 +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 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 a2cd6351b2 fix(databases): keep SSL certificate files and CA in sync with each engine
- Regenerate SSL Certificates now writes server.crt/server.key for every
  engine except MongoDB, which keeps the combined server.pem. Before, the
  button always wrote server.pem, so Postgres, MySQL, MariaDB, Redis, KeyDB
  and Dragonfly failed to start after a regenerate.
- The certificate renewal job uses the same rule, so MongoDB no longer
  switches to server.crt/server.key on renewal and fails on restart.
- Starting an SSL database writes the CA that signs its certificate to
  /data/coolify/ssl/coolify-ca.crt, so a stale CA file (for example one
  written by another server entry for the same host) no longer causes
  "certificate signature failure".
- Saving a custom CA certificate that does not match the stored CA
  private key is rejected.
- The CA file write commands live in SslHelper::caCertificateFileCommands().

Fixes #10388
Fixes #6771
Fixes #11926
2026-09-30 19:01:11 +02:00
Andras Bacsai d8bbd8d196 fix(storage): resolve relative file paths, keep volume options on clone, use random clone dirs
- Resolve relative LocalFileVolume paths against the resource directory.
- Create cloned volumes with the source driver and options.
- Stage clone archives for non-root users in a mktemp directory (mode 700)
  instead of a predictable path in /var/tmp.
2026-09-30 18:10:10 +02:00
Andras Bacsai a599c9e8b7 fix(server): keep data directory commands working for non-root SSH users
A non-root SSH user cannot open redirects, expand globs, or cd into
/data/coolify (9999:root 0700). Several remote commands relied on that
and failed on non-root servers.

- Write README files with `tee` instead of shell redirects in database
  starts and application deployments
- Clear Postgres init scripts with `find` instead of a glob
- Split the proxy config backfill if/else so each branch gets sudo
- Start the log drain with `docker compose -f` instead of `cd`
- Wrap the preserved-repository compose start in `sh -c` for non-root
- Stage clone archives outside /data/coolify via StagesCloneArchives
- Extend the sudo parser and add non-root command tests
2026-09-29 20:46:54 +02:00
Andras BacsaiandClaude Opus 5.5 cbee84353e refactor(events): broadcast team events to an explicit team
Move the shared team id and team channel logic of 15 broadcast events
into a BroadcastsToTeam trait. Events no longer fall back to the session
team: the session team can differ from the resource team, and queued
jobs have no session.

Fix StopDatabaseProxy, which dispatched DatabaseProxyStopped without a
team, so the event was never broadcast from queued jobs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 10:46:16 +02:00
Andras BacsaiandClaude Opus 5.5 3452faec87 fix(livewire): bind team broadcast listeners to the mounted team
Livewire rebuilds listener names from the session team on every event
call. After a team switch in another tab, open pages still listen on the
old team channel, so events failed with EventHandlerDoesNotExist (500),
or ran handlers that load resources scoped to the new team (404).

Store the team at mount and build team channel listeners from it. Events
for a team that is no longer the session team are ignored.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 10:31:32 +02:00
Andras Bacsai 452259aacc feat(scheduler): dispatch scheduled jobs by their stored next run time
The scheduled job manager checked every enabled schedule each minute and
evaluated its cron expression in PHP. On Coolify Cloud one run took more than
60 seconds, so runs overlapped and minutes were skipped.

Each schedule now stores its next due time:
- next_run_at on scheduled database backups, scheduled tasks, and volume
  backups, and docker_cleanup_next_run_at on server settings (UTC, indexed)
- model hooks calculate it when a schedule is created or its frequency or
  enabled flag changes; a server timezone change or a move to another server
  calculates it again for the affected schedules

The `scheduled:dispatch` command runs the manager every minute from the
scheduler, not from a queue. It selects only due rows and claims each
occurrence with an atomic update of next_run_at, together with its delivery
record, so parallel runs on several nodes never dispatch it twice.
- database and volume backups run once when they are late; tasks and Docker
  cleanups more than 10 minutes late are logged as missed
- a local time that occurs two times when the clocks go back runs once
- the migration continues each schedule after its last recorded occurrence and
  drops scheduled_job_states

Show the next run, in the server timezone, on the database backup, scheduled
task, volume backup, and Docker cleanup pages, or "Invalid frequency" when the
frequency cannot be calculated. scheduled:diagnostics now lists overdue
schedules and open deliveries.

Remove workarounds that are no longer needed: the queue overlap lock and its
stale-lock repair, the catch-up window, and debug-only logs.
2026-09-29 10:07:23 +02:00
Andras BacsaiandClaude Opus 5.5 350d8a6571 fix(databases): refresh database form values consistently
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 12:07:02 +02:00
Andras BacsaiandClaude Opus 5.5 7c60ccda0d fix: restore config diff, error text, delete handler, webhook id and danger zone fixes
- Configuration diff: report all settings when an app has no earlier
  snapshot, so older apps show "configuration changed" again (#11430).
- DigitalOcean/Vultr: do not repeat the "API error:" prefix.
- HasSecretManager: the deleting listener returns nothing, so later
  deleting listeners still run.
- GitLab webhook: use new_public_id() like the other webhooks.
- Team danger zone: show the link and open the page only for the team owner.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 09:35:32 +02:00
Andras BacsaiandClaude Opus 5.5 a6a3b1d26b revert: undo the app changes from the test clean-up
Revert the app code changes of d666a0a95, 69eeb2f62, 1e66c9f9b and
a32082b03, so login, registration, OAuth, team danger zone, service
templates, and the other touched files are back to their earlier state.
Keep the removal of unused components and markup-only tests (d666a0a95
also contained those deletions by mistake).

StartupExecutionCleanupTest now fakes the template CDN with the current
file content, so app:init in the test no longer empties
templates/service-templates-latest.json.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 08:06:34 +02:00
Andras BacsaiandClaude Opus 5.5 a32082b03f fix: regressions found by the test suite
- TrustHosts: validate the Host header also when the FQDN cache is cold.
- Settings email: authorize the SMTP and Resend toggles.
- Server navbar: show Sentinel status only to users who can view Sentinel.
- GitHub source: restore permission gates on Sync name and Delete, and the
  Test connection button.
- Profile: make avatar upload work (missing import and file uploads trait).
- API tokens: keep the "Never" expiry choice.
- Environment variables: show validation errors instead of a generic error.
- Servers API: read the server uuid from the route in domains_by_server.
- Configuration diff: report all settings when no earlier snapshot exists.
- Cloud servers: restore Power On for stopped servers; do not repeat the
  provider error prefix.
- HasSecretManager: do not stop later deleting listeners.
- GitLab webhook: use new_public_id() like the other webhooks.
- Dev: show the Lima VM start command on the localhost server page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 00:18:09 +02:00
Andras BacsaiandClaude Opus 5.5 49ae227f6e fix(compose): keep the old volume of existing resources for external volumes
Switching an external volume from the old <uuid>_<name> volume to the
declared external volume on redeploy could make an app look as if it
lost its data (for example a database that initializes a new, empty
data directory).

- If a resource already has the storage entry with the old generated
  name, the parsers keep using that volume and show a warning in the
  deployment log and the service start log, with the steps to switch.
- Without that entry (new resources, or external volumes added later)
  the external volume is used as declared.
- Deleting the old storage entry (storage page) switches to the
  external volume on the next deployment; the storage entry shows a
  note about it.
- Legacy Compose applications (parser versions 1 and 2) never stored
  their volumes, so they keep the old volume names.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 17:24:51 +02:00
Andras BacsaiandClaude Opus 5.5 1e207292b6 fix(deployments): keep secrets out of failed command logs
- A failed command marked skip_command_log (for example the .env,
  build-time env, and SSH key writes) no longer puts its text into the
  exception, which was shown as the visible "Deployment failed" line
  with all secrets as base64. Its error output is also cleaned.
- Mark more secret-carrying commands as sensitive: the helper container
  with build secrets, railpack prepare, the Nixpacks plan, and Compose
  file writes.
- Dev debug lines list only variable names, not values.
- Invalid build-time variable names such as my-var stop a deployment
  only when it builds an image. Docker image deployments log a warning
  with a suggested name instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 10:40:53 +02:00
Andras Bacsai 554b79e8dd feat: add Traefik ACME cert UI and shared managed DNS record ownership
- Proxy: list and delete Traefik ACME certificates from the server proxy
  page via new TraefikAcmeService and Get/DeleteTraefikCertificate actions
- DNS: track ownership and cross-resource references for managed DNS
  records so records are only deleted when no longer referenced; release
  records asynchronously on resource deletion via ReleaseManagedDnsRecordsJob
  and ManagedDnsRecordCleanup; harden Cloudflare provider deletion results
- Databases: fail closed on start when prerequisites or the CA certificate
  are missing (DatabaseStartException, Server::ensureCaCertificate) and
  clean up stale start activities via ResourceStartActivity
- Webhooks: throttle repeated manual webhook signature failures for
  GitHub, GitLab, Gitea and Bitbucket
- Deployments: improve compose build-context handling and compose file
  load error reporting
- Install scripts: rework terminal UI output in install.sh (stable and
  nightly)
- Misc: settings sidebar accordion fixes, log drain toggle rollback,
  add Serverside to README sponsors
- Add migrations and tests covering the above
2026-09-25 19:00:00 +02:00
Andras Bacsai 50643a44f8 Keep deployment logging available on formatting errors 2026-09-24 09:36:59 +02:00
Andras Bacsai b37d24d258 Improve deployment log value handling 2026-09-24 09:29:23 +02:00
Andras Bacsai a29f02fbb1 Merge remote-tracking branch 'origin/main' into pr-11443-next
# Conflicts:
#	openapi.json
#	openapi.yaml
#	resources/views/livewire/project/application/heading.blade.php
#	resources/views/livewire/project/service/heading.blade.php
2026-09-19 17:44:44 +02:00
Andras Bacsai e2e2d4010b fix(deployments): trim remote command outputs before processing
Normalize saved command output for reliable status and metadata handling, and bump the Coolify version to 4.3.23.
2026-09-18 15:34:50 +02:00
Andras Bacsai ebfd4d0c1c Merge remote-tracking branch 'origin/main' into pr-11443-next
# Conflicts:
#	app/Actions/Server/StartSentinel.php
#	app/Livewire/Server/Sentinel.php
#	resources/views/livewire/project/shared/storages/all.blade.php
#	resources/views/livewire/project/shared/storages/show.blade.php
2026-09-18 12:00:04 +02:00
Andras Bacsai 054c560cbd fix(deployments): preserve whitespace in saved command output (#11466) 2026-09-16 17:34:51 +02:00
Andras Bacsai 09e9822264 Merge remote-tracking branch 'origin/next' into automation/sync-main-to-next
# Conflicts:
#	app/Actions/Database/StartDatabase.php
#	app/Models/StandaloneClickhouse.php
#	app/Models/StandaloneDragonfly.php
#	app/Models/StandaloneKeydb.php
#	app/Models/StandaloneMariadb.php
#	app/Models/StandaloneMongodb.php
#	app/Models/StandaloneMysql.php
#	app/Models/StandalonePostgresql.php
#	app/Models/StandaloneRedis.php
#	resources/views/livewire/project/shared/storages/all.blade.php
#	tests/Feature/PersistentStorageVolumesLayoutTest.php
#	tests/Feature/UserSeederTest.php
2026-09-08 10:02:12 +02:00
Andras Bacsai 51cab061be fix(domains): sync Docker Compose domains for noindex settings 2026-09-04 15:19:21 +02:00
Andras Bacsai 9ef1ab7649 Merge remote-tracking branch 'origin/next' into automation/sync-main-to-next
# Conflicts:
#	app/Actions/Database/StartDatabase.php
#	app/Jobs/ApplicationDeploymentJob.php
#	app/Livewire/Project/Shared/EnvironmentVariable/Show.php
#	app/Models/Application.php
#	app/Models/Service.php
#	app/Models/StandaloneClickhouse.php
#	app/Models/StandaloneDragonfly.php
#	app/Models/StandaloneKeydb.php
#	app/Models/StandaloneMariadb.php
#	app/Models/StandaloneMongodb.php
#	app/Models/StandaloneMysql.php
#	app/Models/StandalonePostgresql.php
#	app/Models/StandaloneRedis.php
#	resources/views/livewire/project/application/heading.blade.php
#	resources/views/livewire/project/service/heading.blade.php
#	tests/Feature/PersistentStorageVolumesLayoutTest.php
2026-09-02 21:19:57 +02:00
Andras Bacsai e2e91fbb85 feat(domains): support per-domain internal port overrides (#11594) 2026-09-02 19:39:19 +02:00
Andras Bacsai 67b33c27a9 fix(applications): persist restart limit state for stopped containers (#11566) 2026-08-31 13:13:26 +02:00
Andras Bacsai 4e40a2c05b fix(audit): validate event filters and preserve suppression state
Validate audit event API pagination and filters, serialize paginated responses, and restore the prior audit-logging state after nested suppression callbacks.
2026-08-24 11:03:24 +02:00
Andras Bacsai 2289de4489 fix(audit): prevent duplicate API update events
Suppress model audit logging during API application saves while preserving the explicit event, and improve audit log actor display spacing and token tooltips.
2026-08-24 10:42:04 +02:00
Andras Bacsai d74352f423 fix(audit): harden audit logging and admin controls
Log audit failures, redact invitation emails, exclude noisy model fields, and gate audit-log filters and pagination by admin access.
2026-08-24 09:13:20 +02:00
Andras Bacsai 8726746241 Merge remote-tracking branch 'origin/next' into team-resource-audit-logging 2026-08-24 00:02:30 +02:00
Andras Bacsai 6d716e54d7 fix(database): preserve credentials and activity context on start
Keep raw secret values for database credentials, escape Redis passwords in startup commands, and pass user context through queued database starts.
2026-08-23 23:03:06 +02:00
Andras Bacsai f49c330d9d feat(database): queue starts and resolve credentials securely
Extract database start command execution into a shared service and job, preserving activity tracking and status events while supporting resolved secret credentials.
2026-08-23 22:33:03 +02:00
Andras Bacsai 91d4467322 feat(secrets): resolve integrations across deployments and databases
Add secret manager integration links and API support, resolve referenced credentials in database startup commands, and improve environment variable handling and filtering.
2026-08-23 21:33:00 +02:00
Andras Bacsai ba179d50ac feat(secrets): add integration token and application manager APIs
Add API endpoints for creating validated secret manager tokens and configuring application secret manager settings. Suppress secret-bearing deployment command logs and redact resolved remote secrets.
2026-08-23 20:42:20 +02:00
Andras Bacsai 51461456f6 feat(secrets): resolve remote secret references at deployment
Add Doppler, Infisical, and Vault integrations with per-resource secret links, autocomplete, and deploy-time resolution for applications, services, and databases without persisting remote values.
2026-08-23 20:09:31 +02:00
Andras Bacsai 40e5fd8521 feat(audit): add team activity tracking and audit log 2026-08-22 13:18:14 +02:00
Andras Bacsai 7162185400 fix(metrics): convert container memory samples from bytes to MB
Sentinel stores container used memory in bytes while application and
database charts label the series as megabytes. Convert those samples
before they reach the frontend so the graph is not inflated by ~1024x.
2026-08-13 10:58:28 +02:00
Alberto Rizzi 4afe131905 feat(domains): add per-domain noindex support
Flagged domains are served with X-Robots-Tag: noindex, nofollow via
Traefik and Caddy routing labels, so an auto-generated technical domain
can be excluded from indexing while the production domain on the same
resource stays indexable.
2026-07-12 13:59:09 +02:00
Andras Bacsai 9b060958aa fix(ray): remove Ray debug hooks from runtime (#10847) 2026-07-03 11:40:20 +02:00
Andras Bacsai a630532308 fix(deploy): preserve deploy key command metadata 2026-06-29 10:17:09 +02:00
Andras Bacsai 1a5b8d3612 fix(deploy): skip logging deploy key commands 2026-06-28 13:15:18 +02:00