diff --git a/app/Console/Commands/Generate/Services.php b/app/Console/Commands/Generate/Services.php index 42f9360bb..e316fc391 100644 --- a/app/Console/Commands/Generate/Services.php +++ b/app/Console/Commands/Generate/Services.php @@ -88,6 +88,14 @@ private function processFile(string $file): false|array $payload['envs'] = base64_encode($envFileContent); } + if (str($data->get('amd_only'))->toBoolean()) { + $payload['amd_only'] = true; + } + + if (str($data->get('arm_only'))->toBoolean()) { + $payload['arm_only'] = true; + } + return $payload; } @@ -160,6 +168,14 @@ private function processFileWithFqdn(string $file): false|array $payload['envs'] = base64_encode($modifiedEnvContent); } + if (str($data->get('amd_only'))->toBoolean()) { + $payload['amd_only'] = true; + } + + if (str($data->get('arm_only'))->toBoolean()) { + $payload['arm_only'] = true; + } + return $payload; } @@ -229,6 +245,14 @@ private function processFileWithFqdnRaw(string $file): false|array $payload['envs'] = $modifiedEnvContent; } + if (str($data->get('amd_only'))->toBoolean()) { + $payload['amd_only'] = true; + } + + if (str($data->get('arm_only'))->toBoolean()) { + $payload['arm_only'] = true; + } + return $payload; } } diff --git a/app/Http/Controllers/Api/ApplicationsController.php b/app/Http/Controllers/Api/ApplicationsController.php index 5dad95fa2..8da4f82df 100644 --- a/app/Http/Controllers/Api/ApplicationsController.php +++ b/app/Http/Controllers/Api/ApplicationsController.php @@ -217,7 +217,7 @@ public function applications(Request $request) type: 'object', properties: [ 'name' => ['type' => 'string', 'description' => 'The service name as defined in docker-compose.'], - 'domain' => ['type' => 'string', 'description' => 'Comma-separated list of URLs (e.g. "http://app.coolify.io,https://app2.coolify.io")'], + 'domain' => ['type' => 'string', 'description' => 'Comma-separated list of URLs (e.g. "https://app.coolify.io,https://app2.coolify.io")'], ], ), ], @@ -383,7 +383,7 @@ public function create_public_application(Request $request) type: 'object', properties: [ 'name' => ['type' => 'string', 'description' => 'The service name as defined in docker-compose.'], - 'domain' => ['type' => 'string', 'description' => 'Comma-separated list of URLs (e.g. "http://app.coolify.io,https://app2.coolify.io")'], + 'domain' => ['type' => 'string', 'description' => 'Comma-separated list of URLs (e.g. "https://app.coolify.io,https://app2.coolify.io")'], ], ), ], @@ -549,7 +549,7 @@ public function create_private_gh_app_application(Request $request) type: 'object', properties: [ 'name' => ['type' => 'string', 'description' => 'The service name as defined in docker-compose.'], - 'domain' => ['type' => 'string', 'description' => 'Comma-separated list of URLs (e.g. "http://app.coolify.io,https://app2.coolify.io")'], + 'domain' => ['type' => 'string', 'description' => 'Comma-separated list of URLs (e.g. "https://app.coolify.io,https://app2.coolify.io")'], ], ), ], @@ -2397,7 +2397,7 @@ public function delete_by_uuid(Request $request) type: 'object', properties: [ 'name' => ['type' => 'string', 'description' => 'The service name as defined in docker-compose.'], - 'domain' => ['type' => 'string', 'description' => 'Comma-separated list of URLs (e.g. "http://app.coolify.io,https://app2.coolify.io")'], + 'domain' => ['type' => 'string', 'description' => 'Comma-separated list of URLs (e.g. "https://app.coolify.io,https://app2.coolify.io")'], ], ), ], diff --git a/app/Http/Controllers/Api/ServicesController.php b/app/Http/Controllers/Api/ServicesController.php index fbf4b9e56..23ba30998 100644 --- a/app/Http/Controllers/Api/ServicesController.php +++ b/app/Http/Controllers/Api/ServicesController.php @@ -221,7 +221,7 @@ public function services(Request $request) type: 'object', properties: [ 'name' => ['type' => 'string', 'description' => 'The service name as defined in docker-compose.'], - 'url' => ['type' => 'string', 'description' => 'Comma-separated list of URLs (e.g. "http://app.coolify.io,https://app2.coolify.io").'], + 'url' => ['type' => 'string', 'description' => 'Comma-separated list of URLs (e.g. "https://app.coolify.io,https://app2.coolify.io").'], ], ), ], @@ -843,7 +843,7 @@ public function delete_by_uuid(Request $request) type: 'object', properties: [ 'name' => ['type' => 'string', 'description' => 'The service name as defined in docker-compose.'], - 'url' => ['type' => 'string', 'description' => 'Comma-separated list of URLs (e.g. "http://app.coolify.io,https://app2.coolify.io").'], + 'url' => ['type' => 'string', 'description' => 'Comma-separated list of URLs (e.g. "https://app.coolify.io,https://app2.coolify.io").'], ], ), ], diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index 40f917601..f328274ac 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -3198,7 +3198,7 @@ private function generate_healthcheck_commands() $scheme = $this->sanitizeHealthCheckValue($this->application->health_check_scheme, '/^https?$/', 'http'); $host = $this->sanitizeHealthCheckValue($this->application->health_check_host, '/^[a-zA-Z0-9.\-_]+$/', 'localhost'); $path = $this->application->health_check_path - ? $this->sanitizeHealthCheckValue($this->application->health_check_path, '#^[a-zA-Z0-9/\-_.~%]+$#', '/') + ? $this->sanitizeHealthCheckValue($this->application->health_check_path, '#^[a-zA-Z0-9/\-_.~%,;]+$#', '/') : null; $url = escapeshellarg("{$scheme}://{$host}:{$health_check_port}".($path ?? '/')); diff --git a/app/Livewire/GlobalSearch.php b/app/Livewire/GlobalSearch.php index 154748b47..df2adf22b 100644 --- a/app/Livewire/GlobalSearch.php +++ b/app/Livewire/GlobalSearch.php @@ -1496,7 +1496,10 @@ public function getServicesProperty() 'category' => 'Services', 'resourceType' => 'service', 'logo' => data_get($service, 'logo'), - ]); + ] + array_filter([ + 'amd_only' => data_get($service, 'amd_only') ? true : null, + 'arm_only' => data_get($service, 'arm_only') ? true : null, + ])); } $cachedServices = $items->toArray(); diff --git a/app/Livewire/Project/Shared/HealthChecks.php b/app/Livewire/Project/Shared/HealthChecks.php index 0d5d71b45..195e7fd92 100644 --- a/app/Livewire/Project/Shared/HealthChecks.php +++ b/app/Livewire/Project/Shared/HealthChecks.php @@ -34,7 +34,7 @@ class HealthChecks extends Component #[Validate(['nullable', 'integer', 'min:1', 'max:65535'])] public ?string $healthCheckPort = null; - #[Validate(['required', 'string', 'regex:#^[a-zA-Z0-9/\-_.~%]+$#'])] + #[Validate(['required', 'string', 'regex:#^[a-zA-Z0-9/\-_.~%,;]+$#'])] public string $healthCheckPath; #[Validate(['integer'])] @@ -62,7 +62,7 @@ class HealthChecks extends Component 'healthCheckEnabled' => 'boolean', 'healthCheckType' => 'string|in:http,cmd', 'healthCheckCommand' => ['nullable', 'string', 'max:1000', 'regex:/^[a-zA-Z0-9 \-_.\/:=@,+]+$/'], - 'healthCheckPath' => ['required', 'string', 'regex:#^[a-zA-Z0-9/\-_.~%]+$#'], + 'healthCheckPath' => ['required', 'string', 'regex:#^[a-zA-Z0-9/\-_.~%,;]+$#'], 'healthCheckPort' => 'nullable|integer|min:1|max:65535', 'healthCheckHost' => ['required', 'string', 'regex:/^[a-zA-Z0-9.\-_]+$/'], 'healthCheckMethod' => 'required|string|in:GET,HEAD,POST,OPTIONS', diff --git a/app/Models/Team.php b/app/Models/Team.php index d5d564444..0fbcfe0c6 100644 --- a/app/Models/Team.php +++ b/app/Models/Team.php @@ -233,6 +233,9 @@ public function subscriptionEnded() 'is_reachable' => false, ]); ServerReachabilityChanged::dispatch($server); + $server->unreachable_count = 3; + $server->unreachable_notification_sent = true; + $server->save(); } } @@ -344,5 +347,4 @@ public function webhookNotificationSettings() { return $this->hasOne(WebhookNotificationSettings::class); } - } diff --git a/app/Support/ValidationPatterns.php b/app/Support/ValidationPatterns.php index 15d0f19e0..88121384f 100644 --- a/app/Support/ValidationPatterns.php +++ b/app/Support/ValidationPatterns.php @@ -203,10 +203,24 @@ public static function volumeNameMessages(string $field = 'name'): array } /** - * Pattern for port mappings (e.g. 3000:3000, 8080:80, 8000-8010:8000-8010) - * Each entry requires host:container format, where each side can be a number or a range (number-number) + * Pattern for port mappings with optional IP binding and protocol suffix on either side. + * Format: [ip:]port[:ip:port] where IP is IPv4 or [IPv6], port can be a range, protocol suffix optional. + * Examples: 8080:80, 127.0.0.1:8080:80, [::1]::80/udp, 127.0.0.1:8080:80/tcp */ - public const PORT_MAPPINGS_PATTERN = '/^(\d+(-\d+)?:\d+(-\d+)?)(,\d+(-\d+)?:\d+(-\d+)?)*$/'; + public const PORT_MAPPINGS_PATTERN = '/^ + (?:(?:\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|\[[\da-fA-F:]+\]):)? # optional IP + (?:\d+(?:-\d+)?(?:\/(?:tcp|udp|sctp))?)? # optional host port + : + (?:(?:\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|\[[\da-fA-F:]+\]):)? # optional IP + \d+(?:-\d+)?(?:\/(?:tcp|udp|sctp))? # container port + (?:, + (?:(?:\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|\[[\da-fA-F:]+\]):)? + (?:\d+(?:-\d+)?(?:\/(?:tcp|udp|sctp))?)? + : + (?:(?:\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|\[[\da-fA-F:]+\]):)? + \d+(?:-\d+)?(?:\/(?:tcp|udp|sctp))? + )* + $/x'; /** * Get validation rules for container name fields @@ -230,7 +244,7 @@ public static function portMappingRules(): array public static function portMappingMessages(string $field = 'portsMappings'): array { return [ - "{$field}.regex" => 'Port mappings must be a comma-separated list of port pairs or ranges (e.g. 3000:3000,8080:80,8000-8010:8000-8010).', + "{$field}.regex" => 'Port mappings must be a comma-separated list of port pairs or ranges with optional IP and protocol (e.g. 3000:3000, 8080:80/udp, 127.0.0.1:8080:80, [::1]::80).', ]; } diff --git a/bootstrap/helpers/api.php b/bootstrap/helpers/api.php index c10ed6158..8088e6b99 100644 --- a/bootstrap/helpers/api.php +++ b/bootstrap/helpers/api.php @@ -106,7 +106,7 @@ function sharedDataApplications() 'health_check_enabled' => 'boolean', 'health_check_type' => 'string|in:http,cmd', 'health_check_command' => ['nullable', 'string', 'max:1000', 'regex:/^[a-zA-Z0-9 \-_.\/:=@,+]+$/'], - 'health_check_path' => ['string', 'regex:#^[a-zA-Z0-9/\-_.~%]+$#'], + 'health_check_path' => ['string', 'regex:#^[a-zA-Z0-9/\-_.~%,;]+$#'], 'health_check_port' => 'integer|nullable|min:1|max:65535', 'health_check_host' => ['string', 'regex:/^[a-zA-Z0-9.\-_]+$/'], 'health_check_method' => 'string|in:GET,HEAD,POST,OPTIONS', diff --git a/bootstrap/helpers/shared.php b/bootstrap/helpers/shared.php index cd773f6a9..011c149c9 100644 --- a/bootstrap/helpers/shared.php +++ b/bootstrap/helpers/shared.php @@ -3660,13 +3660,21 @@ function convertGitUrl(string $gitRepository, string $deploymentType, GithubApp| } } - preg_match('/(?<=:)\d+(?=\/)/', $gitRepository, $matches); + $normalizedRepository = $repository; - if (count($matches) === 1) { - $providerInfo['port'] = $matches[0]; - $gitHost = str($gitRepository)->before(':'); - $gitRepo = str($gitRepository)->after('/'); - $repository = "$gitHost:$gitRepo"; + if (str($normalizedRepository)->contains('://')) { + $parsedRepository = parse_url($normalizedRepository); + + if ($parsedRepository !== false && array_key_exists('port', $parsedRepository)) { + $providerInfo['port'] = (string) $parsedRepository['port']; + } + } else { + preg_match('/^(?[^:]+):(?\d+)\/(?.+)$/', $normalizedRepository, $matches); + + if (! empty($matches['port'])) { + $providerInfo['port'] = $matches['port']; + $repository = "{$matches['host']}:{$matches['path']}"; + } } return [ diff --git a/composer.lock b/composer.lock index 3884eac06..2f27235f5 100644 --- a/composer.lock +++ b/composer.lock @@ -72,7 +72,6 @@ "type": "zip", "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/67b6b6210af47319c74c5666388d71bc1bc58276", "reference": "67b6b6210af47319c74c5666388d71bc1bc58276", - "shasum": "" }, "require": { @@ -157,7 +156,6 @@ "source": "https://github.com/aws/aws-sdk-php/tree/3.374.2" }, "time": "2026-03-27T18:05:55+00:00" - }, { "name": "bacon/bacon-qr-code", @@ -5158,16 +5156,16 @@ }, { "name": "phpseclib/phpseclib", - "version": "3.0.50", + "version": "3.0.51", "source": { "type": "git", "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "aa6ad8321ed103dc3624fb600a25b66ebf78ec7b" + "reference": "d59c94077f9c9915abb51ddb52ce85188ece1748" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/aa6ad8321ed103dc3624fb600a25b66ebf78ec7b", - "reference": "aa6ad8321ed103dc3624fb600a25b66ebf78ec7b", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/d59c94077f9c9915abb51ddb52ce85188ece1748", + "reference": "d59c94077f9c9915abb51ddb52ce85188ece1748", "shasum": "" }, "require": { @@ -5248,7 +5246,7 @@ ], "support": { "issues": "https://github.com/phpseclib/phpseclib/issues", - "source": "https://github.com/phpseclib/phpseclib/tree/3.0.50" + "source": "https://github.com/phpseclib/phpseclib/tree/3.0.51" }, "funding": [ { @@ -5264,7 +5262,7 @@ "type": "tidelift" } ], - "time": "2026-03-19T02:57:58+00:00" + "time": "2026-04-10T01:33:53+00:00" }, { "name": "phpstan/phpdoc-parser", diff --git a/config/constants.php b/config/constants.php index adaeb7fb2..743b5e38c 100644 --- a/config/constants.php +++ b/config/constants.php @@ -2,9 +2,9 @@ return [ 'coolify' => [ - 'version' => '4.0.0-beta.473', + 'version' => '4.0.0-beta.474', 'helper_version' => '1.0.13', - 'realtime_version' => '1.0.12', + 'realtime_version' => '1.0.13', 'self_hosted' => env('SELF_HOSTED', true), 'autoupdate' => env('AUTOUPDATE'), 'base_config_path' => env('BASE_CONFIG_PATH', '/data/coolify'), diff --git a/database/migrations/2025_12_24_133707_add_predefined_server_variables_to_existing_servers.php b/database/migrations/2025_12_24_133707_add_predefined_server_variables_to_existing_servers.php index c67987e67..77fcf96a1 100644 --- a/database/migrations/2025_12_24_133707_add_predefined_server_variables_to_existing_servers.php +++ b/database/migrations/2025_12_24_133707_add_predefined_server_variables_to_existing_servers.php @@ -11,7 +11,7 @@ */ public function up(): void { - Server::query()->chunk(100, function ($servers) { + Server::query()->whereHas('team')->chunk(100, function ($servers) { foreach ($servers as $server) { $existingKeys = SharedEnvironmentVariable::where('type', 'server') ->where('server_id', $server->id) diff --git a/database/migrations/2026_03_23_101720_add_uuid_to_local_persistent_volumes_table.php b/database/migrations/2026_03_23_101720_add_uuid_to_local_persistent_volumes_table.php index 6b4fb690d..ab279c592 100644 --- a/database/migrations/2026_03_23_101720_add_uuid_to_local_persistent_volumes_table.php +++ b/database/migrations/2026_03_23_101720_add_uuid_to_local_persistent_volumes_table.php @@ -10,14 +10,15 @@ { public function up(): void { - Schema::table('local_persistent_volumes', function (Blueprint $table) { - $table->string('uuid')->nullable()->after('id'); - }); + if (! Schema::hasColumn('local_persistent_volumes', 'uuid')) { + Schema::table('local_persistent_volumes', function (Blueprint $table) { + $table->string('uuid')->nullable()->after('id'); + }); + } DB::table('local_persistent_volumes') ->whereNull('uuid') - ->orderBy('id') - ->chunk(1000, function ($volumes) { + ->chunkById(1000, function ($volumes) { foreach ($volumes as $volume) { DB::table('local_persistent_volumes') ->where('id', $volume->id) diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 3af443c83..f608fe3cb 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -112,6 +112,7 @@ services: volumes: - /var/run/docker.sock:/var/run/docker.sock - dev_coolify_data:/data/coolify + - dev_coolify_data:/var/lib/docker/volumes/coolify_dev_coolify_data/_data - dev_backups_data:/data/coolify/backups - dev_postgres_data:/data/coolify/_volumes/database - dev_redis_data:/data/coolify/_volumes/redis diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index e6d2bce54..901aeb833 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -60,7 +60,7 @@ services: retries: 10 timeout: 2s soketi: - image: '${REGISTRY_URL:-ghcr.io}/coollabsio/coolify-realtime:1.0.12' + image: '${REGISTRY_URL:-ghcr.io}/coollabsio/coolify-realtime:1.0.13' ports: - "${SOKETI_PORT:-6001}:6001" - "6002:6002" diff --git a/docker-compose.windows.yml b/docker-compose.windows.yml index 00734fb0e..998d35974 100644 --- a/docker-compose.windows.yml +++ b/docker-compose.windows.yml @@ -96,7 +96,7 @@ services: retries: 10 timeout: 2s soketi: - image: 'ghcr.io/coollabsio/coolify-realtime:1.0.12' + image: 'ghcr.io/coollabsio/coolify-realtime:1.0.13' pull_policy: always container_name: coolify-realtime restart: always diff --git a/docker/coolify-realtime/package-lock.json b/docker/coolify-realtime/package-lock.json index 1c49ff930..174077562 100644 --- a/docker/coolify-realtime/package-lock.json +++ b/docker/coolify-realtime/package-lock.json @@ -7,7 +7,7 @@ "dependencies": { "@xterm/addon-fit": "0.11.0", "@xterm/xterm": "6.0.0", - "axios": "1.13.6", + "axios": "1.15.0", "cookie": "1.1.1", "dotenv": "17.3.1", "node-pty": "1.1.0", @@ -36,14 +36,14 @@ "license": "MIT" }, "node_modules/axios": { - "version": "1.13.6", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.6.tgz", - "integrity": "sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.15.0.tgz", + "integrity": "sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q==", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.11", "form-data": "^4.0.5", - "proxy-from-env": "^1.1.0" + "proxy-from-env": "^2.1.0" } }, "node_modules/call-bind-apply-helpers": { @@ -344,10 +344,13 @@ } }, "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "license": "MIT" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } }, "node_modules/ws": { "version": "8.19.0", diff --git a/docker/coolify-realtime/package.json b/docker/coolify-realtime/package.json index ebb7122c8..30bfbcef7 100644 --- a/docker/coolify-realtime/package.json +++ b/docker/coolify-realtime/package.json @@ -5,7 +5,7 @@ "@xterm/addon-fit": "0.11.0", "@xterm/xterm": "6.0.0", "cookie": "1.1.1", - "axios": "1.13.6", + "axios": "1.15.0", "dotenv": "17.3.1", "node-pty": "1.1.0", "ws": "8.19.0" diff --git a/openapi.json b/openapi.json index b3e7cb8b8..1acb4d73b 100644 --- a/openapi.json +++ b/openapi.json @@ -362,7 +362,7 @@ }, "domain": { "type": "string", - "description": "Comma-separated list of URLs (e.g. \"http:\/\/app.coolify.io,https:\/\/app2.coolify.io\")" + "description": "Comma-separated list of URLs (e.g. \"https:\/\/app.coolify.io,https:\/\/app2.coolify.io\")" } }, "type": "object" @@ -813,7 +813,7 @@ }, "domain": { "type": "string", - "description": "Comma-separated list of URLs (e.g. \"http:\/\/app.coolify.io,https:\/\/app2.coolify.io\")" + "description": "Comma-separated list of URLs (e.g. \"https:\/\/app.coolify.io,https:\/\/app2.coolify.io\")" } }, "type": "object" @@ -1264,7 +1264,7 @@ }, "domain": { "type": "string", - "description": "Comma-separated list of URLs (e.g. \"http:\/\/app.coolify.io,https:\/\/app2.coolify.io\")" + "description": "Comma-separated list of URLs (e.g. \"https:\/\/app.coolify.io,https:\/\/app2.coolify.io\")" } }, "type": "object" @@ -2697,7 +2697,7 @@ }, "domain": { "type": "string", - "description": "Comma-separated list of URLs (e.g. \"http:\/\/app.coolify.io,https:\/\/app2.coolify.io\")" + "description": "Comma-separated list of URLs (e.g. \"https:\/\/app.coolify.io,https:\/\/app2.coolify.io\")" } }, "type": "object" @@ -10816,7 +10816,7 @@ }, "url": { "type": "string", - "description": "Comma-separated list of URLs (e.g. \"http:\/\/app.coolify.io,https:\/\/app2.coolify.io\")." + "description": "Comma-separated list of URLs (e.g. \"https:\/\/app.coolify.io,https:\/\/app2.coolify.io\")." } }, "type": "object" @@ -11147,7 +11147,7 @@ }, "url": { "type": "string", - "description": "Comma-separated list of URLs (e.g. \"http:\/\/app.coolify.io,https:\/\/app2.coolify.io\")." + "description": "Comma-separated list of URLs (e.g. \"https:\/\/app.coolify.io,https:\/\/app2.coolify.io\")." } }, "type": "object" diff --git a/openapi.yaml b/openapi.yaml index 740301d5a..6b16e494e 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -258,7 +258,7 @@ paths: docker_compose_domains: type: array description: 'Array of URLs to be applied to containers of a dockercompose application.' - items: { properties: { name: { type: string, description: 'The service name as defined in docker-compose.' }, domain: { type: string, description: 'Comma-separated list of URLs (e.g. "http://app.coolify.io,https://app2.coolify.io")' } }, type: object } + items: { properties: { name: { type: string, description: 'The service name as defined in docker-compose.' }, domain: { type: string, description: 'Comma-separated list of URLs (e.g. "https://app.coolify.io,https://app2.coolify.io")' } }, type: object } watch_paths: type: string description: 'The watch paths.' @@ -546,7 +546,7 @@ paths: docker_compose_domains: type: array description: 'Array of URLs to be applied to containers of a dockercompose application.' - items: { properties: { name: { type: string, description: 'The service name as defined in docker-compose.' }, domain: { type: string, description: 'Comma-separated list of URLs (e.g. "http://app.coolify.io,https://app2.coolify.io")' } }, type: object } + items: { properties: { name: { type: string, description: 'The service name as defined in docker-compose.' }, domain: { type: string, description: 'Comma-separated list of URLs (e.g. "https://app.coolify.io,https://app2.coolify.io")' } }, type: object } watch_paths: type: string description: 'The watch paths.' @@ -834,7 +834,7 @@ paths: docker_compose_domains: type: array description: 'Array of URLs to be applied to containers of a dockercompose application.' - items: { properties: { name: { type: string, description: 'The service name as defined in docker-compose.' }, domain: { type: string, description: 'Comma-separated list of URLs (e.g. "http://app.coolify.io,https://app2.coolify.io")' } }, type: object } + items: { properties: { name: { type: string, description: 'The service name as defined in docker-compose.' }, domain: { type: string, description: 'Comma-separated list of URLs (e.g. "https://app.coolify.io,https://app2.coolify.io")' } }, type: object } watch_paths: type: string description: 'The watch paths.' @@ -1735,7 +1735,7 @@ paths: docker_compose_domains: type: array description: 'Array of URLs to be applied to containers of a dockercompose application.' - items: { properties: { name: { type: string, description: 'The service name as defined in docker-compose.' }, domain: { type: string, description: 'Comma-separated list of URLs (e.g. "http://app.coolify.io,https://app2.coolify.io")' } }, type: object } + items: { properties: { name: { type: string, description: 'The service name as defined in docker-compose.' }, domain: { type: string, description: 'Comma-separated list of URLs (e.g. "https://app.coolify.io,https://app2.coolify.io")' } }, type: object } watch_paths: type: string description: 'The watch paths.' @@ -6886,7 +6886,7 @@ paths: urls: type: array description: 'Array of URLs to be applied to containers of a service.' - items: { properties: { name: { type: string, description: 'The service name as defined in docker-compose.' }, url: { type: string, description: 'Comma-separated list of URLs (e.g. "http://app.coolify.io,https://app2.coolify.io").' } }, type: object } + items: { properties: { name: { type: string, description: 'The service name as defined in docker-compose.' }, url: { type: string, description: 'Comma-separated list of URLs (e.g. "https://app.coolify.io,https://app2.coolify.io").' } }, type: object } force_domain_override: type: boolean default: false @@ -7075,7 +7075,7 @@ paths: urls: type: array description: 'Array of URLs to be applied to containers of a service.' - items: { properties: { name: { type: string, description: 'The service name as defined in docker-compose.' }, url: { type: string, description: 'Comma-separated list of URLs (e.g. "http://app.coolify.io,https://app2.coolify.io").' } }, type: object } + items: { properties: { name: { type: string, description: 'The service name as defined in docker-compose.' }, url: { type: string, description: 'Comma-separated list of URLs (e.g. "https://app.coolify.io,https://app2.coolify.io").' } }, type: object } force_domain_override: type: boolean default: false diff --git a/other/nightly/docker-compose.prod.yml b/other/nightly/docker-compose.prod.yml index e6d2bce54..901aeb833 100644 --- a/other/nightly/docker-compose.prod.yml +++ b/other/nightly/docker-compose.prod.yml @@ -60,7 +60,7 @@ services: retries: 10 timeout: 2s soketi: - image: '${REGISTRY_URL:-ghcr.io}/coollabsio/coolify-realtime:1.0.12' + image: '${REGISTRY_URL:-ghcr.io}/coollabsio/coolify-realtime:1.0.13' ports: - "${SOKETI_PORT:-6001}:6001" - "6002:6002" diff --git a/other/nightly/docker-compose.windows.yml b/other/nightly/docker-compose.windows.yml index 00734fb0e..998d35974 100644 --- a/other/nightly/docker-compose.windows.yml +++ b/other/nightly/docker-compose.windows.yml @@ -96,7 +96,7 @@ services: retries: 10 timeout: 2s soketi: - image: 'ghcr.io/coollabsio/coolify-realtime:1.0.12' + image: 'ghcr.io/coollabsio/coolify-realtime:1.0.13' pull_policy: always container_name: coolify-realtime restart: always diff --git a/other/nightly/install.sh b/other/nightly/install.sh index 09406118c..4a91f7b1b 100755 --- a/other/nightly/install.sh +++ b/other/nightly/install.sh @@ -539,6 +539,15 @@ install_docker_manually() { echo "Docker installed successfully." fi } + +install_docker_from_rhel_repo() { + echo " - Installing Docker from the RHEL repository for Rocky Linux..." + rm -f /etc/yum.repos.d/docker-ce.repo /etc/yum.repos.d/docker-ce-staging.repo + dnf config-manager --add-repo https://download.docker.com/linux/rhel/docker-ce.repo + dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin + systemctl --now enable docker +} + log_section "Step 3/9: Checking Docker installation" echo "3/9 Checking Docker installation..." if ! [ -x "$(command -v docker)" ]; then @@ -579,6 +588,13 @@ if ! [ -x "$(command -v docker)" ]; then exit 1 fi ;; + "rocky") + install_docker_from_rhel_repo + if ! [ -x "$(command -v docker)" ]; then + echo " - Docker could not be installed automatically. Please visit https://docs.docker.com/engine/install/ and install Docker manually to continue." + exit 1 + fi + ;; "almalinux" | "tencentos") dnf config-manager --add-repo=https://download.docker.com/linux/centos/docker-ce.repo >/dev/null 2>&1 dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin >/dev/null 2>&1 diff --git a/other/nightly/versions.json b/other/nightly/versions.json index b8d6efae2..27d911c67 100644 --- a/other/nightly/versions.json +++ b/other/nightly/versions.json @@ -1,7 +1,7 @@ { "coolify": { "v4": { - "version": "4.0.0-beta.473" + "version": "4.0.0-beta.474" }, "nightly": { "version": "4.0.0" @@ -10,7 +10,7 @@ "version": "1.0.13" }, "realtime": { - "version": "1.0.12" + "version": "1.0.13" }, "sentinel": { "version": "0.0.21" diff --git a/package-lock.json b/package-lock.json index 0af80f950..1fcd7cc1e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,7 @@ "devDependencies": { "@tailwindcss/postcss": "4.1.18", "@vitejs/plugin-vue": "6.0.3", - "axios": "1.13.2", + "axios": "1.15.0", "laravel-echo": "2.2.7", "laravel-vite-plugin": "2.0.1", "postcss": "8.5.6", @@ -1474,15 +1474,15 @@ "license": "MIT" }, "node_modules/axios": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz", - "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.15.0.tgz", + "integrity": "sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q==", "dev": true, "license": "MIT", "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.4", - "proxy-from-env": "^1.1.0" + "follow-redirects": "^1.15.11", + "form-data": "^4.0.5", + "proxy-from-env": "^2.1.0" } }, "node_modules/call-bind-apply-helpers": { @@ -2501,11 +2501,14 @@ } }, "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=10" + } }, "node_modules/pusher-js": { "version": "8.4.0", diff --git a/package.json b/package.json index 661b13e4c..3afefa833 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "devDependencies": { "@tailwindcss/postcss": "4.1.18", "@vitejs/plugin-vue": "6.0.3", - "axios": "1.13.2", + "axios": "1.15.0", "laravel-echo": "2.2.7", "laravel-vite-plugin": "2.0.1", "postcss": "8.5.6", diff --git a/resources/views/components/service-database/sidebar.blade.php b/resources/views/components/service-database/sidebar.blade.php index 9d31fc634..dc9a30552 100644 --- a/resources/views/components/service-database/sidebar.blade.php +++ b/resources/views/components/service-database/sidebar.blade.php @@ -16,6 +16,8 @@ class="{{ request()->routeIs('project.service.configuration') ? 'menu-item-activ General + Advanced @if ($serviceDatabase?->isBackupSolutionAvailable() || $serviceDatabase?->is_migrated) Backups diff --git a/resources/views/livewire/global-search.blade.php b/resources/views/livewire/global-search.blade.php index 955533f28..4ece32b52 100644 --- a/resources/views/livewire/global-search.blade.php +++ b/resources/views/livewire/global-search.blade.php @@ -835,6 +835,20 @@ class="h-5 w-5 text-warning-600 dark:text-warning-400"
+ +
Advanced configuration for your application.
-

