Resolve conflicts between main's 4.5 changes and the v5 Node work:
- GetLogs: keep main's browser-side log viewer; read cluster logs from
Sentinel, with since_unix_seconds for streaming.
- Terminal: keep main's session-failure events and attach mode; keep
the Node terminal target.
- Dashboard: keep main's layout; add the cluster map as a third servers view.
- Remove the settings sidebar accordion from Node, cluster, and cluster
application sidebars, as main did for servers.
- Replace removed x-forms.select with x-forms.listbox.
- Node factory creates its SSH key in the node team (main scopes key lookup).
- Add v5 models to the server transfer coverage and app key re-encrypt review.
- let patch.sh run while the coolify container is stopped
- If the compose files are from 4.4 but an older Coolify is installed the error now prints the command to update to 4.4.7
Docker Compose resolves these values from the .env file, so the parser no
longer rejects or misresolves them. Also copy the expected parser fixtures
when parser-snapshot-diff compares with a git ref.
ServiceParserReferenceTest parses reference fixtures for serviceParser and
applicationParser (one service per feature, with setting variations and error
cases) and every template, and compares the output with expected files.
scripts/parser-snapshot-diff shows how a code change alters the output of all
cases (save / baseline). Template expected files are gitignored.
Docker Engine 27.0 to 28.0.0 reports an IPv6 network gateway with its
prefix length (fd00::1/64) until the daemon restarts (moby/moby#49520).
The Docker CLI 29 and Compose 5 in the helper image reject it, so
deployments failed and the upgrade left Coolify stopped.
- Stop the upgrade before it changes containers when the coolify network
has such a gateway, and tell the user to restart or upgrade Docker.
- Create a new coolify network again without IPv6 when Docker reports
its gateway with a prefix.
- Report an error, not "Upgrade complete", when the new Coolify
containers do not start.
- Add the fix to deployment errors that contain this ParseAddr failure.
Fixes#11583
Merge log rotation and the network pool into the existing daemon.json
instead of overwriting it. Skip the change and the Docker restart when
containers are running, unless DOCKER_POOL_FORCE_OVERRIDE=true.
Closes#11221
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
install.sh created the resource directories and ran chown -R and
chmod -R on source, ssh, and images before step 1. When a check or a
CDN download failed, the changed owners and modes stayed although
nothing was installed.
Create only /data/coolify and source (for the log and the downloads)
at the start. Create the other directories and set the permissions in
the SSH key step, after the checks and downloads succeed.
Closes#11973
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Move all git examples into ApplicationSeeder on railpack, using the
reorganized coollabsio/coolify-examples main branch, and drop the
separate Railpack Examples project. Add DEV_SEED_IP to set the IP for
seeded sslip.io domains (e.g. a Tailscale IP).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An upgrade pulls new images and recreates the Coolify containers. A full
disk during an upgrade can leave Coolify broken.
- Measure free space on the Docker root dir and /data/coolify of localhost;
require 5 GB. An unknown value does not block.
- Manual upgrade: show the free and required space, with Run Docker cleanup,
Check again, and a confirmed Upgrade anyway override.
- Automatic upgrade: skip it and notify the team (disk usage channels, at
most once per 24 hours per server).
- upgrade.sh: stop before any change when the disk is low. A new 5th
argument skips the check (used by the override).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Key ingress routes by workload UUID and replicate internal DNS names through cluster network revisions on every node. Reconcile name changes and deletions without relying on mutable container labels.
Require route and name reconciliation for network convergence and extend lifecycle, ingress, and end-to-end coverage.
Allow cluster workloads to configure domains and HTTP ports, and enable
individual nodes as ingress proxies. Reconcile Caddy routes and firewall
rules as network revisions so domain changes apply without redeploying.
Refresh ingress routing when workload placements change and merge node
metadata under a row lock to preserve concurrent updates.
Add ingress controls, domain links, and regression and end-to-end coverage.
Per-Node network convergence: an offline Node no longer blocks the
cluster. Each Node tracks converged, pending, or error with backoff;
the cluster is active, degraded, or error. A scheduled check and Flux
reconnects repair only the Nodes that are behind or drifted. An offline
Node can be removed; its leave runs when it reconnects. Deploys to a
degraded cluster go only to converged Nodes.
Health notifications: one notification when a Node is unreachable for
3 minutes, when a cluster network is degraded or failed, and when each
recovers. They reuse the server reachable and unreachable toggles.
Staged Flux CA rotation: distribute the old and new CA over Flux, wait
for every Node to acknowledge, switch the Flux leaf to the new CA, then
retire the old CA. Supports cancel, force, and catch-up for offline
Nodes. Available to instance admins at /settings/node-trust and through
`flux:rotate-ca`. Renewing the Flux certificate is now instance-admin
only.
Stale recovery closes an uncertain workload operation after one minute
when fresh inventory shows that the requested state already runs.
Add `scripts/node-e2e` and `dev:node-e2e`, a QEMU end-to-end suite for
Coolify down, reboot recovery, stop markers, Flux restart, offline
Nodes, CA rotation, and offline removal.
CDN files are synced through the coollabs-cdn GitHub repository only.
Remove the --bunny direct upload path, the BUNNY_API_KEY and
BUNNY_STORAGE_API_KEY settings, and rename the command to sync:cdn.
Use auth_rate_limit_ip() rather than $request->ip() for the api, 5 and
feedback rate limiters. On cloud, each client behind Cloudflare now gets
its own bucket instead of sharing the proxy's bucket. Self-hosted
instances ignore the CF-Connecting-IP header.
Add feature tests for per-client sentinel push buckets on cloud and for
ignoring the header on self-hosted.
Add scripts/restore-backup-vm.sh, which restores an instance backup into
an offline KVM VM to test database migrations. Bump the v4 version in
other/nightly/versions.json to sha-1e9add3.
install.sh ran chown -R 9999:root and chmod -R 700 on all of
/data/coolify on every run. This changed bind-mounted data of services,
applications, and databases, and reset the ownership that a non-root
SSH user needs.
Set owner and mode on /data/coolify and the resource directories only
when the installer creates them. Change only source, ssh, and images
recursively, because the coolify container uses them.
Also wait until the Docker daemon accepts connections after a restart,
because OpenRC returns before the daemon is ready.
Fixes#11945
Add a Lima backend to scripts/dev. Auto mode picks it on macOS when
limactl (Lima >= 2.0) is installed, and COOLIFY_DEV_SERVER_BACKEND=lima
forces it. Lima VMs are named coolify-dev-<slot>-<profile>. Coolify
connects to them through Lima's forwarded SSH port on
host.docker.internal, and only guest ports 80/443 are forwarded to
the host.
dev:qemu:seed now takes --ip and --port options, so the seeded server
can use a forwarded SSH address instead of the profile IP.
Add tests for the Lima start flow and for seeding with an overridden
address, and document the macOS setup in AGENTS.md.
- 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
Add UpdateNodeWorkloadConfiguration to create a new workload revision
when the command, ports or environment change. Revisions now store the
environment separately, and a shared NodeWorkload::createRevision helper
builds them. The cluster application page can edit these settings.
Deployments take a pull policy ('missing' or 'newer'), which is passed
through to Sentinel. User redeploys use 'newer' so mutable tags pull the
latest image. Before a move starts, the source node must support
workload.lifecycle.v1 and the target must support workload.deploy.v1.
The coordinated workload.move.v1 command no longer needs its own
capability. Adds a migration for Sentinel capabilities on nodes.
Adds a 'naked' dev QEMU profile runtime. These VMs boot with the
coolify-flux hosts entry and are not seeded, so they can be added
through the Node onboarding UI. Removes the standalone scripts/dev-qemu
script in favour of scripts/dev.
Conflict resolution:
- Development QEMU: keep next's instance mode and prepared template images;
re-add v5 Podman worker Node profiles, Node seeding, Podman templates, and
the node-dev compose overlay through ./scripts/dev.
- Terminal: use next's token-based TerminalSessionService; add Node targets
with the v5 readiness and team checks at issue and redeem time.
- Sentinel: keep v5 Flux imports and next's SentinelSynchronized event; use
next's viewSentinel policy.
- Clusters page: follow next's no-placeholder rule for empty descriptions.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Merge scripts/dev-instances into scripts/dev. Each branch gets its own
Compose project, container, volumes, port block, libvirt network, and
KVM VMs, so stop and start reuse the same data and worktrees do not
collide.
- Name instances after the branch; keep slots and APP_KEYs in the main
checkout's .dev-instances/ so they survive worktree removal
- Reuse existing QEMU VMs instead of recreating them; add dev:qemu --fresh
- Give each instance an isolated libvirt network (10.221.<slot>.0/24)
and VM names coolify-dev-<branch>--<profile>
- Publish per-instance browser ports and publish them with tailscale
serve when APP_URL is a tailnet host
- Add urls, exec, logs, container, destroy, and teardown commands; run
teardown from jean.json before Jean deletes a worktree
- Fix Reverb/terminal browser ports and the testing-host alias in the
instance compose file
- Keep fresh worktree instances working: pre-create laravel.log, log the
host dev:qemu call to stderr, and stop Vite from watching vendor/
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Use SOKETI_PORT for Docker host bindings, keep Reverb on port 6001 internally, and stop install/upgrade scripts from overwriting public websocket port overrides.
Add resumable VM provisioning and bootstrap development workers with Sentinel, Podman validation, mesh assignment, and network reconciliation.
Move the node inventory from Servers to Clusters and update cluster navigation.