feat(ca-certificate): add CA certificate management functionality with UI integration and routing
This commit is contained in:
		@@ -43,7 +43,7 @@ class Terminal extends Component
 | 
			
		||||
    #[On('send-terminal-command')]
 | 
			
		||||
    public function sendTerminalCommand($isContainer, $identifier, $serverUuid)
 | 
			
		||||
    {
 | 
			
		||||
        $server = Server::ownedByCurrentTeam()->whereUuid($serverUuid)->firstOrFail();
 | 
			
		||||
        $server = Server::ownedByCurrentTeam()->whereUuid($serverUuid)->where('settings.is_terminal_enabled', true)->firstOrFail();
 | 
			
		||||
 | 
			
		||||
        if ($isContainer) {
 | 
			
		||||
            // Validate container identifier format (alphanumeric, dashes, and underscores only)
 | 
			
		||||
 
 | 
			
		||||
@@ -2,12 +2,8 @@
 | 
			
		||||
 | 
			
		||||
namespace App\Livewire\Server;
 | 
			
		||||
 | 
			
		||||
use App\Helpers\SslHelper;
 | 
			
		||||
use App\Jobs\RegenerateSslCertJob;
 | 
			
		||||
use App\Models\InstanceSettings;
 | 
			
		||||
use App\Models\Server;
 | 
			
		||||
use App\Models\SslCertificate;
 | 
			
		||||
use Carbon\Carbon;
 | 
			
		||||
use Illuminate\Support\Facades\Auth;
 | 
			
		||||
use Illuminate\Support\Facades\Hash;
 | 
			
		||||
use Livewire\Attributes\Validate;
 | 
			
		||||
@@ -17,14 +13,6 @@ class Advanced extends Component
 | 
			
		||||
{
 | 
			
		||||
    public Server $server;
 | 
			
		||||
 | 
			
		||||
    public ?SslCertificate $caCertificate = null;
 | 
			
		||||
 | 
			
		||||
    public $showCertificate = false;
 | 
			
		||||
 | 
			
		||||
    public $certificateContent = '';
 | 
			
		||||
 | 
			
		||||
    public ?Carbon $certificateValidUntil = null;
 | 
			
		||||
 | 
			
		||||
    public array $parameters = [];
 | 
			
		||||
 | 
			
		||||
    #[Validate(['string'])]
 | 
			
		||||
@@ -48,27 +36,12 @@ class Advanced extends Component
 | 
			
		||||
            $this->server = Server::ownedByCurrentTeam()->whereUuid($server_uuid)->firstOrFail();
 | 
			
		||||
            $this->parameters = get_route_parameters();
 | 
			
		||||
            $this->syncData();
 | 
			
		||||
            $this->loadCaCertificate();
 | 
			
		||||
 | 
			
		||||
        } catch (\Throwable) {
 | 
			
		||||
            return redirect()->route('server.index');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function loadCaCertificate()
 | 
			
		||||
    {
 | 
			
		||||
        $this->caCertificate = SslCertificate::where('server_id', $this->server->id)->where('is_ca_certificate', true)->first();
 | 
			
		||||
 | 
			
		||||
        if ($this->caCertificate) {
 | 
			
		||||
            $this->certificateContent = $this->caCertificate->ssl_certificate;
 | 
			
		||||
            $this->certificateValidUntil = $this->caCertificate->valid_until;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function toggleCertificate()
 | 
			
		||||
    {
 | 
			
		||||
        $this->showCertificate = ! $this->showCertificate;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function toggleTerminal($password)
 | 
			
		||||
    {
 | 
			
		||||
        try {
 | 
			
		||||
@@ -100,78 +73,6 @@ class Advanced extends Component
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function saveCaCertificate()
 | 
			
		||||
    {
 | 
			
		||||
        try {
 | 
			
		||||
            if (! $this->certificateContent) {
 | 
			
		||||
                throw new \Exception('Certificate content cannot be empty.');
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (! openssl_x509_read($this->certificateContent)) {
 | 
			
		||||
                throw new \Exception('Invalid certificate format.');
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if ($this->caCertificate) {
 | 
			
		||||
                $this->caCertificate->ssl_certificate = $this->certificateContent;
 | 
			
		||||
                $this->caCertificate->save();
 | 
			
		||||
 | 
			
		||||
                $this->loadCaCertificate();
 | 
			
		||||
 | 
			
		||||
                $this->writeCertificateToServer();
 | 
			
		||||
 | 
			
		||||
                dispatch(new RegenerateSslCertJob(
 | 
			
		||||
                    server_id: $this->server->id,
 | 
			
		||||
                    force_regeneration: true
 | 
			
		||||
                ));
 | 
			
		||||
            }
 | 
			
		||||
            $this->dispatch('success', 'CA Certificate saved successfully.');
 | 
			
		||||
        } catch (\Throwable $e) {
 | 
			
		||||
            return handleError($e, $this);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function regenerateCaCertificate()
 | 
			
		||||
    {
 | 
			
		||||
        try {
 | 
			
		||||
            SslHelper::generateSslCertificate(
 | 
			
		||||
                commonName: 'Coolify CA Certificate',
 | 
			
		||||
                serverId: $this->server->id,
 | 
			
		||||
                isCaCertificate: true,
 | 
			
		||||
                validityDays: 10 * 365
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            $this->loadCaCertificate();
 | 
			
		||||
 | 
			
		||||
            $this->writeCertificateToServer();
 | 
			
		||||
 | 
			
		||||
            dispatch(new RegenerateSslCertJob(
 | 
			
		||||
                server_id: $this->server->id,
 | 
			
		||||
                force_regeneration: true
 | 
			
		||||
            ));
 | 
			
		||||
 | 
			
		||||
            $this->loadCaCertificate();
 | 
			
		||||
            $this->dispatch('success', 'CA Certificate regenerated successfully.');
 | 
			
		||||
        } catch (\Throwable $e) {
 | 
			
		||||
            return handleError($e, $this);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function writeCertificateToServer()
 | 
			
		||||
    {
 | 
			
		||||
        $caCertPath = config('constants.coolify.base_config_path').'/ssl/';
 | 
			
		||||
 | 
			
		||||
        $commands = collect([
 | 
			
		||||
            "mkdir -p $caCertPath",
 | 
			
		||||
            "chown -R 9999:root $caCertPath",
 | 
			
		||||
            "chmod -R 700 $caCertPath",
 | 
			
		||||
            "rm -rf $caCertPath/coolify-ca.crt",
 | 
			
		||||
            "echo '{$this->certificateContent}' > $caCertPath/coolify-ca.crt",
 | 
			
		||||
            "chmod 644 $caCertPath/coolify-ca.crt",
 | 
			
		||||
        ]);
 | 
			
		||||
 | 
			
		||||
        remote_process($commands, $this->server);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function syncData(bool $toModel = false)
 | 
			
		||||
    {
 | 
			
		||||
        if ($toModel) {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										128
									
								
								app/Livewire/Server/CaCertificate/Show.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								app/Livewire/Server/CaCertificate/Show.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,128 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace App\Livewire\Server\CaCertificate;
 | 
			
		||||
 | 
			
		||||
use App\Helpers\SslHelper;
 | 
			
		||||
use App\Jobs\RegenerateSslCertJob;
 | 
			
		||||
use App\Models\Server;
 | 
			
		||||
use App\Models\SslCertificate;
 | 
			
		||||
use Illuminate\Support\Carbon;
 | 
			
		||||
use Livewire\Attributes\Locked;
 | 
			
		||||
use Livewire\Component;
 | 
			
		||||
 | 
			
		||||
class Show extends Component
 | 
			
		||||
{
 | 
			
		||||
    #[Locked]
 | 
			
		||||
    public Server $server;
 | 
			
		||||
 | 
			
		||||
    public ?SslCertificate $caCertificate = null;
 | 
			
		||||
 | 
			
		||||
    public $showCertificate = false;
 | 
			
		||||
 | 
			
		||||
    public $certificateContent = '';
 | 
			
		||||
 | 
			
		||||
    public ?Carbon $certificateValidUntil = null;
 | 
			
		||||
 | 
			
		||||
    public function mount(string $server_uuid)
 | 
			
		||||
    {
 | 
			
		||||
        try {
 | 
			
		||||
            $this->server = Server::ownedByCurrentTeam()->whereUuid($server_uuid)->firstOrFail();
 | 
			
		||||
            $this->loadCaCertificate();
 | 
			
		||||
        } catch (\Throwable $e) {
 | 
			
		||||
            return redirect()->route('server.index');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function loadCaCertificate()
 | 
			
		||||
    {
 | 
			
		||||
        $this->caCertificate = SslCertificate::where('server_id', $this->server->id)->where('is_ca_certificate', true)->first();
 | 
			
		||||
 | 
			
		||||
        if ($this->caCertificate) {
 | 
			
		||||
            $this->certificateContent = $this->caCertificate->ssl_certificate;
 | 
			
		||||
            $this->certificateValidUntil = $this->caCertificate->valid_until;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function toggleCertificate()
 | 
			
		||||
    {
 | 
			
		||||
        $this->showCertificate = ! $this->showCertificate;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function saveCaCertificate()
 | 
			
		||||
    {
 | 
			
		||||
        try {
 | 
			
		||||
            if (! $this->certificateContent) {
 | 
			
		||||
                throw new \Exception('Certificate content cannot be empty.');
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (! openssl_x509_read($this->certificateContent)) {
 | 
			
		||||
                throw new \Exception('Invalid certificate format.');
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if ($this->caCertificate) {
 | 
			
		||||
                $this->caCertificate->ssl_certificate = $this->certificateContent;
 | 
			
		||||
                $this->caCertificate->save();
 | 
			
		||||
 | 
			
		||||
                $this->loadCaCertificate();
 | 
			
		||||
 | 
			
		||||
                $this->writeCertificateToServer();
 | 
			
		||||
 | 
			
		||||
                dispatch(new RegenerateSslCertJob(
 | 
			
		||||
                    server_id: $this->server->id,
 | 
			
		||||
                    force_regeneration: true
 | 
			
		||||
                ));
 | 
			
		||||
            }
 | 
			
		||||
            $this->dispatch('success', 'CA Certificate saved successfully.');
 | 
			
		||||
        } catch (\Throwable $e) {
 | 
			
		||||
            return handleError($e, $this);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function regenerateCaCertificate()
 | 
			
		||||
    {
 | 
			
		||||
        try {
 | 
			
		||||
            SslHelper::generateSslCertificate(
 | 
			
		||||
                commonName: 'Coolify CA Certificate',
 | 
			
		||||
                serverId: $this->server->id,
 | 
			
		||||
                isCaCertificate: true,
 | 
			
		||||
                validityDays: 10 * 365
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            $this->loadCaCertificate();
 | 
			
		||||
 | 
			
		||||
            $this->writeCertificateToServer();
 | 
			
		||||
 | 
			
		||||
            dispatch(new RegenerateSslCertJob(
 | 
			
		||||
                server_id: $this->server->id,
 | 
			
		||||
                force_regeneration: true
 | 
			
		||||
            ));
 | 
			
		||||
 | 
			
		||||
            $this->loadCaCertificate();
 | 
			
		||||
            $this->dispatch('success', 'CA Certificate regenerated successfully.');
 | 
			
		||||
        } catch (\Throwable $e) {
 | 
			
		||||
            return handleError($e, $this);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function writeCertificateToServer()
 | 
			
		||||
    {
 | 
			
		||||
        $caCertPath = config('constants.coolify.base_config_path').'/ssl/';
 | 
			
		||||
 | 
			
		||||
        $commands = collect([
 | 
			
		||||
            "mkdir -p $caCertPath",
 | 
			
		||||
            "chown -R 9999:root $caCertPath",
 | 
			
		||||
            "chmod -R 700 $caCertPath",
 | 
			
		||||
            "rm -rf $caCertPath/coolify-ca.crt",
 | 
			
		||||
            "echo '{$this->certificateContent}' > $caCertPath/coolify-ca.crt",
 | 
			
		||||
            "chmod 644 $caCertPath/coolify-ca.crt",
 | 
			
		||||
        ]);
 | 
			
		||||
 | 
			
		||||
        remote_process($commands, $this->server);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function render()
 | 
			
		||||
    {
 | 
			
		||||
        return view('livewire.server.ca-certificate.show');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -9,6 +9,9 @@
 | 
			
		||||
    <a class="menu-item {{ $activeMenu === 'private-key' ? 'menu-item-active' : '' }}"
 | 
			
		||||
        href="{{ route('server.private-key', ['server_uuid' => $server->uuid]) }}">Private Key
 | 
			
		||||
    </a>
 | 
			
		||||
    <a class="menu-item {{ $activeMenu === 'ca-certificate' ? 'menu-item-active' : '' }}"
 | 
			
		||||
        href="{{ route('server.ca-certificate', ['server_uuid' => $server->uuid]) }}">CA Certificate
 | 
			
		||||
    </a>
 | 
			
		||||
    @if (!$server->isLocalhost())
 | 
			
		||||
        <a class="menu-item {{ $activeMenu === 'cloudflare-tunnels' ? 'menu-item-active' : '' }}"
 | 
			
		||||
            href="{{ route('server.cloudflare-tunnels', ['server_uuid' => $server->uuid]) }}">Cloudflare
 | 
			
		||||
 
 | 
			
		||||
@@ -69,7 +69,6 @@
 | 
			
		||||
 | 
			
		||||
                <div class="flex flex-col">
 | 
			
		||||
                    <h3>Builds</h3>
 | 
			
		||||
                    <div>Customize the build process.</div>
 | 
			
		||||
                    <div class="flex flex-wrap gap-2 sm:flex-nowrap pt-4">
 | 
			
		||||
                        <x-forms.input id="concurrentBuilds" label="Number of concurrent builds" required
 | 
			
		||||
                            helper="You can specify the number of simultaneous build processes/deployments that should run concurrently." />
 | 
			
		||||
@@ -78,85 +77,6 @@
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <div class="flex flex-col gap-4 pt-8">
 | 
			
		||||
                <h3>CA SSL Certificate</h3>
 | 
			
		||||
                <div class="flex gap-2">
 | 
			
		||||
                    <x-modal-confirmation title="Confirm changing of CA Certificate?" buttonTitle="Save Certificate"
 | 
			
		||||
                        submitAction="saveCaCertificate" :actions="[
 | 
			
		||||
                            'This will overwrite the existing CA certificate at /data/coolify/ssl/coolify-ca.crt with your custom CA certificate.',
 | 
			
		||||
                            'This will regenerate all SSL certificates for databases on this server and it will sign them with your custom CA.',
 | 
			
		||||
                            'You must manually redeploy all your databases on this server so that they use the new SSL certificates singned with your new CA certificate.',
 | 
			
		||||
                            'Because of caching, you probably also need to redeploy all your resources on this server that are using this CA certificate.',
 | 
			
		||||
                        ]"
 | 
			
		||||
                        confirmationText="/data/coolify/ssl/coolify-ca.crt" shortConfirmationLabel="CA Certificate Path"
 | 
			
		||||
                        step3ButtonText="Save Certificate">
 | 
			
		||||
                    </x-modal-confirmation>
 | 
			
		||||
                    <x-modal-confirmation title="Confirm Regenerate Certificate?" buttonTitle="Regenerate Certificate"
 | 
			
		||||
                        submitAction="regenerateCaCertificate" :actions="[
 | 
			
		||||
                            'This will generate a new CA certificate at /data/coolify/ssl/coolify-ca.crt and replace the existing one.',
 | 
			
		||||
                            'This will regenerate all SSL certificates for databases on this server and it will sign them with the new CA certificate.',
 | 
			
		||||
                            'You must manually redeploy all your databases on this server so that they use the new SSL certificates singned with the new CA certificate.',
 | 
			
		||||
                            'Because of caching, you probably also need to redeploy all your resources on this server that are using this CA certificate.',
 | 
			
		||||
                        ]"
 | 
			
		||||
                        confirmationText="/data/coolify/ssl/coolify-ca.crt" shortConfirmationLabel="CA Certificate Path"
 | 
			
		||||
                        step3ButtonText="Regenerate Certificate">
 | 
			
		||||
                    </x-modal-confirmation>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="space-y-4">
 | 
			
		||||
                    <div class="text-sm">
 | 
			
		||||
                        <p class="font-medium mb-2">Recommended Configuration:</p>
 | 
			
		||||
                        <ul class="list-disc pl-5 space-y-1">
 | 
			
		||||
                            <li>Mount this CA certificate of Coolify into all containers that need to connect to one of
 | 
			
		||||
                                your databases over SSL. You can see and copy the bind mount below.</li>
 | 
			
		||||
                            <li>Read more when and why this is needed <a class="underline"
 | 
			
		||||
                                    href="https://coolify.io/docs/databases/ssl" target="_blank">here</a>.</li>
 | 
			
		||||
                        </ul>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div class="relative">
 | 
			
		||||
                        <x-forms.copy-button
 | 
			
		||||
                            text="- /data/coolify/ssl/coolify-ca.crt:/etc/ssl/certs/coolify-ca.crt:ro" />
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div>
 | 
			
		||||
                    <div class="flex items-center justify-between mb-2">
 | 
			
		||||
                        <div class="flex items-center gap-2">
 | 
			
		||||
                            <span class="text-sm">CA Certificate</span>
 | 
			
		||||
                            @if ($certificateValidUntil)
 | 
			
		||||
                                <span class="text-sm">(Valid until:
 | 
			
		||||
                                    @if (now()->gt($certificateValidUntil))
 | 
			
		||||
                                        <span class="text-red-500">{{ $certificateValidUntil->format('d.m.Y H:i:s') }} -
 | 
			
		||||
                                            Expired)</span>
 | 
			
		||||
                                    @elseif(now()->addDays(30)->gt($certificateValidUntil))
 | 
			
		||||
                                        <span class="text-red-500">{{ $certificateValidUntil->format('d.m.Y H:i:s') }} -
 | 
			
		||||
                                            Expiring soon)</span>
 | 
			
		||||
                                    @else
 | 
			
		||||
                                        <span>{{ $certificateValidUntil->format('d.m.Y H:i:s') }})</span>
 | 
			
		||||
                                    @endif
 | 
			
		||||
                                </span>
 | 
			
		||||
                            @endif
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <x-forms.button wire:click="toggleCertificate" type="button" class="py-1! px-2! text-sm">
 | 
			
		||||
                            {{ $showCertificate ? 'Hide' : 'Show' }}
 | 
			
		||||
                        </x-forms.button>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    @if ($showCertificate)
 | 
			
		||||
                        <textarea class="w-full h-[370px] input" wire:model="certificateContent"
 | 
			
		||||
                            placeholder="Paste or edit CA certificate content here..."></textarea>
 | 
			
		||||
                    @else
 | 
			
		||||
                        <div class="w-full h-[370px] input">
 | 
			
		||||
                            <div class="h-full flex flex-col items-center justify-center text-gray-300">
 | 
			
		||||
                                <div class="mb-2">
 | 
			
		||||
                                    ━━━━━━━━ CERTIFICATE CONTENT ━━━━━━━━
 | 
			
		||||
                                </div>
 | 
			
		||||
                                <div class="text-sm">
 | 
			
		||||
                                    Click "Show" to view or edit
 | 
			
		||||
                                </div>
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    @endif
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </form>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,88 @@
 | 
			
		||||
<div>
 | 
			
		||||
    <x-slot:title>
 | 
			
		||||
        {{ data_get_str($server, 'name')->limit(10) }} > CA Certificate | Coolify
 | 
			
		||||
    </x-slot>
 | 
			
		||||
    <x-server.navbar :server="$server" />
 | 
			
		||||
    <div class="flex flex-col h-full gap-8 sm:flex-row">
 | 
			
		||||
        <x-server.sidebar :server="$server" activeMenu="ca-certificate" />
 | 
			
		||||
        <div class="flex flex-col gap-4">
 | 
			
		||||
            <div class="flex items-center gap-2">
 | 
			
		||||
                <h3>CA SSL Certificate</h3>
 | 
			
		||||
                <div class="flex gap-2">
 | 
			
		||||
                    <x-modal-confirmation title="Confirm changing of CA Certificate?" buttonTitle="Save"
 | 
			
		||||
                        submitAction="saveCaCertificate" :actions="[
 | 
			
		||||
                            'This will overwrite the existing CA certificate at /data/coolify/ssl/coolify-ca.crt with your custom CA certificate.',
 | 
			
		||||
                            'This will regenerate all SSL certificates for databases on this server and it will sign them with your custom CA.',
 | 
			
		||||
                            'You must manually redeploy all your databases on this server so that they use the new SSL certificates singned with your new CA certificate.',
 | 
			
		||||
                            'Because of caching, you probably also need to redeploy all your resources on this server that are using this CA certificate.',
 | 
			
		||||
                        ]"
 | 
			
		||||
                        confirmationText="/data/coolify/ssl/coolify-ca.crt" shortConfirmationLabel="CA Certificate Path"
 | 
			
		||||
                        step3ButtonText="Save Certificate">
 | 
			
		||||
                    </x-modal-confirmation>
 | 
			
		||||
                    <x-modal-confirmation title="Confirm Regenerate Certificate?" buttonTitle="Regenerate "
 | 
			
		||||
                        submitAction="regenerateCaCertificate" :actions="[
 | 
			
		||||
                            'This will generate a new CA certificate at /data/coolify/ssl/coolify-ca.crt and replace the existing one.',
 | 
			
		||||
                            'This will regenerate all SSL certificates for databases on this server and it will sign them with the new CA certificate.',
 | 
			
		||||
                            'You must manually redeploy all your databases on this server so that they use the new SSL certificates singned with the new CA certificate.',
 | 
			
		||||
                            'Because of caching, you probably also need to redeploy all your resources on this server that are using this CA certificate.',
 | 
			
		||||
                        ]"
 | 
			
		||||
                        confirmationText="/data/coolify/ssl/coolify-ca.crt" shortConfirmationLabel="CA Certificate Path"
 | 
			
		||||
                        step3ButtonText="Regenerate Certificate">
 | 
			
		||||
                    </x-modal-confirmation>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="space-y-4">
 | 
			
		||||
                <div class="text-sm">
 | 
			
		||||
                    <p class="font-medium mb-2">Recommended Configuration:</p>
 | 
			
		||||
                    <ul class="list-disc pl-5 space-y-1">
 | 
			
		||||
                        <li>Mount this CA certificate of Coolify into all containers that need to connect to one of
 | 
			
		||||
                            your databases over SSL. You can see and copy the bind mount below.</li>
 | 
			
		||||
                        <li>Read more when and why this is needed <a class="underline dark:text-white"
 | 
			
		||||
                                href="https://coolify.io/docs/databases/ssl" target="_blank">here</a>.</li>
 | 
			
		||||
                    </ul>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="relative">
 | 
			
		||||
                    <x-forms.copy-button text="- /data/coolify/ssl/coolify-ca.crt:/etc/ssl/certs/coolify-ca.crt:ro" />
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div>
 | 
			
		||||
                <div class="flex items-center justify-between mb-2">
 | 
			
		||||
                    <div class="flex items-center gap-2">
 | 
			
		||||
                        <span class="text-sm">CA Certificate</span>
 | 
			
		||||
                        @if ($certificateValidUntil)
 | 
			
		||||
                            <span class="text-sm">(Valid until:
 | 
			
		||||
                                @if (now()->gt($certificateValidUntil))
 | 
			
		||||
                                    <span class="text-red-500">{{ $certificateValidUntil->format('d.m.Y H:i:s') }} -
 | 
			
		||||
                                        Expired)</span>
 | 
			
		||||
                                @elseif(now()->addDays(30)->gt($certificateValidUntil))
 | 
			
		||||
                                    <span class="text-red-500">{{ $certificateValidUntil->format('d.m.Y H:i:s') }} -
 | 
			
		||||
                                        Expiring soon)</span>
 | 
			
		||||
                                @else
 | 
			
		||||
                                    <span>{{ $certificateValidUntil->format('d.m.Y H:i:s') }})</span>
 | 
			
		||||
                                @endif
 | 
			
		||||
                            </span>
 | 
			
		||||
                        @endif
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <x-forms.button wire:click="toggleCertificate" type="button" class="py-1! px-2! text-sm">
 | 
			
		||||
                        {{ $showCertificate ? 'Hide' : 'Show' }}
 | 
			
		||||
                    </x-forms.button>
 | 
			
		||||
                </div>
 | 
			
		||||
                @if ($showCertificate)
 | 
			
		||||
                    <textarea class="w-full h-[370px] input" wire:model="certificateContent"
 | 
			
		||||
                        placeholder="Paste or edit CA certificate content here..."></textarea>
 | 
			
		||||
                @else
 | 
			
		||||
                    <div class="w-full h-[370px] input">
 | 
			
		||||
                        <div class="h-full flex flex-col items-center justify-center text-gray-300">
 | 
			
		||||
                            <div class="mb-2">
 | 
			
		||||
                                ━━━━━━━━ CERTIFICATE CONTENT ━━━━━━━━
 | 
			
		||||
                            </div>
 | 
			
		||||
                            <div class="text-sm">
 | 
			
		||||
                                Click "Show" to view or edit
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                @endif
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
@@ -37,6 +37,7 @@ use App\Livewire\Security\ApiTokens;
 | 
			
		||||
use App\Livewire\Security\PrivateKey\Index as SecurityPrivateKeyIndex;
 | 
			
		||||
use App\Livewire\Security\PrivateKey\Show as SecurityPrivateKeyShow;
 | 
			
		||||
use App\Livewire\Server\Advanced as ServerAdvanced;
 | 
			
		||||
use App\Livewire\Server\CaCertificate\Show as CaCertificateShow;
 | 
			
		||||
use App\Livewire\Server\Charts as ServerCharts;
 | 
			
		||||
use App\Livewire\Server\CloudflareTunnels;
 | 
			
		||||
use App\Livewire\Server\Delete as DeleteServer;
 | 
			
		||||
@@ -242,6 +243,7 @@ Route::middleware(['auth', 'verified'])->group(function () {
 | 
			
		||||
        Route::get('/', ServerShow::class)->name('server.show');
 | 
			
		||||
        Route::get('/advanced', ServerAdvanced::class)->name('server.advanced');
 | 
			
		||||
        Route::get('/private-key', PrivateKeyShow::class)->name('server.private-key');
 | 
			
		||||
        Route::get('/ca-certificate', CaCertificateShow::class)->name('server.ca-certificate');
 | 
			
		||||
        Route::get('/resources', ResourcesShow::class)->name('server.resources');
 | 
			
		||||
        Route::get('/cloudflare-tunnels', CloudflareTunnels::class)->name('server.cloudflare-tunnels');
 | 
			
		||||
        Route::get('/destinations', ServerDestinations::class)->name('server.destinations');
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user