General

- @if ($application->git_based()) - - - - @endif +

Build

+

Container

+ + @if ($isConsistentContainerNameEnabled === false) +
+ + Save + + @endif + + @if ($application->git_based()) +

Deployment

+ + + + +

Git

+ + + + @endif + + @if ($application->build_pack === 'dockercompose') +

Docker Compose

+ + + @endif + +

Proxy

@if ($application->settings->is_container_label_readonly_enabled) @endif - @if ($application->build_pack === 'dockercompose') -

Docker Compose

- - @endif -

Container Names

- - @if ($isConsistentContainerNameEnabled === false) -
- - Save - - @endif - @if ($application->build_pack === 'dockercompose') -

Network

- - @endif +

Logs

- @if ($application->git_based()) -

Git

- - - - @endif
diff --git a/resources/views/livewire/project/application/general.blade.php b/resources/views/livewire/project/application/general.blade.php index fedbe7f18..e395a8a7d 100644 --- a/resources/views/livewire/project/application/general.blade.php +++ b/resources/views/livewire/project/application/general.blade.php @@ -61,7 +61,7 @@ @if (!isDatabaseImage(data_get($service, 'image')))
@@ -115,7 +115,7 @@ x-bind:disabled="!canUpdate" /> @else @can('update', $application) Generate Domain diff --git a/resources/views/livewire/project/new/select.blade.php b/resources/views/livewire/project/new/select.blade.php index 8f97c22d8..04c09ede1 100644 --- a/resources/views/livewire/project/new/select.blade.php +++ b/resources/views/livewire/project/new/select.blade.php @@ -173,6 +173,34 @@ class="w-full h-full p-2 transition-all duration-200 dark:bg-white/10 bg-black/1 + +