Merge branch 'next' into new-dockerfiles
This commit is contained in:
@@ -13,7 +13,6 @@ class CleanupRedis extends Command
|
|||||||
|
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
echo "Cleanup Redis keys.\n";
|
|
||||||
$prefix = config('database.redis.options.prefix');
|
$prefix = config('database.redis.options.prefix');
|
||||||
|
|
||||||
$keys = Redis::connection()->keys('*:laravel*');
|
$keys = Redis::connection()->keys('*:laravel*');
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ class CleanupStuckedResources extends Command
|
|||||||
|
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
echo "Running cleanup stucked resources.\n";
|
|
||||||
$this->cleanup_stucked_resources();
|
$this->cleanup_stucked_resources();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ class Horizon extends Command
|
|||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
if (config('constants.horizon.is_horizon_enabled')) {
|
if (config('constants.horizon.is_horizon_enabled')) {
|
||||||
$this->info('Horizon is enabled. Starting.');
|
$this->info('[x]: Horizon is enabled. Starting.');
|
||||||
$this->call('horizon');
|
$this->call('horizon');
|
||||||
exit(0);
|
exit(0);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
namespace App\Console\Commands;
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
use App\Actions\Server\StopSentinel;
|
|
||||||
use App\Enums\ActivityTypes;
|
use App\Enums\ActivityTypes;
|
||||||
use App\Enums\ApplicationDeploymentStatus;
|
use App\Enums\ApplicationDeploymentStatus;
|
||||||
|
use App\Jobs\CheckHelperImageJob;
|
||||||
use App\Models\ApplicationDeploymentQueue;
|
use App\Models\ApplicationDeploymentQueue;
|
||||||
use App\Models\Environment;
|
use App\Models\Environment;
|
||||||
use App\Models\ScheduledDatabaseBackup;
|
use App\Models\ScheduledDatabaseBackup;
|
||||||
@@ -12,6 +12,7 @@ use App\Models\Server;
|
|||||||
use App\Models\StandalonePostgresql;
|
use App\Models\StandalonePostgresql;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Facades\Artisan;
|
||||||
use Illuminate\Support\Facades\File;
|
use Illuminate\Support\Facades\File;
|
||||||
use Illuminate\Support\Facades\Http;
|
use Illuminate\Support\Facades\Http;
|
||||||
|
|
||||||
@@ -25,6 +26,8 @@ class Init extends Command
|
|||||||
|
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
|
$this->optimize();
|
||||||
|
|
||||||
if (isCloud() && ! $this->option('force-cloud')) {
|
if (isCloud() && ! $this->option('force-cloud')) {
|
||||||
echo "Skipping init as we are on cloud and --force-cloud option is not set\n";
|
echo "Skipping init as we are on cloud and --force-cloud option is not set\n";
|
||||||
|
|
||||||
@@ -39,7 +42,6 @@ class Init extends Command
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Backward compatibility
|
// Backward compatibility
|
||||||
// $this->disable_metrics();
|
|
||||||
$this->replace_slash_in_environment_name();
|
$this->replace_slash_in_environment_name();
|
||||||
$this->restore_coolify_db_backup();
|
$this->restore_coolify_db_backup();
|
||||||
$this->update_user_emails();
|
$this->update_user_emails();
|
||||||
@@ -53,9 +55,18 @@ class Init extends Command
|
|||||||
} else {
|
} else {
|
||||||
$this->cleanup_in_progress_application_deployments();
|
$this->cleanup_in_progress_application_deployments();
|
||||||
}
|
}
|
||||||
|
echo "[3]: Cleanup Redis keys.\n";
|
||||||
$this->call('cleanup:redis');
|
$this->call('cleanup:redis');
|
||||||
|
|
||||||
|
echo "[4]: Cleanup stucked resources.\n";
|
||||||
$this->call('cleanup:stucked-resources');
|
$this->call('cleanup:stucked-resources');
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->pullHelperImage();
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
if (isCloud()) {
|
if (isCloud()) {
|
||||||
try {
|
try {
|
||||||
$this->pullTemplatesFromCDN();
|
$this->pullTemplatesFromCDN();
|
||||||
@@ -87,6 +98,11 @@ class Init extends Command
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function pullHelperImage()
|
||||||
|
{
|
||||||
|
CheckHelperImageJob::dispatch();
|
||||||
|
}
|
||||||
|
|
||||||
private function pullTemplatesFromCDN()
|
private function pullTemplatesFromCDN()
|
||||||
{
|
{
|
||||||
$response = Http::retry(3, 1000)->get(config('constants.services.official'));
|
$response = Http::retry(3, 1000)->get(config('constants.services.official'));
|
||||||
@@ -95,19 +111,13 @@ class Init extends Command
|
|||||||
File::put(base_path('templates/service-templates.json'), json_encode($services));
|
File::put(base_path('templates/service-templates.json'), json_encode($services));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// private function disable_metrics()
|
|
||||||
// {
|
private function optimize()
|
||||||
// if (version_compare('4.0.0-beta.312', config('version'), '<=')) {
|
{
|
||||||
// foreach ($this->servers as $server) {
|
echo "[1]: Optimizing Laravel (caching config, routes, views).\n";
|
||||||
// if ($server->settings->is_metrics_enabled === true) {
|
Artisan::call('optimize:clear');
|
||||||
// $server->settings->update(['is_metrics_enabled' => false]);
|
Artisan::call('optimize');
|
||||||
// }
|
}
|
||||||
// if ($server->isFunctional()) {
|
|
||||||
// StopSentinel::dispatch($server)->onQueue('high');
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
private function update_user_emails()
|
private function update_user_emails()
|
||||||
{
|
{
|
||||||
@@ -222,15 +232,15 @@ class Init extends Command
|
|||||||
$settings = instanceSettings();
|
$settings = instanceSettings();
|
||||||
$do_not_track = data_get($settings, 'do_not_track');
|
$do_not_track = data_get($settings, 'do_not_track');
|
||||||
if ($do_not_track == true) {
|
if ($do_not_track == true) {
|
||||||
echo "Skipping alive as do_not_track is enabled\n";
|
echo "[2]: Skipping sending live signal as do_not_track is enabled\n";
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
Http::get("https://undead.coolify.io/v4/alive?appId=$id&version=$version");
|
Http::get("https://undead.coolify.io/v4/alive?appId=$id&version=$version");
|
||||||
echo "I am alive!\n";
|
echo "[2]: Sending live signal!\n";
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
echo "Error in alive: {$e->getMessage()}\n";
|
echo "[2]: Error in sending live signal: {$e->getMessage()}\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ class Scheduler extends Command
|
|||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
if (config('constants.horizon.is_scheduler_enabled')) {
|
if (config('constants.horizon.is_scheduler_enabled')) {
|
||||||
$this->info('Scheduler is enabled. Starting.');
|
$this->info('[x]: Scheduler is enabled. Starting.');
|
||||||
$this->call('schedule:work');
|
$this->call('schedule:work');
|
||||||
exit(0);
|
exit(0);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class ServerStorageCheckJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
return isDev() ? 1 : 3;
|
return isDev() ? 1 : 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __construct(public Server $server, public ?int $percentage = null) {}
|
public function __construct(public Server $server, public int|string|null $percentage = null) {}
|
||||||
|
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ class CreateScheduledBackup extends Component
|
|||||||
|
|
||||||
public bool $enabled = true;
|
public bool $enabled = true;
|
||||||
|
|
||||||
#[Validate(['required', 'integer'])]
|
#[Validate(['nullable', 'integer'])]
|
||||||
public int $s3StorageId;
|
public ?int $s3StorageId = null;
|
||||||
|
|
||||||
public Collection $definedS3s;
|
public Collection $definedS3s;
|
||||||
|
|
||||||
@@ -49,6 +49,7 @@ class CreateScheduledBackup extends Component
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$payload = [
|
$payload = [
|
||||||
'enabled' => true,
|
'enabled' => true,
|
||||||
'frequency' => $this->frequency,
|
'frequency' => $this->frequency,
|
||||||
@@ -58,6 +59,7 @@ class CreateScheduledBackup extends Component
|
|||||||
'database_type' => $this->database->getMorphClass(),
|
'database_type' => $this->database->getMorphClass(),
|
||||||
'team_id' => currentTeam()->id,
|
'team_id' => currentTeam()->id,
|
||||||
];
|
];
|
||||||
|
|
||||||
if ($this->database->type() === 'standalone-postgresql') {
|
if ($this->database->type() === 'standalone-postgresql') {
|
||||||
$payload['databases_to_backup'] = $this->database->postgres_db;
|
$payload['databases_to_backup'] = $this->database->postgres_db;
|
||||||
} elseif ($this->database->type() === 'standalone-mysql') {
|
} elseif ($this->database->type() === 'standalone-mysql') {
|
||||||
@@ -72,11 +74,11 @@ class CreateScheduledBackup extends Component
|
|||||||
} else {
|
} else {
|
||||||
$this->dispatch('refreshScheduledBackups');
|
$this->dispatch('refreshScheduledBackups');
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
} finally {
|
} finally {
|
||||||
$this->frequency = '';
|
$this->frequency = '';
|
||||||
$this->saveToS3 = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,9 +91,12 @@ class Select extends Component
|
|||||||
{
|
{
|
||||||
$services = get_service_templates(true);
|
$services = get_service_templates(true);
|
||||||
$services = collect($services)->map(function ($service, $key) {
|
$services = collect($services)->map(function ($service, $key) {
|
||||||
|
$logo = data_get($service, 'logo', 'svgs/coolify.png');
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'name' => str($key)->headline(),
|
'name' => str($key)->headline(),
|
||||||
'logo' => asset(data_get($service, 'logo', 'svgs/coolify.png')),
|
'logo' => asset($logo),
|
||||||
|
'logo_github_url' => 'https://raw.githubusercontent.com/coollabsio/coolify/refs/heads/main/public/a'.$logo,
|
||||||
] + (array) $service;
|
] + (array) $service;
|
||||||
})->all();
|
})->all();
|
||||||
$gitBasedApplications = [
|
$gitBasedApplications = [
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ class Tags extends Component
|
|||||||
$this->validate();
|
$this->validate();
|
||||||
$tags = str($this->newTags)->trim()->explode(' ');
|
$tags = str($this->newTags)->trim()->explode(' ');
|
||||||
foreach ($tags as $tag) {
|
foreach ($tags as $tag) {
|
||||||
|
$tag = strip_tags($tag);
|
||||||
if (strlen($tag) < 2) {
|
if (strlen($tag) < 2) {
|
||||||
$this->dispatch('error', 'Invalid tag.', "Tag <span class='dark:text-warning'>$tag</span> is invalid. Min length is 2.");
|
$this->dispatch('error', 'Invalid tag.', "Tag <span class='dark:text-warning'>$tag</span> is invalid. Min length is 2.");
|
||||||
|
|
||||||
@@ -65,6 +66,7 @@ class Tags extends Component
|
|||||||
public function addTag(string $id, string $name)
|
public function addTag(string $id, string $name)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
$name = strip_tags($name);
|
||||||
if ($this->resource->tags()->where('id', $id)->exists()) {
|
if ($this->resource->tags()->where('id', $id)->exists()) {
|
||||||
$this->dispatch('error', 'Duplicate tags.', "Tag <span class='dark:text-warning'>$name</span> already added.");
|
$this->dispatch('error', 'Duplicate tags.', "Tag <span class='dark:text-warning'>$name</span> already added.");
|
||||||
|
|
||||||
|
|||||||
@@ -6,64 +6,60 @@ use App\Enums\ProxyTypes;
|
|||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use App\Models\Team;
|
use App\Models\Team;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
use Livewire\Attributes\Locked;
|
||||||
|
use Livewire\Attributes\Validate;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class ByIp extends Component
|
class ByIp extends Component
|
||||||
{
|
{
|
||||||
|
#[Locked]
|
||||||
public $private_keys;
|
public $private_keys;
|
||||||
|
|
||||||
|
#[Locked]
|
||||||
public $limit_reached;
|
public $limit_reached;
|
||||||
|
|
||||||
|
#[Validate('nullable|integer', as: 'Private Key')]
|
||||||
public ?int $private_key_id = null;
|
public ?int $private_key_id = null;
|
||||||
|
|
||||||
|
#[Validate('nullable|string', as: 'Private Key Name')]
|
||||||
public $new_private_key_name;
|
public $new_private_key_name;
|
||||||
|
|
||||||
|
#[Validate('nullable|string', as: 'Private Key Description')]
|
||||||
public $new_private_key_description;
|
public $new_private_key_description;
|
||||||
|
|
||||||
|
#[Validate('nullable|string', as: 'Private Key Value')]
|
||||||
public $new_private_key_value;
|
public $new_private_key_value;
|
||||||
|
|
||||||
|
#[Validate('required|string', as: 'Name')]
|
||||||
public string $name;
|
public string $name;
|
||||||
|
|
||||||
|
#[Validate('nullable|string', as: 'Description')]
|
||||||
public ?string $description = null;
|
public ?string $description = null;
|
||||||
|
|
||||||
|
#[Validate('required|string', as: 'IP Address/Domain')]
|
||||||
public string $ip;
|
public string $ip;
|
||||||
|
|
||||||
|
#[Validate('required|string', as: 'User')]
|
||||||
public string $user = 'root';
|
public string $user = 'root';
|
||||||
|
|
||||||
|
#[Validate('required|integer|between:1,65535', as: 'Port')]
|
||||||
public int $port = 22;
|
public int $port = 22;
|
||||||
|
|
||||||
|
#[Validate('required|boolean', as: 'Swarm Manager')]
|
||||||
public bool $is_swarm_manager = false;
|
public bool $is_swarm_manager = false;
|
||||||
|
|
||||||
|
#[Validate('required|boolean', as: 'Swarm Worker')]
|
||||||
public bool $is_swarm_worker = false;
|
public bool $is_swarm_worker = false;
|
||||||
|
|
||||||
|
#[Validate('nullable|integer', as: 'Swarm Cluster')]
|
||||||
public $selected_swarm_cluster = null;
|
public $selected_swarm_cluster = null;
|
||||||
|
|
||||||
|
#[Validate('required|boolean', as: 'Build Server')]
|
||||||
public bool $is_build_server = false;
|
public bool $is_build_server = false;
|
||||||
|
|
||||||
|
#[Locked]
|
||||||
public Collection $swarm_managers;
|
public Collection $swarm_managers;
|
||||||
|
|
||||||
protected $rules = [
|
|
||||||
'name' => 'required|string',
|
|
||||||
'description' => 'nullable|string',
|
|
||||||
'ip' => 'required',
|
|
||||||
'user' => 'required|string',
|
|
||||||
'port' => 'required|integer',
|
|
||||||
'is_swarm_manager' => 'required|boolean',
|
|
||||||
'is_swarm_worker' => 'required|boolean',
|
|
||||||
'is_build_server' => 'required|boolean',
|
|
||||||
];
|
|
||||||
|
|
||||||
protected $validationAttributes = [
|
|
||||||
'name' => 'Name',
|
|
||||||
'description' => 'Description',
|
|
||||||
'ip' => 'IP Address/Domain',
|
|
||||||
'user' => 'User',
|
|
||||||
'port' => 'Port',
|
|
||||||
'is_swarm_manager' => 'Swarm Manager',
|
|
||||||
'is_swarm_worker' => 'Swarm Worker',
|
|
||||||
'is_build_server' => 'Build Server',
|
|
||||||
];
|
|
||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
$this->name = generate_random_name();
|
$this->name = generate_random_name();
|
||||||
@@ -88,6 +84,12 @@ class ByIp extends Component
|
|||||||
{
|
{
|
||||||
$this->validate();
|
$this->validate();
|
||||||
try {
|
try {
|
||||||
|
if (Server::where('team_id', currentTeam()->id)
|
||||||
|
->where('ip', $this->ip)
|
||||||
|
->exists()) {
|
||||||
|
return $this->dispatch('error', 'This IP/Domain is already in use by another server in your team.');
|
||||||
|
}
|
||||||
|
|
||||||
if (is_null($this->private_key_id)) {
|
if (is_null($this->private_key_id)) {
|
||||||
return $this->dispatch('error', 'You must select a private key');
|
return $this->dispatch('error', 'You must select a private key');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -107,6 +107,15 @@ class Show extends Component
|
|||||||
{
|
{
|
||||||
if ($toModel) {
|
if ($toModel) {
|
||||||
$this->validate();
|
$this->validate();
|
||||||
|
|
||||||
|
if (Server::where('team_id', currentTeam()->id)
|
||||||
|
->where('ip', $this->ip)
|
||||||
|
->where('id', '!=', $this->server->id)
|
||||||
|
->exists()) {
|
||||||
|
$this->ip = $this->server->ip;
|
||||||
|
throw new \Exception('This IP/Domain is already in use by another server in your team.');
|
||||||
|
}
|
||||||
|
|
||||||
$this->server->name = $this->name;
|
$this->server->name = $this->name;
|
||||||
$this->server->description = $this->description;
|
$this->server->description = $this->description;
|
||||||
$this->server->ip = $this->ip;
|
$this->server->ip = $this->ip;
|
||||||
|
|||||||
@@ -218,13 +218,16 @@ class PrivateKey extends BaseModel
|
|||||||
|
|
||||||
private static function fingerprintExists($fingerprint, $excludeId = null)
|
private static function fingerprintExists($fingerprint, $excludeId = null)
|
||||||
{
|
{
|
||||||
$query = self::where('fingerprint', $fingerprint);
|
$query = self::query()
|
||||||
|
->where('fingerprint', $fingerprint);
|
||||||
|
|
||||||
if (! is_null($excludeId)) {
|
if (currentTeam()) {
|
||||||
$query->where('id', '!=', $excludeId);
|
$query->where('team_id', currentTeam()->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $query->exists();
|
return $query
|
||||||
|
->when($excludeId, fn ($query) => $query->where('id', '!=', $excludeId))
|
||||||
|
->exists();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function cleanupUnusedKeys()
|
public static function cleanupUnusedKeys()
|
||||||
|
|||||||
@@ -4075,7 +4075,7 @@ function defaultNginxConfiguration(): string
|
|||||||
location / {
|
location / {
|
||||||
root /usr/share/nginx/html;
|
root /usr/share/nginx/html;
|
||||||
index index.html index.htm;
|
index index.html index.htm;
|
||||||
try_files $uri $uri/index.html =404;
|
try_files $uri $uri.html $uri/index.html $uri/index.htm $uri/ /index.html /index.htm =404;
|
||||||
}
|
}
|
||||||
|
|
||||||
error_page 500 502 503 504 /50x.html;
|
error_page 500 502 503 504 /50x.html;
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ class ProductionSeeder extends Seeder
|
|||||||
public function run(): void
|
public function run(): void
|
||||||
{
|
{
|
||||||
if (isCloud()) {
|
if (isCloud()) {
|
||||||
echo "Running in cloud mode.\n";
|
echo "[x]: Running in cloud mode.\n";
|
||||||
} else {
|
} else {
|
||||||
echo "Running in self-hosted mode.\n";
|
echo "[x]: Running in self-hosted mode.\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fix for 4.0.0-beta.37
|
// Fix for 4.0.0-beta.37
|
||||||
|
|||||||
@@ -112,12 +112,3 @@ RUN chmod +x /usr/bin/mc
|
|||||||
|
|
||||||
# Switch to non-root user
|
# Switch to non-root user
|
||||||
USER www-data
|
USER www-data
|
||||||
|
|
||||||
# Optimize Laravel application
|
|
||||||
RUN composer dump-autoload && \
|
|
||||||
php artisan route:clear && \
|
|
||||||
php artisan view:clear && \
|
|
||||||
php artisan config:clear && \
|
|
||||||
php artisan route:cache && \
|
|
||||||
php artisan view:cache && \
|
|
||||||
php artisan config:cache
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ CDN="https://cdn.coollabs.io/coolify-nightly"
|
|||||||
DATE=$(date +"%Y%m%d-%H%M%S")
|
DATE=$(date +"%Y%m%d-%H%M%S")
|
||||||
|
|
||||||
VERSION="1.6"
|
VERSION="1.6"
|
||||||
DOCKER_VERSION="27.3"
|
DOCKER_VERSION="27.0"
|
||||||
# TODO: Ask for a user
|
# TODO: Ask for a user
|
||||||
CURRENT_USER=$USER
|
CURRENT_USER=$USER
|
||||||
|
|
||||||
|
|||||||
@@ -9,12 +9,12 @@
|
|||||||
<a class="menu-item {{ $activeMenu === 'private-key' ? 'menu-item-active' : '' }}"
|
<a class="menu-item {{ $activeMenu === 'private-key' ? 'menu-item-active' : '' }}"
|
||||||
href="{{ route('server.private-key', ['server_uuid' => $server->uuid]) }}">Private Key
|
href="{{ route('server.private-key', ['server_uuid' => $server->uuid]) }}">Private Key
|
||||||
</a>
|
</a>
|
||||||
|
@if (!$server->isLocalhost())
|
||||||
|
<a class="menu-item {{ $activeMenu === 'cloudflare-tunnels' ? 'menu-item-active' : '' }}"
|
||||||
|
href="{{ route('server.cloudflare-tunnels', ['server_uuid' => $server->uuid]) }}">Cloudflare
|
||||||
|
Tunnels</a>
|
||||||
|
@endif
|
||||||
@if ($server->isFunctional())
|
@if ($server->isFunctional())
|
||||||
@if (!$server->isLocalhost())
|
|
||||||
<a class="menu-item {{ $activeMenu === 'cloudflare-tunnels' ? 'menu-item-active' : '' }}"
|
|
||||||
href="{{ route('server.cloudflare-tunnels', ['server_uuid' => $server->uuid]) }}">Cloudflare
|
|
||||||
Tunnels</a>
|
|
||||||
@endif
|
|
||||||
<a class="menu-item {{ $activeMenu === 'destinations' ? 'menu-item-active' : '' }}"
|
<a class="menu-item {{ $activeMenu === 'destinations' ? 'menu-item-active' : '' }}"
|
||||||
href="{{ route('server.destinations', ['server_uuid' => $server->uuid]) }}">Destinations
|
href="{{ route('server.destinations', ['server_uuid' => $server->uuid]) }}">Destinations
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -101,7 +101,11 @@
|
|||||||
<x-slot:logo>
|
<x-slot:logo>
|
||||||
<template x-if="service.logo">
|
<template x-if="service.logo">
|
||||||
<img class="w-[4.5rem] aspect-square h-[4.5rem] p-2 transition-all duration-200 opacity-30 grayscale group-hover:grayscale-0 group-hover:opacity-100"
|
<img class="w-[4.5rem] aspect-square h-[4.5rem] p-2 transition-all duration-200 opacity-30 grayscale group-hover:grayscale-0 group-hover:opacity-100"
|
||||||
:src='service.logo'>
|
:src='service.logo'
|
||||||
|
x-on:error.window="$event.target.src = service.logo_github_url"
|
||||||
|
onerror="this.onerror=null; this.src=this.getAttribute('data-fallback');"
|
||||||
|
x-on:error="$event.target.src = '/svgs/coolify.png'"
|
||||||
|
:data-fallback='service.logo_github_url' />
|
||||||
</template>
|
</template>
|
||||||
</x-slot:logo>
|
</x-slot:logo>
|
||||||
<x-slot:documentation>
|
<x-slot:documentation>
|
||||||
@@ -205,7 +209,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
@if ($current_step === 'servers')
|
@if ($current_step === 'servers')
|
||||||
<h2>Select a server</h2>
|
<h2>Select a server</h2>
|
||||||
|
|||||||
@@ -54,6 +54,10 @@
|
|||||||
<div class="relative w-auto pb-8">
|
<div class="relative w-auto pb-8">
|
||||||
<p>Are you sure you would like to upgrade your instance to {{ $latestVersion }}?</p>
|
<p>Are you sure you would like to upgrade your instance to {{ $latestVersion }}?</p>
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
|
<div class="p-4 mb-4 text-yellow-800 border border-yellow-300 rounded-lg bg-yellow-50 dark:bg-yellow-900/30 dark:text-yellow-300 dark:border-yellow-800">
|
||||||
|
<p class="font-medium">Warning: Any deployments running during the update process will fail. Please ensure no deployments are in progress on any server before continuing.</p>
|
||||||
|
</div>
|
||||||
<p>You can review the changelogs <a class="font-bold underline dark:text-white"
|
<p>You can review the changelogs <a class="font-bold underline dark:text-white"
|
||||||
href="https://github.com/coollabsio/coolify/releases" target="_blank">here</a>.</p>
|
href="https://github.com/coollabsio/coolify/releases" target="_blank">here</a>.</p>
|
||||||
<br />
|
<br />
|
||||||
|
|||||||
@@ -9,10 +9,54 @@ CDN="https://cdn.coollabs.io/coolify"
|
|||||||
DATE=$(date +"%Y%m%d-%H%M%S")
|
DATE=$(date +"%Y%m%d-%H%M%S")
|
||||||
|
|
||||||
VERSION="1.6"
|
VERSION="1.6"
|
||||||
DOCKER_VERSION="27.3"
|
DOCKER_VERSION="27.0"
|
||||||
# TODO: Ask for a user
|
# TODO: Ask for a user
|
||||||
CURRENT_USER=$USER
|
CURRENT_USER=$USER
|
||||||
|
|
||||||
|
if [ $EUID != 0 ]; then
|
||||||
|
echo "Please run this script as root or with sudo"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "Welcome to Coolify Installer!"
|
||||||
|
echo -e "This script will install everything for you. Sit back and relax."
|
||||||
|
echo -e "Source code: https://github.com/coollabsio/coolify/blob/main/scripts/install.sh\n"
|
||||||
|
|
||||||
|
TOTAL_SPACE=$(df -BG / | awk 'NR==2 {print $2}' | sed 's/G//')
|
||||||
|
AVAILABLE_SPACE=$(df -BG / | awk 'NR==2 {print $4}' | sed 's/G//')
|
||||||
|
REQUIRED_TOTAL_SPACE=30
|
||||||
|
REQUIRED_AVAILABLE_SPACE=20
|
||||||
|
WARNING_SPACE=false
|
||||||
|
|
||||||
|
if [ "$TOTAL_SPACE" -lt "$REQUIRED_TOTAL_SPACE" ]; then
|
||||||
|
WARNING_SPACE=true
|
||||||
|
cat << 'EOF'
|
||||||
|
WARNING: Insufficient total disk space!
|
||||||
|
|
||||||
|
Total disk space: ${TOTAL_SPACE}GB
|
||||||
|
Required disk space: ${REQUIRED_TOTAL_SPACE}GB
|
||||||
|
|
||||||
|
==================
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$AVAILABLE_SPACE" -lt "$REQUIRED_AVAILABLE_SPACE" ]; then
|
||||||
|
cat << 'EOF'
|
||||||
|
WARNING: Insufficient available disk space!
|
||||||
|
|
||||||
|
Available disk space: ${AVAILABLE_SPACE}GB
|
||||||
|
Required available space: ${REQUIRED_AVAILABLE_SPACE}GB
|
||||||
|
|
||||||
|
==================
|
||||||
|
EOF
|
||||||
|
WARNING_SPACE=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$WARNING_SPACE" = true ]; then
|
||||||
|
echo "Sleeping for 5 seconds."
|
||||||
|
sleep 5
|
||||||
|
fi
|
||||||
|
|
||||||
mkdir -p /data/coolify/{source,ssh,applications,databases,backups,services,proxy,webhooks-during-maintenance,sentinel}
|
mkdir -p /data/coolify/{source,ssh,applications,databases,backups,services,proxy,webhooks-during-maintenance,sentinel}
|
||||||
mkdir -p /data/coolify/ssh/{keys,mux}
|
mkdir -p /data/coolify/ssh/{keys,mux}
|
||||||
mkdir -p /data/coolify/proxy/dynamic
|
mkdir -p /data/coolify/proxy/dynamic
|
||||||
@@ -83,11 +127,6 @@ if [ -z "$LATEST_REALTIME_VERSION" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
if [ $EUID != 0 ]; then
|
|
||||||
echo "Please run as root"
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
case "$OS_TYPE" in
|
case "$OS_TYPE" in
|
||||||
arch | ubuntu | debian | raspbian | centos | fedora | rhel | ol | rocky | sles | opensuse-leap | opensuse-tumbleweed | almalinux | amzn | alpine) ;;
|
arch | ubuntu | debian | raspbian | centos | fedora | rhel | ol | rocky | sles | opensuse-leap | opensuse-tumbleweed | almalinux | amzn | alpine) ;;
|
||||||
*)
|
*)
|
||||||
@@ -103,21 +142,8 @@ if [ "$1" != "" ]; then
|
|||||||
LATEST_VERSION="${LATEST_VERSION#v}"
|
LATEST_VERSION="${LATEST_VERSION#v}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo -e "\033[0;35m"
|
|
||||||
cat << "EOF"
|
|
||||||
_____ _ _ __
|
|
||||||
/ ____| | (_)/ _|
|
|
||||||
| | ___ ___ | |_| |_ _ _
|
|
||||||
| | / _ \ / _ \| | | _| | | |
|
|
||||||
| |___| (_) | (_) | | | | | |_| |
|
|
||||||
\_____\___/ \___/|_|_|_| \__, |
|
|
||||||
__/ |
|
|
||||||
|___/
|
|
||||||
EOF
|
|
||||||
echo -e "\033[0m"
|
|
||||||
echo -e "Welcome to Coolify Installer!"
|
|
||||||
echo -e "This script will install everything for you. Sit back and relax."
|
|
||||||
echo -e "Source code: https://github.com/coollabsio/coolify/blob/main/scripts/install.sh\n"
|
|
||||||
echo -e "---------------------------------------------"
|
echo -e "---------------------------------------------"
|
||||||
echo "| Operating System | $OS_TYPE $OS_VERSION"
|
echo "| Operating System | $OS_TYPE $OS_VERSION"
|
||||||
echo "| Docker | $DOCKER_VERSION"
|
echo "| Docker | $DOCKER_VERSION"
|
||||||
@@ -125,24 +151,24 @@ echo "| Coolify | $LATEST_VERSION"
|
|||||||
echo "| Helper | $LATEST_HELPER_VERSION"
|
echo "| Helper | $LATEST_HELPER_VERSION"
|
||||||
echo "| Realtime | $LATEST_REALTIME_VERSION"
|
echo "| Realtime | $LATEST_REALTIME_VERSION"
|
||||||
echo -e "---------------------------------------------\n"
|
echo -e "---------------------------------------------\n"
|
||||||
echo -e "1. Installing required packages (curl, wget, git, jq). "
|
echo -e "1. Installing required packages (curl, wget, git, jq, openssl). "
|
||||||
|
|
||||||
case "$OS_TYPE" in
|
case "$OS_TYPE" in
|
||||||
arch)
|
arch)
|
||||||
pacman -Sy --noconfirm --needed curl wget git jq >/dev/null || true
|
pacman -Sy --noconfirm --needed curl wget git jq openssl >/dev/null || true
|
||||||
;;
|
;;
|
||||||
alpine)
|
alpine)
|
||||||
sed -i '/^#.*\/community/s/^#//' /etc/apk/repositories
|
sed -i '/^#.*\/community/s/^#//' /etc/apk/repositories
|
||||||
apk update >/dev/null
|
apk update >/dev/null
|
||||||
apk add curl wget git jq >/dev/null
|
apk add curl wget git jq openssl >/dev/null
|
||||||
;;
|
;;
|
||||||
ubuntu | debian | raspbian)
|
ubuntu | debian | raspbian)
|
||||||
apt-get update -y >/dev/null
|
apt-get update -y >/dev/null
|
||||||
apt-get install -y curl wget git jq >/dev/null
|
apt-get install -y curl wget git jq openssl >/dev/null
|
||||||
;;
|
;;
|
||||||
centos | fedora | rhel | ol | rocky | almalinux | amzn)
|
centos | fedora | rhel | ol | rocky | almalinux | amzn)
|
||||||
if [ "$OS_TYPE" = "amzn" ]; then
|
if [ "$OS_TYPE" = "amzn" ]; then
|
||||||
dnf install -y wget git jq >/dev/null
|
dnf install -y wget git jq openssl >/dev/null
|
||||||
else
|
else
|
||||||
if ! command -v dnf >/dev/null; then
|
if ! command -v dnf >/dev/null; then
|
||||||
yum install -y dnf >/dev/null
|
yum install -y dnf >/dev/null
|
||||||
@@ -150,12 +176,12 @@ centos | fedora | rhel | ol | rocky | almalinux | amzn)
|
|||||||
if ! command -v curl >/dev/null; then
|
if ! command -v curl >/dev/null; then
|
||||||
dnf install -y curl >/dev/null
|
dnf install -y curl >/dev/null
|
||||||
fi
|
fi
|
||||||
dnf install -y wget git jq >/dev/null
|
dnf install -y wget git jq openssl >/dev/null
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
sles | opensuse-leap | opensuse-tumbleweed)
|
sles | opensuse-leap | opensuse-tumbleweed)
|
||||||
zypper refresh >/dev/null
|
zypper refresh >/dev/null
|
||||||
zypper install -y curl wget git jq >/dev/null
|
zypper install -y curl wget git jq openssl >/dev/null
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "This script only supports Debian, Redhat, Arch Linux, or SLES based operating systems for now."
|
echo "This script only supports Debian, Redhat, Arch Linux, or SLES based operating systems for now."
|
||||||
@@ -300,6 +326,22 @@ if ! [ -x "$(command -v docker)" ]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
|
"fedora")
|
||||||
|
if [ -x "$(command -v dnf5)" ]; then
|
||||||
|
# dnf5 is available
|
||||||
|
dnf config-manager addrepo --from-repofile=https://download.docker.com/linux/fedora/docker-ce.repo --overwrite >/dev/null 2>&1
|
||||||
|
else
|
||||||
|
# dnf5 is not available, use dnf
|
||||||
|
dnf config-manager --add-repo=https://download.docker.com/linux/fedora/docker-ce.repo >/dev/null 2>&1
|
||||||
|
fi
|
||||||
|
dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin >/dev/null 2>&1
|
||||||
|
if ! [ -x "$(command -v docker)" ]; then
|
||||||
|
echo " - Docker could not be installed automatically. Please visit https://docs.docker.com/engine/install/ and install Docker manually to continue."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
systemctl start docker >/dev/null 2>&1
|
||||||
|
systemctl enable docker >/dev/null 2>&1
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
if [ "$OS_TYPE" = "ubuntu" ] && [ "$OS_VERSION" = "24.10" ]; then
|
if [ "$OS_TYPE" = "ubuntu" ] && [ "$OS_VERSION" = "24.10" ]; then
|
||||||
echo "Docker automated installation is not supported on Ubuntu 24.10 (non-LTS release)."
|
echo "Docker automated installation is not supported on Ubuntu 24.10 (non-LTS release)."
|
||||||
@@ -490,7 +532,21 @@ echo -e "\033[0;35m
|
|||||||
\____\___/|_| |_|\__, |_| \__,_|\__|\__,_|_|\__,_|\__|_|\___/|_| |_|___(_)
|
\____\___/|_| |_|\__, |_| \__,_|\__|\__,_|_|\__,_|\__|_|\___/|_| |_|___(_)
|
||||||
|___/
|
|___/
|
||||||
\033[0m"
|
\033[0m"
|
||||||
echo -e "\nYour instance is ready to use."
|
echo -e "\nYour instance is ready to use!\n"
|
||||||
echo -e "Please visit http://$(curl -4s https://ifconfig.io):8000 to get started.\n"
|
echo -e "You can access Coolify through your Public IP: http://$(curl -4s https://ifconfig.io):8000"
|
||||||
echo -e "WARNING: We recommend you to backup your /data/coolify/source/.env file to a safe location, outside of this server."
|
|
||||||
|
set +e
|
||||||
|
DEFAULT_PRIVATE_IP=$(ip route get 1 | sed -n 's/^.*src \([0-9.]*\) .*$/\1/p')
|
||||||
|
PRIVATE_IPS=$(hostname -I)
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ -n "$PRIVATE_IPS" ]; then
|
||||||
|
echo -e "\nIf your Public IP is not accessible, you can use the following Private IPs:\n"
|
||||||
|
for IP in $PRIVATE_IPS; do
|
||||||
|
if [ "$IP" != "$DEFAULT_PRIVATE_IP" ]; then
|
||||||
|
echo -e "http://$IP:8000"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
echo -e "\nWARNING: It is highly recommended to backup your Environment variables file (/data/coolify/source/.env) to a safe location, outside of this server (e.g. into a Password Manager).\n"
|
||||||
cp /data/coolify/source/.env /data/coolify/source/.env.backup
|
cp /data/coolify/source/.env /data/coolify/source/.env.backup
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ services:
|
|||||||
image: ghcr.io/browserless/chromium
|
image: ghcr.io/browserless/chromium
|
||||||
environment:
|
environment:
|
||||||
- SERVICE_FQDN_BROWSERLESS_3000
|
- SERVICE_FQDN_BROWSERLESS_3000
|
||||||
- TOKEN=$SERVICE_BASE64_BROWSERLESS_TOKEN
|
- TOKEN=$SERVICE_PASSWORD_BROWSERLESS
|
||||||
expose:
|
expose:
|
||||||
- 3000
|
- 3000
|
||||||
healthcheck:
|
healthcheck:
|
||||||
|
|||||||
@@ -192,7 +192,7 @@
|
|||||||
"browserless": {
|
"browserless": {
|
||||||
"documentation": "https://docs.browserless.io/?utm_source=coolify.io",
|
"documentation": "https://docs.browserless.io/?utm_source=coolify.io",
|
||||||
"slogan": "A headless Chrome browser as a service .",
|
"slogan": "A headless Chrome browser as a service .",
|
||||||
"compose": "c2VydmljZXM6CiAgYnJvd3Nlcmxlc3M6CiAgICBpbWFnZTogZ2hjci5pby9icm93c2VybGVzcy9jaHJvbWl1bQogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX0JST1dTRVJMRVNTXzMwMDAKICAgICAgLSBUT0tFTj0kU0VSVklDRV9CQVNFNjRfQlJPV1NFUkxFU1NfVE9LRU4KICAgIGV4cG9zZToKICAgICAgLSAzMDAwCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gY3VybAogICAgICAgIC0gJy1mJwogICAgICAgIC0gJ2h0dHA6Ly8xMjcuMC4wLjE6MzAwMC9kb2NzJwogICAgICBpbnRlcnZhbDogMnMKICAgICAgdGltZW91dDogMTBzCiAgICAgIHJldHJpZXM6IDE1Cg==",
|
"compose": "c2VydmljZXM6CiAgYnJvd3Nlcmxlc3M6CiAgICBpbWFnZTogZ2hjci5pby9icm93c2VybGVzcy9jaHJvbWl1bQogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX0JST1dTRVJMRVNTXzMwMDAKICAgICAgLSBUT0tFTj0kU0VSVklDRV9QQVNTV09SRF9CUk9XU0VSTEVTUwogICAgZXhwb3NlOgogICAgICAtIDMwMDAKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBjdXJsCiAgICAgICAgLSAnLWYnCiAgICAgICAgLSAnaHR0cDovLzEyNy4wLjAuMTozMDAwL2RvY3MnCiAgICAgIGludGVydmFsOiAycwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMTUK",
|
||||||
"tags": [
|
"tags": [
|
||||||
"chrome",
|
"chrome",
|
||||||
"headless",
|
"headless",
|
||||||
|
|||||||
Reference in New Issue
Block a user