diff --git a/.gitignore b/.gitignore index d75e3c80f..ac8a1e090 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,4 @@ _ide_helper.php _ide_helper_models.php .rnd /.ssh +scripts/load-test/* diff --git a/README.md b/README.md index 0a4b2c367..0910b6897 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,30 @@ -# Coolify v4 Beta +# About the Project -An open-source & self-hostable Heroku / Netlify alternative. +Coolify is an open-source & self-hostable alternative to Heroku / Netlify / Vercel / etc. + +It helps you to manage your servers, applications, databases on your own hardware, all you need is SSH connection. You can manage VPS, Bare Metal, Raspberry PI's anything. + +Image if you could have the ease of a cloud but with your own servers. That is **Coolify**. + +No vendor lock-in, which means that all the configuration for your applications/databases/etc are saved to your server. So if you decide to stop using Coolify (oh nooo), you could still manage your running resources. You just lose the automations and all the magic. 🪄️ + +For more information, take a look at our landing page [here](https://coolify.io). + +> If you are looking for previous (v3) version, it is [here](https://github.com/coollabsio/coolify/tree/v3). + +# Cloud + +If you do not want to self-host Coolify, there is a paid cloud version available: https://app.coolify.io + +You can easily attach your own servers, get all the automations, free email notifications, etc. + +For more information & pricing, take a look at our landing page [here](https://coolify.io). # Beta -You are checking the next-gen of Coolify, aka v4. Hi 👋 +The latest version (v4) is still in beta. That does not mean it is unstable. All the features that are available are stable enough be usable in real-life. -It is still in beta, lots of improvements will come every day. Things could break, but we are working hard to make it stable as soon as possible. If you find any bugs, please report them. - -Automatic updates are available, so you will receive the latest version as soon as it is released. - -If you are looking for v3, check out the [v3 branch](https://github.com/coollabsio/coolify/tree/v3). - -## What's new? - -Well, the whole tech stack changed, core is different, so yeah, a lot (documentation incoming). +There are hundreds of people using it for managing their client's applications, freelancers, hobbyists, businesses. # Installation @@ -26,13 +36,19 @@ You can find the installation script [here](./scripts/install.sh). ## Support -- Twitter: [@heyandras](https://twitter.com/heyandras) -- Mastodon: [@andrasbacsai@fosstodon.org](https://fosstodon.org/@andrasbacsai) -- Email: [andras@coollabs.io](mailto:andras@coollabs.io) -- Discord: [Invitation](https://coollabs.io/discord) -- Telegram: [@andrasbacsai](https://t.me/andrasbacsai) +Contact us [here](https://docs.coollabs.io/contact). ---- +## Recognitions + + + Featured on Hacker News + + +Coolify - An open-source & self-hostable Heroku, Netlify alternative | Product Hunt ## 💰 Financial Contributors diff --git a/app/Http/Livewire/Project/Database/Heading.php b/app/Http/Livewire/Project/Database/Heading.php index 347c439a6..178cbfca5 100644 --- a/app/Http/Livewire/Project/Database/Heading.php +++ b/app/Http/Livewire/Project/Database/Heading.php @@ -42,8 +42,13 @@ class Heading extends Component ["docker rm -f {$this->database->uuid}"], $this->database->destination->server ); + if ($this->database->is_public) { + stopPostgresProxy($this->database); + $this->database->is_public = false; + } $this->database->status = 'stopped'; $this->database->save(); + $this->emit('refresh'); // $this->database->environment->project->team->notify(new StatusChanged($this->database)); } diff --git a/app/Http/Livewire/Project/Database/Postgresql/General.php b/app/Http/Livewire/Project/Database/Postgresql/General.php index c58bd51e3..da9470783 100644 --- a/app/Http/Livewire/Project/Database/Postgresql/General.php +++ b/app/Http/Livewire/Project/Database/Postgresql/General.php @@ -12,6 +12,7 @@ class General extends Component public StandalonePostgresql $database; public string $new_filename; public string $new_content; + public string $db_url; protected $listeners = ['refresh', 'save_init_script', 'delete_init_script']; @@ -26,6 +27,8 @@ class General extends Component 'database.init_scripts' => 'nullable', 'database.image' => 'required', 'database.ports_mappings' => 'nullable', + 'database.is_public' => 'nullable|boolean', + 'database.public_port' => 'nullable|integer', ]; protected $validationAttributes = [ 'database.name' => 'Name', @@ -38,8 +41,43 @@ class General extends Component 'database.init_scripts' => 'Init Scripts', 'database.image' => 'Image', 'database.ports_mappings' => 'Port Mapping', + 'database.is_public' => 'Is Public', + 'database.public_port' => 'Public Port', ]; + public function mount() + { + $this->getDbUrl(); + } + public function getDbUrl() { + if ($this->database->is_public) { + $this->db_url = "postgres://{$this->database->postgres_user}:{$this->database->postgres_password}@{$this->database->destination->server->ip}:{$this->database->public_port}/{$this->database->postgres_db}"; + } else { + $this->db_url = "postgres://{$this->database->postgres_user}:{$this->database->postgres_password}@{$this->database->uuid}:5432/{$this->database->postgres_db}"; + } + } + public function instantSave() + { + try { + if ($this->database->is_public && !$this->database->public_port) { + $this->emit('error', 'Public port is required.'); + $this->database->is_public = false; + return; + } + if ($this->database->is_public) { + startPostgresProxy($this->database); + $this->emit('success', 'Database is now publicly accessible.'); + } else { + stopPostgresProxy($this->database); + $this->emit('success', 'Database is no longer publicly accessible.'); + } + $this->getDbUrl(); + $this->database->save(); + } catch(Exception $e) { + $this->database->is_public = !$this->database->is_public; + return general_error_handler(err: $e, that: $this); + } + } public function save_init_script($script) { $this->database->init_scripts = filter($this->database->init_scripts, fn ($s) => $s['filename'] !== $script['filename']); diff --git a/bootstrap/helpers/databases.php b/bootstrap/helpers/databases.php index c005ad15d..3b8e893c7 100644 --- a/bootstrap/helpers/databases.php +++ b/bootstrap/helpers/databases.php @@ -20,7 +20,7 @@ function create_standalone_postgresql($environment_id, $destination_uuid): Stand } return StandalonePostgresql::create([ 'name' => generate_database_name('postgresql'), - 'postgres_password' => \Illuminate\Support\Str::password(), + 'postgres_password' => \Illuminate\Support\Str::password(symbols: false), 'environment_id' => $environment_id, 'destination_id' => $destination->id, 'destination_type' => $destination->getMorphClass(), diff --git a/bootstrap/helpers/proxy.php b/bootstrap/helpers/proxy.php index 164c46e94..c78a560c7 100644 --- a/bootstrap/helpers/proxy.php +++ b/bootstrap/helpers/proxy.php @@ -1,6 +1,7 @@ uuid}-proxy"; + $configuration_dir = database_proxy_dir($database->uuid); + $nginxconf = <<public_port; + proxy_pass $database->uuid:5432; + } +} +EOF; + $docker_compose = [ + 'version' => '3.8', + 'services' => [ + $containerName => [ + 'image' => "nginx:stable-alpine", + 'container_name' => $containerName, + 'restart' => RESTART_MODE, + 'volumes' => [ + "$configuration_dir/nginx.conf:/etc/nginx/nginx.conf:ro", + ], + 'ports' => [ + "$database->public_port:$database->public_port", + ], + 'networks' => [ + $database->destination->network, + ], + 'healthcheck' => [ + 'test' => [ + 'CMD-SHELL', + 'stat /etc/nginx/nginx.conf || exit 1', + ], + 'interval' => '5s', + 'timeout' => '5s', + 'retries' => 3, + 'start_period' => '1s' + ], + ] + ], + 'networks' => [ + $database->destination->network => [ + 'external' => true, + 'name' => $database->destination->network, + 'attachable' => true, + ] + ] + ]; + $dockercompose_base64 = base64_encode(Yaml::dump($docker_compose, 4, 2)); + $nginxconf_base64 = base64_encode($nginxconf); + instant_remote_process([ + "mkdir -p $configuration_dir", + "echo '{$nginxconf_base64}' | base64 -d > $configuration_dir/nginx.conf", + "echo '{$dockercompose_base64}' | base64 -d > $configuration_dir/docker-compose.yaml", + "docker compose --project-directory {$configuration_dir} up -d >/dev/null", + + + ], $database->destination->server); +} +function stopPostgresProxy(StandalonePostgresql $database) +{ + instant_remote_process(["docker rm -f {$database->uuid}-proxy"], $database->destination->server); +} diff --git a/bootstrap/helpers/shared.php b/bootstrap/helpers/shared.php index ac8beecf3..15f8fc0db 100644 --- a/bootstrap/helpers/shared.php +++ b/bootstrap/helpers/shared.php @@ -28,6 +28,10 @@ function database_configuration_dir(): string { return '/data/coolify/databases'; } +function database_proxy_dir($uuid): string +{ + return "/data/coolify/databases/$uuid/proxy"; +} function backup_dir(): string { diff --git a/config/sentry.php b/config/sentry.php index ea6317851..8d9da20e0 100644 --- a/config/sentry.php +++ b/config/sentry.php @@ -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.25', + 'release' => '4.0.0-beta.26', 'server_name' => env('APP_ID', 'coolify'), // When left empty or `null` the Laravel environment will be used 'environment' => config('app.env'), diff --git a/config/version.php b/config/version.php index 03ee49dc6..39c13e6c2 100644 --- a/config/version.php +++ b/config/version.php @@ -1,3 +1,3 @@ merge(['class' => $defaultClass]) }} - @if ($instantSave) wire:click='{{ $instantSave === 'instantSave' || $instantSave == '1' ? 'instantSave' : $instantSave }}' + @if ($instantSave) wire:loading.attr="disabled" wire:click='{{ $instantSave === 'instantSave' || $instantSave == '1' ? 'instantSave' : $instantSave }}' wire:model.defer={{ $id }} @else wire:model.defer={{ $value ?? $id }} @endif /> diff --git a/resources/views/livewire/project/database/postgresql/general.blade.php b/resources/views/livewire/project/database/postgresql/general.blade.php index 7fe29c2bf..8b184f024 100644 --- a/resources/views/livewire/project/database/postgresql/general.blade.php +++ b/resources/views/livewire/project/database/postgresql/general.blade.php @@ -51,10 +51,15 @@ -
+

Network

- + + + +
+
diff --git a/resources/views/vendor/toaster/hub.blade.php b/resources/views/vendor/toaster/hub.blade.php index 5aff1b506..3bca749b6 100644 --- a/resources/views/vendor/toaster/hub.blade.php +++ b/resources/views/vendor/toaster/hub.blade.php @@ -22,7 +22,7 @@ class="relative flex duration-300 transform transition ease-in-out max-w-md w-full pointer-events-auto {{ $position->is('center') ? 'text-center' : 'text-left' }}" :class="toast.select({ error: 'text-white', info: 'text-white', success: 'text-white', warning: 'text-white' })" > - + @if ($closeable) diff --git a/versions.json b/versions.json index b31c1415b..cfa6f9ad8 100644 --- a/versions.json +++ b/versions.json @@ -4,7 +4,7 @@ "version": "3.12.36" }, "v4": { - "version": "4.0.0-beta.24" + "version": "4.0.0-beta.25" } } }