Merge branch 'next' into feat-db-ssl
This commit is contained in:
159
CHANGELOG.md
159
CHANGELOG.md
@@ -2,6 +2,145 @@
|
|||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
## [unreleased]
|
||||||
|
|
||||||
|
### 🚀 Features
|
||||||
|
|
||||||
|
- *(billing)* Add Stripe past due subscription status tracking
|
||||||
|
- *(ui)* Add past due subscription warning banner
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
- *(billing)* Restrict Stripe subscription status update to 'active' only
|
||||||
|
|
||||||
|
### 💼 Other
|
||||||
|
|
||||||
|
- Bump Coolify to 4.0.0-beta.398
|
||||||
|
|
||||||
|
### 🚜 Refactor
|
||||||
|
|
||||||
|
- *(billing)* Enhance Stripe subscription status handling and notifications
|
||||||
|
|
||||||
|
## [4.0.0-beta.397] - 2025-02-28
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
- *(billing)* Handle 'past_due' subscription status in Stripe processing
|
||||||
|
- *(revert)* Label parsing
|
||||||
|
- *(helpers)* Initialize command variable in parseCommandFromMagicEnvVariable
|
||||||
|
|
||||||
|
### 📚 Documentation
|
||||||
|
|
||||||
|
- Update changelog
|
||||||
|
|
||||||
|
## [4.0.0-beta.396] - 2025-02-28
|
||||||
|
|
||||||
|
### 🚀 Features
|
||||||
|
|
||||||
|
- *(ui)* Add wire:key to two-step confirmation settings
|
||||||
|
- *(database)* Add index to scheduled task executions for improved query performance
|
||||||
|
- *(database)* Add index to scheduled database backup executions
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
- *(core)* Production dockerfile
|
||||||
|
- *(ui)* Update storage configuration guidance link
|
||||||
|
- *(ui)* Set default SMTP encryption to starttls
|
||||||
|
- *(notifications)* Correct environment URL path in application notifications
|
||||||
|
- *(config)* Update default PostgreSQL host to coolify-db instead of postgres
|
||||||
|
- *(docker)* Improve Docker compose file validation process
|
||||||
|
- *(ui)* Restrict service retrieval to current team
|
||||||
|
- *(core)* Only validate custom compose files
|
||||||
|
- *(mail)* Set default mailer to array when not specified
|
||||||
|
- *(ui)* Correct redirect routes after task deletion
|
||||||
|
- *(core)* Adding a new server should not try to make the default docker network
|
||||||
|
- *(core)* Clean up unnecessary files during application image build
|
||||||
|
- *(core)* Improve label generation and merging for applications and services
|
||||||
|
|
||||||
|
### 💼 Other
|
||||||
|
|
||||||
|
- Bump all dependencies (#5216)
|
||||||
|
|
||||||
|
### 🚜 Refactor
|
||||||
|
|
||||||
|
- *(ui)* Simplify file storage modal confirmations
|
||||||
|
- *(notifications)* Improve transactional email settings handling
|
||||||
|
- *(scheduled-tasks)* Improve scheduled task creation and management
|
||||||
|
|
||||||
|
### 📚 Documentation
|
||||||
|
|
||||||
|
- Update changelog
|
||||||
|
- Update changelog
|
||||||
|
|
||||||
|
### ⚙️ Miscellaneous Tasks
|
||||||
|
|
||||||
|
- Bump helper and realtime version
|
||||||
|
|
||||||
|
## [4.0.0-beta.395] - 2025-02-22
|
||||||
|
|
||||||
|
### 📚 Documentation
|
||||||
|
|
||||||
|
- Update changelog
|
||||||
|
|
||||||
|
## [4.0.0-beta.394] - 2025-02-17
|
||||||
|
|
||||||
|
### 📚 Documentation
|
||||||
|
|
||||||
|
- Update changelog
|
||||||
|
|
||||||
|
## [4.0.0-beta.393] - 2025-02-15
|
||||||
|
|
||||||
|
### 📚 Documentation
|
||||||
|
|
||||||
|
- Update changelog
|
||||||
|
|
||||||
|
## [4.0.0-beta.392] - 2025-02-13
|
||||||
|
|
||||||
|
### 🚀 Features
|
||||||
|
|
||||||
|
- *(ui)* Add top padding to pricing plans view
|
||||||
|
- *(core)* Add error logging and cron parsing to docker/server schedules
|
||||||
|
- *(core)* Prevent using servers with existing resources as build servers
|
||||||
|
- *(ui)* Add textarea switching option in service compose editor
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
- Pull latest image from registry when using build server
|
||||||
|
- *(deployment)* Improve server selection for deployment cancellation
|
||||||
|
- *(deployment)* Improve log line rendering and formatting
|
||||||
|
- *(s3-storage)* Optimize team admin notification query
|
||||||
|
- *(core)* Improve connection testing with dynamic disk configuration for s3 backups
|
||||||
|
- *(core)* Update service status refresh event handling
|
||||||
|
- *(ui)* Adjust polling intervals for database and service status checks
|
||||||
|
- *(service)* Update Fider service template healthcheck command
|
||||||
|
- *(core)* Improve server selection error handling in Docker component
|
||||||
|
- *(core)* Add server functionality check before dispatching container status
|
||||||
|
- *(ui)* Disable sticky scroll in Monaco editor
|
||||||
|
- *(ui)* Add literal and multiline env support to services.
|
||||||
|
- *(services)* Owncloud docs link
|
||||||
|
- *(template)* Remove db-migration step from `infisical.yaml` (#5209)
|
||||||
|
- *(service)* Penpot (#5047)
|
||||||
|
|
||||||
|
### 🚜 Refactor
|
||||||
|
|
||||||
|
- Use pull flag on docker compose up
|
||||||
|
|
||||||
|
### 📚 Documentation
|
||||||
|
|
||||||
|
- Update changelog
|
||||||
|
- Update changelog
|
||||||
|
|
||||||
|
### ⚙️ Miscellaneous Tasks
|
||||||
|
|
||||||
|
- Rollback Coolify version to 4.0.0-beta.392
|
||||||
|
- Bump Coolify version to 4.0.0-beta.393
|
||||||
|
- Bump Coolify version to 4.0.0-beta.394
|
||||||
|
- Bump Coolify version to 4.0.0-beta.395
|
||||||
|
- Bump Coolify version to 4.0.0-beta.396
|
||||||
|
- *(services)* Update zipline to use new Database env var. (#5210)
|
||||||
|
- *(service)* Upgrade authentik service
|
||||||
|
- *(service)* Remove unused env from zipline
|
||||||
|
|
||||||
## [4.0.0-beta.391] - 2025-02-04
|
## [4.0.0-beta.391] - 2025-02-04
|
||||||
|
|
||||||
### 🚀 Features
|
### 🚀 Features
|
||||||
@@ -13,6 +152,11 @@ All notable changes to this project will be documented in this file.
|
|||||||
- *(changelog)* Add git cliff for automatic changelog generation
|
- *(changelog)* Add git cliff for automatic changelog generation
|
||||||
- *(workflows)* Improve changelog generation and workflows
|
- *(workflows)* Improve changelog generation and workflows
|
||||||
- *(ui)* Add periodic status checking for services
|
- *(ui)* Add periodic status checking for services
|
||||||
|
- *(deployment)* Ensure private key is stored in filesystem before deployment
|
||||||
|
- *(slack)* Show message title in notification previews (#5063)
|
||||||
|
- *(i18n)* Add Arabic translations (#4991)
|
||||||
|
- *(i18n)* Add French translations (#4992)
|
||||||
|
- *(services)* Update `service-templates.json`
|
||||||
|
|
||||||
### 🐛 Bug Fixes
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
@@ -22,6 +166,17 @@ All notable changes to this project will be documented in this file.
|
|||||||
- *(ui)* Simplify service templates loading logic
|
- *(ui)* Simplify service templates loading logic
|
||||||
- *(ui)* Align title and add button vertically in various views
|
- *(ui)* Align title and add button vertically in various views
|
||||||
- Handle pullrequest:updated for reliable preview deployments
|
- Handle pullrequest:updated for reliable preview deployments
|
||||||
|
- *(ui)* Fix typo on team page (#5105)
|
||||||
|
- Cal.com documentation link give 404 (#5070)
|
||||||
|
- *(slack)* Notification settings URL in `HighDiskUsage` message (#5071)
|
||||||
|
- *(ui)* Correct typo in Storage delete dialog (#5061)
|
||||||
|
- *(lang)* Add missing italian translations (#5057)
|
||||||
|
- *(service)* Improve duplicati.yaml (#4971)
|
||||||
|
- *(service)* Links in homepage service (#5002)
|
||||||
|
- *(service)* Added SMTP credentials to getoutline yaml template file (#5011)
|
||||||
|
- *(service)* Added `KEY` Variable to Beszel Template (#5021)
|
||||||
|
- *(cloudflare-tunnels)* Dead links to docs (#5104)
|
||||||
|
- System-wide GitHub apps (#5114)
|
||||||
|
|
||||||
### 🚜 Refactor
|
### 🚜 Refactor
|
||||||
|
|
||||||
@@ -31,12 +186,16 @@ All notable changes to this project will be documented in this file.
|
|||||||
|
|
||||||
- *(services)* Reword nitropage url and slogan
|
- *(services)* Reword nitropage url and slogan
|
||||||
- *(readme)* Add Convex to special sponsors section
|
- *(readme)* Add Convex to special sponsors section
|
||||||
|
- Update changelog
|
||||||
|
|
||||||
### ⚙️ Miscellaneous Tasks
|
### ⚙️ Miscellaneous Tasks
|
||||||
|
|
||||||
- *(config)* Increase default PHP memory limit to 256M
|
- *(config)* Increase default PHP memory limit to 256M
|
||||||
- Add openapi response
|
- Add openapi response
|
||||||
- *(workflows)* Make naming more clear and remove unused code
|
- *(workflows)* Make naming more clear and remove unused code
|
||||||
|
- Bump Coolify version to 4.0.0-beta.392/393
|
||||||
|
- *(ci)* Update changelog generation workflow to target 'next' branch
|
||||||
|
- *(ci)* Update changelog generation workflow to target main branch
|
||||||
|
|
||||||
## [4.0.0-beta.390] - 2025-01-28
|
## [4.0.0-beta.390] - 2025-01-28
|
||||||
|
|
||||||
|
@@ -22,74 +22,27 @@ class StartDatabaseProxy
|
|||||||
|
|
||||||
public function handle(StandaloneRedis|StandalonePostgresql|StandaloneMongodb|StandaloneMysql|StandaloneMariadb|StandaloneKeydb|StandaloneDragonfly|StandaloneClickhouse|ServiceDatabase $database)
|
public function handle(StandaloneRedis|StandalonePostgresql|StandaloneMongodb|StandaloneMysql|StandaloneMariadb|StandaloneKeydb|StandaloneDragonfly|StandaloneClickhouse|ServiceDatabase $database)
|
||||||
{
|
{
|
||||||
$internalPort = null;
|
$databaseType = $database->database_type;
|
||||||
$type = $database->getMorphClass();
|
|
||||||
$network = data_get($database, 'destination.network');
|
$network = data_get($database, 'destination.network');
|
||||||
$server = data_get($database, 'destination.server');
|
$server = data_get($database, 'destination.server');
|
||||||
$containerName = data_get($database, 'uuid');
|
$containerName = data_get($database, 'uuid');
|
||||||
$proxyContainerName = "{$database->uuid}-proxy";
|
$proxyContainerName = "{$database->uuid}-proxy";
|
||||||
if ($database->getMorphClass() === \App\Models\ServiceDatabase::class) {
|
if ($database->getMorphClass() === \App\Models\ServiceDatabase::class) {
|
||||||
$databaseType = $database->databaseType();
|
$databaseType = $database->databaseType();
|
||||||
// $connectPredefined = data_get($database, 'service.connect_to_docker_network');
|
|
||||||
$network = $database->service->uuid;
|
$network = $database->service->uuid;
|
||||||
$server = data_get($database, 'service.destination.server');
|
$server = data_get($database, 'service.destination.server');
|
||||||
$proxyContainerName = "{$database->service->uuid}-proxy";
|
$proxyContainerName = "{$database->service->uuid}-proxy";
|
||||||
switch ($databaseType) {
|
$containerName = "{$database->name}-{$database->service->uuid}";
|
||||||
case 'standalone-mariadb':
|
|
||||||
$type = \App\Models\StandaloneMariadb::class;
|
|
||||||
$containerName = "mariadb-{$database->service->uuid}";
|
|
||||||
break;
|
|
||||||
case 'standalone-mongodb':
|
|
||||||
$type = \App\Models\StandaloneMongodb::class;
|
|
||||||
$containerName = "mongodb-{$database->service->uuid}";
|
|
||||||
break;
|
|
||||||
case 'standalone-mysql':
|
|
||||||
$type = \App\Models\StandaloneMysql::class;
|
|
||||||
$containerName = "mysql-{$database->service->uuid}";
|
|
||||||
break;
|
|
||||||
case 'standalone-postgresql':
|
|
||||||
$type = \App\Models\StandalonePostgresql::class;
|
|
||||||
$containerName = "postgresql-{$database->service->uuid}";
|
|
||||||
break;
|
|
||||||
case 'standalone-redis':
|
|
||||||
$type = \App\Models\StandaloneRedis::class;
|
|
||||||
$containerName = "redis-{$database->service->uuid}";
|
|
||||||
break;
|
|
||||||
case 'standalone-keydb':
|
|
||||||
$type = \App\Models\StandaloneKeydb::class;
|
|
||||||
$containerName = "keydb-{$database->service->uuid}";
|
|
||||||
break;
|
|
||||||
case 'standalone-dragonfly':
|
|
||||||
$type = \App\Models\StandaloneDragonfly::class;
|
|
||||||
$containerName = "dragonfly-{$database->service->uuid}";
|
|
||||||
break;
|
|
||||||
case 'standalone-clickhouse':
|
|
||||||
$type = \App\Models\StandaloneClickhouse::class;
|
|
||||||
$containerName = "clickhouse-{$database->service->uuid}";
|
|
||||||
break;
|
|
||||||
case 'standalone-supabase/postgres':
|
|
||||||
$type = \App\Models\StandalonePostgresql::class;
|
|
||||||
$containerName = "supabase-db-{$database->service->uuid}";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($type === \App\Models\StandaloneRedis::class) {
|
|
||||||
$internalPort = 6379;
|
|
||||||
} elseif ($type === \App\Models\StandalonePostgresql::class) {
|
|
||||||
$internalPort = 5432;
|
|
||||||
} elseif ($type === \App\Models\StandaloneMongodb::class) {
|
|
||||||
$internalPort = 27017;
|
|
||||||
} elseif ($type === \App\Models\StandaloneMysql::class) {
|
|
||||||
$internalPort = 3306;
|
|
||||||
} elseif ($type === \App\Models\StandaloneMariadb::class) {
|
|
||||||
$internalPort = 3306;
|
|
||||||
} elseif ($type === \App\Models\StandaloneKeydb::class) {
|
|
||||||
$internalPort = 6379;
|
|
||||||
} elseif ($type === \App\Models\StandaloneDragonfly::class) {
|
|
||||||
$internalPort = 6379;
|
|
||||||
} elseif ($type === \App\Models\StandaloneClickhouse::class) {
|
|
||||||
$internalPort = 9000;
|
|
||||||
}
|
}
|
||||||
|
$internalPort = match ($databaseType) {
|
||||||
|
'standalone-mariadb', 'standalone-mysql' => 3306,
|
||||||
|
'standalone-postgresql', 'standalone-supabase/postgres' => 5432,
|
||||||
|
'standalone-redis', 'standalone-keydb', 'standalone-dragonfly' => 6379,
|
||||||
|
'standalone-clickhouse' => 9000,
|
||||||
|
'standalone-mongodb' => 27017,
|
||||||
|
default => throw new \Exception("Unsupported database type: $databaseType"),
|
||||||
|
};
|
||||||
|
|
||||||
$configuration_dir = database_proxy_dir($database->uuid);
|
$configuration_dir = database_proxy_dir($database->uuid);
|
||||||
$nginxconf = <<<EOF
|
$nginxconf = <<<EOF
|
||||||
user nginx;
|
user nginx;
|
||||||
|
@@ -208,7 +208,6 @@ class GetContainersStatus
|
|||||||
$foundServices[] = "$service->id-$service->name";
|
$foundServices[] = "$service->id-$service->name";
|
||||||
$statusFromDb = $service->status;
|
$statusFromDb = $service->status;
|
||||||
if ($statusFromDb !== $containerStatus) {
|
if ($statusFromDb !== $containerStatus) {
|
||||||
// ray('Updating status: ' . $containerStatus);
|
|
||||||
$service->update(['status' => $containerStatus]);
|
$service->update(['status' => $containerStatus]);
|
||||||
} else {
|
} else {
|
||||||
$service->update(['last_online_at' => now()]);
|
$service->update(['last_online_at' => now()]);
|
||||||
|
@@ -50,7 +50,7 @@ class CloudCleanupSubscriptions extends Command
|
|||||||
} else {
|
} else {
|
||||||
$subscription = $stripe->subscriptions->retrieve(data_get($team, 'subscription.stripe_subscription_id'), []);
|
$subscription = $stripe->subscriptions->retrieve(data_get($team, 'subscription.stripe_subscription_id'), []);
|
||||||
$status = data_get($subscription, 'status');
|
$status = data_get($subscription, 'status');
|
||||||
if ($status === 'active' || $status === 'past_due') {
|
if ($status === 'active') {
|
||||||
$team->subscription->update([
|
$team->subscription->update([
|
||||||
'stripe_invoice_paid' => true,
|
'stripe_invoice_paid' => true,
|
||||||
'stripe_trial_already_ended' => false,
|
'stripe_trial_already_ended' => false,
|
||||||
|
@@ -18,6 +18,7 @@ use App\Models\Service;
|
|||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Validation\Rule;
|
use Illuminate\Validation\Rule;
|
||||||
use OpenApi\Attributes as OA;
|
use OpenApi\Attributes as OA;
|
||||||
|
use Spatie\Url\Url;
|
||||||
use Symfony\Component\Yaml\Yaml;
|
use Symfony\Component\Yaml\Yaml;
|
||||||
use Visus\Cuid2\Cuid2;
|
use Visus\Cuid2\Cuid2;
|
||||||
|
|
||||||
@@ -811,6 +812,11 @@ class ApplicationsController extends Controller
|
|||||||
'docker_compose_raw' => 'string|nullable',
|
'docker_compose_raw' => 'string|nullable',
|
||||||
'docker_compose_domains' => 'array|nullable',
|
'docker_compose_domains' => 'array|nullable',
|
||||||
];
|
];
|
||||||
|
// ports_exposes is not required for dockercompose
|
||||||
|
if ($request->build_pack === 'dockercompose') {
|
||||||
|
$validationRules['ports_exposes'] = 'string';
|
||||||
|
$request->offsetSet('ports_exposes', '80');
|
||||||
|
}
|
||||||
$validationRules = array_merge(sharedDataApplications(), $validationRules);
|
$validationRules = array_merge(sharedDataApplications(), $validationRules);
|
||||||
$validator = customApiValidator($request->all(), $validationRules);
|
$validator = customApiValidator($request->all(), $validationRules);
|
||||||
if ($validator->fails()) {
|
if ($validator->fails()) {
|
||||||
@@ -822,10 +828,6 @@ class ApplicationsController extends Controller
|
|||||||
if (! $request->has('name')) {
|
if (! $request->has('name')) {
|
||||||
$request->offsetSet('name', generate_application_name($request->git_repository, $request->git_branch));
|
$request->offsetSet('name', generate_application_name($request->git_repository, $request->git_branch));
|
||||||
}
|
}
|
||||||
if ($request->build_pack === 'dockercompose') {
|
|
||||||
$request->offsetSet('ports_exposes', '80');
|
|
||||||
}
|
|
||||||
|
|
||||||
$return = $this->validateDataApplications($request, $server);
|
$return = $this->validateDataApplications($request, $server);
|
||||||
if ($return instanceof \Illuminate\Http\JsonResponse) {
|
if ($return instanceof \Illuminate\Http\JsonResponse) {
|
||||||
return $return;
|
return $return;
|
||||||
@@ -848,7 +850,13 @@ class ApplicationsController extends Controller
|
|||||||
if ($dockerComposeDomainsJson->count() > 0) {
|
if ($dockerComposeDomainsJson->count() > 0) {
|
||||||
$application->docker_compose_domains = $dockerComposeDomainsJson;
|
$application->docker_compose_domains = $dockerComposeDomainsJson;
|
||||||
}
|
}
|
||||||
|
$repository_url_parsed = Url::fromString($request->git_repository);
|
||||||
|
$git_host = $repository_url_parsed->getHost();
|
||||||
|
if ($git_host === 'github.com') {
|
||||||
|
$application->source_type = GithubApp::class;
|
||||||
|
$application->source_id = GithubApp::find(0)->id;
|
||||||
|
}
|
||||||
|
$application->git_repository = $repository_url_parsed->getSegment(1).'/'.$repository_url_parsed->getSegment(2);
|
||||||
$application->fqdn = $fqdn;
|
$application->fqdn = $fqdn;
|
||||||
$application->destination_id = $destination->id;
|
$application->destination_id = $destination->id;
|
||||||
$application->destination_type = $destination->getMorphClass();
|
$application->destination_type = $destination->getMorphClass();
|
||||||
@@ -1291,11 +1299,6 @@ class ApplicationsController extends Controller
|
|||||||
$dockerCompose = base64_decode($request->docker_compose_raw);
|
$dockerCompose = base64_decode($request->docker_compose_raw);
|
||||||
$dockerComposeRaw = Yaml::dump(Yaml::parse($dockerCompose), 10, 2, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK);
|
$dockerComposeRaw = Yaml::dump(Yaml::parse($dockerCompose), 10, 2, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK);
|
||||||
|
|
||||||
// $isValid = validateComposeFile($dockerComposeRaw, $server_id);
|
|
||||||
// if ($isValid !== 'OK') {
|
|
||||||
// return $this->dispatch('error', "Invalid docker-compose file.\n$isValid");
|
|
||||||
// }
|
|
||||||
|
|
||||||
$service = new Service;
|
$service = new Service;
|
||||||
removeUnnecessaryFieldsFromRequest($request);
|
removeUnnecessaryFieldsFromRequest($request);
|
||||||
$service->fill($request->all());
|
$service->fill($request->all());
|
||||||
|
@@ -54,7 +54,7 @@ class Controller extends BaseController
|
|||||||
'email' => Str::lower($arrayOfRequest['email']),
|
'email' => Str::lower($arrayOfRequest['email']),
|
||||||
]);
|
]);
|
||||||
$type = set_transanctional_email_settings();
|
$type = set_transanctional_email_settings();
|
||||||
if (! $type) {
|
if (blank($type)) {
|
||||||
return response()->json(['message' => 'Transactional emails are not active'], 400);
|
return response()->json(['message' => 'Transactional emails are not active'], 400);
|
||||||
}
|
}
|
||||||
$request->validate([Fortify::email() => 'required|email']);
|
$request->validate([Fortify::email() => 'required|email']);
|
||||||
|
@@ -49,7 +49,7 @@ class Bitbucket extends Controller
|
|||||||
$full_name = data_get($payload, 'repository.full_name');
|
$full_name = data_get($payload, 'repository.full_name');
|
||||||
$commit = data_get($payload, 'push.changes.0.new.target.hash');
|
$commit = data_get($payload, 'push.changes.0.new.target.hash');
|
||||||
|
|
||||||
if (!$branch) {
|
if (! $branch) {
|
||||||
return response([
|
return response([
|
||||||
'status' => 'failed',
|
'status' => 'failed',
|
||||||
'message' => 'Nothing to do. No branch found in the request.',
|
'message' => 'Nothing to do. No branch found in the request.',
|
||||||
|
@@ -152,7 +152,7 @@ class Gitea extends Controller
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($x_gitea_event === 'pull_request') {
|
if ($x_gitea_event === 'pull_request') {
|
||||||
if ($action === 'opened' || $action === 'synchronize' || $action === 'reopened') {
|
if ($action === 'opened' || $action === 'synchronized' || $action === 'reopened') {
|
||||||
if ($application->isPRDeployable()) {
|
if ($application->isPRDeployable()) {
|
||||||
$deployment_uuid = new Cuid2;
|
$deployment_uuid = new Cuid2;
|
||||||
$found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
|
$found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
|
||||||
@@ -202,7 +202,6 @@ class Gitea extends Controller
|
|||||||
if ($found) {
|
if ($found) {
|
||||||
$found->delete();
|
$found->delete();
|
||||||
$container_name = generateApplicationContainerName($application, $pull_request_id);
|
$container_name = generateApplicationContainerName($application, $pull_request_id);
|
||||||
// ray('Stopping container: ' . $container_name);
|
|
||||||
instant_remote_process(["docker rm -f $container_name"], $application->destination->server);
|
instant_remote_process(["docker rm -f $container_name"], $application->destination->server);
|
||||||
$return_payloads->push([
|
$return_payloads->push([
|
||||||
'application' => $application->name,
|
'application' => $application->name,
|
||||||
|
@@ -208,7 +208,6 @@ class Github extends Controller
|
|||||||
if ($found) {
|
if ($found) {
|
||||||
$found->delete();
|
$found->delete();
|
||||||
$container_name = generateApplicationContainerName($application, $pull_request_id);
|
$container_name = generateApplicationContainerName($application, $pull_request_id);
|
||||||
// ray('Stopping container: ' . $container_name);
|
|
||||||
instant_remote_process(["docker rm -f $container_name"], $application->destination->server);
|
instant_remote_process(["docker rm -f $container_name"], $application->destination->server);
|
||||||
$return_payloads->push([
|
$return_payloads->push([
|
||||||
'application' => $application->name,
|
'application' => $application->name,
|
||||||
|
@@ -227,7 +227,6 @@ class Gitlab extends Controller
|
|||||||
if ($found) {
|
if ($found) {
|
||||||
$found->delete();
|
$found->delete();
|
||||||
$container_name = generateApplicationContainerName($application, $pull_request_id);
|
$container_name = generateApplicationContainerName($application, $pull_request_id);
|
||||||
// ray('Stopping container: ' . $container_name);
|
|
||||||
instant_remote_process(["docker rm -f $container_name"], $application->destination->server);
|
instant_remote_process(["docker rm -f $container_name"], $application->destination->server);
|
||||||
$return_payloads->push([
|
$return_payloads->push([
|
||||||
'application' => $application->name,
|
'application' => $application->name,
|
||||||
|
@@ -19,6 +19,7 @@ use App\Notifications\Application\DeploymentFailed;
|
|||||||
use App\Notifications\Application\DeploymentSuccess;
|
use App\Notifications\Application\DeploymentSuccess;
|
||||||
use App\Traits\ExecuteRemoteCommand;
|
use App\Traits\ExecuteRemoteCommand;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
|
use Exception;
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
@@ -1207,7 +1208,6 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
if ($this->application->custom_healthcheck_found) {
|
if ($this->application->custom_healthcheck_found) {
|
||||||
$this->application_deployment_queue->addLogEntry('Custom healthcheck found, skipping default healthcheck.');
|
$this->application_deployment_queue->addLogEntry('Custom healthcheck found, skipping default healthcheck.');
|
||||||
}
|
}
|
||||||
// ray('New container name: ', $this->container_name);
|
|
||||||
if ($this->container_name) {
|
if ($this->container_name) {
|
||||||
$counter = 1;
|
$counter = 1;
|
||||||
$this->application_deployment_queue->addLogEntry('Waiting for healthcheck to pass on the new container.');
|
$this->application_deployment_queue->addLogEntry('Waiting for healthcheck to pass on the new container.');
|
||||||
@@ -1410,7 +1410,6 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// ray('Deploying to additional destination: ', $server->name);
|
|
||||||
$deployment_uuid = new Cuid2;
|
$deployment_uuid = new Cuid2;
|
||||||
queue_application_deployment(
|
queue_application_deployment(
|
||||||
deployment_uuid: $deployment_uuid,
|
deployment_uuid: $deployment_uuid,
|
||||||
@@ -2023,6 +2022,8 @@ LABEL coolify.deploymentId={$this->deployment_uuid}
|
|||||||
COPY . .
|
COPY . .
|
||||||
RUN rm -f /usr/share/nginx/html/nginx.conf
|
RUN rm -f /usr/share/nginx/html/nginx.conf
|
||||||
RUN rm -f /usr/share/nginx/html/Dockerfile
|
RUN rm -f /usr/share/nginx/html/Dockerfile
|
||||||
|
RUN rm -f /usr/share/nginx/html/docker-compose.yaml
|
||||||
|
RUN rm -f /usr/share/nginx/html/.env
|
||||||
COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
||||||
if (str($this->application->custom_nginx_configuration)->isNotEmpty()) {
|
if (str($this->application->custom_nginx_configuration)->isNotEmpty()) {
|
||||||
$nginx_config = base64_encode($this->application->custom_nginx_configuration);
|
$nginx_config = base64_encode($this->application->custom_nginx_configuration);
|
||||||
|
@@ -73,19 +73,21 @@ class StripeProcessJob implements ShouldQueue
|
|||||||
}
|
}
|
||||||
$subscription = Subscription::where('team_id', $teamId)->first();
|
$subscription = Subscription::where('team_id', $teamId)->first();
|
||||||
if ($subscription) {
|
if ($subscription) {
|
||||||
send_internal_notification('Old subscription activated for team: '.$teamId);
|
// send_internal_notification('Old subscription activated for team: '.$teamId);
|
||||||
$subscription->update([
|
$subscription->update([
|
||||||
'stripe_subscription_id' => $subscriptionId,
|
'stripe_subscription_id' => $subscriptionId,
|
||||||
'stripe_customer_id' => $customerId,
|
'stripe_customer_id' => $customerId,
|
||||||
'stripe_invoice_paid' => true,
|
'stripe_invoice_paid' => true,
|
||||||
|
'stripe_past_due' => false,
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
send_internal_notification('New subscription for team: '.$teamId);
|
// send_internal_notification('New subscription for team: '.$teamId);
|
||||||
Subscription::create([
|
Subscription::create([
|
||||||
'team_id' => $teamId,
|
'team_id' => $teamId,
|
||||||
'stripe_subscription_id' => $subscriptionId,
|
'stripe_subscription_id' => $subscriptionId,
|
||||||
'stripe_customer_id' => $customerId,
|
'stripe_customer_id' => $customerId,
|
||||||
'stripe_invoice_paid' => true,
|
'stripe_invoice_paid' => true,
|
||||||
|
'stripe_past_due' => false,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -100,6 +102,7 @@ class StripeProcessJob implements ShouldQueue
|
|||||||
if ($subscription) {
|
if ($subscription) {
|
||||||
$subscription->update([
|
$subscription->update([
|
||||||
'stripe_invoice_paid' => true,
|
'stripe_invoice_paid' => true,
|
||||||
|
'stripe_past_due' => false,
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
throw new \RuntimeException("No subscription found for customer: {$customerId}");
|
throw new \RuntimeException("No subscription found for customer: {$customerId}");
|
||||||
@@ -119,9 +122,7 @@ class StripeProcessJob implements ShouldQueue
|
|||||||
}
|
}
|
||||||
if (! $subscription->stripe_invoice_paid) {
|
if (! $subscription->stripe_invoice_paid) {
|
||||||
SubscriptionInvoiceFailedJob::dispatch($team);
|
SubscriptionInvoiceFailedJob::dispatch($team);
|
||||||
send_internal_notification('Invoice payment failed: '.$customerId);
|
// send_internal_notification('Invoice payment failed: '.$customerId);
|
||||||
} else {
|
|
||||||
send_internal_notification('Invoice payment failed but already paid: '.$customerId);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'payment_intent.payment_failed':
|
case 'payment_intent.payment_failed':
|
||||||
@@ -136,7 +137,7 @@ class StripeProcessJob implements ShouldQueue
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
send_internal_notification('Subscription payment failed for customer: '.$customerId);
|
// send_internal_notification('Subscription payment failed for customer: '.$customerId);
|
||||||
break;
|
break;
|
||||||
case 'customer.subscription.created':
|
case 'customer.subscription.created':
|
||||||
$customerId = data_get($data, 'customer');
|
$customerId = data_get($data, 'customer');
|
||||||
@@ -158,7 +159,7 @@ class StripeProcessJob implements ShouldQueue
|
|||||||
}
|
}
|
||||||
$subscription = Subscription::where('team_id', $teamId)->first();
|
$subscription = Subscription::where('team_id', $teamId)->first();
|
||||||
if ($subscription) {
|
if ($subscription) {
|
||||||
send_internal_notification("Subscription already exists for team: {$teamId}");
|
// send_internal_notification("Subscription already exists for team: {$teamId}");
|
||||||
throw new \RuntimeException("Subscription already exists for team: {$teamId}");
|
throw new \RuntimeException("Subscription already exists for team: {$teamId}");
|
||||||
} else {
|
} else {
|
||||||
Subscription::create([
|
Subscription::create([
|
||||||
@@ -182,7 +183,7 @@ class StripeProcessJob implements ShouldQueue
|
|||||||
$subscription = Subscription::where('stripe_customer_id', $customerId)->first();
|
$subscription = Subscription::where('stripe_customer_id', $customerId)->first();
|
||||||
if (! $subscription) {
|
if (! $subscription) {
|
||||||
if ($status === 'incomplete_expired') {
|
if ($status === 'incomplete_expired') {
|
||||||
send_internal_notification('Subscription incomplete expired');
|
// send_internal_notification('Subscription incomplete expired');
|
||||||
throw new \RuntimeException('Subscription incomplete expired');
|
throw new \RuntimeException('Subscription incomplete expired');
|
||||||
}
|
}
|
||||||
if ($teamId) {
|
if ($teamId) {
|
||||||
@@ -224,9 +225,33 @@ class StripeProcessJob implements ShouldQueue
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ($status === 'past_due') {
|
||||||
|
if ($subscription->stripe_subscription_id === $subscriptionId) {
|
||||||
|
$subscription->update([
|
||||||
|
'stripe_past_due' => true,
|
||||||
|
]);
|
||||||
|
send_internal_notification('Past Due: '.$customerId.'Subscription ID: '.$subscriptionId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($status === 'unpaid') {
|
||||||
|
if ($subscription->stripe_subscription_id === $subscriptionId) {
|
||||||
|
$subscription->update([
|
||||||
|
'stripe_invoice_paid' => false,
|
||||||
|
]);
|
||||||
|
send_internal_notification('Unpaid: '.$customerId.'Subscription ID: '.$subscriptionId);
|
||||||
|
}
|
||||||
|
$team = data_get($subscription, 'team');
|
||||||
|
if ($team) {
|
||||||
|
$team->subscriptionEnded();
|
||||||
|
} else {
|
||||||
|
send_internal_notification('Subscription unpaid but no team found in Coolify for customer: '.$customerId);
|
||||||
|
throw new \RuntimeException("No team found in Coolify for customer: {$customerId}");
|
||||||
|
}
|
||||||
|
}
|
||||||
if ($status === 'active') {
|
if ($status === 'active') {
|
||||||
if ($subscription->stripe_subscription_id === $subscriptionId) {
|
if ($subscription->stripe_subscription_id === $subscriptionId) {
|
||||||
$subscription->update([
|
$subscription->update([
|
||||||
|
'stripe_past_due' => false,
|
||||||
'stripe_invoice_paid' => true,
|
'stripe_invoice_paid' => true,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
@@ -36,7 +36,7 @@ class Help extends Component
|
|||||||
$type = set_transanctional_email_settings($settings);
|
$type = set_transanctional_email_settings($settings);
|
||||||
|
|
||||||
// Sending feedback through Cloud API
|
// Sending feedback through Cloud API
|
||||||
if ($type === false) {
|
if (blank($type)) {
|
||||||
$url = 'https://app.coolify.io/api/feedback';
|
$url = 'https://app.coolify.io/api/feedback';
|
||||||
Http::post($url, [
|
Http::post($url, [
|
||||||
'content' => 'User: `'.auth()->user()?->email.'` with subject: `'.$this->subject.'` has the following problem: `'.$this->description.'`',
|
'content' => 'User: `'.auth()->user()?->email.'` with subject: `'.$this->subject.'` has the following problem: `'.$this->description.'`',
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Livewire;
|
namespace App\Livewire;
|
||||||
|
|
||||||
//use Livewire\Component;
|
// use Livewire\Component;
|
||||||
use Illuminate\View\Component;
|
use Illuminate\View\Component;
|
||||||
use Visus\Cuid2\Cuid2;
|
use Visus\Cuid2\Cuid2;
|
||||||
|
|
||||||
|
@@ -22,6 +22,7 @@ class Configuration extends Component
|
|||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
$this->currentRoute = request()->route()->getName();
|
$this->currentRoute = request()->route()->getName();
|
||||||
|
|
||||||
$project = currentTeam()
|
$project = currentTeam()
|
||||||
->projects()
|
->projects()
|
||||||
->select('id', 'uuid', 'team_id')
|
->select('id', 'uuid', 'team_id')
|
||||||
@@ -39,6 +40,9 @@ class Configuration extends Component
|
|||||||
$this->project = $project;
|
$this->project = $project;
|
||||||
$this->environment = $environment;
|
$this->environment = $environment;
|
||||||
$this->application = $application;
|
$this->application = $application;
|
||||||
|
if ($this->application->build_pack === 'dockercompose' && $this->currentRoute === 'project.application.healthcheck') {
|
||||||
|
return redirect()->route('project.application.configuration', ['project_uuid' => $project->uuid, 'environment_uuid' => $environment->uuid, 'application_uuid' => $application->uuid]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render()
|
public function render()
|
||||||
|
@@ -43,8 +43,10 @@ class Heading extends Component
|
|||||||
|
|
||||||
public function check_status($showNotification = false)
|
public function check_status($showNotification = false)
|
||||||
{
|
{
|
||||||
GetContainersStatus::run($this->database->destination->server);
|
if ($this->database->destination->server->isFunctional()) {
|
||||||
$this->database->refresh();
|
GetContainersStatus::dispatch($this->database->destination->server);
|
||||||
|
}
|
||||||
|
|
||||||
if ($showNotification) {
|
if ($showNotification) {
|
||||||
$this->dispatch('success', 'Database status updated.');
|
$this->dispatch('success', 'Database status updated.');
|
||||||
}
|
}
|
||||||
|
@@ -52,12 +52,6 @@ class DockerCompose extends Component
|
|||||||
'dockerComposeRaw' => 'required',
|
'dockerComposeRaw' => 'required',
|
||||||
]);
|
]);
|
||||||
$this->dockerComposeRaw = Yaml::dump(Yaml::parse($this->dockerComposeRaw), 10, 2, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK);
|
$this->dockerComposeRaw = Yaml::dump(Yaml::parse($this->dockerComposeRaw), 10, 2, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK);
|
||||||
|
|
||||||
$isValid = validateComposeFile($this->dockerComposeRaw, $server_id);
|
|
||||||
if ($isValid !== 'OK') {
|
|
||||||
return $this->dispatch('error', "Invalid docker-compose file.\n$isValid");
|
|
||||||
}
|
|
||||||
|
|
||||||
$project = Project::where('uuid', $this->parameters['project_uuid'])->first();
|
$project = Project::where('uuid', $this->parameters['project_uuid'])->first();
|
||||||
$environment = $project->load(['environments'])->environments->where('uuid', $this->parameters['environment_uuid'])->first();
|
$environment = $project->load(['environments'])->environments->where('uuid', $this->parameters['environment_uuid'])->first();
|
||||||
|
|
||||||
|
@@ -92,7 +92,9 @@ class Configuration extends Component
|
|||||||
public function check_status()
|
public function check_status()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
GetContainersStatus::run($this->service->server);
|
if ($this->service->server->isFunctional()) {
|
||||||
|
GetContainersStatus::dispatch($this->service->server);
|
||||||
|
}
|
||||||
$this->service->applications->each(function ($application) {
|
$this->service->applications->each(function ($application) {
|
||||||
$application->refresh();
|
$application->refresh();
|
||||||
});
|
});
|
||||||
|
@@ -4,7 +4,10 @@ namespace App\Livewire\Project\Service;
|
|||||||
|
|
||||||
use App\Actions\Database\StartDatabaseProxy;
|
use App\Actions\Database\StartDatabaseProxy;
|
||||||
use App\Actions\Database\StopDatabaseProxy;
|
use App\Actions\Database\StopDatabaseProxy;
|
||||||
|
use App\Models\InstanceSettings;
|
||||||
use App\Models\ServiceDatabase;
|
use App\Models\ServiceDatabase;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class Database extends Component
|
class Database extends Component
|
||||||
@@ -15,6 +18,8 @@ class Database extends Component
|
|||||||
|
|
||||||
public $fileStorages;
|
public $fileStorages;
|
||||||
|
|
||||||
|
public $parameters;
|
||||||
|
|
||||||
protected $listeners = ['refreshFileStorages'];
|
protected $listeners = ['refreshFileStorages'];
|
||||||
|
|
||||||
protected $rules = [
|
protected $rules = [
|
||||||
@@ -34,12 +39,33 @@ class Database extends Component
|
|||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
|
$this->parameters = get_route_parameters();
|
||||||
if ($this->database->is_public) {
|
if ($this->database->is_public) {
|
||||||
$this->db_url_public = $this->database->getServiceDatabaseUrl();
|
$this->db_url_public = $this->database->getServiceDatabaseUrl();
|
||||||
}
|
}
|
||||||
$this->refreshFileStorages();
|
$this->refreshFileStorages();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function delete($password)
|
||||||
|
{
|
||||||
|
if (! data_get(InstanceSettings::get(), 'disable_two_step_confirmation')) {
|
||||||
|
if (! Hash::check($password, Auth::user()->password)) {
|
||||||
|
$this->addError('password', 'The provided password is incorrect.');
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->database->delete();
|
||||||
|
$this->dispatch('success', 'Database deleted.');
|
||||||
|
|
||||||
|
return redirect()->route('project.service.configuration', $this->parameters);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function instantSaveExclude()
|
public function instantSaveExclude()
|
||||||
{
|
{
|
||||||
$this->submit();
|
$this->submit();
|
||||||
|
@@ -31,12 +31,22 @@ class EditCompose extends Component
|
|||||||
|
|
||||||
public function refreshEnvs()
|
public function refreshEnvs()
|
||||||
{
|
{
|
||||||
$this->service = Service::find($this->serviceId);
|
$this->service = Service::ownedByCurrentTeam()->find($this->serviceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
$this->service = Service::find($this->serviceId);
|
$this->service = Service::ownedByCurrentTeam()->find($this->serviceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function validateCompose()
|
||||||
|
{
|
||||||
|
$isValid = validateComposeFile($this->service->docker_compose_raw, $this->service->server_id);
|
||||||
|
if ($isValid !== 'OK') {
|
||||||
|
$this->dispatch('error', "Invalid docker-compose file.\n$isValid");
|
||||||
|
} else {
|
||||||
|
$this->dispatch('success', 'Docker compose is valid.');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function saveEditedCompose()
|
public function saveEditedCompose()
|
||||||
|
@@ -43,12 +43,11 @@ class EditDomain extends Component
|
|||||||
updateCompose($this->application);
|
updateCompose($this->application);
|
||||||
if (str($this->application->fqdn)->contains(',')) {
|
if (str($this->application->fqdn)->contains(',')) {
|
||||||
$this->dispatch('warning', 'Some services do not support multiple domains, which can lead to problems and is NOT RECOMMENDED.<br><br>Only use multiple domains if you know what you are doing.');
|
$this->dispatch('warning', 'Some services do not support multiple domains, which can lead to problems and is NOT RECOMMENDED.<br><br>Only use multiple domains if you know what you are doing.');
|
||||||
} else {
|
|
||||||
! $warning && $this->dispatch('success', 'Service saved.');
|
|
||||||
}
|
}
|
||||||
$this->application->service->parse();
|
$this->application->service->parse();
|
||||||
$this->dispatch('refresh');
|
$this->dispatch('refresh');
|
||||||
$this->dispatch('configurationChanged');
|
$this->dispatch('configurationChanged');
|
||||||
|
$this->dispatch('refreshStatus');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
$originalFqdn = $this->application->getOriginal('fqdn');
|
$originalFqdn = $this->application->getOriginal('fqdn');
|
||||||
if ($originalFqdn !== $this->application->fqdn) {
|
if ($originalFqdn !== $this->application->fqdn) {
|
||||||
|
@@ -63,7 +63,7 @@ class StackForm extends Component
|
|||||||
public function saveCompose($raw)
|
public function saveCompose($raw)
|
||||||
{
|
{
|
||||||
$this->service->docker_compose_raw = $raw;
|
$this->service->docker_compose_raw = $raw;
|
||||||
$this->submit(notify: false);
|
$this->submit(notify: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function instantSave()
|
public function instantSave()
|
||||||
@@ -76,10 +76,6 @@ class StackForm extends Component
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$this->validate();
|
$this->validate();
|
||||||
$isValid = validateComposeFile($this->service->docker_compose_raw, $this->service->server->id);
|
|
||||||
if ($isValid !== 'OK') {
|
|
||||||
throw new \Exception("Invalid docker-compose file.\n$isValid");
|
|
||||||
}
|
|
||||||
$this->service->save();
|
$this->service->save();
|
||||||
$this->service->saveExtraFields($this->fields);
|
$this->service->saveExtraFields($this->fields);
|
||||||
$this->service->parse();
|
$this->service->parse();
|
||||||
|
@@ -2,15 +2,22 @@
|
|||||||
|
|
||||||
namespace App\Livewire\Project\Shared\ScheduledTask;
|
namespace App\Livewire\Project\Shared\ScheduledTask;
|
||||||
|
|
||||||
|
use App\Models\ScheduledTask;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
use Livewire\Attributes\Locked;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class Add extends Component
|
class Add extends Component
|
||||||
{
|
{
|
||||||
public $parameters;
|
public $parameters;
|
||||||
|
|
||||||
|
#[Locked]
|
||||||
|
public string $id;
|
||||||
|
|
||||||
|
#[Locked]
|
||||||
public string $type;
|
public string $type;
|
||||||
|
|
||||||
|
#[Locked]
|
||||||
public Collection $containerNames;
|
public Collection $containerNames;
|
||||||
|
|
||||||
public string $name;
|
public string $name;
|
||||||
@@ -21,8 +28,6 @@ class Add extends Component
|
|||||||
|
|
||||||
public ?string $container = '';
|
public ?string $container = '';
|
||||||
|
|
||||||
protected $listeners = ['clearScheduledTask' => 'clear'];
|
|
||||||
|
|
||||||
protected $rules = [
|
protected $rules = [
|
||||||
'name' => 'required|string',
|
'name' => 'required|string',
|
||||||
'command' => 'required|string',
|
'command' => 'required|string',
|
||||||
@@ -60,18 +65,42 @@ class Add extends Component
|
|||||||
$this->container = $this->subServiceName;
|
$this->container = $this->subServiceName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->dispatch('saveScheduledTask', [
|
$this->saveScheduledTask();
|
||||||
'name' => $this->name,
|
|
||||||
'command' => $this->command,
|
|
||||||
'frequency' => $this->frequency,
|
|
||||||
'container' => $this->container,
|
|
||||||
]);
|
|
||||||
$this->clear();
|
$this->clear();
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function saveScheduledTask()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$task = new ScheduledTask;
|
||||||
|
$task->name = $this->name;
|
||||||
|
$task->command = $this->command;
|
||||||
|
$task->frequency = $this->frequency;
|
||||||
|
$task->container = $this->container;
|
||||||
|
$task->team_id = currentTeam()->id;
|
||||||
|
|
||||||
|
switch ($this->type) {
|
||||||
|
case 'application':
|
||||||
|
$task->application_id = $this->id;
|
||||||
|
break;
|
||||||
|
case 'standalone-postgresql':
|
||||||
|
$task->standalone_postgresql_id = $this->id;
|
||||||
|
break;
|
||||||
|
case 'service':
|
||||||
|
$task->service_id = $this->id;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$task->save();
|
||||||
|
$this->dispatch('refreshTasks');
|
||||||
|
$this->dispatch('success', 'Scheduled task added.');
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function clear()
|
public function clear()
|
||||||
{
|
{
|
||||||
$this->name = '';
|
$this->name = '';
|
||||||
|
@@ -2,22 +2,23 @@
|
|||||||
|
|
||||||
namespace App\Livewire\Project\Shared\ScheduledTask;
|
namespace App\Livewire\Project\Shared\ScheduledTask;
|
||||||
|
|
||||||
use App\Models\ScheduledTask;
|
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
use Livewire\Attributes\Locked;
|
||||||
|
use Livewire\Attributes\On;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class All extends Component
|
class All extends Component
|
||||||
{
|
{
|
||||||
|
#[Locked]
|
||||||
public $resource;
|
public $resource;
|
||||||
|
|
||||||
|
#[Locked]
|
||||||
|
public array $parameters;
|
||||||
|
|
||||||
public Collection $containerNames;
|
public Collection $containerNames;
|
||||||
|
|
||||||
public ?string $variables = null;
|
public ?string $variables = null;
|
||||||
|
|
||||||
public array $parameters;
|
|
||||||
|
|
||||||
protected $listeners = ['refreshTasks', 'saveScheduledTask' => 'submit'];
|
|
||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
$this->parameters = get_route_parameters();
|
$this->parameters = get_route_parameters();
|
||||||
@@ -35,37 +36,9 @@ class All extends Component
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[On('refreshTasks')]
|
||||||
public function refreshTasks()
|
public function refreshTasks()
|
||||||
{
|
{
|
||||||
$this->resource->refresh();
|
$this->resource->refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function submit($data)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$task = new ScheduledTask;
|
|
||||||
$task->name = $data['name'];
|
|
||||||
$task->command = $data['command'];
|
|
||||||
$task->frequency = $data['frequency'];
|
|
||||||
$task->container = $data['container'];
|
|
||||||
$task->team_id = currentTeam()->id;
|
|
||||||
|
|
||||||
switch ($this->resource->type()) {
|
|
||||||
case 'application':
|
|
||||||
$task->application_id = $this->resource->id;
|
|
||||||
break;
|
|
||||||
case 'standalone-postgresql':
|
|
||||||
$task->standalone_postgresql_id = $this->resource->id;
|
|
||||||
break;
|
|
||||||
case 'service':
|
|
||||||
$task->service_id = $this->resource->id;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
$task->save();
|
|
||||||
$this->refreshTasks();
|
|
||||||
$this->dispatch('success', 'Scheduled task added.');
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
return handleError($e, $this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -133,9 +133,9 @@ class Show extends Component
|
|||||||
$this->task->delete();
|
$this->task->delete();
|
||||||
|
|
||||||
if ($this->type === 'application') {
|
if ($this->type === 'application') {
|
||||||
return redirect()->route('project.application.configuration', $this->parameters, $this->task->name);
|
return redirect()->route('project.application.scheduled-tasks.show', $this->parameters);
|
||||||
} else {
|
} else {
|
||||||
return redirect()->route('project.service.configuration', $this->parameters, $this->task->name);
|
return redirect()->route('project.service.scheduled-tasks.show', $this->parameters);
|
||||||
}
|
}
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
return handleError($e);
|
return handleError($e);
|
||||||
|
@@ -29,8 +29,6 @@ class Webhooks extends Component
|
|||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
// ray()->clearAll();
|
|
||||||
// ray()->showQueries();
|
|
||||||
$this->deploywebhook = generateDeployWebhook($this->resource);
|
$this->deploywebhook = generateDeployWebhook($this->resource);
|
||||||
|
|
||||||
$this->githubManualWebhookSecret = data_get($this->resource, 'manual_webhook_secret_github');
|
$this->githubManualWebhookSecret = data_get($this->resource, 'manual_webhook_secret_github');
|
||||||
|
@@ -105,7 +105,6 @@ class Deploy extends Component
|
|||||||
|
|
||||||
$startTime = Carbon::now()->getTimestamp();
|
$startTime = Carbon::now()->getTimestamp();
|
||||||
while ($process->running()) {
|
while ($process->running()) {
|
||||||
ray('running');
|
|
||||||
if (Carbon::now()->getTimestamp() - $startTime >= $timeout) {
|
if (Carbon::now()->getTimestamp() - $startTime >= $timeout) {
|
||||||
$this->forceStopContainer($containerName);
|
$this->forceStopContainer($containerName);
|
||||||
break;
|
break;
|
||||||
|
@@ -36,7 +36,7 @@ class SettingsEmail extends Component
|
|||||||
public ?int $smtpPort = null;
|
public ?int $smtpPort = null;
|
||||||
|
|
||||||
#[Validate(['nullable', 'string', 'in:starttls,tls,none'])]
|
#[Validate(['nullable', 'string', 'in:starttls,tls,none'])]
|
||||||
public ?string $smtpEncryption = null;
|
public ?string $smtpEncryption = 'starttls';
|
||||||
|
|
||||||
#[Validate(['nullable', 'string'])]
|
#[Validate(['nullable', 'string'])]
|
||||||
public ?string $smtpUsername = null;
|
public ?string $smtpUsername = null;
|
||||||
@@ -114,19 +114,24 @@ class SettingsEmail extends Component
|
|||||||
public function instantSave(string $type)
|
public function instantSave(string $type)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
$currentSmtpEnabled = $this->settings->smtp_enabled;
|
||||||
|
$currentResendEnabled = $this->settings->resend_enabled;
|
||||||
$this->resetErrorBag();
|
$this->resetErrorBag();
|
||||||
|
|
||||||
if ($type === 'SMTP') {
|
if ($type === 'SMTP') {
|
||||||
$this->submitSmtp();
|
$this->submitSmtp();
|
||||||
|
$this->resendEnabled = $this->settings->resend_enabled = false;
|
||||||
} elseif ($type === 'Resend') {
|
} elseif ($type === 'Resend') {
|
||||||
$this->submitResend();
|
$this->submitResend();
|
||||||
|
$this->smtpEnabled = $this->settings->smtp_enabled = false;
|
||||||
}
|
}
|
||||||
|
$this->settings->save();
|
||||||
|
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
if ($type === 'SMTP') {
|
if ($type === 'SMTP') {
|
||||||
$this->smtpEnabled = false;
|
$this->smtpEnabled = $currentSmtpEnabled;
|
||||||
} elseif ($type === 'Resend') {
|
} elseif ($type === 'Resend') {
|
||||||
$this->resendEnabled = false;
|
$this->resendEnabled = $currentResendEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
@@ -156,9 +161,6 @@ class SettingsEmail extends Component
|
|||||||
'smtpEncryption.required' => 'Encryption type is required.',
|
'smtpEncryption.required' => 'Encryption type is required.',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->resendEnabled = false;
|
|
||||||
$this->settings->resend_enabled = false;
|
|
||||||
|
|
||||||
$this->settings->smtp_enabled = $this->smtpEnabled;
|
$this->settings->smtp_enabled = $this->smtpEnabled;
|
||||||
$this->settings->smtp_host = $this->smtpHost;
|
$this->settings->smtp_host = $this->smtpHost;
|
||||||
$this->settings->smtp_port = $this->smtpPort;
|
$this->settings->smtp_port = $this->smtpPort;
|
||||||
@@ -194,9 +196,6 @@ class SettingsEmail extends Component
|
|||||||
'smtpFromName.required' => 'From Name is required.',
|
'smtpFromName.required' => 'From Name is required.',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->smtpEnabled = false;
|
|
||||||
$this->settings->smtp_enabled = false;
|
|
||||||
|
|
||||||
$this->settings->resend_enabled = $this->resendEnabled;
|
$this->settings->resend_enabled = $this->resendEnabled;
|
||||||
$this->settings->resend_api_key = $this->resendApiKey;
|
$this->settings->resend_api_key = $this->resendApiKey;
|
||||||
$this->settings->smtp_from_address = $this->smtpFromAddress;
|
$this->settings->smtp_from_address = $this->smtpFromAddress;
|
||||||
|
@@ -37,6 +37,8 @@ class Change extends Component
|
|||||||
|
|
||||||
public $applications;
|
public $applications;
|
||||||
|
|
||||||
|
public $privateKeys;
|
||||||
|
|
||||||
protected $rules = [
|
protected $rules = [
|
||||||
'github_app.name' => 'required|string',
|
'github_app.name' => 'required|string',
|
||||||
'github_app.organization' => 'nullable|string',
|
'github_app.organization' => 'nullable|string',
|
||||||
@@ -54,6 +56,7 @@ class Change extends Component
|
|||||||
'github_app.metadata' => 'nullable|string',
|
'github_app.metadata' => 'nullable|string',
|
||||||
'github_app.pull_requests' => 'nullable|string',
|
'github_app.pull_requests' => 'nullable|string',
|
||||||
'github_app.administration' => 'nullable|string',
|
'github_app.administration' => 'nullable|string',
|
||||||
|
'github_app.private_key_id' => 'required|int',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function boot()
|
public function boot()
|
||||||
@@ -65,9 +68,13 @@ class Change extends Component
|
|||||||
|
|
||||||
public function checkPermissions()
|
public function checkPermissions()
|
||||||
{
|
{
|
||||||
GithubAppPermissionJob::dispatchSync($this->github_app);
|
try {
|
||||||
$this->github_app->refresh()->makeVisible('client_secret')->makeVisible('webhook_secret');
|
GithubAppPermissionJob::dispatchSync($this->github_app);
|
||||||
$this->dispatch('success', 'Github App permissions updated.');
|
$this->github_app->refresh()->makeVisible('client_secret')->makeVisible('webhook_secret');
|
||||||
|
$this->dispatch('success', 'Github App permissions updated.');
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// public function check()
|
// public function check()
|
||||||
@@ -101,7 +108,6 @@ class Change extends Component
|
|||||||
// ]);
|
// ]);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// ray($runners_by_repository);
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
@@ -110,6 +116,7 @@ class Change extends Component
|
|||||||
$github_app_uuid = request()->github_app_uuid;
|
$github_app_uuid = request()->github_app_uuid;
|
||||||
$this->github_app = GithubApp::ownedByCurrentTeam()->whereUuid($github_app_uuid)->firstOrFail();
|
$this->github_app = GithubApp::ownedByCurrentTeam()->whereUuid($github_app_uuid)->firstOrFail();
|
||||||
$this->github_app->makeVisible(['client_secret', 'webhook_secret']);
|
$this->github_app->makeVisible(['client_secret', 'webhook_secret']);
|
||||||
|
$this->privateKeys = PrivateKey::ownedByCurrentTeam()->get();
|
||||||
|
|
||||||
$this->applications = $this->github_app->applications;
|
$this->applications = $this->github_app->applications;
|
||||||
$settings = instanceSettings();
|
$settings = instanceSettings();
|
||||||
@@ -244,6 +251,7 @@ class Change extends Component
|
|||||||
'github_app.client_secret' => 'required|string',
|
'github_app.client_secret' => 'required|string',
|
||||||
'github_app.webhook_secret' => 'required|string',
|
'github_app.webhook_secret' => 'required|string',
|
||||||
'github_app.is_system_wide' => 'required|bool',
|
'github_app.is_system_wide' => 'required|bool',
|
||||||
|
'github_app.private_key_id' => 'required|int',
|
||||||
]);
|
]);
|
||||||
$this->github_app->save();
|
$this->github_app->save();
|
||||||
$this->dispatch('success', 'Github App updated.');
|
$this->dispatch('success', 'Github App updated.');
|
||||||
@@ -252,6 +260,15 @@ class Change extends Component
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function createGithubAppManually()
|
||||||
|
{
|
||||||
|
$this->github_app->makeVisible('client_secret')->makeVisible('webhook_secret');
|
||||||
|
$this->github_app->app_id = '1234567890';
|
||||||
|
$this->github_app->installation_id = '1234567890';
|
||||||
|
$this->github_app->save();
|
||||||
|
$this->dispatch('success', 'Github App updated.');
|
||||||
|
}
|
||||||
|
|
||||||
public function instantSave()
|
public function instantSave()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
@@ -3,6 +3,7 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Events\FileStorageChanged;
|
use App\Events\FileStorageChanged;
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
|
||||||
class LocalFileVolume extends BaseModel
|
class LocalFileVolume extends BaseModel
|
||||||
@@ -17,6 +18,8 @@ class LocalFileVolume extends BaseModel
|
|||||||
|
|
||||||
protected $guarded = [];
|
protected $guarded = [];
|
||||||
|
|
||||||
|
public $appends = ['is_binary'];
|
||||||
|
|
||||||
protected static function booted()
|
protected static function booted()
|
||||||
{
|
{
|
||||||
static::created(function (LocalFileVolume $fileVolume) {
|
static::created(function (LocalFileVolume $fileVolume) {
|
||||||
@@ -25,6 +28,15 @@ class LocalFileVolume extends BaseModel
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function isBinary(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: function () {
|
||||||
|
return $this->content === '[binary file]';
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function service()
|
public function service()
|
||||||
{
|
{
|
||||||
return $this->morphTo('resource');
|
return $this->morphTo('resource');
|
||||||
@@ -50,6 +62,10 @@ class LocalFileVolume extends BaseModel
|
|||||||
$isFile = instant_remote_process(["test -f $path && echo OK || echo NOK"], $server);
|
$isFile = instant_remote_process(["test -f $path && echo OK || echo NOK"], $server);
|
||||||
if ($isFile === 'OK') {
|
if ($isFile === 'OK') {
|
||||||
$content = instant_remote_process(["cat $path"], $server, false);
|
$content = instant_remote_process(["cat $path"], $server, false);
|
||||||
|
// Check if content contains binary data by looking for null bytes or non-printable characters
|
||||||
|
if (str_contains($content, "\0") || preg_match('/[\x00-\x08\x0B\x0C\x0E-\x1F]/', $content)) {
|
||||||
|
$content = '[binary file]';
|
||||||
|
}
|
||||||
$this->content = $content;
|
$this->content = $content;
|
||||||
$this->is_directory = false;
|
$this->is_directory = false;
|
||||||
$this->save();
|
$this->save();
|
||||||
|
@@ -17,6 +17,7 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
|||||||
use Illuminate\Support\Carbon;
|
use Illuminate\Support\Carbon;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Illuminate\Support\Stringable;
|
use Illuminate\Support\Stringable;
|
||||||
use OpenApi\Attributes as OA;
|
use OpenApi\Attributes as OA;
|
||||||
@@ -24,6 +25,7 @@ use Spatie\SchemalessAttributes\Casts\SchemalessAttributes;
|
|||||||
use Spatie\SchemalessAttributes\SchemalessAttributesTrait;
|
use Spatie\SchemalessAttributes\SchemalessAttributesTrait;
|
||||||
use Spatie\Url\Url;
|
use Spatie\Url\Url;
|
||||||
use Symfony\Component\Yaml\Yaml;
|
use Symfony\Component\Yaml\Yaml;
|
||||||
|
use Visus\Cuid2\Cuid2;
|
||||||
|
|
||||||
#[OA\Schema(
|
#[OA\Schema(
|
||||||
description: 'Server model',
|
description: 'Server model',
|
||||||
@@ -101,11 +103,13 @@ class Server extends BaseModel
|
|||||||
'server_id' => $server->id,
|
'server_id' => $server->id,
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
StandaloneDocker::create([
|
$standaloneDocker = new StandaloneDocker([
|
||||||
'name' => 'coolify',
|
'name' => 'coolify',
|
||||||
|
'uuid' => (string) new Cuid2,
|
||||||
'network' => 'coolify',
|
'network' => 'coolify',
|
||||||
'server_id' => $server->id,
|
'server_id' => $server->id,
|
||||||
]);
|
]);
|
||||||
|
$standaloneDocker->saveQuietly();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (! isset($server->proxy->redirect_enabled)) {
|
if (! isset($server->proxy->redirect_enabled)) {
|
||||||
@@ -437,10 +441,6 @@ class Server extends BaseModel
|
|||||||
"mkdir -p $dynamic_config_path",
|
"mkdir -p $dynamic_config_path",
|
||||||
"echo '$base64' | base64 -d | tee $file > /dev/null",
|
"echo '$base64' | base64 -d | tee $file > /dev/null",
|
||||||
], $this);
|
], $this);
|
||||||
|
|
||||||
if (config('app.env') === 'local') {
|
|
||||||
// ray($yaml);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} elseif ($this->proxyType() === 'CADDY') {
|
} elseif ($this->proxyType() === 'CADDY') {
|
||||||
$file = "$dynamic_config_path/coolify.caddy";
|
$file = "$dynamic_config_path/coolify.caddy";
|
||||||
@@ -709,22 +709,6 @@ $schema://$host {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getContainersWithSentinel(): Collection
|
|
||||||
{
|
|
||||||
$sentinel_found = instant_remote_process(['docker inspect coolify-sentinel'], $this, false);
|
|
||||||
$sentinel_found = json_decode($sentinel_found, true);
|
|
||||||
$status = data_get($sentinel_found, '0.State.Status', 'exited');
|
|
||||||
if ($status === 'running') {
|
|
||||||
$containers = instant_remote_process(['docker exec coolify-sentinel sh -c "curl http://127.0.0.1:8888/api/containers"'], $this, false);
|
|
||||||
if (is_null($containers)) {
|
|
||||||
return collect([]);
|
|
||||||
}
|
|
||||||
$containers = data_get(json_decode($containers, true), 'containers', []);
|
|
||||||
|
|
||||||
return collect($containers);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function loadAllContainers(): Collection
|
public function loadAllContainers(): Collection
|
||||||
{
|
{
|
||||||
if ($this->isFunctional()) {
|
if ($this->isFunctional()) {
|
||||||
@@ -970,10 +954,8 @@ $schema://$host {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
if ($supported->count() === 1) {
|
if ($supported->count() === 1) {
|
||||||
// ray('supported');
|
|
||||||
return str($supported->first());
|
return str($supported->first());
|
||||||
} else {
|
} else {
|
||||||
// ray('not supported');
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1042,7 +1024,7 @@ $schema://$host {
|
|||||||
$unreachableNotificationSent = (bool) $this->unreachable_notification_sent;
|
$unreachableNotificationSent = (bool) $this->unreachable_notification_sent;
|
||||||
$isReachable = (bool) $this->settings->is_reachable;
|
$isReachable = (bool) $this->settings->is_reachable;
|
||||||
|
|
||||||
\Log::debug('Server reachability check', [
|
Log::debug('Server reachability check', [
|
||||||
'server_id' => $this->id,
|
'server_id' => $this->id,
|
||||||
'is_reachable' => $isReachable,
|
'is_reachable' => $isReachable,
|
||||||
'notification_sent' => $unreachableNotificationSent,
|
'notification_sent' => $unreachableNotificationSent,
|
||||||
@@ -1054,7 +1036,7 @@ $schema://$host {
|
|||||||
$this->save();
|
$this->save();
|
||||||
|
|
||||||
if ($unreachableNotificationSent === true) {
|
if ($unreachableNotificationSent === true) {
|
||||||
\Log::debug('Server is now reachable, sending notification', [
|
Log::debug('Server is now reachable, sending notification', [
|
||||||
'server_id' => $this->id,
|
'server_id' => $this->id,
|
||||||
]);
|
]);
|
||||||
$this->sendReachableNotification();
|
$this->sendReachableNotification();
|
||||||
@@ -1064,7 +1046,7 @@ $schema://$host {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->increment('unreachable_count');
|
$this->increment('unreachable_count');
|
||||||
\Log::debug('Incremented unreachable count', [
|
Log::debug('Incremented unreachable count', [
|
||||||
'server_id' => $this->id,
|
'server_id' => $this->id,
|
||||||
'new_count' => $this->unreachable_count,
|
'new_count' => $this->unreachable_count,
|
||||||
]);
|
]);
|
||||||
@@ -1072,7 +1054,7 @@ $schema://$host {
|
|||||||
if ($this->unreachable_count === 1) {
|
if ($this->unreachable_count === 1) {
|
||||||
$this->settings->is_reachable = true;
|
$this->settings->is_reachable = true;
|
||||||
$this->settings->save();
|
$this->settings->save();
|
||||||
\Log::debug('First unreachable attempt, marking as reachable', [
|
Log::debug('First unreachable attempt, marking as reachable', [
|
||||||
'server_id' => $this->id,
|
'server_id' => $this->id,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -1083,7 +1065,7 @@ $schema://$host {
|
|||||||
$failedChecks = 0;
|
$failedChecks = 0;
|
||||||
for ($i = 0; $i < 3; $i++) {
|
for ($i = 0; $i < 3; $i++) {
|
||||||
$status = $this->serverStatus();
|
$status = $this->serverStatus();
|
||||||
\Log::debug('Additional reachability check', [
|
Log::debug('Additional reachability check', [
|
||||||
'server_id' => $this->id,
|
'server_id' => $this->id,
|
||||||
'attempt' => $i + 1,
|
'attempt' => $i + 1,
|
||||||
'status' => $status,
|
'status' => $status,
|
||||||
@@ -1095,7 +1077,7 @@ $schema://$host {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($failedChecks === 3 && ! $unreachableNotificationSent) {
|
if ($failedChecks === 3 && ! $unreachableNotificationSent) {
|
||||||
\Log::debug('Server confirmed unreachable after 3 attempts, sending notification', [
|
Log::debug('Server confirmed unreachable after 3 attempts, sending notification', [
|
||||||
'server_id' => $this->id,
|
'server_id' => $this->id,
|
||||||
]);
|
]);
|
||||||
$this->sendUnreachableNotification();
|
$this->sendUnreachableNotification();
|
||||||
|
@@ -78,11 +78,15 @@ class ServiceDatabase extends BaseModel
|
|||||||
public function databaseType()
|
public function databaseType()
|
||||||
{
|
{
|
||||||
$image = str($this->image)->before(':');
|
$image = str($this->image)->before(':');
|
||||||
if ($image->contains('postgres') || $image->contains('postgis')) {
|
if ($image->contains('supabase/postgres')) {
|
||||||
$image = 'postgresql';
|
$finalImage = 'supabase/postgres';
|
||||||
|
} elseif ($image->contains('postgres') || $image->contains('postgis')) {
|
||||||
|
$finalImage = 'postgresql';
|
||||||
|
} else {
|
||||||
|
$finalImage = $image;
|
||||||
}
|
}
|
||||||
|
|
||||||
return "standalone-$image";
|
return "standalone-$finalImage";
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getServiceDatabaseUrl()
|
public function getServiceDatabaseUrl()
|
||||||
|
@@ -38,6 +38,12 @@ class StandaloneRedis extends BaseModel
|
|||||||
$database->forceFill(['last_online_at' => now()]);
|
$database->forceFill(['last_online_at' => now()]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
static::retrieved(function ($database) {
|
||||||
|
if (! $database->redis_username) {
|
||||||
|
$database->redis_username = 'default';
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function serverStatus(): Attribute
|
protected function serverStatus(): Attribute
|
||||||
@@ -198,8 +204,8 @@ class StandaloneRedis extends BaseModel
|
|||||||
{
|
{
|
||||||
return Attribute::make(
|
return Attribute::make(
|
||||||
get: fn () => is_null($this->ports_mappings)
|
get: fn () => is_null($this->ports_mappings)
|
||||||
? []
|
? []
|
||||||
: explode(',', $this->ports_mappings),
|
: explode(',', $this->ports_mappings),
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -366,7 +372,12 @@ class StandaloneRedis extends BaseModel
|
|||||||
get: function () {
|
get: function () {
|
||||||
$username = $this->runtime_environment_variables()->where('key', 'REDIS_USERNAME')->first();
|
$username = $this->runtime_environment_variables()->where('key', 'REDIS_USERNAME')->first();
|
||||||
if (! $username) {
|
if (! $username) {
|
||||||
return null;
|
$this->runtime_environment_variables()->create([
|
||||||
|
'key' => 'REDIS_USERNAME',
|
||||||
|
'value' => 'default',
|
||||||
|
]);
|
||||||
|
|
||||||
|
return 'default';
|
||||||
}
|
}
|
||||||
|
|
||||||
return $username->value;
|
return $username->value;
|
||||||
|
@@ -93,6 +93,15 @@ class Team extends Model implements SendsDiscord, SendsEmail, SendsPushover, Sen
|
|||||||
return $servers >= $serverLimit;
|
return $servers >= $serverLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function subscriptionPastOverDue()
|
||||||
|
{
|
||||||
|
if (isCloud()) {
|
||||||
|
return $this->subscription?->stripe_past_due;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public function serverOverflow()
|
public function serverOverflow()
|
||||||
{
|
{
|
||||||
if ($this->serverLimit() < $this->servers->count()) {
|
if ($this->serverLimit() < $this->servers->count()) {
|
||||||
@@ -185,6 +194,7 @@ class Team extends Model implements SendsDiscord, SendsEmail, SendsPushover, Sen
|
|||||||
'stripe_cancel_at_period_end' => false,
|
'stripe_cancel_at_period_end' => false,
|
||||||
'stripe_invoice_paid' => false,
|
'stripe_invoice_paid' => false,
|
||||||
'stripe_trial_already_ended' => false,
|
'stripe_trial_already_ended' => false,
|
||||||
|
'stripe_past_due' => false,
|
||||||
]);
|
]);
|
||||||
foreach ($this->servers as $server) {
|
foreach ($this->servers as $server) {
|
||||||
$server->settings()->update([
|
$server->settings()->update([
|
||||||
|
@@ -44,7 +44,7 @@ class DeploymentSuccess extends CustomEmailNotification
|
|||||||
if (str($this->fqdn)->explode(',')->count() > 1) {
|
if (str($this->fqdn)->explode(',')->count() > 1) {
|
||||||
$this->fqdn = str($this->fqdn)->explode(',')->first();
|
$this->fqdn = str($this->fqdn)->explode(',')->first();
|
||||||
}
|
}
|
||||||
$this->deployment_url = base_url()."/project/{$this->project_uuid}/environments/{$this->environment_uuid}/application/{$this->application->uuid}/deployment/{$this->deployment_uuid}";
|
$this->deployment_url = base_url()."/project/{$this->project_uuid}/environment/{$this->environment_uuid}/application/{$this->application->uuid}/deployment/{$this->deployment_uuid}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public function via(object $notifiable): array
|
public function via(object $notifiable): array
|
||||||
|
@@ -34,7 +34,7 @@ class StatusChanged extends CustomEmailNotification
|
|||||||
if (str($this->fqdn)->explode(',')->count() > 1) {
|
if (str($this->fqdn)->explode(',')->count() > 1) {
|
||||||
$this->fqdn = str($this->fqdn)->explode(',')->first();
|
$this->fqdn = str($this->fqdn)->explode(',')->first();
|
||||||
}
|
}
|
||||||
$this->resource_url = base_url()."/project/{$this->project_uuid}/environments/{$this->environment_uuid}/application/{$this->resource->uuid}";
|
$this->resource_url = base_url()."/project/{$this->project_uuid}/environment/{$this->environment_uuid}/application/{$this->resource->uuid}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public function via(object $notifiable): array
|
public function via(object $notifiable): array
|
||||||
|
@@ -50,10 +50,9 @@ class EmailChannel
|
|||||||
|
|
||||||
if ($emailSettings->use_instance_email_settings) {
|
if ($emailSettings->use_instance_email_settings) {
|
||||||
$type = set_transanctional_email_settings();
|
$type = set_transanctional_email_settings();
|
||||||
if (! $type) {
|
if (blank($type)) {
|
||||||
throw new Exception('No email settings found.');
|
throw new Exception('No email settings found.');
|
||||||
}
|
}
|
||||||
config()->set('mail.default', $type);
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@@ -35,7 +35,7 @@ class TransactionalEmailChannel
|
|||||||
private function bootConfigs(): void
|
private function bootConfigs(): void
|
||||||
{
|
{
|
||||||
$type = set_transanctional_email_settings();
|
$type = set_transanctional_email_settings();
|
||||||
if (! $type) {
|
if (blank($type)) {
|
||||||
throw new Exception('No email settings found.');
|
throw new Exception('No email settings found.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -40,7 +40,7 @@ class PushoverMessage
|
|||||||
if ($buttonUrl && str_contains($buttonUrl, 'http://localhost')) {
|
if ($buttonUrl && str_contains($buttonUrl, 'http://localhost')) {
|
||||||
$buttonUrl = str_replace('http://localhost', config('app.url'), $buttonUrl);
|
$buttonUrl = str_replace('http://localhost', config('app.url'), $buttonUrl);
|
||||||
}
|
}
|
||||||
$payload['message'] .= " <a href='" . $buttonUrl . "'>" . $text . '</a>';
|
$payload['message'] .= " <a href='".$buttonUrl."'>".$text.'</a>';
|
||||||
}
|
}
|
||||||
|
|
||||||
Log::info('Pushover message', $payload);
|
Log::info('Pushover message', $payload);
|
||||||
|
@@ -3,6 +3,7 @@
|
|||||||
namespace App\Notifications\TransactionalEmails;
|
namespace App\Notifications\TransactionalEmails;
|
||||||
|
|
||||||
use App\Models\InstanceSettings;
|
use App\Models\InstanceSettings;
|
||||||
|
use Exception;
|
||||||
use Illuminate\Notifications\Messages\MailMessage;
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
use Illuminate\Notifications\Notification;
|
use Illuminate\Notifications\Notification;
|
||||||
|
|
||||||
@@ -35,8 +36,8 @@ class ResetPassword extends Notification
|
|||||||
public function via($notifiable)
|
public function via($notifiable)
|
||||||
{
|
{
|
||||||
$type = set_transanctional_email_settings();
|
$type = set_transanctional_email_settings();
|
||||||
if (! $type) {
|
if (blank($type)) {
|
||||||
throw new \Exception('No email settings found.');
|
throw new Exception('No email settings found.');
|
||||||
}
|
}
|
||||||
|
|
||||||
return ['mail'];
|
return ['mail'];
|
||||||
|
@@ -11,6 +11,7 @@ use Illuminate\Foundation\Events\MaintenanceModeEnabled;
|
|||||||
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
|
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
|
||||||
use SocialiteProviders\Authentik\AuthentikExtendSocialite;
|
use SocialiteProviders\Authentik\AuthentikExtendSocialite;
|
||||||
use SocialiteProviders\Azure\AzureExtendSocialite;
|
use SocialiteProviders\Azure\AzureExtendSocialite;
|
||||||
|
use SocialiteProviders\Google\GoogleExtendSocialite;
|
||||||
use SocialiteProviders\Infomaniak\InfomaniakExtendSocialite;
|
use SocialiteProviders\Infomaniak\InfomaniakExtendSocialite;
|
||||||
use SocialiteProviders\Manager\SocialiteWasCalled;
|
use SocialiteProviders\Manager\SocialiteWasCalled;
|
||||||
|
|
||||||
@@ -26,6 +27,7 @@ class EventServiceProvider extends ServiceProvider
|
|||||||
SocialiteWasCalled::class => [
|
SocialiteWasCalled::class => [
|
||||||
AzureExtendSocialite::class.'@handle',
|
AzureExtendSocialite::class.'@handle',
|
||||||
AuthentikExtendSocialite::class.'@handle',
|
AuthentikExtendSocialite::class.'@handle',
|
||||||
|
GoogleExtendSocialite::class.'@handle',
|
||||||
InfomaniakExtendSocialite::class.'@handle',
|
InfomaniakExtendSocialite::class.'@handle',
|
||||||
],
|
],
|
||||||
ProxyStarted::class => [
|
ProxyStarted::class => [
|
||||||
|
@@ -91,8 +91,6 @@ function next_queuable(string $server_id, string $application_id): bool
|
|||||||
$server = Server::find($server_id);
|
$server = Server::find($server_id);
|
||||||
$concurrent_builds = $server->settings->concurrent_builds;
|
$concurrent_builds = $server->settings->concurrent_builds;
|
||||||
|
|
||||||
// ray("serverId:{$server->id}", "concurrentBuilds:{$concurrent_builds}", "deployments:{$deployments->count()}", "sameApplicationDeployments:{$same_application_deployments->count()}")->green();
|
|
||||||
|
|
||||||
if ($deployments->count() > $concurrent_builds) {
|
if ($deployments->count() > $concurrent_builds) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@@ -236,15 +236,29 @@ function deleteEmptyBackupFolder($folderPath, Server $server): void
|
|||||||
function removeOldBackups($backup): void
|
function removeOldBackups($backup): void
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$processedBackups = deleteOldBackupsLocally($backup);
|
if ($backup->executions) {
|
||||||
|
$localBackupsToDelete = deleteOldBackupsLocally($backup);
|
||||||
if ($backup->save_s3) {
|
if ($localBackupsToDelete->isNotEmpty()) {
|
||||||
$processedBackups = $processedBackups->merge(deleteOldBackupsFromS3($backup));
|
$backup->executions()
|
||||||
|
->whereIn('id', $localBackupsToDelete->pluck('id'))
|
||||||
|
->update(['local_storage_deleted' => true]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($processedBackups->isNotEmpty()) {
|
if ($backup->save_s3 && $backup->executions) {
|
||||||
$backup->executions()->whereIn('id', $processedBackups->pluck('id'))->delete();
|
$s3BackupsToDelete = deleteOldBackupsFromS3($backup);
|
||||||
|
if ($s3BackupsToDelete->isNotEmpty()) {
|
||||||
|
$backup->executions()
|
||||||
|
->whereIn('id', $s3BackupsToDelete->pluck('id'))
|
||||||
|
->update(['s3_storage_deleted' => true]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$backup->executions()
|
||||||
|
->where('local_storage_deleted', true)
|
||||||
|
->where('s3_storage_deleted', true)
|
||||||
|
->delete();
|
||||||
|
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
@@ -258,6 +272,7 @@ function deleteOldBackupsLocally($backup): Collection
|
|||||||
|
|
||||||
$successfulBackups = $backup->executions()
|
$successfulBackups = $backup->executions()
|
||||||
->where('status', 'success')
|
->where('status', 'success')
|
||||||
|
->where('local_storage_deleted', false)
|
||||||
->orderBy('created_at', 'desc')
|
->orderBy('created_at', 'desc')
|
||||||
->get();
|
->get();
|
||||||
|
|
||||||
@@ -341,6 +356,7 @@ function deleteOldBackupsFromS3($backup): Collection
|
|||||||
|
|
||||||
$successfulBackups = $backup->executions()
|
$successfulBackups = $backup->executions()
|
||||||
->where('status', 'success')
|
->where('status', 'success')
|
||||||
|
->where('s3_storage_deleted', false)
|
||||||
->orderBy('created_at', 'desc')
|
->orderBy('created_at', 'desc')
|
||||||
->get();
|
->get();
|
||||||
|
|
||||||
|
@@ -778,7 +778,6 @@ function convertDockerRunToCompose(?string $custom_docker_run_options = null)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ray($payload);
|
|
||||||
$compose_options->put('deploy', [
|
$compose_options->put('deploy', [
|
||||||
'resources' => [
|
'resources' => [
|
||||||
'reservations' => [
|
'reservations' => [
|
||||||
@@ -829,26 +828,29 @@ function generateCustomDockerRunOptionsForDatabases($docker_run_options, $docker
|
|||||||
|
|
||||||
function validateComposeFile(string $compose, int $server_id): string|Throwable
|
function validateComposeFile(string $compose, int $server_id): string|Throwable
|
||||||
{
|
{
|
||||||
return 'OK';
|
$uuid = Str::random(18);
|
||||||
|
$server = Server::ownedByCurrentTeam()->find($server_id);
|
||||||
try {
|
try {
|
||||||
$uuid = Str::random(10);
|
if (! $server) {
|
||||||
$server = Server::findOrFail($server_id);
|
throw new \Exception('Server not found');
|
||||||
|
}
|
||||||
$base64_compose = base64_encode($compose);
|
$base64_compose = base64_encode($compose);
|
||||||
$output = instant_remote_process([
|
instant_remote_process([
|
||||||
"echo {$base64_compose} | base64 -d | tee /tmp/{$uuid}.yml > /dev/null",
|
"echo {$base64_compose} | base64 -d | tee /tmp/{$uuid}.yml > /dev/null",
|
||||||
"docker compose -f /tmp/{$uuid}.yml config",
|
"chmod 600 /tmp/{$uuid}.yml",
|
||||||
|
"docker compose -f /tmp/{$uuid}.yml config --no-interpolate --no-path-resolution -q",
|
||||||
|
"rm /tmp/{$uuid}.yml",
|
||||||
], $server);
|
], $server);
|
||||||
ray($output);
|
|
||||||
|
|
||||||
return 'OK';
|
return 'OK';
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
ray($e);
|
|
||||||
|
|
||||||
return $e->getMessage();
|
return $e->getMessage();
|
||||||
} finally {
|
} finally {
|
||||||
instant_remote_process([
|
if (filled($server)) {
|
||||||
"rm /tmp/{$uuid}.yml",
|
instant_remote_process([
|
||||||
], $server);
|
"rm /tmp/{$uuid}.yml",
|
||||||
|
], $server, throwError: false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -28,7 +28,7 @@ function send_user_an_email(MailMessage $mail, string $email, ?string $cc = null
|
|||||||
{
|
{
|
||||||
$settings = instanceSettings();
|
$settings = instanceSettings();
|
||||||
$type = set_transanctional_email_settings($settings);
|
$type = set_transanctional_email_settings($settings);
|
||||||
if (! $type) {
|
if (blank($type)) {
|
||||||
throw new Exception('No email settings found.');
|
throw new Exception('No email settings found.');
|
||||||
}
|
}
|
||||||
if ($cc) {
|
if ($cc) {
|
||||||
@@ -54,15 +54,19 @@ function send_user_an_email(MailMessage $mail, string $email, ?string $cc = null
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function set_transanctional_email_settings(?InstanceSettings $settings = null): ?string //
|
function set_transanctional_email_settings(?InstanceSettings $settings = null): ?string // returns null|resend|smtp and defaults to array based on mail.php config
|
||||||
{
|
{
|
||||||
if (! $settings) {
|
if (! $settings) {
|
||||||
$settings = instanceSettings();
|
$settings = instanceSettings();
|
||||||
}
|
}
|
||||||
config()->set('mail.from.address', data_get($settings, 'smtp_from_address'));
|
if (! data_get($settings, 'smtp_enabled') && ! data_get($settings, 'resend_enabled')) {
|
||||||
config()->set('mail.from.name', data_get($settings, 'smtp_from_name'));
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (data_get($settings, 'resend_enabled')) {
|
if (data_get($settings, 'resend_enabled')) {
|
||||||
config()->set('mail.default', 'resend');
|
config()->set('mail.default', 'resend');
|
||||||
|
config()->set('mail.from.address', data_get($settings, 'smtp_from_address'));
|
||||||
|
config()->set('mail.from.name', data_get($settings, 'smtp_from_name'));
|
||||||
config()->set('resend.api_key', data_get($settings, 'resend_api_key'));
|
config()->set('resend.api_key', data_get($settings, 'resend_api_key'));
|
||||||
|
|
||||||
return 'resend';
|
return 'resend';
|
||||||
@@ -76,6 +80,8 @@ function set_transanctional_email_settings(?InstanceSettings $settings = null):
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (data_get($settings, 'smtp_enabled')) {
|
if (data_get($settings, 'smtp_enabled')) {
|
||||||
|
config()->set('mail.from.address', data_get($settings, 'smtp_from_address'));
|
||||||
|
config()->set('mail.from.name', data_get($settings, 'smtp_from_name'));
|
||||||
config()->set('mail.default', 'smtp');
|
config()->set('mail.default', 'smtp');
|
||||||
config()->set('mail.mailers.smtp', [
|
config()->set('mail.mailers.smtp', [
|
||||||
'transport' => 'smtp',
|
'transport' => 'smtp',
|
||||||
@@ -91,6 +97,4 @@ function set_transanctional_email_settings(?InstanceSettings $settings = null):
|
|||||||
|
|
||||||
return 'smtp';
|
return 'smtp';
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
@@ -748,6 +748,7 @@ function parseCommandFromMagicEnvVariable(Str|string $key): Stringable
|
|||||||
{
|
{
|
||||||
$value = str($key);
|
$value = str($key);
|
||||||
$count = substr_count($value->value(), '_');
|
$count = substr_count($value->value(), '_');
|
||||||
|
$command = null;
|
||||||
if ($count === 2) {
|
if ($count === 2) {
|
||||||
if ($value->startsWith('SERVICE_FQDN') || $value->startsWith('SERVICE_URL')) {
|
if ($value->startsWith('SERVICE_FQDN') || $value->startsWith('SERVICE_URL')) {
|
||||||
// SERVICE_FQDN_UMAMI
|
// SERVICE_FQDN_UMAMI
|
||||||
@@ -800,7 +801,6 @@ function parseEnvVariable(Str|string $value)
|
|||||||
} else {
|
} else {
|
||||||
// SERVICE_BASE64_64_UMAMI
|
// SERVICE_BASE64_64_UMAMI
|
||||||
$command = $value->after('SERVICE_')->beforeLast('_');
|
$command = $value->after('SERVICE_')->beforeLast('_');
|
||||||
ray($command);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -952,7 +952,6 @@ function validate_dns_entry(string $fqdn, Server $server)
|
|||||||
$type = \PurplePixie\PhpDns\DNSTypes::NAME_A;
|
$type = \PurplePixie\PhpDns\DNSTypes::NAME_A;
|
||||||
foreach ($dns_servers as $dns_server) {
|
foreach ($dns_servers as $dns_server) {
|
||||||
try {
|
try {
|
||||||
ray("Checking $host on $dns_server");
|
|
||||||
$query = new DNSQuery($dns_server);
|
$query = new DNSQuery($dns_server);
|
||||||
$results = $query->query($host, $type);
|
$results = $query->query($host, $type);
|
||||||
if ($results === false || $query->hasError()) {
|
if ($results === false || $query->hasError()) {
|
||||||
@@ -961,13 +960,10 @@ function validate_dns_entry(string $fqdn, Server $server)
|
|||||||
foreach ($results as $result) {
|
foreach ($results as $result) {
|
||||||
if ($result->getType() == $type) {
|
if ($result->getType() == $type) {
|
||||||
if (ip_match($result->getData(), $cloudflare_ips->toArray(), $match)) {
|
if (ip_match($result->getData(), $cloudflare_ips->toArray(), $match)) {
|
||||||
ray("Found match in Cloudflare IPs: $match");
|
|
||||||
$found_matching_ip = true;
|
$found_matching_ip = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if ($result->getData() === $ip) {
|
if ($result->getData() === $ip) {
|
||||||
ray($host.' has IP address '.$result->getData());
|
|
||||||
ray($result->getString());
|
|
||||||
$found_matching_ip = true;
|
$found_matching_ip = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -977,7 +973,6 @@ function validate_dns_entry(string $fqdn, Server $server)
|
|||||||
} catch (\Exception) {
|
} catch (\Exception) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ray("Found match: $found_matching_ip");
|
|
||||||
|
|
||||||
return $found_matching_ip;
|
return $found_matching_ip;
|
||||||
}
|
}
|
||||||
@@ -1331,7 +1326,6 @@ function parseServiceVolumes($serviceVolumes, $resource, $topLevelVolumes, $pull
|
|||||||
$isDirectory = (bool) data_get($volume, 'isDirectory', null) || (bool) data_get($volume, 'is_directory', null);
|
$isDirectory = (bool) data_get($volume, 'isDirectory', null) || (bool) data_get($volume, 'is_directory', null);
|
||||||
if ((is_null($isDirectory) || ! $isDirectory) && is_null($content)) {
|
if ((is_null($isDirectory) || ! $isDirectory) && is_null($content)) {
|
||||||
// if isDirectory is not set (or false) & content is also not set, we assume it is a directory
|
// if isDirectory is not set (or false) & content is also not set, we assume it is a directory
|
||||||
ray('setting isDirectory to true');
|
|
||||||
$isDirectory = true;
|
$isDirectory = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1499,7 +1493,6 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
$serviceLabels->push("$removedLabelName=$removedLabel");
|
$serviceLabels->push("$removedLabelName=$removedLabel");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$containerName = "$serviceName-{$resource->uuid}";
|
$containerName = "$serviceName-{$resource->uuid}";
|
||||||
|
|
||||||
// Decide if the service is a database
|
// Decide if the service is a database
|
||||||
@@ -1662,7 +1655,6 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
}
|
}
|
||||||
if (is_null($isDirectory) && is_null($content)) {
|
if (is_null($isDirectory) && is_null($content)) {
|
||||||
// if isDirectory is not set & content is also not set, we assume it is a directory
|
// if isDirectory is not set & content is also not set, we assume it is a directory
|
||||||
ray('setting isDirectory to true');
|
|
||||||
$isDirectory = true;
|
$isDirectory = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2529,9 +2521,6 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($collectedPorts->count() > 0) {
|
|
||||||
ray($collectedPorts->implode(','));
|
|
||||||
}
|
|
||||||
$definedNetworkExists = $topLevelNetworks->contains(function ($value, $_) use ($definedNetwork) {
|
$definedNetworkExists = $topLevelNetworks->contains(function ($value, $_) use ($definedNetwork) {
|
||||||
return $value == $definedNetwork;
|
return $value == $definedNetwork;
|
||||||
});
|
});
|
||||||
@@ -2956,7 +2945,6 @@ function newParser(Application|Service $resource, int $pull_request_id = 0, ?int
|
|||||||
}
|
}
|
||||||
|
|
||||||
$parsedServices = collect([]);
|
$parsedServices = collect([]);
|
||||||
// ray()->clearAll();
|
|
||||||
|
|
||||||
$allMagicEnvironments = collect([]);
|
$allMagicEnvironments = collect([]);
|
||||||
foreach ($services as $serviceName => $service) {
|
foreach ($services as $serviceName => $service) {
|
||||||
@@ -3016,7 +3004,7 @@ function newParser(Application|Service $resource, int $pull_request_id = 0, ?int
|
|||||||
$environment = $environment->merge($buildArgs);
|
$environment = $environment->merge($buildArgs);
|
||||||
|
|
||||||
// convert environment variables to one format
|
// convert environment variables to one format
|
||||||
$environment = convertComposeEnvironmentToArray($environment);
|
$environment = convertToKeyValueCollection($environment);
|
||||||
|
|
||||||
// Add Coolify defined environments
|
// Add Coolify defined environments
|
||||||
$allEnvironments = $resource->environment_variables()->get(['key', 'value']);
|
$allEnvironments = $resource->environment_variables()->get(['key', 'value']);
|
||||||
@@ -3197,7 +3185,7 @@ function newParser(Application|Service $resource, int $pull_request_id = 0, ?int
|
|||||||
$buildArgs = collect(data_get($service, 'build.args', []));
|
$buildArgs = collect(data_get($service, 'build.args', []));
|
||||||
$environment = $environment->merge($buildArgs);
|
$environment = $environment->merge($buildArgs);
|
||||||
|
|
||||||
$environment = convertComposeEnvironmentToArray($environment);
|
$environment = convertToKeyValueCollection($environment);
|
||||||
$coolifyEnvironments = collect([]);
|
$coolifyEnvironments = collect([]);
|
||||||
|
|
||||||
$isDatabase = isDatabaseImage(data_get_str($service, 'image'));
|
$isDatabase = isDatabaseImage(data_get_str($service, 'image'));
|
||||||
@@ -3934,7 +3922,7 @@ function add_coolify_default_environment_variables(StandaloneRedis|StandalonePos
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function convertComposeEnvironmentToArray($environment)
|
function convertToKeyValueCollection($environment)
|
||||||
{
|
{
|
||||||
$convertedServiceVariables = collect([]);
|
$convertedServiceVariables = collect([]);
|
||||||
if (isAssociativeArray($environment)) {
|
if (isAssociativeArray($environment)) {
|
||||||
@@ -4066,29 +4054,24 @@ function defaultNginxConfiguration(): string
|
|||||||
{
|
{
|
||||||
return 'server {
|
return 'server {
|
||||||
location / {
|
location / {
|
||||||
root /usr/share/nginx/html;
|
root /usr/share/nginx/html;
|
||||||
index index.html index.htm;
|
index index.html index.htm;
|
||||||
try_files $uri $uri.html $uri/index.html $uri/index.htm $uri/ /index.html /index.htm =404;
|
try_files $uri $uri.html $uri/index.html $uri/index.htm $uri/ =404;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Handle 404 errors
|
||||||
|
error_page 404 /404.html;
|
||||||
|
location = /404.html {
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
internal;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Handle server errors (50x)
|
||||||
error_page 500 502 503 504 /50x.html;
|
error_page 500 502 503 504 /50x.html;
|
||||||
location = /50x.html {
|
location = /50x.html {
|
||||||
root /usr/share/nginx/html;
|
root /usr/share/nginx/html;
|
||||||
try_files $uri @redirect_to_index;
|
|
||||||
internal;
|
internal;
|
||||||
}
|
}
|
||||||
|
|
||||||
error_page 404 = @handle_404;
|
|
||||||
|
|
||||||
location @handle_404 {
|
|
||||||
root /usr/share/nginx/html;
|
|
||||||
try_files /404.html @redirect_to_index;
|
|
||||||
internal;
|
|
||||||
}
|
|
||||||
|
|
||||||
location @redirect_to_index {
|
|
||||||
return 302 /;
|
|
||||||
}
|
|
||||||
}';
|
}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -29,6 +29,18 @@ function get_socialite_provider(string $provider)
|
|||||||
return Socialite::driver('authentik')->setConfig($authentik_config);
|
return Socialite::driver('authentik')->setConfig($authentik_config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($provider == 'google') {
|
||||||
|
$google_config = new \SocialiteProviders\Manager\Config(
|
||||||
|
$oauth_setting->client_id,
|
||||||
|
$oauth_setting->client_secret,
|
||||||
|
$oauth_setting->redirect_uri
|
||||||
|
);
|
||||||
|
|
||||||
|
return Socialite::driver('google')
|
||||||
|
->setConfig($google_config)
|
||||||
|
->with(['hd' => $oauth_setting->tenant]);
|
||||||
|
}
|
||||||
|
|
||||||
$config = [
|
$config = [
|
||||||
'client_id' => $oauth_setting->client_id,
|
'client_id' => $oauth_setting->client_id,
|
||||||
'client_secret' => $oauth_setting->client_secret,
|
'client_secret' => $oauth_setting->client_secret,
|
||||||
@@ -39,7 +51,6 @@ function get_socialite_provider(string $provider)
|
|||||||
'bitbucket' => \Laravel\Socialite\Two\BitbucketProvider::class,
|
'bitbucket' => \Laravel\Socialite\Two\BitbucketProvider::class,
|
||||||
'github' => \Laravel\Socialite\Two\GithubProvider::class,
|
'github' => \Laravel\Socialite\Two\GithubProvider::class,
|
||||||
'gitlab' => \Laravel\Socialite\Two\GitlabProvider::class,
|
'gitlab' => \Laravel\Socialite\Two\GitlabProvider::class,
|
||||||
'google' => \Laravel\Socialite\Two\GoogleProvider::class,
|
|
||||||
'infomaniak' => \SocialiteProviders\Infomaniak\Provider::class,
|
'infomaniak' => \SocialiteProviders\Infomaniak\Provider::class,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@@ -40,6 +40,7 @@
|
|||||||
"resend/resend-laravel": "^0.15.0",
|
"resend/resend-laravel": "^0.15.0",
|
||||||
"sentry/sentry-laravel": "^4.6",
|
"sentry/sentry-laravel": "^4.6",
|
||||||
"socialiteproviders/authentik": "^5.2",
|
"socialiteproviders/authentik": "^5.2",
|
||||||
|
"socialiteproviders/google": "^4.1",
|
||||||
"socialiteproviders/infomaniak": "^4.0",
|
"socialiteproviders/infomaniak": "^4.0",
|
||||||
"socialiteproviders/microsoft-azure": "^5.1",
|
"socialiteproviders/microsoft-azure": "^5.1",
|
||||||
"spatie/laravel-activitylog": "^4.7.3",
|
"spatie/laravel-activitylog": "^4.7.3",
|
||||||
@@ -125,4 +126,4 @@
|
|||||||
"@php artisan key:generate --ansi"
|
"@php artisan key:generate --ansi"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
1558
composer.lock
generated
1558
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see https://github.com/pionl/laravel-chunk-upload
|
* @see https://github.com/pionl/laravel-chunk-upload
|
||||||
*/
|
*/
|
||||||
|
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
return [
|
return [
|
||||||
'coolify' => [
|
'coolify' => [
|
||||||
'version' => '4.0.0-beta.394',
|
'version' => '4.0.0-beta.399',
|
||||||
'helper_version' => '1.0.6',
|
'helper_version' => '1.0.7',
|
||||||
'realtime_version' => '1.0.5',
|
'realtime_version' => '1.0.6',
|
||||||
'self_hosted' => env('SELF_HOSTED', true),
|
'self_hosted' => env('SELF_HOSTED', true),
|
||||||
'autoupdate' => env('AUTOUPDATE'),
|
'autoupdate' => env('AUTOUPDATE'),
|
||||||
'base_config_path' => env('BASE_CONFIG_PATH', '/data/coolify'),
|
'base_config_path' => env('BASE_CONFIG_PATH', '/data/coolify'),
|
||||||
|
@@ -38,7 +38,7 @@ return [
|
|||||||
'pgsql' => [
|
'pgsql' => [
|
||||||
'driver' => 'pgsql',
|
'driver' => 'pgsql',
|
||||||
'url' => env('DATABASE_URL'),
|
'url' => env('DATABASE_URL'),
|
||||||
'host' => env('DB_HOST', 'postgres'),
|
'host' => env('DB_HOST', 'coolify-db'),
|
||||||
'port' => env('DB_PORT', '5432'),
|
'port' => env('DB_PORT', '5432'),
|
||||||
'database' => env('DB_DATABASE', 'coolify'),
|
'database' => env('DB_DATABASE', 'coolify'),
|
||||||
'username' => env('DB_USERNAME', 'coolify'),
|
'username' => env('DB_USERNAME', 'coolify'),
|
||||||
|
@@ -234,7 +234,7 @@ return [
|
|||||||
],
|
],
|
||||||
'views' => [
|
'views' => [
|
||||||
'timeline' => false, // Add the views to the timeline (Experimental)
|
'timeline' => false, // Add the views to the timeline (Experimental)
|
||||||
'data' => false, //true for all data, 'keys' for only names, false for no parameters.
|
'data' => false, // true for all data, 'keys' for only names, false for no parameters.
|
||||||
'group' => 50, // Group duplicate views. Pass value to auto-group, or true/false to force
|
'group' => 50, // Group duplicate views. Pass value to auto-group, or true/false to force
|
||||||
'exclude_paths' => [ // Add the paths which you don't want to appear in the views
|
'exclude_paths' => [ // Add the paths which you don't want to appear in the views
|
||||||
'vendor/filament', // Exclude Filament components by default
|
'vendor/filament', // Exclude Filament components by default
|
||||||
|
@@ -13,7 +13,7 @@ return [
|
|||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'default' => env('MAIL_MAILER', null),
|
'default' => env('MAIL_MAILER', 'array'),
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
|
@@ -45,4 +45,12 @@ return [
|
|||||||
'client_secret' => env('AUTHENTIK_CLIENT_SECRET'),
|
'client_secret' => env('AUTHENTIK_CLIENT_SECRET'),
|
||||||
'redirect' => env('AUTHENTIK_REDIRECT_URI'),
|
'redirect' => env('AUTHENTIK_REDIRECT_URI'),
|
||||||
],
|
],
|
||||||
|
|
||||||
|
'google' => [
|
||||||
|
'client_id' => env('GOOGLE_CLIENT_ID'),
|
||||||
|
'client_secret' => env('GOOGLE_CLIENT_SECRET'),
|
||||||
|
'redirect' => env('GOOGLE_REDIRECT_URI'),
|
||||||
|
'tenant' => env('GOOGLE_TENANT'),
|
||||||
|
],
|
||||||
|
|
||||||
];
|
];
|
||||||
|
@@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('scheduled_task_executions', function (Blueprint $table) {
|
||||||
|
$table->index(['scheduled_task_id', 'created_at'], 'scheduled_task_executions_task_id_created_at_index');
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('scheduled_database_backup_executions', function (Blueprint $table) {
|
||||||
|
$table->index(
|
||||||
|
['scheduled_database_backup_id', 'created_at'],
|
||||||
|
'scheduled_db_backup_executions_backup_id_created_at_index'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('scheduled_task_executions', function (Blueprint $table) {
|
||||||
|
$table->dropIndex('scheduled_task_executions_task_id_created_at_index');
|
||||||
|
});
|
||||||
|
Schema::table('scheduled_database_backup_executions', function (Blueprint $table) {
|
||||||
|
$table->dropIndex('scheduled_db_backup_executions_backup_id_created_at_index');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('subscriptions', function (Blueprint $table) {
|
||||||
|
$table->boolean('stripe_past_due')->default(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('subscriptions', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('stripe_past_due');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('scheduled_database_backup_executions', function (Blueprint $table) {
|
||||||
|
$table->boolean('local_storage_deleted')->default(false);
|
||||||
|
$table->boolean('s3_storage_deleted')->default(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
@@ -21,7 +21,7 @@ class GithubAppSeeder extends Seeder
|
|||||||
'team_id' => 0,
|
'team_id' => 0,
|
||||||
]);
|
]);
|
||||||
GithubApp::create([
|
GithubApp::create([
|
||||||
'name' => 'coolify-laravel-development-public',
|
'name' => 'coolify-laravel-dev-public',
|
||||||
'uuid' => '69420',
|
'uuid' => '69420',
|
||||||
'organization' => 'coollabsio',
|
'organization' => 'coollabsio',
|
||||||
'api_url' => 'https://api.github.com',
|
'api_url' => 'https://api.github.com',
|
||||||
|
@@ -61,7 +61,7 @@ services:
|
|||||||
retries: 10
|
retries: 10
|
||||||
timeout: 2s
|
timeout: 2s
|
||||||
soketi:
|
soketi:
|
||||||
image: 'ghcr.io/coollabsio/coolify-realtime:1.0.5'
|
image: 'ghcr.io/coollabsio/coolify-realtime:1.0.6'
|
||||||
ports:
|
ports:
|
||||||
- "${SOKETI_PORT:-6001}:6001"
|
- "${SOKETI_PORT:-6001}:6001"
|
||||||
- "6002:6002"
|
- "6002:6002"
|
||||||
|
@@ -103,7 +103,7 @@ services:
|
|||||||
retries: 10
|
retries: 10
|
||||||
timeout: 2s
|
timeout: 2s
|
||||||
soketi:
|
soketi:
|
||||||
image: 'ghcr.io/coollabsio/coolify-realtime:1.0.4'
|
image: 'ghcr.io/coollabsio/coolify-realtime:1.0.6'
|
||||||
pull_policy: always
|
pull_policy: always
|
||||||
container_name: coolify-realtime
|
container_name: coolify-realtime
|
||||||
restart: always
|
restart: always
|
||||||
|
@@ -1,20 +1,18 @@
|
|||||||
# Versions
|
# Versions
|
||||||
|
|
||||||
|
|
||||||
# https://hub.docker.com/_/alpine
|
# https://hub.docker.com/_/alpine
|
||||||
ARG BASE_IMAGE=alpine:3.21
|
ARG BASE_IMAGE=alpine:3.21
|
||||||
# https://download.docker.com/linux/static/stable/
|
# https://download.docker.com/linux/static/stable/
|
||||||
ARG DOCKER_VERSION=27.4.1
|
ARG DOCKER_VERSION=28.0.0
|
||||||
# https://github.com/docker/compose/releases
|
# https://github.com/docker/compose/releases
|
||||||
ARG DOCKER_COMPOSE_VERSION=2.32.2
|
ARG DOCKER_COMPOSE_VERSION=2.33.1
|
||||||
# https://github.com/docker/buildx/releases
|
# https://github.com/docker/buildx/releases
|
||||||
ARG DOCKER_BUILDX_VERSION=0.19.3
|
ARG DOCKER_BUILDX_VERSION=0.21.1
|
||||||
# https://github.com/buildpacks/pack/releases
|
# https://github.com/buildpacks/pack/releases
|
||||||
ARG PACK_VERSION=0.36.2
|
ARG PACK_VERSION=0.36.4
|
||||||
# https://github.com/railwayapp/nixpacks/releases
|
# https://github.com/railwayapp/nixpacks/releases
|
||||||
ARG NIXPACKS_VERSION=1.29.0
|
ARG NIXPACKS_VERSION=1.33.0
|
||||||
# https://github.com/minio/mc/releases
|
# https://github.com/minio/mc/releases
|
||||||
ARG MINIO_VERSION=RELEASE.2024-11-21T17-21-54Z
|
ARG MINIO_VERSION=RELEASE.2025-02-15T10-36-16Z
|
||||||
|
|
||||||
FROM minio/mc:${MINIO_VERSION} AS minio-client
|
FROM minio/mc:${MINIO_VERSION} AS minio-client
|
||||||
|
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
# https://github.com/soketi/soketi/releases
|
# https://github.com/soketi/soketi/releases
|
||||||
ARG SOKETI_VERSION=1.6-16-alpine
|
ARG SOKETI_VERSION=1.6-16-alpine
|
||||||
# https://github.com/cloudflare/cloudflared/releases
|
# https://github.com/cloudflare/cloudflared/releases
|
||||||
ARG CLOUDFLARED_VERSION=2025.1.0
|
ARG CLOUDFLARED_VERSION=2025.2.0
|
||||||
|
|
||||||
FROM quay.io/soketi/soketi:${SOKETI_VERSION}
|
FROM quay.io/soketi/soketi:${SOKETI_VERSION}
|
||||||
|
|
||||||
|
199
docker/coolify-realtime/package-lock.json
generated
199
docker/coolify-realtime/package-lock.json
generated
@@ -11,7 +11,7 @@
|
|||||||
"cookie": "1.0.2",
|
"cookie": "1.0.2",
|
||||||
"dotenv": "16.4.7",
|
"dotenv": "16.4.7",
|
||||||
"node-pty": "1.0.0",
|
"node-pty": "1.0.0",
|
||||||
"ws": "8.18.0"
|
"ws": "8.18.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@xterm/addon-fit": {
|
"node_modules/@xterm/addon-fit": {
|
||||||
@@ -46,6 +46,19 @@
|
|||||||
"proxy-from-env": "^1.1.0"
|
"proxy-from-env": "^1.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/call-bind-apply-helpers": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"es-errors": "^1.3.0",
|
||||||
|
"function-bind": "^1.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/combined-stream": {
|
"node_modules/combined-stream": {
|
||||||
"version": "1.0.8",
|
"version": "1.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||||
@@ -88,6 +101,65 @@
|
|||||||
"url": "https://dotenvx.com"
|
"url": "https://dotenvx.com"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/dunder-proto": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"call-bind-apply-helpers": "^1.0.1",
|
||||||
|
"es-errors": "^1.3.0",
|
||||||
|
"gopd": "^1.2.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/es-define-property": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/es-errors": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/es-object-atoms": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"es-errors": "^1.3.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/es-set-tostringtag": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"es-errors": "^1.3.0",
|
||||||
|
"get-intrinsic": "^1.2.6",
|
||||||
|
"has-tostringtag": "^1.0.2",
|
||||||
|
"hasown": "^2.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/follow-redirects": {
|
"node_modules/follow-redirects": {
|
||||||
"version": "1.15.9",
|
"version": "1.15.9",
|
||||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
|
||||||
@@ -109,19 +181,126 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/form-data": {
|
"node_modules/form-data": {
|
||||||
"version": "4.0.1",
|
"version": "4.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz",
|
||||||
"integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==",
|
"integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"asynckit": "^0.4.0",
|
"asynckit": "^0.4.0",
|
||||||
"combined-stream": "^1.0.8",
|
"combined-stream": "^1.0.8",
|
||||||
|
"es-set-tostringtag": "^2.1.0",
|
||||||
"mime-types": "^2.1.12"
|
"mime-types": "^2.1.12"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/function-bind": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/get-intrinsic": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"call-bind-apply-helpers": "^1.0.2",
|
||||||
|
"es-define-property": "^1.0.1",
|
||||||
|
"es-errors": "^1.3.0",
|
||||||
|
"es-object-atoms": "^1.1.1",
|
||||||
|
"function-bind": "^1.1.2",
|
||||||
|
"get-proto": "^1.0.1",
|
||||||
|
"gopd": "^1.2.0",
|
||||||
|
"has-symbols": "^1.1.0",
|
||||||
|
"hasown": "^2.0.2",
|
||||||
|
"math-intrinsics": "^1.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/get-proto": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"dunder-proto": "^1.0.1",
|
||||||
|
"es-object-atoms": "^1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/gopd": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/has-symbols": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/has-tostringtag": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"has-symbols": "^1.0.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/hasown": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"function-bind": "^1.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/math-intrinsics": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/mime-db": {
|
"node_modules/mime-db": {
|
||||||
"version": "1.52.0",
|
"version": "1.52.0",
|
||||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||||
@@ -144,9 +323,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/nan": {
|
"node_modules/nan": {
|
||||||
"version": "2.22.0",
|
"version": "2.22.1",
|
||||||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.22.0.tgz",
|
"resolved": "https://registry.npmjs.org/nan/-/nan-2.22.1.tgz",
|
||||||
"integrity": "sha512-nbajikzWTMwsW+eSsNm3QwlOs7het9gGJU5dDZzRTQGk03vyBOauxgI4VakDzE0PtsGTmXPsXTbbjVhRwR5mpw==",
|
"integrity": "sha512-pfRR4ZcNTSm2ZFHaztuvbICf+hyiG6ecA06SfAxoPmuHjvMu0KUIae7Y8GyVkbBqeEIidsmXeYooWIX9+qjfRQ==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/node-pty": {
|
"node_modules/node-pty": {
|
||||||
@@ -166,9 +345,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/ws": {
|
"node_modules/ws": {
|
||||||
"version": "8.18.0",
|
"version": "8.18.1",
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz",
|
||||||
"integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
|
"integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10.0.0"
|
"node": ">=10.0.0"
|
||||||
|
@@ -8,6 +8,6 @@
|
|||||||
"axios": "1.7.9",
|
"axios": "1.7.9",
|
||||||
"dotenv": "16.4.7",
|
"dotenv": "16.4.7",
|
||||||
"node-pty": "1.0.0",
|
"node-pty": "1.0.0",
|
||||||
"ws": "8.18.0"
|
"ws": "8.18.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,9 +2,9 @@
|
|||||||
# https://hub.docker.com/r/serversideup/php/tags?name=8.4-fpm-nginx-alpine
|
# https://hub.docker.com/r/serversideup/php/tags?name=8.4-fpm-nginx-alpine
|
||||||
ARG SERVERSIDEUP_PHP_VERSION=8.4-fpm-nginx-alpine
|
ARG SERVERSIDEUP_PHP_VERSION=8.4-fpm-nginx-alpine
|
||||||
# https://github.com/minio/mc/releases
|
# https://github.com/minio/mc/releases
|
||||||
ARG MINIO_VERSION=RELEASE.2024-11-21T17-21-54Z
|
ARG MINIO_VERSION=RELEASE.2025-02-15T10-36-16Z
|
||||||
# https://github.com/cloudflare/cloudflared/releases
|
# https://github.com/cloudflare/cloudflared/releases
|
||||||
ARG CLOUDFLARED_VERSION=2025.1.0
|
ARG CLOUDFLARED_VERSION=2025.2.0
|
||||||
# https://www.postgresql.org/support/versioning/
|
# https://www.postgresql.org/support/versioning/
|
||||||
ARG POSTGRES_VERSION=15
|
ARG POSTGRES_VERSION=15
|
||||||
|
|
||||||
|
@@ -2,9 +2,9 @@
|
|||||||
# https://hub.docker.com/r/serversideup/php/tags?name=8.4-fpm-nginx-alpine
|
# https://hub.docker.com/r/serversideup/php/tags?name=8.4-fpm-nginx-alpine
|
||||||
ARG SERVERSIDEUP_PHP_VERSION=8.4-fpm-nginx-alpine
|
ARG SERVERSIDEUP_PHP_VERSION=8.4-fpm-nginx-alpine
|
||||||
# https://github.com/minio/mc/releases
|
# https://github.com/minio/mc/releases
|
||||||
ARG MINIO_VERSION=RELEASE.2024-11-21T17-21-54Z
|
ARG MINIO_VERSION=RELEASE.2025-02-15T10-36-16Z
|
||||||
# https://github.com/cloudflare/cloudflared/releases
|
# https://github.com/cloudflare/cloudflared/releases
|
||||||
ARG CLOUDFLARED_VERSION=2025.1.0
|
ARG CLOUDFLARED_VERSION=2025.2.0
|
||||||
# https://www.postgresql.org/support/versioning/
|
# https://www.postgresql.org/support/versioning/
|
||||||
ARG POSTGRES_VERSION=15
|
ARG POSTGRES_VERSION=15
|
||||||
|
|
||||||
|
@@ -1,10 +1,10 @@
|
|||||||
# Versions
|
# Versions
|
||||||
# https://download.docker.com/linux/static/stable/
|
# https://download.docker.com/linux/static/stable/
|
||||||
ARG DOCKER_VERSION=27.4.1
|
ARG DOCKER_VERSION=28.0.0
|
||||||
# https://github.com/docker/compose/releases
|
# https://github.com/docker/compose/releases
|
||||||
ARG DOCKER_COMPOSE_VERSION=2.32.2
|
ARG DOCKER_COMPOSE_VERSION=2.33.1
|
||||||
# https://github.com/docker/buildx/releases
|
# https://github.com/docker/buildx/releases
|
||||||
ARG DOCKER_BUILDX_VERSION=0.19.3
|
ARG DOCKER_BUILDX_VERSION=0.21.1
|
||||||
|
|
||||||
|
|
||||||
FROM debian:12-slim
|
FROM debian:12-slim
|
||||||
|
@@ -61,7 +61,7 @@ services:
|
|||||||
retries: 10
|
retries: 10
|
||||||
timeout: 2s
|
timeout: 2s
|
||||||
soketi:
|
soketi:
|
||||||
image: 'ghcr.io/coollabsio/coolify-realtime:1.0.5'
|
image: 'ghcr.io/coollabsio/coolify-realtime:1.0.6'
|
||||||
ports:
|
ports:
|
||||||
- "${SOKETI_PORT:-6001}:6001"
|
- "${SOKETI_PORT:-6001}:6001"
|
||||||
- "6002:6002"
|
- "6002:6002"
|
||||||
|
@@ -1,6 +1,15 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
## Do not modify this file. You will lose the ability to install and auto-update!
|
## Do not modify this file. You will lose the ability to install and auto-update!
|
||||||
|
|
||||||
|
## Environment variables that can be set:
|
||||||
|
## ROOT_USERNAME - Predefined root username
|
||||||
|
## ROOT_USER_EMAIL - Predefined root user email
|
||||||
|
## ROOT_USER_PASSWORD - Predefined root user password
|
||||||
|
## DOCKER_ADDRESS_POOL_BASE - Custom Docker address pool base (default: 10.0.0.0/8)
|
||||||
|
## DOCKER_ADDRESS_POOL_SIZE - Custom Docker address pool size (default: 24)
|
||||||
|
## DOCKER_POOL_FORCE_OVERRIDE - Force override Docker address pool configuration (default: false)
|
||||||
|
## AUTOUPDATE - Set to "false" to disable auto-updates
|
||||||
|
|
||||||
set -e # Exit immediately if a command exits with a non-zero status
|
set -e # Exit immediately if a command exits with a non-zero status
|
||||||
## $1 could be empty, so we need to disable this check
|
## $1 could be empty, so we need to disable this check
|
||||||
#set -u # Treat unset variables as an error and exit
|
#set -u # Treat unset variables as an error and exit
|
||||||
@@ -8,7 +17,7 @@ set -o pipefail # Cause a pipeline to return the status of the last command that
|
|||||||
CDN="https://cdn.coollabs.io/coolify-nightly"
|
CDN="https://cdn.coollabs.io/coolify-nightly"
|
||||||
DATE=$(date +"%Y%m%d-%H%M%S")
|
DATE=$(date +"%Y%m%d-%H%M%S")
|
||||||
|
|
||||||
VERSION="1.7"
|
VERSION="1.8"
|
||||||
DOCKER_VERSION="27.0"
|
DOCKER_VERSION="27.0"
|
||||||
# TODO: Ask for a user
|
# TODO: Ask for a user
|
||||||
CURRENT_USER=$USER
|
CURRENT_USER=$USER
|
||||||
@@ -27,6 +36,144 @@ ROOT_USERNAME=${ROOT_USERNAME:-}
|
|||||||
ROOT_USER_EMAIL=${ROOT_USER_EMAIL:-}
|
ROOT_USER_EMAIL=${ROOT_USER_EMAIL:-}
|
||||||
ROOT_USER_PASSWORD=${ROOT_USER_PASSWORD:-}
|
ROOT_USER_PASSWORD=${ROOT_USER_PASSWORD:-}
|
||||||
|
|
||||||
|
# Docker address pool configuration defaults
|
||||||
|
DOCKER_ADDRESS_POOL_BASE_DEFAULT="10.0.0.0/8"
|
||||||
|
DOCKER_ADDRESS_POOL_SIZE_DEFAULT=24
|
||||||
|
|
||||||
|
# Check if environment variables were explicitly provided
|
||||||
|
DOCKER_POOL_BASE_PROVIDED=false
|
||||||
|
DOCKER_POOL_SIZE_PROVIDED=false
|
||||||
|
DOCKER_POOL_FORCE_OVERRIDE=${DOCKER_POOL_FORCE_OVERRIDE:-false}
|
||||||
|
|
||||||
|
if [ -n "${DOCKER_ADDRESS_POOL_BASE+x}" ]; then
|
||||||
|
DOCKER_POOL_BASE_PROVIDED=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "${DOCKER_ADDRESS_POOL_SIZE+x}" ]; then
|
||||||
|
DOCKER_POOL_SIZE_PROVIDED=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
restart_docker_service() {
|
||||||
|
# Check if systemctl is available
|
||||||
|
if command -v systemctl >/dev/null 2>&1; then
|
||||||
|
systemctl restart docker
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo " - Docker daemon restarted successfully"
|
||||||
|
else
|
||||||
|
echo " - Failed to restart Docker daemon"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
# Check if service command is available
|
||||||
|
elif command -v service >/dev/null 2>&1; then
|
||||||
|
service docker restart
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo " - Docker daemon restarted successfully"
|
||||||
|
else
|
||||||
|
echo " - Failed to restart Docker daemon"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
# If neither systemctl nor service is available
|
||||||
|
else
|
||||||
|
echo " - Error: No service management system found"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to compare address pools
|
||||||
|
compare_address_pools() {
|
||||||
|
local base1="$1"
|
||||||
|
local size1="$2"
|
||||||
|
local base2="$3"
|
||||||
|
local size2="$4"
|
||||||
|
|
||||||
|
# Normalize CIDR notation for comparison
|
||||||
|
local ip1=$(echo "$base1" | cut -d'/' -f1)
|
||||||
|
local prefix1=$(echo "$base1" | cut -d'/' -f2)
|
||||||
|
local ip2=$(echo "$base2" | cut -d'/' -f1)
|
||||||
|
local prefix2=$(echo "$base2" | cut -d'/' -f2)
|
||||||
|
|
||||||
|
# Compare IPs and prefixes
|
||||||
|
if [ "$ip1" = "$ip2" ] && [ "$prefix1" = "$prefix2" ] && [ "$size1" = "$size2" ]; then
|
||||||
|
return 0 # Pools are the same
|
||||||
|
else
|
||||||
|
return 1 # Pools are different
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Docker address pool configuration
|
||||||
|
DOCKER_ADDRESS_POOL_BASE=${DOCKER_ADDRESS_POOL_BASE:-"$DOCKER_ADDRESS_POOL_BASE_DEFAULT"}
|
||||||
|
DOCKER_ADDRESS_POOL_SIZE=${DOCKER_ADDRESS_POOL_SIZE:-$DOCKER_ADDRESS_POOL_SIZE_DEFAULT}
|
||||||
|
|
||||||
|
# Load Docker address pool configuration from .env file if it exists and environment variables were not provided
|
||||||
|
if [ -f "/data/coolify/source/.env" ] && [ "$DOCKER_POOL_BASE_PROVIDED" = false ] && [ "$DOCKER_POOL_SIZE_PROVIDED" = false ]; then
|
||||||
|
ENV_DOCKER_ADDRESS_POOL_BASE=$(grep -E "^DOCKER_ADDRESS_POOL_BASE=" /data/coolify/source/.env | cut -d '=' -f2 || true)
|
||||||
|
ENV_DOCKER_ADDRESS_POOL_SIZE=$(grep -E "^DOCKER_ADDRESS_POOL_SIZE=" /data/coolify/source/.env | cut -d '=' -f2 || true)
|
||||||
|
|
||||||
|
if [ -n "$ENV_DOCKER_ADDRESS_POOL_BASE" ]; then
|
||||||
|
DOCKER_ADDRESS_POOL_BASE="$ENV_DOCKER_ADDRESS_POOL_BASE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$ENV_DOCKER_ADDRESS_POOL_SIZE" ]; then
|
||||||
|
DOCKER_ADDRESS_POOL_SIZE="$ENV_DOCKER_ADDRESS_POOL_SIZE"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if daemon.json exists and extract existing address pool configuration
|
||||||
|
EXISTING_POOL_CONFIGURED=false
|
||||||
|
if [ -f /etc/docker/daemon.json ]; then
|
||||||
|
if jq -e '.["default-address-pools"]' /etc/docker/daemon.json >/dev/null 2>&1; then
|
||||||
|
EXISTING_POOL_BASE=$(jq -r '.["default-address-pools"][0].base' /etc/docker/daemon.json 2>/dev/null || true)
|
||||||
|
EXISTING_POOL_SIZE=$(jq -r '.["default-address-pools"][0].size' /etc/docker/daemon.json 2>/dev/null || true)
|
||||||
|
|
||||||
|
if [ -n "$EXISTING_POOL_BASE" ] && [ -n "$EXISTING_POOL_SIZE" ] && [ "$EXISTING_POOL_BASE" != "null" ] && [ "$EXISTING_POOL_SIZE" != "null" ]; then
|
||||||
|
echo "Found existing Docker network pool: $EXISTING_POOL_BASE/$EXISTING_POOL_SIZE"
|
||||||
|
EXISTING_POOL_CONFIGURED=true
|
||||||
|
|
||||||
|
# Check if environment variables were explicitly provided
|
||||||
|
if [ "$DOCKER_POOL_BASE_PROVIDED" = false ] && [ "$DOCKER_POOL_SIZE_PROVIDED" = false ]; then
|
||||||
|
DOCKER_ADDRESS_POOL_BASE="$EXISTING_POOL_BASE"
|
||||||
|
DOCKER_ADDRESS_POOL_SIZE="$EXISTING_POOL_SIZE"
|
||||||
|
else
|
||||||
|
# Check if force override is enabled
|
||||||
|
if [ "$DOCKER_POOL_FORCE_OVERRIDE" = true ]; then
|
||||||
|
echo "Force override enabled - network pool will be updated with $DOCKER_ADDRESS_POOL_BASE/$DOCKER_ADDRESS_POOL_SIZE."
|
||||||
|
else
|
||||||
|
echo "Custom pool provided but force override not enabled - using existing configuration."
|
||||||
|
echo "To force override, set DOCKER_POOL_FORCE_OVERRIDE=true"
|
||||||
|
echo "This won't change the existing docker networks, only the pool configuration for the newly created networks."
|
||||||
|
DOCKER_ADDRESS_POOL_BASE="$EXISTING_POOL_BASE"
|
||||||
|
DOCKER_ADDRESS_POOL_SIZE="$EXISTING_POOL_SIZE"
|
||||||
|
DOCKER_POOL_BASE_PROVIDED=false
|
||||||
|
DOCKER_POOL_SIZE_PROVIDED=false
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Validate Docker address pool configuration
|
||||||
|
if ! [[ $DOCKER_ADDRESS_POOL_BASE =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/[0-9]+$ ]]; then
|
||||||
|
echo "Warning: Invalid network pool base format: $DOCKER_ADDRESS_POOL_BASE"
|
||||||
|
if [ "$EXISTING_POOL_CONFIGURED" = true ]; then
|
||||||
|
echo "Using existing configuration: $EXISTING_POOL_BASE"
|
||||||
|
DOCKER_ADDRESS_POOL_BASE="$EXISTING_POOL_BASE"
|
||||||
|
else
|
||||||
|
echo "Using default configuration: $DOCKER_ADDRESS_POOL_BASE_DEFAULT"
|
||||||
|
DOCKER_ADDRESS_POOL_BASE="$DOCKER_ADDRESS_POOL_BASE_DEFAULT"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! [[ $DOCKER_ADDRESS_POOL_SIZE =~ ^[0-9]+$ ]] || [ "$DOCKER_ADDRESS_POOL_SIZE" -lt 16 ] || [ "$DOCKER_ADDRESS_POOL_SIZE" -gt 28 ]; then
|
||||||
|
echo "Warning: Invalid network pool size: $DOCKER_ADDRESS_POOL_SIZE (must be 16-28)"
|
||||||
|
if [ "$EXISTING_POOL_CONFIGURED" = true ]; then
|
||||||
|
echo "Using existing configuration: $EXISTING_POOL_SIZE"
|
||||||
|
DOCKER_ADDRESS_POOL_SIZE="$EXISTING_POOL_SIZE"
|
||||||
|
else
|
||||||
|
echo "Using default configuration: $DOCKER_ADDRESS_POOL_SIZE_DEFAULT"
|
||||||
|
DOCKER_ADDRESS_POOL_SIZE=$DOCKER_ADDRESS_POOL_SIZE_DEFAULT
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
TOTAL_SPACE=$(df -BG / | awk 'NR==2 {print $2}' | sed 's/G//')
|
TOTAL_SPACE=$(df -BG / | awk 'NR==2 {print $2}' | sed 's/G//')
|
||||||
AVAILABLE_SPACE=$(df -BG / | awk 'NR==2 {print $4}' | sed 's/G//')
|
AVAILABLE_SPACE=$(df -BG / | awk 'NR==2 {print $4}' | sed 's/G//')
|
||||||
REQUIRED_TOTAL_SPACE=30
|
REQUIRED_TOTAL_SPACE=30
|
||||||
@@ -35,7 +182,7 @@ WARNING_SPACE=false
|
|||||||
|
|
||||||
if [ "$TOTAL_SPACE" -lt "$REQUIRED_TOTAL_SPACE" ]; then
|
if [ "$TOTAL_SPACE" -lt "$REQUIRED_TOTAL_SPACE" ]; then
|
||||||
WARNING_SPACE=true
|
WARNING_SPACE=true
|
||||||
cat << EOF
|
cat <<EOF
|
||||||
WARNING: Insufficient total disk space!
|
WARNING: Insufficient total disk space!
|
||||||
|
|
||||||
Total disk space: ${TOTAL_SPACE}GB
|
Total disk space: ${TOTAL_SPACE}GB
|
||||||
@@ -46,7 +193,7 @@ EOF
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$AVAILABLE_SPACE" -lt "$REQUIRED_AVAILABLE_SPACE" ]; then
|
if [ "$AVAILABLE_SPACE" -lt "$REQUIRED_AVAILABLE_SPACE" ]; then
|
||||||
cat << EOF
|
cat <<EOF
|
||||||
WARNING: Insufficient available disk space!
|
WARNING: Insufficient available disk space!
|
||||||
|
|
||||||
Available disk space: ${AVAILABLE_SPACE}GB
|
Available disk space: ${AVAILABLE_SPACE}GB
|
||||||
@@ -54,7 +201,7 @@ Required available space: ${REQUIRED_AVAILABLE_SPACE}GB
|
|||||||
|
|
||||||
==================
|
==================
|
||||||
EOF
|
EOF
|
||||||
WARNING_SPACE=true
|
WARNING_SPACE=true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$WARNING_SPACE" = true ]; then
|
if [ "$WARNING_SPACE" = true ]; then
|
||||||
@@ -136,7 +283,6 @@ if [ -z "$LATEST_REALTIME_VERSION" ]; then
|
|||||||
LATEST_REALTIME_VERSION=latest
|
LATEST_REALTIME_VERSION=latest
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
case "$OS_TYPE" in
|
case "$OS_TYPE" in
|
||||||
arch | ubuntu | debian | raspbian | centos | fedora | rhel | ol | rocky | sles | opensuse-leap | opensuse-tumbleweed | almalinux | amzn | alpine) ;;
|
arch | ubuntu | debian | raspbian | centos | fedora | rhel | ol | rocky | sles | opensuse-leap | opensuse-tumbleweed | almalinux | amzn | alpine) ;;
|
||||||
*)
|
*)
|
||||||
@@ -152,14 +298,13 @@ if [ "$1" != "" ]; then
|
|||||||
LATEST_VERSION="${LATEST_VERSION#v}"
|
LATEST_VERSION="${LATEST_VERSION#v}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
echo -e "---------------------------------------------"
|
echo -e "---------------------------------------------"
|
||||||
echo "| Operating System | $OS_TYPE $OS_VERSION"
|
echo "| Operating System | $OS_TYPE $OS_VERSION"
|
||||||
echo "| Docker | $DOCKER_VERSION"
|
echo "| Docker | $DOCKER_VERSION"
|
||||||
echo "| Coolify | $LATEST_VERSION"
|
echo "| Coolify | $LATEST_VERSION"
|
||||||
echo "| Helper | $LATEST_HELPER_VERSION"
|
echo "| Helper | $LATEST_HELPER_VERSION"
|
||||||
echo "| Realtime | $LATEST_REALTIME_VERSION"
|
echo "| Realtime | $LATEST_REALTIME_VERSION"
|
||||||
|
echo "| Docker Pool | $DOCKER_ADDRESS_POOL_BASE (size $DOCKER_ADDRESS_POOL_SIZE)"
|
||||||
echo -e "---------------------------------------------\n"
|
echo -e "---------------------------------------------\n"
|
||||||
echo -e "1. Installing required packages (curl, wget, git, jq, openssl). "
|
echo -e "1. Installing required packages (curl, wget, git, jq, openssl). "
|
||||||
|
|
||||||
@@ -199,7 +344,6 @@ sles | opensuse-leap | opensuse-tumbleweed)
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
|
||||||
echo -e "2. Check OpenSSH server configuration. "
|
echo -e "2. Check OpenSSH server configuration. "
|
||||||
|
|
||||||
# Detect OpenSSH server
|
# Detect OpenSSH server
|
||||||
@@ -222,7 +366,6 @@ elif [ -x "$(command -v service)" ]; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
if [ "$SSH_DETECTED" = "false" ]; then
|
if [ "$SSH_DETECTED" = "false" ]; then
|
||||||
echo " - OpenSSH server not detected. Installing OpenSSH server."
|
echo " - OpenSSH server not detected. Installing OpenSSH server."
|
||||||
case "$OS_TYPE" in
|
case "$OS_TYPE" in
|
||||||
@@ -288,86 +431,112 @@ if [ -x "$(command -v snap)" ]; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
install_docker() {
|
||||||
|
curl -s https://releases.rancher.com/install-docker/${DOCKER_VERSION}.sh | sh 2>&1
|
||||||
|
if ! [ -x "$(command -v docker)" ]; then
|
||||||
|
curl -s https://get.docker.com | sh -s -- --version ${DOCKER_VERSION} 2>&1
|
||||||
|
if ! [ -x "$(command -v docker)" ]; then
|
||||||
|
echo " - Docker installation failed."
|
||||||
|
echo " Maybe your OS is not supported?"
|
||||||
|
echo " - Please visit https://docs.docker.com/engine/install/ and install Docker manually to continue."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
echo -e "3. Check Docker Installation. "
|
echo -e "3. Check Docker Installation. "
|
||||||
if ! [ -x "$(command -v docker)" ]; then
|
if ! [ -x "$(command -v docker)" ]; then
|
||||||
echo " - Docker is not installed. Installing Docker. It may take a while."
|
echo " - Docker is not installed. Installing Docker. It may take a while."
|
||||||
getAJoke
|
getAJoke
|
||||||
case "$OS_TYPE" in
|
case "$OS_TYPE" in
|
||||||
"almalinux")
|
"almalinux")
|
||||||
dnf config-manager --add-repo=https://download.docker.com/linux/centos/docker-ce.repo >/dev/null 2>&1
|
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
|
dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin >/dev/null 2>&1
|
||||||
|
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
|
||||||
|
systemctl start docker >/dev/null 2>&1
|
||||||
|
systemctl enable docker >/dev/null 2>&1
|
||||||
|
;;
|
||||||
|
"alpine")
|
||||||
|
apk add docker docker-cli-compose >/dev/null 2>&1
|
||||||
|
rc-update add docker default >/dev/null 2>&1
|
||||||
|
service docker start >/dev/null 2>&1
|
||||||
|
if ! [ -x "$(command -v docker)" ]; then
|
||||||
|
echo " - Failed to install Docker with apk. Try to install it manually."
|
||||||
|
echo " Please visit https://wiki.alpinelinux.org/wiki/Docker for more information."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
"arch")
|
||||||
|
pacman -Sy docker docker-compose --noconfirm >/dev/null 2>&1
|
||||||
|
systemctl enable docker.service >/dev/null 2>&1
|
||||||
|
if ! [ -x "$(command -v docker)" ]; then
|
||||||
|
echo " - Failed to install Docker with pacman. Try to install it manually."
|
||||||
|
echo " Please visit https://wiki.archlinux.org/title/docker for more information."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
"amzn")
|
||||||
|
dnf install docker -y >/dev/null 2>&1
|
||||||
|
DOCKER_CONFIG=${DOCKER_CONFIG:-/usr/local/lib/docker}
|
||||||
|
mkdir -p $DOCKER_CONFIG/cli-plugins >/dev/null 2>&1
|
||||||
|
curl -sL https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m) -o $DOCKER_CONFIG/cli-plugins/docker-compose >/dev/null 2>&1
|
||||||
|
chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose >/dev/null 2>&1
|
||||||
|
systemctl start docker >/dev/null 2>&1
|
||||||
|
systemctl enable docker >/dev/null 2>&1
|
||||||
|
if ! [ -x "$(command -v docker)" ]; then
|
||||||
|
echo " - Failed to install Docker with dnf. Try to install it manually."
|
||||||
|
echo " Please visit https://www.cyberciti.biz/faq/how-to-install-docker-on-amazon-linux-2/ for more information."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
"centos" | "fedora" | "rhel")
|
||||||
|
if [ -x "$(command -v dnf5)" ]; then
|
||||||
|
# dnf5 is available
|
||||||
|
dnf config-manager addrepo --from-repofile=https://download.docker.com/linux/$OS_TYPE/docker-ce.repo --overwrite >/dev/null 2>&1
|
||||||
|
else
|
||||||
|
# dnf5 is not available, use dnf
|
||||||
|
dnf config-manager --add-repo=https://download.docker.com/linux/$OS_TYPE/docker-ce.repo >/dev/null 2>&1
|
||||||
|
fi
|
||||||
|
dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin >/dev/null 2>&1
|
||||||
|
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
|
||||||
|
systemctl start docker >/dev/null 2>&1
|
||||||
|
systemctl enable docker >/dev/null 2>&1
|
||||||
|
;;
|
||||||
|
"ubuntu" | "debian" | "raspbian")
|
||||||
|
if [ "$OS_TYPE" = "ubuntu" ] && [ "$OS_VERSION" = "24.10" ]; then
|
||||||
|
echo " - Installing Docker for Ubuntu 24.10..."
|
||||||
|
apt-get update >/dev/null
|
||||||
|
apt-get install -y ca-certificates curl >/dev/null
|
||||||
|
install -m 0755 -d /etc/apt/keyrings
|
||||||
|
curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
|
||||||
|
chmod a+r /etc/apt/keyrings/docker.asc
|
||||||
|
|
||||||
|
# Add the repository to Apt sources
|
||||||
|
echo \
|
||||||
|
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
|
||||||
|
$(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" |
|
||||||
|
tee /etc/apt/sources.list.d/docker.list >/dev/null
|
||||||
|
apt-get update >/dev/null
|
||||||
|
apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin >/dev/null
|
||||||
|
|
||||||
if ! [ -x "$(command -v docker)" ]; then
|
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."
|
echo " - Docker installation failed."
|
||||||
|
echo " Please visit https://docs.docker.com/engine/install/ubuntu/ and install Docker manually to continue."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
systemctl start docker >/dev/null 2>&1
|
echo " - Docker installed successfully for Ubuntu 24.10."
|
||||||
systemctl enable docker >/dev/null 2>&1
|
else
|
||||||
;;
|
install_docker
|
||||||
"alpine")
|
fi
|
||||||
apk add docker docker-cli-compose >/dev/null 2>&1
|
;;
|
||||||
rc-update add docker default >/dev/null 2>&1
|
*)
|
||||||
service docker start >/dev/null 2>&1
|
install_docker
|
||||||
if ! [ -x "$(command -v docker)" ]; then
|
;;
|
||||||
echo " - Failed to install Docker with apk. Try to install it manually."
|
|
||||||
echo " Please visit https://wiki.alpinelinux.org/wiki/Docker for more information."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
"arch")
|
|
||||||
pacman -Sy docker docker-compose --noconfirm >/dev/null 2>&1
|
|
||||||
systemctl enable docker.service >/dev/null 2>&1
|
|
||||||
if ! [ -x "$(command -v docker)" ]; then
|
|
||||||
echo " - Failed to install Docker with pacman. Try to install it manually."
|
|
||||||
echo " Please visit https://wiki.archlinux.org/title/docker for more information."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
"amzn")
|
|
||||||
dnf install docker -y >/dev/null 2>&1
|
|
||||||
DOCKER_CONFIG=${DOCKER_CONFIG:-/usr/local/lib/docker}
|
|
||||||
mkdir -p $DOCKER_CONFIG/cli-plugins >/dev/null 2>&1
|
|
||||||
curl -sL https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m) -o $DOCKER_CONFIG/cli-plugins/docker-compose >/dev/null 2>&1
|
|
||||||
chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose >/dev/null 2>&1
|
|
||||||
systemctl start docker >/dev/null 2>&1
|
|
||||||
systemctl enable docker >/dev/null 2>&1
|
|
||||||
if ! [ -x "$(command -v docker)" ]; then
|
|
||||||
echo " - Failed to install Docker with dnf. Try to install it manually."
|
|
||||||
echo " Please visit https://www.cyberciti.biz/faq/how-to-install-docker-on-amazon-linux-2/ for more information."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
"fedora")
|
|
||||||
if [ -x "$(command -v dnf5)" ]; then
|
|
||||||
# dnf5 is available
|
|
||||||
dnf config-manager addrepo --from-repofile=https://download.docker.com/linux/fedora/docker-ce.repo --overwrite >/dev/null 2>&1
|
|
||||||
else
|
|
||||||
# dnf5 is not available, use dnf
|
|
||||||
dnf config-manager --add-repo=https://download.docker.com/linux/fedora/docker-ce.repo >/dev/null 2>&1
|
|
||||||
fi
|
|
||||||
dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin >/dev/null 2>&1
|
|
||||||
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
|
|
||||||
systemctl start docker >/dev/null 2>&1
|
|
||||||
systemctl enable docker >/dev/null 2>&1
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
if [ "$OS_TYPE" = "ubuntu" ] && [ "$OS_VERSION" = "24.10" ]; then
|
|
||||||
echo "Docker automated installation is not supported on Ubuntu 24.10 (non-LTS release)."
|
|
||||||
echo "Please install Docker manually."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
curl -s https://releases.rancher.com/install-docker/${DOCKER_VERSION}.sh | sh 2>&1
|
|
||||||
if ! [ -x "$(command -v docker)" ]; then
|
|
||||||
curl -s https://get.docker.com | sh -s -- --version ${DOCKER_VERSION} 2>&1
|
|
||||||
if ! [ -x "$(command -v docker)" ]; then
|
|
||||||
echo " - Docker installation failed."
|
|
||||||
echo " Maybe your OS is not supported?"
|
|
||||||
echo " - Please visit https://docs.docker.com/engine/install/ and install Docker manually to continue."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
esac
|
esac
|
||||||
echo " - Docker installed successfully."
|
echo " - Docker installed successfully."
|
||||||
else
|
else
|
||||||
@@ -375,82 +544,132 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
echo -e "4. Check Docker Configuration. "
|
echo -e "4. Check Docker Configuration. "
|
||||||
|
|
||||||
|
echo " - Network pool configuration: ${DOCKER_ADDRESS_POOL_BASE}/${DOCKER_ADDRESS_POOL_SIZE}"
|
||||||
|
echo " - To override existing configuration: DOCKER_POOL_FORCE_OVERRIDE=true"
|
||||||
|
|
||||||
mkdir -p /etc/docker
|
mkdir -p /etc/docker
|
||||||
# shellcheck disable=SC2015
|
|
||||||
test -s /etc/docker/daemon.json && cp /etc/docker/daemon.json /etc/docker/daemon.json.original-"$DATE" || cat >/etc/docker/daemon.json <<EOL
|
# Backup original daemon.json if it exists
|
||||||
{
|
if [ -f /etc/docker/daemon.json ]; then
|
||||||
"log-driver": "json-file",
|
cp /etc/docker/daemon.json /etc/docker/daemon.json.original-"$DATE"
|
||||||
"log-opts": {
|
|
||||||
"max-size": "10m",
|
|
||||||
"max-file": "3"
|
|
||||||
},
|
|
||||||
"default-address-pools": [
|
|
||||||
{"base":"10.0.0.0/8","size":24}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
EOL
|
|
||||||
cat >/etc/docker/daemon.json.coolify <<EOL
|
|
||||||
{
|
|
||||||
"log-driver": "json-file",
|
|
||||||
"log-opts": {
|
|
||||||
"max-size": "10m",
|
|
||||||
"max-file": "3"
|
|
||||||
},
|
|
||||||
"default-address-pools": [
|
|
||||||
{"base":"10.0.0.0/8","size":24}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
EOL
|
|
||||||
TEMP_FILE=$(mktemp)
|
|
||||||
if ! jq -s '.[0] * .[1]' /etc/docker/daemon.json /etc/docker/daemon.json.coolify >"$TEMP_FILE"; then
|
|
||||||
echo "Error merging JSON files"
|
|
||||||
exit 1
|
|
||||||
fi
|
fi
|
||||||
mv "$TEMP_FILE" /etc/docker/daemon.json
|
|
||||||
|
|
||||||
restart_docker_service() {
|
# Create coolify configuration with or without address pools based on whether they were explicitly provided
|
||||||
# Check if systemctl is available
|
if [ "$DOCKER_POOL_FORCE_OVERRIDE" = true ] || [ "$EXISTING_POOL_CONFIGURED" = false ]; then
|
||||||
if command -v systemctl >/dev/null 2>&1; then
|
# First check if the configuration would actually change anything
|
||||||
echo " - Using systemctl to restart Docker."
|
if [ -f /etc/docker/daemon.json ]; then
|
||||||
systemctl restart docker
|
CURRENT_POOL_BASE=$(jq -r '.["default-address-pools"][0].base' /etc/docker/daemon.json 2>/dev/null)
|
||||||
|
CURRENT_POOL_SIZE=$(jq -r '.["default-address-pools"][0].size' /etc/docker/daemon.json 2>/dev/null)
|
||||||
|
|
||||||
if [ $? -eq 0 ]; then
|
if [ "$CURRENT_POOL_BASE" = "$DOCKER_ADDRESS_POOL_BASE" ] && [ "$CURRENT_POOL_SIZE" = "$DOCKER_ADDRESS_POOL_SIZE" ]; then
|
||||||
echo " - Docker restarted successfully using systemctl."
|
echo " - Network pool configuration unchanged, skipping update"
|
||||||
|
NEED_MERGE=false
|
||||||
else
|
else
|
||||||
echo " - Failed to restart Docker using systemctl."
|
# If force override is enabled or no existing configuration exists,
|
||||||
return 1
|
# create a new configuration with the specified address pools
|
||||||
fi
|
echo " - Creating new Docker configuration with network pool: ${DOCKER_ADDRESS_POOL_BASE}/${DOCKER_ADDRESS_POOL_SIZE}"
|
||||||
|
cat >/etc/docker/daemon.json <<EOL
|
||||||
# Check if service command is available
|
{
|
||||||
elif command -v service >/dev/null 2>&1; then
|
"log-driver": "json-file",
|
||||||
echo " - Using service command to restart Docker."
|
"log-opts": {
|
||||||
service docker restart
|
"max-size": "10m",
|
||||||
|
"max-file": "3"
|
||||||
if [ $? -eq 0 ]; then
|
},
|
||||||
echo " - Docker restarted successfully using service."
|
"default-address-pools": [
|
||||||
else
|
{"base":"${DOCKER_ADDRESS_POOL_BASE}","size":${DOCKER_ADDRESS_POOL_SIZE}}
|
||||||
echo " - Failed to restart Docker using service."
|
]
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# If neither systemctl nor service is available
|
|
||||||
else
|
|
||||||
echo " - Neither systemctl nor service command is available on this system."
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
EOL
|
||||||
if [ -s /etc/docker/daemon.json.original-"$DATE" ]; then
|
NEED_MERGE=true
|
||||||
DIFF=$(diff <(jq --sort-keys . /etc/docker/daemon.json) <(jq --sort-keys . /etc/docker/daemon.json.original-"$DATE"))
|
fi
|
||||||
if [ "$DIFF" != "" ]; then
|
|
||||||
echo " - Docker configuration updated, restart docker daemon..."
|
|
||||||
restart_docker_service
|
|
||||||
else
|
else
|
||||||
echo " - Docker configuration is up to date."
|
# No existing configuration, create new one
|
||||||
|
echo " - Creating new Docker configuration with network pool: ${DOCKER_ADDRESS_POOL_BASE}/${DOCKER_ADDRESS_POOL_SIZE}"
|
||||||
|
cat >/etc/docker/daemon.json <<EOL
|
||||||
|
{
|
||||||
|
"log-driver": "json-file",
|
||||||
|
"log-opts": {
|
||||||
|
"max-size": "10m",
|
||||||
|
"max-file": "3"
|
||||||
|
},
|
||||||
|
"default-address-pools": [
|
||||||
|
{"base":"${DOCKER_ADDRESS_POOL_BASE}","size":${DOCKER_ADDRESS_POOL_SIZE}}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
EOL
|
||||||
|
NEED_MERGE=true
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo " - Docker configuration updated, restart docker daemon..."
|
# Check if we need to update log settings
|
||||||
restart_docker_service
|
if [ -f /etc/docker/daemon.json ] && jq -e '.["log-driver"] == "json-file" and .["log-opts"]["max-size"] == "10m" and .["log-opts"]["max-file"] == "3"' /etc/docker/daemon.json >/dev/null 2>&1; then
|
||||||
|
echo " - Log configuration is up to date"
|
||||||
|
NEED_MERGE=false
|
||||||
|
else
|
||||||
|
# Create a configuration without address pools to preserve existing ones
|
||||||
|
cat >/etc/docker/daemon.json.coolify <<EOL
|
||||||
|
{
|
||||||
|
"log-driver": "json-file",
|
||||||
|
"log-opts": {
|
||||||
|
"max-size": "10m",
|
||||||
|
"max-file": "3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOL
|
||||||
|
NEED_MERGE=true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Remove the duplicate daemon.json creation since we handle it above
|
||||||
|
if ! [ -f /etc/docker/daemon.json ]; then
|
||||||
|
# If no daemon.json exists, create it with default settings
|
||||||
|
cat >/etc/docker/daemon.json <<EOL
|
||||||
|
{
|
||||||
|
"log-driver": "json-file",
|
||||||
|
"log-opts": {
|
||||||
|
"max-size": "10m",
|
||||||
|
"max-file": "3"
|
||||||
|
},
|
||||||
|
"default-address-pools": [
|
||||||
|
{"base":"${DOCKER_ADDRESS_POOL_BASE}","size":${DOCKER_ADDRESS_POOL_SIZE}}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
EOL
|
||||||
|
NEED_MERGE=false
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -s /etc/docker/daemon.json.original-"$DATE" ]; then
|
||||||
|
DIFF=$(diff <(jq --sort-keys . /etc/docker/daemon.json) <(jq --sort-keys . /etc/docker/daemon.json.original-"$DATE") || true)
|
||||||
|
if [ "$DIFF" != "" ]; then
|
||||||
|
echo " - Checking configuration changes..."
|
||||||
|
|
||||||
|
# Check if address pools were changed
|
||||||
|
if echo "$DIFF" | grep -q "default-address-pools"; then
|
||||||
|
if [ "$DOCKER_POOL_BASE_PROVIDED" = true ] || [ "$DOCKER_POOL_SIZE_PROVIDED" = true ]; then
|
||||||
|
echo " - Network pool updated per user request"
|
||||||
|
else
|
||||||
|
echo " - Warning: Network pool modified without explicit request"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Remove this redundant restart since we already restarted when writing the config
|
||||||
|
echo " - Configuration changes confirmed"
|
||||||
|
if [ "$NEED_MERGE" = true ]; then
|
||||||
|
echo " - Configuration updated - restarting Docker daemon..."
|
||||||
|
restart_docker_service
|
||||||
|
else
|
||||||
|
echo " - Configuration is up to date"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo " - Configuration is up to date"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [ "$NEED_MERGE" = true ]; then
|
||||||
|
echo " - Configuration updated - restarting Docker daemon..."
|
||||||
|
restart_docker_service
|
||||||
|
else
|
||||||
|
echo " - Configuration is up to date"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo -e "5. Download required files from CDN. "
|
echo -e "5. Download required files from CDN. "
|
||||||
@@ -501,7 +720,7 @@ fi
|
|||||||
|
|
||||||
# Merge .env and .env.production. New values will be added to .env
|
# Merge .env and .env.production. New values will be added to .env
|
||||||
echo -e "7. Propagating .env with new values - if necessary."
|
echo -e "7. Propagating .env with new values - if necessary."
|
||||||
awk -F '=' '!seen[$1]++' "$ENV_FILE-$DATE" /data/coolify/source/.env.production > $ENV_FILE
|
awk -F '=' '!seen[$1]++' "$ENV_FILE-$DATE" /data/coolify/source/.env.production >$ENV_FILE
|
||||||
|
|
||||||
if [ "$AUTOUPDATE" = "false" ]; then
|
if [ "$AUTOUPDATE" = "false" ]; then
|
||||||
if ! grep -q "AUTOUPDATE=" /data/coolify/source/.env; then
|
if ! grep -q "AUTOUPDATE=" /data/coolify/source/.env; then
|
||||||
@@ -510,6 +729,26 @@ if [ "$AUTOUPDATE" = "false" ]; then
|
|||||||
sed -i "s|AUTOUPDATE=.*|AUTOUPDATE=false|g" /data/coolify/source/.env
|
sed -i "s|AUTOUPDATE=.*|AUTOUPDATE=false|g" /data/coolify/source/.env
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Save Docker address pool configuration to .env file
|
||||||
|
if ! grep -q "DOCKER_ADDRESS_POOL_BASE=" /data/coolify/source/.env; then
|
||||||
|
echo "DOCKER_ADDRESS_POOL_BASE=$DOCKER_ADDRESS_POOL_BASE" >>/data/coolify/source/.env
|
||||||
|
else
|
||||||
|
# Only update if explicitly provided
|
||||||
|
if [ "$DOCKER_POOL_BASE_PROVIDED" = true ]; then
|
||||||
|
sed -i "s|DOCKER_ADDRESS_POOL_BASE=.*|DOCKER_ADDRESS_POOL_BASE=$DOCKER_ADDRESS_POOL_BASE|g" /data/coolify/source/.env
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! grep -q "DOCKER_ADDRESS_POOL_SIZE=" /data/coolify/source/.env; then
|
||||||
|
echo "DOCKER_ADDRESS_POOL_SIZE=$DOCKER_ADDRESS_POOL_SIZE" >>/data/coolify/source/.env
|
||||||
|
else
|
||||||
|
# Only update if explicitly provided
|
||||||
|
if [ "$DOCKER_POOL_SIZE_PROVIDED" = true ]; then
|
||||||
|
sed -i "s|DOCKER_ADDRESS_POOL_SIZE=.*|DOCKER_ADDRESS_POOL_SIZE=$DOCKER_ADDRESS_POOL_SIZE|g" /data/coolify/source/.env
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
echo -e "8. Checking for SSH key for localhost access."
|
echo -e "8. Checking for SSH key for localhost access."
|
||||||
if [ ! -f ~/.ssh/authorized_keys ]; then
|
if [ ! -f ~/.ssh/authorized_keys ]; then
|
||||||
mkdir -p ~/.ssh
|
mkdir -p ~/.ssh
|
||||||
@@ -527,7 +766,7 @@ if [ "$IS_COOLIFY_VOLUME_EXISTS" -eq 0 ]; then
|
|||||||
ssh-keygen -t ed25519 -a 100 -f /data/coolify/ssh/keys/id.$CURRENT_USER@host.docker.internal -q -N "" -C coolify
|
ssh-keygen -t ed25519 -a 100 -f /data/coolify/ssh/keys/id.$CURRENT_USER@host.docker.internal -q -N "" -C coolify
|
||||||
chown 9999 /data/coolify/ssh/keys/id.$CURRENT_USER@host.docker.internal
|
chown 9999 /data/coolify/ssh/keys/id.$CURRENT_USER@host.docker.internal
|
||||||
sed -i "/coolify/d" ~/.ssh/authorized_keys
|
sed -i "/coolify/d" ~/.ssh/authorized_keys
|
||||||
cat /data/coolify/ssh/keys/id.$CURRENT_USER@host.docker.internal.pub >> ~/.ssh/authorized_keys
|
cat /data/coolify/ssh/keys/id.$CURRENT_USER@host.docker.internal.pub >>~/.ssh/authorized_keys
|
||||||
rm -f /data/coolify/ssh/keys/id.$CURRENT_USER@host.docker.internal.pub
|
rm -f /data/coolify/ssh/keys/id.$CURRENT_USER@host.docker.internal.pub
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@@ -1,16 +1,16 @@
|
|||||||
{
|
{
|
||||||
"coolify": {
|
"coolify": {
|
||||||
"v4": {
|
"v4": {
|
||||||
"version": "4.0.0-beta.382"
|
"version": "4.0.0-beta.397"
|
||||||
},
|
},
|
||||||
"nightly": {
|
"nightly": {
|
||||||
"version": "4.0.0-beta.383"
|
"version": "4.0.0-beta.398"
|
||||||
},
|
},
|
||||||
"helper": {
|
"helper": {
|
||||||
"version": "1.0.4"
|
"version": "1.0.7"
|
||||||
},
|
},
|
||||||
"realtime": {
|
"realtime": {
|
||||||
"version": "1.0.5"
|
"version": "1.0.6"
|
||||||
},
|
},
|
||||||
"sentinel": {
|
"sentinel": {
|
||||||
"version": "0.0.15"
|
"version": "0.0.15"
|
||||||
|
369
package-lock.json
generated
369
package-lock.json
generated
@@ -10,19 +10,19 @@
|
|||||||
"@tailwindcss/typography": "0.5.16",
|
"@tailwindcss/typography": "0.5.16",
|
||||||
"@xterm/addon-fit": "^0.10.0",
|
"@xterm/addon-fit": "^0.10.0",
|
||||||
"@xterm/xterm": "^5.5.0",
|
"@xterm/xterm": "^5.5.0",
|
||||||
"ioredis": "5.4.2"
|
"ioredis": "5.5.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vitejs/plugin-vue": "5.2.1",
|
"@vitejs/plugin-vue": "5.2.1",
|
||||||
"autoprefixer": "10.4.20",
|
"autoprefixer": "10.4.20",
|
||||||
"axios": "1.7.9",
|
"axios": "1.7.9",
|
||||||
"laravel-echo": "1.17.1",
|
"laravel-echo": "2.0.2",
|
||||||
"laravel-vite-plugin": "1.1.1",
|
"laravel-vite-plugin": "^1.2.0",
|
||||||
"postcss": "8.4.49",
|
"postcss": "8.5.3",
|
||||||
"pusher-js": "8.4.0-rc2",
|
"pusher-js": "8.4.0",
|
||||||
"tailwind-scrollbar": "^3.1.0",
|
"tailwind-scrollbar": "^3.1.0",
|
||||||
"tailwindcss": "3.4.17",
|
"tailwindcss": "3.4.17",
|
||||||
"vite": "6.0.11",
|
"vite": "^6.1.1",
|
||||||
"vue": "3.5.13"
|
"vue": "3.5.13"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -535,9 +535,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@jridgewell/gen-mapping": {
|
"node_modules/@jridgewell/gen-mapping": {
|
||||||
"version": "0.3.5",
|
"version": "0.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz",
|
||||||
"integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
|
"integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/set-array": "^1.2.1",
|
"@jridgewell/set-array": "^1.2.1",
|
||||||
@@ -586,6 +586,7 @@
|
|||||||
"version": "2.1.5",
|
"version": "2.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||||
"integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
|
"integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nodelib/fs.stat": "2.0.5",
|
"@nodelib/fs.stat": "2.0.5",
|
||||||
"run-parallel": "^1.1.9"
|
"run-parallel": "^1.1.9"
|
||||||
@@ -598,6 +599,7 @@
|
|||||||
"version": "2.0.5",
|
"version": "2.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
|
||||||
"integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
|
"integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
@@ -606,6 +608,7 @@
|
|||||||
"version": "1.2.8",
|
"version": "1.2.8",
|
||||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
|
"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
|
||||||
"integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
|
"integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nodelib/fs.scandir": "2.1.5",
|
"@nodelib/fs.scandir": "2.1.5",
|
||||||
"fastq": "^1.6.0"
|
"fastq": "^1.6.0"
|
||||||
@@ -625,9 +628,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||||
"version": "4.25.0",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.8.tgz",
|
||||||
"integrity": "sha512-CC/ZqFZwlAIbU1wUPisHyV/XRc5RydFrNLtgl3dGYskdwPZdt4HERtKm50a/+DtTlKeCq9IXFEWR+P6blwjqBA==",
|
"integrity": "sha512-q217OSE8DTp8AFHuNHXo0Y86e1wtlfVrXiAlwkIvGRQv9zbc6mE3sjIVfwI8sYUyNxwOg0j/Vm1RKM04JcWLJw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
@@ -639,9 +642,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-android-arm64": {
|
"node_modules/@rollup/rollup-android-arm64": {
|
||||||
"version": "4.25.0",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.8.tgz",
|
||||||
"integrity": "sha512-/Y76tmLGUJqVBXXCfVS8Q8FJqYGhgH4wl4qTA24E9v/IJM0XvJCGQVSW1QZ4J+VURO9h8YCa28sTFacZXwK7Rg==",
|
"integrity": "sha512-Gigjz7mNWaOL9wCggvoK3jEIUUbGul656opstjaUSGC3eT0BM7PofdAJaBfPFWWkXNVAXbaQtC99OCg4sJv70Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -653,9 +656,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-darwin-arm64": {
|
"node_modules/@rollup/rollup-darwin-arm64": {
|
||||||
"version": "4.25.0",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.8.tgz",
|
||||||
"integrity": "sha512-YVT6L3UrKTlC0FpCZd0MGA7NVdp7YNaEqkENbWQ7AOVOqd/7VzyHpgIpc1mIaxRAo1ZsJRH45fq8j4N63I/vvg==",
|
"integrity": "sha512-02rVdZ5tgdUNRxIUrFdcMBZQoaPMrxtwSb+/hOfBdqkatYHR3lZ2A2EGyHq2sGOd0Owk80oV3snlDASC24He3Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -667,9 +670,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-darwin-x64": {
|
"node_modules/@rollup/rollup-darwin-x64": {
|
||||||
"version": "4.25.0",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.8.tgz",
|
||||||
"integrity": "sha512-ZRL+gexs3+ZmmWmGKEU43Bdn67kWnMeWXLFhcVv5Un8FQcx38yulHBA7XR2+KQdYIOtD0yZDWBCudmfj6lQJoA==",
|
"integrity": "sha512-qIP/elwR/tq/dYRx3lgwK31jkZvMiD6qUtOycLhTzCvrjbZ3LjQnEM9rNhSGpbLXVJYQ3rq39A6Re0h9tU2ynw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -681,9 +684,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-freebsd-arm64": {
|
"node_modules/@rollup/rollup-freebsd-arm64": {
|
||||||
"version": "4.25.0",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.8.tgz",
|
||||||
"integrity": "sha512-xpEIXhiP27EAylEpreCozozsxWQ2TJbOLSivGfXhU4G1TBVEYtUPi2pOZBnvGXHyOdLAUUhPnJzH3ah5cqF01g==",
|
"integrity": "sha512-IQNVXL9iY6NniYbTaOKdrlVP3XIqazBgJOVkddzJlqnCpRi/yAeSOa8PLcECFSQochzqApIOE1GHNu3pCz+BDA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -695,9 +698,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-freebsd-x64": {
|
"node_modules/@rollup/rollup-freebsd-x64": {
|
||||||
"version": "4.25.0",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.8.tgz",
|
||||||
"integrity": "sha512-sC5FsmZGlJv5dOcURrsnIK7ngc3Kirnx3as2XU9uER+zjfyqIjdcMVgzy4cOawhsssqzoAX19qmxgJ8a14Qrqw==",
|
"integrity": "sha512-TYXcHghgnCqYFiE3FT5QwXtOZqDj5GmaFNTNt3jNC+vh22dc/ukG2cG+pi75QO4kACohZzidsq7yKTKwq/Jq7Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -709,9 +712,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
||||||
"version": "4.25.0",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.8.tgz",
|
||||||
"integrity": "sha512-uD/dbLSs1BEPzg564TpRAQ/YvTnCds2XxyOndAO8nJhaQcqQGFgv/DAVko/ZHap3boCvxnzYMa3mTkV/B/3SWA==",
|
"integrity": "sha512-A4iphFGNkWRd+5m3VIGuqHnG3MVnqKe7Al57u9mwgbyZ2/xF9Jio72MaY7xxh+Y87VAHmGQr73qoKL9HPbXj1g==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
@@ -723,9 +726,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
||||||
"version": "4.25.0",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.8.tgz",
|
||||||
"integrity": "sha512-ZVt/XkrDlQWegDWrwyC3l0OfAF7yeJUF4fq5RMS07YM72BlSfn2fQQ6lPyBNjt+YbczMguPiJoCfaQC2dnflpQ==",
|
"integrity": "sha512-S0lqKLfTm5u+QTxlFiAnb2J/2dgQqRy/XvziPtDd1rKZFXHTyYLoVL58M/XFwDI01AQCDIevGLbQrMAtdyanpA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
@@ -737,9 +740,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
||||||
"version": "4.25.0",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.8.tgz",
|
||||||
"integrity": "sha512-qboZ+T0gHAW2kkSDPHxu7quaFaaBlynODXpBVnPxUgvWYaE84xgCKAPEYE+fSMd3Zv5PyFZR+L0tCdYCMAtG0A==",
|
"integrity": "sha512-jpz9YOuPiSkL4G4pqKrus0pn9aYwpImGkosRKwNi+sJSkz+WU3anZe6hi73StLOQdfXYXC7hUfsQlTnjMd3s1A==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -751,9 +754,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
||||||
"version": "4.25.0",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.8.tgz",
|
||||||
"integrity": "sha512-ndWTSEmAaKr88dBuogGH2NZaxe7u2rDoArsejNslugHZ+r44NfWiwjzizVS1nUOHo+n1Z6qV3X60rqE/HlISgw==",
|
"integrity": "sha512-KdSfaROOUJXgTVxJNAZ3KwkRc5nggDk+06P6lgi1HLv1hskgvxHUKZ4xtwHkVYJ1Rep4GNo+uEfycCRRxht7+Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -764,10 +767,24 @@
|
|||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
|
||||||
|
"version": "4.34.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.8.tgz",
|
||||||
|
"integrity": "sha512-NyF4gcxwkMFRjgXBM6g2lkT58OWztZvw5KkV2K0qqSnUEqCVcqdh2jN4gQrTn/YUpAcNKyFHfoOZEer9nwo6uQ==",
|
||||||
|
"cpu": [
|
||||||
|
"loong64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
]
|
||||||
|
},
|
||||||
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
|
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
|
||||||
"version": "4.25.0",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.8.tgz",
|
||||||
"integrity": "sha512-BVSQvVa2v5hKwJSy6X7W1fjDex6yZnNKy3Kx1JGimccHft6HV0THTwNtC2zawtNXKUu+S5CjXslilYdKBAadzA==",
|
"integrity": "sha512-LMJc999GkhGvktHU85zNTDImZVUCJ1z/MbAJTnviiWmmjyckP5aQsHtcujMjpNdMZPT2rQEDBlJfubhs3jsMfw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ppc64"
|
"ppc64"
|
||||||
],
|
],
|
||||||
@@ -779,9 +796,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
||||||
"version": "4.25.0",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.8.tgz",
|
||||||
"integrity": "sha512-G4hTREQrIdeV0PE2JruzI+vXdRnaK1pg64hemHq2v5fhv8C7WjVaeXc9P5i4Q5UC06d/L+zA0mszYIKl+wY8oA==",
|
"integrity": "sha512-xAQCAHPj8nJq1PI3z8CIZzXuXCstquz7cIOL73HHdXiRcKk8Ywwqtx2wrIy23EcTn4aZ2fLJNBB8d0tQENPCmw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"riscv64"
|
"riscv64"
|
||||||
],
|
],
|
||||||
@@ -793,9 +810,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
||||||
"version": "4.25.0",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.8.tgz",
|
||||||
"integrity": "sha512-9T/w0kQ+upxdkFL9zPVB6zy9vWW1deA3g8IauJxojN4bnz5FwSsUAD034KpXIVX5j5p/rn6XqumBMxfRkcHapQ==",
|
"integrity": "sha512-DdePVk1NDEuc3fOe3dPPTb+rjMtuFw89gw6gVWxQFAuEqqSdDKnrwzZHrUYdac7A7dXl9Q2Vflxpme15gUWQFA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"s390x"
|
"s390x"
|
||||||
],
|
],
|
||||||
@@ -807,9 +824,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
||||||
"version": "4.25.0",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.8.tgz",
|
||||||
"integrity": "sha512-ThcnU0EcMDn+J4B9LD++OgBYxZusuA7iemIIiz5yzEcFg04VZFzdFjuwPdlURmYPZw+fgVrFzj4CA64jSTG4Ig==",
|
"integrity": "sha512-8y7ED8gjxITUltTUEJLQdgpbPh1sUQ0kMTmufRF/Ns5tI9TNMNlhWtmPKKHCU0SilX+3MJkZ0zERYYGIVBYHIA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -821,9 +838,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-x64-musl": {
|
"node_modules/@rollup/rollup-linux-x64-musl": {
|
||||||
"version": "4.25.0",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.8.tgz",
|
||||||
"integrity": "sha512-zx71aY2oQxGxAT1JShfhNG79PnjYhMC6voAjzpu/xmMjDnKNf6Nl/xv7YaB/9SIa9jDYf8RBPWEnjcdlhlv1rQ==",
|
"integrity": "sha512-SCXcP0ZpGFIe7Ge+McxY5zKxiEI5ra+GT3QRxL0pMMtxPfpyLAKleZODi1zdRHkz5/BhueUrYtYVgubqe9JBNQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -835,9 +852,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
||||||
"version": "4.25.0",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.8.tgz",
|
||||||
"integrity": "sha512-JT8tcjNocMs4CylWY/CxVLnv8e1lE7ff1fi6kbGocWwxDq9pj30IJ28Peb+Y8yiPNSF28oad42ApJB8oUkwGww==",
|
"integrity": "sha512-YHYsgzZgFJzTRbth4h7Or0m5O74Yda+hLin0irAIobkLQFRQd1qWmnoVfwmKm9TXIZVAD0nZ+GEb2ICicLyCnQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -849,9 +866,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
||||||
"version": "4.25.0",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.8.tgz",
|
||||||
"integrity": "sha512-dRLjLsO3dNOfSN6tjyVlG+Msm4IiZnGkuZ7G5NmpzwF9oOc582FZG05+UdfTbz5Jd4buK/wMb6UeHFhG18+OEg==",
|
"integrity": "sha512-r3NRQrXkHr4uWy5TOjTpTYojR9XmF0j/RYgKCef+Ag46FWUTltm5ziticv8LdNsDMehjJ543x/+TJAek/xBA2w==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ia32"
|
"ia32"
|
||||||
],
|
],
|
||||||
@@ -863,9 +880,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
||||||
"version": "4.25.0",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.8.tgz",
|
||||||
"integrity": "sha512-/RqrIFtLB926frMhZD0a5oDa4eFIbyNEwLLloMTEjmqfwZWXywwVVOVmwTsuyhC9HKkVEZcOOi+KV4U9wmOdlg==",
|
"integrity": "sha512-U0FaE5O1BCpZSeE6gBl3c5ObhePQSfk9vDRToMmTkbhCOgW4jqvtS5LGyQ76L1fH8sM0keRp4uDTsbjiUyjk0g==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -1155,7 +1172,8 @@
|
|||||||
"node_modules/arg": {
|
"node_modules/arg": {
|
||||||
"version": "5.0.2",
|
"version": "5.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
|
||||||
"integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="
|
"integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/asynckit": {
|
"node_modules/asynckit": {
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
@@ -1248,9 +1266,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/browserslist": {
|
"node_modules/browserslist": {
|
||||||
"version": "4.24.2",
|
"version": "4.24.4",
|
||||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz",
|
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz",
|
||||||
"integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==",
|
"integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -1268,9 +1286,9 @@
|
|||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"caniuse-lite": "^1.0.30001669",
|
"caniuse-lite": "^1.0.30001688",
|
||||||
"electron-to-chromium": "^1.5.41",
|
"electron-to-chromium": "^1.5.73",
|
||||||
"node-releases": "^2.0.18",
|
"node-releases": "^2.0.19",
|
||||||
"update-browserslist-db": "^1.1.1"
|
"update-browserslist-db": "^1.1.1"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
@@ -1284,14 +1302,15 @@
|
|||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
|
||||||
"integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
|
"integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/caniuse-lite": {
|
"node_modules/caniuse-lite": {
|
||||||
"version": "1.0.30001680",
|
"version": "1.0.30001700",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001680.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001700.tgz",
|
||||||
"integrity": "sha512-rPQy70G6AGUMnbwS1z6Xg+RkHYPAi18ihs47GH0jcxIG7wArmPgY3XbS2sRdBbxJljp3thdT8BIqv9ccCypiPA==",
|
"integrity": "sha512-2S6XIXwaE7K7erT8dY+kLQcpa5ms63XlRkMkReXjle+kf6c5g38vyMl+Z5y8dSxOFDhcFe+nxnn261PLxBSQsQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -1459,12 +1478,14 @@
|
|||||||
"node_modules/didyoumean": {
|
"node_modules/didyoumean": {
|
||||||
"version": "1.2.2",
|
"version": "1.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
|
||||||
"integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw=="
|
"integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==",
|
||||||
|
"license": "Apache-2.0"
|
||||||
},
|
},
|
||||||
"node_modules/dlv": {
|
"node_modules/dlv": {
|
||||||
"version": "1.1.3",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
|
||||||
"integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="
|
"integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/eastasianwidth": {
|
"node_modules/eastasianwidth": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
@@ -1473,9 +1494,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/electron-to-chromium": {
|
"node_modules/electron-to-chromium": {
|
||||||
"version": "1.5.55",
|
"version": "1.5.103",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.55.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.103.tgz",
|
||||||
"integrity": "sha512-6maZ2ASDOTBtjt9FhqYPRnbvKU5tjG0IN9SztUOWYw2AzNDNpKJYLJmlK0/En4Hs/aiWnB+JZ+gW19PIGszgKg==",
|
"integrity": "sha512-P6+XzIkfndgsrjROJWfSvVEgNHtPgbhVyTkwLjUM2HU/h7pZRORgaTlHqfAikqxKmdJMLW8fftrdGWbd/Ds0FA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
@@ -1557,15 +1578,16 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/fast-glob": {
|
"node_modules/fast-glob": {
|
||||||
"version": "3.3.2",
|
"version": "3.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
|
||||||
"integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
|
"integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nodelib/fs.stat": "^2.0.2",
|
"@nodelib/fs.stat": "^2.0.2",
|
||||||
"@nodelib/fs.walk": "^1.2.3",
|
"@nodelib/fs.walk": "^1.2.3",
|
||||||
"glob-parent": "^5.1.2",
|
"glob-parent": "^5.1.2",
|
||||||
"merge2": "^1.3.0",
|
"merge2": "^1.3.0",
|
||||||
"micromatch": "^4.0.4"
|
"micromatch": "^4.0.8"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8.6.0"
|
"node": ">=8.6.0"
|
||||||
@@ -1575,6 +1597,7 @@
|
|||||||
"version": "5.1.2",
|
"version": "5.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||||
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"is-glob": "^4.0.1"
|
"is-glob": "^4.0.1"
|
||||||
},
|
},
|
||||||
@@ -1583,9 +1606,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/fastq": {
|
"node_modules/fastq": {
|
||||||
"version": "1.15.0",
|
"version": "1.19.0",
|
||||||
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
|
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.0.tgz",
|
||||||
"integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==",
|
"integrity": "sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA==",
|
||||||
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"reusify": "^1.0.4"
|
"reusify": "^1.0.4"
|
||||||
}
|
}
|
||||||
@@ -1656,6 +1680,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz",
|
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz",
|
||||||
"integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==",
|
"integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "*"
|
"node": "*"
|
||||||
},
|
},
|
||||||
@@ -1710,6 +1735,7 @@
|
|||||||
"version": "6.0.2",
|
"version": "6.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
|
||||||
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
|
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
|
||||||
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"is-glob": "^4.0.3"
|
"is-glob": "^4.0.3"
|
||||||
},
|
},
|
||||||
@@ -1729,18 +1755,10 @@
|
|||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/immutable": {
|
|
||||||
"version": "4.3.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.0.tgz",
|
|
||||||
"integrity": "sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg==",
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"peer": true
|
|
||||||
},
|
|
||||||
"node_modules/ioredis": {
|
"node_modules/ioredis": {
|
||||||
"version": "5.4.2",
|
"version": "5.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.5.0.tgz",
|
||||||
"integrity": "sha512-0SZXGNGZ+WzISQ67QDyZ2x0+wVxjjUndtD8oSeik/4ajifeiRufed8fCb8QW8VMyi4MXcS+UO1k/0NGhvq1PAg==",
|
"integrity": "sha512-7CutT89g23FfSa8MDoIFs2GYYa0PaNiW/OrT+nRyjRXHDZd17HmIgy+reOQ/yhh72NznNjGuS8kbCAcA4Ro4mw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ioredis/commands": "^1.1.1",
|
"@ioredis/commands": "^1.1.1",
|
||||||
@@ -1773,9 +1791,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/is-core-module": {
|
"node_modules/is-core-module": {
|
||||||
"version": "2.15.1",
|
"version": "2.16.1",
|
||||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz",
|
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
|
||||||
"integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==",
|
"integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"hasown": "^2.0.2"
|
"hasown": "^2.0.2"
|
||||||
@@ -1854,19 +1872,19 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/laravel-echo": {
|
"node_modules/laravel-echo": {
|
||||||
"version": "1.17.1",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/laravel-echo/-/laravel-echo-1.17.1.tgz",
|
"resolved": "https://registry.npmjs.org/laravel-echo/-/laravel-echo-2.0.2.tgz",
|
||||||
"integrity": "sha512-ORWc4vDfnBj/Oe5ThZ5kYyGItRjLDqAQUyhD/7UhehUOqc+s5x9HEBjtMVludNMP6VuXw6t7Uxt8bp63kaTofg==",
|
"integrity": "sha512-Ciai6hA7r35MFqNRb8G034cvm9WiveSTFQQKRGJhWtZGbng7C8BBa5QvqDxk/Mw5GeJ+q19jrEwQhf7r1b1lcg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=20"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/laravel-vite-plugin": {
|
"node_modules/laravel-vite-plugin": {
|
||||||
"version": "1.1.1",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-1.2.0.tgz",
|
||||||
"integrity": "sha512-HMZXpoSs1OR+7Lw1+g4Iy/s3HF3Ldl8KxxYT2Ot8pEB4XB/QRuZeWgDYJdu552UN03YRSRNK84CLC9NzYRtncA==",
|
"integrity": "sha512-R0pJ+IcTVeqEMoKz/B2Ij57QVq3sFTABiFmb06gAwFdivbOgsUtuhX6N2MGLEArajrS3U5JbberzwOe7uXHMHQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -1946,6 +1964,7 @@
|
|||||||
"version": "1.4.1",
|
"version": "1.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
|
||||||
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
|
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
@@ -1954,6 +1973,7 @@
|
|||||||
"version": "4.0.8",
|
"version": "4.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
|
||||||
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
|
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"braces": "^3.0.3",
|
"braces": "^3.0.3",
|
||||||
"picomatch": "^2.3.1"
|
"picomatch": "^2.3.1"
|
||||||
@@ -2050,9 +2070,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/node-releases": {
|
"node_modules/node-releases": {
|
||||||
"version": "2.0.18",
|
"version": "2.0.19",
|
||||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz",
|
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
|
||||||
"integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==",
|
"integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
@@ -2069,6 +2089,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
|
||||||
"integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==",
|
"integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@@ -2086,6 +2107,7 @@
|
|||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
|
||||||
"integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
|
"integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
@@ -2108,7 +2130,8 @@
|
|||||||
"node_modules/path-parse": {
|
"node_modules/path-parse": {
|
||||||
"version": "1.0.7",
|
"version": "1.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
|
||||||
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
|
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/path-scurry": {
|
"node_modules/path-scurry": {
|
||||||
"version": "1.11.1",
|
"version": "1.11.1",
|
||||||
@@ -2147,6 +2170,7 @@
|
|||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
|
||||||
"integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
|
"integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@@ -2161,9 +2185,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.4.49",
|
"version": "8.5.3",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz",
|
||||||
"integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==",
|
"integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
@@ -2180,7 +2204,7 @@
|
|||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nanoid": "^3.3.7",
|
"nanoid": "^3.3.8",
|
||||||
"picocolors": "^1.1.1",
|
"picocolors": "^1.1.1",
|
||||||
"source-map-js": "^1.2.1"
|
"source-map-js": "^1.2.1"
|
||||||
},
|
},
|
||||||
@@ -2192,6 +2216,7 @@
|
|||||||
"version": "15.1.0",
|
"version": "15.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz",
|
||||||
"integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==",
|
"integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"postcss-value-parser": "^4.0.0",
|
"postcss-value-parser": "^4.0.0",
|
||||||
"read-cache": "^1.0.0",
|
"read-cache": "^1.0.0",
|
||||||
@@ -2208,6 +2233,7 @@
|
|||||||
"version": "4.0.1",
|
"version": "4.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz",
|
||||||
"integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==",
|
"integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"camelcase-css": "^2.0.1"
|
"camelcase-css": "^2.0.1"
|
||||||
},
|
},
|
||||||
@@ -2298,7 +2324,8 @@
|
|||||||
"node_modules/postcss-value-parser": {
|
"node_modules/postcss-value-parser": {
|
||||||
"version": "4.2.0",
|
"version": "4.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
|
||||||
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
|
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/proxy-from-env": {
|
"node_modules/proxy-from-env": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
@@ -2307,10 +2334,11 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/pusher-js": {
|
"node_modules/pusher-js": {
|
||||||
"version": "8.4.0-rc2",
|
"version": "8.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/pusher-js/-/pusher-js-8.4.0-rc2.tgz",
|
"resolved": "https://registry.npmjs.org/pusher-js/-/pusher-js-8.4.0.tgz",
|
||||||
"integrity": "sha512-d87GjOEEl9QgO5BWmViSqW0LOzPvybvX6WA9zLUstNdB57jVJuR27zHkRnrav2a3+zAMlHbP2Og8wug+rG8T+g==",
|
"integrity": "sha512-wp3HqIIUc1GRyu1XrP6m2dgyE9MoCsXVsWNlohj0rjSkLf+a0jLvEyVubdg58oMk7bhjBWnFClgp8jfAa6Ak4Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tweetnacl": "^1.0.3"
|
"tweetnacl": "^1.0.3"
|
||||||
}
|
}
|
||||||
@@ -2332,12 +2360,14 @@
|
|||||||
"type": "consulting",
|
"type": "consulting",
|
||||||
"url": "https://feross.org/support"
|
"url": "https://feross.org/support"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/read-cache": {
|
"node_modules/read-cache": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
||||||
"integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
|
"integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"pify": "^2.3.0"
|
"pify": "^2.3.0"
|
||||||
}
|
}
|
||||||
@@ -2373,18 +2403,21 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/resolve": {
|
"node_modules/resolve": {
|
||||||
"version": "1.22.8",
|
"version": "1.22.10",
|
||||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
|
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
|
||||||
"integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
|
"integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"is-core-module": "^2.13.0",
|
"is-core-module": "^2.16.0",
|
||||||
"path-parse": "^1.0.7",
|
"path-parse": "^1.0.7",
|
||||||
"supports-preserve-symlinks-flag": "^1.0.0"
|
"supports-preserve-symlinks-flag": "^1.0.0"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"resolve": "bin/resolve"
|
"resolve": "bin/resolve"
|
||||||
},
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
@@ -2393,15 +2426,16 @@
|
|||||||
"version": "1.0.4",
|
"version": "1.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
|
||||||
"integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
|
"integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"iojs": ">=1.0.0",
|
"iojs": ">=1.0.0",
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rollup": {
|
"node_modules/rollup": {
|
||||||
"version": "4.25.0",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.34.8.tgz",
|
||||||
"integrity": "sha512-uVbClXmR6wvx5R1M3Od4utyLUxrmOcEm3pAtMphn73Apq19PDtHpgZoEvqH2YnnaNUuvKmg2DgRd2Sqv+odyqg==",
|
"integrity": "sha512-489gTVMzAYdiZHFVA/ig/iYFllCcWFHMvUHI1rpFmkoUtRlQxqh6/yiNqnYibjMZ2b/+FUQwldG+aLsEt6bglQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -2415,24 +2449,25 @@
|
|||||||
"npm": ">=8.0.0"
|
"npm": ">=8.0.0"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@rollup/rollup-android-arm-eabi": "4.25.0",
|
"@rollup/rollup-android-arm-eabi": "4.34.8",
|
||||||
"@rollup/rollup-android-arm64": "4.25.0",
|
"@rollup/rollup-android-arm64": "4.34.8",
|
||||||
"@rollup/rollup-darwin-arm64": "4.25.0",
|
"@rollup/rollup-darwin-arm64": "4.34.8",
|
||||||
"@rollup/rollup-darwin-x64": "4.25.0",
|
"@rollup/rollup-darwin-x64": "4.34.8",
|
||||||
"@rollup/rollup-freebsd-arm64": "4.25.0",
|
"@rollup/rollup-freebsd-arm64": "4.34.8",
|
||||||
"@rollup/rollup-freebsd-x64": "4.25.0",
|
"@rollup/rollup-freebsd-x64": "4.34.8",
|
||||||
"@rollup/rollup-linux-arm-gnueabihf": "4.25.0",
|
"@rollup/rollup-linux-arm-gnueabihf": "4.34.8",
|
||||||
"@rollup/rollup-linux-arm-musleabihf": "4.25.0",
|
"@rollup/rollup-linux-arm-musleabihf": "4.34.8",
|
||||||
"@rollup/rollup-linux-arm64-gnu": "4.25.0",
|
"@rollup/rollup-linux-arm64-gnu": "4.34.8",
|
||||||
"@rollup/rollup-linux-arm64-musl": "4.25.0",
|
"@rollup/rollup-linux-arm64-musl": "4.34.8",
|
||||||
"@rollup/rollup-linux-powerpc64le-gnu": "4.25.0",
|
"@rollup/rollup-linux-loongarch64-gnu": "4.34.8",
|
||||||
"@rollup/rollup-linux-riscv64-gnu": "4.25.0",
|
"@rollup/rollup-linux-powerpc64le-gnu": "4.34.8",
|
||||||
"@rollup/rollup-linux-s390x-gnu": "4.25.0",
|
"@rollup/rollup-linux-riscv64-gnu": "4.34.8",
|
||||||
"@rollup/rollup-linux-x64-gnu": "4.25.0",
|
"@rollup/rollup-linux-s390x-gnu": "4.34.8",
|
||||||
"@rollup/rollup-linux-x64-musl": "4.25.0",
|
"@rollup/rollup-linux-x64-gnu": "4.34.8",
|
||||||
"@rollup/rollup-win32-arm64-msvc": "4.25.0",
|
"@rollup/rollup-linux-x64-musl": "4.34.8",
|
||||||
"@rollup/rollup-win32-ia32-msvc": "4.25.0",
|
"@rollup/rollup-win32-arm64-msvc": "4.34.8",
|
||||||
"@rollup/rollup-win32-x64-msvc": "4.25.0",
|
"@rollup/rollup-win32-ia32-msvc": "4.34.8",
|
||||||
|
"@rollup/rollup-win32-x64-msvc": "4.34.8",
|
||||||
"fsevents": "~2.3.2"
|
"fsevents": "~2.3.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2454,29 +2489,11 @@
|
|||||||
"url": "https://feross.org/support"
|
"url": "https://feross.org/support"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"queue-microtask": "^1.2.2"
|
"queue-microtask": "^1.2.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/sass": {
|
|
||||||
"version": "1.62.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.62.1.tgz",
|
|
||||||
"integrity": "sha512-NHpxIzN29MXvWiuswfc1W3I0N8SXBd8UR26WntmDlRYf0bSADnwnOjsyMZ3lMezSlArD33Vs3YFhp7dWvL770A==",
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
|
||||||
"chokidar": ">=3.0.0 <4.0.0",
|
|
||||||
"immutable": "^4.0.0",
|
|
||||||
"source-map-js": ">=0.6.2 <2.0.0"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"sass": "sass.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=14.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/shebang-command": {
|
"node_modules/shebang-command": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||||
@@ -2646,6 +2663,7 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
|
||||||
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
|
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
},
|
},
|
||||||
@@ -2748,9 +2766,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/update-browserslist-db": {
|
"node_modules/update-browserslist-db": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.2.tgz",
|
||||||
"integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==",
|
"integrity": "sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -2769,7 +2787,7 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"escalade": "^3.2.0",
|
"escalade": "^3.2.0",
|
||||||
"picocolors": "^1.1.0"
|
"picocolors": "^1.1.1"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"update-browserslist-db": "cli.js"
|
"update-browserslist-db": "cli.js"
|
||||||
@@ -2784,15 +2802,15 @@
|
|||||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
||||||
},
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "6.0.11",
|
"version": "6.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-6.0.11.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-6.1.1.tgz",
|
||||||
"integrity": "sha512-4VL9mQPKoHy4+FE0NnRE/kbY51TOfaknxAjt3fJbGJxhIpBZiqVzlZDEesWWsuREXHwNdAoOFZ9MkPEVXczHwg==",
|
"integrity": "sha512-4GgM54XrwRfrOp297aIYspIti66k56v16ZnqHvrIM7mG+HjDlAwS7p+Srr7J6fGvEdOJ5JcQ/D9T7HhtdXDTzA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "^0.24.2",
|
"esbuild": "^0.24.2",
|
||||||
"postcss": "^8.4.49",
|
"postcss": "^8.5.2",
|
||||||
"rollup": "^4.23.0"
|
"rollup": "^4.30.1"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"vite": "bin/vite.js"
|
"vite": "bin/vite.js"
|
||||||
@@ -2856,10 +2874,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vite-plugin-full-reload": {
|
"node_modules/vite-plugin-full-reload": {
|
||||||
"version": "1.1.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/vite-plugin-full-reload/-/vite-plugin-full-reload-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/vite-plugin-full-reload/-/vite-plugin-full-reload-1.2.0.tgz",
|
||||||
"integrity": "sha512-3cObNDzX6DdfhD9E7kf6w2mNunFpD7drxyNgHLw+XwIYAgb+Xt16SEXo0Up4VH+TMf3n+DSVJZtW2POBGcBYAA==",
|
"integrity": "sha512-kz18NW79x0IHbxRSHm0jttP4zoO9P9gXh+n6UTwlNKnviTTEpOlum6oS9SmecrTtSr+muHEn5TUuC75UovQzcA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"picocolors": "^1.0.0",
|
"picocolors": "^1.0.0",
|
||||||
"picomatch": "^2.3.1"
|
"picomatch": "^2.3.1"
|
||||||
|
12
package.json
12
package.json
@@ -10,13 +10,13 @@
|
|||||||
"@vitejs/plugin-vue": "5.2.1",
|
"@vitejs/plugin-vue": "5.2.1",
|
||||||
"autoprefixer": "10.4.20",
|
"autoprefixer": "10.4.20",
|
||||||
"axios": "1.7.9",
|
"axios": "1.7.9",
|
||||||
"laravel-echo": "1.17.1",
|
"laravel-echo": "2.0.2",
|
||||||
"laravel-vite-plugin": "1.1.1",
|
"laravel-vite-plugin": "^1.2.0",
|
||||||
"postcss": "8.4.49",
|
"postcss": "8.5.3",
|
||||||
"pusher-js": "8.4.0-rc2",
|
"pusher-js": "8.4.0",
|
||||||
"tailwind-scrollbar": "^3.1.0",
|
"tailwind-scrollbar": "^3.1.0",
|
||||||
"tailwindcss": "3.4.17",
|
"tailwindcss": "3.4.17",
|
||||||
"vite": "6.0.11",
|
"vite": "^6.1.1",
|
||||||
"vue": "3.5.13"
|
"vue": "3.5.13"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -24,6 +24,6 @@
|
|||||||
"@tailwindcss/typography": "0.5.16",
|
"@tailwindcss/typography": "0.5.16",
|
||||||
"@xterm/addon-fit": "^0.10.0",
|
"@xterm/addon-fit": "^0.10.0",
|
||||||
"@xterm/xterm": "^5.5.0",
|
"@xterm/xterm": "^5.5.0",
|
||||||
"ioredis": "5.4.2"
|
"ioredis": "5.5.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
9
public/coolify-logo.svg
Normal file
9
public/coolify-logo.svg
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg version="1.1" viewBox="0 0 2048 2048" width="512" height="512" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path transform="translate(257,640)" d="m0 0h254l1 1v127h127l1 1v639h895l1 1v127h127l1 1v254l-5 1h-1018l-1-1v-127h-127l-1-1v-127h-127l-1-1v-127h-127l-1-1v-766z" fill="#8550FC"/>
|
||||||
|
<path transform="translate(513,384)" d="m0 0h1022l1 1v127h127l1 1v254l-5 1h-1018l-1-1v-127h-127l-1-1v-254z" fill="#8550FC"/>
|
||||||
|
<path transform="translate(1537,1536)" d="m0 0h126l1 1v254l-5 1h-1018l-1-1v-126l896-1v-29z" fill="#452E72"/>
|
||||||
|
<path transform="translate(1537,512)" d="m0 0h126l1 1v254l-5 1h-1018l-1-1v-126l896-1v-29z" fill="#452E72"/>
|
||||||
|
<path transform="translate(513,768)" d="m0 0h126l1 1v638l-7 1-108-1-12-1z" fill="#452E72"/>
|
||||||
|
<path transform="translate(478,1408)" d="m0 0h32l1 1v127h-126l-1-1v-126z" fill="#452E72"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 853 B |
1
public/svgs/denoKV.svg
Normal file
1
public/svgs/denoKV.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 4410 4410"><circle cx="2200" cy="2200" r="2200" fill="#fff"/><path d="M384 3039a1991 1991 0 0 1-184-839c0-78 4-154 13-229a2007 2007 0 0 1 39-224A2000 2000 0 0 1 871 706a2001 2001 0 0 1 910-462 2004 2004 0 0 1 571-38 1994 1994 0 0 1 680 175 2003 2003 0 0 1 463 295 2004 2004 0 0 1 676 1180 2009 2009 0 0 1 29 344 2025 2025 0 0 1-6 152 1998 1998 0 0 1-121 551 2001 2001 0 0 1-397 646 1035 1035 0 0 1-738 323 722 722 0 0 1-688-910c17-64 62-186 127-240a762 762 0 0 1-205-138c-7-8-6-22 1-31a26 26 0 0 1 29-8 1458 1458 0 0 0 228 58c111 18 248 42 387 48 338 17 692-135 802-437 109-303 67-602-327-781-394-180-576-393-894-522-208-84-439-34-676 98-640 353-1213 1470-949 2505a32 32 0 0 1-52 31 2011 2011 0 0 1-209-272 2003 2003 0 0 1-128-234zm1745-1989c107-8 202 84 218 206 21 163-39 332-235 336-169 3-220-166-208-269 11-103 95-263 224-273z"/></svg>
|
After Width: | Height: | Size: 891 B |
150
public/svgs/wakapi.svg
Normal file
150
public/svgs/wakapi.svg
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="275.9418mm"
|
||||||
|
height="107.06042mm"
|
||||||
|
viewBox="0 0 275.9418 107.06042"
|
||||||
|
version="1.1"
|
||||||
|
id="svg900"
|
||||||
|
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
|
||||||
|
sodipodi:docname="logo-dark-bg.svg">
|
||||||
|
<defs
|
||||||
|
id="defs894">
|
||||||
|
<clipPath
|
||||||
|
clipPathUnits="userSpaceOnUse"
|
||||||
|
id="clipPath20">
|
||||||
|
<path
|
||||||
|
d="M 0,700 H 1100 V 0 H 0 Z"
|
||||||
|
id="path18" />
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="0.35"
|
||||||
|
inkscape:cx="501.46484"
|
||||||
|
inkscape:cy="865.17604"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
inkscape:document-rotation="0"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:window-width="1346"
|
||||||
|
inkscape:window-height="1198"
|
||||||
|
inkscape:window-x="149"
|
||||||
|
inkscape:window-y="113"
|
||||||
|
inkscape:window-maximized="0" />
|
||||||
|
<metadata
|
||||||
|
id="metadata897">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(26.845906,80.744493)">
|
||||||
|
<g
|
||||||
|
id="g14"
|
||||||
|
transform="matrix(0.35277777,0,0,-0.35277777,-100.60779,96.696294)">
|
||||||
|
<g
|
||||||
|
id="g16"
|
||||||
|
clip-path="url(#clipPath20)">
|
||||||
|
<g
|
||||||
|
id="g22"
|
||||||
|
transform="translate(600.9092,345.958)" />
|
||||||
|
<g
|
||||||
|
id="g26"
|
||||||
|
transform="translate(706.707,299.5566)" />
|
||||||
|
<g
|
||||||
|
id="g30"
|
||||||
|
transform="translate(810.2764,345.958)" />
|
||||||
|
<g
|
||||||
|
id="g34"
|
||||||
|
transform="translate(930.5527,345.958)" />
|
||||||
|
<g
|
||||||
|
id="g40"
|
||||||
|
transform="translate(503.8398,367.5195)">
|
||||||
|
<path
|
||||||
|
d="m 8.7266003,-16.286056 c 0,-3.170064 -0.10674,-6.340128 -0.32021,-9.492657 -0.85541,-13.857403 -3.56194,-27.197135 -7.89009005,-39.789715 C -18.95161,-122.31318 -71.13644,-163.86557 -133.5283,-167.69511 c -3.13424,-0.23101 -6.30506,-0.32097 -9.49342,-0.32097 -3.1876,0 -6.33937,0.09 -9.4919,0.32097 -76.24773,4.68419 -137.23296,65.6679 -141.91639,141.916397 -0.23101,3.152529 -0.32098,6.322593 -0.32098,9.492657 0,3.188361 0.09,6.358425 0.32098,9.493419 4.68343,76.22944 65.66866,137.249737 141.91639,141.933927 3.15253,0.21348 6.3043,0.32098 9.4919,0.32098 3.18836,0 6.35918,-0.1075 9.49342,-0.32098 V 94.354359 h -18.98532 V 110.75818 C -215.22645,106.14489 -265.43361,55.901133 -270.06444,-6.792637 h 14.65793 v -18.986076 h -14.65793 c 4.63083,-62.712067 54.83799,-112.920757 117.55082,-117.551577 v 16.72479 h 18.98532 v -16.72479 c 46.32654,3.42013 85.86619,31.73876 105.20907,71.59937 6.83873,14.070117 11.14859,29.584217 12.34251,45.952207 h -0.0358 l 8.8697703,18.986076 h 15.54917 c 0.21347,-3.134994 0.32021,-6.305058 0.32021,-9.493419"
|
||||||
|
style="fill:#2f855a;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.762401"
|
||||||
|
id="path42" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g44"
|
||||||
|
transform="translate(504.2754,431.2373)">
|
||||||
|
<path
|
||||||
|
d="m 11.6231,-31.425333 -17.1029497,8.252992 -4.6666503,-9.703842 -9.61922,-20.006168 -37.98968,-78.855149 -0.0572,-0.0854 h -37.47886 l -0.0282,0.0572 0.0282,0.0854 14.77,30.64853 3.78456,7.85425 0.19898,0.42618 19.2087,39.869009 7.37013,15.25336 2.27653,4.752808 11.72497,24.386926 -5.77672,2.761416 -9.59024,4.638449 49.9708203,23.249422 z"
|
||||||
|
style="fill:#2f855a;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.762401"
|
||||||
|
id="path46" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g48"
|
||||||
|
transform="translate(258.5654,361.2139)">
|
||||||
|
<path
|
||||||
|
d="m 65.50352,-19.287853 v -0.0183 L 46.73396,-58.308305 12.56848,12.654468 2.9523203,32.646912 H 40.49066 l 9.63446,-19.992444 z"
|
||||||
|
style="fill:#2f855a;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.762401"
|
||||||
|
id="path50" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g52"
|
||||||
|
transform="translate(320.9248,367.3867)">
|
||||||
|
<path
|
||||||
|
d="M 52.18699,-16.254503 27.28545,-67.966647 v -0.01906 h -37.57494 v 0.01906 l 18.7870903,39.002155 19.2506297,39.94677 5.65168,11.764611 5.66921,-11.764611 9.2647,-19.232331 z"
|
||||||
|
style="fill:#2f855a;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.762401"
|
||||||
|
id="path54" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g56"
|
||||||
|
transform="translate(383.7656,359.833)">
|
||||||
|
<path
|
||||||
|
d="m 38.75609,-18.959752 -3.78456,-7.854257 -14.7982,-30.591345 -0.0282,-0.08539 -25.2979997,52.560696 -9.1358503,18.95253 -9.61769,20.005406 h 37.10759 z"
|
||||||
|
style="fill:#2f855a;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.762401"
|
||||||
|
id="path58" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
aria-label="akapi"
|
||||||
|
transform="matrix(0.35277777,0,0,0.35277777,-84.30991,101.5377)"
|
||||||
|
id="text856"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:176px;line-height:1.25;font-family:Roboto;-inkscape-font-specification:'Roboto, Medium';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;letter-spacing:7.5px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.75">
|
||||||
|
<path
|
||||||
|
d="m 565.57956,-313.41107 q -1.375,-2.66406 -2.40625,-8.67969 -9.96875,10.39844 -24.40625,10.39844 -14.00781,0 -22.85938,-7.99219 -8.85156,-7.99219 -8.85156,-19.76562 0,-14.86719 11,-22.77344 11.08594,-7.99219 31.625,-7.99219 h 12.80469 v -6.10156 q 0,-7.21875 -4.03906,-11.51563 -4.03907,-4.38281 -12.28907,-4.38281 -7.13281,0 -11.6875,3.60938 -4.55468,3.52343 -4.55468,9.02343 h -20.88282 q 0,-7.64843 5.07032,-14.26562 5.07031,-6.70313 13.75,-10.48438 8.76562,-3.78125 19.50781,-3.78125 16.32812,0 26.03906,8.25 9.71094,8.16407 9.96875,23.03125 v 41.9375 q 0,12.54688 3.52344,20.02344 v 1.46094 z m -22.94531,-15.03906 q 6.1875,0 11.60156,-3.00782 5.5,-3.00781 8.25,-8.07812 v -17.53125 H 551.228 q -11.60157,0 -17.44532,4.03906 -5.84375,4.03906 -5.84375,11.42969 0,6.01562 3.95313,9.625 4.03906,3.52344 10.74219,3.52344 z"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:176px;font-family:Roboto;-inkscape-font-specification:'Roboto, Medium';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#ffffff;fill-opacity:1;stroke-width:0.75"
|
||||||
|
id="path851" />
|
||||||
|
<path
|
||||||
|
d="m 642.94675,-353.28607 -9.28125,9.53906 v 30.33594 h -20.88282 v -132 h 20.88282 v 76.14062 l 6.53125,-8.16406 25.69531,-28.96094 h 25.09375 l -34.54688,38.75782 38.24219,54.22656 h -24.14844 z"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:176px;font-family:Roboto;-inkscape-font-specification:'Roboto, Medium';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#ffffff;fill-opacity:1;stroke-width:0.75"
|
||||||
|
id="path853" />
|
||||||
|
<path
|
||||||
|
d="m 767.6655,-313.41107 q -1.375,-2.66406 -2.40625,-8.67969 -9.96875,10.39844 -24.40625,10.39844 -14.00782,0 -22.85938,-7.99219 -8.85156,-7.99219 -8.85156,-19.76562 0,-14.86719 11,-22.77344 11.08594,-7.99219 31.625,-7.99219 h 12.80469 v -6.10156 q 0,-7.21875 -4.03907,-11.51563 -4.03906,-4.38281 -12.28906,-4.38281 -7.13281,0 -11.6875,3.60938 -4.55469,3.52343 -4.55469,9.02343 h -20.88281 q 0,-7.64843 5.07031,-14.26562 5.07032,-6.70313 13.75,-10.48438 8.76563,-3.78125 19.50782,-3.78125 16.32812,0 26.03906,8.25 9.71094,8.16407 9.96875,23.03125 v 41.9375 q 0,12.54688 3.52344,20.02344 v 1.46094 z m -22.94532,-15.03906 q 6.1875,0 11.60157,-3.00782 5.5,-3.00781 8.25,-8.07812 v -17.53125 h -11.25782 q -11.60156,0 -17.44531,4.03906 -5.84375,4.03906 -5.84375,11.42969 0,6.01562 3.95313,9.625 4.03906,3.52344 10.74218,3.52344 z"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:176px;font-family:Roboto;-inkscape-font-specification:'Roboto, Medium';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#ffffff;fill-opacity:1;stroke-width:0.75"
|
||||||
|
id="path855" />
|
||||||
|
<path
|
||||||
|
d="m 896.25143,-358.95795 q 0,21.57032 -9.79687,34.46094 -9.79688,12.80469 -26.29688,12.80469 -15.29687,0 -24.49218,-10.05469 v 44.08594 h -20.88282 v -128.73438 h 19.25 l 0.85938,9.45313 q 9.19531,-11.17188 25.00781,-11.17188 17.01563,0 26.64063,12.71875 9.71093,12.63282 9.71093,35.14844 z m -20.79687,-1.80468 q 0,-13.92188 -5.58594,-22.08594 -5.5,-8.16406 -15.8125,-8.16406 -12.80469,0 -18.39062,10.57031 v 41.25 q 5.67187,10.82812 18.5625,10.82812 9.96875,0 15.55468,-7.99218 5.67188,-8.07813 5.67188,-24.40625 z"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:176px;font-family:Roboto;-inkscape-font-specification:'Roboto, Medium';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#ffffff;fill-opacity:1;stroke-width:0.75"
|
||||||
|
id="path857" />
|
||||||
|
<path
|
||||||
|
d="m 943.62643,-313.41107 h -20.88281 v -92.98438 h 20.88281 z m -22.17187,-117.13281 q 0,-4.8125 3.00781,-7.99219 3.09375,-3.17969 8.76563,-3.17969 5.67187,0 8.76562,3.17969 3.09375,3.17969 3.09375,7.99219 0,4.72656 -3.09375,7.90625 -3.09375,3.09375 -8.76562,3.09375 -5.67188,0 -8.76563,-3.09375 -3.00781,-3.17969 -3.00781,-7.90625 z"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:176px;font-family:Roboto;-inkscape-font-specification:'Roboto, Medium';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#ffffff;fill-opacity:1;stroke-width:0.75"
|
||||||
|
id="path859" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 10 KiB |
@@ -25,11 +25,6 @@ body {
|
|||||||
@apply hidden !important;
|
@apply hidden !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input,
|
|
||||||
.select {
|
|
||||||
@apply text-black dark:bg-coolgray-100 dark:text-white ring-neutral-200 dark:ring-coolgray-300;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-sticky {
|
.input-sticky {
|
||||||
@apply text-black dark:bg-coolgray-100 dark:text-white ring-neutral-200 dark:ring-coolgray-300 focus:ring-2 dark:focus:ring-coolgray-300 focus:ring-neutral-400 block w-full py-1.5 rounded border-0 text-sm ring-1 ring-inset;
|
@apply text-black dark:bg-coolgray-100 dark:text-white ring-neutral-200 dark:ring-coolgray-300 focus:ring-2 dark:focus:ring-coolgray-300 focus:ring-neutral-400 block w-full py-1.5 rounded border-0 text-sm ring-1 ring-inset;
|
||||||
}
|
}
|
||||||
@@ -51,7 +46,11 @@ body {
|
|||||||
|
|
||||||
.input,
|
.input,
|
||||||
.select {
|
.select {
|
||||||
@apply block w-full py-1.5 rounded border-0 text-sm ring-1 ring-inset;
|
@apply text-black dark:bg-coolgray-100 dark:text-white ring-neutral-200 dark:ring-coolgray-300 block w-full py-1.5 rounded border-0 text-sm ring-1 ring-inset;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select {
|
||||||
|
@apply w-full;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input[type="password"] {
|
.input[type="password"] {
|
||||||
|
@@ -57,7 +57,8 @@
|
|||||||
language: '{{ $language }}',
|
language: '{{ $language }}',
|
||||||
domReadOnly: '{{ $readonly ?? false }}',
|
domReadOnly: '{{ $readonly ?? false }}',
|
||||||
contextmenu: '!{{ $readonly ?? false }}',
|
contextmenu: '!{{ $readonly ?? false }}',
|
||||||
renderLineHighlight: '{{ $readonly ?? false }} ? none : all'
|
renderLineHighlight: '{{ $readonly ?? false }} ? none : all',
|
||||||
|
stickyScroll: { enabled: false }
|
||||||
});
|
});
|
||||||
|
|
||||||
const observer = new MutationObserver((mutations) => {
|
const observer = new MutationObserver((mutations) => {
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
<div class="flex flex-col items-center justify-center h-full">
|
<div class="flex flex-col items-center justify-center h-full">
|
||||||
<div>
|
<div>
|
||||||
<p class="font-mono font-semibold text-7xl dark:text-warning">404</p>
|
<p class="font-mono font-semibold text-7xl dark:text-warning">404</p>
|
||||||
<h1 class="mt-4 font-bold tracking-tight dark:text-white">How did you got here?</h1>
|
<h1 class="mt-4 font-bold tracking-tight dark:text-white">How did you get here?</h1>
|
||||||
<p class="text-base leading-7 text-neutral-300">Sorry, we couldn’t find the page you’re looking
|
<p class="text-base leading-7 text-neutral-300">Sorry, we couldn’t find the page you’re looking
|
||||||
for.
|
for.
|
||||||
</p>
|
</p>
|
||||||
|
@@ -79,6 +79,16 @@
|
|||||||
</x-slot:button-text>
|
</x-slot:button-text>
|
||||||
</x-popup>
|
</x-popup>
|
||||||
</span>
|
</span>
|
||||||
|
@if (currentTeam()->subscriptionPastOverDue())
|
||||||
|
<x-banner :closable=false>
|
||||||
|
<div><span class="font-bold text-red-500">WARNING:</span> Your subscription is in over-due. If your latest
|
||||||
|
payment is not paid within a week, all automations <span class="font-bold text-red-500">will
|
||||||
|
be deactivated</span>. Visit <a href="{{ route('subscription.show') }}"
|
||||||
|
class="underline dark:text-white">/subscription</a> to check your subscription status or pay your
|
||||||
|
invoice (or check your email for the invoice).
|
||||||
|
</div>
|
||||||
|
</x-banner>
|
||||||
|
@endif
|
||||||
@if (currentTeam()->serverOverflow())
|
@if (currentTeam()->serverOverflow())
|
||||||
<x-banner :closable=false>
|
<x-banner :closable=false>
|
||||||
<div><span class="font-bold text-red-500">WARNING:</span> The number of active servers exceeds the limit
|
<div><span class="font-bold text-red-500">WARNING:</span> The number of active servers exceeds the limit
|
||||||
|
@@ -58,12 +58,9 @@
|
|||||||
<x-forms.checkbox instantSave id="isConnectToDockerNetworkEnabled" label="Connect To Predefined Network"
|
<x-forms.checkbox instantSave id="isConnectToDockerNetworkEnabled" label="Connect To Predefined Network"
|
||||||
helper="By default, you do not reach the Coolify defined networks.<br>Starting a docker compose based resource will have an internal network. <br>If you connect to a Coolify defined network, you maybe need to use different internal DNS names to connect to a resource.<br><br>For more information, check <a class='underline dark:text-white' target='_blank' href='https://coolify.io/docs/knowledge-base/docker/compose#connect-to-predefined-networks'>this</a>." />
|
helper="By default, you do not reach the Coolify defined networks.<br>Starting a docker compose based resource will have an internal network. <br>If you connect to a Coolify defined network, you maybe need to use different internal DNS names to connect to a resource.<br><br>For more information, check <a class='underline dark:text-white' target='_blank' href='https://coolify.io/docs/knowledge-base/docker/compose#connect-to-predefined-networks'>this</a>." />
|
||||||
@endif
|
@endif
|
||||||
@if ($isLogDrainEnabled === false)
|
<h3 class="pt-4">Logs</h3>
|
||||||
<h3 class="pt-4">Logs</h3>
|
<x-forms.checkbox helper="Drain logs to your configured log drain endpoint in your Server settings."
|
||||||
<x-forms.checkbox helper="Drain logs to your configured log drain endpoint in your Server settings."
|
instantSave id="isLogDrainEnabled" label="Drain Logs" />
|
||||||
instantSave id="isLogDrainEnabled" label="Drain Logs" />
|
|
||||||
@endif
|
|
||||||
|
|
||||||
@if ($application->git_based())
|
@if ($application->git_based())
|
||||||
<h3>Git</h3>
|
<h3>Git</h3>
|
||||||
<x-forms.checkbox instantSave id="isGitSubmodulesEnabled" label="Submodules"
|
<x-forms.checkbox instantSave id="isGitSubmodulesEnabled" label="Submodules"
|
||||||
|
@@ -15,8 +15,7 @@
|
|||||||
href="{{ route('project.application.advanced', ['project_uuid' => $project->uuid, 'environment_uuid' => $environment->uuid, 'application_uuid' => $application->uuid]) }}"
|
href="{{ route('project.application.advanced', ['project_uuid' => $project->uuid, 'environment_uuid' => $environment->uuid, 'application_uuid' => $application->uuid]) }}"
|
||||||
wire:navigate>Advanced</a>
|
wire:navigate>Advanced</a>
|
||||||
@if ($application->destination->server->isSwarm())
|
@if ($application->destination->server->isSwarm())
|
||||||
<a class="menu-item"
|
<a class="menu-item" wire:current.exact="menu-item-active"
|
||||||
wire:current.exact="menu-item-active"
|
|
||||||
href="{{ route('project.application.swarm', ['project_uuid' => $project->uuid, 'environment_uuid' => $environment->uuid, 'application_uuid' => $application->uuid]) }}"
|
href="{{ route('project.application.swarm', ['project_uuid' => $project->uuid, 'environment_uuid' => $environment->uuid, 'application_uuid' => $application->uuid]) }}"
|
||||||
wire:navigate>Swarm Configuration</a>
|
wire:navigate>Swarm Configuration</a>
|
||||||
@endif
|
@endif
|
||||||
@@ -60,21 +59,22 @@
|
|||||||
<a class="menu-item" wire:current.exact="menu-item-active"
|
<a class="menu-item" wire:current.exact="menu-item-active"
|
||||||
href="{{ route('project.application.preview-deployments', ['project_uuid' => $project->uuid, 'environment_uuid' => $environment->uuid, 'application_uuid' => $application->uuid]) }}"
|
href="{{ route('project.application.preview-deployments', ['project_uuid' => $project->uuid, 'environment_uuid' => $environment->uuid, 'application_uuid' => $application->uuid]) }}"
|
||||||
wire:navigate>Preview Deployments</a>
|
wire:navigate>Preview Deployments</a>
|
||||||
<a class="menu-item" wire:current.exact="menu-item-active"
|
@if ($application->build_pack !== 'dockercompose')
|
||||||
href="{{ route('project.application.healthcheck', ['project_uuid' => $project->uuid, 'environment_uuid' => $environment->uuid, 'application_uuid' => $application->uuid]) }}"
|
<a class="menu-item" wire:current.exact="menu-item-active"
|
||||||
wire:navigate>Healthcheck</a>
|
href="{{ route('project.application.healthcheck', ['project_uuid' => $project->uuid, 'environment_uuid' => $environment->uuid, 'application_uuid' => $application->uuid]) }}"
|
||||||
|
wire:navigate>Healthcheck</a>
|
||||||
|
@endif
|
||||||
<a class="menu-item" wire:current.exact="menu-item-active"
|
<a class="menu-item" wire:current.exact="menu-item-active"
|
||||||
href="{{ route('project.application.rollback', ['project_uuid' => $project->uuid, 'environment_uuid' => $environment->uuid, 'application_uuid' => $application->uuid]) }}"
|
href="{{ route('project.application.rollback', ['project_uuid' => $project->uuid, 'environment_uuid' => $environment->uuid, 'application_uuid' => $application->uuid]) }}"
|
||||||
wire:navigate>Rollback</a>
|
wire:navigate>Rollback</a>
|
||||||
<a class="menu-item" wire:current.exact="menu-item-active"
|
<a class="menu-item" wire:current.exact="menu-item-active"
|
||||||
href="{{ route('project.application.resource-limits', ['project_uuid' => $project->uuid, 'environment_uuid' => $environment->uuid, 'application_uuid' => $application->uuid]) }}"
|
href="{{ route('project.application.resource-limits', ['project_uuid' => $project->uuid, 'environment_uuid' => $environment->uuid, 'application_uuid' => $application->uuid]) }}"
|
||||||
wire:navigate>Resource Limits</a>
|
wire:navigate>Resource Limits</a>
|
||||||
|
|
||||||
<a class="menu-item" wire:current.exact="menu-item-active"
|
<a class="menu-item" wire:current.exact="menu-item-active"
|
||||||
href="{{ route('project.application.resource-operations', ['project_uuid' => $project->uuid, 'environment_uuid' => $environment->uuid, 'application_uuid' => $application->uuid]) }}"
|
href="{{ route('project.application.resource-operations', ['project_uuid' => $project->uuid, 'environment_uuid' => $environment->uuid, 'application_uuid' => $application->uuid]) }}"
|
||||||
wire:navigate>Resource Operations</a>
|
wire:navigate>Resource Operations</a>
|
||||||
<a class="menu-item" wire:current.exact="menu-item-active"
|
<a class="menu-item" wire:current.exact="menu-item-active"
|
||||||
href="{{ route('project.application.metrics', ['project_uuid' => $project->uuid, 'environment_uuid' => $environment->uuid, 'application_uuid' => $application->uuid]) }}" >Metrics</a>
|
href="{{ route('project.application.metrics', ['project_uuid' => $project->uuid, 'environment_uuid' => $environment->uuid, 'application_uuid' => $application->uuid]) }}">Metrics</a>
|
||||||
<a class="menu-item" wire:current.exact="menu-item-active"
|
<a class="menu-item" wire:current.exact="menu-item-active"
|
||||||
href="{{ route('project.application.tags', ['project_uuid' => $project->uuid, 'environment_uuid' => $environment->uuid, 'application_uuid' => $application->uuid]) }}"
|
href="{{ route('project.application.tags', ['project_uuid' => $project->uuid, 'environment_uuid' => $environment->uuid, 'application_uuid' => $application->uuid]) }}"
|
||||||
wire:navigate>Tags</a>
|
wire:navigate>Tags</a>
|
||||||
@@ -103,7 +103,7 @@
|
|||||||
<livewire:project.shared.webhooks :resource="$application" />
|
<livewire:project.shared.webhooks :resource="$application" />
|
||||||
@elseif ($currentRoute === 'project.application.preview-deployments')
|
@elseif ($currentRoute === 'project.application.preview-deployments')
|
||||||
<livewire:project.application.previews :application="$application" />
|
<livewire:project.application.previews :application="$application" />
|
||||||
@elseif ($currentRoute === 'project.application.healthcheck')
|
@elseif ($currentRoute === 'project.application.healthcheck' && $application->build_pack !== 'dockercompose')
|
||||||
<livewire:project.shared.health-checks :resource="$application" />
|
<livewire:project.shared.health-checks :resource="$application" />
|
||||||
@elseif ($currentRoute === 'project.application.rollback')
|
@elseif ($currentRoute === 'project.application.rollback')
|
||||||
<livewire:project.application.rollback :application="$application" />
|
<livewire:project.application.rollback :application="$application" />
|
||||||
|
@@ -185,7 +185,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="pt-1 text-xs">Nixpacks will detect the required configuration
|
<div class="pt-1 text-xs">Nixpacks will detect the required configuration
|
||||||
automatically.
|
automatically.
|
||||||
<a class="underline" href="https://coolify.io/docs/applications">Framework
|
<a class="underline" href="https://coolify.io/docs/applications/">Framework
|
||||||
Specific Docs</a>
|
Specific Docs</a>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
@@ -54,6 +54,49 @@
|
|||||||
<div class="text-gray-600 dark:text-gray-400 text-sm">
|
<div class="text-gray-600 dark:text-gray-400 text-sm">
|
||||||
Location: {{ data_get($execution, 'filename', 'N/A') }}
|
Location: {{ data_get($execution, 'filename', 'N/A') }}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="flex items-center gap-3 mt-2">
|
||||||
|
<div class="text-gray-600 dark:text-gray-400 text-sm">
|
||||||
|
Backup Availability:
|
||||||
|
</div>
|
||||||
|
<span @class([
|
||||||
|
'px-2 py-1 rounded text-xs font-medium',
|
||||||
|
'bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-200' => !data_get($execution, 'local_storage_deleted', false),
|
||||||
|
'bg-gray-100 text-gray-600 dark:bg-gray-800/50 dark:text-gray-400' => data_get($execution, 'local_storage_deleted', false),
|
||||||
|
])>
|
||||||
|
<span class="flex items-center gap-1">
|
||||||
|
@if(!data_get($execution, 'local_storage_deleted', false))
|
||||||
|
<svg class="w-3 h-3" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"></path>
|
||||||
|
</svg>
|
||||||
|
@else
|
||||||
|
<svg class="w-3 h-3" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd"></path>
|
||||||
|
</svg>
|
||||||
|
@endif
|
||||||
|
Local Storage
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
@if($backup->save_s3)
|
||||||
|
<span @class([
|
||||||
|
'px-2 py-1 rounded text-xs font-medium',
|
||||||
|
'bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-200' => !data_get($execution, 's3_storage_deleted', false),
|
||||||
|
'bg-gray-100 text-gray-600 dark:bg-gray-800/50 dark:text-gray-400' => data_get($execution, 's3_storage_deleted', false),
|
||||||
|
])>
|
||||||
|
<span class="flex items-center gap-1">
|
||||||
|
@if(!data_get($execution, 's3_storage_deleted', false))
|
||||||
|
<svg class="w-3 h-3" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"></path>
|
||||||
|
</svg>
|
||||||
|
@else
|
||||||
|
<svg class="w-3 h-3" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd"></path>
|
||||||
|
</svg>
|
||||||
|
@endif
|
||||||
|
S3 Storage
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
@if (data_get($execution, 'message'))
|
@if (data_get($execution, 'message'))
|
||||||
<div class="mt-2 p-2 bg-gray-100 dark:bg-coolgray-200 rounded">
|
<div class="mt-2 p-2 bg-gray-100 dark:bg-coolgray-200 rounded">
|
||||||
<pre class="whitespace-pre-wrap text-sm">{{ data_get($execution, 'message') }}</pre>
|
<pre class="whitespace-pre-wrap text-sm">{{ data_get($execution, 'message') }}</pre>
|
||||||
|
@@ -15,9 +15,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="pb-4">Deploy any public or private Git repositories through a GitHub App.</div>
|
<div class="pb-4">Deploy any public or private Git repositories through a GitHub App.</div>
|
||||||
@if ($github_apps->count() !== 0)
|
@if ($github_apps->count() !== 0)
|
||||||
<h2 class="pt-4 pb-4">Select a Github App</h2>
|
|
||||||
<div class="flex flex-col gap-2">
|
<div class="flex flex-col gap-2">
|
||||||
@if ($current_step === 'github_apps')
|
@if ($current_step === 'github_apps')
|
||||||
|
<h2 class="pt-4 pb-4">Select a Github App</h2>
|
||||||
<div class="flex flex-col justify-center gap-2 text-left">
|
<div class="flex flex-col justify-center gap-2 text-left">
|
||||||
@foreach ($github_apps as $ghapp)
|
@foreach ($github_apps as $ghapp)
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
@@ -43,25 +43,28 @@
|
|||||||
@endif
|
@endif
|
||||||
@if ($current_step === 'repository')
|
@if ($current_step === 'repository')
|
||||||
@if ($repositories->count() > 0)
|
@if ($repositories->count() > 0)
|
||||||
<div class="flex items-end gap-2">
|
<div class="flex flex-col gap-2 pb-6">
|
||||||
<x-forms.select class="w-full" label="Repository" wire:model="selected_repository_id">
|
<div class="flex gap-2">
|
||||||
@foreach ($repositories as $repo)
|
<x-forms.select class="w-full" label="Repository" wire:model="selected_repository_id">
|
||||||
@if ($loop->first)
|
@foreach ($repositories as $repo)
|
||||||
<option selected value="{{ data_get($repo, 'id') }}">
|
@if ($loop->first)
|
||||||
{{ data_get($repo, 'name') }}
|
<option selected value="{{ data_get($repo, 'id') }}">
|
||||||
</option>
|
{{ data_get($repo, 'name') }}
|
||||||
@else
|
</option>
|
||||||
<option value="{{ data_get($repo, 'id') }}">{{ data_get($repo, 'name') }}
|
@else
|
||||||
</option>
|
<option value="{{ data_get($repo, 'id') }}">{{ data_get($repo, 'name') }}
|
||||||
@endif
|
</option>
|
||||||
@endforeach
|
@endif
|
||||||
</x-forms.select>
|
@endforeach
|
||||||
|
</x-forms.select>
|
||||||
|
</div>
|
||||||
<x-forms.button wire:click.prevent="loadBranches"> Load Repository </x-forms.button>
|
<x-forms.button wire:click.prevent="loadBranches"> Load Repository </x-forms.button>
|
||||||
</div>
|
</div>
|
||||||
@else
|
@else
|
||||||
<div>No repositories found. Check your GitHub App configuration.</div>
|
<div>No repositories found. Check your GitHub App configuration.</div>
|
||||||
@endif
|
@endif
|
||||||
@if ($branches->count() > 0)
|
@if ($branches->count() > 0)
|
||||||
|
<h2 class="text-lg font-bold">Configuration</h2>
|
||||||
<div class="flex flex-col gap-2 pb-6">
|
<div class="flex flex-col gap-2 pb-6">
|
||||||
<form class="flex flex-col" wire:submit='submit'>
|
<form class="flex flex-col" wire:submit='submit'>
|
||||||
<div class="flex flex-col gap-2 pb-6">
|
<div class="flex flex-col gap-2 pb-6">
|
||||||
|
@@ -80,7 +80,7 @@
|
|||||||
respective
|
respective
|
||||||
companies, and use of them does not imply any affiliation or endorsement.<br>Find more services
|
companies, and use of them does not imply any affiliation or endorsement.<br>Find more services
|
||||||
<a class="dark:text-white underline" target="_blank"
|
<a class="dark:text-white underline" target="_blank"
|
||||||
href="https://coolify.io/docs/services">here</a>.
|
href="https://coolify.io/docs/services/overview">here</a>.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid justify-start grid-cols-1 gap-4 text-left xl:grid-cols-2">
|
<div class="grid justify-start grid-cols-1 gap-4 text-left xl:grid-cols-2">
|
||||||
|
@@ -176,7 +176,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="pb-4">Persistent storage to preserve data between deployments.</div>
|
<div class="pb-4">Persistent storage to preserve data between deployments.</div>
|
||||||
<div class="pb-4 dark:text-warning text-coollabs">If you would like to add a volume, you must add it to
|
<div class="pb-4 dark:text-warning text-coollabs">If you would like to add a volume, you must add it to
|
||||||
your compose file (Service Stack tab).</div>
|
your compose file (<a class="underline"
|
||||||
|
href="{{ route('project.service.configuration', ['project_uuid' => $project->uuid, 'environment_uuid' => $environment->uuid, 'service_uuid' => $service->uuid]) }}"
|
||||||
|
wire:navigate>General tab</a>).</div>
|
||||||
@foreach ($applications as $application)
|
@foreach ($applications as $application)
|
||||||
<livewire:project.service.storage wire:key="application-{{ $application->id }}"
|
<livewire:project.service.storage wire:key="application-{{ $application->id }}"
|
||||||
:resource="$application" />
|
:resource="$application" />
|
||||||
|
@@ -7,6 +7,10 @@
|
|||||||
<h2>{{ Str::headline($database->name) }}</h2>
|
<h2>{{ Str::headline($database->name) }}</h2>
|
||||||
@endif
|
@endif
|
||||||
<x-forms.button type="submit">Save</x-forms.button>
|
<x-forms.button type="submit">Save</x-forms.button>
|
||||||
|
<x-modal-confirmation title="Confirm Service Database Deletion?" buttonTitle="Delete" isErrorButton
|
||||||
|
submitAction="delete" :actions="['The selected service database container will be stopped and permanently deleted.']" confirmationText="{{ Str::headline($database->name) }}"
|
||||||
|
confirmationLabel="Please confirm the execution of the actions by entering the Service Database Name below"
|
||||||
|
shortConfirmationLabel="Service Database Name" step3ButtonText="Permanently Delete" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col gap-2">
|
<div class="flex flex-col gap-2">
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
|
@@ -1,35 +1,48 @@
|
|||||||
<div x-data="{ raw: true }">
|
<div x-data="{ raw: true, showNormalTextarea: false }">
|
||||||
<div class="pb-4">Volume names are updated upon save. The service UUID will be added as a prefix to all volumes, to
|
<div class="pb-4">Volume names are updated upon save. The service UUID will be added as a prefix to all volumes, to
|
||||||
prevent
|
prevent
|
||||||
name collision. <br>To see the actual volume names, check the Deployable Compose file, or go to Storage
|
name collision. <br>To see the actual volume names, check the Deployable Compose file, or go to Storage
|
||||||
menu.</div>
|
menu.</div>
|
||||||
|
|
||||||
<div x-cloak x-show="raw" class="font-mono">
|
<div x-cloak x-show="raw" class="font-mono">
|
||||||
<x-forms.textarea allowTab useMonacoEditor monacoEditorLanguage="yaml" rows="20"
|
<div x-cloak x-show="showNormalTextarea">
|
||||||
id="service.docker_compose_raw">
|
<x-forms.textarea rows="20" id="service.docker_compose_raw">
|
||||||
</x-forms.textarea>
|
</x-forms.textarea>
|
||||||
|
</div>
|
||||||
|
<div x-cloak x-show="!showNormalTextarea">
|
||||||
|
<x-forms.textarea allowTab useMonacoEditor monacoEditorLanguage="yaml" rows="20"
|
||||||
|
id="service.docker_compose_raw">
|
||||||
|
</x-forms.textarea>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div x-cloak x-show="raw === false" class="font-mono">
|
<div x-cloak x-show="raw === false" class="font-mono">
|
||||||
<x-forms.textarea rows="20" readonly id="service.docker_compose">
|
<x-forms.textarea rows="20" readonly id="service.docker_compose">
|
||||||
</x-forms.textarea>
|
</x-forms.textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="pt-2 w-96">
|
<div class="pt-2 flex gap-2">
|
||||||
<x-forms.checkbox label="Escape special characters in labels?"
|
<div class="flex flex-col gap-2">
|
||||||
helper="By default, $ (and other chars) is escaped. So if you write $ in the labels, it will be saved as $$.<br><br>If you want to use env variables inside the labels, turn this off."
|
<x-forms.checkbox label="Escape special characters in labels?"
|
||||||
id="service.is_container_label_escape_enabled" instantSave></x-forms.checkbox>
|
helper="By default, $ (and other chars) is escaped. So if you write $ in the labels, it will be saved as $$.<br><br>If you want to use env variables inside the labels, turn this off."
|
||||||
|
id="service.is_container_label_escape_enabled" instantSave></x-forms.checkbox>
|
||||||
|
<x-forms.checkbox label="Show Normal Textarea" x-model="showNormalTextarea"></x-forms.checkbox>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-end w-full gap-2 pt-4">
|
<div class="flex w-full gap-2 pt-4">
|
||||||
<div class="flex items-end gap-2">
|
<div x-cloak x-show="raw">
|
||||||
<div x-cloak x-show="raw">
|
<x-forms.button class="w-64" @click.prevent="raw = !raw">Show Deployable Compose</x-forms.button>
|
||||||
<x-forms.button class="w-64" @click.prevent="raw = !raw">Show Deployable Compose</x-forms.button>
|
</div>
|
||||||
</div>
|
<div x-cloak x-show="raw === false">
|
||||||
<div x-cloak x-show="raw === false">
|
<x-forms.button class="w-64" @click.prevent="raw = !raw">Show Source
|
||||||
<x-forms.button class="w-64" @click.prevent="raw = !raw">Show Source
|
Compose</x-forms.button>
|
||||||
Compose</x-forms.button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-1"></div>
|
<div class="flex-1"></div>
|
||||||
<x-forms.button class="w-64" wire:click.prevent='saveEditedCompose'>
|
@if (blank($service->service_type))
|
||||||
|
<x-forms.button class="w-28" wire:click.prevent='validateCompose'>
|
||||||
|
Validate
|
||||||
|
</x-forms.button>
|
||||||
|
@endif
|
||||||
|
<x-forms.button class="w-28" wire:click.prevent='saveEditedCompose'>
|
||||||
Save
|
Save
|
||||||
</x-forms.button>
|
</x-forms.button>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -21,15 +21,6 @@
|
|||||||
]" confirmationText="{{ $fs_path }}"
|
]" confirmationText="{{ $fs_path }}"
|
||||||
confirmationLabel="Please confirm the execution of the actions by entering the Filepath below"
|
confirmationLabel="Please confirm the execution of the actions by entering the Filepath below"
|
||||||
shortConfirmationLabel="Filepath" :confirmWithPassword="false" step2ButtonText="Convert to file" />
|
shortConfirmationLabel="Filepath" :confirmWithPassword="false" step2ButtonText="Convert to file" />
|
||||||
@else
|
|
||||||
<x-modal-confirmation title="Confirm File Conversion to Directory?" buttonTitle="Convert to directory"
|
|
||||||
submitAction="convertToDirectory" :actions="[
|
|
||||||
'The selected file will be permanently deleted and an empty directory will be created in its place.',
|
|
||||||
]" confirmationText="{{ $fs_path }}"
|
|
||||||
confirmationLabel="Please confirm the execution of the actions by entering the Filepath below"
|
|
||||||
shortConfirmationLabel="Filepath" :confirmWithPassword="false" step2ButtonText="Convert to directory" />
|
|
||||||
@endif
|
|
||||||
@if ($fileStorage->is_directory)
|
|
||||||
<x-modal-confirmation title="Confirm Directory Deletion?" buttonTitle="Delete Directory" isErrorButton
|
<x-modal-confirmation title="Confirm Directory Deletion?" buttonTitle="Delete Directory" isErrorButton
|
||||||
submitAction="delete" :checkboxes="$directoryDeletionCheckboxes" :actions="[
|
submitAction="delete" :checkboxes="$directoryDeletionCheckboxes" :actions="[
|
||||||
'The selected directory and all its contents will be permanently deleted from the container.',
|
'The selected directory and all its contents will be permanently deleted from the container.',
|
||||||
@@ -37,13 +28,21 @@
|
|||||||
confirmationLabel="Please confirm the execution of the actions by entering the Filepath below"
|
confirmationLabel="Please confirm the execution of the actions by entering the Filepath below"
|
||||||
shortConfirmationLabel="Filepath" step3ButtonText="Permanently Delete" />
|
shortConfirmationLabel="Filepath" step3ButtonText="Permanently Delete" />
|
||||||
@else
|
@else
|
||||||
|
@if (!$fileStorage->is_binary)
|
||||||
|
<x-modal-confirmation title="Confirm File Conversion to Directory?"
|
||||||
|
buttonTitle="Convert to directory" submitAction="convertToDirectory" :actions="[
|
||||||
|
'The selected file will be permanently deleted and an empty directory will be created in its place.',
|
||||||
|
]"
|
||||||
|
confirmationText="{{ $fs_path }}"
|
||||||
|
confirmationLabel="Please confirm the execution of the actions by entering the Filepath below"
|
||||||
|
shortConfirmationLabel="Filepath" :confirmWithPassword="false" step2ButtonText="Convert to directory" />
|
||||||
|
@endif
|
||||||
<x-modal-confirmation title="Confirm File Deletion?" buttonTitle="Delete File" isErrorButton
|
<x-modal-confirmation title="Confirm File Deletion?" buttonTitle="Delete File" isErrorButton
|
||||||
submitAction="delete" :checkboxes="$fileDeletionCheckboxes" :actions="['The selected file will be permanently deleted from the container.']" confirmationText="{{ $fs_path }}"
|
submitAction="delete" :checkboxes="$fileDeletionCheckboxes" :actions="['The selected file will be permanently deleted from the container.']" confirmationText="{{ $fs_path }}"
|
||||||
confirmationLabel="Please confirm the execution of the actions by entering the Filepath below"
|
confirmationLabel="Please confirm the execution of the actions by entering the Filepath below"
|
||||||
shortConfirmationLabel="Filepath" step3ButtonText="Permanently Delete" />
|
shortConfirmationLabel="Filepath" step3ButtonText="Permanently Delete" />
|
||||||
@endif
|
@endif
|
||||||
|
{{-- @if (!$fileStorage->is_based_on_git)
|
||||||
@if (!$fileStorage->is_based_on_git)
|
|
||||||
<x-modal-confirmation isErrorButton buttonTitle="Delete">
|
<x-modal-confirmation isErrorButton buttonTitle="Delete">
|
||||||
<div class="px-2">This storage will be deleted. It is not reversible. <strong
|
<div class="px-2">This storage will be deleted. It is not reversible. <strong
|
||||||
class="text-error">Please
|
class="text-error">Please
|
||||||
@@ -58,7 +57,7 @@
|
|||||||
label="Permanently delete file from the server?"></x-forms.checkbox>
|
label="Permanently delete file from the server?"></x-forms.checkbox>
|
||||||
@endif
|
@endif
|
||||||
</x-modal-confirmation>
|
</x-modal-confirmation>
|
||||||
@endif
|
@endif --}}
|
||||||
</div>
|
</div>
|
||||||
@if (!$fileStorage->is_directory)
|
@if (!$fileStorage->is_directory)
|
||||||
@if (data_get($resource, 'settings.is_preserve_repository_enabled'))
|
@if (data_get($resource, 'settings.is_preserve_repository_enabled'))
|
||||||
@@ -70,11 +69,10 @@
|
|||||||
<x-forms.textarea
|
<x-forms.textarea
|
||||||
label="{{ $fileStorage->is_based_on_git ? 'Content (refreshed after a successful deployment)' : 'Content' }}"
|
label="{{ $fileStorage->is_based_on_git ? 'Content (refreshed after a successful deployment)' : 'Content' }}"
|
||||||
rows="20" id="fileStorage.content"
|
rows="20" id="fileStorage.content"
|
||||||
readonly="{{ $fileStorage->is_based_on_git }}"></x-forms.textarea>
|
readonly="{{ $fileStorage->is_based_on_git || $fileStorage->is_binary }}"></x-forms.textarea>
|
||||||
@if (!$fileStorage->is_based_on_git)
|
@if (!$fileStorage->is_based_on_git && !$fileStorage->is_binary)
|
||||||
<x-forms.button class="w-full" type="submit">Save</x-forms.button>
|
<x-forms.button class="w-full" type="submit">Save</x-forms.button>
|
||||||
@endif
|
@endif
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -3,8 +3,8 @@
|
|||||||
<div class="flex flex-col h-full gap-8 pt-6 sm:flex-row">
|
<div class="flex flex-col h-full gap-8 pt-6 sm:flex-row">
|
||||||
<div class="flex flex-col items-start gap-2 min-w-fit">
|
<div class="flex flex-col items-start gap-2 min-w-fit">
|
||||||
<a class="menu-item"
|
<a class="menu-item"
|
||||||
class="{{ request()->routeIs('project.service.configuration') ? 'menu-item-active' : '' }}"
|
class="{{ request()->routeIs('project.service.configuration') ? 'menu-item-active' : '' }}" wire:navigate
|
||||||
wire:navigate href="{{ route('project.service.configuration', [...$parameters, 'stack_service_uuid' => null]) }}">
|
href="{{ route('project.service.configuration', [...$parameters, 'stack_service_uuid' => null]) }}">
|
||||||
<button><- Back</button>
|
<button><- Back</button>
|
||||||
</a>
|
</a>
|
||||||
<a class="menu-item" :class="activeTab === 'general' && 'menu-item-active'"
|
<a class="menu-item" :class="activeTab === 'general' && 'menu-item-active'"
|
||||||
@@ -12,8 +12,8 @@
|
|||||||
wire:navigate href="#">General</a>
|
wire:navigate href="#">General</a>
|
||||||
@if ($serviceDatabase?->isBackupSolutionAvailable())
|
@if ($serviceDatabase?->isBackupSolutionAvailable())
|
||||||
<a :class="activeTab === 'backups' && 'menu-item-active'" class="menu-item"
|
<a :class="activeTab === 'backups' && 'menu-item-active'" class="menu-item"
|
||||||
@click.prevent="activeTab = 'backups'; window.location.hash = 'backups'"
|
@click.prevent="activeTab = 'backups'; window.location.hash = 'backups'" wire:navigate
|
||||||
wire:navigate href="#backups">Backups</a>
|
href="#backups">Backups</a>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
|
@@ -47,6 +47,10 @@
|
|||||||
<x-forms.checkbox instantSave id="is_build_time"
|
<x-forms.checkbox instantSave id="is_build_time"
|
||||||
helper="If you are using Docker, remember to modify the file to be ready to receive the build time args. Ex.: for docker file, add `ARG name_of_the_variable`, or dockercompose add `- 'name_of_the_variable=${name_of_the_variable}'`"
|
helper="If you are using Docker, remember to modify the file to be ready to receive the build time args. Ex.: for docker file, add `ARG name_of_the_variable`, or dockercompose add `- 'name_of_the_variable=${name_of_the_variable}'`"
|
||||||
label="Build Variable?" />
|
label="Build Variable?" />
|
||||||
|
<x-forms.checkbox instantSave id="is_literal"
|
||||||
|
helper="This means that when you use $VARIABLES in a value, it should be interpreted as the actual characters '$VARIABLES' and not as the value of a variable named VARIABLE.<br><br>Useful if you have $ sign in your value and there are some characters after it, but you would not like to interpolate it from another value. In this case, you should set this to true."
|
||||||
|
label="Is Literal?" />
|
||||||
|
<x-forms.checkbox instantSave id="is_multiline" label="Is Multiline?" />
|
||||||
@else
|
@else
|
||||||
@if ($is_shared)
|
@if ($is_shared)
|
||||||
<x-forms.checkbox instantSave id="is_build_time"
|
<x-forms.checkbox instantSave id="is_build_time"
|
||||||
|
@@ -3,9 +3,9 @@
|
|||||||
<h2>Scheduled Tasks</h2>
|
<h2>Scheduled Tasks</h2>
|
||||||
<x-modal-input buttonTitle="+ Add" title="New Scheduled Task" :closeOutside="false">
|
<x-modal-input buttonTitle="+ Add" title="New Scheduled Task" :closeOutside="false">
|
||||||
@if ($resource->type() == 'application')
|
@if ($resource->type() == 'application')
|
||||||
<livewire:project.shared.scheduled-task.add :type="$resource->type()" :containerNames="$containerNames" />
|
<livewire:project.shared.scheduled-task.add :type="$resource->type()" :id="$resource->id" :containerNames="$containerNames" />
|
||||||
@elseif ($resource->type() == 'service')
|
@elseif ($resource->type() == 'service')
|
||||||
<livewire:project.shared.scheduled-task.add :type="$resource->type()" :containerNames="$containerNames" />
|
<livewire:project.shared.scheduled-task.add :type="$resource->type()" :id="$resource->id" :containerNames="$containerNames" />
|
||||||
@endif
|
@endif
|
||||||
</x-modal-input>
|
</x-modal-input>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -32,6 +32,11 @@
|
|||||||
<x-forms.input id="oauth_settings_map.{{ $oauth_setting->provider }}.tenant"
|
<x-forms.input id="oauth_settings_map.{{ $oauth_setting->provider }}.tenant"
|
||||||
label="Tenant" />
|
label="Tenant" />
|
||||||
@endif
|
@endif
|
||||||
|
@if ($oauth_setting->provider == 'google')
|
||||||
|
<x-forms.input id="oauth_settings_map.{{ $oauth_setting->provider }}.tenant"
|
||||||
|
helper="Optional parameter that supplies a hosted domain (HD) to Google, which<br>triggers a login hint to be displayed on the OAuth screen with this domain.<br><br><a class='underline dark:text-warning text-coollabs' href='https://developers.google.com/identity/openid-connect/openid-connect#hd-param' target='_blank'>Google Documentation</a>"
|
||||||
|
label="Tenant" />
|
||||||
|
@endif
|
||||||
@if ($oauth_setting->provider == 'authentik')
|
@if ($oauth_setting->provider == 'authentik')
|
||||||
<x-forms.input id="oauth_settings_map.{{ $oauth_setting->provider }}.base_url"
|
<x-forms.input id="oauth_settings_map.{{ $oauth_setting->provider }}.base_url"
|
||||||
label="Base URL" />
|
label="Base URL" />
|
||||||
|
@@ -132,12 +132,12 @@
|
|||||||
<h4 class="py-4">Confirmation Settings</h4>
|
<h4 class="py-4">Confirmation Settings</h4>
|
||||||
|
|
||||||
@if ($disable_two_step_confirmation)
|
@if ($disable_two_step_confirmation)
|
||||||
<div class="md:w-96 pb-4">
|
<div class="md:w-96 pb-4" wire:key="two-step-confirmation-enabled">
|
||||||
<x-forms.checkbox instantSave id="disable_two_step_confirmation" label="Disable Two Step Confirmation"
|
<x-forms.checkbox instantSave id="disable_two_step_confirmation" label="Disable Two Step Confirmation"
|
||||||
helper="When disabled, you will not need to confirm actions with a text and user password. This significantly reduces security and may lead to accidental deletions or unwanted changes. Use with extreme caution, especially on production servers." />
|
helper="When disabled, you will not need to confirm actions with a text and user password. This significantly reduces security and may lead to accidental deletions or unwanted changes. Use with extreme caution, especially on production servers." />
|
||||||
</div>
|
</div>
|
||||||
@else
|
@else
|
||||||
<div class="md:w-96 pb-4">
|
<div class="md:w-96 pb-4" wire:key="two-step-confirmation-disabled">
|
||||||
<x-modal-confirmation title="Disable Two Step Confirmation?"
|
<x-modal-confirmation title="Disable Two Step Confirmation?"
|
||||||
buttonTitle="Disable Two Step Confirmation" isErrorButton submitAction="toggleTwoStepConfirmation"
|
buttonTitle="Disable Two Step Confirmation" isErrorButton submitAction="toggleTwoStepConfirmation"
|
||||||
:actions="[
|
:actions="[
|
||||||
|
@@ -27,6 +27,7 @@
|
|||||||
confirmationText="{{ data_get($github_app, 'name') }}" :confirmWithPassword="false"
|
confirmationText="{{ data_get($github_app, 'name') }}" :confirmWithPassword="false"
|
||||||
step2ButtonText="Permanently Delete" />
|
step2ButtonText="Permanently Delete" />
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="subtitle">Your Private GitHub App for private repositories.</div>
|
<div class="subtitle">Your Private GitHub App for private repositories.</div>
|
||||||
@@ -46,7 +47,7 @@
|
|||||||
<div class="flex flex-col gap-2">
|
<div class="flex flex-col gap-2">
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
<div class="flex items-end gap-2 w-full">
|
<div class="flex items-end gap-2 w-full">
|
||||||
<x-forms.input id="github_app.name" label="App Name" disabled />
|
<x-forms.input id="github_app.name" label="App Name" />
|
||||||
<x-forms.button wire:click.prevent="updateGithubAppName" class="bg-coollabs">
|
<x-forms.button wire:click.prevent="updateGithubAppName" class="bg-coollabs">
|
||||||
Sync Name
|
Sync Name
|
||||||
</x-forms.button>
|
</x-forms.button>
|
||||||
@@ -57,7 +58,7 @@
|
|||||||
</x-forms.button>
|
</x-forms.button>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<x-forms.input id="github_app.organization" label="Organization" disabled
|
<x-forms.input id="github_app.organization" label="Organization"
|
||||||
placeholder="If empty, personal user will be used" />
|
placeholder="If empty, personal user will be used" />
|
||||||
</div>
|
</div>
|
||||||
@if (!isCloud())
|
@if (!isCloud())
|
||||||
@@ -68,27 +69,32 @@
|
|||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
<x-forms.input id="github_app.html_url" label="HTML Url" disabled />
|
<x-forms.input id="github_app.html_url" label="HTML Url" />
|
||||||
<x-forms.input id="github_app.api_url" label="API Url" disabled />
|
<x-forms.input id="github_app.api_url" label="API Url" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
@if ($github_app->html_url === 'https://github.com')
|
<x-forms.input id="github_app.custom_user" label="User" required />
|
||||||
<x-forms.input id="github_app.custom_user" label="User" disabled />
|
<x-forms.input type="number" id="github_app.custom_port" label="Port" required />
|
||||||
<x-forms.input type="number" id="github_app.custom_port" label="Port" disabled />
|
|
||||||
@else
|
|
||||||
<x-forms.input id="github_app.custom_user" label="User" required />
|
|
||||||
<x-forms.input type="number" id="github_app.custom_port" label="Port" required />
|
|
||||||
@endif
|
|
||||||
</div>
|
</div>
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
<x-forms.input type="number" id="github_app.app_id" label="App Id" disabled />
|
<x-forms.input type="number" id="github_app.app_id" label="App Id" required />
|
||||||
<x-forms.input type="number" id="github_app.installation_id" label="Installation Id"
|
<x-forms.input type="number" id="github_app.installation_id" label="Installation Id"
|
||||||
disabled />
|
required />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
<x-forms.input id="github_app.client_id" label="Client Id" type="password" disabled />
|
<x-forms.input id="github_app.client_id" label="Client Id" type="password" required />
|
||||||
<x-forms.input id="github_app.client_secret" label="Client Secret" type="password" />
|
<x-forms.input id="github_app.client_secret" label="Client Secret" type="password" required />
|
||||||
<x-forms.input id="github_app.webhook_secret" label="Webhook Secret" type="password" />
|
<x-forms.input id="github_app.webhook_secret" label="Webhook Secret" type="password" required />
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<x-forms.select id="github_app.private_key_id" label="Private Key" required>
|
||||||
|
@if (blank($github_app->private_key_id))
|
||||||
|
<option value="0" selected>Select a private key</option>
|
||||||
|
@endif
|
||||||
|
@foreach ($privateKeys as $privateKey)
|
||||||
|
<option value="{{ $privateKey->id }}">{{ $privateKey->name }}</option>
|
||||||
|
@endforeach
|
||||||
|
</x-forms.select>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-end gap-2 ">
|
<div class="flex items-end gap-2 ">
|
||||||
<h2 class="pt-4">Permissions</h2>
|
<h2 class="pt-4">Permissions</h2>
|
||||||
@@ -182,120 +188,129 @@
|
|||||||
shortConfirmationLabel="GitHub App Name" :confirmWithPassword="false" step2ButtonText="Permanently Delete" />
|
shortConfirmationLabel="GitHub App Name" :confirmWithPassword="false" step2ButtonText="Permanently Delete" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class=" pb-5 rounded alert-error">
|
<div class="flex flex-col gap-2">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 stroke-current shrink-0" fill="none"
|
<h3>Manual Installation</h3>
|
||||||
viewBox="0 0 24 24">
|
<div class="flex gap-2 items-center">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
If you want to fill the form manually, you can continue below. Only for advanced users.
|
||||||
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
|
<x-forms.button wire:click.prevent="createGithubAppManually">
|
||||||
</svg>
|
Continue
|
||||||
<span>You must complete this step before you can use this source!</span>
|
</x-forms.button>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col">
|
<h3>Automated Installation</h3>
|
||||||
<div class="pb-10">
|
<div class=" pb-5 rounded alert-error">
|
||||||
@if (!isCloud() || isDev())
|
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 stroke-current shrink-0" fill="none"
|
||||||
<div class="flex items-end gap-2">
|
viewBox="0 0 24 24">
|
||||||
<x-forms.select wire:model.live='webhook_endpoint' label="Webhook Endpoint"
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||||
helper="All Git webhooks will be sent to this endpoint. <br><br>If you would like to use domain instead of IP address, set your Coolify instance's FQDN in the Settings menu.">
|
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
|
||||||
@if ($ipv4)
|
</svg>
|
||||||
<option value="{{ $ipv4 }}">Use {{ $ipv4 }}</option>
|
<span>You must complete this step before you can use this source!</span>
|
||||||
@endif
|
</div>
|
||||||
@if ($ipv6)
|
<div class="flex flex-col">
|
||||||
<option value="{{ $ipv6 }}">Use {{ $ipv6 }}</option>
|
<div class="pb-10">
|
||||||
@endif
|
@if (!isCloud() || isDev())
|
||||||
@if ($fqdn)
|
<div class="flex items-end gap-2">
|
||||||
<option value="{{ $fqdn }}">Use {{ $fqdn }}</option>
|
<x-forms.select wire:model.live='webhook_endpoint' label="Webhook Endpoint"
|
||||||
@endif
|
helper="All Git webhooks will be sent to this endpoint. <br><br>If you would like to use domain instead of IP address, set your Coolify instance's FQDN in the Settings menu.">
|
||||||
@if (config('app.url'))
|
@if ($ipv4)
|
||||||
<option value="{{ config('app.url') }}">Use {{ config('app.url') }}</option>
|
<option value="{{ $ipv4 }}">Use {{ $ipv4 }}</option>
|
||||||
@endif
|
@endif
|
||||||
</x-forms.select>
|
@if ($ipv6)
|
||||||
<x-forms.button isHighlighted
|
<option value="{{ $ipv6 }}">Use {{ $ipv6 }}</option>
|
||||||
x-on:click.prevent="createGithubApp('{{ $webhook_endpoint }}','{{ $preview_deployment_permissions }}',{{ $administration }})">
|
@endif
|
||||||
Register Now
|
@if ($fqdn)
|
||||||
</x-forms.button>
|
<option value="{{ $fqdn }}">Use {{ $fqdn }}</option>
|
||||||
</div>
|
@endif
|
||||||
@else
|
@if (config('app.url'))
|
||||||
<div class="flex gap-2">
|
<option value="{{ config('app.url') }}">Use {{ config('app.url') }}</option>
|
||||||
<h2>Register a GitHub App</h2>
|
@endif
|
||||||
<x-forms.button isHighlighted
|
</x-forms.select>
|
||||||
x-on:click.prevent="createGithubApp('{{ $webhook_endpoint }}','{{ $preview_deployment_permissions }}',{{ $administration }})">
|
<x-forms.button isHighlighted
|
||||||
Register Now
|
x-on:click.prevent="createGithubApp('{{ $webhook_endpoint }}','{{ $preview_deployment_permissions }}',{{ $administration }})">
|
||||||
</x-forms.button>
|
Register Now
|
||||||
</div>
|
</x-forms.button>
|
||||||
<div>You need to register a GitHub App before using this source.</div>
|
</div>
|
||||||
@endif
|
@else
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<h2>Register a GitHub App</h2>
|
||||||
|
<x-forms.button isHighlighted
|
||||||
|
x-on:click.prevent="createGithubApp('{{ $webhook_endpoint }}','{{ $preview_deployment_permissions }}',{{ $administration }})">
|
||||||
|
Register Now
|
||||||
|
</x-forms.button>
|
||||||
|
</div>
|
||||||
|
<div>You need to register a GitHub App before using this source.</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
<div class="flex flex-col gap-2 pt-4 w-96">
|
<div class="flex flex-col gap-2 pt-4 w-96">
|
||||||
<x-forms.checkbox disabled instantSave id="default_permissions" label="Mandatory"
|
<x-forms.checkbox disabled instantSave id="default_permissions" label="Mandatory"
|
||||||
helper="Contents: read<br>Metadata: read<br>Email: read" />
|
helper="Contents: read<br>Metadata: read<br>Email: read" />
|
||||||
<x-forms.checkbox instantSave id="preview_deployment_permissions" label="Preview Deployments "
|
<x-forms.checkbox instantSave id="preview_deployment_permissions" label="Preview Deployments "
|
||||||
helper="Necessary for updating pull requests with useful comments (deployment status, links, etc.)<br><br>Pull Request: read & write" />
|
helper="Necessary for updating pull requests with useful comments (deployment status, links, etc.)<br><br>Pull Request: read & write" />
|
||||||
{{-- <x-forms.checkbox instantSave id="administration" label="Administration (for Github Runners)"
|
{{-- <x-forms.checkbox instantSave id="administration" label="Administration (for Github Runners)"
|
||||||
helper="Necessary for adding Github Runners to repositories.<br><br>Administration: read & write" /> --}}
|
helper="Necessary for adding Github Runners to repositories.<br><br>Administration: read & write" /> --}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<script>
|
||||||
<script>
|
function createGithubApp(webhook_endpoint, preview_deployment_permissions, administration) {
|
||||||
function createGithubApp(webhook_endpoint, preview_deployment_permissions, administration) {
|
const {
|
||||||
const {
|
organization,
|
||||||
organization,
|
uuid,
|
||||||
uuid,
|
html_url
|
||||||
html_url
|
} = @json($github_app);
|
||||||
} = @json($github_app);
|
if (!webhook_endpoint) {
|
||||||
if (!webhook_endpoint) {
|
alert('Please select a webhook endpoint.');
|
||||||
alert('Please select a webhook endpoint.');
|
return;
|
||||||
return;
|
}
|
||||||
|
let baseUrl = webhook_endpoint;
|
||||||
|
const name = @js($name);
|
||||||
|
const isDev = @js(config('app.env')) ===
|
||||||
|
'local';
|
||||||
|
const devWebhook = @js(config('constants.webhooks.dev_webhook'));
|
||||||
|
if (isDev && devWebhook) {
|
||||||
|
baseUrl = devWebhook;
|
||||||
|
}
|
||||||
|
const webhookBaseUrl = `${baseUrl}/webhooks`;
|
||||||
|
const path = organization ? `organizations/${organization}/settings/apps/new` : 'settings/apps/new';
|
||||||
|
const default_permissions = {
|
||||||
|
contents: 'read',
|
||||||
|
metadata: 'read',
|
||||||
|
emails: 'read',
|
||||||
|
administration: 'read'
|
||||||
|
};
|
||||||
|
if (preview_deployment_permissions) {
|
||||||
|
default_permissions.pull_requests = 'write';
|
||||||
|
}
|
||||||
|
if (administration) {
|
||||||
|
default_permissions.administration = 'write';
|
||||||
|
}
|
||||||
|
const data = {
|
||||||
|
name,
|
||||||
|
url: baseUrl,
|
||||||
|
hook_attributes: {
|
||||||
|
url: `${webhookBaseUrl}/source/github/events`,
|
||||||
|
active: true,
|
||||||
|
},
|
||||||
|
redirect_url: `${webhookBaseUrl}/source/github/redirect`,
|
||||||
|
callback_urls: [`${baseUrl}/login/github/app`],
|
||||||
|
public: false,
|
||||||
|
request_oauth_on_install: false,
|
||||||
|
setup_url: `${webhookBaseUrl}/source/github/install?source=${uuid}`,
|
||||||
|
setup_on_update: true,
|
||||||
|
default_permissions,
|
||||||
|
default_events: ['pull_request', 'push']
|
||||||
|
};
|
||||||
|
const form = document.createElement('form');
|
||||||
|
form.setAttribute('method', 'post');
|
||||||
|
form.setAttribute('action', `${html_url}/${path}?state=${uuid}`);
|
||||||
|
const input = document.createElement('input');
|
||||||
|
input.setAttribute('id', 'manifest');
|
||||||
|
input.setAttribute('name', 'manifest');
|
||||||
|
input.setAttribute('type', 'hidden');
|
||||||
|
input.setAttribute('value', JSON.stringify(data));
|
||||||
|
form.appendChild(input);
|
||||||
|
document.getElementsByTagName('body')[0].appendChild(form);
|
||||||
|
form.submit();
|
||||||
}
|
}
|
||||||
let baseUrl = webhook_endpoint;
|
</script>
|
||||||
const name = @js($name);
|
|
||||||
const isDev = @js(config('app.env')) ===
|
|
||||||
'local';
|
|
||||||
const devWebhook = @js(config('constants.webhooks.dev_webhook'));
|
|
||||||
if (isDev && devWebhook) {
|
|
||||||
baseUrl = devWebhook;
|
|
||||||
}
|
|
||||||
const webhookBaseUrl = `${baseUrl}/webhooks`;
|
|
||||||
const path = organization ? `organizations/${organization}/settings/apps/new` : 'settings/apps/new';
|
|
||||||
const default_permissions = {
|
|
||||||
contents: 'read',
|
|
||||||
metadata: 'read',
|
|
||||||
emails: 'read',
|
|
||||||
administration: 'read'
|
|
||||||
};
|
|
||||||
if (preview_deployment_permissions) {
|
|
||||||
default_permissions.pull_requests = 'write';
|
|
||||||
}
|
|
||||||
if (administration) {
|
|
||||||
default_permissions.administration = 'write';
|
|
||||||
}
|
|
||||||
const data = {
|
|
||||||
name,
|
|
||||||
url: baseUrl,
|
|
||||||
hook_attributes: {
|
|
||||||
url: `${webhookBaseUrl}/source/github/events`,
|
|
||||||
active: true,
|
|
||||||
},
|
|
||||||
redirect_url: `${webhookBaseUrl}/source/github/redirect`,
|
|
||||||
callback_urls: [`${baseUrl}/login/github/app`],
|
|
||||||
public: false,
|
|
||||||
request_oauth_on_install: false,
|
|
||||||
setup_url: `${webhookBaseUrl}/source/github/install?source=${uuid}`,
|
|
||||||
setup_on_update: true,
|
|
||||||
default_permissions,
|
|
||||||
default_events: ['pull_request', 'push']
|
|
||||||
};
|
|
||||||
const form = document.createElement('form');
|
|
||||||
form.setAttribute('method', 'post');
|
|
||||||
form.setAttribute('action', `${html_url}/${path}?state=${uuid}`);
|
|
||||||
const input = document.createElement('input');
|
|
||||||
input.setAttribute('id', 'manifest');
|
|
||||||
input.setAttribute('name', 'manifest');
|
|
||||||
input.setAttribute('type', 'hidden');
|
|
||||||
input.setAttribute('value', JSON.stringify(data));
|
|
||||||
form.appendChild(input);
|
|
||||||
document.getElementsByTagName('body')[0].appendChild(form);
|
|
||||||
form.submit();
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
571
scripts/install-1.6.sh
Normal file
571
scripts/install-1.6.sh
Normal file
@@ -0,0 +1,571 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
## Do not modify this file. You will lose the ability to install and auto-update!
|
||||||
|
|
||||||
|
set -e # Exit immediately if a command exits with a non-zero status
|
||||||
|
## $1 could be empty, so we need to disable this check
|
||||||
|
#set -u # Treat unset variables as an error and exit
|
||||||
|
set -o pipefail # Cause a pipeline to return the status of the last command that exited with a non-zero status
|
||||||
|
CDN="https://cdn.coollabs.io/coolify"
|
||||||
|
DATE=$(date +"%Y%m%d-%H%M%S")
|
||||||
|
|
||||||
|
VERSION="1.6"
|
||||||
|
DOCKER_VERSION="27.0"
|
||||||
|
# TODO: Ask for a user
|
||||||
|
CURRENT_USER=$USER
|
||||||
|
|
||||||
|
if [ $EUID != 0 ]; then
|
||||||
|
echo "Please run this script as root or with sudo"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "Welcome to Coolify Installer!"
|
||||||
|
echo -e "This script will install everything for you. Sit back and relax."
|
||||||
|
echo -e "Source code: https://github.com/coollabsio/coolify/blob/main/scripts/install.sh\n"
|
||||||
|
|
||||||
|
# Predefined root user
|
||||||
|
ROOT_USERNAME=${ROOT_USERNAME:-}
|
||||||
|
ROOT_USER_EMAIL=${ROOT_USER_EMAIL:-}
|
||||||
|
ROOT_USER_PASSWORD=${ROOT_USER_PASSWORD:-}
|
||||||
|
|
||||||
|
TOTAL_SPACE=$(df -BG / | awk 'NR==2 {print $2}' | sed 's/G//')
|
||||||
|
AVAILABLE_SPACE=$(df -BG / | awk 'NR==2 {print $4}' | sed 's/G//')
|
||||||
|
REQUIRED_TOTAL_SPACE=30
|
||||||
|
REQUIRED_AVAILABLE_SPACE=20
|
||||||
|
WARNING_SPACE=false
|
||||||
|
|
||||||
|
if [ "$TOTAL_SPACE" -lt "$REQUIRED_TOTAL_SPACE" ]; then
|
||||||
|
WARNING_SPACE=true
|
||||||
|
cat <<EOF
|
||||||
|
WARNING: Insufficient total disk space!
|
||||||
|
|
||||||
|
Total disk space: ${TOTAL_SPACE}GB
|
||||||
|
Required disk space: ${REQUIRED_TOTAL_SPACE}GB
|
||||||
|
|
||||||
|
==================
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$AVAILABLE_SPACE" -lt "$REQUIRED_AVAILABLE_SPACE" ]; then
|
||||||
|
cat <<EOF
|
||||||
|
WARNING: Insufficient available disk space!
|
||||||
|
|
||||||
|
Available disk space: ${AVAILABLE_SPACE}GB
|
||||||
|
Required available space: ${REQUIRED_AVAILABLE_SPACE}GB
|
||||||
|
|
||||||
|
==================
|
||||||
|
EOF
|
||||||
|
WARNING_SPACE=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$WARNING_SPACE" = true ]; then
|
||||||
|
echo "Sleeping for 5 seconds."
|
||||||
|
sleep 5
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p /data/coolify/{source,ssh,applications,databases,backups,services,proxy,webhooks-during-maintenance,sentinel}
|
||||||
|
mkdir -p /data/coolify/ssh/{keys,mux}
|
||||||
|
mkdir -p /data/coolify/proxy/dynamic
|
||||||
|
|
||||||
|
chown -R 9999:root /data/coolify
|
||||||
|
chmod -R 700 /data/coolify
|
||||||
|
|
||||||
|
INSTALLATION_LOG_WITH_DATE="/data/coolify/source/installation-${DATE}.log"
|
||||||
|
|
||||||
|
exec > >(tee -a $INSTALLATION_LOG_WITH_DATE) 2>&1
|
||||||
|
|
||||||
|
getAJoke() {
|
||||||
|
JOKES=$(curl -s --max-time 2 "https://v2.jokeapi.dev/joke/Programming?blacklistFlags=nsfw,religious,political,racist,sexist,explicit&format=txt&type=single" || true)
|
||||||
|
if [ "$JOKES" != "" ]; then
|
||||||
|
echo -e " - Until then, here's a joke for you:\n"
|
||||||
|
echo -e "$JOKES\n"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
OS_TYPE=$(grep -w "ID" /etc/os-release | cut -d "=" -f 2 | tr -d '"')
|
||||||
|
ENV_FILE="/data/coolify/source/.env"
|
||||||
|
|
||||||
|
# Check if the OS is manjaro, if so, change it to arch
|
||||||
|
if [ "$OS_TYPE" = "manjaro" ] || [ "$OS_TYPE" = "manjaro-arm" ]; then
|
||||||
|
OS_TYPE="arch"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if the OS is Endeavour OS, if so, change it to arch
|
||||||
|
if [ "$OS_TYPE" = "endeavouros" ]; then
|
||||||
|
OS_TYPE="arch"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if the OS is Asahi Linux, if so, change it to fedora
|
||||||
|
if [ "$OS_TYPE" = "fedora-asahi-remix" ]; then
|
||||||
|
OS_TYPE="fedora"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if the OS is popOS, if so, change it to ubuntu
|
||||||
|
if [ "$OS_TYPE" = "pop" ]; then
|
||||||
|
OS_TYPE="ubuntu"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if the OS is linuxmint, if so, change it to ubuntu
|
||||||
|
if [ "$OS_TYPE" = "linuxmint" ]; then
|
||||||
|
OS_TYPE="ubuntu"
|
||||||
|
fi
|
||||||
|
|
||||||
|
#Check if the OS is zorin, if so, change it to ubuntu
|
||||||
|
if [ "$OS_TYPE" = "zorin" ]; then
|
||||||
|
OS_TYPE="ubuntu"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$OS_TYPE" = "arch" ] || [ "$OS_TYPE" = "archarm" ]; then
|
||||||
|
OS_VERSION="rolling"
|
||||||
|
else
|
||||||
|
OS_VERSION=$(grep -w "VERSION_ID" /etc/os-release | cut -d "=" -f 2 | tr -d '"')
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Install xargs on Amazon Linux 2023 - lol
|
||||||
|
if [ "$OS_TYPE" = 'amzn' ]; then
|
||||||
|
dnf install -y findutils >/dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
LATEST_VERSION=$(curl --silent $CDN/versions.json | grep -i version | xargs | awk '{print $2}' | tr -d ',')
|
||||||
|
LATEST_HELPER_VERSION=$(curl --silent $CDN/versions.json | grep -i version | xargs | awk '{print $6}' | tr -d ',')
|
||||||
|
LATEST_REALTIME_VERSION=$(curl --silent $CDN/versions.json | grep -i version | xargs | awk '{print $8}' | tr -d ',')
|
||||||
|
|
||||||
|
if [ -z "$LATEST_HELPER_VERSION" ]; then
|
||||||
|
LATEST_HELPER_VERSION=latest
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$LATEST_REALTIME_VERSION" ]; then
|
||||||
|
LATEST_REALTIME_VERSION=latest
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$OS_TYPE" in
|
||||||
|
arch | ubuntu | debian | raspbian | centos | fedora | rhel | ol | rocky | sles | opensuse-leap | opensuse-tumbleweed | almalinux | amzn | alpine) ;;
|
||||||
|
*)
|
||||||
|
echo "This script only supports Debian, Redhat, Arch Linux, Alpine Linux, or SLES based operating systems for now."
|
||||||
|
exit
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Overwrite LATEST_VERSION if user pass a version number
|
||||||
|
if [ "$1" != "" ]; then
|
||||||
|
LATEST_VERSION=$1
|
||||||
|
LATEST_VERSION="${LATEST_VERSION,,}"
|
||||||
|
LATEST_VERSION="${LATEST_VERSION#v}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "---------------------------------------------"
|
||||||
|
echo "| Operating System | $OS_TYPE $OS_VERSION"
|
||||||
|
echo "| Docker | $DOCKER_VERSION"
|
||||||
|
echo "| Coolify | $LATEST_VERSION"
|
||||||
|
echo "| Helper | $LATEST_HELPER_VERSION"
|
||||||
|
echo "| Realtime | $LATEST_REALTIME_VERSION"
|
||||||
|
echo -e "---------------------------------------------\n"
|
||||||
|
echo -e "1. Installing required packages (curl, wget, git, jq, openssl). "
|
||||||
|
|
||||||
|
case "$OS_TYPE" in
|
||||||
|
arch)
|
||||||
|
pacman -Sy --noconfirm --needed curl wget git jq openssl >/dev/null || true
|
||||||
|
;;
|
||||||
|
alpine)
|
||||||
|
sed -i '/^#.*\/community/s/^#//' /etc/apk/repositories
|
||||||
|
apk update >/dev/null
|
||||||
|
apk add curl wget git jq openssl >/dev/null
|
||||||
|
;;
|
||||||
|
ubuntu | debian | raspbian)
|
||||||
|
apt-get update -y >/dev/null
|
||||||
|
apt-get install -y curl wget git jq openssl >/dev/null
|
||||||
|
;;
|
||||||
|
centos | fedora | rhel | ol | rocky | almalinux | amzn)
|
||||||
|
if [ "$OS_TYPE" = "amzn" ]; then
|
||||||
|
dnf install -y wget git jq openssl >/dev/null
|
||||||
|
else
|
||||||
|
if ! command -v dnf >/dev/null; then
|
||||||
|
yum install -y dnf >/dev/null
|
||||||
|
fi
|
||||||
|
if ! command -v curl >/dev/null; then
|
||||||
|
dnf install -y curl >/dev/null
|
||||||
|
fi
|
||||||
|
dnf install -y wget git jq openssl >/dev/null
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
sles | opensuse-leap | opensuse-tumbleweed)
|
||||||
|
zypper refresh >/dev/null
|
||||||
|
zypper install -y curl wget git jq openssl >/dev/null
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "This script only supports Debian, Redhat, Arch Linux, or SLES based operating systems for now."
|
||||||
|
exit
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo -e "2. Check OpenSSH server configuration. "
|
||||||
|
|
||||||
|
# Detect OpenSSH server
|
||||||
|
SSH_DETECTED=false
|
||||||
|
if [ -x "$(command -v systemctl)" ]; then
|
||||||
|
if systemctl status sshd >/dev/null 2>&1; then
|
||||||
|
echo " - OpenSSH server is installed."
|
||||||
|
SSH_DETECTED=true
|
||||||
|
elif systemctl status ssh >/dev/null 2>&1; then
|
||||||
|
echo " - OpenSSH server is installed."
|
||||||
|
SSH_DETECTED=true
|
||||||
|
fi
|
||||||
|
elif [ -x "$(command -v service)" ]; then
|
||||||
|
if service sshd status >/dev/null 2>&1; then
|
||||||
|
echo " - OpenSSH server is installed."
|
||||||
|
SSH_DETECTED=true
|
||||||
|
elif service ssh status >/dev/null 2>&1; then
|
||||||
|
echo " - OpenSSH server is installed."
|
||||||
|
SSH_DETECTED=true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$SSH_DETECTED" = "false" ]; then
|
||||||
|
echo " - OpenSSH server not detected. Installing OpenSSH server."
|
||||||
|
case "$OS_TYPE" in
|
||||||
|
arch)
|
||||||
|
pacman -Sy --noconfirm openssh >/dev/null
|
||||||
|
systemctl enable sshd >/dev/null 2>&1
|
||||||
|
systemctl start sshd >/dev/null 2>&1
|
||||||
|
;;
|
||||||
|
alpine)
|
||||||
|
apk add openssh >/dev/null
|
||||||
|
rc-update add sshd default >/dev/null 2>&1
|
||||||
|
service sshd start >/dev/null 2>&1
|
||||||
|
;;
|
||||||
|
ubuntu | debian | raspbian)
|
||||||
|
apt-get update -y >/dev/null
|
||||||
|
apt-get install -y openssh-server >/dev/null
|
||||||
|
systemctl enable ssh >/dev/null 2>&1
|
||||||
|
systemctl start ssh >/dev/null 2>&1
|
||||||
|
;;
|
||||||
|
centos | fedora | rhel | ol | rocky | almalinux | amzn)
|
||||||
|
if [ "$OS_TYPE" = "amzn" ]; then
|
||||||
|
dnf install -y openssh-server >/dev/null
|
||||||
|
else
|
||||||
|
dnf install -y openssh-server >/dev/null
|
||||||
|
fi
|
||||||
|
systemctl enable sshd >/dev/null 2>&1
|
||||||
|
systemctl start sshd >/dev/null 2>&1
|
||||||
|
;;
|
||||||
|
sles | opensuse-leap | opensuse-tumbleweed)
|
||||||
|
zypper install -y openssh >/dev/null
|
||||||
|
systemctl enable sshd >/dev/null 2>&1
|
||||||
|
systemctl start sshd >/dev/null 2>&1
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "###############################################################################"
|
||||||
|
echo "WARNING: Could not detect and install OpenSSH server - this does not mean that it is not installed or not running, just that we could not detect it."
|
||||||
|
echo -e "Please make sure it is installed and running, otherwise Coolify cannot connect to the host system. \n"
|
||||||
|
echo "###############################################################################"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
echo " - OpenSSH server installed successfully."
|
||||||
|
SSH_DETECTED=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Detect SSH PermitRootLogin
|
||||||
|
SSH_PERMIT_ROOT_LOGIN=$(sshd -T | grep -i "permitrootlogin" | awk '{print $2}') || true
|
||||||
|
if [ "$SSH_PERMIT_ROOT_LOGIN" = "yes" ] || [ "$SSH_PERMIT_ROOT_LOGIN" = "without-password" ] || [ "$SSH_PERMIT_ROOT_LOGIN" = "prohibit-password" ]; then
|
||||||
|
echo " - SSH PermitRootLogin is enabled."
|
||||||
|
else
|
||||||
|
echo " - SSH PermitRootLogin is disabled."
|
||||||
|
echo " If you have problems with SSH, please read this: https://coolify.io/docs/knowledge-base/server/openssh"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Detect if docker is installed via snap
|
||||||
|
if [ -x "$(command -v snap)" ]; then
|
||||||
|
SNAP_DOCKER_INSTALLED=$(snap list docker >/dev/null 2>&1 && echo "true" || echo "false")
|
||||||
|
if [ "$SNAP_DOCKER_INSTALLED" = "true" ]; then
|
||||||
|
echo " - Docker is installed via snap."
|
||||||
|
echo " Please note that Coolify does not support Docker installed via snap."
|
||||||
|
echo " Please remove Docker with snap (snap remove docker) and reexecute this script."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "3. Check Docker Installation. "
|
||||||
|
if ! [ -x "$(command -v docker)" ]; then
|
||||||
|
echo " - Docker is not installed. Installing Docker. It may take a while."
|
||||||
|
getAJoke
|
||||||
|
case "$OS_TYPE" in
|
||||||
|
"almalinux")
|
||||||
|
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
|
||||||
|
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
|
||||||
|
systemctl start docker >/dev/null 2>&1
|
||||||
|
systemctl enable docker >/dev/null 2>&1
|
||||||
|
;;
|
||||||
|
"alpine")
|
||||||
|
apk add docker docker-cli-compose >/dev/null 2>&1
|
||||||
|
rc-update add docker default >/dev/null 2>&1
|
||||||
|
service docker start >/dev/null 2>&1
|
||||||
|
if ! [ -x "$(command -v docker)" ]; then
|
||||||
|
echo " - Failed to install Docker with apk. Try to install it manually."
|
||||||
|
echo " Please visit https://wiki.alpinelinux.org/wiki/Docker for more information."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
"arch")
|
||||||
|
pacman -Sy docker docker-compose --noconfirm >/dev/null 2>&1
|
||||||
|
systemctl enable docker.service >/dev/null 2>&1
|
||||||
|
if ! [ -x "$(command -v docker)" ]; then
|
||||||
|
echo " - Failed to install Docker with pacman. Try to install it manually."
|
||||||
|
echo " Please visit https://wiki.archlinux.org/title/docker for more information."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
"amzn")
|
||||||
|
dnf install docker -y >/dev/null 2>&1
|
||||||
|
DOCKER_CONFIG=${DOCKER_CONFIG:-/usr/local/lib/docker}
|
||||||
|
mkdir -p $DOCKER_CONFIG/cli-plugins >/dev/null 2>&1
|
||||||
|
curl -sL https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m) -o $DOCKER_CONFIG/cli-plugins/docker-compose >/dev/null 2>&1
|
||||||
|
chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose >/dev/null 2>&1
|
||||||
|
systemctl start docker >/dev/null 2>&1
|
||||||
|
systemctl enable docker >/dev/null 2>&1
|
||||||
|
if ! [ -x "$(command -v docker)" ]; then
|
||||||
|
echo " - Failed to install Docker with dnf. Try to install it manually."
|
||||||
|
echo " Please visit https://www.cyberciti.biz/faq/how-to-install-docker-on-amazon-linux-2/ for more information."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
"fedora")
|
||||||
|
if [ -x "$(command -v dnf5)" ]; then
|
||||||
|
# dnf5 is available
|
||||||
|
dnf config-manager addrepo --from-repofile=https://download.docker.com/linux/fedora/docker-ce.repo --overwrite >/dev/null 2>&1
|
||||||
|
else
|
||||||
|
# dnf5 is not available, use dnf
|
||||||
|
dnf config-manager --add-repo=https://download.docker.com/linux/fedora/docker-ce.repo >/dev/null 2>&1
|
||||||
|
fi
|
||||||
|
dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin >/dev/null 2>&1
|
||||||
|
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
|
||||||
|
systemctl start docker >/dev/null 2>&1
|
||||||
|
systemctl enable docker >/dev/null 2>&1
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if [ "$OS_TYPE" = "ubuntu" ] && [ "$OS_VERSION" = "24.10" ]; then
|
||||||
|
echo "Docker automated installation is not supported on Ubuntu 24.10 (non-LTS release)."
|
||||||
|
echo "Please install Docker manually."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
curl -s https://releases.rancher.com/install-docker/${DOCKER_VERSION}.sh | sh 2>&1
|
||||||
|
if ! [ -x "$(command -v docker)" ]; then
|
||||||
|
curl -s https://get.docker.com | sh -s -- --version ${DOCKER_VERSION} 2>&1
|
||||||
|
if ! [ -x "$(command -v docker)" ]; then
|
||||||
|
echo " - Docker installation failed."
|
||||||
|
echo " Maybe your OS is not supported?"
|
||||||
|
echo " - Please visit https://docs.docker.com/engine/install/ and install Docker manually to continue."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
echo " - Docker installed successfully."
|
||||||
|
else
|
||||||
|
echo " - Docker is installed."
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "4. Check Docker Configuration. "
|
||||||
|
mkdir -p /etc/docker
|
||||||
|
# shellcheck disable=SC2015
|
||||||
|
test -s /etc/docker/daemon.json && cp /etc/docker/daemon.json /etc/docker/daemon.json.original-"$DATE" || cat >/etc/docker/daemon.json <<EOL
|
||||||
|
{
|
||||||
|
"log-driver": "json-file",
|
||||||
|
"log-opts": {
|
||||||
|
"max-size": "10m",
|
||||||
|
"max-file": "3"
|
||||||
|
},
|
||||||
|
"default-address-pools": [
|
||||||
|
{"base":"10.0.0.0/8","size":24}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
EOL
|
||||||
|
cat >/etc/docker/daemon.json.coolify <<EOL
|
||||||
|
{
|
||||||
|
"log-driver": "json-file",
|
||||||
|
"log-opts": {
|
||||||
|
"max-size": "10m",
|
||||||
|
"max-file": "3"
|
||||||
|
},
|
||||||
|
"default-address-pools": [
|
||||||
|
{"base":"10.0.0.0/8","size":24}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
EOL
|
||||||
|
TEMP_FILE=$(mktemp)
|
||||||
|
if ! jq -s '.[0] * .[1]' /etc/docker/daemon.json /etc/docker/daemon.json.coolify >"$TEMP_FILE"; then
|
||||||
|
echo "Error merging JSON files"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
mv "$TEMP_FILE" /etc/docker/daemon.json
|
||||||
|
|
||||||
|
restart_docker_service() {
|
||||||
|
# Check if systemctl is available
|
||||||
|
if command -v systemctl >/dev/null 2>&1; then
|
||||||
|
echo " - Using systemctl to restart Docker."
|
||||||
|
systemctl restart docker
|
||||||
|
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo " - Docker restarted successfully using systemctl."
|
||||||
|
else
|
||||||
|
echo " - Failed to restart Docker using systemctl."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if service command is available
|
||||||
|
elif command -v service >/dev/null 2>&1; then
|
||||||
|
echo " - Using service command to restart Docker."
|
||||||
|
service docker restart
|
||||||
|
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo " - Docker restarted successfully using service."
|
||||||
|
else
|
||||||
|
echo " - Failed to restart Docker using service."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If neither systemctl nor service is available
|
||||||
|
else
|
||||||
|
echo " - Neither systemctl nor service command is available on this system."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ -s /etc/docker/daemon.json.original-"$DATE" ]; then
|
||||||
|
DIFF=$(diff <(jq --sort-keys . /etc/docker/daemon.json) <(jq --sort-keys . /etc/docker/daemon.json.original-"$DATE"))
|
||||||
|
if [ "$DIFF" != "" ]; then
|
||||||
|
echo " - Docker configuration updated, restart docker daemon..."
|
||||||
|
restart_docker_service
|
||||||
|
else
|
||||||
|
echo " - Docker configuration is up to date."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo " - Docker configuration updated, restart docker daemon..."
|
||||||
|
restart_docker_service
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "5. Download required files from CDN. "
|
||||||
|
curl -fsSL $CDN/docker-compose.yml -o /data/coolify/source/docker-compose.yml
|
||||||
|
curl -fsSL $CDN/docker-compose.prod.yml -o /data/coolify/source/docker-compose.prod.yml
|
||||||
|
curl -fsSL $CDN/.env.production -o /data/coolify/source/.env.production
|
||||||
|
curl -fsSL $CDN/upgrade.sh -o /data/coolify/source/upgrade.sh
|
||||||
|
|
||||||
|
echo -e "6. Make backup of .env to .env-$DATE"
|
||||||
|
|
||||||
|
# Copy .env.example if .env does not exist
|
||||||
|
if [ -f $ENV_FILE ]; then
|
||||||
|
cp $ENV_FILE $ENV_FILE-$DATE
|
||||||
|
else
|
||||||
|
echo " - File does not exist: $ENV_FILE"
|
||||||
|
echo " - Copying .env.production to .env-$DATE"
|
||||||
|
cp /data/coolify/source/.env.production $ENV_FILE-$DATE
|
||||||
|
# Generate a secure APP_ID and APP_KEY
|
||||||
|
sed -i "s|^APP_ID=.*|APP_ID=$(openssl rand -hex 16)|" "$ENV_FILE-$DATE"
|
||||||
|
sed -i "s|^APP_KEY=.*|APP_KEY=base64:$(openssl rand -base64 32)|" "$ENV_FILE-$DATE"
|
||||||
|
|
||||||
|
# Generate a secure Postgres DB username and password
|
||||||
|
# Causes issues: database "random-user" does not exist
|
||||||
|
# sed -i "s|^DB_USERNAME=.*|DB_USERNAME=$(openssl rand -hex 16)|" "$ENV_FILE-$DATE"
|
||||||
|
sed -i "s|^DB_PASSWORD=.*|DB_PASSWORD=$(openssl rand -base64 32)|" "$ENV_FILE-$DATE"
|
||||||
|
|
||||||
|
# Generate a secure Redis password
|
||||||
|
sed -i "s|^REDIS_PASSWORD=.*|REDIS_PASSWORD=$(openssl rand -base64 32)|" "$ENV_FILE-$DATE"
|
||||||
|
|
||||||
|
# Generate secure Pusher credentials
|
||||||
|
sed -i "s|^PUSHER_APP_ID=.*|PUSHER_APP_ID=$(openssl rand -hex 32)|" "$ENV_FILE-$DATE"
|
||||||
|
sed -i "s|^PUSHER_APP_KEY=.*|PUSHER_APP_KEY=$(openssl rand -hex 32)|" "$ENV_FILE-$DATE"
|
||||||
|
sed -i "s|^PUSHER_APP_SECRET=.*|PUSHER_APP_SECRET=$(openssl rand -hex 32)|" "$ENV_FILE-$DATE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add default root user credentials from environment variables
|
||||||
|
if [ -n "$ROOT_USERNAME" ] && [ -n "$ROOT_USER_EMAIL" ] && [ -n "$ROOT_USER_PASSWORD" ]; then
|
||||||
|
if grep -q "^ROOT_USERNAME=" "$ENV_FILE-$DATE"; then
|
||||||
|
sed -i "s|^ROOT_USERNAME=.*|ROOT_USERNAME=$ROOT_USERNAME|" "$ENV_FILE-$DATE"
|
||||||
|
fi
|
||||||
|
if grep -q "^ROOT_USER_EMAIL=" "$ENV_FILE-$DATE"; then
|
||||||
|
sed -i "s|^ROOT_USER_EMAIL=.*|ROOT_USER_EMAIL=$ROOT_USER_EMAIL|" "$ENV_FILE-$DATE"
|
||||||
|
fi
|
||||||
|
if grep -q "^ROOT_USER_PASSWORD=" "$ENV_FILE-$DATE"; then
|
||||||
|
sed -i "s|^ROOT_USER_PASSWORD=.*|ROOT_USER_PASSWORD=$ROOT_USER_PASSWORD|" "$ENV_FILE-$DATE"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Merge .env and .env.production. New values will be added to .env
|
||||||
|
echo -e "7. Propagating .env with new values - if necessary."
|
||||||
|
awk -F '=' '!seen[$1]++' "$ENV_FILE-$DATE" /data/coolify/source/.env.production >$ENV_FILE
|
||||||
|
|
||||||
|
if [ "$AUTOUPDATE" = "false" ]; then
|
||||||
|
if ! grep -q "AUTOUPDATE=" /data/coolify/source/.env; then
|
||||||
|
echo "AUTOUPDATE=false" >>/data/coolify/source/.env
|
||||||
|
else
|
||||||
|
sed -i "s|AUTOUPDATE=.*|AUTOUPDATE=false|g" /data/coolify/source/.env
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
echo -e "8. Checking for SSH key for localhost access."
|
||||||
|
if [ ! -f ~/.ssh/authorized_keys ]; then
|
||||||
|
mkdir -p ~/.ssh
|
||||||
|
chmod 700 ~/.ssh
|
||||||
|
touch ~/.ssh/authorized_keys
|
||||||
|
chmod 600 ~/.ssh/authorized_keys
|
||||||
|
fi
|
||||||
|
|
||||||
|
set +e
|
||||||
|
IS_COOLIFY_VOLUME_EXISTS=$(docker volume ls | grep coolify-db | wc -l)
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ "$IS_COOLIFY_VOLUME_EXISTS" -eq 0 ]; then
|
||||||
|
echo " - Generating SSH key."
|
||||||
|
ssh-keygen -t ed25519 -a 100 -f /data/coolify/ssh/keys/id.$CURRENT_USER@host.docker.internal -q -N "" -C coolify
|
||||||
|
chown 9999 /data/coolify/ssh/keys/id.$CURRENT_USER@host.docker.internal
|
||||||
|
sed -i "/coolify/d" ~/.ssh/authorized_keys
|
||||||
|
cat /data/coolify/ssh/keys/id.$CURRENT_USER@host.docker.internal.pub >>~/.ssh/authorized_keys
|
||||||
|
rm -f /data/coolify/ssh/keys/id.$CURRENT_USER@host.docker.internal.pub
|
||||||
|
fi
|
||||||
|
|
||||||
|
chown -R 9999:root /data/coolify
|
||||||
|
chmod -R 700 /data/coolify
|
||||||
|
|
||||||
|
echo -e "9. Installing Coolify ($LATEST_VERSION)"
|
||||||
|
echo -e " - It could take a while based on your server's performance, network speed, stars, etc."
|
||||||
|
echo -e " - Please wait."
|
||||||
|
getAJoke
|
||||||
|
|
||||||
|
bash /data/coolify/source/upgrade.sh "${LATEST_VERSION:-latest}" "${LATEST_HELPER_VERSION:-latest}"
|
||||||
|
echo " - Coolify installed successfully."
|
||||||
|
rm -f $ENV_FILE-$DATE
|
||||||
|
|
||||||
|
echo " - Waiting for 20 seconds for Coolify (database migrations) to be ready."
|
||||||
|
getAJoke
|
||||||
|
|
||||||
|
sleep 20
|
||||||
|
echo -e "\033[0;35m
|
||||||
|
____ _ _ _ _ _
|
||||||
|
/ ___|___ _ __ __ _ _ __ __ _| |_ _ _| | __ _| |_(_) ___ _ __ ___| |
|
||||||
|
| | / _ \| '_ \ / _\` | '__/ _\` | __| | | | |/ _\` | __| |/ _ \| '_ \/ __| |
|
||||||
|
| |__| (_) | | | | (_| | | | (_| | |_| |_| | | (_| | |_| | (_) | | | \__ \_|
|
||||||
|
\____\___/|_| |_|\__, |_| \__,_|\__|\__,_|_|\__,_|\__|_|\___/|_| |_|___(_)
|
||||||
|
|___/
|
||||||
|
\033[0m"
|
||||||
|
echo -e "\nYour instance is ready to use!\n"
|
||||||
|
echo -e "You can access Coolify through your Public IP: http://$(curl -4s https://ifconfig.io):8000"
|
||||||
|
|
||||||
|
set +e
|
||||||
|
DEFAULT_PRIVATE_IP=$(ip route get 1 | sed -n 's/^.*src \([0-9.]*\) .*$/\1/p')
|
||||||
|
PRIVATE_IPS=$(hostname -I 2>/dev/null || ip -o addr show scope global | awk '{print $4}' | cut -d/ -f1)
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ -n "$PRIVATE_IPS" ]; then
|
||||||
|
echo -e "\nIf your Public IP is not accessible, you can use the following Private IPs:\n"
|
||||||
|
for IP in $PRIVATE_IPS; do
|
||||||
|
if [ "$IP" != "$DEFAULT_PRIVATE_IP" ]; then
|
||||||
|
echo -e "http://$IP:8000"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
echo -e "\nWARNING: It is highly recommended to backup your Environment variables file (/data/coolify/source/.env) to a safe location, outside of this server (e.g. into a Password Manager).\n"
|
||||||
|
cp /data/coolify/source/.env /data/coolify/source/.env.backup
|
789
scripts/install-1.7.sh
Executable file
789
scripts/install-1.7.sh
Executable file
@@ -0,0 +1,789 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
## Do not modify this file. You will lose the ability to install and auto-update!
|
||||||
|
|
||||||
|
## Environment variables that can be set:
|
||||||
|
## ROOT_USERNAME - Predefined root username
|
||||||
|
## ROOT_USER_EMAIL - Predefined root user email
|
||||||
|
## ROOT_USER_PASSWORD - Predefined root user password
|
||||||
|
## DOCKER_ADDRESS_POOL_BASE - Custom Docker address pool base (default: 10.0.0.0/8)
|
||||||
|
## DOCKER_ADDRESS_POOL_SIZE - Custom Docker address pool size (default: 24)
|
||||||
|
## DOCKER_POOL_FORCE_OVERRIDE - Force override Docker address pool configuration (default: false)
|
||||||
|
## AUTOUPDATE - Set to "false" to disable auto-updates
|
||||||
|
|
||||||
|
set -e # Exit immediately if a command exits with a non-zero status
|
||||||
|
## $1 could be empty, so we need to disable this check
|
||||||
|
#set -u # Treat unset variables as an error and exit
|
||||||
|
set -o pipefail # Cause a pipeline to return the status of the last command that exited with a non-zero status
|
||||||
|
CDN="https://cdn.coollabs.io/coolify"
|
||||||
|
DATE=$(date +"%Y%m%d-%H%M%S")
|
||||||
|
|
||||||
|
VERSION="1.7"
|
||||||
|
DOCKER_VERSION="27.0"
|
||||||
|
# TODO: Ask for a user
|
||||||
|
CURRENT_USER=$USER
|
||||||
|
|
||||||
|
if [ $EUID != 0 ]; then
|
||||||
|
echo "Please run this script as root or with sudo"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "Welcome to Coolify Installer!"
|
||||||
|
echo -e "This script will install everything for you. Sit back and relax."
|
||||||
|
echo -e "Source code: https://github.com/coollabsio/coolify/blob/main/scripts/install.sh\n"
|
||||||
|
|
||||||
|
# Predefined root user
|
||||||
|
ROOT_USERNAME=${ROOT_USERNAME:-}
|
||||||
|
ROOT_USER_EMAIL=${ROOT_USER_EMAIL:-}
|
||||||
|
ROOT_USER_PASSWORD=${ROOT_USER_PASSWORD:-}
|
||||||
|
|
||||||
|
# Docker address pool configuration defaults
|
||||||
|
DOCKER_ADDRESS_POOL_BASE_DEFAULT="10.0.0.0/8"
|
||||||
|
DOCKER_ADDRESS_POOL_SIZE_DEFAULT=24
|
||||||
|
|
||||||
|
# Check if environment variables were explicitly provided
|
||||||
|
DOCKER_POOL_BASE_PROVIDED=false
|
||||||
|
DOCKER_POOL_SIZE_PROVIDED=false
|
||||||
|
DOCKER_POOL_FORCE_OVERRIDE=${DOCKER_POOL_FORCE_OVERRIDE:-false}
|
||||||
|
|
||||||
|
if [ -n "${DOCKER_ADDRESS_POOL_BASE+x}" ]; then
|
||||||
|
DOCKER_POOL_BASE_PROVIDED=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "${DOCKER_ADDRESS_POOL_SIZE+x}" ]; then
|
||||||
|
DOCKER_POOL_SIZE_PROVIDED=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
restart_docker_service() {
|
||||||
|
# Check if systemctl is available
|
||||||
|
if command -v systemctl >/dev/null 2>&1; then
|
||||||
|
systemctl restart docker
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo " - Docker daemon restarted successfully"
|
||||||
|
else
|
||||||
|
echo " - Failed to restart Docker daemon"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
# Check if service command is available
|
||||||
|
elif command -v service >/dev/null 2>&1; then
|
||||||
|
service docker restart
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo " - Docker daemon restarted successfully"
|
||||||
|
else
|
||||||
|
echo " - Failed to restart Docker daemon"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
# If neither systemctl nor service is available
|
||||||
|
else
|
||||||
|
echo " - Error: No service management system found"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to compare address pools
|
||||||
|
compare_address_pools() {
|
||||||
|
local base1="$1"
|
||||||
|
local size1="$2"
|
||||||
|
local base2="$3"
|
||||||
|
local size2="$4"
|
||||||
|
|
||||||
|
# Normalize CIDR notation for comparison
|
||||||
|
local ip1=$(echo "$base1" | cut -d'/' -f1)
|
||||||
|
local prefix1=$(echo "$base1" | cut -d'/' -f2)
|
||||||
|
local ip2=$(echo "$base2" | cut -d'/' -f1)
|
||||||
|
local prefix2=$(echo "$base2" | cut -d'/' -f2)
|
||||||
|
|
||||||
|
# Compare IPs and prefixes
|
||||||
|
if [ "$ip1" = "$ip2" ] && [ "$prefix1" = "$prefix2" ] && [ "$size1" = "$size2" ]; then
|
||||||
|
return 0 # Pools are the same
|
||||||
|
else
|
||||||
|
return 1 # Pools are different
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Docker address pool configuration
|
||||||
|
DOCKER_ADDRESS_POOL_BASE=${DOCKER_ADDRESS_POOL_BASE:-"$DOCKER_ADDRESS_POOL_BASE_DEFAULT"}
|
||||||
|
DOCKER_ADDRESS_POOL_SIZE=${DOCKER_ADDRESS_POOL_SIZE:-$DOCKER_ADDRESS_POOL_SIZE_DEFAULT}
|
||||||
|
|
||||||
|
# Load Docker address pool configuration from .env file if it exists and environment variables were not provided
|
||||||
|
if [ -f "/data/coolify/source/.env" ] && [ "$DOCKER_POOL_BASE_PROVIDED" = false ] && [ "$DOCKER_POOL_SIZE_PROVIDED" = false ]; then
|
||||||
|
ENV_DOCKER_ADDRESS_POOL_BASE=$(grep -E "^DOCKER_ADDRESS_POOL_BASE=" /data/coolify/source/.env | cut -d '=' -f2)
|
||||||
|
ENV_DOCKER_ADDRESS_POOL_SIZE=$(grep -E "^DOCKER_ADDRESS_POOL_SIZE=" /data/coolify/source/.env | cut -d '=' -f2)
|
||||||
|
|
||||||
|
if [ -n "$ENV_DOCKER_ADDRESS_POOL_BASE" ]; then
|
||||||
|
DOCKER_ADDRESS_POOL_BASE="$ENV_DOCKER_ADDRESS_POOL_BASE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$ENV_DOCKER_ADDRESS_POOL_SIZE" ]; then
|
||||||
|
DOCKER_ADDRESS_POOL_SIZE="$ENV_DOCKER_ADDRESS_POOL_SIZE"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if daemon.json exists and extract existing address pool configuration
|
||||||
|
EXISTING_POOL_CONFIGURED=false
|
||||||
|
if [ -f /etc/docker/daemon.json ]; then
|
||||||
|
if jq -e '.["default-address-pools"]' /etc/docker/daemon.json >/dev/null 2>&1; then
|
||||||
|
EXISTING_POOL_BASE=$(jq -r '.["default-address-pools"][0].base' /etc/docker/daemon.json 2>/dev/null)
|
||||||
|
EXISTING_POOL_SIZE=$(jq -r '.["default-address-pools"][0].size' /etc/docker/daemon.json 2>/dev/null)
|
||||||
|
|
||||||
|
if [ -n "$EXISTING_POOL_BASE" ] && [ -n "$EXISTING_POOL_SIZE" ] && [ "$EXISTING_POOL_BASE" != "null" ] && [ "$EXISTING_POOL_SIZE" != "null" ]; then
|
||||||
|
echo "Found existing Docker network pool: $EXISTING_POOL_BASE/$EXISTING_POOL_SIZE"
|
||||||
|
EXISTING_POOL_CONFIGURED=true
|
||||||
|
|
||||||
|
# Check if environment variables were explicitly provided
|
||||||
|
if [ "$DOCKER_POOL_BASE_PROVIDED" = false ] && [ "$DOCKER_POOL_SIZE_PROVIDED" = false ]; then
|
||||||
|
DOCKER_ADDRESS_POOL_BASE="$EXISTING_POOL_BASE"
|
||||||
|
DOCKER_ADDRESS_POOL_SIZE="$EXISTING_POOL_SIZE"
|
||||||
|
else
|
||||||
|
# Check if force override is enabled
|
||||||
|
if [ "$DOCKER_POOL_FORCE_OVERRIDE" = true ]; then
|
||||||
|
echo "Force override enabled - network pool will be updated with $DOCKER_ADDRESS_POOL_BASE/$DOCKER_ADDRESS_POOL_SIZE."
|
||||||
|
else
|
||||||
|
echo "Custom pool provided but force override not enabled - using existing configuration."
|
||||||
|
echo "To force override, set DOCKER_POOL_FORCE_OVERRIDE=true"
|
||||||
|
echo "This won't change the existing docker networks, only the pool configuration for the newly created networks."
|
||||||
|
DOCKER_ADDRESS_POOL_BASE="$EXISTING_POOL_BASE"
|
||||||
|
DOCKER_ADDRESS_POOL_SIZE="$EXISTING_POOL_SIZE"
|
||||||
|
DOCKER_POOL_BASE_PROVIDED=false
|
||||||
|
DOCKER_POOL_SIZE_PROVIDED=false
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Validate Docker address pool configuration
|
||||||
|
if ! [[ $DOCKER_ADDRESS_POOL_BASE =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/[0-9]+$ ]]; then
|
||||||
|
echo "Warning: Invalid network pool base format: $DOCKER_ADDRESS_POOL_BASE"
|
||||||
|
if [ "$EXISTING_POOL_CONFIGURED" = true ]; then
|
||||||
|
echo "Using existing configuration: $EXISTING_POOL_BASE"
|
||||||
|
DOCKER_ADDRESS_POOL_BASE="$EXISTING_POOL_BASE"
|
||||||
|
else
|
||||||
|
echo "Using default configuration: $DOCKER_ADDRESS_POOL_BASE_DEFAULT"
|
||||||
|
DOCKER_ADDRESS_POOL_BASE="$DOCKER_ADDRESS_POOL_BASE_DEFAULT"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! [[ $DOCKER_ADDRESS_POOL_SIZE =~ ^[0-9]+$ ]] || [ "$DOCKER_ADDRESS_POOL_SIZE" -lt 16 ] || [ "$DOCKER_ADDRESS_POOL_SIZE" -gt 28 ]; then
|
||||||
|
echo "Warning: Invalid network pool size: $DOCKER_ADDRESS_POOL_SIZE (must be 16-28)"
|
||||||
|
if [ "$EXISTING_POOL_CONFIGURED" = true ]; then
|
||||||
|
echo "Using existing configuration: $EXISTING_POOL_SIZE"
|
||||||
|
DOCKER_ADDRESS_POOL_SIZE="$EXISTING_POOL_SIZE"
|
||||||
|
else
|
||||||
|
echo "Using default configuration: $DOCKER_ADDRESS_POOL_SIZE_DEFAULT"
|
||||||
|
DOCKER_ADDRESS_POOL_SIZE=$DOCKER_ADDRESS_POOL_SIZE_DEFAULT
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
TOTAL_SPACE=$(df -BG / | awk 'NR==2 {print $2}' | sed 's/G//')
|
||||||
|
AVAILABLE_SPACE=$(df -BG / | awk 'NR==2 {print $4}' | sed 's/G//')
|
||||||
|
REQUIRED_TOTAL_SPACE=30
|
||||||
|
REQUIRED_AVAILABLE_SPACE=20
|
||||||
|
WARNING_SPACE=false
|
||||||
|
|
||||||
|
if [ "$TOTAL_SPACE" -lt "$REQUIRED_TOTAL_SPACE" ]; then
|
||||||
|
WARNING_SPACE=true
|
||||||
|
cat <<EOF
|
||||||
|
WARNING: Insufficient total disk space!
|
||||||
|
|
||||||
|
Total disk space: ${TOTAL_SPACE}GB
|
||||||
|
Required disk space: ${REQUIRED_TOTAL_SPACE}GB
|
||||||
|
|
||||||
|
==================
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$AVAILABLE_SPACE" -lt "$REQUIRED_AVAILABLE_SPACE" ]; then
|
||||||
|
cat <<EOF
|
||||||
|
WARNING: Insufficient available disk space!
|
||||||
|
|
||||||
|
Available disk space: ${AVAILABLE_SPACE}GB
|
||||||
|
Required available space: ${REQUIRED_AVAILABLE_SPACE}GB
|
||||||
|
|
||||||
|
==================
|
||||||
|
EOF
|
||||||
|
WARNING_SPACE=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$WARNING_SPACE" = true ]; then
|
||||||
|
echo "Sleeping for 5 seconds."
|
||||||
|
sleep 5
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p /data/coolify/{source,ssh,applications,databases,backups,services,proxy,webhooks-during-maintenance,sentinel}
|
||||||
|
mkdir -p /data/coolify/ssh/{keys,mux}
|
||||||
|
mkdir -p /data/coolify/proxy/dynamic
|
||||||
|
|
||||||
|
chown -R 9999:root /data/coolify
|
||||||
|
chmod -R 700 /data/coolify
|
||||||
|
|
||||||
|
INSTALLATION_LOG_WITH_DATE="/data/coolify/source/installation-${DATE}.log"
|
||||||
|
|
||||||
|
exec > >(tee -a $INSTALLATION_LOG_WITH_DATE) 2>&1
|
||||||
|
|
||||||
|
getAJoke() {
|
||||||
|
JOKES=$(curl -s --max-time 2 "https://v2.jokeapi.dev/joke/Programming?blacklistFlags=nsfw,religious,political,racist,sexist,explicit&format=txt&type=single" || true)
|
||||||
|
if [ "$JOKES" != "" ]; then
|
||||||
|
echo -e " - Until then, here's a joke for you:\n"
|
||||||
|
echo -e "$JOKES\n"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
OS_TYPE=$(grep -w "ID" /etc/os-release | cut -d "=" -f 2 | tr -d '"')
|
||||||
|
ENV_FILE="/data/coolify/source/.env"
|
||||||
|
|
||||||
|
# Check if the OS is manjaro, if so, change it to arch
|
||||||
|
if [ "$OS_TYPE" = "manjaro" ] || [ "$OS_TYPE" = "manjaro-arm" ]; then
|
||||||
|
OS_TYPE="arch"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if the OS is Endeavour OS, if so, change it to arch
|
||||||
|
if [ "$OS_TYPE" = "endeavouros" ]; then
|
||||||
|
OS_TYPE="arch"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if the OS is Asahi Linux, if so, change it to fedora
|
||||||
|
if [ "$OS_TYPE" = "fedora-asahi-remix" ]; then
|
||||||
|
OS_TYPE="fedora"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if the OS is popOS, if so, change it to ubuntu
|
||||||
|
if [ "$OS_TYPE" = "pop" ]; then
|
||||||
|
OS_TYPE="ubuntu"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if the OS is linuxmint, if so, change it to ubuntu
|
||||||
|
if [ "$OS_TYPE" = "linuxmint" ]; then
|
||||||
|
OS_TYPE="ubuntu"
|
||||||
|
fi
|
||||||
|
|
||||||
|
#Check if the OS is zorin, if so, change it to ubuntu
|
||||||
|
if [ "$OS_TYPE" = "zorin" ]; then
|
||||||
|
OS_TYPE="ubuntu"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$OS_TYPE" = "arch" ] || [ "$OS_TYPE" = "archarm" ]; then
|
||||||
|
OS_VERSION="rolling"
|
||||||
|
else
|
||||||
|
OS_VERSION=$(grep -w "VERSION_ID" /etc/os-release | cut -d "=" -f 2 | tr -d '"')
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Install xargs on Amazon Linux 2023 - lol
|
||||||
|
if [ "$OS_TYPE" = 'amzn' ]; then
|
||||||
|
dnf install -y findutils >/dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
LATEST_VERSION=$(curl --silent $CDN/versions.json | grep -i version | xargs | awk '{print $2}' | tr -d ',')
|
||||||
|
LATEST_HELPER_VERSION=$(curl --silent $CDN/versions.json | grep -i version | xargs | awk '{print $6}' | tr -d ',')
|
||||||
|
LATEST_REALTIME_VERSION=$(curl --silent $CDN/versions.json | grep -i version | xargs | awk '{print $8}' | tr -d ',')
|
||||||
|
|
||||||
|
if [ -z "$LATEST_HELPER_VERSION" ]; then
|
||||||
|
LATEST_HELPER_VERSION=latest
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$LATEST_REALTIME_VERSION" ]; then
|
||||||
|
LATEST_REALTIME_VERSION=latest
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$OS_TYPE" in
|
||||||
|
arch | ubuntu | debian | raspbian | centos | fedora | rhel | ol | rocky | sles | opensuse-leap | opensuse-tumbleweed | almalinux | amzn | alpine) ;;
|
||||||
|
*)
|
||||||
|
echo "This script only supports Debian, Redhat, Arch Linux, Alpine Linux, or SLES based operating systems for now."
|
||||||
|
exit
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Overwrite LATEST_VERSION if user pass a version number
|
||||||
|
if [ "$1" != "" ]; then
|
||||||
|
LATEST_VERSION=$1
|
||||||
|
LATEST_VERSION="${LATEST_VERSION,,}"
|
||||||
|
LATEST_VERSION="${LATEST_VERSION#v}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "---------------------------------------------"
|
||||||
|
echo "| Operating System | $OS_TYPE $OS_VERSION"
|
||||||
|
echo "| Docker | $DOCKER_VERSION"
|
||||||
|
echo "| Coolify | $LATEST_VERSION"
|
||||||
|
echo "| Helper | $LATEST_HELPER_VERSION"
|
||||||
|
echo "| Realtime | $LATEST_REALTIME_VERSION"
|
||||||
|
echo "| Docker Pool | $DOCKER_ADDRESS_POOL_BASE (size $DOCKER_ADDRESS_POOL_SIZE)"
|
||||||
|
echo -e "---------------------------------------------\n"
|
||||||
|
echo -e "1. Installing required packages (curl, wget, git, jq, openssl). "
|
||||||
|
|
||||||
|
case "$OS_TYPE" in
|
||||||
|
arch)
|
||||||
|
pacman -Sy --noconfirm --needed curl wget git jq openssl >/dev/null || true
|
||||||
|
;;
|
||||||
|
alpine)
|
||||||
|
sed -i '/^#.*\/community/s/^#//' /etc/apk/repositories
|
||||||
|
apk update >/dev/null
|
||||||
|
apk add curl wget git jq openssl >/dev/null
|
||||||
|
;;
|
||||||
|
ubuntu | debian | raspbian)
|
||||||
|
apt-get update -y >/dev/null
|
||||||
|
apt-get install -y curl wget git jq openssl >/dev/null
|
||||||
|
;;
|
||||||
|
centos | fedora | rhel | ol | rocky | almalinux | amzn)
|
||||||
|
if [ "$OS_TYPE" = "amzn" ]; then
|
||||||
|
dnf install -y wget git jq openssl >/dev/null
|
||||||
|
else
|
||||||
|
if ! command -v dnf >/dev/null; then
|
||||||
|
yum install -y dnf >/dev/null
|
||||||
|
fi
|
||||||
|
if ! command -v curl >/dev/null; then
|
||||||
|
dnf install -y curl >/dev/null
|
||||||
|
fi
|
||||||
|
dnf install -y wget git jq openssl >/dev/null
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
sles | opensuse-leap | opensuse-tumbleweed)
|
||||||
|
zypper refresh >/dev/null
|
||||||
|
zypper install -y curl wget git jq openssl >/dev/null
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "This script only supports Debian, Redhat, Arch Linux, or SLES based operating systems for now."
|
||||||
|
exit
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo -e "2. Check OpenSSH server configuration. "
|
||||||
|
|
||||||
|
# Detect OpenSSH server
|
||||||
|
SSH_DETECTED=false
|
||||||
|
if [ -x "$(command -v systemctl)" ]; then
|
||||||
|
if systemctl status sshd >/dev/null 2>&1; then
|
||||||
|
echo " - OpenSSH server is installed."
|
||||||
|
SSH_DETECTED=true
|
||||||
|
elif systemctl status ssh >/dev/null 2>&1; then
|
||||||
|
echo " - OpenSSH server is installed."
|
||||||
|
SSH_DETECTED=true
|
||||||
|
fi
|
||||||
|
elif [ -x "$(command -v service)" ]; then
|
||||||
|
if service sshd status >/dev/null 2>&1; then
|
||||||
|
echo " - OpenSSH server is installed."
|
||||||
|
SSH_DETECTED=true
|
||||||
|
elif service ssh status >/dev/null 2>&1; then
|
||||||
|
echo " - OpenSSH server is installed."
|
||||||
|
SSH_DETECTED=true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$SSH_DETECTED" = "false" ]; then
|
||||||
|
echo " - OpenSSH server not detected. Installing OpenSSH server."
|
||||||
|
case "$OS_TYPE" in
|
||||||
|
arch)
|
||||||
|
pacman -Sy --noconfirm openssh >/dev/null
|
||||||
|
systemctl enable sshd >/dev/null 2>&1
|
||||||
|
systemctl start sshd >/dev/null 2>&1
|
||||||
|
;;
|
||||||
|
alpine)
|
||||||
|
apk add openssh >/dev/null
|
||||||
|
rc-update add sshd default >/dev/null 2>&1
|
||||||
|
service sshd start >/dev/null 2>&1
|
||||||
|
;;
|
||||||
|
ubuntu | debian | raspbian)
|
||||||
|
apt-get update -y >/dev/null
|
||||||
|
apt-get install -y openssh-server >/dev/null
|
||||||
|
systemctl enable ssh >/dev/null 2>&1
|
||||||
|
systemctl start ssh >/dev/null 2>&1
|
||||||
|
;;
|
||||||
|
centos | fedora | rhel | ol | rocky | almalinux | amzn)
|
||||||
|
if [ "$OS_TYPE" = "amzn" ]; then
|
||||||
|
dnf install -y openssh-server >/dev/null
|
||||||
|
else
|
||||||
|
dnf install -y openssh-server >/dev/null
|
||||||
|
fi
|
||||||
|
systemctl enable sshd >/dev/null 2>&1
|
||||||
|
systemctl start sshd >/dev/null 2>&1
|
||||||
|
;;
|
||||||
|
sles | opensuse-leap | opensuse-tumbleweed)
|
||||||
|
zypper install -y openssh >/dev/null
|
||||||
|
systemctl enable sshd >/dev/null 2>&1
|
||||||
|
systemctl start sshd >/dev/null 2>&1
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "###############################################################################"
|
||||||
|
echo "WARNING: Could not detect and install OpenSSH server - this does not mean that it is not installed or not running, just that we could not detect it."
|
||||||
|
echo -e "Please make sure it is installed and running, otherwise Coolify cannot connect to the host system. \n"
|
||||||
|
echo "###############################################################################"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
echo " - OpenSSH server installed successfully."
|
||||||
|
SSH_DETECTED=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Detect SSH PermitRootLogin
|
||||||
|
SSH_PERMIT_ROOT_LOGIN=$(sshd -T | grep -i "permitrootlogin" | awk '{print $2}') || true
|
||||||
|
if [ "$SSH_PERMIT_ROOT_LOGIN" = "yes" ] || [ "$SSH_PERMIT_ROOT_LOGIN" = "without-password" ] || [ "$SSH_PERMIT_ROOT_LOGIN" = "prohibit-password" ]; then
|
||||||
|
echo " - SSH PermitRootLogin is enabled."
|
||||||
|
else
|
||||||
|
echo " - SSH PermitRootLogin is disabled."
|
||||||
|
echo " If you have problems with SSH, please read this: https://coolify.io/docs/knowledge-base/server/openssh"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Detect if docker is installed via snap
|
||||||
|
if [ -x "$(command -v snap)" ]; then
|
||||||
|
SNAP_DOCKER_INSTALLED=$(snap list docker >/dev/null 2>&1 && echo "true" || echo "false")
|
||||||
|
if [ "$SNAP_DOCKER_INSTALLED" = "true" ]; then
|
||||||
|
echo " - Docker is installed via snap."
|
||||||
|
echo " Please note that Coolify does not support Docker installed via snap."
|
||||||
|
echo " Please remove Docker with snap (snap remove docker) and reexecute this script."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "3. Check Docker Installation. "
|
||||||
|
if ! [ -x "$(command -v docker)" ]; then
|
||||||
|
echo " - Docker is not installed. Installing Docker. It may take a while."
|
||||||
|
getAJoke
|
||||||
|
case "$OS_TYPE" in
|
||||||
|
"almalinux")
|
||||||
|
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
|
||||||
|
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
|
||||||
|
systemctl start docker >/dev/null 2>&1
|
||||||
|
systemctl enable docker >/dev/null 2>&1
|
||||||
|
;;
|
||||||
|
"alpine")
|
||||||
|
apk add docker docker-cli-compose >/dev/null 2>&1
|
||||||
|
rc-update add docker default >/dev/null 2>&1
|
||||||
|
service docker start >/dev/null 2>&1
|
||||||
|
if ! [ -x "$(command -v docker)" ]; then
|
||||||
|
echo " - Failed to install Docker with apk. Try to install it manually."
|
||||||
|
echo " Please visit https://wiki.alpinelinux.org/wiki/Docker for more information."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
"arch")
|
||||||
|
pacman -Sy docker docker-compose --noconfirm >/dev/null 2>&1
|
||||||
|
systemctl enable docker.service >/dev/null 2>&1
|
||||||
|
if ! [ -x "$(command -v docker)" ]; then
|
||||||
|
echo " - Failed to install Docker with pacman. Try to install it manually."
|
||||||
|
echo " Please visit https://wiki.archlinux.org/title/docker for more information."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
"amzn")
|
||||||
|
dnf install docker -y >/dev/null 2>&1
|
||||||
|
DOCKER_CONFIG=${DOCKER_CONFIG:-/usr/local/lib/docker}
|
||||||
|
mkdir -p $DOCKER_CONFIG/cli-plugins >/dev/null 2>&1
|
||||||
|
curl -sL https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m) -o $DOCKER_CONFIG/cli-plugins/docker-compose >/dev/null 2>&1
|
||||||
|
chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose >/dev/null 2>&1
|
||||||
|
systemctl start docker >/dev/null 2>&1
|
||||||
|
systemctl enable docker >/dev/null 2>&1
|
||||||
|
if ! [ -x "$(command -v docker)" ]; then
|
||||||
|
echo " - Failed to install Docker with dnf. Try to install it manually."
|
||||||
|
echo " Please visit https://www.cyberciti.biz/faq/how-to-install-docker-on-amazon-linux-2/ for more information."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
"centos" | "fedora" | "rhel")
|
||||||
|
if [ -x "$(command -v dnf5)" ]; then
|
||||||
|
# dnf5 is available
|
||||||
|
dnf config-manager addrepo --from-repofile=https://download.docker.com/linux/$OS_TYPE/docker-ce.repo --overwrite >/dev/null 2>&1
|
||||||
|
else
|
||||||
|
# dnf5 is not available, use dnf
|
||||||
|
dnf config-manager --add-repo=https://download.docker.com/linux/$OS_TYPE/docker-ce.repo >/dev/null 2>&1
|
||||||
|
fi
|
||||||
|
dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin >/dev/null 2>&1
|
||||||
|
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
|
||||||
|
systemctl start docker >/dev/null 2>&1
|
||||||
|
systemctl enable docker >/dev/null 2>&1
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if [ "$OS_TYPE" = "ubuntu" ] && [ "$OS_VERSION" = "24.10" ]; then
|
||||||
|
echo "Docker automated installation is not supported on Ubuntu 24.10 (non-LTS release)."
|
||||||
|
echo "Please install Docker manually."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
curl -s https://releases.rancher.com/install-docker/${DOCKER_VERSION}.sh | sh 2>&1
|
||||||
|
if ! [ -x "$(command -v docker)" ]; then
|
||||||
|
curl -s https://get.docker.com | sh -s -- --version ${DOCKER_VERSION} 2>&1
|
||||||
|
if ! [ -x "$(command -v docker)" ]; then
|
||||||
|
echo " - Docker installation failed."
|
||||||
|
echo " Maybe your OS is not supported?"
|
||||||
|
echo " - Please visit https://docs.docker.com/engine/install/ and install Docker manually to continue."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
echo " - Docker installed successfully."
|
||||||
|
else
|
||||||
|
echo " - Docker is installed."
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "4. Check Docker Configuration. "
|
||||||
|
|
||||||
|
echo " - Network pool configuration: ${DOCKER_ADDRESS_POOL_BASE}/${DOCKER_ADDRESS_POOL_SIZE}"
|
||||||
|
echo " - To override existing configuration: DOCKER_POOL_FORCE_OVERRIDE=true"
|
||||||
|
|
||||||
|
mkdir -p /etc/docker
|
||||||
|
|
||||||
|
# Backup original daemon.json if it exists
|
||||||
|
if [ -f /etc/docker/daemon.json ]; then
|
||||||
|
cp /etc/docker/daemon.json /etc/docker/daemon.json.original-"$DATE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create coolify configuration with or without address pools based on whether they were explicitly provided
|
||||||
|
if [ "$DOCKER_POOL_FORCE_OVERRIDE" = true ] || [ "$EXISTING_POOL_CONFIGURED" = false ]; then
|
||||||
|
# First check if the configuration would actually change anything
|
||||||
|
if [ -f /etc/docker/daemon.json ]; then
|
||||||
|
CURRENT_POOL_BASE=$(jq -r '.["default-address-pools"][0].base' /etc/docker/daemon.json 2>/dev/null)
|
||||||
|
CURRENT_POOL_SIZE=$(jq -r '.["default-address-pools"][0].size' /etc/docker/daemon.json 2>/dev/null)
|
||||||
|
|
||||||
|
if [ "$CURRENT_POOL_BASE" = "$DOCKER_ADDRESS_POOL_BASE" ] && [ "$CURRENT_POOL_SIZE" = "$DOCKER_ADDRESS_POOL_SIZE" ]; then
|
||||||
|
echo " - Network pool configuration unchanged, skipping update"
|
||||||
|
NEED_MERGE=false
|
||||||
|
else
|
||||||
|
# If force override is enabled or no existing configuration exists,
|
||||||
|
# create a new configuration with the specified address pools
|
||||||
|
echo " - Creating new Docker configuration with network pool: ${DOCKER_ADDRESS_POOL_BASE}/${DOCKER_ADDRESS_POOL_SIZE}"
|
||||||
|
cat >/etc/docker/daemon.json <<EOL
|
||||||
|
{
|
||||||
|
"log-driver": "json-file",
|
||||||
|
"log-opts": {
|
||||||
|
"max-size": "10m",
|
||||||
|
"max-file": "3"
|
||||||
|
},
|
||||||
|
"default-address-pools": [
|
||||||
|
{"base":"${DOCKER_ADDRESS_POOL_BASE}","size":${DOCKER_ADDRESS_POOL_SIZE}}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
EOL
|
||||||
|
NEED_MERGE=true
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# No existing configuration, create new one
|
||||||
|
echo " - Creating new Docker configuration with network pool: ${DOCKER_ADDRESS_POOL_BASE}/${DOCKER_ADDRESS_POOL_SIZE}"
|
||||||
|
cat >/etc/docker/daemon.json <<EOL
|
||||||
|
{
|
||||||
|
"log-driver": "json-file",
|
||||||
|
"log-opts": {
|
||||||
|
"max-size": "10m",
|
||||||
|
"max-file": "3"
|
||||||
|
},
|
||||||
|
"default-address-pools": [
|
||||||
|
{"base":"${DOCKER_ADDRESS_POOL_BASE}","size":${DOCKER_ADDRESS_POOL_SIZE}}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
EOL
|
||||||
|
NEED_MERGE=true
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# Check if we need to update log settings
|
||||||
|
if [ -f /etc/docker/daemon.json ] && jq -e '.["log-driver"] == "json-file" and .["log-opts"]["max-size"] == "10m" and .["log-opts"]["max-file"] == "3"' /etc/docker/daemon.json >/dev/null 2>&1; then
|
||||||
|
echo " - Log configuration is up to date"
|
||||||
|
NEED_MERGE=false
|
||||||
|
else
|
||||||
|
# Create a configuration without address pools to preserve existing ones
|
||||||
|
cat >/etc/docker/daemon.json.coolify <<EOL
|
||||||
|
{
|
||||||
|
"log-driver": "json-file",
|
||||||
|
"log-opts": {
|
||||||
|
"max-size": "10m",
|
||||||
|
"max-file": "3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOL
|
||||||
|
NEED_MERGE=true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Remove the duplicate daemon.json creation since we handle it above
|
||||||
|
if ! [ -f /etc/docker/daemon.json ]; then
|
||||||
|
# If no daemon.json exists, create it with default settings
|
||||||
|
cat >/etc/docker/daemon.json <<EOL
|
||||||
|
{
|
||||||
|
"log-driver": "json-file",
|
||||||
|
"log-opts": {
|
||||||
|
"max-size": "10m",
|
||||||
|
"max-file": "3"
|
||||||
|
},
|
||||||
|
"default-address-pools": [
|
||||||
|
{"base":"${DOCKER_ADDRESS_POOL_BASE}","size":${DOCKER_ADDRESS_POOL_SIZE}}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
EOL
|
||||||
|
NEED_MERGE=false
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -s /etc/docker/daemon.json.original-"$DATE" ]; then
|
||||||
|
DIFF=$(diff <(jq --sort-keys . /etc/docker/daemon.json) <(jq --sort-keys . /etc/docker/daemon.json.original-"$DATE") || true)
|
||||||
|
if [ "$DIFF" != "" ]; then
|
||||||
|
echo " - Checking configuration changes..."
|
||||||
|
|
||||||
|
# Check if address pools were changed
|
||||||
|
if echo "$DIFF" | grep -q "default-address-pools"; then
|
||||||
|
if [ "$DOCKER_POOL_BASE_PROVIDED" = true ] || [ "$DOCKER_POOL_SIZE_PROVIDED" = true ]; then
|
||||||
|
echo " - Network pool updated per user request"
|
||||||
|
else
|
||||||
|
echo " - Warning: Network pool modified without explicit request"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Remove this redundant restart since we already restarted when writing the config
|
||||||
|
echo " - Configuration changes confirmed"
|
||||||
|
if [ "$NEED_MERGE" = true ]; then
|
||||||
|
echo " - Configuration updated - restarting Docker daemon..."
|
||||||
|
restart_docker_service
|
||||||
|
else
|
||||||
|
echo " - Configuration is up to date"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo " - Configuration is up to date"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [ "$NEED_MERGE" = true ]; then
|
||||||
|
echo " - Configuration updated - restarting Docker daemon..."
|
||||||
|
restart_docker_service
|
||||||
|
else
|
||||||
|
echo " - Configuration is up to date"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "5. Download required files from CDN. "
|
||||||
|
curl -fsSL $CDN/docker-compose.yml -o /data/coolify/source/docker-compose.yml
|
||||||
|
curl -fsSL $CDN/docker-compose.prod.yml -o /data/coolify/source/docker-compose.prod.yml
|
||||||
|
curl -fsSL $CDN/.env.production -o /data/coolify/source/.env.production
|
||||||
|
curl -fsSL $CDN/upgrade.sh -o /data/coolify/source/upgrade.sh
|
||||||
|
|
||||||
|
echo -e "6. Make backup of .env to .env-$DATE"
|
||||||
|
|
||||||
|
# Copy .env.example if .env does not exist
|
||||||
|
if [ -f $ENV_FILE ]; then
|
||||||
|
cp $ENV_FILE $ENV_FILE-$DATE
|
||||||
|
else
|
||||||
|
echo " - File does not exist: $ENV_FILE"
|
||||||
|
echo " - Copying .env.production to .env-$DATE"
|
||||||
|
cp /data/coolify/source/.env.production $ENV_FILE-$DATE
|
||||||
|
# Generate a secure APP_ID and APP_KEY
|
||||||
|
sed -i "s|^APP_ID=.*|APP_ID=$(openssl rand -hex 16)|" "$ENV_FILE-$DATE"
|
||||||
|
sed -i "s|^APP_KEY=.*|APP_KEY=base64:$(openssl rand -base64 32)|" "$ENV_FILE-$DATE"
|
||||||
|
|
||||||
|
# Generate a secure Postgres DB username and password
|
||||||
|
# Causes issues: database "random-user" does not exist
|
||||||
|
# sed -i "s|^DB_USERNAME=.*|DB_USERNAME=$(openssl rand -hex 16)|" "$ENV_FILE-$DATE"
|
||||||
|
sed -i "s|^DB_PASSWORD=.*|DB_PASSWORD=$(openssl rand -base64 32)|" "$ENV_FILE-$DATE"
|
||||||
|
|
||||||
|
# Generate a secure Redis password
|
||||||
|
sed -i "s|^REDIS_PASSWORD=.*|REDIS_PASSWORD=$(openssl rand -base64 32)|" "$ENV_FILE-$DATE"
|
||||||
|
|
||||||
|
# Generate secure Pusher credentials
|
||||||
|
sed -i "s|^PUSHER_APP_ID=.*|PUSHER_APP_ID=$(openssl rand -hex 32)|" "$ENV_FILE-$DATE"
|
||||||
|
sed -i "s|^PUSHER_APP_KEY=.*|PUSHER_APP_KEY=$(openssl rand -hex 32)|" "$ENV_FILE-$DATE"
|
||||||
|
sed -i "s|^PUSHER_APP_SECRET=.*|PUSHER_APP_SECRET=$(openssl rand -hex 32)|" "$ENV_FILE-$DATE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add default root user credentials from environment variables
|
||||||
|
if [ -n "$ROOT_USERNAME" ] && [ -n "$ROOT_USER_EMAIL" ] && [ -n "$ROOT_USER_PASSWORD" ]; then
|
||||||
|
if grep -q "^ROOT_USERNAME=" "$ENV_FILE-$DATE"; then
|
||||||
|
sed -i "s|^ROOT_USERNAME=.*|ROOT_USERNAME=$ROOT_USERNAME|" "$ENV_FILE-$DATE"
|
||||||
|
fi
|
||||||
|
if grep -q "^ROOT_USER_EMAIL=" "$ENV_FILE-$DATE"; then
|
||||||
|
sed -i "s|^ROOT_USER_EMAIL=.*|ROOT_USER_EMAIL=$ROOT_USER_EMAIL|" "$ENV_FILE-$DATE"
|
||||||
|
fi
|
||||||
|
if grep -q "^ROOT_USER_PASSWORD=" "$ENV_FILE-$DATE"; then
|
||||||
|
sed -i "s|^ROOT_USER_PASSWORD=.*|ROOT_USER_PASSWORD=$ROOT_USER_PASSWORD|" "$ENV_FILE-$DATE"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Merge .env and .env.production. New values will be added to .env
|
||||||
|
echo -e "7. Propagating .env with new values - if necessary."
|
||||||
|
awk -F '=' '!seen[$1]++' "$ENV_FILE-$DATE" /data/coolify/source/.env.production >$ENV_FILE
|
||||||
|
|
||||||
|
if [ "$AUTOUPDATE" = "false" ]; then
|
||||||
|
if ! grep -q "AUTOUPDATE=" /data/coolify/source/.env; then
|
||||||
|
echo "AUTOUPDATE=false" >>/data/coolify/source/.env
|
||||||
|
else
|
||||||
|
sed -i "s|AUTOUPDATE=.*|AUTOUPDATE=false|g" /data/coolify/source/.env
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Save Docker address pool configuration to .env file
|
||||||
|
if ! grep -q "DOCKER_ADDRESS_POOL_BASE=" /data/coolify/source/.env; then
|
||||||
|
echo "DOCKER_ADDRESS_POOL_BASE=$DOCKER_ADDRESS_POOL_BASE" >>/data/coolify/source/.env
|
||||||
|
else
|
||||||
|
# Only update if explicitly provided
|
||||||
|
if [ "$DOCKER_POOL_BASE_PROVIDED" = true ]; then
|
||||||
|
sed -i "s|DOCKER_ADDRESS_POOL_BASE=.*|DOCKER_ADDRESS_POOL_BASE=$DOCKER_ADDRESS_POOL_BASE|g" /data/coolify/source/.env
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! grep -q "DOCKER_ADDRESS_POOL_SIZE=" /data/coolify/source/.env; then
|
||||||
|
echo "DOCKER_ADDRESS_POOL_SIZE=$DOCKER_ADDRESS_POOL_SIZE" >>/data/coolify/source/.env
|
||||||
|
else
|
||||||
|
# Only update if explicitly provided
|
||||||
|
if [ "$DOCKER_POOL_SIZE_PROVIDED" = true ]; then
|
||||||
|
sed -i "s|DOCKER_ADDRESS_POOL_SIZE=.*|DOCKER_ADDRESS_POOL_SIZE=$DOCKER_ADDRESS_POOL_SIZE|g" /data/coolify/source/.env
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "8. Checking for SSH key for localhost access."
|
||||||
|
if [ ! -f ~/.ssh/authorized_keys ]; then
|
||||||
|
mkdir -p ~/.ssh
|
||||||
|
chmod 700 ~/.ssh
|
||||||
|
touch ~/.ssh/authorized_keys
|
||||||
|
chmod 600 ~/.ssh/authorized_keys
|
||||||
|
fi
|
||||||
|
|
||||||
|
set +e
|
||||||
|
IS_COOLIFY_VOLUME_EXISTS=$(docker volume ls | grep coolify-db | wc -l)
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ "$IS_COOLIFY_VOLUME_EXISTS" -eq 0 ]; then
|
||||||
|
echo " - Generating SSH key."
|
||||||
|
ssh-keygen -t ed25519 -a 100 -f /data/coolify/ssh/keys/id.$CURRENT_USER@host.docker.internal -q -N "" -C coolify
|
||||||
|
chown 9999 /data/coolify/ssh/keys/id.$CURRENT_USER@host.docker.internal
|
||||||
|
sed -i "/coolify/d" ~/.ssh/authorized_keys
|
||||||
|
cat /data/coolify/ssh/keys/id.$CURRENT_USER@host.docker.internal.pub >>~/.ssh/authorized_keys
|
||||||
|
rm -f /data/coolify/ssh/keys/id.$CURRENT_USER@host.docker.internal.pub
|
||||||
|
fi
|
||||||
|
|
||||||
|
chown -R 9999:root /data/coolify
|
||||||
|
chmod -R 700 /data/coolify
|
||||||
|
|
||||||
|
echo -e "9. Installing Coolify ($LATEST_VERSION)"
|
||||||
|
echo -e " - It could take a while based on your server's performance, network speed, stars, etc."
|
||||||
|
echo -e " - Please wait."
|
||||||
|
getAJoke
|
||||||
|
|
||||||
|
bash /data/coolify/source/upgrade.sh "${LATEST_VERSION:-latest}" "${LATEST_HELPER_VERSION:-latest}"
|
||||||
|
echo " - Coolify installed successfully."
|
||||||
|
rm -f $ENV_FILE-$DATE
|
||||||
|
|
||||||
|
echo " - Waiting for 20 seconds for Coolify (database migrations) to be ready."
|
||||||
|
getAJoke
|
||||||
|
|
||||||
|
sleep 20
|
||||||
|
echo -e "\033[0;35m
|
||||||
|
____ _ _ _ _ _
|
||||||
|
/ ___|___ _ __ __ _ _ __ __ _| |_ _ _| | __ _| |_(_) ___ _ __ ___| |
|
||||||
|
| | / _ \| '_ \ / _\` | '__/ _\` | __| | | | |/ _\` | __| |/ _ \| '_ \/ __| |
|
||||||
|
| |__| (_) | | | | (_| | | | (_| | |_| |_| | | (_| | |_| | (_) | | | \__ \_|
|
||||||
|
\____\___/|_| |_|\__, |_| \__,_|\__|\__,_|_|\__,_|\__|_|\___/|_| |_|___(_)
|
||||||
|
|___/
|
||||||
|
\033[0m"
|
||||||
|
echo -e "\nYour instance is ready to use!\n"
|
||||||
|
echo -e "You can access Coolify through your Public IP: http://$(curl -4s https://ifconfig.io):8000"
|
||||||
|
|
||||||
|
set +e
|
||||||
|
DEFAULT_PRIVATE_IP=$(ip route get 1 | sed -n 's/^.*src \([0-9.]*\) .*$/\1/p')
|
||||||
|
PRIVATE_IPS=$(hostname -I 2>/dev/null || ip -o addr show scope global | awk '{print $4}' | cut -d/ -f1)
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ -n "$PRIVATE_IPS" ]; then
|
||||||
|
echo -e "\nIf your Public IP is not accessible, you can use the following Private IPs:\n"
|
||||||
|
for IP in $PRIVATE_IPS; do
|
||||||
|
if [ "$IP" != "$DEFAULT_PRIVATE_IP" ]; then
|
||||||
|
echo -e "http://$IP:8000"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
echo -e "\nWARNING: It is highly recommended to backup your Environment variables file (/data/coolify/source/.env) to a safe location, outside of this server (e.g. into a Password Manager).\n"
|
||||||
|
cp /data/coolify/source/.env /data/coolify/source/.env.backup
|
@@ -1,6 +1,15 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
## Do not modify this file. You will lose the ability to install and auto-update!
|
## Do not modify this file. You will lose the ability to install and auto-update!
|
||||||
|
|
||||||
|
## Environment variables that can be set:
|
||||||
|
## ROOT_USERNAME - Predefined root username
|
||||||
|
## ROOT_USER_EMAIL - Predefined root user email
|
||||||
|
## ROOT_USER_PASSWORD - Predefined root user password
|
||||||
|
## DOCKER_ADDRESS_POOL_BASE - Custom Docker address pool base (default: 10.0.0.0/8)
|
||||||
|
## DOCKER_ADDRESS_POOL_SIZE - Custom Docker address pool size (default: 24)
|
||||||
|
## DOCKER_POOL_FORCE_OVERRIDE - Force override Docker address pool configuration (default: false)
|
||||||
|
## AUTOUPDATE - Set to "false" to disable auto-updates
|
||||||
|
|
||||||
set -e # Exit immediately if a command exits with a non-zero status
|
set -e # Exit immediately if a command exits with a non-zero status
|
||||||
## $1 could be empty, so we need to disable this check
|
## $1 could be empty, so we need to disable this check
|
||||||
#set -u # Treat unset variables as an error and exit
|
#set -u # Treat unset variables as an error and exit
|
||||||
@@ -8,7 +17,7 @@ set -o pipefail # Cause a pipeline to return the status of the last command that
|
|||||||
CDN="https://cdn.coollabs.io/coolify"
|
CDN="https://cdn.coollabs.io/coolify"
|
||||||
DATE=$(date +"%Y%m%d-%H%M%S")
|
DATE=$(date +"%Y%m%d-%H%M%S")
|
||||||
|
|
||||||
VERSION="1.7"
|
VERSION="1.8"
|
||||||
DOCKER_VERSION="27.0"
|
DOCKER_VERSION="27.0"
|
||||||
# TODO: Ask for a user
|
# TODO: Ask for a user
|
||||||
CURRENT_USER=$USER
|
CURRENT_USER=$USER
|
||||||
@@ -27,6 +36,144 @@ ROOT_USERNAME=${ROOT_USERNAME:-}
|
|||||||
ROOT_USER_EMAIL=${ROOT_USER_EMAIL:-}
|
ROOT_USER_EMAIL=${ROOT_USER_EMAIL:-}
|
||||||
ROOT_USER_PASSWORD=${ROOT_USER_PASSWORD:-}
|
ROOT_USER_PASSWORD=${ROOT_USER_PASSWORD:-}
|
||||||
|
|
||||||
|
# Docker address pool configuration defaults
|
||||||
|
DOCKER_ADDRESS_POOL_BASE_DEFAULT="10.0.0.0/8"
|
||||||
|
DOCKER_ADDRESS_POOL_SIZE_DEFAULT=24
|
||||||
|
|
||||||
|
# Check if environment variables were explicitly provided
|
||||||
|
DOCKER_POOL_BASE_PROVIDED=false
|
||||||
|
DOCKER_POOL_SIZE_PROVIDED=false
|
||||||
|
DOCKER_POOL_FORCE_OVERRIDE=${DOCKER_POOL_FORCE_OVERRIDE:-false}
|
||||||
|
|
||||||
|
if [ -n "${DOCKER_ADDRESS_POOL_BASE+x}" ]; then
|
||||||
|
DOCKER_POOL_BASE_PROVIDED=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "${DOCKER_ADDRESS_POOL_SIZE+x}" ]; then
|
||||||
|
DOCKER_POOL_SIZE_PROVIDED=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
restart_docker_service() {
|
||||||
|
# Check if systemctl is available
|
||||||
|
if command -v systemctl >/dev/null 2>&1; then
|
||||||
|
systemctl restart docker
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo " - Docker daemon restarted successfully"
|
||||||
|
else
|
||||||
|
echo " - Failed to restart Docker daemon"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
# Check if service command is available
|
||||||
|
elif command -v service >/dev/null 2>&1; then
|
||||||
|
service docker restart
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo " - Docker daemon restarted successfully"
|
||||||
|
else
|
||||||
|
echo " - Failed to restart Docker daemon"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
# If neither systemctl nor service is available
|
||||||
|
else
|
||||||
|
echo " - Error: No service management system found"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to compare address pools
|
||||||
|
compare_address_pools() {
|
||||||
|
local base1="$1"
|
||||||
|
local size1="$2"
|
||||||
|
local base2="$3"
|
||||||
|
local size2="$4"
|
||||||
|
|
||||||
|
# Normalize CIDR notation for comparison
|
||||||
|
local ip1=$(echo "$base1" | cut -d'/' -f1)
|
||||||
|
local prefix1=$(echo "$base1" | cut -d'/' -f2)
|
||||||
|
local ip2=$(echo "$base2" | cut -d'/' -f1)
|
||||||
|
local prefix2=$(echo "$base2" | cut -d'/' -f2)
|
||||||
|
|
||||||
|
# Compare IPs and prefixes
|
||||||
|
if [ "$ip1" = "$ip2" ] && [ "$prefix1" = "$prefix2" ] && [ "$size1" = "$size2" ]; then
|
||||||
|
return 0 # Pools are the same
|
||||||
|
else
|
||||||
|
return 1 # Pools are different
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Docker address pool configuration
|
||||||
|
DOCKER_ADDRESS_POOL_BASE=${DOCKER_ADDRESS_POOL_BASE:-"$DOCKER_ADDRESS_POOL_BASE_DEFAULT"}
|
||||||
|
DOCKER_ADDRESS_POOL_SIZE=${DOCKER_ADDRESS_POOL_SIZE:-$DOCKER_ADDRESS_POOL_SIZE_DEFAULT}
|
||||||
|
|
||||||
|
# Load Docker address pool configuration from .env file if it exists and environment variables were not provided
|
||||||
|
if [ -f "/data/coolify/source/.env" ] && [ "$DOCKER_POOL_BASE_PROVIDED" = false ] && [ "$DOCKER_POOL_SIZE_PROVIDED" = false ]; then
|
||||||
|
ENV_DOCKER_ADDRESS_POOL_BASE=$(grep -E "^DOCKER_ADDRESS_POOL_BASE=" /data/coolify/source/.env | cut -d '=' -f2 || true)
|
||||||
|
ENV_DOCKER_ADDRESS_POOL_SIZE=$(grep -E "^DOCKER_ADDRESS_POOL_SIZE=" /data/coolify/source/.env | cut -d '=' -f2 || true)
|
||||||
|
|
||||||
|
if [ -n "$ENV_DOCKER_ADDRESS_POOL_BASE" ]; then
|
||||||
|
DOCKER_ADDRESS_POOL_BASE="$ENV_DOCKER_ADDRESS_POOL_BASE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$ENV_DOCKER_ADDRESS_POOL_SIZE" ]; then
|
||||||
|
DOCKER_ADDRESS_POOL_SIZE="$ENV_DOCKER_ADDRESS_POOL_SIZE"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if daemon.json exists and extract existing address pool configuration
|
||||||
|
EXISTING_POOL_CONFIGURED=false
|
||||||
|
if [ -f /etc/docker/daemon.json ]; then
|
||||||
|
if jq -e '.["default-address-pools"]' /etc/docker/daemon.json >/dev/null 2>&1; then
|
||||||
|
EXISTING_POOL_BASE=$(jq -r '.["default-address-pools"][0].base' /etc/docker/daemon.json 2>/dev/null || true)
|
||||||
|
EXISTING_POOL_SIZE=$(jq -r '.["default-address-pools"][0].size' /etc/docker/daemon.json 2>/dev/null || true)
|
||||||
|
|
||||||
|
if [ -n "$EXISTING_POOL_BASE" ] && [ -n "$EXISTING_POOL_SIZE" ] && [ "$EXISTING_POOL_BASE" != "null" ] && [ "$EXISTING_POOL_SIZE" != "null" ]; then
|
||||||
|
echo "Found existing Docker network pool: $EXISTING_POOL_BASE/$EXISTING_POOL_SIZE"
|
||||||
|
EXISTING_POOL_CONFIGURED=true
|
||||||
|
|
||||||
|
# Check if environment variables were explicitly provided
|
||||||
|
if [ "$DOCKER_POOL_BASE_PROVIDED" = false ] && [ "$DOCKER_POOL_SIZE_PROVIDED" = false ]; then
|
||||||
|
DOCKER_ADDRESS_POOL_BASE="$EXISTING_POOL_BASE"
|
||||||
|
DOCKER_ADDRESS_POOL_SIZE="$EXISTING_POOL_SIZE"
|
||||||
|
else
|
||||||
|
# Check if force override is enabled
|
||||||
|
if [ "$DOCKER_POOL_FORCE_OVERRIDE" = true ]; then
|
||||||
|
echo "Force override enabled - network pool will be updated with $DOCKER_ADDRESS_POOL_BASE/$DOCKER_ADDRESS_POOL_SIZE."
|
||||||
|
else
|
||||||
|
echo "Custom pool provided but force override not enabled - using existing configuration."
|
||||||
|
echo "To force override, set DOCKER_POOL_FORCE_OVERRIDE=true"
|
||||||
|
echo "This won't change the existing docker networks, only the pool configuration for the newly created networks."
|
||||||
|
DOCKER_ADDRESS_POOL_BASE="$EXISTING_POOL_BASE"
|
||||||
|
DOCKER_ADDRESS_POOL_SIZE="$EXISTING_POOL_SIZE"
|
||||||
|
DOCKER_POOL_BASE_PROVIDED=false
|
||||||
|
DOCKER_POOL_SIZE_PROVIDED=false
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Validate Docker address pool configuration
|
||||||
|
if ! [[ $DOCKER_ADDRESS_POOL_BASE =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/[0-9]+$ ]]; then
|
||||||
|
echo "Warning: Invalid network pool base format: $DOCKER_ADDRESS_POOL_BASE"
|
||||||
|
if [ "$EXISTING_POOL_CONFIGURED" = true ]; then
|
||||||
|
echo "Using existing configuration: $EXISTING_POOL_BASE"
|
||||||
|
DOCKER_ADDRESS_POOL_BASE="$EXISTING_POOL_BASE"
|
||||||
|
else
|
||||||
|
echo "Using default configuration: $DOCKER_ADDRESS_POOL_BASE_DEFAULT"
|
||||||
|
DOCKER_ADDRESS_POOL_BASE="$DOCKER_ADDRESS_POOL_BASE_DEFAULT"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! [[ $DOCKER_ADDRESS_POOL_SIZE =~ ^[0-9]+$ ]] || [ "$DOCKER_ADDRESS_POOL_SIZE" -lt 16 ] || [ "$DOCKER_ADDRESS_POOL_SIZE" -gt 28 ]; then
|
||||||
|
echo "Warning: Invalid network pool size: $DOCKER_ADDRESS_POOL_SIZE (must be 16-28)"
|
||||||
|
if [ "$EXISTING_POOL_CONFIGURED" = true ]; then
|
||||||
|
echo "Using existing configuration: $EXISTING_POOL_SIZE"
|
||||||
|
DOCKER_ADDRESS_POOL_SIZE="$EXISTING_POOL_SIZE"
|
||||||
|
else
|
||||||
|
echo "Using default configuration: $DOCKER_ADDRESS_POOL_SIZE_DEFAULT"
|
||||||
|
DOCKER_ADDRESS_POOL_SIZE=$DOCKER_ADDRESS_POOL_SIZE_DEFAULT
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
TOTAL_SPACE=$(df -BG / | awk 'NR==2 {print $2}' | sed 's/G//')
|
TOTAL_SPACE=$(df -BG / | awk 'NR==2 {print $2}' | sed 's/G//')
|
||||||
AVAILABLE_SPACE=$(df -BG / | awk 'NR==2 {print $4}' | sed 's/G//')
|
AVAILABLE_SPACE=$(df -BG / | awk 'NR==2 {print $4}' | sed 's/G//')
|
||||||
REQUIRED_TOTAL_SPACE=30
|
REQUIRED_TOTAL_SPACE=30
|
||||||
@@ -35,7 +182,7 @@ WARNING_SPACE=false
|
|||||||
|
|
||||||
if [ "$TOTAL_SPACE" -lt "$REQUIRED_TOTAL_SPACE" ]; then
|
if [ "$TOTAL_SPACE" -lt "$REQUIRED_TOTAL_SPACE" ]; then
|
||||||
WARNING_SPACE=true
|
WARNING_SPACE=true
|
||||||
cat << EOF
|
cat <<EOF
|
||||||
WARNING: Insufficient total disk space!
|
WARNING: Insufficient total disk space!
|
||||||
|
|
||||||
Total disk space: ${TOTAL_SPACE}GB
|
Total disk space: ${TOTAL_SPACE}GB
|
||||||
@@ -46,7 +193,7 @@ EOF
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$AVAILABLE_SPACE" -lt "$REQUIRED_AVAILABLE_SPACE" ]; then
|
if [ "$AVAILABLE_SPACE" -lt "$REQUIRED_AVAILABLE_SPACE" ]; then
|
||||||
cat << EOF
|
cat <<EOF
|
||||||
WARNING: Insufficient available disk space!
|
WARNING: Insufficient available disk space!
|
||||||
|
|
||||||
Available disk space: ${AVAILABLE_SPACE}GB
|
Available disk space: ${AVAILABLE_SPACE}GB
|
||||||
@@ -54,7 +201,7 @@ Required available space: ${REQUIRED_AVAILABLE_SPACE}GB
|
|||||||
|
|
||||||
==================
|
==================
|
||||||
EOF
|
EOF
|
||||||
WARNING_SPACE=true
|
WARNING_SPACE=true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$WARNING_SPACE" = true ]; then
|
if [ "$WARNING_SPACE" = true ]; then
|
||||||
@@ -136,7 +283,6 @@ if [ -z "$LATEST_REALTIME_VERSION" ]; then
|
|||||||
LATEST_REALTIME_VERSION=latest
|
LATEST_REALTIME_VERSION=latest
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
case "$OS_TYPE" in
|
case "$OS_TYPE" in
|
||||||
arch | ubuntu | debian | raspbian | centos | fedora | rhel | ol | rocky | sles | opensuse-leap | opensuse-tumbleweed | almalinux | amzn | alpine) ;;
|
arch | ubuntu | debian | raspbian | centos | fedora | rhel | ol | rocky | sles | opensuse-leap | opensuse-tumbleweed | almalinux | amzn | alpine) ;;
|
||||||
*)
|
*)
|
||||||
@@ -152,14 +298,13 @@ if [ "$1" != "" ]; then
|
|||||||
LATEST_VERSION="${LATEST_VERSION#v}"
|
LATEST_VERSION="${LATEST_VERSION#v}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
echo -e "---------------------------------------------"
|
echo -e "---------------------------------------------"
|
||||||
echo "| Operating System | $OS_TYPE $OS_VERSION"
|
echo "| Operating System | $OS_TYPE $OS_VERSION"
|
||||||
echo "| Docker | $DOCKER_VERSION"
|
echo "| Docker | $DOCKER_VERSION"
|
||||||
echo "| Coolify | $LATEST_VERSION"
|
echo "| Coolify | $LATEST_VERSION"
|
||||||
echo "| Helper | $LATEST_HELPER_VERSION"
|
echo "| Helper | $LATEST_HELPER_VERSION"
|
||||||
echo "| Realtime | $LATEST_REALTIME_VERSION"
|
echo "| Realtime | $LATEST_REALTIME_VERSION"
|
||||||
|
echo "| Docker Pool | $DOCKER_ADDRESS_POOL_BASE (size $DOCKER_ADDRESS_POOL_SIZE)"
|
||||||
echo -e "---------------------------------------------\n"
|
echo -e "---------------------------------------------\n"
|
||||||
echo -e "1. Installing required packages (curl, wget, git, jq, openssl). "
|
echo -e "1. Installing required packages (curl, wget, git, jq, openssl). "
|
||||||
|
|
||||||
@@ -199,7 +344,6 @@ sles | opensuse-leap | opensuse-tumbleweed)
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
|
||||||
echo -e "2. Check OpenSSH server configuration. "
|
echo -e "2. Check OpenSSH server configuration. "
|
||||||
|
|
||||||
# Detect OpenSSH server
|
# Detect OpenSSH server
|
||||||
@@ -222,7 +366,6 @@ elif [ -x "$(command -v service)" ]; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
if [ "$SSH_DETECTED" = "false" ]; then
|
if [ "$SSH_DETECTED" = "false" ]; then
|
||||||
echo " - OpenSSH server not detected. Installing OpenSSH server."
|
echo " - OpenSSH server not detected. Installing OpenSSH server."
|
||||||
case "$OS_TYPE" in
|
case "$OS_TYPE" in
|
||||||
@@ -288,86 +431,112 @@ if [ -x "$(command -v snap)" ]; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
install_docker() {
|
||||||
|
curl -s https://releases.rancher.com/install-docker/${DOCKER_VERSION}.sh | sh 2>&1
|
||||||
|
if ! [ -x "$(command -v docker)" ]; then
|
||||||
|
curl -s https://get.docker.com | sh -s -- --version ${DOCKER_VERSION} 2>&1
|
||||||
|
if ! [ -x "$(command -v docker)" ]; then
|
||||||
|
echo " - Docker installation failed."
|
||||||
|
echo " Maybe your OS is not supported?"
|
||||||
|
echo " - Please visit https://docs.docker.com/engine/install/ and install Docker manually to continue."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
echo -e "3. Check Docker Installation. "
|
echo -e "3. Check Docker Installation. "
|
||||||
if ! [ -x "$(command -v docker)" ]; then
|
if ! [ -x "$(command -v docker)" ]; then
|
||||||
echo " - Docker is not installed. Installing Docker. It may take a while."
|
echo " - Docker is not installed. Installing Docker. It may take a while."
|
||||||
getAJoke
|
getAJoke
|
||||||
case "$OS_TYPE" in
|
case "$OS_TYPE" in
|
||||||
"almalinux")
|
"almalinux")
|
||||||
dnf config-manager --add-repo=https://download.docker.com/linux/centos/docker-ce.repo >/dev/null 2>&1
|
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
|
dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin >/dev/null 2>&1
|
||||||
|
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
|
||||||
|
systemctl start docker >/dev/null 2>&1
|
||||||
|
systemctl enable docker >/dev/null 2>&1
|
||||||
|
;;
|
||||||
|
"alpine")
|
||||||
|
apk add docker docker-cli-compose >/dev/null 2>&1
|
||||||
|
rc-update add docker default >/dev/null 2>&1
|
||||||
|
service docker start >/dev/null 2>&1
|
||||||
|
if ! [ -x "$(command -v docker)" ]; then
|
||||||
|
echo " - Failed to install Docker with apk. Try to install it manually."
|
||||||
|
echo " Please visit https://wiki.alpinelinux.org/wiki/Docker for more information."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
"arch")
|
||||||
|
pacman -Sy docker docker-compose --noconfirm >/dev/null 2>&1
|
||||||
|
systemctl enable docker.service >/dev/null 2>&1
|
||||||
|
if ! [ -x "$(command -v docker)" ]; then
|
||||||
|
echo " - Failed to install Docker with pacman. Try to install it manually."
|
||||||
|
echo " Please visit https://wiki.archlinux.org/title/docker for more information."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
"amzn")
|
||||||
|
dnf install docker -y >/dev/null 2>&1
|
||||||
|
DOCKER_CONFIG=${DOCKER_CONFIG:-/usr/local/lib/docker}
|
||||||
|
mkdir -p $DOCKER_CONFIG/cli-plugins >/dev/null 2>&1
|
||||||
|
curl -sL https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m) -o $DOCKER_CONFIG/cli-plugins/docker-compose >/dev/null 2>&1
|
||||||
|
chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose >/dev/null 2>&1
|
||||||
|
systemctl start docker >/dev/null 2>&1
|
||||||
|
systemctl enable docker >/dev/null 2>&1
|
||||||
|
if ! [ -x "$(command -v docker)" ]; then
|
||||||
|
echo " - Failed to install Docker with dnf. Try to install it manually."
|
||||||
|
echo " Please visit https://www.cyberciti.biz/faq/how-to-install-docker-on-amazon-linux-2/ for more information."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
"centos" | "fedora" | "rhel")
|
||||||
|
if [ -x "$(command -v dnf5)" ]; then
|
||||||
|
# dnf5 is available
|
||||||
|
dnf config-manager addrepo --from-repofile=https://download.docker.com/linux/$OS_TYPE/docker-ce.repo --overwrite >/dev/null 2>&1
|
||||||
|
else
|
||||||
|
# dnf5 is not available, use dnf
|
||||||
|
dnf config-manager --add-repo=https://download.docker.com/linux/$OS_TYPE/docker-ce.repo >/dev/null 2>&1
|
||||||
|
fi
|
||||||
|
dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin >/dev/null 2>&1
|
||||||
|
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
|
||||||
|
systemctl start docker >/dev/null 2>&1
|
||||||
|
systemctl enable docker >/dev/null 2>&1
|
||||||
|
;;
|
||||||
|
"ubuntu" | "debian" | "raspbian")
|
||||||
|
if [ "$OS_TYPE" = "ubuntu" ] && [ "$OS_VERSION" = "24.10" ]; then
|
||||||
|
echo " - Installing Docker for Ubuntu 24.10..."
|
||||||
|
apt-get update >/dev/null
|
||||||
|
apt-get install -y ca-certificates curl >/dev/null
|
||||||
|
install -m 0755 -d /etc/apt/keyrings
|
||||||
|
curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
|
||||||
|
chmod a+r /etc/apt/keyrings/docker.asc
|
||||||
|
|
||||||
|
# Add the repository to Apt sources
|
||||||
|
echo \
|
||||||
|
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
|
||||||
|
$(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" |
|
||||||
|
tee /etc/apt/sources.list.d/docker.list >/dev/null
|
||||||
|
apt-get update >/dev/null
|
||||||
|
apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin >/dev/null
|
||||||
|
|
||||||
if ! [ -x "$(command -v docker)" ]; then
|
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."
|
echo " - Docker installation failed."
|
||||||
|
echo " Please visit https://docs.docker.com/engine/install/ubuntu/ and install Docker manually to continue."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
systemctl start docker >/dev/null 2>&1
|
echo " - Docker installed successfully for Ubuntu 24.10."
|
||||||
systemctl enable docker >/dev/null 2>&1
|
else
|
||||||
;;
|
install_docker
|
||||||
"alpine")
|
fi
|
||||||
apk add docker docker-cli-compose >/dev/null 2>&1
|
;;
|
||||||
rc-update add docker default >/dev/null 2>&1
|
*)
|
||||||
service docker start >/dev/null 2>&1
|
install_docker
|
||||||
if ! [ -x "$(command -v docker)" ]; then
|
;;
|
||||||
echo " - Failed to install Docker with apk. Try to install it manually."
|
|
||||||
echo " Please visit https://wiki.alpinelinux.org/wiki/Docker for more information."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
"arch")
|
|
||||||
pacman -Sy docker docker-compose --noconfirm >/dev/null 2>&1
|
|
||||||
systemctl enable docker.service >/dev/null 2>&1
|
|
||||||
if ! [ -x "$(command -v docker)" ]; then
|
|
||||||
echo " - Failed to install Docker with pacman. Try to install it manually."
|
|
||||||
echo " Please visit https://wiki.archlinux.org/title/docker for more information."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
"amzn")
|
|
||||||
dnf install docker -y >/dev/null 2>&1
|
|
||||||
DOCKER_CONFIG=${DOCKER_CONFIG:-/usr/local/lib/docker}
|
|
||||||
mkdir -p $DOCKER_CONFIG/cli-plugins >/dev/null 2>&1
|
|
||||||
curl -sL https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m) -o $DOCKER_CONFIG/cli-plugins/docker-compose >/dev/null 2>&1
|
|
||||||
chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose >/dev/null 2>&1
|
|
||||||
systemctl start docker >/dev/null 2>&1
|
|
||||||
systemctl enable docker >/dev/null 2>&1
|
|
||||||
if ! [ -x "$(command -v docker)" ]; then
|
|
||||||
echo " - Failed to install Docker with dnf. Try to install it manually."
|
|
||||||
echo " Please visit https://www.cyberciti.biz/faq/how-to-install-docker-on-amazon-linux-2/ for more information."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
"fedora")
|
|
||||||
if [ -x "$(command -v dnf5)" ]; then
|
|
||||||
# dnf5 is available
|
|
||||||
dnf config-manager addrepo --from-repofile=https://download.docker.com/linux/fedora/docker-ce.repo --overwrite >/dev/null 2>&1
|
|
||||||
else
|
|
||||||
# dnf5 is not available, use dnf
|
|
||||||
dnf config-manager --add-repo=https://download.docker.com/linux/fedora/docker-ce.repo >/dev/null 2>&1
|
|
||||||
fi
|
|
||||||
dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin >/dev/null 2>&1
|
|
||||||
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
|
|
||||||
systemctl start docker >/dev/null 2>&1
|
|
||||||
systemctl enable docker >/dev/null 2>&1
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
if [ "$OS_TYPE" = "ubuntu" ] && [ "$OS_VERSION" = "24.10" ]; then
|
|
||||||
echo "Docker automated installation is not supported on Ubuntu 24.10 (non-LTS release)."
|
|
||||||
echo "Please install Docker manually."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
curl -s https://releases.rancher.com/install-docker/${DOCKER_VERSION}.sh | sh 2>&1
|
|
||||||
if ! [ -x "$(command -v docker)" ]; then
|
|
||||||
curl -s https://get.docker.com | sh -s -- --version ${DOCKER_VERSION} 2>&1
|
|
||||||
if ! [ -x "$(command -v docker)" ]; then
|
|
||||||
echo " - Docker installation failed."
|
|
||||||
echo " Maybe your OS is not supported?"
|
|
||||||
echo " - Please visit https://docs.docker.com/engine/install/ and install Docker manually to continue."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
esac
|
esac
|
||||||
echo " - Docker installed successfully."
|
echo " - Docker installed successfully."
|
||||||
else
|
else
|
||||||
@@ -375,82 +544,132 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
echo -e "4. Check Docker Configuration. "
|
echo -e "4. Check Docker Configuration. "
|
||||||
|
|
||||||
|
echo " - Network pool configuration: ${DOCKER_ADDRESS_POOL_BASE}/${DOCKER_ADDRESS_POOL_SIZE}"
|
||||||
|
echo " - To override existing configuration: DOCKER_POOL_FORCE_OVERRIDE=true"
|
||||||
|
|
||||||
mkdir -p /etc/docker
|
mkdir -p /etc/docker
|
||||||
# shellcheck disable=SC2015
|
|
||||||
test -s /etc/docker/daemon.json && cp /etc/docker/daemon.json /etc/docker/daemon.json.original-"$DATE" || cat >/etc/docker/daemon.json <<EOL
|
# Backup original daemon.json if it exists
|
||||||
{
|
if [ -f /etc/docker/daemon.json ]; then
|
||||||
"log-driver": "json-file",
|
cp /etc/docker/daemon.json /etc/docker/daemon.json.original-"$DATE"
|
||||||
"log-opts": {
|
|
||||||
"max-size": "10m",
|
|
||||||
"max-file": "3"
|
|
||||||
},
|
|
||||||
"default-address-pools": [
|
|
||||||
{"base":"10.0.0.0/8","size":24}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
EOL
|
|
||||||
cat >/etc/docker/daemon.json.coolify <<EOL
|
|
||||||
{
|
|
||||||
"log-driver": "json-file",
|
|
||||||
"log-opts": {
|
|
||||||
"max-size": "10m",
|
|
||||||
"max-file": "3"
|
|
||||||
},
|
|
||||||
"default-address-pools": [
|
|
||||||
{"base":"10.0.0.0/8","size":24}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
EOL
|
|
||||||
TEMP_FILE=$(mktemp)
|
|
||||||
if ! jq -s '.[0] * .[1]' /etc/docker/daemon.json /etc/docker/daemon.json.coolify >"$TEMP_FILE"; then
|
|
||||||
echo "Error merging JSON files"
|
|
||||||
exit 1
|
|
||||||
fi
|
fi
|
||||||
mv "$TEMP_FILE" /etc/docker/daemon.json
|
|
||||||
|
|
||||||
restart_docker_service() {
|
# Create coolify configuration with or without address pools based on whether they were explicitly provided
|
||||||
# Check if systemctl is available
|
if [ "$DOCKER_POOL_FORCE_OVERRIDE" = true ] || [ "$EXISTING_POOL_CONFIGURED" = false ]; then
|
||||||
if command -v systemctl >/dev/null 2>&1; then
|
# First check if the configuration would actually change anything
|
||||||
echo " - Using systemctl to restart Docker."
|
if [ -f /etc/docker/daemon.json ]; then
|
||||||
systemctl restart docker
|
CURRENT_POOL_BASE=$(jq -r '.["default-address-pools"][0].base' /etc/docker/daemon.json 2>/dev/null)
|
||||||
|
CURRENT_POOL_SIZE=$(jq -r '.["default-address-pools"][0].size' /etc/docker/daemon.json 2>/dev/null)
|
||||||
|
|
||||||
if [ $? -eq 0 ]; then
|
if [ "$CURRENT_POOL_BASE" = "$DOCKER_ADDRESS_POOL_BASE" ] && [ "$CURRENT_POOL_SIZE" = "$DOCKER_ADDRESS_POOL_SIZE" ]; then
|
||||||
echo " - Docker restarted successfully using systemctl."
|
echo " - Network pool configuration unchanged, skipping update"
|
||||||
|
NEED_MERGE=false
|
||||||
else
|
else
|
||||||
echo " - Failed to restart Docker using systemctl."
|
# If force override is enabled or no existing configuration exists,
|
||||||
return 1
|
# create a new configuration with the specified address pools
|
||||||
fi
|
echo " - Creating new Docker configuration with network pool: ${DOCKER_ADDRESS_POOL_BASE}/${DOCKER_ADDRESS_POOL_SIZE}"
|
||||||
|
cat >/etc/docker/daemon.json <<EOL
|
||||||
# Check if service command is available
|
{
|
||||||
elif command -v service >/dev/null 2>&1; then
|
"log-driver": "json-file",
|
||||||
echo " - Using service command to restart Docker."
|
"log-opts": {
|
||||||
service docker restart
|
"max-size": "10m",
|
||||||
|
"max-file": "3"
|
||||||
if [ $? -eq 0 ]; then
|
},
|
||||||
echo " - Docker restarted successfully using service."
|
"default-address-pools": [
|
||||||
else
|
{"base":"${DOCKER_ADDRESS_POOL_BASE}","size":${DOCKER_ADDRESS_POOL_SIZE}}
|
||||||
echo " - Failed to restart Docker using service."
|
]
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# If neither systemctl nor service is available
|
|
||||||
else
|
|
||||||
echo " - Neither systemctl nor service command is available on this system."
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
EOL
|
||||||
if [ -s /etc/docker/daemon.json.original-"$DATE" ]; then
|
NEED_MERGE=true
|
||||||
DIFF=$(diff <(jq --sort-keys . /etc/docker/daemon.json) <(jq --sort-keys . /etc/docker/daemon.json.original-"$DATE"))
|
fi
|
||||||
if [ "$DIFF" != "" ]; then
|
|
||||||
echo " - Docker configuration updated, restart docker daemon..."
|
|
||||||
restart_docker_service
|
|
||||||
else
|
else
|
||||||
echo " - Docker configuration is up to date."
|
# No existing configuration, create new one
|
||||||
|
echo " - Creating new Docker configuration with network pool: ${DOCKER_ADDRESS_POOL_BASE}/${DOCKER_ADDRESS_POOL_SIZE}"
|
||||||
|
cat >/etc/docker/daemon.json <<EOL
|
||||||
|
{
|
||||||
|
"log-driver": "json-file",
|
||||||
|
"log-opts": {
|
||||||
|
"max-size": "10m",
|
||||||
|
"max-file": "3"
|
||||||
|
},
|
||||||
|
"default-address-pools": [
|
||||||
|
{"base":"${DOCKER_ADDRESS_POOL_BASE}","size":${DOCKER_ADDRESS_POOL_SIZE}}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
EOL
|
||||||
|
NEED_MERGE=true
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo " - Docker configuration updated, restart docker daemon..."
|
# Check if we need to update log settings
|
||||||
restart_docker_service
|
if [ -f /etc/docker/daemon.json ] && jq -e '.["log-driver"] == "json-file" and .["log-opts"]["max-size"] == "10m" and .["log-opts"]["max-file"] == "3"' /etc/docker/daemon.json >/dev/null 2>&1; then
|
||||||
|
echo " - Log configuration is up to date"
|
||||||
|
NEED_MERGE=false
|
||||||
|
else
|
||||||
|
# Create a configuration without address pools to preserve existing ones
|
||||||
|
cat >/etc/docker/daemon.json.coolify <<EOL
|
||||||
|
{
|
||||||
|
"log-driver": "json-file",
|
||||||
|
"log-opts": {
|
||||||
|
"max-size": "10m",
|
||||||
|
"max-file": "3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOL
|
||||||
|
NEED_MERGE=true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Remove the duplicate daemon.json creation since we handle it above
|
||||||
|
if ! [ -f /etc/docker/daemon.json ]; then
|
||||||
|
# If no daemon.json exists, create it with default settings
|
||||||
|
cat >/etc/docker/daemon.json <<EOL
|
||||||
|
{
|
||||||
|
"log-driver": "json-file",
|
||||||
|
"log-opts": {
|
||||||
|
"max-size": "10m",
|
||||||
|
"max-file": "3"
|
||||||
|
},
|
||||||
|
"default-address-pools": [
|
||||||
|
{"base":"${DOCKER_ADDRESS_POOL_BASE}","size":${DOCKER_ADDRESS_POOL_SIZE}}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
EOL
|
||||||
|
NEED_MERGE=false
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -s /etc/docker/daemon.json.original-"$DATE" ]; then
|
||||||
|
DIFF=$(diff <(jq --sort-keys . /etc/docker/daemon.json) <(jq --sort-keys . /etc/docker/daemon.json.original-"$DATE") || true)
|
||||||
|
if [ "$DIFF" != "" ]; then
|
||||||
|
echo " - Checking configuration changes..."
|
||||||
|
|
||||||
|
# Check if address pools were changed
|
||||||
|
if echo "$DIFF" | grep -q "default-address-pools"; then
|
||||||
|
if [ "$DOCKER_POOL_BASE_PROVIDED" = true ] || [ "$DOCKER_POOL_SIZE_PROVIDED" = true ]; then
|
||||||
|
echo " - Network pool updated per user request"
|
||||||
|
else
|
||||||
|
echo " - Warning: Network pool modified without explicit request"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Remove this redundant restart since we already restarted when writing the config
|
||||||
|
echo " - Configuration changes confirmed"
|
||||||
|
if [ "$NEED_MERGE" = true ]; then
|
||||||
|
echo " - Configuration updated - restarting Docker daemon..."
|
||||||
|
restart_docker_service
|
||||||
|
else
|
||||||
|
echo " - Configuration is up to date"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo " - Configuration is up to date"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [ "$NEED_MERGE" = true ]; then
|
||||||
|
echo " - Configuration updated - restarting Docker daemon..."
|
||||||
|
restart_docker_service
|
||||||
|
else
|
||||||
|
echo " - Configuration is up to date"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo -e "5. Download required files from CDN. "
|
echo -e "5. Download required files from CDN. "
|
||||||
@@ -501,7 +720,7 @@ fi
|
|||||||
|
|
||||||
# Merge .env and .env.production. New values will be added to .env
|
# Merge .env and .env.production. New values will be added to .env
|
||||||
echo -e "7. Propagating .env with new values - if necessary."
|
echo -e "7. Propagating .env with new values - if necessary."
|
||||||
awk -F '=' '!seen[$1]++' "$ENV_FILE-$DATE" /data/coolify/source/.env.production > $ENV_FILE
|
awk -F '=' '!seen[$1]++' "$ENV_FILE-$DATE" /data/coolify/source/.env.production >$ENV_FILE
|
||||||
|
|
||||||
if [ "$AUTOUPDATE" = "false" ]; then
|
if [ "$AUTOUPDATE" = "false" ]; then
|
||||||
if ! grep -q "AUTOUPDATE=" /data/coolify/source/.env; then
|
if ! grep -q "AUTOUPDATE=" /data/coolify/source/.env; then
|
||||||
@@ -510,6 +729,26 @@ if [ "$AUTOUPDATE" = "false" ]; then
|
|||||||
sed -i "s|AUTOUPDATE=.*|AUTOUPDATE=false|g" /data/coolify/source/.env
|
sed -i "s|AUTOUPDATE=.*|AUTOUPDATE=false|g" /data/coolify/source/.env
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Save Docker address pool configuration to .env file
|
||||||
|
if ! grep -q "DOCKER_ADDRESS_POOL_BASE=" /data/coolify/source/.env; then
|
||||||
|
echo "DOCKER_ADDRESS_POOL_BASE=$DOCKER_ADDRESS_POOL_BASE" >>/data/coolify/source/.env
|
||||||
|
else
|
||||||
|
# Only update if explicitly provided
|
||||||
|
if [ "$DOCKER_POOL_BASE_PROVIDED" = true ]; then
|
||||||
|
sed -i "s|DOCKER_ADDRESS_POOL_BASE=.*|DOCKER_ADDRESS_POOL_BASE=$DOCKER_ADDRESS_POOL_BASE|g" /data/coolify/source/.env
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! grep -q "DOCKER_ADDRESS_POOL_SIZE=" /data/coolify/source/.env; then
|
||||||
|
echo "DOCKER_ADDRESS_POOL_SIZE=$DOCKER_ADDRESS_POOL_SIZE" >>/data/coolify/source/.env
|
||||||
|
else
|
||||||
|
# Only update if explicitly provided
|
||||||
|
if [ "$DOCKER_POOL_SIZE_PROVIDED" = true ]; then
|
||||||
|
sed -i "s|DOCKER_ADDRESS_POOL_SIZE=.*|DOCKER_ADDRESS_POOL_SIZE=$DOCKER_ADDRESS_POOL_SIZE|g" /data/coolify/source/.env
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
echo -e "8. Checking for SSH key for localhost access."
|
echo -e "8. Checking for SSH key for localhost access."
|
||||||
if [ ! -f ~/.ssh/authorized_keys ]; then
|
if [ ! -f ~/.ssh/authorized_keys ]; then
|
||||||
mkdir -p ~/.ssh
|
mkdir -p ~/.ssh
|
||||||
@@ -527,7 +766,7 @@ if [ "$IS_COOLIFY_VOLUME_EXISTS" -eq 0 ]; then
|
|||||||
ssh-keygen -t ed25519 -a 100 -f /data/coolify/ssh/keys/id.$CURRENT_USER@host.docker.internal -q -N "" -C coolify
|
ssh-keygen -t ed25519 -a 100 -f /data/coolify/ssh/keys/id.$CURRENT_USER@host.docker.internal -q -N "" -C coolify
|
||||||
chown 9999 /data/coolify/ssh/keys/id.$CURRENT_USER@host.docker.internal
|
chown 9999 /data/coolify/ssh/keys/id.$CURRENT_USER@host.docker.internal
|
||||||
sed -i "/coolify/d" ~/.ssh/authorized_keys
|
sed -i "/coolify/d" ~/.ssh/authorized_keys
|
||||||
cat /data/coolify/ssh/keys/id.$CURRENT_USER@host.docker.internal.pub >> ~/.ssh/authorized_keys
|
cat /data/coolify/ssh/keys/id.$CURRENT_USER@host.docker.internal.pub >>~/.ssh/authorized_keys
|
||||||
rm -f /data/coolify/ssh/keys/id.$CURRENT_USER@host.docker.internal.pub
|
rm -f /data/coolify/ssh/keys/id.$CURRENT_USER@host.docker.internal.pub
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
services:
|
services:
|
||||||
authentik-server:
|
authentik-server:
|
||||||
image: ghcr.io/goauthentik/server:${AUTHENTIK_TAG:-2024.12.2}
|
image: ghcr.io/goauthentik/server:${AUTHENTIK_TAG:-2025.2.0}
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
command: server
|
command: server
|
||||||
environment:
|
environment:
|
||||||
@@ -35,7 +35,7 @@ services:
|
|||||||
redis:
|
redis:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
authentik-worker:
|
authentik-worker:
|
||||||
image: ghcr.io/goauthentik/server:${AUTHENTIK_TAG:-2024.12.2}
|
image: ghcr.io/goauthentik/server:${AUTHENTIK_TAG:-2025.2.0}
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
command: worker
|
command: worker
|
||||||
environment:
|
environment:
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user