102 Commits
Author SHA1 Message Date
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 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 9a11407e2f fix(previews): isolate NFS and CIFS volumes from production 2026-10-05 22:27:49 +02:00
Andras Bacsai 8aa57d66e8 fix(previews): give each preview its own volume for external volumes
Previews of Docker Compose applications used external volumes as
written, so a preview mounted the production volume. Two database
containers on the same data can corrupt it.

- A preview uses {uuid}_<name>-pr-N with a name-only declaration, the
  same name as v4.3.23, so old preview volumes are used again
- Production still uses the external volume as written
- Preview cleanup removes the preview volume, never the external one
- Do not show the external volume warning for previews
2026-10-05 21:25:40 +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 BacsaiandClaude Opus 5.5 7ec46faecb fix(previews): do not bind preview volumes to the production host device
A preview volume no longer gets driver_opts that name a host device, so it
does not mount the same folder or disk as the production volume. tmpfs
options are kept.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 16:01:20 +02:00
Andras Bacsai 5921fb2958 fix(compose): keep name-only declaration for pre-existing volumes
Before Coolify kept `driver`, `driver_opts` and `labels` of renamed
Compose volumes, Docker created those volumes without them. Applying the
options now would make Docker Compose ask to recreate the volumes on
every deployment.

- Add `ignores_compose_driver_options` column to local_persistent_volumes
  and mark all volumes that exist at upgrade time
- Parsers now use composeRenamedVolumeDeclarationFor() so flagged volumes
  keep the old name-only top-level declaration
- Legacy application parsers (v1/v2) always emit name-only declarations
- Reset the flag when a volume is replicated, since a clone is a new
  Docker volume
- Include the flag in server transfer export/import; bundles without it
  default to true
- Storages UI shows which volumes ignore driver options and allows
  deleting them so the options apply on recreation
- Add tests for parsers, cloning and server transfer
2026-09-30 14:31:33 +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 d1bdecba6d fix(compose): allow variables in external volume names
Accept Compose variables ($NAME, ${NAME}, ${NAME-default},
${NAME:-default}) in the `name:` of an external volume, and in the old
`external: {name: x}` syntax. Docker Compose resolves them from the
deployment .env. Coolify never removes external volumes, so it does not
need the resolved name.

The volume key must still be a literal Docker volume name, because
Compose does not resolve variables in keys. Names that are unsafe or use
unsupported syntax are still rejected, for example command substitution,
spaces, escaped dollars, and ${VAR:?err}.

Add tests for application and service parsing, legacy volume rows, the
StackForm save, legacy Compose parsing, and the rejected cases.
2026-09-30 12:29:50 +02:00
Andras Bacsai af983a29d8 refactor(docker): identify containers by resource UUID instead of numeric id
Container ownership labels now use UUIDs: coolify.applicationUuid,
coolify.serviceUuid, coolify.service.subUuid and coolify.databaseUuid.
Numeric ids differ between Coolify instances, so after a server transfer
the target could not find existing containers: redeploys left the old
container running and service statuses were wrong.

Containers are matched by UUID label first, then by the compose project
(Swarm: stack namespace), which is the resource UUID since July 2024, and
last by the older numeric id label. Existing containers keep working
without a redeploy and get the UUID labels on the next deploy or restart.
2026-09-29 09:57:56 +02:00
Andras BacsaiandClaude Opus 5.5 862e021f2d feat(compose): warn about legacy external volumes and list external volumes
Legacy Compose applications keep the old name of an external volume. The
deployment log now tells the user why and how to move to the external
volume. The storage page shows external volumes as a read-only list.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 21:09:13 +02:00
peaklabs-dev 2aef5ab459 feat(database): let docker compose applications mount the sqlite volume 2026-09-27 18:00:34 +02:00
Andras BacsaiandClaude Opus 5.5 49ae227f6e fix(compose): keep the old volume of existing resources for external volumes
Switching an external volume from the old <uuid>_<name> volume to the
declared external volume on redeploy could make an app look as if it
lost its data (for example a database that initializes a new, empty
data directory).

