Updating the image of a service named like "api.test" wrote a nested
"test" key into the "api" service, because data_get/data_set split the
name on dots. Use array key paths instead. Also refuse service names that
Docker cannot use as a container name prefix, with a clear error on save.
Closes#12456
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GitHub rejects new RSA SSH keys smaller than 3072 bits, and phpseclib
made 2048-bit keys by default, so new RSA deploy keys from Coolify
could not authenticate.
Closes#12461
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Read compound and fractional durations (1m30s, 1.5m), quoted values,
only the flags before CMD, the escape parser directive, and NONE with
flags. Zero and sub-second values no longer become 0 seconds.
Closes#12455
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Containers without the Coolify default variables sent no project,
environment, or service to the drain. The fluentd driver now also sends
the Coolify container labels; the built-in configs use them as a
fallback and add coolify.service_name.
Closes#8415
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Every channel has a block of its own, every version after this one reads only these blocks
- Every stable sync also fills the coolify and traefik keys older instances read
- An instance keeps a copy of versions.json and reads upstream.json of the image until it has one
- On a resource page, the main menu starts with a row that shows the
resource name and opens the deepest resource menu again.
- Pass the resource name to registerMainNavContext() again.
- Document the row in DESIGN.md.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Cloning a clone added another "-clone-<id>" to the name, so after about
seven clones the name was longer than 255 characters and the insert failed.
Closes#9976
The main sidebar shows the resource menu from lg, where it appears, and the
mobile drawer shows it too, so the page grid menu is gone. The drawer opens
on the menu of the current page again after it closes. Below xl, the resource
actions are a compact button in line with the title.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Wait for each ifconfig.io lookup alone instead of through
Process::concurrently(), which throws on the first timeout and discards
the sibling result. Add --max-time 10 so a stalled lookup ends early.
Closes#12275
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Make the dark sidebar a flat neutral #0d0d0d with neutral tiles, text,
search, and account button; only the current item stays purple.
- Remove the resource row and spacer at the top of the main menu, so
Dashboard sits under Search, and drop the unused nav context name.
- Route hard-coded brand purple, canvas, and card colors through tokens
that the custom theme overrides, so sidebar, buttons, accents, cards,
and tables follow the picked color.
- Paint page-level button and view-toggle tints over the canvas so the
floating navigation dots do not show through.
- Document the new sidebar and token rules in DESIGN.md.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Add a main-menu row that reopens the resource menu, with a placeholder row
- Show only the other view as an icon in the view switcher
- Remove the active tile glow and the collapsed Search frame
- Tint the dark command palette purple and whiten focused-row details
- Soften the toast edge and give the toast icon tile 3D depth
- Document the decisions in DESIGN.md
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Retry CDN requests only for transient errors and honor Retry-After
(Cloudflare error 1200 sends 60 s), with jitter.
- Read helper and Sentinel versions from the local versions.json, which
the hourly update check refreshes, instead of fetching per job/server.
- Replace the random 0-600 s delay with a stable per-instance offset
inside the cron interval (max 1 h).
- Manual update checks and upgrades make one CDN attempt only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The repository URL rule rejected ssh://user@host:port/path, so deploy-key
resources on servers with a custom SSH port needed a manual URL edit after
creation. Accept ssh:// URLs and keep them unchanged for deploy keys so the
port reaches the clone. Rename scpStyleGitUrlToHttps to sshGitUrlToHttps and
let it convert ssh:// URLs too, so public flows, repository links and GitHub
App repository slugs handle them.
Closes#12161
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Applications and service applications can now use the server resolver,
no resolver ("none"), or a custom resolver name. This allows servers
that mix Let's Encrypt domains with domains that use their own
certificates, such as Cloudflare Origin CA. The setting is available in
the UI and the API.
Closes#12138
Coolify always added tls.certresolver=letsencrypt to generated HTTPS
routers, so Traefik logged errors when the proxy used its own
certificates (for example Cloudflare Origin CA) without that resolver.
Add a server setting (default letsencrypt) in the proxy page and API.
An empty value omits the resolver from resource labels, the Coolify
dashboard routes, and the catch-all router.
Closes#12138
Store server IPs in one form (no brackets, short lower-case IPv6) and
write each address in the form its context needs:
- URLs and host:port (Sentinel, database URLs, SFTP backup download,
DNS servers, SMTP, webhook base URLs, links, health checks) get
brackets through formatHostForUrl().
- Traefik Host() rules use the address without brackets, so IPv6
domains no longer return 404; saved labels are fixed at deploy.
Caddy keeps the brackets.
- SSH keeps the plain address.
- Hetzner gives an IPv6 /64 network; IPv6-only servers now get the
server address (prefix::1) instead of the unusable prefix::64.
- sslip labels, registry image names with an IPv6 host, the API domain
list, allowlist matching and duplicate checks handle IPv6.
A migration normalizes stored IPv6 server addresses, repairs Hetzner
servers saved as ::64 that are not reachable, and adds brackets to
saved Sentinel URLs.
Accept HTTP(S), git:// and SCP-style SSH repository URLs whose host is an
IP address, including bracketed IPv6 such as git@[2a01:4f8::1]:org/repo.git.
The clone runs on the user's deployment server, so the IP block did not
protect Coolify, and SSH URLs with IPv4 already passed.
Loopback, link-local and other reserved addresses are still rejected as
internal hosts. Brackets are allowed only around a valid IPv6 host.