diff --git a/app/Livewire/Boarding/Index.php b/app/Livewire/Boarding/Index.php index 430470fa0..ac2b9213b 100644 --- a/app/Livewire/Boarding/Index.php +++ b/app/Livewire/Boarding/Index.php @@ -16,14 +16,18 @@ class Index extends Component { protected $listeners = ['refreshBoardingIndex' => 'validateServer']; + #[\Livewire\Attributes\Url(as: 'step', history: true)] public string $currentState = 'welcome'; + #[\Livewire\Attributes\Url(keep: true)] public ?string $selectedServerType = null; public ?Collection $privateKeys = null; + #[\Livewire\Attributes\Url(keep: true)] public ?int $selectedExistingPrivateKey = null; + #[\Livewire\Attributes\Url(keep: true)] public ?string $privateKeyType = null; public ?string $privateKey = null; @@ -38,6 +42,7 @@ class Index extends Component public ?Collection $servers = null; + #[\Livewire\Attributes\Url(keep: true)] public ?int $selectedExistingServer = null; public ?string $remoteServerName = null; @@ -58,6 +63,7 @@ class Index extends Component public Collection $projects; + #[\Livewire\Attributes\Url(keep: true)] public ?int $selectedProject = null; public ?Project $createdProject = null; @@ -79,17 +85,68 @@ public function mount() $this->minDockerVersion = str(config('constants.docker.minimum_required_version'))->before('.'); $this->privateKeyName = generate_random_name(); $this->remoteServerName = generate_random_name(); - if (isDev()) { - $this->privateKey = '-----BEGIN OPENSSH PRIVATE KEY----- -b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW -QyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevAAAAJi/QySHv0Mk -hwAAAAtzc2gtZWQyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevA -AAAECBQw4jg1WRT2IGHMncCiZhURCts2s24HoDS0thHnnRKVuGmoeGq/pojrsyP1pszcNV -uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA== ------END OPENSSH PRIVATE KEY-----'; - $this->privateKeyDescription = 'Created by Coolify'; - $this->remoteServerDescription = 'Created by Coolify'; - $this->remoteServerHost = 'coolify-testing-host'; + + // Initialize collections to avoid null errors + if ($this->privateKeys === null) { + $this->privateKeys = collect(); + } + if ($this->servers === null) { + $this->servers = collect(); + } + if (! isset($this->projects)) { + $this->projects = collect(); + } + + // Restore state when coming from URL with query params + if ($this->selectedServerType === 'localhost' && $this->selectedExistingServer === 0) { + $this->createdServer = Server::find(0); + if ($this->createdServer) { + $this->serverPublicKey = $this->createdServer->privateKey->getPublicKey(); + } + } + + if ($this->selectedServerType === 'remote') { + if ($this->privateKeys->isEmpty()) { + $this->privateKeys = PrivateKey::ownedByCurrentTeam(['name'])->where('id', '!=', 0)->get(); + } + if ($this->servers->isEmpty()) { + $this->servers = Server::ownedByCurrentTeam(['name'])->where('id', '!=', 0)->get(); + } + + if ($this->selectedExistingServer) { + $this->createdServer = Server::find($this->selectedExistingServer); + if ($this->createdServer) { + $this->serverPublicKey = $this->createdServer->privateKey->getPublicKey(); + $this->updateServerDetails(); + } + } + + if ($this->selectedExistingPrivateKey) { + $this->createdPrivateKey = PrivateKey::where('team_id', currentTeam()->id) + ->where('id', $this->selectedExistingPrivateKey) + ->first(); + if ($this->createdPrivateKey) { + $this->privateKey = $this->createdPrivateKey->private_key; + $this->publicKey = $this->createdPrivateKey->getPublicKey(); + } + } + + // Auto-regenerate key pair for "Generate with Coolify" mode on page refresh + if ($this->privateKeyType === 'create' && empty($this->privateKey)) { + $this->createNewPrivateKey(); + } + } + + if ($this->selectedProject) { + $this->createdProject = Project::find($this->selectedProject); + if (! $this->createdProject) { + $this->projects = Project::ownedByCurrentTeam(['name'])->get(); + } + } + + // Load projects when on create-project state (for page refresh) + if ($this->currentState === 'create-project' && $this->projects->isEmpty()) { + $this->projects = Project::ownedByCurrentTeam(['name'])->get(); } } @@ -129,41 +186,16 @@ public function setServerType(string $type) return $this->validateServer('localhost'); } elseif ($this->selectedServerType === 'remote') { - if (isDev()) { - $this->privateKeys = PrivateKey::ownedByCurrentTeam(['name'])->get(); - } else { - $this->privateKeys = PrivateKey::ownedByCurrentTeam(['name'])->where('id', '!=', 0)->get(); - } + $this->privateKeys = PrivateKey::ownedByCurrentTeam(['name'])->where('id', '!=', 0)->get(); + // Auto-select first key if available for better UX if ($this->privateKeys->count() > 0) { $this->selectedExistingPrivateKey = $this->privateKeys->first()->id; } - $this->servers = Server::ownedByCurrentTeam(['name'])->where('id', '!=', 0)->get(); - if ($this->servers->count() > 0) { - $this->selectedExistingServer = $this->servers->first()->id; - $this->updateServerDetails(); - $this->currentState = 'select-existing-server'; - - return; - } + // Onboarding always creates new servers, skip existing server selection $this->currentState = 'private-key'; } } - public function selectExistingServer() - { - $this->createdServer = Server::find($this->selectedExistingServer); - if (! $this->createdServer) { - $this->dispatch('error', 'Server is not found.'); - $this->currentState = 'private-key'; - - return; - } - $this->selectedExistingPrivateKey = $this->createdServer->privateKey->id; - $this->serverPublicKey = $this->createdServer->privateKey->getPublicKey(); - $this->updateServerDetails(); - $this->currentState = 'validate-server'; - } - private function updateServerDetails() { if ($this->createdServer) { @@ -181,7 +213,7 @@ public function getProxyType() public function selectExistingPrivateKey() { if (is_null($this->selectedExistingPrivateKey)) { - $this->restartBoarding(); + $this->dispatch('error', 'Please select a private key.'); return; } @@ -202,6 +234,9 @@ public function setPrivateKey(string $type) $this->privateKeyType = $type; if ($type === 'create') { $this->createNewPrivateKey(); + } else { + $this->privateKey = null; + $this->publicKey = null; } $this->currentState = 'create-private-key'; } diff --git a/resources/views/components/boarding-progress.blade.php b/resources/views/components/boarding-progress.blade.php new file mode 100644 index 000000000..dec34abac --- /dev/null +++ b/resources/views/components/boarding-progress.blade.php @@ -0,0 +1,47 @@ +@props(['currentStep' => 1, 'totalSteps' => 3]) + +
+
+ @for ($i = 1; $i <= $totalSteps; $i++) +
+
+
+ @if ($i < $currentStep) + + + + @else + + {{ $i }} + + @endif +
+ + @if ($i === 1) + Server + @elseif ($i === 2) + Connection + @elseif ($i === 3) + Complete + @endif + +
+ @if ($i < $totalSteps) +
+
+ @endif +
+ @endfor +
+
diff --git a/resources/views/components/boarding-step.blade.php b/resources/views/components/boarding-step.blade.php index d963e55f0..716987baf 100644 --- a/resources/views/components/boarding-step.blade.php +++ b/resources/views/components/boarding-step.blade.php @@ -1,25 +1,29 @@ -
-
-

{{ $title }}

-
+
+
+
+

{{ $title }}

@isset($question) -

+

{{ $question }} -

+
@endisset + + @if ($actions) +
+ {{ $actions }} +
+ @endif
- @if ($actions) -
- {{ $actions }} + + @isset($explanation) +
+

+ Technical Details +

+
+ {{ $explanation }} +
- @endif + @endisset
- @isset($explanation) -
-

Explanation

-
- {{ $explanation }} -
-
- @endisset
diff --git a/resources/views/layouts/boarding.blade.php b/resources/views/layouts/boarding.blade.php index 67c1cc998..e0b5f49a3 100644 --- a/resources/views/layouts/boarding.blade.php +++ b/resources/views/layouts/boarding.blade.php @@ -1,6 +1,6 @@ @extends('layouts.base') @section('body') -
+
{{ $slot }}
@parent diff --git a/resources/views/livewire/boarding/index.blade.php b/resources/views/livewire/boarding/index.blade.php index 68b328b30..faee9883b 100644 --- a/resources/views/livewire/boarding/index.blade.php +++ b/resources/views/livewire/boarding/index.blade.php @@ -1,400 +1,737 @@ @php use App\Enums\ProxyTypes; @endphp Onboarding | Coolify - -
-
- @if ($currentState === 'welcome') -

Welcome to Coolify

-
Let me help you set up the basics.
-
- Get - Started - -
- @elseif ($currentState === 'explanation') - - - Coolify is an all-in-one application to automate tasks on your servers, deploy applications with - Git - integrations, deploy databases and services, monitor these resources with notifications and - alerts - without vendor lock-in.
- Coolify Home. -

- - -
- -

- You don't need to manage your servers anymore. - Coolify does - it for you. -

-

- All configurations are stored on your servers, so - everything works without a connection to Coolify (except integrations and automations). -

-

- You can get notified on your favourite platforms - (Discord, - Telegram, Email, etc.) when something goes wrong, or an action is needed from your side. -

-
- - Next - - -
- @elseif ($currentState === 'select-server-type') - - - Do you want to deploy your resources to your - - or to a - ? - - - Localhost - - - Remote Server - - - @if (!$serverReachable) -
-

Server is not reachable

-

Please check the connection details below and correct them if they are - incorrect.

- -
- -
- -

- Non-root user is experimental: - docs -

-
-
- -
-

If the connection details are correct, please ensure:

-
    -
  • The correct public key is in your ~/.ssh/authorized_keys - file for the specified user
  • -
  • Or skip the boarding process and manually add a new private key to Coolify and - the server
  • -
-
- -

- For more help, check this documentation. -

- - - - - Check Again - -
- @endif -
- -

Servers are the main building blocks, as they will host your applications, databases, - services, called resources. Any CPU intensive process will use the server's CPU where you - are deploying your resources.

-

- is the server where Coolify is running on. It is not - recommended to use one server - for everything. -

-

- is a server reachable through SSH. It can be hosted - at home, or from any cloud - provider. -

-
-
- @elseif ($currentState === 'private-key') - - - Do you have your own SSH Private Key? - - - Yes - - No (create one for me) - - @if (count($privateKeys) > 0) -
- - @foreach ($privateKeys as $privateKey) - - @endforeach - - Use this SSH Key -
- @endif -
- -

SSH Keys are used to connect to a remote server through a secure shell, called SSH.

-

You can use your own ssh private key, or you can let Coolify to create one for you.

-

In both ways, you need to add the public version of your ssh private key to the remote - server's - ~/.ssh/authorized_keys file. -

-
-
- @elseif ($currentState === 'select-existing-server') - - - There are already servers available for your Team. Do you want to use one of them? - - -
-
- No - (create one for me) - -
-
-
- - @foreach ($servers as $server) - - @endforeach - - Use this Server -
-
+ +
+
+ @if ($currentState === 'welcome') +
+
+

Welcome to Coolify

+

+ Connect your first server and start deploying in minutes +

- @if (!$serverReachable) -
-

Server is not reachable

-

Please check the connection details below and correct them if they are - incorrect.

-
- +
+

+ What You'll Set Up +

+
+
+
+ + + +
- -

- Non-root user is experimental: - docs -

+
Server Connection
+
Connect via SSH to deploy your resources +
- -
-

If the connection details are correct, please ensure:

-
    -
  • The correct public key is in your ~/.ssh/authorized_keys - file for the specified user
  • -
  • Or skip the boarding process and manually add a new private key to Coolify and - the server
  • -
-
- -

- For more help, check this documentation. -

- - - - - Check again - -
- @endif - - -

Private Keys are used to connect to a remote server through a secure shell, called SSH.

-

You can use your own private key, or you can let Coolify to create one for you.

-

In both ways, you need to add the public version of your private key to the remote server's - ~/.ssh/authorized_keys file. -

-
- - @elseif ($currentState === 'create-private-key') - - - Please let me know your key details. - - -
- - - - @if ($privateKeyType === 'create') - - ACTION REQUIRED: Copy the 'Public Key' to your - server's - ~/.ssh/authorized_keys - file. - @endif - Save - -
- -

Private Keys are used to connect to a remote server through a secure shell, called SSH.

-

You can use your own private key, or you can let Coolify to create one for you.

-

In both ways, you need to add the public version of your private key to the remote server's - ~/.ssh/authorized_keys file. -

-
-
- @elseif ($currentState === 'create-server') - - - Please let me know your server details. - - -
- - - -
- -
- +
+
+ + + +
- -
Non-root user is - experimental: docs. +
Docker Environment
+
Automated installation and configuration +
+
+
+
+
+ + + +
+
+
Project Structure
+
Organize your applications and resources
- Continue - - - - @elseif ($currentState === 'validate-server') - - - I need to validate your server (connection, Docker Engine, etc) and configure if something is - missing for me. Are you okay with this? - - - - Validate & configure - - - - - Let's do it! - - - - -

This will install the latest Docker Engine on your server, configure a few things to be able - to run optimal.

Minimum Docker Engine version is: {{ $minDockerVersion }}

To - manually install - Docker - Engine, check this - documentation.

-
-
- @elseif ($currentState === 'create-project') - - - @if (count($projects) > 0) - You already have some projects. Do you want to use one of them or should I create a new one - for - you? - @else - Let's create an initial project for you. You can change all the details later on. - @endif - - - Create new - project! -
- @if (count($projects) > 0) -
- - @foreach ($projects as $project) - - @endforeach - - Use this Project -
- @endif
-
- -

Projects contain several resources combined into one virtual group. There are no - limitations on the number of projects you can add.

-

Each project should have at least one environment, this allows you to create a production & - staging version of the same application, but grouped separately.

-
-
- @elseif ($currentState === 'create-resource') - - - Let's go to the new resource page, where you can create your first resource. - - -
Let's do - it!
-
- -

A resource could be an application, a database or a service (like WordPress).

-
-
- @endif -
-
-
-
Skip - onboarding
-
Restart - onboarding
-
- - -
- Feedback + +
+ + Start Setup + +
-
- -
-
-
+ @elseif ($currentState === 'explanation') + + + + Coolify automates deployment and infrastructure management on your own servers. Deploy applications + from Git, manage databases, and monitor everything—without vendor lock-in. + + +

+ Coolify handles server configuration, Docker management, + and + deployments automatically. +

+

+ All data and configurations live on your infrastructure. + Works offline except for external integrations. +

+

+ Get real-time notifications via Discord, Telegram, + Email, and other platforms. +

+
+ + + Continue + + +
+ @elseif ($currentState === 'select-server-type') + + + + Select where to deploy your applications and databases. You can add more servers later. + + +
+ + + + + + @can('viewAny', App\Models\CloudProviderToken::class) + + +
+
+
+ + + + + + Recommended + +
+
+

Hetzner Cloud

+

+ Deploy servers directly from your Hetzner Cloud account. +

+
+
+
+
+ +
+ @endcan +
+ + @if (!$serverReachable) +
+

Server is not reachable

+

Please check the connection details below and correct them if they are + incorrect.

+ +
+ +
+ +

+ Non-root user is experimental: + docs +

+
+
+ +
+

If the connection details are correct, please ensure:

+
    +
  • The correct public key is in your ~/.ssh/authorized_keys + file for the specified user
  • +
  • Or skip the boarding process and manually add a new private key to Coolify and + the server
  • +
+
+ +

+ For more help, check this documentation. +

+ + + + + Check Again + +
+ @endif +
+ +

+ host your applications, databases, and services (collectively + called resources). All CPU-intensive operations run on the target server. +

+

+ The machine running Coolify. Not recommended for production + workloads due to resource contention. +

+

+ Any SSH-accessible server—cloud providers (AWS, Hetzner, + DigitalOcean), bare metal, or self-hosted infrastructure. +

+
+
+ @elseif ($currentState === 'private-key') + + + + Configure SSH key-based authentication for secure server access. + + + @if ($privateKeys && $privateKeys->count() > 0) +
+
+
+ + @foreach ($privateKeys as $privateKey) + + @endforeach + + Use Selected Key +
+
+
+
+
+
+
+
+ OR +
+
+
+
+ @endif +
+ +
+ + + +
+

Use Existing Key

+

I have my own SSH key

+
+
+
+ +
+ + + +
+

Generate New Key

+

Create ED25519 key pair

+
+
+
+
+
+ +

+ Uses public-key cryptography for secure, + password-less server access. +

+

+ Add the public key to your server's + ~/.ssh/authorized_keys + file. +

+

+ Coolify generates ED25519 keys by default for optimal + security and performance. +

+
+
+ @elseif ($currentState === 'create-private-key') + + + + Configure your SSH key for server authentication. + + +
+ + + @if ($privateKeyType === 'create') + + + @else + + @endif + @if ($privateKeyType === 'create') +
+
+ + + +
+

Action Required

+

+ Copy the public key above and add it to your server's + ~/.ssh/authorized_keys + file. +

+
+
+
+ @endif + Save SSH Key + +
+ +

+ Private keys are encrypted at rest in Coolify's database. +

+

+ Deploy the public key to + ~/.ssh/authorized_keys + on your target server for the specified user. +

+

+ Supports RSA, ED25519, ECDSA, and DSA key types in OpenSSH + format. +

+
+
+ @elseif ($currentState === 'create-server') + + + + Provide connection details for your remote server. + + +
+
+ + +
+ + +
+ +
+ +
+ +

+ Non-root user support is experimental. + Learn + more +

+
+
+
+ Validate Connection + +
+ +

+ Server must be accessible via SSH on the + specified port (default 22). +

+

+ Use IP addresses for direct connections or ensure + DNS resolution is configured. +

+

+ Root or sudo-enabled users recommended for full + Docker + management capabilities. +

+
+
+ @elseif ($currentState === 'validate-server') + + + + Coolify will automatically install Docker {{ $minDockerVersion }}+ if not present. + + +
+
+

Validation Steps

+
+
+
+ + + +
+
+
Test SSH Connection
+
Verify key-based authentication
+
+
+
+
+ + + +
+
+
Check OS Compatibility +
+
Verify supported Linux distribution +
+
+
+
+
+ + + +
+
+
Install Docker Engine
+
Auto-install if version + {{ $minDockerVersion }}+ not + found +
+
+
+
+
+ + + +
+
+
Configure Network
+
Set up Docker networks and proxy +
+
+
+
+
+ + + Server Validation + + + + + Start Validation + + +
+
+ +

+ Coolify installs Docker Engine, Docker Compose, and + configures system requirements automatically. +

+

+ Minimum Docker Engine {{ $minDockerVersion }}.x + required. + Manual installation guide +

+

+ Sets up Docker networks, proxy configuration, and + resource monitoring. +

+
+
+ @elseif ($currentState === 'create-project') + + + + @if ($projects && $projects->count() > 0) + You have existing projects. Select one or create a new project to organize your resources. + @else + Create your first project to organize applications, databases, and services. + @endif + + +
+ + Create "My First Project" + + + @if ($projects && $projects->count() > 0) +
+
+
+
+
+ Or use existing +
+
+
+ + @foreach ($projects as $project) + + @endforeach + + Use Selected Project +
+ @endif +
+
+ +

+ Group related resources (apps, databases, + services) + into logical projects. +

+

+ Each project includes a production environment by + default. + Add staging, development, or custom environments as needed. +

+

+ Projects inherit team permissions and can be managed + collaboratively. +

+
+
+ @elseif ($currentState === 'create-resource') + +
+
+
+ + + +
+

Setup Complete!

+

+ Your server is connected and ready. Start deploying your first resource. +

+
+ +
+

+ What's Configured +

+
+
+
+ + + +
+
+
Server: {{ $createdServer->name }} +
+
{{ $createdServer->ip }}
+
+
+
+
+ + + +
+
+
Project: + {{ $createdProject->name }} +
+
Production environment ready
+
+
+
+
+ + + +
+
+
Docker Engine
+
Installed and running
+
+
+
+
+ +
+ + Deploy Your First Resource + + +
+
+ @endif +
+ + @if ($currentState !== 'welcome' && $currentState !== 'create-resource') +
+
+ + +
+ + + + + + +
+ @endif +
\ No newline at end of file