The terminal server built the Laravel session cookie name from APP_NAME
with its own regex and ignored SESSION_COOKIE. When the name differed
from Laravel's, every connection closed with "Missing required tokens".
Forward the browser Cookie header so Laravel reads its own session.
Also remove the text rejection messages kept for terminal clients from
before close codes; the server and client now ship in the same image.
Closes#10549
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Dashboard: projects and servers fill the left, recent deployments sit in a
fixed-width right column; cards stretch to fill rows; the server table shows
live CPU and memory usage when metrics are on.
- Deploy canvas: purple accent in dark mode, the Steps panel floats over the
canvas, and both canvases use the flask beta icon.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Replace the container accordion with Deployment and Service selectors
that show one stream, merging replica containers by timestamp. The
viewer fills the page, opens in text view, keeps whitespace, and only
lets grid rows expand when the detail shows more than the row.
Based on the proposal in discussion #12176 by PhilippMolitor.
Hold saved card and group positions on the canvas until a load that
started after the save completes, so stale poll or refresh responses
no longer snap cards back to their old spots.
Use GROUP_GAP instead of BOX_GAP when dragging groups and checking
group spacing in dragRules, matching layoutServerView so a reload
does not shift a dropped group. Save before ending the group drag.
Add tests covering group spacing after drag and reload.
Environments without resources now appear as placeholder cards on the
project, team projects and server canvases. They sit in the zone that
holds most of their project's cards, or in a new "Empty environments"
zone when there is none. A new EmptyCard component renders them.
- Project canvas: admins can move groups and cards, and the moves are
saved on their environment canvas. Environments are ordered by id.
- Server canvas: admins can move single cards as well as groups.
- Shared variable canvas: built-in COOLIFY_SERVER_UUID/NAME variables
and their links are hidden on server scope.
- Main nav: resource menus register through registerMainNavContext()
with depth levels (#main-nav-context-{depth}). Back goes one level
lower, and Back at depth 0 returns to the main menu.
- The deploy canvas state, styles and controls are simplified, and the
related sidebar, navbar and dashboard views are updated.
Tests are added or updated for the canvases and the main nav resource
menus.
Add a /dashboard/canvas page that renders every team server with its
resources and their running or queued deployments, backed by a new
ServerCanvasController::dashboard endpoint and a per-server usage
endpoint for zone headers. The dashboard remembers the list/canvas
choice and each section (projects, servers) its own table/grid view.
- Show Deploying/Queued pills on canvas cards and a foldable recent
deployments panel; add shared CanvasControls component
- Allow backup downloads from the server host via the S3 download
storage (PrepareFileDownloadJob accepts a null container)
- Extract backup toggle/run actions into ManagesDatabaseBackup and
surface them in backup execution headers; merge S3 and retention
sections into the general backup settings
- Move deployments indicator to the top bar and add a main nav
resource menu with submenus; simplify breadcrumbs and settings
layouts
- Add shared variables overview canvas and scheduled task modals
- Add feature tests for dashboard canvas, view modes, navbar
submenus, backup S3 downloads and scheduled task modals
Enable Fortify passkeys (laravel/passkeys) with the @laravel/passkeys
client. Users can sign in with a passkey, confirm sensitive actions with
one, and add, rename, and delete passkeys on the Profile page.
- Resolve the relying party for each request from the instance URL, then
APP_URL, then localhost. Passkey routes return 404 on other hosts.
- Add the is_passkey_enabled instance setting (Settings > Advanced).
- Use a hex user handle (laravel/passkeys-server#41).
- Rate limit the passkey routes by client IP.
- Record audit events for registered, verified, and deleted passkeys.
- Runtime logs: add a compact text view, move display options and log level filters into a View menu, move copy and download into an Export menu, and remove the extra top margin.
- Replace spinner loading cards with skeletons on the logs, dynamic configurations, proxy, TLS certificates, Docker images, environment variables, preview deployments, rollback, subscription, cloud provider, and new resource pages.
Malformed JSON in the coolify-log-filters localStorage key threw during
runtime log viewer startup. Read the saved value safely and keep only
boolean values for known levels.
Fixes#12101
Replace datalist and searchable-listbox components with the shared listbox and migrate form fields.
Deduplicate superseded Livewire updates to prevent repeated array update hooks, with regression coverage.
On non-secure origins the copy button falls back to execCommand('copy')
with a temporary textarea. The textarea was appended to <body>, outside
the x-trap focus trap of the DNS entries modal, so the trap pulled focus
back and the selection was lost before the copy. The button showed
success, but nothing was copied.
Append the textarea next to the button, select it explicitly, and
restore focus afterwards. "Copy all" now uses the shared copyButton
handler instead of its own duplicate fallback that ignored failures.
Closes#12075
Mark DNS proposals, conflicts and server IP properties as #[Locked] so
clients cannot tamper with them. Re-resolve the zone per hostname,
lowercase hostnames, validate record content server-side and use the
resource's team id for DNS lookups and jobs.
Move modal-confirmation submitAction parsing into a tested JS helper
that strips quotes and keeps commas, parentheses and escaped quotes
inside quoted arguments. Pass the hostname to replaceManagedDnsRecord
through it instead of Js::from.
Rework member-permission tests to open the real DNS dialog rather than
setting locked properties directly.
The All button read $wire.numberOfLines, which does not update while the user
types or pastes a new number, so All stayed highlighted. Keep the state in
Alpine instead: All loads set it, and any input in the number field clears it
unless the value is -1.
Show a spinner in the All button while all logs load, and in place of the
Lines label while a new line count loads. Both keep their width.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When the terminal started automatically, the session timeout started
only after a token arrived. If the server returned no token (container
not running, no shell, access denied, terminal disabled), the spinner
stayed on "connecting…" until the page was reloaded.
- Every early return now sends terminal-session-failed with a short
message; denied and unknown servers get the same text.
- Auto-start starts the session timeout in init(), so a missing token
always ends in a visible error with "Reload page".
- With more than one container, auto-start is cancelled, so the
container picker shows no false timeout error.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Traffic analytics:
- Reject enabling unless the server runs a Coolify-managed Traefik or
Caddy proxy, and show the reason in the settings UI
- Save the proxy configuration before the setting so a failure leaves
both unchanged; allow disabling after the proxy was removed
- Skip the proxy restart when the proxy is stopped and report that the
config applies on next start
- Preserve the user's own Traefik --accesslog* flags and restore them
when analytics is disabled
- Rotate the Traefik access log in the sidecar with BusyBox tools
(copytruncate, 5 gzip rotations)
- Create the access log before starting Sentinel, which opens it once
Terminal:
- Detect and surface WebSocket connection rejections in the browser
terminal, with shared helpers in terminal-connection.js and
terminal-utils.js
Database import:
- Restore PostgreSQL backups in a single transaction; SQL replace
restores go into a temporary database and swap in only on success,
leaving the current database untouched on failure
- 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
The application settings sidebar is long, so add a client-side search that
filters the nav items as you type. While searching it flattens the list (hides
group headers/dividers and in-page sub-sections) and shows a 'no results' hint;
clearing it restores the accordion. Extends the shared settingsSidebarAccordion
Alpine helper (search/matches/hasResults) so other sidebars can opt in later.
Discussion #11833: since v4.3.19 the resource settings sidebar expands every
group by default, so reaching Backups etc. means scrolling past every section.
Restore the v4.3.18 behaviour across all grouped resource sidebars (application,
database, service, server): each group header is now a collapsible toggle, and
only the group containing the active page is open by default. Manual expand/
collapse is remembered per resource type in localStorage; an explicit collapse
sticks even for the active group. Desktop (xl) only — the mobile grid is
unchanged (display:contents wrapper + xl-scoped collapse).
- new shared Alpine provider settingsSidebarAccordion (resources/js) + app.js
- nav-section-toggle utility (chevron header)
- wired into the four grouped sidebars
- static regression test
Design tokens
- Fix WCAG AA text failures: darken light muted text and lighten dark
tertiary text so 13-14px copy clears 4.5:1 on every surface.
- Rebuild the dark surface ladder in correct values (oklch compresses to
near-black below ~15%), giving visible steps: content, chrome, cards.
- Establish a 3-layer shell (deep content, lighter sidebar/topbar chrome,
lifted cards) with crisp hairline rings and a restrained card shadow.
- Unify every surface to one neutral temperature (pure gray); neutralize
the cool-tinted sidebar text and legacy surface tokens.
- Convert all color tokens to oklch (neutrals + brand).
- Unify inputs to the recessed token; fix invisible dark placeholders.
- One shared --shadow-dropdown for all menus/listboxes/command palette.
Settings sidebar
- Sticky contained-card rail with subtle scrollbar; collapsible sub-section
groups (active open by default), cross-page section links.
- Mobile: collapsible disclosure with animated open, outside/Escape dismiss,
press feedback, and reduced-motion support.
Mobile
- Consolidate the resource header (title + status + links on one row).
- Tighten settings-page vertical rhythm.
- Rebuild the main sidebar as an animated shadcn-style sheet (slide/fade,
Escape, scroll lock, in-panel close, close-on-navigate).
Fixes
- #11532: selected server invisible in the light-mode terminal toolbar.
Docs: update DESIGN.md tokens, shell layering, and temperature rules.