Merge branch 'next' into new-dockerfiles

This commit is contained in:
🏔️ Peak
2024-11-15 12:25:37 +01:00
committed by GitHub
22 changed files with 190 additions and 106 deletions

View File

@@ -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*');

View File

@@ -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();
} }

View File

@@ -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 {

View File

@@ -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";
} }
} }

View File

@@ -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 {

View File

@@ -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()
{ {

View File

@@ -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;
} }
} }
} }

View File

@@ -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 = [

View File

@@ -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.");

View File

@@ -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');
} }

View File

@@ -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;

View File

@@ -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()

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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->isFunctional())
@if (!$server->isLocalhost()) @if (!$server->isLocalhost())
<a class="menu-item {{ $activeMenu === 'cloudflare-tunnels' ? 'menu-item-active' : '' }}" <a class="menu-item {{ $activeMenu === 'cloudflare-tunnels' ? 'menu-item-active' : '' }}"
href="{{ route('server.cloudflare-tunnels', ['server_uuid' => $server->uuid]) }}">Cloudflare href="{{ route('server.cloudflare-tunnels', ['server_uuid' => $server->uuid]) }}">Cloudflare
Tunnels</a> Tunnels</a>
@endif @endif
@if ($server->isFunctional())
<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>

View File

@@ -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>

View File

@@ -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 />

View File

@@ -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

View File

@@ -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:

View File

@@ -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",