67 Commits
Author SHA1 Message Date
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 b08383805c fix(sentinel): prevent concurrent starts and duplicate restarts (#12100) 2026-10-05 21:56:17 +02:00
Andras Bacsai 66cc64e0d9 fix(sentinel): repair stalled Sentinel and show why pushes fail
- Restart a running Sentinel that has not pushed for 10 minutes, at most
  once per hour. The restart applies the current URL and token.
- Restart an unhealthy Sentinel. Do not restart while its health check
  starts or while its API does not answer yet, which caused restart loops.
- Remember why pushes fail: the reason Coolify rejects a push, and the last
  push error from Sentinel's /api/push-status. Show it on the Sentinel page
  while Sentinel is out of sync.
- When the instance URL or public IP changes, move remote servers that use
  the generated Sentinel URL to the new URL. Custom URLs stay.
2026-10-04 12:03:54 +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 9e7cb60b0d feat: add import restore options, OAuth confirmation, and fixes
- database import: add keep_owners (restore PostgreSQL owners and
  privileges) and sqlite_database (pick the target SQLite file) to the
  API, OpenAPI spec, and import form
- oauth: require password confirmation and support team selection on
  OAuth login
- remote process: send team broadcast events to the team of the server
  that ran the process instead of the causer's user id
- servers API: handle the legacy build server setting
- compose: support parent bind paths and volume driver options
- dns: improve record hints and provider management
- notifications: fix throttling and missing backup notifications
- ui: rework the confirmation modal
- add feature and unit tests for the new behavior
2026-09-30 13:35:22 +02:00
Andras Bacsai 99c840922c fix(notifications): throttle repeated notifications per resource
High disk usage notifications were sent every ~10 minutes on Coolify Cloud
because the cache rate limiter did not hold across Sentinel-triggered checks.

- Add a notification_throttles table and NotificationThrottle helper that
  atomically records when a notification was sent for a resource.
- Add the ThrottledNotification contract; Team::notify() skips a throttled
  notification that was already sent within its interval.
- High disk usage: configurable per-server interval
  (server_disk_usage_notification_interval_hours, default 24h) in
  Server > Advanced and the servers API.
- Container restarted (coolify-proxy, database TCP proxy): at most one
  notification per hour per server/database during a restart loop.
- Move the unreachable and missing-backup markers into the new table and
  migrate existing data (servers.unreachable_notification_sent and
  scheduled_database_backups.missing_backup_notification_sent_at).
- Regenerate OpenAPI files.
2026-09-29 11:29:39 +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 f4fbcaacff fix(tests): repair tests that failed on main
- ServerSetting: default is_traffic_analytics_enabled to false on the
  model, so a new instance does not show null before a refresh.
- Update navbar, mobile menu, and proxy button tests to the current
  redesigned UI (split action menus, settings rail, neutral icons).
- Traffic nudge test: set server_role to mark a build server, the same
  as the product code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 23:52:01 +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 383a5a742f feat(servers): add configurable deployment and build roles
Introduce deployment, build, and dual-purpose server roles, with API and UI support, build-server fallback controls, and role-aware resource hosting.
2026-09-19 17:22:13 +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 16b092336e feat(sentinel): track synchronization state and refresh status UI
Add sentinel waiting-state tracking, synchronization broadcasts, and restore
status handling across server and application interfaces.
2026-09-16 12:51:27 +02:00
Andras Bacsai 936a2566c6 fix(analytics): hide traffic UI when disabled and skip default-on (#11700) 2026-09-09 14:28:15 +02:00
Aditya Tripathi 19752da6af feat(analytics): lazy-load traffic pages and batch Sentinel calls
- Mark Analytics, Dashboard\TrafficAnalytics and Project\Application\Analytics
  Livewire components #[Lazy] with skeleton placeholder() views so pages render
  instantly while Sentinel data loads in a deferred request
- Add SentinelTrafficClient::prefetchServerWide() to warm all server-wide
  endpoints in a single batched docker exec instead of ~14-15 serial SSH
  round-trips, and refactor overview/paths/breakdown URL building into shared
  helpers
- Cap per-app leaderboard overviews fetched via MAX_LEADERBOARD_APPS to bound
  requests on servers with many apps
- Add hasRequestSeries() to detect empty request charts and render a no-data
  state instead of a blank chart
- Gate ServerSetting's automatic Sentinel restart on is_sentinel_enabled so
  tuning geoip/traffic settings no longer silently enables Sentinel
- Add reusable skeleton UI components (skeleton, skeleton/table, skeleton/tiles)
  for the new placeholder views
2026-08-22 11:13:49 +00:00
Aditya Tripathi b2fb22934c Merge remote-tracking branch 'origin/next' into coolify-analytics-traefik-caddy
# Conflicts:
#	app/Models/ServerSetting.php
#	package-lock.json
#	package.json
#	resources/views/components/forms/listbox.blade.php
2026-08-20 09:33:47 +00:00
Andras Bacsai 857375f69c feat(backups): add configurable CPU usage for volume compression
Add server-level compression CPU presets for volume backups and close the private key modal after saving.
2026-08-14 12:00:46 +02:00
Andras Bacsai e79230cf37 fix(docker): replace deprecated stop flags with version-aware ones
Store each server's Docker version and build stop commands via
dockerStopCommand() so newer Docker uses --timeout instead of
deprecated --time/-t. Also show Docker version in server details.
2026-08-13 11:17:44 +02:00
Aditya Tripathi 825a5206ad feat(traffic): add traffic and GeoIP Sentinel config settings
Expose top-n, sampling threshold, retention, and GeoIP options on
server settings; pass them into Sentinel env and the API/UI.
2026-08-13 07:58:51 +00:00
Aditya Tripathi 872f8aafb8 feat(traffic): add live refresh, geo maps, and app overview widget
- Add live 24h polling toggle to server/application analytics views
- Add geo visualization (world map, country flags/names) for traffic
- Add dashboard nudge for servers eligible but not yet analytics-enabled
- Add lazy-loaded TrafficOverview widget to application General page
- Default-enable traffic analytics on new eligible server settings
- Rotate Caddy access logs via lumberjack roll options
- Add Traefik logrotate sidecar for copytruncate access-log rotation
2026-08-11 10:55:50 +00:00
Aditya Tripathi 99b25fbd8a feat(traffic): add traffic analytics server settings 2026-08-10 19:15:46 +00:00
Andras Bacsai de4e74b4cd feat(server): fall back Sentinel URL to request host
Use the current request scheme/host when no FQDN or public IP is set,
skipping loopback hosts. Polish boarding/server create cards, optional
listbox tooltips, and cover the layout and Sentinel URL behavior in tests.
2026-08-07 15:41:39 +02:00
Andras Bacsai 8f7eb2d790 feat(server): auto-resolve Sentinel URL and polish setup UI
Ensure a Sentinel endpoint from instance FQDN/IP when enabling, use process dialogs for validation with install state, and tidy server create, boarding, metrics empty state, and log timestamps.
2026-08-07 15:21:18 +02:00
Andras Bacsai 913d033c75 fix(resources): clarify build server hosting restrictions (#10961) 2026-07-16 21:35:23 +02:00
Andras Bacsai e828058755 Merge remote-tracking branch 'origin/next' into api-sensitive-data-scrubber 2026-04-30 11:30:50 +02:00
Andras Bacsai 8b7dbbafb2 fix(api): hide sensitive fields by default, expose via makeVisible for privileged tokens
Models now declare $hidden for passwords, tokens, db URLs, and compose
fields. API controllers flip from makeHidden-on-deny to makeVisible-on-
allow (can_read_sensitive=true), fixing fields that were never hidden.
Also adds missing fields (mysql/mariadb passwords, logdrain keys, etc.)
to privileged disclosure lists.

Tests added: Feature/Security/ApiSensitiveFieldsTest and
Unit/Models/SensitiveFieldsHiddenTest cover all affected models and
controllers.
2026-04-30 11:28:06 +02:00
Andras Bacsai 4575106f53 feat(sentinel): embed server UUID in encrypted sentinel token
Replace random string with encrypted JSON payload containing
server_uuid, binding token to its server for validation.
Remove double-encrypt test no longer relevant to new token format.
2026-04-30 08:21:30 +02:00
Andras Bacsai 00d6e83e7f fix(sentinel): auto-regenerate invalid or undecryptable tokens
Replace hard validation error with self-healing token logic. Tokens that
are null, empty, or fail decryption are now regenerated automatically
rather than crashing sentinel startup or metrics reads.

Token format changed from encrypted JSON payload to a plain 64-char
random string (Str::random), eliminating double-encryption issues and
simplifying the validation regex to cover the new character set.

New `ensureValidSentinelToken()` method on ServerSetting centralises
the get-or-regenerate contract; both StartSentinel and HasMetrics now
delegate to it. HasMetrics logs a warning when regeneration occurs so
operators know a sentinel container restart is required.

`isValidSentinelToken()` now accepts `?string` (null → false).

Adds feature tests covering: null/empty/undecryptable stored values,
idempotent return of valid tokens, RuntimeException only when
regeneration itself produces an invalid token, no double-encryption of
newly generated tokens, and cast round-trip consistency.
2026-04-29 16:44:12 +02:00
Andras Bacsai 6293b14586 feat(server): add configurable SSH connection timeout per server
Add `connection_timeout` field to server settings, allowing per-server
override of the global SSH connection timeout constant.

- Migration adds `connection_timeout` integer column (default 10s)
- `ServerSetting` model exposes and casts the new field
- `SshMultiplexingHelper::getConnectionTimeout()` resolves per-server
  value with fallback to `constants.ssh.connection_timeout`
- All SSH/SCP command builders use the new resolver instead of the
  global config directly
- Livewire `Show` component binds `connectionTimeout` with validation
  (1–300 seconds) and syncs to/from the model
- UI input added to server settings form with helper text
- Feature tests cover default, persistence, resolver, and fallback
2026-04-28 15:39:36 +02:00
Andras Bacsai 1a603a10ed fix(models): replace forceFill/forceCreate with fill/create and add fillable guards
Replace all uses of `forceFill`, `forceCreate`, and `forceFill` with their
non-force equivalents across models, actions, controllers, and Livewire
components. Add explicit `$fillable` arrays to all affected Eloquent models
to enforce mass assignment protection.

Add ModelFillableCreationTest and ModelFillableRegressionTest to verify that
model creation respects fillable constraints and prevent regressions.
2026-03-31 13:45:31 +02:00
Andras Bacsai 7ad51241f3 Merge remote-tracking branch 'origin/next' into refactor/sync-model-attributes
# Conflicts:
#	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
#	app/Models/Team.php
#	app/Models/User.php
#	tests/Feature/MassAssignmentProtectionTest.php
2026-03-29 21:32:54 +02:00
Andras BacsaiandClaude Opus 4.6 9f46586d4a refactor: define explicit fillable attributes on all Eloquent models
Replace $guarded usage with explicit $fillable arrays across all models.
Sync fillable definitions with current database schema and add tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-29 21:25:41 +02:00
Andras Bacsai b3256d4df1 fix(security): harden model assignment and sensitive data handling
Restrict mass-assignable attributes across user/team/redis models and
switch privileged root/team creation paths to forceFill/forceCreate.

Encrypt legacy ClickHouse admin passwords via migration and cast the
correct ClickHouse password field as encrypted.

Tighten API and runtime exposure by removing sensitive team fields from
responses and sanitizing Git/compose error messages.

Expand security-focused feature coverage for command-injection and mass
assignment protections.
2026-03-29 20:56:04 +02:00
Andras Bacsai 096d4369e5 fix(sentinel): add token validation to prevent command injection
Add validation to ensure sentinel tokens contain only safe characters
(alphanumeric, dots, hyphens, underscores, plus, forward slash, equals),
preventing OS command injection vulnerabilities when tokens are
interpolated into shell commands.

- Add ServerSetting::isValidSentinelToken() validation method
- Validate tokens in StartSentinel action and metrics queries
- Improve shell argument escaping with escapeshellarg()
- Add comprehensive test coverage for token validation
2026-03-10 22:19:19 +01:00
Andras Bacsai 700550b26f Fix: Concurrent builds ignored & add deployment queue limit (#7488) 2025-12-11 11:03:02 +01:00
Andras BacsaiandClaude 511415770a Add server-level toggle to disable application image retention
Adds a new server-level setting that allows administrators to disable
per-application image retention globally for all applications on a server.
When enabled, Docker cleanup will only keep the currently running image
regardless of individual application retention settings.

Changes:
- Add migration for disable_application_image_retention boolean field
- Update ServerSetting model with cast
- Add checkbox in DockerCleanup page (Advanced section)
- Modify CleanupDocker action to check server-level setting
- Update Rollback page to show warning and disable inputs when server
  retention is disabled
- Add helper text noting server-level override capability

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 12:22:20 +01:00
Andras BacsaiandClaude 6d16f52143 Add deployment queue limit to prevent queue bombing
- Add configurable deployment_queue_limit server setting (default: 25)
- Check queue size before accepting new deployments
- Return 429 status for webhooks/API when queue is full (allows retry)
- Show error toast in UI when queue limit reached
- Add UI control in Server Advanced settings

Fixes #6708

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 13:52:27 +01:00
Andras Bacsai 728f261316 Changes auto-committed by Conductor 2025-10-16 09:51:37 +02:00
Andras Bacsai 46b4cfac68 feat(terminal-access): implement terminal access control for servers and containers, including UI updates and backend logic 2025-05-29 14:09:05 +02:00
peaklabs-dev f26853b576 fix: unreachable notifications 2024-12-23 16:51:34 +01:00
SierraJC bbd7d8b567 fix: move servers API delete_unused_* properties
correct location from API response is in server.settings
2024-11-23 13:23:13 +11:00
Andras Bacsai aa1e80ccae fix: start sentinel on seeder 2024-11-08 10:39:02 +01:00
Andras Bacsai 9d9ac5943e fix 2024-11-08 10:30:10 +01:00
Andras Bacsai e7f2215652 fix: seeder should not start sentinel 2024-11-08 10:28:40 +01:00
Andras Bacsai f1587d3302 cleanups 2024-11-06 12:39:37 +01:00
Andras Bacsai 96ca72fcdb refactor server view (phuuu) 2024-10-30 20:03:30 +01:00
Andras Bacsai 8c96ab52d7 feat: notification rate limiter
fix: limit server up / down notification limits
2024-10-25 15:13:23 +02:00
Andras Bacsai 7ed0ebf106 fix: generateSentinelUrl method 2024-10-25 11:41:52 +02:00
Andras Bacsai 6e305a33de Refactor server setting model to restart Sentinel on specific config changes 2024-10-22 14:10:52 +02:00
Andras Bacsai 1f221d9791 fix: sentinel config changes restarts sentinel 2024-10-22 14:10:36 +02:00
Andras Bacsai e8854c3101 fix: sentinel start fixed 2024-10-22 08:31:53 +02:00