mirror of
https://github.com/ershisan99/coolify.git
synced 2025-12-18 12:33:06 +00:00
Compare commits
51 Commits
v4.0.0-bet
...
v4.0.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1724c0d3ff | ||
|
|
0b8f48230f | ||
|
|
e8d84b7067 | ||
|
|
5236bbc757 | ||
|
|
094e1d1bba | ||
|
|
68b25523d6 | ||
|
|
bdc478d5f5 | ||
|
|
002472d7c6 | ||
|
|
0d65bf62b9 | ||
|
|
01c7e76071 | ||
|
|
884ae0efb0 | ||
|
|
8e7040bf7c | ||
|
|
059e6a88eb | ||
|
|
9947158f7e | ||
|
|
61aa9e8766 | ||
|
|
75813a289c | ||
|
|
af11d8cf3d | ||
|
|
48990db699 | ||
|
|
da71353bfa | ||
|
|
0f5559bc61 | ||
|
|
1afb509c33 | ||
|
|
bccca6e874 | ||
|
|
083dc15053 | ||
|
|
1b6d376472 | ||
|
|
891deee05a | ||
|
|
5ffbba908b | ||
|
|
f762959c9f | ||
|
|
90a5a23fd9 | ||
|
|
94e87141ff | ||
|
|
fceaf3e94b | ||
|
|
3be554cb55 | ||
|
|
27b18fbedf | ||
|
|
5e7c6906b3 | ||
|
|
d05ffe32a3 | ||
|
|
f1298d1db4 | ||
|
|
408738e08d | ||
|
|
8d04fbdb74 | ||
|
|
dccb31d17e | ||
|
|
f61210287e | ||
|
|
18ad7220f0 | ||
|
|
79e0df1d43 | ||
|
|
a2f53085e5 | ||
|
|
c5782252ea | ||
|
|
bf3d88facd | ||
|
|
e45b0bf715 | ||
|
|
9db6c12eea | ||
|
|
3a391b69e8 | ||
|
|
cc1fb83c79 | ||
|
|
efa5dd28f1 | ||
|
|
f1eddae379 | ||
|
|
34febe670d |
@@ -57,7 +57,6 @@ class StartMariadb
|
||||
'mem_swappiness' => $this->database->limits_memory_swappiness,
|
||||
'mem_reservation' => $this->database->limits_memory_reservation,
|
||||
'cpus' => (float) $this->database->limits_cpus,
|
||||
'cpuset' => $this->database->limits_cpuset,
|
||||
'cpu_shares' => $this->database->limits_cpu_shares,
|
||||
]
|
||||
],
|
||||
@@ -69,6 +68,9 @@ class StartMariadb
|
||||
]
|
||||
]
|
||||
];
|
||||
if (!is_null($this->database->limits_cpuset)) {
|
||||
data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset);
|
||||
}
|
||||
if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) {
|
||||
$docker_compose['services'][$container_name]['logging'] = [
|
||||
'driver' => 'fluentd',
|
||||
|
||||
@@ -64,7 +64,6 @@ class StartMongodb
|
||||
'mem_swappiness' => $this->database->limits_memory_swappiness,
|
||||
'mem_reservation' => $this->database->limits_memory_reservation,
|
||||
'cpus' => (float) $this->database->limits_cpus,
|
||||
'cpuset' => $this->database->limits_cpuset,
|
||||
'cpu_shares' => $this->database->limits_cpu_shares,
|
||||
]
|
||||
],
|
||||
@@ -76,6 +75,9 @@ class StartMongodb
|
||||
]
|
||||
]
|
||||
];
|
||||
if (!is_null($this->database->limits_cpuset)) {
|
||||
data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset);
|
||||
}
|
||||
if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) {
|
||||
$docker_compose['services'][$container_name]['logging'] = [
|
||||
'driver' => 'fluentd',
|
||||
@@ -121,7 +123,7 @@ class StartMongodb
|
||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml pull";
|
||||
$this->commands[] = "docker compose -f $this->configuration_dir/docker-compose.yml up -d";
|
||||
$this->commands[] = "echo '{$database->name} started.'";
|
||||
return remote_process($this->commands, $database->destination->server,callEventOnFinish: 'DatabaseStatusChanged');
|
||||
return remote_process($this->commands, $database->destination->server, callEventOnFinish: 'DatabaseStatusChanged');
|
||||
}
|
||||
|
||||
private function generate_local_persistent_volumes()
|
||||
|
||||
@@ -57,7 +57,6 @@ class StartMysql
|
||||
'mem_swappiness' => $this->database->limits_memory_swappiness,
|
||||
'mem_reservation' => $this->database->limits_memory_reservation,
|
||||
'cpus' => (float) $this->database->limits_cpus,
|
||||
'cpuset' => $this->database->limits_cpuset,
|
||||
'cpu_shares' => $this->database->limits_cpu_shares,
|
||||
]
|
||||
],
|
||||
@@ -69,6 +68,9 @@ class StartMysql
|
||||
]
|
||||
]
|
||||
];
|
||||
if (!is_null($this->database->limits_cpuset)) {
|
||||
data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset);
|
||||
}
|
||||
if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) {
|
||||
$docker_compose['services'][$container_name]['logging'] = [
|
||||
'driver' => 'fluentd',
|
||||
|
||||
@@ -50,12 +50,8 @@ class StartPostgresql
|
||||
],
|
||||
'healthcheck' => [
|
||||
'test' => [
|
||||
'CMD-SHELL',
|
||||
'pg_isready',
|
||||
'-d',
|
||||
$this->database->postgres_db,
|
||||
'-U',
|
||||
$this->database->postgres_user,
|
||||
"CMD-SHELL",
|
||||
"psql -U {$this->database->postgres_user} -d {$this->database->postgres_db} -c 'SELECT 1' || exit 1"
|
||||
],
|
||||
'interval' => '5s',
|
||||
'timeout' => '5s',
|
||||
@@ -67,7 +63,6 @@ class StartPostgresql
|
||||
'mem_swappiness' => $this->database->limits_memory_swappiness,
|
||||
'mem_reservation' => $this->database->limits_memory_reservation,
|
||||
'cpus' => (float) $this->database->limits_cpus,
|
||||
'cpuset' => $this->database->limits_cpuset,
|
||||
'cpu_shares' => $this->database->limits_cpu_shares,
|
||||
]
|
||||
],
|
||||
@@ -79,6 +74,9 @@ class StartPostgresql
|
||||
]
|
||||
]
|
||||
];
|
||||
if (!is_null($this->database->limits_cpuset)) {
|
||||
data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset);
|
||||
}
|
||||
if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) {
|
||||
ray('Log Drain Enabled');
|
||||
$docker_compose['services'][$container_name]['logging'] = [
|
||||
|
||||
@@ -66,7 +66,6 @@ class StartRedis
|
||||
'mem_swappiness' => $this->database->limits_memory_swappiness,
|
||||
'mem_reservation' => $this->database->limits_memory_reservation,
|
||||
'cpus' => (float) $this->database->limits_cpus,
|
||||
'cpuset' => $this->database->limits_cpuset,
|
||||
'cpu_shares' => $this->database->limits_cpu_shares,
|
||||
]
|
||||
],
|
||||
@@ -78,6 +77,9 @@ class StartRedis
|
||||
]
|
||||
]
|
||||
];
|
||||
if (!is_null($this->database->limits_cpuset)) {
|
||||
data_set($docker_compose, "services.{$container_name}.cpuset", $this->database->limits_cpuset);
|
||||
}
|
||||
if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) {
|
||||
$docker_compose['services'][$container_name]['logging'] = [
|
||||
'driver' => 'fluentd',
|
||||
|
||||
23
app/Actions/Server/CleanupDocker.php
Normal file
23
app/Actions/Server/CleanupDocker.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace App\Actions\Server;
|
||||
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
use App\Models\Server;
|
||||
|
||||
class CleanupDocker
|
||||
{
|
||||
use AsAction;
|
||||
public function handle(Server $server, bool $force = true)
|
||||
{
|
||||
if ($force) {
|
||||
instant_remote_process(['docker image prune -af'], $server, false);
|
||||
instant_remote_process(['docker container prune -f --filter "label=coolify.managed=true"'], $server, false);
|
||||
instant_remote_process(['docker builder prune -af'], $server, false);
|
||||
} else {
|
||||
instant_remote_process(['docker image prune -f'], $server, false);
|
||||
instant_remote_process(['docker container prune -f --filter "label=coolify.managed=true"'], $server, false);
|
||||
instant_remote_process(['docker builder prune -f'], $server, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@ class UpdateCoolify
|
||||
if (!$this->server) {
|
||||
return;
|
||||
}
|
||||
CleanupDocker::run($this->server, false);
|
||||
$this->latestVersion = get_latest_version_of_coolify();
|
||||
$this->currentVersion = config('version');
|
||||
ray('latest version:' . $this->latestVersion . " current version: " . $this->currentVersion . ' force: ' . $force);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Jobs\DeleteResourceJob;
|
||||
use App\Models\Application;
|
||||
use App\Models\Server;
|
||||
use App\Models\Service;
|
||||
@@ -91,7 +92,7 @@ class ServicesDelete extends Command
|
||||
if (!$confirmed) {
|
||||
break;
|
||||
}
|
||||
$toDelete->delete();
|
||||
DeleteResourceJob::dispatch($toDelete);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,7 +116,7 @@ class ServicesDelete extends Command
|
||||
if (!$confirmed) {
|
||||
return;
|
||||
}
|
||||
$toDelete->delete();
|
||||
DeleteResourceJob::dispatch($toDelete);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -139,7 +140,7 @@ class ServicesDelete extends Command
|
||||
if (!$confirmed) {
|
||||
return;
|
||||
}
|
||||
$toDelete->delete();
|
||||
DeleteResourceJob::dispatch($toDelete);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ class Kernel extends ConsoleKernel
|
||||
}
|
||||
}
|
||||
foreach ($servers as $server) {
|
||||
$schedule->job(new ServerStatusJob($server))->everyTenMinutes()->onOneServer();
|
||||
$schedule->job(new ServerStatusJob($server))->everyFiveMinutes()->onOneServer();
|
||||
}
|
||||
}
|
||||
private function instance_auto_update($schedule)
|
||||
|
||||
@@ -203,7 +203,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
||||
dispatch(new ContainerStatusJob($this->server));
|
||||
}
|
||||
$this->next(ApplicationDeploymentStatus::FINISHED->value);
|
||||
$this->application->isConfigurationChanged(true);
|
||||
$this->application->isConfigurationChanged(false);
|
||||
return;
|
||||
} else if ($this->application->dockerfile) {
|
||||
$this->deploy_simple_dockerfile();
|
||||
@@ -477,7 +477,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
||||
);
|
||||
} else {
|
||||
$this->execute_remote_command(
|
||||
[executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} build"), "hidden" => true],
|
||||
[executeInDocker($this->deployment_uuid, "SOURCE_COMMIT={$this->commit} docker compose --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} build"), "hidden" => true],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -521,7 +521,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
||||
);
|
||||
} else {
|
||||
$this->execute_remote_command(
|
||||
[executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} up -d"), "hidden" => true],
|
||||
[executeInDocker($this->deployment_uuid, "SOURCE_COMMIT={$this->commit} docker compose --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} up -d"), "hidden" => true],
|
||||
);
|
||||
}
|
||||
$this->application_deployment_queue->addLogEntry("New container started.");
|
||||
@@ -738,13 +738,15 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
||||
$this->generate_nixpacks_confs();
|
||||
}
|
||||
$this->generate_compose_file();
|
||||
|
||||
// Needs separate preview variables
|
||||
$this->generate_build_env_variables();
|
||||
$this->add_build_env_variables_to_dockerfile();
|
||||
if ($this->application->build_pack !== 'nixpacks') {
|
||||
$this->add_build_env_variables_to_dockerfile();
|
||||
}
|
||||
$this->build_image();
|
||||
$this->stop_running_container();
|
||||
if ($this->application->destination->server->isSwarm()) {
|
||||
ray("{$this->workdir}{$this->docker_compose_location}");
|
||||
$this->push_to_docker_registry();
|
||||
$this->execute_remote_command(
|
||||
[
|
||||
@@ -754,7 +756,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
||||
} else {
|
||||
$this->execute_remote_command(
|
||||
["echo -n 'Starting preview deployment.'"],
|
||||
[executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} up -d"), "hidden" => true],
|
||||
[executeInDocker($this->deployment_uuid, "SOURCE_COMMIT={$this->commit} docker compose --project-directory {$this->workdir} up -d"), "hidden" => true],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -911,13 +913,11 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
||||
if ($this->nixpacks_plan) {
|
||||
$parsed = Toml::Parse($this->nixpacks_plan);
|
||||
// Do any modifications here
|
||||
// $cmds = collect(data_get($parsed, 'phases.setup.cmds', []));
|
||||
$this->generate_env_variables();
|
||||
// data_set($parsed, 'phases.setup.cmds', $cmds);
|
||||
ray($this->env_args->toArray());
|
||||
$merged_envs = $this->env_args->merge(collect(data_get($parsed, 'variables', [])));
|
||||
data_set($parsed, 'variables', $merged_envs->toArray());
|
||||
$this->nixpacks_plan = json_encode($parsed, JSON_PRETTY_PRINT);
|
||||
ray($this->nixpacks_plan);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -965,6 +965,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
||||
$this->env_args->put($env->key, $env->value);
|
||||
}
|
||||
}
|
||||
$this->env_args->put('SOURCE_COMMIT', $this->commit);
|
||||
}
|
||||
|
||||
private function generate_compose_file()
|
||||
@@ -1017,7 +1018,6 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
||||
'mem_swappiness' => $this->application->limits_memory_swappiness,
|
||||
'mem_reservation' => $this->application->limits_memory_reservation,
|
||||
'cpus' => (float) $this->application->limits_cpus,
|
||||
'cpuset' => $this->application->limits_cpuset,
|
||||
'cpu_shares' => $this->application->limits_cpu_shares,
|
||||
]
|
||||
],
|
||||
@@ -1029,6 +1029,9 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
||||
]
|
||||
]
|
||||
];
|
||||
if (!is_null($this->application->limits_cpuset)) {
|
||||
data_set($docker_compose, 'services.' . $this->container_name . '.cpuset', $this->application->limits_cpuset);
|
||||
}
|
||||
if ($this->server->isSwarm()) {
|
||||
data_forget($docker_compose, 'services.' . $this->container_name . '.container_name');
|
||||
data_forget($docker_compose, 'services.' . $this->container_name . '.expose');
|
||||
@@ -1189,12 +1192,14 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
||||
}
|
||||
}
|
||||
// Add PORT if not exists, use the first port as default
|
||||
if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('PORT'))->isEmpty()) {
|
||||
if ($environment_variables->filter(fn ($env) => Str::of($env)->startsWith('PORT'))->isEmpty()) {
|
||||
$environment_variables->push("PORT={$ports[0]}");
|
||||
}
|
||||
if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('SOURCE_COMMIT'))->isEmpty()) {
|
||||
if ($environment_variables->filter(fn ($env) => Str::of($env)->startsWith('SOURCE_COMMIT'))->isEmpty()) {
|
||||
if (!is_null($this->commit)) {
|
||||
$environment_variables->push("SOURCE_COMMIT={$this->commit}");
|
||||
} else {
|
||||
$environment_variables->push("SOURCE_COMMIT=unknown");
|
||||
}
|
||||
}
|
||||
return $environment_variables->all();
|
||||
@@ -1439,11 +1444,11 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
||||
$this->application_deployment_queue->addLogEntry("Pulling latest images from the registry.");
|
||||
$this->execute_remote_command(
|
||||
[executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} pull"), "hidden" => true],
|
||||
[executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} build"), "hidden" => true],
|
||||
[executeInDocker($this->deployment_uuid, "SOURCE_COMMIT={$this->commit} docker compose --project-directory {$this->workdir} build"), "hidden" => true],
|
||||
);
|
||||
} else {
|
||||
$this->execute_remote_command(
|
||||
[executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} build"), "hidden" => true],
|
||||
[executeInDocker($this->deployment_uuid, "SOURCE_COMMIT={$this->commit} docker compose --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} build"), "hidden" => true],
|
||||
);
|
||||
}
|
||||
$this->application_deployment_queue->addLogEntry("New images built.");
|
||||
@@ -1455,16 +1460,16 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
||||
$this->application_deployment_queue->addLogEntry("Pulling latest images from the registry.");
|
||||
$this->execute_remote_command(
|
||||
[executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} pull"), "hidden" => true],
|
||||
[executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} up --build -d"), "hidden" => true],
|
||||
[executeInDocker($this->deployment_uuid, "SOURCE_COMMIT={$this->commit} docker compose --project-directory {$this->workdir} up --build -d"), "hidden" => true],
|
||||
);
|
||||
} else {
|
||||
if ($this->docker_compose_location) {
|
||||
$this->execute_remote_command(
|
||||
[executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} up --build -d"), "hidden" => true],
|
||||
[executeInDocker($this->deployment_uuid, "SOURCE_COMMIT={$this->commit} docker compose --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} up --build -d"), "hidden" => true],
|
||||
);
|
||||
} else {
|
||||
$this->execute_remote_command(
|
||||
[executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} up --build -d"), "hidden" => true],
|
||||
[executeInDocker($this->deployment_uuid, "SOURCE_COMMIT={$this->commit} docker compose --project-directory {$this->workdir} up --build -d"), "hidden" => true],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Actions\Server\CleanupDocker;
|
||||
use App\Models\Server;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
||||
@@ -43,9 +44,7 @@ class DockerCleanupJob implements ShouldQueue, ShouldBeEncrypted
|
||||
ray('Usage before: ' . $this->usageBefore);
|
||||
if ($this->usageBefore >= $this->server->settings->cleanup_after_percentage) {
|
||||
ray('Cleaning up ' . $this->server->name);
|
||||
instant_remote_process(['docker image prune -af'], $this->server, false);
|
||||
instant_remote_process(['docker container prune -f --filter "label=coolify.managed=true"'], $this->server, false);
|
||||
instant_remote_process(['docker builder prune -af'], $this->server, false);
|
||||
CleanupDocker::run($this->server);
|
||||
$usageAfter = $this->server->getDiskUsage();
|
||||
if ($usageAfter < $this->usageBefore) {
|
||||
ray('Saved ' . ($this->usageBefore - $usageAfter) . '% disk space on ' . $this->server->name);
|
||||
|
||||
@@ -108,7 +108,7 @@ class ScheduledTaskJob implements ShouldQueue
|
||||
'message' => $this->task_output ?? $e->getMessage(),
|
||||
]);
|
||||
}
|
||||
send_internal_notification('ScheduledTaskJob failed with: ' . $e->getMessage());
|
||||
// send_internal_notification('ScheduledTaskJob failed with: ' . $e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ class General extends Component
|
||||
$this->isConfigurationChanged = $this->application->isConfigurationChanged();
|
||||
$this->customLabels = $this->application->parseContainerLabels();
|
||||
if (!$this->customLabels && $this->application->destination->server->proxyType() === 'TRAEFIK_V2') {
|
||||
$this->customLabels = str(implode(",", generateLabelsApplication($this->application)))->replace(',', "\n");
|
||||
$this->customLabels = str(implode("|", generateLabelsApplication($this->application)))->replace("|", "\n");
|
||||
$this->application->custom_labels = base64_encode($this->customLabels);
|
||||
$this->application->save();
|
||||
}
|
||||
@@ -182,7 +182,7 @@ class General extends Component
|
||||
}
|
||||
public function checkLabelUpdates()
|
||||
{
|
||||
if (md5($this->application->custom_labels) !== md5(implode(",", generateLabelsApplication($this->application)))) {
|
||||
if (md5($this->application->custom_labels) !== md5(implode("|", generateLabelsApplication($this->application)))) {
|
||||
$this->labelsChanged = true;
|
||||
} else {
|
||||
$this->labelsChanged = false;
|
||||
@@ -201,7 +201,7 @@ class General extends Component
|
||||
}
|
||||
public function resetDefaultLabels($showToaster = true)
|
||||
{
|
||||
$this->customLabels = str(implode(",", generateLabelsApplication($this->application)))->replace(',', "\n");
|
||||
$this->customLabels = str(implode("|", generateLabelsApplication($this->application)))->replace("|", "\n");
|
||||
$this->ports_exposes = $this->application->ports_exposes;
|
||||
$this->submit($showToaster);
|
||||
}
|
||||
@@ -209,13 +209,13 @@ class General extends Component
|
||||
public function updatedApplicationFqdn()
|
||||
{
|
||||
$this->resetDefaultLabels(false);
|
||||
$this->dispatch('success', 'Labels reset to default!');
|
||||
// $this->dispatch('success', 'Labels reset to default!');
|
||||
}
|
||||
public function submit($showToaster = true)
|
||||
{
|
||||
try {
|
||||
if (!$this->customLabels && $this->application->destination->server->proxyType() === 'TRAEFIK_V2') {
|
||||
$this->customLabels = str(implode(",", generateLabelsApplication($this->application)))->replace(',', "\n");
|
||||
$this->customLabels = str(implode("|", generateLabelsApplication($this->application)))->replace("|", "\n");
|
||||
$this->application->custom_labels = base64_encode($this->customLabels);
|
||||
$this->application->save();
|
||||
}
|
||||
@@ -235,9 +235,16 @@ class General extends Component
|
||||
]);
|
||||
}
|
||||
if (data_get($this->application, 'fqdn')) {
|
||||
$domains = Str::of($this->application->fqdn)->trim()->explode(',')->map(function ($domain) {
|
||||
return Str::of($domain)->trim()->lower();
|
||||
$this->application->fqdn = str($this->application->fqdn)->replaceEnd(',', '')->trim();
|
||||
$domains = str($this->application->fqdn)->trim()->explode(',')->map(function ($domain) {
|
||||
return str($domain)->trim()->lower();
|
||||
});
|
||||
$domains = $domains->unique();
|
||||
foreach ($domains as $domain) {
|
||||
if (!validate_dns_entry($domain, $this->application->destination->server)) {
|
||||
$showToaster && $this->dispatch('error', "Validating DNS settings for: $domain failed.<br>Make sure you have added the DNS records correctly.<br><br>Check this <a target='_blank' class='underline' href='https://coolify.io/docs/dns-settings'>documentation</a> for further help.");
|
||||
}
|
||||
}
|
||||
$this->application->fqdn = $domains->implode(',');
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ class Heading extends Component
|
||||
} else {
|
||||
dispatch(new ServerStatusJob($this->application->destination->server));
|
||||
}
|
||||
if ($showNotification) $this->dispatch('success', "Application ({$this->application->name}) status updated.");
|
||||
if ($showNotification) $this->dispatch('success', "Application status updated.");
|
||||
}
|
||||
|
||||
public function force_deploy_without_cache()
|
||||
|
||||
@@ -10,7 +10,15 @@ class Index extends Component
|
||||
{
|
||||
public Project $project;
|
||||
public Environment $environment;
|
||||
public function mount () {
|
||||
public $applications = [];
|
||||
public $postgresqls = [];
|
||||
public $redis = [];
|
||||
public $mongodbs = [];
|
||||
public $mysqls = [];
|
||||
public $mariadbs = [];
|
||||
public $services = [];
|
||||
public function mount()
|
||||
{
|
||||
$project = currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
||||
if (!$project) {
|
||||
return redirect()->route('dashboard');
|
||||
@@ -21,6 +29,84 @@ class Index extends Component
|
||||
}
|
||||
$this->project = $project;
|
||||
$this->environment = $environment;
|
||||
$this->applications = $environment->applications->sortBy('name');
|
||||
$this->applications = $this->applications->map(function ($application) {
|
||||
if (data_get($application, 'environment.project.uuid')) {
|
||||
$application->hrefLink = route('project.application.configuration', [
|
||||
'project_uuid' => data_get($application, 'environment.project.uuid'),
|
||||
'environment_name' => data_get($application, 'environment.name'),
|
||||
'application_uuid' => data_get($application, 'uuid')
|
||||
]);
|
||||
}
|
||||
return $application;
|
||||
});
|
||||
$this->postgresqls = $environment->postgresqls->sortBy('name');
|
||||
$this->postgresqls = $this->postgresqls->map(function ($postgresql) {
|
||||
if (data_get($postgresql, 'environment.project.uuid')) {
|
||||
$postgresql->hrefLink = route('project.database.configuration', [
|
||||
'project_uuid' => data_get($postgresql, 'environment.project.uuid'),
|
||||
'environment_name' => data_get($postgresql, 'environment.name'),
|
||||
'database_uuid' => data_get($postgresql, 'uuid')
|
||||
]);
|
||||
}
|
||||
return $postgresql;
|
||||
});
|
||||
$this->redis = $environment->redis->sortBy('name');
|
||||
$this->redis = $this->redis->map(function ($redis) {
|
||||
if (data_get($redis, 'environment.project.uuid')) {
|
||||
$redis->hrefLink = route('project.database.configuration', [
|
||||
'project_uuid' => data_get($redis, 'environment.project.uuid'),
|
||||
'environment_name' => data_get($redis, 'environment.name'),
|
||||
'database_uuid' => data_get($redis, 'uuid')
|
||||
]);
|
||||
}
|
||||
return $redis;
|
||||
});
|
||||
$this->mongodbs = $environment->mongodbs->sortBy('name');
|
||||
$this->mongodbs = $this->mongodbs->map(function ($mongodb) {
|
||||
if (data_get($mongodb, 'environment.project.uuid')) {
|
||||
$mongodb->hrefLink = route('project.database.configuration', [
|
||||
'project_uuid' => data_get($mongodb, 'environment.project.uuid'),
|
||||
'environment_name' => data_get($mongodb, 'environment.name'),
|
||||
'database_uuid' => data_get($mongodb, 'uuid')
|
||||
]);
|
||||
}
|
||||
return $mongodb;
|
||||
});
|
||||
$this->mysqls = $environment->mysqls->sortBy('name');
|
||||
$this->mysqls = $this->mysqls->map(function ($mysql) {
|
||||
if (data_get($mysql, 'environment.project.uuid')) {
|
||||
$mysql->hrefLink = route('project.database.configuration', [
|
||||
'project_uuid' => data_get($mysql, 'environment.project.uuid'),
|
||||
'environment_name' => data_get($mysql, 'environment.name'),
|
||||
'database_uuid' => data_get($mysql, 'uuid')
|
||||
]);
|
||||
}
|
||||
return $mysql;
|
||||
});
|
||||
$this->mariadbs = $environment->mariadbs->sortBy('name');
|
||||
$this->mariadbs = $this->mariadbs->map(function ($mariadb) {
|
||||
if (data_get($mariadb, 'environment.project.uuid')) {
|
||||
$mariadb->hrefLink = route('project.database.configuration', [
|
||||
'project_uuid' => data_get($mariadb, 'environment.project.uuid'),
|
||||
'environment_name' => data_get($mariadb, 'environment.name'),
|
||||
'database_uuid' => data_get($mariadb, 'uuid')
|
||||
]);
|
||||
}
|
||||
return $mariadb;
|
||||
});
|
||||
$this->services = $environment->services->sortBy('name');
|
||||
$this->services = $this->services->map(function ($service) {
|
||||
if (data_get($service, 'environment.project.uuid')) {
|
||||
$service->hrefLink = route('project.service.configuration', [
|
||||
'project_uuid' => data_get($service, 'environment.project.uuid'),
|
||||
'environment_name' => data_get($service, 'environment.name'),
|
||||
'service_uuid' => data_get($service, 'uuid')
|
||||
]);
|
||||
$service->status = serviceStatus($service);
|
||||
}
|
||||
return $service;
|
||||
});
|
||||
}
|
||||
public function render()
|
||||
{
|
||||
|
||||
@@ -108,8 +108,7 @@ class ExecuteContainerCommand extends Component
|
||||
$this->validate();
|
||||
try {
|
||||
// Wrap command to prevent escaped execution in the host.
|
||||
$cmd = 'sh -c "' . str_replace('"', '\"', $this->command) . '"';
|
||||
|
||||
$cmd = 'sh -c "if [ -f ~/.profile ]; then . ~/.profile; fi; ' . str_replace('"', '\"', $this->command) . '"';
|
||||
if (!empty($this->workDir)) {
|
||||
$exec = "docker exec -w {$this->workDir} {$this->container} {$cmd}";
|
||||
} else {
|
||||
|
||||
@@ -44,8 +44,8 @@ class ResourceLimits extends Component
|
||||
if (!$this->resource->limits_cpus) {
|
||||
$this->resource->limits_cpus = "0";
|
||||
}
|
||||
if (!$this->resource->limits_cpuset) {
|
||||
$this->resource->limits_cpuset = "0";
|
||||
if ($this->resource->limits_cpuset === "") {
|
||||
$this->resource->limits_cpuset = null;
|
||||
}
|
||||
if (!$this->resource->limits_cpu_shares) {
|
||||
$this->resource->limits_cpu_shares = 1024;
|
||||
|
||||
@@ -76,7 +76,7 @@ class Form extends Component
|
||||
$this->server->settings->is_usable = true;
|
||||
$this->server->settings->save();
|
||||
} else {
|
||||
$this->dispatch('error', 'Server is not reachable. Please check your connection and configuration.');
|
||||
$this->dispatch('error', 'Server is not reachable.<br>Please validate your configuration and connection.<br><br>Check this <a target="_blank" class="underline" href="https://coolify.io/docs/configuration#openssh-server">documentation</a> for further help.');
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -85,7 +85,7 @@ class Form extends Component
|
||||
try {
|
||||
$uptime = $this->server->validateConnection();
|
||||
if (!$uptime) {
|
||||
$install && $this->dispatch('error', 'Server is not reachable. Please check your connection and configuration.');
|
||||
$install && $this->dispatch('error', 'Server is not reachable.<br>Please validate your configuration and connection.<br><br>Check this <a target="_blank" class="underline" href="https://coolify.io/docs/configuration#openssh-server">documentation</a> for further help.');
|
||||
return;
|
||||
}
|
||||
$supported_os_type = $this->server->validateOS();
|
||||
|
||||
@@ -39,7 +39,7 @@ class ShowPrivateKey extends Component
|
||||
if ($uptime) {
|
||||
$this->dispatch('success', 'Server is reachable.');
|
||||
} else {
|
||||
$this->dispatch('error', 'Server is not reachable. Please check your connection and private key configuration.');
|
||||
$this->dispatch('error', 'Server is not reachable.<br>Please validate your configuration and connection.<br><br>Check this <a target="_blank" class="underline" href="https://coolify.io/docs/configuration#openssh-server">documentation</a> for further help.');
|
||||
return;
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
|
||||
@@ -15,6 +15,7 @@ class Configuration extends Component
|
||||
public bool $do_not_track;
|
||||
public bool $is_auto_update_enabled;
|
||||
public bool $is_registration_enabled;
|
||||
public bool $is_dns_validation_enabled;
|
||||
public bool $next_channel;
|
||||
protected string $dynamic_config_path = '/data/coolify/proxy/dynamic';
|
||||
protected Server $server;
|
||||
@@ -24,12 +25,14 @@ class Configuration extends Component
|
||||
'settings.resale_license' => 'nullable',
|
||||
'settings.public_port_min' => 'required',
|
||||
'settings.public_port_max' => 'required',
|
||||
'settings.custom_dns_servers' => 'nullable',
|
||||
];
|
||||
protected $validationAttributes = [
|
||||
'settings.fqdn' => 'FQDN',
|
||||
'settings.resale_license' => 'Resale License',
|
||||
'settings.public_port_min' => 'Public port min',
|
||||
'settings.public_port_max' => 'Public port max',
|
||||
'settings.custom_dns_servers' => 'Custom DNS servers',
|
||||
];
|
||||
|
||||
public function mount()
|
||||
@@ -38,6 +41,7 @@ class Configuration extends Component
|
||||
$this->is_auto_update_enabled = $this->settings->is_auto_update_enabled;
|
||||
$this->is_registration_enabled = $this->settings->is_registration_enabled;
|
||||
$this->next_channel = $this->settings->next_channel;
|
||||
$this->is_dns_validation_enabled = $this->settings->is_dns_validation_enabled;
|
||||
}
|
||||
|
||||
public function instantSave()
|
||||
@@ -45,6 +49,7 @@ class Configuration extends Component
|
||||
$this->settings->do_not_track = $this->do_not_track;
|
||||
$this->settings->is_auto_update_enabled = $this->is_auto_update_enabled;
|
||||
$this->settings->is_registration_enabled = $this->is_registration_enabled;
|
||||
$this->settings->is_dns_validation_enabled = $this->is_dns_validation_enabled;
|
||||
if ($this->next_channel) {
|
||||
$this->settings->next_channel = false;
|
||||
$this->next_channel = false;
|
||||
@@ -63,6 +68,14 @@ class Configuration extends Component
|
||||
return;
|
||||
}
|
||||
$this->validate();
|
||||
|
||||
$this->settings->custom_dns_servers = str($this->settings->custom_dns_servers)->replaceEnd(',', '')->trim();
|
||||
$this->settings->custom_dns_servers = str($this->settings->custom_dns_servers)->trim()->explode(',')->map(function ($dns) {
|
||||
return str($dns)->trim()->lower();
|
||||
});
|
||||
$this->settings->custom_dns_servers = $this->settings->custom_dns_servers->unique();
|
||||
$this->settings->custom_dns_servers = $this->settings->custom_dns_servers->implode(',');
|
||||
|
||||
$this->settings->save();
|
||||
$this->server = Server::findOrFail(0);
|
||||
$this->setup_instance_fqdn();
|
||||
|
||||
@@ -429,7 +429,7 @@ class Application extends BaseModel
|
||||
}
|
||||
public function isConfigurationChanged($save = false)
|
||||
{
|
||||
$newConfigHash = $this->fqdn . $this->git_repository . $this->git_branch . $this->git_commit_sha . $this->build_pack . $this->static_image . $this->install_command . $this->build_command . $this->start_command . $this->port_exposes . $this->port_mappings . $this->base_directory . $this->publish_directory . $this->health_check_path . $this->health_check_port . $this->health_check_host . $this->health_check_method . $this->health_check_return_code . $this->health_check_scheme . $this->health_check_response_text . $this->health_check_interval . $this->health_check_timeout . $this->health_check_retries . $this->health_check_start_period . $this->health_check_enabled . $this->limits_memory . $this->limits_swap . $this->limits_swappiness . $this->limits_reservation . $this->limits_cpus . $this->limits_cpuset . $this->limits_cpu_shares . $this->dockerfile . $this->dockerfile_location . $this->custom_labels;
|
||||
$newConfigHash = $this->fqdn . $this->git_repository . $this->git_branch . $this->git_commit_sha . $this->build_pack . $this->static_image . $this->install_command . $this->build_command . $this->start_command . $this->port_exposes . $this->port_mappings . $this->base_directory . $this->publish_directory . $this->dockerfile . $this->dockerfile_location . $this->custom_labels;
|
||||
if ($this->pull_request_id === 0 || $this->pull_request_id === null) {
|
||||
$newConfigHash .= json_encode($this->environment_variables->all());
|
||||
} else {
|
||||
@@ -642,7 +642,6 @@ class Application extends BaseModel
|
||||
'mem_swappiness' => $this->limits_memory_swappiness,
|
||||
'mem_reservation' => $this->limits_memory_reservation,
|
||||
'cpus' => (float) $this->limits_cpus,
|
||||
'cpuset' => $this->limits_cpuset,
|
||||
'cpu_shares' => $this->limits_cpu_shares,
|
||||
]
|
||||
],
|
||||
@@ -654,6 +653,9 @@ class Application extends BaseModel
|
||||
]
|
||||
]
|
||||
];
|
||||
if (!is_null($this->limits_cpuset)) {
|
||||
data_set($docker_compose, "services.{$container_name}.cpuset", $this->limits_cpuset);
|
||||
}
|
||||
if ($server->isSwarm()) {
|
||||
data_forget($docker_compose, 'services.' . $container_name . '.container_name');
|
||||
data_forget($docker_compose, 'services.' . $container_name . '.expose');
|
||||
@@ -1064,7 +1066,7 @@ class Application extends BaseModel
|
||||
$customLabels = base64_decode($this->custom_labels);
|
||||
if (mb_detect_encoding($customLabels, 'ASCII', true) === false) {
|
||||
ray('custom_labels contains non-ascii characters');
|
||||
$customLabels = str(implode(",", generateLabelsApplication($this, $preview)))->replace(',', "\n");
|
||||
$customLabels = str(implode("|", generateLabelsApplication($this, $preview)))->replace("|", "\n");
|
||||
}
|
||||
$this->custom_labels = base64_encode($customLabels);
|
||||
$this->save();
|
||||
|
||||
@@ -167,7 +167,6 @@ function generateComposeFile(string $deploymentUuid, Server $server, string $net
|
||||
'mem_swappiness' => $application->limits_memory_swappiness,
|
||||
'mem_reservation' => $application->limits_memory_reservation,
|
||||
'cpus' => (int) $application->limits_cpus,
|
||||
'cpuset' => $application->limits_cpuset,
|
||||
'cpu_shares' => $application->limits_cpu_shares,
|
||||
]
|
||||
],
|
||||
@@ -179,6 +178,9 @@ function generateComposeFile(string $deploymentUuid, Server $server, string $net
|
||||
]
|
||||
]
|
||||
];
|
||||
if (!is_null($application->limits_cpuset)) {
|
||||
data_set($docker_compose, "services.{$containerName}.cpuset", $application->limits_cpuset);
|
||||
}
|
||||
if ($server->isLogDrainEnabled() && $application->isLogDrainEnabled()) {
|
||||
$docker_compose['services'][$containerName]['logging'] = [
|
||||
'driver' => 'fluentd',
|
||||
|
||||
@@ -215,6 +215,8 @@ function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_
|
||||
{
|
||||
$labels = collect([]);
|
||||
$labels->push('traefik.enable=true');
|
||||
$labels->push("traefik.http.middlewares.gzip.compress=true");
|
||||
$labels->push("traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https");
|
||||
foreach ($domains as $loop => $domain) {
|
||||
try {
|
||||
$uuid = new Cuid2(7);
|
||||
@@ -233,14 +235,15 @@ function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_
|
||||
// Set labels for https
|
||||
$labels->push("traefik.http.routers.{$https_label}.rule=Host(`{$host}`) && PathPrefix(`{$path}`)");
|
||||
$labels->push("traefik.http.routers.{$https_label}.entryPoints=https");
|
||||
$labels->push("traefik.http.routers.{$https_label}.middlewares=gzip");
|
||||
if ($port) {
|
||||
$labels->push("traefik.http.routers.{$https_label}.service={$https_label}");
|
||||
$labels->push("traefik.http.services.{$https_label}.loadbalancer.server.port=$port");
|
||||
}
|
||||
if ($path !== '/') {
|
||||
$labels->push("traefik.http.routers.{$https_label}.middlewares={$https_label}-stripprefix");
|
||||
$labels->push("traefik.http.middlewares.{$https_label}-stripprefix.stripprefix.prefixes={$path}");
|
||||
$labels->push("traefik.http.routers.{$https_label}.middlewares={$https_label}-stripprefix,gzip");
|
||||
} else {
|
||||
$labels->push("traefik.http.routers.{$https_label}.middlewares=gzip");
|
||||
}
|
||||
|
||||
$labels->push("traefik.http.routers.{$https_label}.tls=true");
|
||||
@@ -260,14 +263,15 @@ function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_
|
||||
// Set labels for http
|
||||
$labels->push("traefik.http.routers.{$http_label}.rule=Host(`{$host}`) && PathPrefix(`{$path}`)");
|
||||
$labels->push("traefik.http.routers.{$http_label}.entryPoints=http");
|
||||
$labels->push("traefik.http.routers.{$http_label}.middlewares=gzip");
|
||||
if ($port) {
|
||||
$labels->push("traefik.http.services.{$http_label}.loadbalancer.server.port=$port");
|
||||
$labels->push("traefik.http.routers.{$http_label}.service={$http_label}");
|
||||
}
|
||||
if ($path !== '/') {
|
||||
$labels->push("traefik.http.routers.{$http_label}.middlewares={$http_label}-stripprefix");
|
||||
$labels->push("traefik.http.middlewares.{$http_label}-stripprefix.stripprefix.prefixes={$path}");
|
||||
$labels->push("traefik.http.routers.{$http_label}.middlewares={$http_label}-stripprefix,gzip");
|
||||
} else {
|
||||
$labels->push("traefik.http.routers.{$http_label}.middlewares=gzip");
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
|
||||
@@ -103,9 +103,6 @@ function generate_default_proxy_configuration(Server $server)
|
||||
"traefik.http.routers.traefik.entrypoints=http",
|
||||
"traefik.http.routers.traefik.service=api@internal",
|
||||
"traefik.http.services.traefik.loadbalancer.server.port=8080",
|
||||
// Global Middlewares
|
||||
"traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https",
|
||||
"traefik.http.middlewares.gzip.compress=true",
|
||||
];
|
||||
$config = [
|
||||
"version" => "3.8",
|
||||
@@ -198,10 +195,23 @@ function setup_dynamic_configuration()
|
||||
$traefik_dynamic_conf = [
|
||||
'http' =>
|
||||
[
|
||||
'middlewares' => [
|
||||
'redirect-to-https' => [
|
||||
'redirectscheme' => [
|
||||
'scheme' => 'https',
|
||||
],
|
||||
],
|
||||
'gzip' => [
|
||||
'compress' => true,
|
||||
],
|
||||
],
|
||||
'routers' =>
|
||||
[
|
||||
'coolify-http' =>
|
||||
[
|
||||
'middlewares' => [
|
||||
0 => 'gzip',
|
||||
],
|
||||
'entryPoints' => [
|
||||
0 => 'http',
|
||||
],
|
||||
@@ -251,7 +261,7 @@ function setup_dynamic_configuration()
|
||||
|
||||
if ($schema === 'https') {
|
||||
$traefik_dynamic_conf['http']['routers']['coolify-http']['middlewares'] = [
|
||||
0 => 'redirect-to-https@docker',
|
||||
0 => 'redirect-to-https',
|
||||
];
|
||||
|
||||
$traefik_dynamic_conf['http']['routers']['coolify-https'] = [
|
||||
@@ -288,7 +298,7 @@ function setup_dynamic_configuration()
|
||||
], $server);
|
||||
|
||||
if (config('app.env') == 'local') {
|
||||
ray($yaml);
|
||||
// ray($yaml);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,14 +22,11 @@ use App\Notifications\Channels\EmailChannel;
|
||||
use App\Notifications\Channels\TelegramChannel;
|
||||
use App\Notifications\Internal\GeneralNotification;
|
||||
use DanHarrin\LivewireRateLimiting\Exceptions\TooManyRequestsException;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Illuminate\Mail\Message;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Facades\Request;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
@@ -40,6 +37,7 @@ use Visus\Cuid2\Cuid2;
|
||||
use phpseclib3\Crypt\RSA;
|
||||
use Spatie\Url\Url;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
use PurplePixie\PhpDns\DNSQuery;
|
||||
|
||||
function base_configuration_dir(): string
|
||||
{
|
||||
@@ -1592,3 +1590,70 @@ function getRealtime()
|
||||
return $envDefined;
|
||||
}
|
||||
}
|
||||
|
||||
function validate_dns_entry(string $fqdn, Server $server)
|
||||
{
|
||||
# https://www.cloudflare.com/ips-v4/#
|
||||
$cloudflare_ips = collect(['173.245.48.0/20', '103.21.244.0/22', '103.22.200.0/22', '103.31.4.0/22', '141.101.64.0/18', '108.162.192.0/18', '190.93.240.0/20', '188.114.96.0/20', '197.234.240.0/22', '198.41.128.0/17', '162.158.0.0/15', '104.16.0.0/13', '172.64.0.0/13', '131.0.72.0/22']);
|
||||
|
||||
$url = Url::fromString($fqdn);
|
||||
$host = $url->getHost();
|
||||
if (str($host)->contains('sslip.io')) {
|
||||
return true;
|
||||
}
|
||||
$settings = InstanceSettings::get();
|
||||
$is_dns_validation_enabled = data_get($settings, 'is_dns_validation_enabled');
|
||||
if (!$is_dns_validation_enabled) {
|
||||
return true;
|
||||
}
|
||||
$dns_servers = data_get($settings, 'custom_dns_servers');
|
||||
$dns_servers = str($dns_servers)->explode(',');
|
||||
if ($server->id === 0) {
|
||||
$ip = data_get($settings, 'public_ipv4') || data_get($settings, 'public_ipv6') || $server->ip;
|
||||
} else {
|
||||
$ip = $server->ip;
|
||||
}
|
||||
$found_matching_ip = false;
|
||||
$type = \PurplePixie\PhpDns\DNSTypes::NAME_A;
|
||||
foreach ($dns_servers as $dns_server) {
|
||||
try {
|
||||
ray("Checking $host on $dns_server");
|
||||
$query = new DNSQuery($dns_server);
|
||||
$results = $query->query($host, $type);
|
||||
if ($results === false || $query->hasError()) {
|
||||
ray("Error: " . $query->getLasterror());
|
||||
} else {
|
||||
foreach ($results as $result) {
|
||||
if ($result->getType() == $type) {
|
||||
if (ip_match($result->getData(), $cloudflare_ips->toArray(), $match)) {
|
||||
ray("Found match in Cloudflare IPs: $match");
|
||||
$found_matching_ip = true;
|
||||
break;
|
||||
}
|
||||
if ($result->getData() === $ip) {
|
||||
ray($host . " has IP address " . $result->getData());
|
||||
ray($result->getString());
|
||||
$found_matching_ip = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
}
|
||||
ray("Found match: $found_matching_ip");
|
||||
return $found_matching_ip;
|
||||
}
|
||||
|
||||
function ip_match($ip, $cidrs, &$match = null)
|
||||
{
|
||||
foreach ((array) $cidrs as $cidr) {
|
||||
list($subnet, $mask) = explode('/', $cidr);
|
||||
if (((ip2long($ip) & ($mask = ~((1 << (32 - $mask)) - 1))) == (ip2long($subnet) & $mask))) {
|
||||
$match = $cidr;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"nubs/random-name-generator": "^2.2",
|
||||
"phpseclib/phpseclib": "~3.0",
|
||||
"poliander/cron": "^3.0",
|
||||
"purplepixie/phpdns": "^2.1",
|
||||
"pusher/pusher-php-server": "^7.2",
|
||||
"resend/resend-laravel": "^0.5.0",
|
||||
"sentry/sentry-laravel": "^3.4",
|
||||
|
||||
1624
composer.lock
generated
1624
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@ return [
|
||||
|
||||
// The release version of your application
|
||||
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
|
||||
'release' => '4.0.0-beta.187',
|
||||
'release' => '4.0.0-beta.196',
|
||||
// When left empty or `null` the Laravel environment will be used
|
||||
'environment' => config('app.env'),
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<?php
|
||||
|
||||
return '4.0.0-beta.187';
|
||||
return '4.0.0-beta.196';
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Application;
|
||||
use App\Models\StandaloneMariadb;
|
||||
use App\Models\StandaloneMongodb;
|
||||
use App\Models\StandaloneMysql;
|
||||
use App\Models\StandalonePostgresql;
|
||||
use App\Models\StandaloneRedis;
|
||||
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('applications', function (Blueprint $table) {
|
||||
$table->string('limits_cpuset')->nullable()->default(null)->change();
|
||||
});
|
||||
Schema::table('standalone_postgresqls', function (Blueprint $table) {
|
||||
$table->string('limits_cpuset')->nullable()->default(null)->change();
|
||||
});
|
||||
Schema::table('standalone_redis', function (Blueprint $table) {
|
||||
$table->string('limits_cpuset')->nullable()->default(null)->change();
|
||||
});
|
||||
Schema::table('standalone_mariadbs', function (Blueprint $table) {
|
||||
$table->string('limits_cpuset')->nullable()->default(null)->change();
|
||||
});
|
||||
Schema::table('standalone_mysqls', function (Blueprint $table) {
|
||||
$table->string('limits_cpuset')->nullable()->default(null)->change();
|
||||
});
|
||||
Schema::table('standalone_mongodbs', function (Blueprint $table) {
|
||||
$table->string('limits_cpuset')->nullable()->default(null)->change();
|
||||
});
|
||||
Application::where('limits_cpuset', '0')->update(['limits_cpuset' => null]);
|
||||
StandalonePostgresql::where('limits_cpuset', '0')->update(['limits_cpuset' => null]);
|
||||
StandaloneRedis::where('limits_cpuset', '0')->update(['limits_cpuset' => null]);
|
||||
StandaloneMariadb::where('limits_cpuset', '0')->update(['limits_cpuset' => null]);
|
||||
StandaloneMysql::where('limits_cpuset', '0')->update(['limits_cpuset' => null]);
|
||||
StandaloneMongodb::where('limits_cpuset', '0')->update(['limits_cpuset' => null]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('applications', function (Blueprint $table) {
|
||||
$table->string('limits_cpuset')->nullable()->default("0")->change();
|
||||
});
|
||||
Schema::table('standalone_postgresqls', function (Blueprint $table) {
|
||||
$table->string('limits_cpuset')->nullable()->default("0")->change();
|
||||
});
|
||||
Schema::table('standalone_redis', function (Blueprint $table) {
|
||||
$table->string('limits_cpuset')->nullable()->default("0")->change();
|
||||
});
|
||||
Schema::table('standalone_mariadbs', function (Blueprint $table) {
|
||||
$table->string('limits_cpuset')->nullable()->default("0")->change();
|
||||
});
|
||||
Schema::table('standalone_mysqls', function (Blueprint $table) {
|
||||
$table->string('limits_cpuset')->nullable()->default("0")->change();
|
||||
});
|
||||
Schema::table('standalone_mongodbs', function (Blueprint $table) {
|
||||
$table->string('limits_cpuset')->nullable()->default("0")->change();
|
||||
});
|
||||
Application::where('limits_cpuset', null)->update(['limits_cpuset' => '0']);
|
||||
StandalonePostgresql::where('limits_cpuset', null)->update(['limits_cpuset' => '0']);
|
||||
StandaloneRedis::where('limits_cpuset', null)->update(['limits_cpuset' => '0']);
|
||||
StandaloneMariadb::where('limits_cpuset', null)->update(['limits_cpuset' => '0']);
|
||||
StandaloneMysql::where('limits_cpuset', null)->update(['limits_cpuset' => '0']);
|
||||
StandaloneMongodb::where('limits_cpuset', null)->update(['limits_cpuset' => '0']);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
<?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('instance_settings', function (Blueprint $table) {
|
||||
$table->boolean('is_dns_validation_enabled')->default(true);
|
||||
$table->string('custom_dns_servers')->nullable()->default('1.1.1.1');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('instance_settings', function (Blueprint $table) {
|
||||
$table->dropColumn('is_dns_validation_enabled');
|
||||
$table->dropColumn('custom_dns_servers');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
version: '3.8'
|
||||
services:
|
||||
coolify:
|
||||
image: "ghcr.io/coollabsio/coolify:${LATEST_IMAGE:-4.0.0-beta.153}"
|
||||
image: "ghcr.io/coollabsio/coolify:${LATEST_IMAGE:-4.0.0-beta.190}"
|
||||
volumes:
|
||||
- type: bind
|
||||
source: /data/coolify/source/.env
|
||||
@@ -10,6 +10,7 @@ services:
|
||||
- /data/coolify/ssh:/var/www/html/storage/app/ssh
|
||||
- /data/coolify/applications:/var/www/html/storage/app/applications
|
||||
- /data/coolify/databases:/var/www/html/storage/app/databases
|
||||
- /data/coolify/services:/var/www/html/storage/app/services
|
||||
- /data/coolify/backups:/var/www/html/storage/app/backups
|
||||
environment:
|
||||
- APP_ID
|
||||
|
||||
254
package-lock.json
generated
254
package-lock.json
generated
@@ -5,7 +5,6 @@
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"@alpinejs/focus": "^3.13.3",
|
||||
"@tailwindcss/typography": "0.5.10",
|
||||
"alpinejs": "3.13.3",
|
||||
"daisyui": "4.4.19",
|
||||
@@ -15,14 +14,14 @@
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "4.5.1",
|
||||
"autoprefixer": "10.4.16",
|
||||
"axios": "1.6.2",
|
||||
"axios": "1.6.5",
|
||||
"laravel-echo": "1.15.3",
|
||||
"laravel-vite-plugin": "0.8.1",
|
||||
"postcss": "8.4.32",
|
||||
"postcss": "8.4.33",
|
||||
"pusher-js": "8.4.0-rc2",
|
||||
"tailwindcss": "3.3.6",
|
||||
"tailwindcss": "3.4.1",
|
||||
"vite": "4.5.1",
|
||||
"vue": "3.3.10"
|
||||
"vue": "3.4.13"
|
||||
}
|
||||
},
|
||||
"node_modules/@alloc/quick-lru": {
|
||||
@@ -36,19 +35,10 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/@alpinejs/focus": {
|
||||
"version": "3.13.3",
|
||||
"resolved": "https://registry.npmjs.org/@alpinejs/focus/-/focus-3.13.3.tgz",
|
||||
"integrity": "sha512-fTRX/9wOfysyZ1PJ4gHeUnmiNTIgqBDIqKxeP5iMvj1UHD3TFLDXllvoIKH3ezqcsyQZqxd/q1MFM7dlIhkmeg==",
|
||||
"dependencies": {
|
||||
"focus-trap": "^6.9.4",
|
||||
"tabbable": "^5.3.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/parser": {
|
||||
"version": "7.23.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.5.tgz",
|
||||
"integrity": "sha512-hOOqoiNXrmGdFbhgCzu6GiURxUgM27Xwd/aPuu8RfHEZPBzL1Z54okAHAQjXfcQNwvrlkAmAp4SlRTZ45vlthQ==",
|
||||
"version": "7.23.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz",
|
||||
"integrity": "sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"parser": "bin/babel-parser.js"
|
||||
@@ -534,51 +524,51 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-core": {
|
||||
"version": "3.3.10",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.3.10.tgz",
|
||||
"integrity": "sha512-doe0hODR1+i1menPkRzJ5MNR6G+9uiZHIknK3Zn5OcIztu6GGw7u0XUzf3AgB8h/dfsZC9eouzoLo3c3+N/cVA==",
|
||||
"version": "3.4.13",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.13.tgz",
|
||||
"integrity": "sha512-zGUdmB3j3Irn9z51GXLJ5s0EAHxmsm5/eXl0y6MBaajMeOAaiT4+zaDoxui4Ets98dwIRr8BBaqXXHtHSfm+KA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.23.5",
|
||||
"@vue/shared": "3.3.10",
|
||||
"@babel/parser": "^7.23.6",
|
||||
"@vue/shared": "3.4.13",
|
||||
"entities": "^4.5.0",
|
||||
"estree-walker": "^2.0.2",
|
||||
"source-map-js": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-core/node_modules/@vue/shared": {
|
||||
"version": "3.3.10",
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.10.tgz",
|
||||
"integrity": "sha512-2y3Y2J1a3RhFa0WisHvACJR2ncvWiVHcP8t0Inxo+NKz+8RKO4ZV8eZgCxRgQoA6ITfV12L4E6POOL9HOU5nqw==",
|
||||
"version": "3.4.13",
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.13.tgz",
|
||||
"integrity": "sha512-56crFKLPpzk85WXX1L1c0QzPOuoapWlPVys8eMG8kkRmqdMjWUqK8KpFdE2d7BQA4CEbXwyyHPq6MpFr8H9rcg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@vue/compiler-dom": {
|
||||
"version": "3.3.10",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.3.10.tgz",
|
||||
"integrity": "sha512-NCrqF5fm10GXZIK0GrEAauBqdy+F2LZRt3yNHzrYjpYBuRssQbuPLtSnSNjyR9luHKkWSH8we5LMB3g+4z2HvA==",
|
||||
"version": "3.4.13",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.13.tgz",
|
||||
"integrity": "sha512-XSNbpr5Rs3kCfVAmBqMu/HDwOS+RL6y28ZZjDlnDUuf146pRWt2sQkwhsOYc9uu2lxjjJy2NcyOkK7MBLVEc7w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@vue/compiler-core": "3.3.10",
|
||||
"@vue/shared": "3.3.10"
|
||||
"@vue/compiler-core": "3.4.13",
|
||||
"@vue/shared": "3.4.13"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-dom/node_modules/@vue/shared": {
|
||||
"version": "3.3.10",
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.10.tgz",
|
||||
"integrity": "sha512-2y3Y2J1a3RhFa0WisHvACJR2ncvWiVHcP8t0Inxo+NKz+8RKO4ZV8eZgCxRgQoA6ITfV12L4E6POOL9HOU5nqw==",
|
||||
"version": "3.4.13",
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.13.tgz",
|
||||
"integrity": "sha512-56crFKLPpzk85WXX1L1c0QzPOuoapWlPVys8eMG8kkRmqdMjWUqK8KpFdE2d7BQA4CEbXwyyHPq6MpFr8H9rcg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@vue/compiler-sfc": {
|
||||
"version": "3.3.10",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.3.10.tgz",
|
||||
"integrity": "sha512-xpcTe7Rw7QefOTRFFTlcfzozccvjM40dT45JtrE3onGm/jBLZ0JhpKu3jkV7rbDFLeeagR/5RlJ2Y9SvyS0lAg==",
|
||||
"version": "3.4.13",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.13.tgz",
|
||||
"integrity": "sha512-SkpmQN8xIFBd5onT413DFSDdjxULJf6jmJg/t3w/DZ9I8ZzyNlLIBLO0qFLewVHyHCiAgpPZlWqSRZXYrawk3Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.23.5",
|
||||
"@vue/compiler-core": "3.3.10",
|
||||
"@vue/compiler-dom": "3.3.10",
|
||||
"@vue/compiler-ssr": "3.3.10",
|
||||
"@vue/reactivity-transform": "3.3.10",
|
||||
"@vue/shared": "3.3.10",
|
||||
"@babel/parser": "^7.23.6",
|
||||
"@vue/compiler-core": "3.4.13",
|
||||
"@vue/compiler-dom": "3.4.13",
|
||||
"@vue/compiler-ssr": "3.4.13",
|
||||
"@vue/shared": "3.4.13",
|
||||
"estree-walker": "^2.0.2",
|
||||
"magic-string": "^0.30.5",
|
||||
"postcss": "^8.4.32",
|
||||
@@ -586,25 +576,25 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-sfc/node_modules/@vue/shared": {
|
||||
"version": "3.3.10",
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.10.tgz",
|
||||
"integrity": "sha512-2y3Y2J1a3RhFa0WisHvACJR2ncvWiVHcP8t0Inxo+NKz+8RKO4ZV8eZgCxRgQoA6ITfV12L4E6POOL9HOU5nqw==",
|
||||
"version": "3.4.13",
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.13.tgz",
|
||||
"integrity": "sha512-56crFKLPpzk85WXX1L1c0QzPOuoapWlPVys8eMG8kkRmqdMjWUqK8KpFdE2d7BQA4CEbXwyyHPq6MpFr8H9rcg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@vue/compiler-ssr": {
|
||||
"version": "3.3.10",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.3.10.tgz",
|
||||
"integrity": "sha512-12iM4jA4GEbskwXMmPcskK5wImc2ohKm408+o9iox3tfN9qua8xL0THIZtoe9OJHnXP4eOWZpgCAAThEveNlqQ==",
|
||||
"version": "3.4.13",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.13.tgz",
|
||||
"integrity": "sha512-rwnw9SVBgD6eGKh8UucnwztieQo/R3RQrEGpE0b0cxb2xxvJeLs/fe7DoYlhEfaSyzM/qD5odkK87hl3G3oW+A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@vue/compiler-dom": "3.3.10",
|
||||
"@vue/shared": "3.3.10"
|
||||
"@vue/compiler-dom": "3.4.13",
|
||||
"@vue/shared": "3.4.13"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-ssr/node_modules/@vue/shared": {
|
||||
"version": "3.3.10",
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.10.tgz",
|
||||
"integrity": "sha512-2y3Y2J1a3RhFa0WisHvACJR2ncvWiVHcP8t0Inxo+NKz+8RKO4ZV8eZgCxRgQoA6ITfV12L4E6POOL9HOU5nqw==",
|
||||
"version": "3.4.13",
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.13.tgz",
|
||||
"integrity": "sha512-56crFKLPpzk85WXX1L1c0QzPOuoapWlPVys8eMG8kkRmqdMjWUqK8KpFdE2d7BQA4CEbXwyyHPq6MpFr8H9rcg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@vue/reactivity": {
|
||||
@@ -615,84 +605,65 @@
|
||||
"@vue/shared": "3.1.5"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/reactivity-transform": {
|
||||
"version": "3.3.10",
|
||||
"resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.3.10.tgz",
|
||||
"integrity": "sha512-0xBdk+CKHWT+Gev8oZ63Tc0qFfj935YZx+UAynlutnrDZ4diFCVFMWixn65HzjE3S1iJppWOo6Tt1OzASH7VEg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.23.5",
|
||||
"@vue/compiler-core": "3.3.10",
|
||||
"@vue/shared": "3.3.10",
|
||||
"estree-walker": "^2.0.2",
|
||||
"magic-string": "^0.30.5"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/reactivity-transform/node_modules/@vue/shared": {
|
||||
"version": "3.3.10",
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.10.tgz",
|
||||
"integrity": "sha512-2y3Y2J1a3RhFa0WisHvACJR2ncvWiVHcP8t0Inxo+NKz+8RKO4ZV8eZgCxRgQoA6ITfV12L4E6POOL9HOU5nqw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@vue/runtime-core": {
|
||||
"version": "3.3.10",
|
||||
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.3.10.tgz",
|
||||
"integrity": "sha512-DZ0v31oTN4YHX9JEU5VW1LoIVgFovWgIVb30bWn9DG9a7oA415idcwsRNNajqTx8HQJyOaWfRKoyuP2P2TYIag==",
|
||||
"version": "3.4.13",
|
||||
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.13.tgz",
|
||||
"integrity": "sha512-Ov4d4At7z3goxqzSqQxdfVYEcN5HY4dM1uDYL6Hu/Es9Za9BEN602zyjWhhi2+BEki5F9NizRSvn02k/tqNWlg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@vue/reactivity": "3.3.10",
|
||||
"@vue/shared": "3.3.10"
|
||||
"@vue/reactivity": "3.4.13",
|
||||
"@vue/shared": "3.4.13"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/runtime-core/node_modules/@vue/reactivity": {
|
||||
"version": "3.3.10",
|
||||
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.3.10.tgz",
|
||||
"integrity": "sha512-H5Z7rOY/JLO+e5a6/FEXaQ1TMuOvY4LDVgT+/+HKubEAgs9qeeZ+NhADSeEtrNQeiKLDuzeKc8v0CUFpB6Pqgw==",
|
||||
"version": "3.4.13",
|
||||
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.13.tgz",
|
||||
"integrity": "sha512-/ZdUOrGKkGVONzVJkfDqNcn2fLMvaa5VlYx2KwTbnRbX06YZ4GJE0PVTmWzIxtBYdpSTLLXgw3pDggO+96KXzg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@vue/shared": "3.3.10"
|
||||
"@vue/shared": "3.4.13"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/runtime-core/node_modules/@vue/shared": {
|
||||
"version": "3.3.10",
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.10.tgz",
|
||||
"integrity": "sha512-2y3Y2J1a3RhFa0WisHvACJR2ncvWiVHcP8t0Inxo+NKz+8RKO4ZV8eZgCxRgQoA6ITfV12L4E6POOL9HOU5nqw==",
|
||||
"version": "3.4.13",
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.13.tgz",
|
||||
"integrity": "sha512-56crFKLPpzk85WXX1L1c0QzPOuoapWlPVys8eMG8kkRmqdMjWUqK8KpFdE2d7BQA4CEbXwyyHPq6MpFr8H9rcg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@vue/runtime-dom": {
|
||||
"version": "3.3.10",
|
||||
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.3.10.tgz",
|
||||
"integrity": "sha512-c/jKb3ny05KJcYk0j1m7Wbhrxq7mZYr06GhKykDMNRRR9S+/dGT8KpHuNQjv3/8U4JshfkAk6TpecPD3B21Ijw==",
|
||||
"version": "3.4.13",
|
||||
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.13.tgz",
|
||||
"integrity": "sha512-ynde9p16eEV3u1VCxUre2e0nKzD0l3NzH0r599+bXeLT1Yhac8Atcot3iL9XNqwolxYCI89KBII+2MSVzfrz6w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@vue/runtime-core": "3.3.10",
|
||||
"@vue/shared": "3.3.10",
|
||||
"csstype": "^3.1.2"
|
||||
"@vue/runtime-core": "3.4.13",
|
||||
"@vue/shared": "3.4.13",
|
||||
"csstype": "^3.1.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/runtime-dom/node_modules/@vue/shared": {
|
||||
"version": "3.3.10",
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.10.tgz",
|
||||
"integrity": "sha512-2y3Y2J1a3RhFa0WisHvACJR2ncvWiVHcP8t0Inxo+NKz+8RKO4ZV8eZgCxRgQoA6ITfV12L4E6POOL9HOU5nqw==",
|
||||
"version": "3.4.13",
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.13.tgz",
|
||||
"integrity": "sha512-56crFKLPpzk85WXX1L1c0QzPOuoapWlPVys8eMG8kkRmqdMjWUqK8KpFdE2d7BQA4CEbXwyyHPq6MpFr8H9rcg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@vue/server-renderer": {
|
||||
"version": "3.3.10",
|
||||
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.3.10.tgz",
|
||||
"integrity": "sha512-0i6ww3sBV3SKlF3YTjSVqKQ74xialMbjVYGy7cOTi7Imd8ediE7t72SK3qnvhrTAhOvlQhq6Bk6nFPdXxe0sAg==",
|
||||
"version": "3.4.13",
|
||||
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.13.tgz",
|
||||
"integrity": "sha512-hkw+UQyDZZtSn1q30nObMfc8beVEQv2pG08nghigxGw+iOWodR+tWSuJak0mzWAHlP/xt/qLc//dG6igfgvGEA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@vue/compiler-ssr": "3.3.10",
|
||||
"@vue/shared": "3.3.10"
|
||||
"@vue/compiler-ssr": "3.4.13",
|
||||
"@vue/shared": "3.4.13"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": "3.3.10"
|
||||
"vue": "3.4.13"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/server-renderer/node_modules/@vue/shared": {
|
||||
"version": "3.3.10",
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.10.tgz",
|
||||
"integrity": "sha512-2y3Y2J1a3RhFa0WisHvACJR2ncvWiVHcP8t0Inxo+NKz+8RKO4ZV8eZgCxRgQoA6ITfV12L4E6POOL9HOU5nqw==",
|
||||
"version": "3.4.13",
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.13.tgz",
|
||||
"integrity": "sha512-56crFKLPpzk85WXX1L1c0QzPOuoapWlPVys8eMG8kkRmqdMjWUqK8KpFdE2d7BQA4CEbXwyyHPq6MpFr8H9rcg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@vue/shared": {
|
||||
@@ -774,12 +745,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.6.2",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz",
|
||||
"integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==",
|
||||
"version": "1.6.5",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.5.tgz",
|
||||
"integrity": "sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.0",
|
||||
"follow-redirects": "^1.15.4",
|
||||
"form-data": "^4.0.0",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
@@ -968,9 +939,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/csstype": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
|
||||
"integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==",
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
||||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/culori": {
|
||||
@@ -1048,6 +1019,18 @@
|
||||
"integrity": "sha512-UdREXMXzLkREF4jA8t89FQjA8WHI6ssP38PMY4/4KhXFQbtImnghh4GkCgrtiZwLKUKVD2iTVXvDVQjfomEQuA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/entities": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
|
||||
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.18.20",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz",
|
||||
@@ -1150,18 +1133,10 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/focus-trap": {
|
||||
"version": "6.9.4",
|
||||
"resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-6.9.4.tgz",
|
||||
"integrity": "sha512-v2NTsZe2FF59Y+sDykKY+XjqZ0cPfhq/hikWVL88BqLivnNiEffAsac6rP6H45ff9wG9LL5ToiDqrLEP9GX9mw==",
|
||||
"dependencies": {
|
||||
"tabbable": "^5.3.3"
|
||||
}
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.15.2",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
|
||||
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
|
||||
"version": "1.15.5",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz",
|
||||
"integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -1623,9 +1598,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.4.32",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz",
|
||||
"integrity": "sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==",
|
||||
"version": "8.4.33",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz",
|
||||
"integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
@@ -1945,15 +1920,10 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/tabbable": {
|
||||
"version": "5.3.3",
|
||||
"resolved": "https://registry.npmjs.org/tabbable/-/tabbable-5.3.3.tgz",
|
||||
"integrity": "sha512-QD9qKY3StfbZqWOPLp0++pOrAVb/HbUi5xCc8cUo4XjP19808oaMiDzn0leBY5mCespIBM0CIZePzZjgzR83kA=="
|
||||
},
|
||||
"node_modules/tailwindcss": {
|
||||
"version": "3.3.6",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.6.tgz",
|
||||
"integrity": "sha512-AKjF7qbbLvLaPieoKeTjG1+FyNZT6KaJMJPFeQyLfIp7l82ggH1fbHJSsYIvnbTFQOlkh+gBYpyby5GT1LIdLw==",
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.1.tgz",
|
||||
"integrity": "sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==",
|
||||
"dependencies": {
|
||||
"@alloc/quick-lru": "^5.2.0",
|
||||
"arg": "^5.0.2",
|
||||
@@ -2136,16 +2106,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vue": {
|
||||
"version": "3.3.10",
|
||||
"resolved": "https://registry.npmjs.org/vue/-/vue-3.3.10.tgz",
|
||||
"integrity": "sha512-zg6SIXZdTBwiqCw/1p+m04VyHjLfwtjwz8N57sPaBhEex31ND0RYECVOC1YrRwMRmxFf5T1dabl6SGUbMKKuVw==",
|
||||
"version": "3.4.13",
|
||||
"resolved": "https://registry.npmjs.org/vue/-/vue-3.4.13.tgz",
|
||||
"integrity": "sha512-FE3UZ0p+oUZTwz+SzlH/hDFg+XsVRFvwmx0LXjdD1pRK/cO4fu5v6ltAZji4za4IBih3dV78elUK3di8v3pWIg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@vue/compiler-dom": "3.3.10",
|
||||
"@vue/compiler-sfc": "3.3.10",
|
||||
"@vue/runtime-dom": "3.3.10",
|
||||
"@vue/server-renderer": "3.3.10",
|
||||
"@vue/shared": "3.3.10"
|
||||
"@vue/compiler-dom": "3.4.13",
|
||||
"@vue/compiler-sfc": "3.4.13",
|
||||
"@vue/runtime-dom": "3.4.13",
|
||||
"@vue/server-renderer": "3.4.13",
|
||||
"@vue/shared": "3.4.13"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "*"
|
||||
@@ -2157,9 +2127,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vue/node_modules/@vue/shared": {
|
||||
"version": "3.3.10",
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.10.tgz",
|
||||
"integrity": "sha512-2y3Y2J1a3RhFa0WisHvACJR2ncvWiVHcP8t0Inxo+NKz+8RKO4ZV8eZgCxRgQoA6ITfV12L4E6POOL9HOU5nqw==",
|
||||
"version": "3.4.13",
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.13.tgz",
|
||||
"integrity": "sha512-56crFKLPpzk85WXX1L1c0QzPOuoapWlPVys8eMG8kkRmqdMjWUqK8KpFdE2d7BQA4CEbXwyyHPq6MpFr8H9rcg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/wrappy": {
|
||||
|
||||
@@ -8,17 +8,16 @@
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "4.5.1",
|
||||
"autoprefixer": "10.4.16",
|
||||
"axios": "1.6.2",
|
||||
"axios": "1.6.5",
|
||||
"laravel-echo": "1.15.3",
|
||||
"laravel-vite-plugin": "0.8.1",
|
||||
"postcss": "8.4.32",
|
||||
"postcss": "8.4.33",
|
||||
"pusher-js": "8.4.0-rc2",
|
||||
"tailwindcss": "3.3.6",
|
||||
"tailwindcss": "3.4.1",
|
||||
"vite": "4.5.1",
|
||||
"vue": "3.3.10"
|
||||
"vue": "3.4.13"
|
||||
},
|
||||
"dependencies": {
|
||||
"@alpinejs/focus": "^3.13.3",
|
||||
"@tailwindcss/typography": "0.5.10",
|
||||
"alpinejs": "3.13.3",
|
||||
"daisyui": "4.4.19",
|
||||
|
||||
@@ -80,7 +80,7 @@ a {
|
||||
}
|
||||
|
||||
.description {
|
||||
@apply pt-2 text-xs font-bold text-neutral-500 group-hover:text-white;
|
||||
@apply text-xs font-bold text-neutral-500 group-hover:text-white;
|
||||
}
|
||||
|
||||
.lds-heart {
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
<x-layout>
|
||||
<h1>Command Center</h1>
|
||||
<div class="subtitle">Execute commands on your servers without leaving the browser.</div>
|
||||
@if ($servers->count() > 0)
|
||||
<livewire:run-command :servers="$servers" />
|
||||
@else
|
||||
<div>
|
||||
<div>No servers found. Without a server, you won't be able to do much.</div>
|
||||
<x-use-magic-bar link="/server/new" />
|
||||
</div>
|
||||
@endif
|
||||
</x-layout>
|
||||
@@ -56,6 +56,8 @@
|
||||
Please make sure you have the correct public key in your ~/.ssh/authorized_keys file for user
|
||||
'root' or skip the boarding process and add a new private key manually to Coolify and to the
|
||||
server.
|
||||
<br />
|
||||
Check this <a target="_blank" class="underline" href="https://coolify.io/docs/configuration#openssh-server">documentation</a> for further help.
|
||||
<x-forms.input readonly id="serverPublicKey"></x-forms.input>
|
||||
<x-forms.button class="box" wire:target="setServerType('localhost')"
|
||||
wire:click="setServerType('localhost')">Check again
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
@if ($database->started_at)
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input label="Initial Username" id="database.postgres_username" placeholder="If empty: postgres"
|
||||
<x-forms.input label="Initial Username" id="database.postgres_user" placeholder="If empty: postgres"
|
||||
readonly helper="You can only change this in the database." />
|
||||
<x-forms.input label="Initial Password" id="database.postgres_password" type="password" required
|
||||
readonly helper="You can only change this in the database." />
|
||||
|
||||
@@ -202,10 +202,7 @@
|
||||
<li class="step step-secondary">Select a Server</li>
|
||||
<li class="step">Select a Destination</li>
|
||||
</ul>
|
||||
@if ($isDatabase)
|
||||
<div class="text-center">Swarm clusters are excluded from this type of resource at the moment. It will
|
||||
be activated soon. Stay tuned.</div>
|
||||
@endif
|
||||
|
||||
{{-- @if ($isDatabase)
|
||||
<div class="flex items-center justify-center pt-4">
|
||||
<x-forms.checkbox instantSave wire:model="includeSwarm"
|
||||
@@ -235,6 +232,10 @@
|
||||
</div>
|
||||
@endforelse
|
||||
</div>
|
||||
@if ($isDatabase)
|
||||
<div class="text-center">Swarm clusters are excluded from this type of resource at the moment. It will
|
||||
be activated soon. Stay tuned.</div>
|
||||
@endif
|
||||
@endif
|
||||
@if ($current_step === 'destinations')
|
||||
<ul class="pb-10 steps">
|
||||
@@ -267,7 +268,7 @@
|
||||
</div>
|
||||
@endforeach
|
||||
@endif
|
||||
<a href="{{ route('destination.new', ['server_id' => $server_id]) }}"
|
||||
<a href="{{ route('destination.new', ['server_id' => $server_id]) }}"
|
||||
class="items-center justify-center pb-10 text-center box-without-bg group bg-coollabs hover:bg-coollabs-100">
|
||||
<div class="flex flex-col mx-6 ">
|
||||
<div class="font-bold text-white">
|
||||
|
||||
@@ -44,54 +44,216 @@
|
||||
<a href="{{ route('project.resource.create', ['project_uuid' => request()->route('project_uuid'), 'environment_name' => request()->route('environment_name')]) }} "
|
||||
class="items-center justify-center box">+ Add New Resource</a>
|
||||
@endif
|
||||
<div class="grid gap-2 lg:grid-cols-2">
|
||||
@foreach ($environment->applications->sortBy('name') as $application)
|
||||
<a class="relative box group"
|
||||
href="{{ route('project.application.configuration', [$project->uuid, $environment->name, $application->uuid]) }}">
|
||||
<div class="flex flex-col mx-6">
|
||||
<div class="font-bold text-white">{{ $application->name }}</div>
|
||||
<div class="description">{{ $application->description }}</div>
|
||||
</div>
|
||||
@if (Str::of(data_get($application, 'status'))->startsWith('running'))
|
||||
<div class="absolute bg-success -top-1 -left-1 badge badge-xs"></div>
|
||||
@elseif (Str::of(data_get($application, 'status'))->startsWith('exited'))
|
||||
<div class="absolute bg-error -top-1 -left-1 badge badge-xs"></div>
|
||||
@elseif (Str::of(data_get($application, 'status'))->startsWith('restarting'))
|
||||
<div class="absolute bg-warning -top-1 -left-1 badge badge-xs"></div>
|
||||
@endif
|
||||
</a>
|
||||
@endforeach
|
||||
@foreach ($environment->databases()->sortBy('name') as $database)
|
||||
<a class="relative box group"
|
||||
href="{{ route('project.database.configuration', [$project->uuid, $environment->name, $database->uuid]) }}">
|
||||
<div class="flex flex-col mx-6">
|
||||
<div class="font-bold text-white">{{ $database->name }}</div>
|
||||
<div class="description">{{ $database->description }}</div>
|
||||
</div>
|
||||
@if (Str::of(data_get($database, 'status'))->startsWith('running'))
|
||||
<div class="absolute bg-success -top-1 -left-1 badge badge-xs"></div>
|
||||
@elseif (Str::of(data_get($database, 'status'))->startsWith('exited'))
|
||||
<div class="absolute bg-error -top-1 -left-1 badge badge-xs"></div>
|
||||
@elseif (Str::of(data_get($database, 'status'))->startsWith('restaring'))
|
||||
<div class="absolute bg-warning -top-1 -left-1 badge badge-xs"></div>
|
||||
@endif
|
||||
</a>
|
||||
@endforeach
|
||||
@foreach ($environment->services->sortBy('name') as $service)
|
||||
<a class="relative box group"
|
||||
href="{{ route('project.service.configuration', [$project->uuid, $environment->name, $service->uuid]) }}">
|
||||
<div class="flex flex-col mx-6">
|
||||
<div class="font-bold text-white">{{ $service->name }}</div>
|
||||
<div class="description">{{ $service->description }}</div>
|
||||
</div>
|
||||
@if (Str::of(serviceStatus($service))->startsWith('running'))
|
||||
<div class="absolute bg-success -top-1 -left-1 badge badge-xs"></div>
|
||||
@elseif (Str::of(serviceStatus($service))->startsWith('degraded'))
|
||||
<div class="absolute bg-warning -top-1 -left-1 badge badge-xs"></div>
|
||||
@elseif (Str::of(serviceStatus($service))->startsWith('exited'))
|
||||
<div class="absolute bg-error -top-1 -left-1 badge badge-xs"></div>
|
||||
@endif
|
||||
</a>
|
||||
@endforeach
|
||||
<div x-data="searchComponent()">
|
||||
<x-forms.input placeholder="Search for name, fqdn..." class="w-full" x-model="search" />
|
||||
<div class="grid gap-2 pt-4 lg:grid-cols-2">
|
||||
<template x-for="item in filteredApplications" :key="item.id">
|
||||
<a class="relative box group" :href="item.hrefLink">
|
||||
<div class="flex flex-col mx-6">
|
||||
<div class="pb-2 font-bold text-white" x-text="item.name"></div>
|
||||
<div class="description" x-text="item.description"></div>
|
||||
<div class="description" x-text="item.fqdn"></div>
|
||||
</div>
|
||||
<template x-if="item.status.startsWith('running')">
|
||||
<div class="absolute bg-success -top-1 -left-1 badge badge-xs"></div>
|
||||
</template>
|
||||
<template x-if="item.status.startsWith('exited')">
|
||||
<div class="absolute bg-error -top-1 -left-1 badge badge-xs"></div>
|
||||
</template>
|
||||
<template x-if="item.status.startsWith('restarting')">
|
||||
<div class="absolute bg-warning -top-1 -left-1 badge badge-xs"></div>
|
||||
</template>
|
||||
</a>
|
||||
</template>
|
||||
<template x-for="item in filteredPostgresqls" :key="item.id">
|
||||
<a class="relative box group" :href="item.hrefLink">
|
||||
<div class="flex flex-col mx-6">
|
||||
<div class="font-bold text-white" x-text="item.name"></div>
|
||||
<div class="description" x-text="item.description"></div>
|
||||
</div>
|
||||
<template x-if="item.status.startsWith('running')">
|
||||
<div class="absolute bg-success -top-1 -left-1 badge badge-xs"></div>
|
||||
</template>
|
||||
<template x-if="item.status.startsWith('exited')">
|
||||
<div class="absolute bg-error -top-1 -left-1 badge badge-xs"></div>
|
||||
</template>
|
||||
<template x-if="item.status.startsWith('restarting')">
|
||||
<div class="absolute bg-warning -top-1 -left-1 badge badge-xs"></div>
|
||||
</template>
|
||||
</a>
|
||||
</template>
|
||||
<template x-for="item in filteredRedis" :key="item.id">
|
||||
<a class="relative box group" :href="item.hrefLink">
|
||||
<div class="flex flex-col mx-6">
|
||||
<div class="font-bold text-white" x-text="item.name"></div>
|
||||
<div class="description" x-text="item.description"></div>
|
||||
</div>
|
||||
<template x-if="item.status.startsWith('running')">
|
||||
<div class="absolute bg-success -top-1 -left-1 badge badge-xs"></div>
|
||||
</template>
|
||||
<template x-if="item.status.startsWith('exited')">
|
||||
<div class="absolute bg-error -top-1 -left-1 badge badge-xs"></div>
|
||||
</template>
|
||||
<template x-if="item.status.startsWith('restarting')">
|
||||
<div class="absolute bg-warning -top-1 -left-1 badge badge-xs"></div>
|
||||
</template>
|
||||
</a>
|
||||
</template>
|
||||
<template x-for="item in filteredMongodbs" :key="item.id">
|
||||
<a class="relative box group" :href="item.hrefLink">
|
||||
<div class="flex flex-col mx-6">
|
||||
<div class="font-bold text-white" x-text="item.name"></div>
|
||||
<div class="description" x-text="item.description"></div>
|
||||
</div>
|
||||
<template x-if="item.status.startsWith('running')">
|
||||
<div class="absolute bg-success -top-1 -left-1 badge badge-xs"></div>
|
||||
</template>
|
||||
<template x-if="item.status.startsWith('exited')">
|
||||
<div class="absolute bg-error -top-1 -left-1 badge badge-xs"></div>
|
||||
</template>
|
||||
<template x-if="item.status.startsWith('restarting')">
|
||||
<div class="absolute bg-warning -top-1 -left-1 badge badge-xs"></div>
|
||||
</template>
|
||||
</a>
|
||||
</template>
|
||||
<template x-for="item in filteredMysqls" :key="item.id">
|
||||
<a class="relative box group" :href="item.hrefLink">
|
||||
<div class="flex flex-col mx-6">
|
||||
<div class="font-bold text-white" x-text="item.name"></div>
|
||||
<div class="description" x-text="item.description"></div>
|
||||
</div>
|
||||
<template x-if="item.status.startsWith('running')">
|
||||
<div class="absolute bg-success -top-1 -left-1 badge badge-xs"></div>
|
||||
</template>
|
||||
<template x-if="item.status.startsWith('exited')">
|
||||
<div class="absolute bg-error -top-1 -left-1 badge badge-xs"></div>
|
||||
</template>
|
||||
<template x-if="item.status.startsWith('restarting')">
|
||||
<div class="absolute bg-warning -top-1 -left-1 badge badge-xs"></div>
|
||||
</template>
|
||||
</a>
|
||||
</template>
|
||||
<template x-for="item in filteredMariadbs" :key="item.id">
|
||||
<a class="relative box group" :href="item.hrefLink">
|
||||
<div class="flex flex-col mx-6">
|
||||
<div class="font-bold text-white" x-text="item.name"></div>
|
||||
<div class="description" x-text="item.description"></div>
|
||||
</div>
|
||||
<template x-if="item.status.startsWith('running')">
|
||||
<div class="absolute bg-success -top-1 -left-1 badge badge-xs"></div>
|
||||
</template>
|
||||
<template x-if="item.status.startsWith('exited')">
|
||||
<div class="absolute bg-error -top-1 -left-1 badge badge-xs"></div>
|
||||
</template>
|
||||
<template x-if="item.status.startsWith('restarting')">
|
||||
<div class="absolute bg-warning -top-1 -left-1 badge badge-xs"></div>
|
||||
</template>
|
||||
</a>
|
||||
</template>
|
||||
<template x-for="item in filteredServices" :key="item.id">
|
||||
<a class="relative box group" :href="item.hrefLink">
|
||||
<div class="flex flex-col mx-6">
|
||||
<div class="font-bold text-white" x-text="item.name"></div>
|
||||
<div class="description" x-text="item.description"></div>
|
||||
</div>
|
||||
<template x-if="item.status.startsWith('running')">
|
||||
<div class="absolute bg-success -top-1 -left-1 badge badge-xs"></div>
|
||||
</template>
|
||||
<template x-if="item.status.startsWith('exited')">
|
||||
<div class="absolute bg-error -top-1 -left-1 badge badge-xs"></div>
|
||||
</template>
|
||||
<template x-if="item.status.startsWith('degraded')">
|
||||
<div class="absolute bg-warning -top-1 -left-1 badge badge-xs"></div>
|
||||
</template>
|
||||
</a>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function searchComponent() {
|
||||
return {
|
||||
search: '',
|
||||
applications: @js($applications),
|
||||
postgresqls: @js($postgresqls),
|
||||
redis: @js($redis),
|
||||
mongodbs: @js($mongodbs),
|
||||
mysqls: @js($mysqls),
|
||||
mariadbs: @js($mariadbs),
|
||||
services: @js($services),
|
||||
get filteredApplications() {
|
||||
if (this.search === '') {
|
||||
return this.applications;
|
||||
}
|
||||
this.applications = Object.values(this.applications);
|
||||
return this.applications.filter(item => {
|
||||
return item.name.toLowerCase().includes(this.search.toLowerCase()) ||
|
||||
item.fqdn?.toLowerCase().includes(this.search.toLowerCase()) ||
|
||||
item.description?.toLowerCase().includes(this.search.toLowerCase());
|
||||
});
|
||||
},
|
||||
get filteredPostgresqls() {
|
||||
if (this.search === '') {
|
||||
return this.postgresqls;
|
||||
}
|
||||
this.postgresqls = Object.values(this.postgresqls);
|
||||
return this.postgresqls.filter(item => {
|
||||
return item.name.toLowerCase().includes(this.search.toLowerCase()) ||
|
||||
item.description?.toLowerCase().includes(this.search.toLowerCase());
|
||||
});
|
||||
},
|
||||
get filteredRedis() {
|
||||
if (this.search === '') {
|
||||
return this.redis;
|
||||
}
|
||||
this.redis = Object.values(this.redis);
|
||||
return this.redis.filter(item => {
|
||||
return item.name.toLowerCase().includes(this.search.toLowerCase()) ||
|
||||
item.description?.toLowerCase().includes(this.search.toLowerCase());
|
||||
});
|
||||
},
|
||||
get filteredMongodbs() {
|
||||
if (this.search === '') {
|
||||
return this.mongodbs;
|
||||
}
|
||||
this.mongodbs = Object.values(this.mongodbs);
|
||||
return this.mongodbs.filter(item => {
|
||||
return item.name.toLowerCase().includes(this.search.toLowerCase()) ||
|
||||
item.description?.toLowerCase().includes(this.search.toLowerCase());
|
||||
});
|
||||
},
|
||||
get filteredMysqls() {
|
||||
if (this.search === '') {
|
||||
return this.mysqls;
|
||||
}
|
||||
this.mysqls = Object.values(this.mysqls);
|
||||
return this.mysqls.filter(item => {
|
||||
return item.name.toLowerCase().includes(this.search.toLowerCase()) ||
|
||||
item.description?.toLowerCase().includes(this.search.toLowerCase());
|
||||
});
|
||||
},
|
||||
get filteredMariadbs() {
|
||||
if (this.search === '') {
|
||||
return this.mariadbs;
|
||||
}
|
||||
this.mariadbs = Object.values(this.mariadbs);
|
||||
return this.mariadbs.filter(item => {
|
||||
return item.name.toLowerCase().includes(this.search.toLowerCase()) ||
|
||||
item.description?.toLowerCase().includes(this.search.toLowerCase());
|
||||
});
|
||||
},
|
||||
get filteredServices() {
|
||||
if (this.search === '') {
|
||||
return this.services;
|
||||
}
|
||||
this.services = Object.values(this.services);
|
||||
return this.services.filter(item => {
|
||||
return item.name.toLowerCase().includes(this.search.toLowerCase()) ||
|
||||
item.description?.toLowerCase().includes(this.search.toLowerCase());
|
||||
});
|
||||
},
|
||||
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -68,8 +68,7 @@
|
||||
<div class="text-xs">{{ $application->status }}</div>
|
||||
</div>
|
||||
<div class="flex items-center px-4">
|
||||
<a
|
||||
class="flex flex-col flex-1 group-hover:text-white hover:no-underline"
|
||||
<a class="flex flex-col flex-1 group-hover:text-white hover:no-underline"
|
||||
href="{{ route('project.service.index', [...$parameters, 'service_name' => $application->name]) }}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon hover:text-warning"
|
||||
viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none"
|
||||
@@ -115,8 +114,7 @@
|
||||
<div class="text-xs">{{ $database->status }}</div>
|
||||
</div>
|
||||
<div class="flex items-center px-4">
|
||||
<a
|
||||
class="flex flex-col flex-1 group-hover:text-white hover:no-underline"
|
||||
<a class="flex flex-col flex-1 group-hover:text-white hover:no-underline"
|
||||
href="{{ route('project.service.index', [...$parameters, 'service_name' => $database->name]) }}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon hover:text-warning"
|
||||
viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none"
|
||||
@@ -157,9 +155,7 @@
|
||||
<livewire:project.shared.execute-container-command :resource="$service" />
|
||||
</div>
|
||||
<div x-cloak x-show="activeTab === 'environment-variables'">
|
||||
<div x-cloak x-show="activeTab === 'environment-variables'">
|
||||
<livewire:project.shared.environment-variable.all :resource="$service" />
|
||||
</div>
|
||||
<livewire:project.shared.environment-variable.all :resource="$service" />
|
||||
</div>
|
||||
<div x-cloak x-show="activeTab === 'danger'">
|
||||
<livewire:project.shared.danger :resource="$service" />
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<livewire:project.service.navbar :service="$service" :parameters="$parameters" :query="$query" />
|
||||
<div class="flex h-full pt-6">
|
||||
<div class="flex flex-col gap-4 min-w-fit">
|
||||
<a class="{{ request()->routeIs('project.service.configuration') ? 'text-white' : '' }}"
|
||||
<a class="{{ request()->routeIs('project.service.configuration') ? 'text-white' : '' }}"
|
||||
href="{{ route('project.service.configuration', [...$parameters, 'service_name' => null]) }}">
|
||||
<button><- Back</button>
|
||||
</a>
|
||||
@@ -13,19 +13,10 @@
|
||||
@click.prevent="activeTab = 'storages'; window.location.hash = 'storages'; if(window.location.search) window.location.search = ''"
|
||||
href="#">Storages
|
||||
</a>
|
||||
<a :class="activeTab === 'environment-variables' && 'text-white'"
|
||||
@click.prevent="activeTab = 'environment-variables'; window.location.hash = 'environment-variables'"
|
||||
href="#">Environment
|
||||
Variables</a>
|
||||
<a :class="activeTab === 'scheduled-tasks' && 'text-white'"
|
||||
@click.prevent="activeTab = 'scheduled-tasks'; window.location.hash = 'scheduled-tasks'"
|
||||
href="#">Scheduled Tasks
|
||||
</a>
|
||||
<a :class="activeTab === 'danger' && 'text-white'"
|
||||
@click.prevent="activeTab = 'danger';
|
||||
window.location.hash = 'danger'"
|
||||
href="#">Danger Zone
|
||||
|
||||
@if (
|
||||
$serviceDatabase?->databaseType() === 'standalone-mysql' ||
|
||||
$serviceDatabase?->databaseType() === 'standalone-postgresql' ||
|
||||
@@ -69,14 +60,10 @@
|
||||
<livewire:project.database.create-scheduled-backup :database="$serviceDatabase" :s3s="$s3s" />
|
||||
<livewire:project.database.scheduled-backups :database="$serviceDatabase" />
|
||||
</div>
|
||||
</div>
|
||||
@endisset
|
||||
<div x-cloak x-show="activeTab === 'scheduled-tasks'">
|
||||
<livewire:project.shared.scheduled-task.all :resource="$service" />
|
||||
</div>
|
||||
<div x-cloak x-show="activeTab === 'danger'">
|
||||
<livewire:project.shared.danger :resource="$service" />
|
||||
</div>
|
||||
@endisset
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -48,5 +48,10 @@
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
@if (
|
||||
$resource->persistentStorages()->get()->count() == 0 &&
|
||||
$resource->fileStorages()->get()->count() == 0)
|
||||
<div class="pt-4">No storages found.</div>
|
||||
@endif
|
||||
@endif
|
||||
</div>
|
||||
|
||||
@@ -7,9 +7,15 @@
|
||||
<div class="">Limit your container resources by CPU & memory.</div>
|
||||
<h3 class="pt-4">Limit CPUs</h3>
|
||||
<div class="flex gap-2">
|
||||
<x-forms.input placeholder="1.5" label="Number of CPUs" id="resource.limits_cpus" />
|
||||
<x-forms.input placeholder="0-2" label="CPU sets to use" id="resource.limits_cpuset" />
|
||||
<x-forms.input placeholder="1024" label="CPU Weight" id="resource.limits_cpu_shares" />
|
||||
<x-forms.input placeholder="1.5"
|
||||
helper="0 means use all CPUs. Floating point number, like 0.002 or 1.5. More info <a target='_blank' href='https://docs.docker.com/engine/reference/run/#cpu-share-constraint'>here</a>."
|
||||
label="Number of CPUs" id="resource.limits_cpus" />
|
||||
<x-forms.input placeholder="0-2"
|
||||
helper="Empty means, use all CPU sets. 0-2 will use CPU 0, CPU 1 and CPU 2. More info <a target='_blank' href='https://docs.docker.com/engine/reference/run/#cpu-share-constraint'>here</a>."
|
||||
label="CPU sets to use" id="resource.limits_cpuset" />
|
||||
<x-forms.input placeholder="1024"
|
||||
helper="More info <a target='_blank' href='https://docs.docker.com/engine/reference/run/#cpu-share-constraint'>here</a>."
|
||||
label="CPU Weight" id="resource.limits_cpu_shares" />
|
||||
</div>
|
||||
<h3 class="pt-4">Limit Memory</h3>
|
||||
<div class="flex gap-2">
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
<div class="w-64">
|
||||
@if (!$server->isLocalhost())
|
||||
<x-forms.checkbox instantSave
|
||||
helper="If you are using Cloudflare Tunnels, enable this. It will proxy all ssh requests to your server through Cloudflare.<span class='text-warning'>Coolify does not install/setup Cloudflare (cloudflared) on your server.</span>"
|
||||
helper="If you are using Cloudflare Tunnels, enable this. It will proxy all ssh requests to your server through Cloudflare.<br><span class='text-warning'>Coolify does not install/setup Cloudflare (cloudflared) on your server.</span>"
|
||||
id="server.settings.is_cloudflare_tunnel" label="Cloudflare Tunnel" />
|
||||
@if ($server->isSwarm())
|
||||
<div class="pt-6"> Swarm support is in alpha version. </div>
|
||||
|
||||
@@ -9,8 +9,10 @@
|
||||
<div>General configuration for your Coolify instance.</div>
|
||||
|
||||
<div class="flex flex-col gap-2 pt-4">
|
||||
<div class="flex gap-2 w-96">
|
||||
<div class="flex items-end gap-2">
|
||||
<x-forms.input id="settings.fqdn" label="Instance's Domain" placeholder="https://coolify.io" />
|
||||
<x-forms.input id="settings.custom_dns_servers" label="DNS Servers" helper="DNS servers for validation FQDNS againts. A comma separated list of DNS servers." placeholder="1.1.1.1,8.8.8.8" />
|
||||
<x-forms.checkbox instantSave id="is_dns_validation_enabled" label="Validate DNS settings?" />
|
||||
</div>
|
||||
|
||||
{{-- <div class="flex gap-2 ">
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
<x-layout>
|
||||
<h1>Profile</h1>
|
||||
<div class="subtitle ">Your user profile settings.</div>
|
||||
<livewire:profile.form :request="$request" />
|
||||
<h2 class="py-4">Subscription</h2>
|
||||
<a href="{{ route('team.index') }}">Check in Team Settings</a>
|
||||
<h2 class="py-4">Two-factor Authentication</h2>
|
||||
@if (session('status') == 'two-factor-authentication-enabled')
|
||||
<div class="mb-4 font-medium">
|
||||
Please finish configuring two factor authentication below. Read the QR code or enter the secret key
|
||||
manually.
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<form action="/user/confirmed-two-factor-authentication" method="POST" class="flex items-end gap-2">
|
||||
@csrf
|
||||
<x-forms.input type="number" id="code" label="One-time code" required />
|
||||
<x-forms.button type="submit">Validate 2FA</x-forms.button>
|
||||
</form>
|
||||
<div>
|
||||
<div>{!! $request->user()->twoFactorQrCodeSvg() !!}</div>
|
||||
<div x-data="{ showCode: false }" class="py-2">
|
||||
<template x-if="showCode">
|
||||
<div class="py-2 ">{!! decrypt($request->user()->two_factor_secret) !!}</div>
|
||||
</template>
|
||||
<x-forms.button x-on:click="showCode = !showCode">Show secret key to manually
|
||||
enter</x-forms.button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@elseif(session('status') == 'two-factor-authentication-confirmed')
|
||||
<div class="mb-4 ">
|
||||
Two factor authentication confirmed and enabled successfully.
|
||||
</div>
|
||||
<div>
|
||||
<div class="pb-6 ">Here are the recovery codes for your account. Please store them in a secure
|
||||
location.
|
||||
</div>
|
||||
<div class="text-white">
|
||||
@foreach ($request->user()->recoveryCodes() as $code)
|
||||
<div>{{ $code }}</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
@if ($request->user()->two_factor_confirmed_at)
|
||||
<div class="pb-4 "> Two factor authentication is <span class="text-helper">enabled</span>.</div>
|
||||
<div class="flex gap-2">
|
||||
<form action="/user/two-factor-authentication" method="POST">
|
||||
@csrf
|
||||
@method ('DELETE')
|
||||
<x-forms.button type="submit">Disable</x-forms.button>
|
||||
</form>
|
||||
<form action="/user/two-factor-recovery-codes" method="POST">
|
||||
@csrf
|
||||
<x-forms.button type="submit">Regenerate Recovery Codes</x-forms.button>
|
||||
</form>
|
||||
</div>
|
||||
@if (session('status') == 'recovery-codes-generated')
|
||||
<div>
|
||||
<div class="py-6 ">Here are the recovery codes for your account. Please store them in a
|
||||
secure
|
||||
location.
|
||||
</div>
|
||||
<div class="text-white">
|
||||
@foreach ($request->user()->recoveryCodes() as $code)
|
||||
<div>{{ $code }}</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
@else
|
||||
<form action="/user/two-factor-authentication" method="POST">
|
||||
@csrf
|
||||
<x-forms.button type="submit">Configure 2FA</x-forms.button>
|
||||
</form>
|
||||
@endif
|
||||
@endif
|
||||
@if (session()->has('errors'))
|
||||
<div class="text-error">
|
||||
Something went wrong. Please try again.
|
||||
</div>
|
||||
@endif
|
||||
</x-layout>
|
||||
@@ -163,7 +163,7 @@ Route::post('/source/gitlab/events/manual', function () {
|
||||
}
|
||||
}
|
||||
if ($x_gitlab_event === 'merge_request') {
|
||||
if ($action === 'opened' || $action === 'synchronize' || $action === 'reopened' || $action === 'reopen' || $action === 'update') {
|
||||
if ($action === 'open' || $action === 'opened' || $action === 'synchronize' || $action === 'reopened' || $action === 'reopen' || $action === 'update') {
|
||||
if ($application->isPRDeployable()) {
|
||||
$deployment_uuid = new Cuid2(7);
|
||||
$found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
|
||||
@@ -197,7 +197,7 @@ Route::post('/source/gitlab/events/manual', function () {
|
||||
]);
|
||||
ray('Preview deployments disabled for ' . $application->name);
|
||||
}
|
||||
} else if ($action === 'closed') {
|
||||
} else if ($action === 'closed' || $action === 'close') {
|
||||
$found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
|
||||
if ($found) {
|
||||
$found->delete();
|
||||
|
||||
@@ -6,7 +6,7 @@ set -e # Exit immediately if a command exits with a non-zero status
|
||||
#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
|
||||
|
||||
VERSION="1.1.0"
|
||||
VERSION="1.2.0"
|
||||
DOCKER_VERSION="24.0"
|
||||
|
||||
CDN="https://cdn.coollabs.io/coolify"
|
||||
@@ -65,6 +65,44 @@ sles | opensuse-leap | opensuse-tumbleweed)
|
||||
;;
|
||||
esac
|
||||
|
||||
# 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 and running."
|
||||
SSH_DETECTED=true
|
||||
fi
|
||||
elif [ -x "$(command -v service)" ]; then
|
||||
if service sshd status >/dev/null 2>&1; then
|
||||
echo "OpenSSH server is installed and running."
|
||||
SSH_DETECTED=true
|
||||
fi
|
||||
fi
|
||||
if [ "$SSH_DETECTED" = "false" ]; then
|
||||
echo "###############################################################################"
|
||||
echo "WARNING: Could not detect if OpenSSH server is installed and running - this does not mean that it is not installed, just that we could not detect it."
|
||||
echo -e "Please make sure it is set, otherwise Coolify cannot connect to the host system. \n"
|
||||
echo "###############################################################################"
|
||||
fi
|
||||
|
||||
# Detect SSH PermitRootLogin
|
||||
SSH_PERMIT_ROOT_LOGIN=false
|
||||
SSH_PERMIT_ROOT_LOGIN_CONFIG=$(grep "^PermitRootLogin" /etc/ssh/sshd_config | awk '{print $2}') || SSH_PERMIT_ROOT_LOGIN_CONFIG="N/A (commented out or not found at all)"
|
||||
if [ "$SSH_PERMIT_ROOT_LOGIN_CONFIG" = "prohibit-password" ] || [ "$SSH_PERMIT_ROOT_LOGIN_CONFIG" = "yes" ] || [ "$SSH_PERMIT_ROOT_LOGIN_CONFIG" = "without-password" ]; then
|
||||
echo "PermitRootLogin is enabled."
|
||||
SSH_PERMIT_ROOT_LOGIN=true
|
||||
fi
|
||||
|
||||
|
||||
if [ "$SSH_PERMIT_ROOT_LOGIN" != "true" ]; then
|
||||
echo "###############################################################################"
|
||||
echo "WARNING: PermitRootLogin is not enabled in /etc/ssh/sshd_config."
|
||||
echo -e "It is set to $SSH_PERMIT_ROOT_LOGIN_CONFIG. Should be prohibit-password, yes or without-password.\n"
|
||||
echo -e "Please make sure it is set, otherwise Coolify cannot connect to the host system. \n"
|
||||
echo "(Currently we only support root user to login via SSH, this will be changed in the future.)"
|
||||
echo "###############################################################################"
|
||||
fi
|
||||
|
||||
if ! [ -x "$(command -v docker)" ]; then
|
||||
echo "Docker is not installed. Installing Docker."
|
||||
curl https://releases.rancher.com/install-docker/${DOCKER_VERSION}.sh | sh
|
||||
@@ -127,9 +165,8 @@ fi
|
||||
|
||||
echo -e "-------------"
|
||||
|
||||
mkdir -p /data/coolify/ssh/keys
|
||||
mkdir -p /data/coolify/ssh/mux
|
||||
mkdir -p /data/coolify/source
|
||||
mkdir -p /data/coolify/{source,ssh,applications,databases,backups,services,proxy}
|
||||
mkdir -p /data/coolify/ssh/{keys,mux}
|
||||
mkdir -p /data/coolify/proxy/dynamic
|
||||
|
||||
chown -R 9999:root /data/coolify
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"version": "3.12.36"
|
||||
},
|
||||
"v4": {
|
||||
"version": "4.0.0-beta.187"
|
||||
"version": "4.0.0-beta.196"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user