Commit Graph
811 Commits
Author SHA1 Message Date
Andras Bacsai 57faba1b96 fix(logs): prevent URL redaction from spanning log lines (#12238) 2026-10-20 10:49:29 +02:00
Andras Bacsai bf957e425f fix(docker): parse quoted and hyphenated custom docker option values (#12208) 2026-10-19 23:12:16 +02:00
Andras Bacsai 62be8674bc feat(proxy): add optional permanent redirects for apps and services (#12233) 2026-10-19 21:46:12 +02:00
Andras Bacsai fb6d3e7c9b fix(proxy): exclude SSE streams from Traefik compression (#12229) 2026-10-19 21:43:51 +02:00
Andras Bacsai 54315b10e5 fix(compose): strip UTF-8 BOM before parsing Docker Compose YAML (#12223) 2026-10-19 21:21:15 +02:00
Andras Bacsai 7fe40f4cf6 fix(api): require deploy ability for server side effects
Require deploy permission for API changes that trigger server side effects, including resource deletion, storage access, provider operations, and database imports. Also escape Docker cleanup filters and sanitize log drain server names.
2026-10-19 09:07:42 +02:00
Andras Bacsai 34b3a18307 fix(compose): resolve ../ bind sources in raw compose mode
oldRawParser made the bind directory of a long-syntax source like
../data at {workdir}./data, next to the path that Docker Compose uses.
Resolve the source with replaceLocalSource(), as the compose parsers do,
so Coolify makes the directory that the container mounts. A source that
resolves above / now stops the deployment before remote work.

Closes #4055
2026-10-18 12:09:42 +02:00
Andras Bacsai 420692c020 fix(upgrade): keep Coolify running when Docker reports IPv6 gateways with a prefix
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
2026-10-16 21:19:35 +02:00
Andras BacsaiandClaude Opus 5.5 69e448dac9 fix(installer): do not restart Docker with running containers
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>
2026-10-16 21:10:35 +02:00
Andras BacsaiandClaude Opus 5.5 f5c88f7e4f fix(deploy): do not pull locally built compose images before stop
Skip the pre-stop pull when a custom build command runs without a build server, and pull only services whose image does not come from a build, including services that reuse the image of a build service.

Closes #11773

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 00:19:17 +02:00
Andras BacsaiandClaude Opus 5.5 97f451cc2a fix(installer): change data directories only after checks and downloads
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>
2026-10-16 00:09:47 +02:00
Andras BacsaiandClaude Opus 5.5 6b3f60c7d6 fix(docker): ship versions.json in production image
Closes #11868

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 23:38:06 +02:00
Andras Bacsai 12fd9e448b fix(upgrade): retry rate limited image pulls and spread auto updates
Closes #11890
2026-10-15 23:36:47 +02:00
Andras BacsaiandClaude Opus 5.5 3414b88e0d fix(applications): ignore missing health on additional server status
Closes #11892

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 23:33:52 +02:00
Andras BacsaiandClaude Opus 5.5 3fbb8da5ff fix(service): add seadoc server to seafile template for wikis
Closes #11976

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 23:27:15 +02:00
Andras BacsaiandClaude Opus 5.5 2a202d9fe9 fix(domains): apply noindex to domains that include a port
Closes #11965

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 23:20:23 +02:00
Andras BacsaiandFurox 6cf1516749 fix(server): accept OS derivatives through ID_LIKE in validateOS
validateOS matched only ID from /etc/os-release, so derivatives such as
Omarchy, CachyOS, Manjaro or Linux Mint failed validation before the
Docker checks ran. Check ID first, then each ID_LIKE entry, and keep the
exactly-one-match rule. Move the parsing into a testable function.

Closes #12033

Co-authored-by: Furox <177975472+Furox-Art@users.noreply.github.com>
2026-10-15 22:35:45 +02:00
Andras BacsaiandClaude Opus 5.5 7466da12a2 fix(git): accept ssh:// repository URLs with custom ports
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>
2026-10-15 22:30:26 +02:00
Andras Bacsai d080bf35e6 refactor(policies): remove unused authorization methods (#12165) 2026-10-14 10:18:05 +02:00
Andras Bacsai 7837a07ba2 fix(notifications): disable channels after repeated configuration failures
Count invalid keys, tokens, and deleted webhooks in a new failure_count column
on each notification settings table, like servers.unreachable_count. After 3
failures in a row the channel is disabled and the team is told by instance
email and its other channels. Rate limits and server errors are retried and
not counted; test notifications never count.
2026-10-12 14:37:58 +02:00
Andras BacsaiandClaude Opus 5.5 213a61b7ab fix(env): pass exact env values to containers, keep old escaping for existing variables (#12024)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 13:06:45 +02:00
Andras Bacsai cdd8f82840 fix(compose): preserve environment variable semantics (#11794) 2026-10-11 21:02:11 +02:00
Andras Bacsai 1e42284db0 feat(proxy): override the Traefik certificate resolver per resource
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
2026-10-11 19:01:27 +02:00
Andras Bacsai ec9621370a fix(deployments): log the configured timeout when a deployment times out 2026-10-11 16:25:26 +02:00
Andras Bacsai 5246427b03 fix(upgrade): remove disk space checks that block Coolify updates 2026-10-09 20:03:49 +02:00
Andras Bacsai a963f95612 fix(railpack): match frontend version to the helper's CLI
Use the helper's RAILPACK_VERSION, falling back to the installed CLI
version, instead of a hardcoded frontend version. Add regression tests
for both version sources and application-variable isolation.
2026-10-09 16:15:49 +02:00
Andras Bacsai 0873616a7f fix(dns): retry custom DNS queries over TCP when UDP answer is truncated
Closes #12076
2026-10-09 15:34:26 +02:00
Andras Bacsai f39c884cc7 fix(servers): support IPv6 server addresses everywhere
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.
2026-10-09 13:50:28 +02:00
Andras BacsaiandClaude Opus 5.5 376e7aab24 feat(upgrade): block upgrades when the disk is almost full
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>
2026-10-09 13:26:53 +02:00
Andras Bacsai 8c4aa7bb00 feat(git): allow IPv4 and IPv6 addresses in repository 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.
2026-10-09 09:31:07 +02:00
Andras Bacsai ea1199bf8e fix(compose): allow required and alternative variables in network names
Accept the `?`, `:?`, `+` and `:+` interpolation operators in Compose
network names, such as `${CONTAINER_NAME?error}`. The validation added
in v4.4.0 only knew `-` and `:-`, so these valid files stopped deploying.

The text after `?` is an error message and is not used as the default of
the created environment variable. Unsafe operands are still rejected.

Fixes #12126
2026-10-09 08:45:03 +02:00
Andras Bacsai df953bdcd1 fix(upgrade): prevent duplicate upgrades and stalled progress polling
Block new upgrades while a recent upgrade is running, allowing retries after 15 minutes without a status update.

Add request timeouts and polling guards to keep upgrade progress responsive during restarts.
2026-10-09 08:01:20 +02:00
🏔️ Peak 3f953d1dce revert(git): stop forcing HTTP/1.1 for repository imports (#12080) 2026-10-08 18:10:07 +02:00
Andras Bacsai cac22f65f4 fix(deployment): build static buildpack preview images from generated Dockerfile
Pull request deployments sent every non-railpack build pack to build_image(),
which no longer handles the static build pack since it was moved to
build_static_image(). Static preview deployments then failed with
"open Dockerfile: no such file or directory".

Closes #8238
2026-10-08 07:18:39 +02:00
Andras Bacsai e0639a8e6d fix(applications): normalize nested base64 custom labels (#11473) 2026-10-07 16:44:59 +02:00
Andras Bacsai 76d3386a4d refactor(forms): unify searchable and multi-select listboxes
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.
2026-10-07 15:37:03 +02:00
Andras Bacsai 81045b2dc2 fix(compose): deploy large Compose files such as Sentry self-hosted
Sentry self-hosted (getsentry/self-hosted 26.8.0) could not be deployed
as a Docker Compose application. Three separate problems blocked it:

- YAML collection aliases: the first fix raised the limit to 256 only in
  Application::oldRawParser(). The safety check added in v4.4.0
  (validateDockerComposeForInjection) and all other Compose parse calls
  still used the Symfony default of 128, so the Sentry file (133 aliases)
  failed with "Maximum number of collection aliases (128) exceeded".
  Add parseDockerComposeYaml() and use it for every Compose parse.
- Argument list too long: the deployment job sent the generated Compose
  file as base64 inside the SSH command. Linux limits one argument to
  128 KiB, and the Sentry file is about 370 KB. execute_remote_command()
  now accepts an 'input' key that streams content over SSH stdin, and
  the job writes the Compose file with it.
- A list-style build arg without a value (build.args: [SENTRY_IMAGE])
  merged into a map environment kept its numeric key, so Docker Compose
  rejected the file with "non-string key in ...environment: 0". It now
  becomes NAME with no value, as in Compose.

Closes #11725
2026-10-07 13:30:42 +02:00
Andras Bacsai 7d17c6ff8b fix(domains): skip favicons for private network hosts (#12107) 2026-10-07 12:28:48 +02:00
Andras Bacsai 56497d50cf fix(deployments): include scheduled jobs in progress checks
Count running scheduled tasks, database backups, and volume backups,
excluding runs older than their job timeout. Report scheduled job counts
and keep the progress check active while any scheduled jobs are running.
2026-10-06 21:59:16 +02:00
Andras Bacsai 41ed5b7a69 test: fix stale and flaky tests
- Update tests whose expectations no longer matched intended changes
  (GitHub App redirect, wildcard domains, container IDs, nightly
  install folders, localhost metadata, Sentinel restart on save)
- Seed the instance settings the 2FA profile test needs
- Run the global Pest hooks for all test folders and release the
  Laravel application after each test, so tests do not leak state
- Replace a class alias mock that broke later tests
- Generate factory names that always pass name validation; Faker names
  with apostrophes or short words made form tests fail at random
2026-10-06 13:01:49 +02:00
Andras Bacsai 8c5fe1c85b fix(runners): create the runner secret file readable only by its owner 2026-10-06 12:56:50 +02:00
Andras Bacsai 3645c4747e fix(sudo): do not follow symlinks when chown gives Coolify paths to a non-root SSH user 2026-10-06 12:56:50 +02:00
Andras Bacsai 116806df1b fix(compose): allow content files outside the resource directory again
Since aabd12737 a Compose bind volume with a content block had to stay
inside the resource directory. Services and Compose applications saved
in v4.3.23 with other paths, and Git Compose files with them, no longer
started or deployed.

Only admins and owners can edit Compose files, and they can already
write any host file with a plain bind mount, so the rule added no
security.

- Write content files to their host path again, as in v4.3.23
- Keep shell escaping and the safe-character checks on volume sources,
  so injection attempts are still rejected
2026-10-06 11:03:39 +02:00
Andras Bacsai 41dbcbbab3 fix(server): keep commands after mkdir -p for non-root users
The sudo parser read everything after `mkdir -p` as the path, so the
ownership step ended up after the last command of the line. For
`mkdir -p /data/coolify/proxy/dynamic && ls ... | head -n 1000`, `head`
got the `find` options and the proxy dynamic configurations failed on
every server with a non-root user.

- Add the ownership step right after the mkdir path; commands after
  `&&` or `;` stay unchanged
- Lines with other forms (redirects, `||`, pipes) get no ownership step
2026-10-05 22:37:06 +02:00
Andras Bacsai 111ff9adae docs(api): document audit events and fix the private key update path
- Add the OpenAPI attribute for GET /audit-events
- Document PATCH /security/keys/{uuid} with its uuid parameter instead
  of /security/keys
2026-10-05 21:24:20 +02:00
Andras Bacsai 13db52f730 fix(scheduler): accept ScheduledJobManager jobs queued before the upgrade
Jobs that v4.3.23 put in the queue have no type property. The promoted
constructor property had no default, so these jobs failed with "must not
be accessed before initialization" after the upgrade.

- Declare type as a normal property with a null default
2026-10-05 21:18:48 +02:00
Andras Bacsai 0da202b39d fix: protect restores, preview imports, and analytics access 2026-10-05 17:02:56 +02:00
Andras Bacsai 439ee6faea fix: restrict proxy content access and scope backup storage to owners
- Hide proxy configuration contents from users without update permission.
- Select and validate backup S3 storage against the resource's team.
- Keep scheduled branch syncs green while a conflict PR remains open.
- Document external mount permissions and Sentinel traffic limits.
- Add regression coverage for authorization and backup storage selection.
2026-10-05 13:20:19 +02:00
Andras Bacsai 4227ec6ebf fix(storage): require deploy permission for external host writes
Require deploy or root token access when creating managed mounts outside
resource directories or changing their file contents through the API.

Synchronize KeyDB and Dragonfly passwords with local and shared
REDIS_PASSWORD values while preserving secret manager resolution.
2026-10-05 12:03:37 +02:00
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