- If a resource already has the storage entry with the old generated
  name, the parsers keep using that volume and show a warning in the
  deployment log and the service start log, with the steps to switch.
- Without that entry (new resources, or external volumes added later)
  the external volume is used as declared.
- Deleting the old storage entry (storage page) switches to the
  external volume on the next deployment; the storage entry shows a
  note about it.
- Legacy Compose applications (parser versions 1 and 2) never stored
  their volumes, so they keep the old volume names.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 17:24:51 +02:00
Andras BacsaiandClaude Opus 5.5 ee62f64add fix(compose): use external volumes as declared
Compose volumes declared with external: true (or external: {name: x})
were renamed to <uuid>_<name>, so containers got a new empty volume
instead of the existing one. All Compose parsers (applications,
previews, services, and the legacy parsers) now use them as written:
no uuid prefix, no preview suffix, the top-level declaration kept, and
no tracking row, so Coolify never removes a shared external volume.
External volume names must be literal; ${VAR} names are rejected.
Existing <uuid>_<name> volumes and their rows are kept on redeploy.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 16:53:54 +02:00
Andras BacsaiandClaude Opus 5.5 700d476bac fix(dev): rewrite host paths only for the testing-host dev server
Development mode rewrote /data/coolify paths to the dev Docker volume
for every server. That is only right for the testing-host backend,
which uses the host Docker daemon. The KVM localhost and other dev VMs
have their own /data/coolify, so bind mounts, Compose content files,
the Traefik and Caddy traffic mounts, Sentinel, and database proxies
pointed to wrong paths there.

- Server::sharesDevHostDocker() and devHostDockerPath() decide per
  server; only the testing-host server (ip coolify-testing-host) gets
  the volume path. Production is unchanged.
- The testing-host volume names come from the Compose project
  (DEV_COOLIFY_DATA_VOLUME, DEV_COOLIFY_BACKUPS_VOLUME), with the
  legacy names as fallback.
- In development, saved proxy configurations with the old path are
  fixed when they load and ask for a proxy restart.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 15:21:39 +02:00
Andras BacsaiandClaude Opus 5.5 aabd127374 fix(compose): keep content files inside the resource directory
- A Compose bind volume with a Coolify `content:` block could make
  Coolify write any host file (for example /root/.ssh/authorized_keys)
  when the file was loaded. Content sources must now be inside the
  resource directory (./ paths); other sources get a clear validation
  error for services and applications (UI, API, load, deployment),
  and every content write is confined again on the server. Bind
  mounts without content are unchanged. All 94 template content
  volumes use ./ paths and still work.
- Quote container names in scheduled tasks and in the stop actions for
  applications, previews, and services.
- Fix a development-only crash when a preview with a bind mount was
  parsed (the preview suffix returned a plain string).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 14:37:21 +02:00
Andras BacsaiandClaude Opus 5.5 5b2724621a fix(compose): validate Git-based Docker Compose applications
Git-based Docker Compose applications skipped the Compose injection
validation that services use. It now runs when the file is loaded or
reloaded, when the raw Compose is saved (UI and API create), and at
deployment before any command uses the file; an unsafe file is not
saved, and a deployment stops with a clear log line.

- All 371 service templates and realistic Compose files still pass.
- Network names may now mix text with $VAR, ${VAR}, ${VAR:-default},
  or ${VAR-default} (for example ${COMPOSE_PROJECT_NAME}_default), so
  such existing applications keep deploying; command substitution and
  unsafe defaults stay rejected.
- Quote the preserved-repository path in a stat command.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 13:47:01 +02:00
Andras BacsaiandClaude Opus 5.5 45f7b8422f fix(compose): create network name variables for Compose applications
A Docker Compose application could use ${VAR} as a network name, but
only services created the variable. With ${VAR:-default} the value was
hidden and could not be edited; with ${VAR} Compose got an empty name
and the deployment failed. Applications now get the variable (and its
preview copy) with the default from the compose file, like services.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 22:18:17 +02:00
Andras BacsaiandClaude Opus 5.5 510a2d838b feat(analytics): log Compose resources on Caddy and add service analytics
Traffic analytics now covers every resource on both proxies:

- Caddy: Compose applications and services get access-log labels. The
  log_append key is {uuid}-{service}, the same key Sentinel reads from
  Traefik router names.
- A resource owns the Sentinel key {uuid} and every key that starts
  with {uuid}-. Application pages and the traffic card now merge all
  keys, so Compose applications and previews show data on Traefik too.
- Global analytics: the leaderboard groups the keys of one resource
  into one row, lists services, and never names keys of other teams.
- New service analytics page (project.service.analytics) with the same
  view and authorization as the application page.
- Switching the proxy type restarts Sentinel when analytics is on, so
  it reads the new log path. Sentinel gets no traffic mount when the
  proxy has no analytics support.
- Caddy servers show a note that resources log only after a redeploy.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 01:00:55 +02:00
Andras Bacsai 37bd776f70 feat(services): allow variables in compose network names
Accept a top-level network `name:` that is a single Compose variable
(`${VAR}`, `${VAR:-default}`, `${VAR-default}`), e.g. for external
networks that differ per server. The default must still be a valid
network name; surrounding text, nested variables, and shell syntax
are still rejected.

When parsing services, such variables are created as service
environment variables (seeded with the default) so users can view and
change them, while the compose file keeps the variable for Compose to
resolve from .env at deployment. Existing values are preserved on
re-parse.
2026-09-25 21:43:35 +02:00
Andras Bacsai 0935bf141e Improve volume path handling (#11993) 2026-09-24 23:22:35 +02:00
Andras Bacsai 3f47bae0b6 fix(service): save switches without saving pending Compose edits (#11985) 2026-09-24 13:43:37 +02:00
Andras Bacsai aa2b6b862b fix(compose): validate Docker network names
Require Compose network names to match Docker identifier rules.
Ensure missing proxy networks with inspect and a single escaped argument.
2026-09-21 15:30:11 +02:00
Andras Bacsai 1b842090ad fix(previews): split compose domains into Traefik labels (#11812) 2026-09-16 13:33:29 +02:00
Andras Bacsai 59eacc9ff8 fix(services): keep Traefik subtype from stored service type
Label service apps as application even after the compose image looks like a database. Do not auto-heal existing deployments.
2026-09-13 21:09:01 +02:00
Andras Bacsai 183e28682c fix(domains): route Compose domains using service ports
Resolve routing ports per Compose service, preserve legacy embedded ports, and ignore non-TCP declarations.
2026-09-07 15:17:23 +02:00
Andras Bacsai 208f7720bc fix: avoid inherited compose ports and defer archive inspection
Prevent multi-service Compose domains from inheriting the application port, and defer PostgreSQL custom-format archive inspection to pg_restore.
2026-09-05 14:19:38 +02:00
Andras Bacsai 851a902346 fix(domains): preserve removed compose service domains 2026-09-04 16:47:12 +02:00
Andras Bacsai 986ece457d fix(domains): use Compose service ports for internal routing
Detect Docker Compose service ports for domain internal ports and proxy labels, with application ports as a fallback.
2026-09-03 20:38:19 +02:00
Andras Bacsai e2e91fbb85 feat(domains): support per-domain internal port overrides (#11594) 2026-09-02 19:39:19 +02:00
Andras Bacsai ab5025f0a7 fix: select Traefik networks and stabilize dropdown positioning 2026-08-18 09:42:36 +02:00
Andras Bacsai 17d9d1a370 feat(domains): add configurable HTTPS redirects for service apps 2026-08-18 09:08:18 +02:00
Andras Bacsai 1c25b58dc8 fix(proxy): set Traefik network labels for compose services
Add the Coolify network label when no user-selected Traefik network exists, while preserving custom labels for applications and services.
2026-08-15 18:31:32 +02:00
Andras Bacsai 003e44d123 Merge remote-tracking branch 'origin/next' into feat/noindex-domains 2026-08-08 11:26:20 +02:00
Andras Bacsai 5de6f97256 feat(ui): unify resource nav sidebars and polish project layouts
Extract application/database/service configuration sidebars and
unified headings; improve clone-to-environment, embedded deployments,
storage actions, OAuth icons, terminal, and shared form components.
2026-08-05 17:56:59 +02:00
Andras BacsaiandShadowArcanist 8ae56587d5 feat(ui): Shadow UI redesign, domain management, and DNS autoconfigure (#11119)
Co-authored-by: ShadowArcanist <162910371+ShadowArcanist@users.noreply.github.com>
2026-08-03 23:11:54 +02:00
Andras Bacsai 0b843bb07c fix(compose): normalize service-name keys for domains and env vars (#11040) 2026-08-03 23:08:56 +02:00
Alberto Rizzi 4afe131905 feat(domains): add per-domain noindex support
Flagged domains are served with X-Robots-Tag: noindex, nofollow via
Traefik and Caddy routing labels, so an auto-generated technical domain
can be excluded from indexing while the production domain on the same
resource stays indexable.
2026-07-12 13:59:09 +02:00
Andras Bacsai d01e3a9730 fix(parsers): populate docker_compose_domains for API-created Docker Compose apps (#9300) 2026-07-07 12:17:52 +02:00
Andras Bacsai eddcbe819b fix(parser): populate compose domains from service env keys 2026-07-03 11:57:02 +02:00
Andras Bacsai 9b060958aa fix(ray): remove Ray debug hooks from runtime (#10847) 2026-07-03 11:40:20 +02:00
Andras Bacsai b5ba40b049 Merge remote-tracking branch 'origin/next' into fix/docker-compose-domains-api-9211 2026-07-03 10:26:19 +02:00
Andras Bacsai 67693acce7 fix(parser): preserve file volume state (#10843) 2026-07-03 10:14:39 +02:00
Andras Bacsai 062ad57740 fix(security): enforce team access on mutable actions
Authorize cloud provider token access, audit sensitive operations, and
standardize public IDs across deployment and resource flows.
2026-06-04 11:03:06 +02:00
Tobias Thiele 8b12aae266 fix(parsers): remove unused $svc variable in dockercompose domain loop
Use array_keys() instead of key-value iteration since only the service
name keys are needed for comparison. Addresses CodeRabbit review feedback.
2026-04-02 09:25:59 +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
Tobias Thiele 7f46b2ed71 ✨ Populate docker_compose_domains for dockercompose apps
Add logic to populate docker_compose_domains in applicationParser
for dockercompose build packs, ensuring proper domain handling
for KEY-based SERVICE_FQDN variables.
2026-03-30 14:59:20 +02:00
Andras Bacsai 1da1f32f0e refactor: use forceCreate() for internal model creation
Replace create() with forceCreate() across internal model creation operations to bypass mass assignment protection. This is appropriate for internal code that constructs complete model state without user input.

Add InternalModelCreationMassAssignmentTest to ensure internal model creation behavior is properly tested. Optimize imports by using shortened Livewire attribute references and removing unused imports.
2026-03-30 13:04:11 +02:00
Andras Bacsai 6a14a12a58 fix(parsers): preserve ${VAR} references in compose instead of resolving to DB values
Do not replace self-referencing environment variables (e.g., DATABASE_URL: ${DATABASE_URL})
with saved DB values in the compose environment section. Keeping the reference intact allows
Docker Compose to resolve from .env at deploy time, preventing stale values from overriding
user updates that haven't been re-parsed.

Fixes #9136
2026-03-24 21:52:36 +01:00
Andras Bacsai add16853a8 feat(preview): add configurable PR suffix toggle for volumes
Add `is_preview_suffix_enabled` flag to `local_file_volumes` and
`local_persistent_volumes` tables, allowing per-volume control over
whether a `-pr-N` suffix is appended during preview deployments.

Defaults to `true` to preserve existing behavior. Users can disable
it for volumes containing shared config or repository scripts that
should not be isolated per PR.
2026-03-16 14:54:22 +01:00