mirror of
https://github.com/coollabsio/coolify.git
synced 2026-09-27 17:55:59 -04:00
feat(domains): support per-domain internal port overrides (#11594)
This commit is contained in:
@@ -366,4 +366,48 @@
|
||||
|
||||
<x-domain-conflict-modal :conflicts="$domainConflicts" :showModal="$showDomainConflictModal"
|
||||
confirmAction="confirmDomainUsage" />
|
||||
|
||||
@if ($showPortWarningModal)
|
||||
<div x-data="{ modalOpen: true }"
|
||||
@keydown.escape.window="modalOpen = false; $wire.call('cancelUseUnknownPort')"
|
||||
class="relative z-40">
|
||||
<template x-teleport="body">
|
||||
<div x-show="modalOpen"
|
||||
class="fixed inset-0 z-99 flex min-h-full items-center justify-center overflow-y-auto p-4" x-cloak>
|
||||
<div class="absolute inset-0 bg-black/50 backdrop-blur-[2px]"></div>
|
||||
<div x-show="modalOpen" x-trap.inert.noscroll="modalOpen"
|
||||
class="application-settings-form application-settings-section relative w-full lg:min-w-[36rem] lg:max-w-2xl"
|
||||
style="box-shadow: 0 0 0 1px var(--coollabs-hairline), var(--shadow-modal)">
|
||||
<header>
|
||||
<h3>Use a different port?</h3>
|
||||
<button type="button"
|
||||
@click="modalOpen = false; $wire.call('cancelUseUnknownPort')"
|
||||
class="icon-button" aria-label="Close">
|
||||
<x-reicon name="x" class="size-4" />
|
||||
</button>
|
||||
</header>
|
||||
<div class="application-settings-section-body">
|
||||
<x-callout type="warning" title="Unrecognized internal port" class="mb-4">
|
||||
Port <strong>{{ $unrecognizedPort }}</strong> is not listed in Ports Exposes
|
||||
and is not used by any application domain. The proxy will still route to it,
|
||||
but the container may not be listening there.
|
||||
</x-callout>
|
||||
|
||||
<div class="mt-4 flex flex-wrap justify-end gap-2 border-t border-neutral-200 pt-4 dark:border-white/[0.08]">
|
||||
<x-forms.button type="button" canGate="update" :canResource="$application"
|
||||
@click="modalOpen = false; $wire.call('cancelUseUnknownPort')">
|
||||
Cancel
|
||||
</x-forms.button>
|
||||
<x-forms.button type="button" wire:click="confirmUseUnknownPort" canGate="update"
|
||||
:canResource="$application"
|
||||
@click="modalOpen = false" isError>
|
||||
Use this port anyway
|
||||
</x-forms.button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
@@ -398,7 +398,15 @@
|
||||
@endif
|
||||
|
||||
@if ($buildPack !== 'dockercompose')
|
||||
<x-application.settings-section id="networking-section" title="Networking" helper="Ports the container exposes, host port mappings and internal network aliases.">
|
||||
@php
|
||||
$applicationDomainsUrl = route('project.application.domains', [
|
||||
'project_uuid' => $application->environment->project->uuid,
|
||||
'environment_uuid' => $application->environment->uuid,
|
||||
'application_uuid' => $application->uuid,
|
||||
]);
|
||||
$portsExposesDomainHint = "You can also set a different internal port for each domain on the <a class='underline dark:text-white' href='{$applicationDomainsUrl}'>Domains</a> page.";
|
||||
@endphp
|
||||
<x-application.settings-section id="networking-section" title="Networking" helper="Ports the container exposes, host port mappings and internal network aliases. You can also set an internal port per domain.">
|
||||
@if ($this->detectedPortInfo)
|
||||
@if ($this->detectedPortInfo['isEmpty'])
|
||||
<div
|
||||
@@ -460,20 +468,30 @@
|
||||
</x-callout>
|
||||
@endif
|
||||
<div class="grid gap-4 lg:grid-cols-[14rem_16rem_minmax(0,1fr)]">
|
||||
<div class="min-w-0">
|
||||
@if ($isStatic || $buildPack === 'static')
|
||||
<x-forms.input id="portsExposes" label="Ports exposes" readonly
|
||||
:helper="$portsExposesDomainHint"
|
||||
canGate="update" :canResource="$application"
|
||||
x-bind:disabled="!canUpdate" />
|
||||
@else
|
||||
@if ($application->settings->is_container_label_readonly_enabled === false)
|
||||
<x-forms.input placeholder="3000,3001" id="portsExposes" label="Ports exposes" readonly
|
||||
helper="Readonly labels are disabled. You can set the ports manually in the labels section."
|
||||
:helper="'Readonly labels are disabled. You can set the ports manually in the labels section.<br><br>'.$portsExposesDomainHint"
|
||||
canGate="update" :canResource="$application"
|
||||
x-bind:disabled="!canUpdate" />
|
||||
@else
|
||||
<x-forms.input placeholder="3000,3001" id="portsExposes" label="Ports exposes"
|
||||
helper="A comma separated list of ports your application uses. The first port will be used as default healthcheck port if nothing defined in the Healthcheck menu. Be sure to set this correctly."
|
||||
:helper="'A comma separated list of ports your application uses. The first port will be used as default healthcheck port if nothing defined in the Healthcheck menu. Be sure to set this correctly.<br><br>'.$portsExposesDomainHint"
|
||||
canGate="update" :canResource="$application"
|
||||
x-bind:disabled="!canUpdate" />
|
||||
@endif
|
||||
@endif
|
||||
<p class="mt-1.5 text-xs text-neutral-500 dark:text-fg-dim">
|
||||
You can also set an internal port per domain on
|
||||
<a class="underline dark:text-white" href="{{ $applicationDomainsUrl }}" {{ wireNavigate() }}>Domains</a>.
|
||||
</p>
|
||||
</div>
|
||||
@if (!$application->destination->server->isSwarm())
|
||||
<x-forms.input placeholder="3000:3000" id="portsMappings" label="Port mappings"
|
||||
helper="A comma separated list of ports you would like to map to the host system. Useful when you do not want to use domains.<br><br><span class='inline-block font-bold dark:text-warning'>Format:</span> host:container<br><br><span class='inline-block font-bold dark:text-warning'>Example:</span> 3000:3000,3002:3002<br><br>Rolling update is not supported if you have a port mapped to the host."
|
||||
|
||||
@@ -74,6 +74,17 @@
|
||||
title="{{ $row['url'] }}">
|
||||
{{ $row['url'] }}
|
||||
</a>
|
||||
@if (filled($row['internal_port'] ?? null) && (int) $row['internal_port'] > 0)
|
||||
<span class="table-badge shrink-0"
|
||||
title="{{ ($row['has_port_override'] ?? false) ? 'Custom internal port for this domain' : 'Inherited from Ports Exposes' }}">
|
||||
Internal port {{ $row['internal_port'] }}
|
||||
</span>
|
||||
@else
|
||||
<span class="table-badge table-badge-danger shrink-0"
|
||||
title="Set Ports Exposes or a per-domain internal port so the proxy can route this domain.">
|
||||
No internal port
|
||||
</span>
|
||||
@endif
|
||||
@endif
|
||||
@if ($isSuggested && ! empty($row['suggestion_label']))
|
||||
<span class="table-badge table-badge-warning shrink-0">{{ $row['suggestion_label'] }}</span>
|
||||
|
||||
@@ -76,6 +76,17 @@
|
||||
<a href="{{ getFqdnWithoutPort($row['url']) }}" target="_blank"
|
||||
class="min-w-0 flex-1 text-[13px] text-black underline decoration-neutral-300 underline-offset-2 hover:decoration-coollabs sm:truncate dark:text-fg dark:decoration-white/20 dark:hover:decoration-warning"
|
||||
title="{{ $row['url'] }}">{{ $row['url'] }}</a>
|
||||
@if (filled($row['internal_port'] ?? null) && (int) $row['internal_port'] > 0)
|
||||
<span class="table-badge shrink-0"
|
||||
title="{{ ($row['has_port_override'] ?? false) ? 'Custom internal port for this domain' : 'Inherited from Ports Exposes' }}">
|
||||
Internal port {{ $row['internal_port'] }}
|
||||
</span>
|
||||
@else
|
||||
<span class="table-badge table-badge-danger shrink-0"
|
||||
title="Set Ports Exposes or a per-domain internal port so the proxy can route this domain.">
|
||||
No internal port
|
||||
</span>
|
||||
@endif
|
||||
@if (filled($row['service']))
|
||||
<span class="table-badge shrink-0">{{ $row['service'] }}</span>
|
||||
@endif
|
||||
@@ -149,4 +160,48 @@
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@if ($showPortWarningModal)
|
||||
<div x-data="{ modalOpen: true }"
|
||||
@keydown.escape.window="modalOpen = false; $wire.call('cancelUseUnknownPort')"
|
||||
class="relative z-40">
|
||||
<template x-teleport="body">
|
||||
<div x-show="modalOpen"
|
||||
class="fixed inset-0 z-99 flex min-h-full items-center justify-center overflow-y-auto p-4" x-cloak>
|
||||
<div class="absolute inset-0 bg-black/50 backdrop-blur-[2px]"></div>
|
||||
<div x-show="modalOpen" x-trap.inert.noscroll="modalOpen"
|
||||
class="application-settings-form application-settings-section relative w-full lg:min-w-[36rem] lg:max-w-2xl"
|
||||
style="box-shadow: 0 0 0 1px var(--coollabs-hairline), var(--shadow-modal)">
|
||||
<header>
|
||||
<h3>Use a different port?</h3>
|
||||
<button type="button"
|
||||
@click="modalOpen = false; $wire.call('cancelUseUnknownPort')"
|
||||
class="icon-button" aria-label="Close">
|
||||
<x-reicon name="x" class="size-4" />
|
||||
</button>
|
||||
</header>
|
||||
<div class="application-settings-section-body">
|
||||
<x-callout type="warning" title="Unrecognized internal port" class="mb-4">
|
||||
Port <strong>{{ $unrecognizedPort }}</strong> is not listed in Ports Exposes
|
||||
and is not used by any application domain. The proxy will still route to it,
|
||||
but the container may not be listening there.
|
||||
</x-callout>
|
||||
|
||||
<div class="mt-4 flex flex-wrap justify-end gap-2 border-t border-neutral-200 pt-4 dark:border-white/[0.08]">
|
||||
<x-forms.button type="button" canGate="update" :canResource="$preview->application"
|
||||
@click="modalOpen = false; $wire.call('cancelUseUnknownPort')">
|
||||
Cancel
|
||||
</x-forms.button>
|
||||
<x-forms.button type="button" wire:click="confirmUseUnknownPort" canGate="update"
|
||||
:canResource="$preview->application"
|
||||
@click="modalOpen = false" isError>
|
||||
Use this port anyway
|
||||
</x-forms.button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
@@ -296,7 +296,7 @@
|
||||
class="application-settings-form application-settings-section relative w-full lg:min-w-[36rem] lg:max-w-2xl"
|
||||
style="box-shadow: 0 0 0 1px var(--coollabs-hairline), var(--shadow-modal)">
|
||||
<header>
|
||||
<h3>Remove required port?</h3>
|
||||
<h3>Use a different port?</h3>
|
||||
<button type="button"
|
||||
@click="modalOpen = false; $wire.call('cancelRemovePort')"
|
||||
class="icon-button" aria-label="Close">
|
||||
@@ -306,17 +306,17 @@
|
||||
<div class="application-settings-section-body">
|
||||
<x-callout type="warning" title="Port requirement" class="mb-4">
|
||||
This service requires port <strong>{{ $requiredPort }}</strong> to function correctly.
|
||||
One or more of your domains are missing a port number.
|
||||
One or more of your domains use a different port, or none.
|
||||
</x-callout>
|
||||
|
||||
<div class="mt-4 flex flex-wrap justify-end gap-2 border-t border-neutral-200 pt-4 dark:border-white/[0.08]">
|
||||
<x-forms.button type="button"
|
||||
@click="modalOpen = false; $wire.call('cancelRemovePort')">
|
||||
Keep port
|
||||
Keep required port
|
||||
</x-forms.button>
|
||||
<x-forms.button type="button" wire:click="confirmRemovePort"
|
||||
@click="modalOpen = false" isError>
|
||||
Remove port anyway
|
||||
Use this port anyway
|
||||
</x-forms.button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
class="application-settings-form application-settings-section relative w-full lg:min-w-[36rem] lg:max-w-2xl"
|
||||
style="box-shadow: 0 0 0 1px var(--coollabs-hairline), var(--shadow-modal)">
|
||||
<header>
|
||||
<h3>Remove required port?</h3>
|
||||
<h3>Use a different port?</h3>
|
||||
<button @click="modalOpen = false; $wire.call('cancelRemovePort')"
|
||||
class="flex size-7 items-center justify-center rounded-md text-neutral-500 transition-colors hover:bg-neutral-100 hover:text-black dark:text-fg-faint dark:hover:bg-white/[0.06] dark:hover:text-fg">
|
||||
<x-reicon name="x" class="size-4" />
|
||||
@@ -53,7 +53,7 @@
|
||||
<div class="application-settings-section-body">
|
||||
<x-callout type="warning" title="Port requirement" class="mb-4">
|
||||
This service requires port <strong>{{ $requiredPort }}</strong> to function correctly.
|
||||
One or more of your domains are missing a port number.
|
||||
One or more of your domains use a different port, or none.
|
||||
</x-callout>
|
||||
|
||||
<x-callout type="danger" title="What will happen if you continue?" class="mb-4">
|
||||
@@ -68,11 +68,11 @@
|
||||
<div class="mt-4 flex flex-wrap justify-end gap-2 border-t border-neutral-200 pt-4 dark:border-white/[0.08]">
|
||||
<x-forms.button @click="modalOpen = false; $wire.call('cancelRemovePort')"
|
||||
class="w-auto">
|
||||
Keep port
|
||||
Keep required port
|
||||
</x-forms.button>
|
||||
<x-forms.button wire:click="confirmRemovePort" @click="modalOpen = false" class="w-auto"
|
||||
isError>
|
||||
Remove port anyway
|
||||
Use this port anyway
|
||||
</x-forms.button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -175,7 +175,7 @@
|
||||
class="application-settings-form application-settings-section relative w-full lg:min-w-[36rem] lg:max-w-2xl"
|
||||
style="box-shadow: 0 0 0 1px var(--coollabs-hairline), var(--shadow-modal)">
|
||||
<header>
|
||||
<h3>Remove required port?</h3>
|
||||
<h3>Use a different port?</h3>
|
||||
<button @click="modalOpen = false; $wire.call('cancelRemovePort')"
|
||||
class="flex size-7 items-center justify-center rounded-md text-neutral-500 transition-colors hover:bg-neutral-100 hover:text-black dark:text-fg-faint dark:hover:bg-white/[0.06] dark:hover:text-fg">
|
||||
<x-reicon name="x" class="size-4" />
|
||||
@@ -184,7 +184,7 @@
|
||||
<div class="application-settings-section-body">
|
||||
<x-callout type="warning" title="Port requirement" class="mb-4">
|
||||
This service requires port <strong>{{ $requiredPort }}</strong> to function correctly.
|
||||
One or more of your domains are missing a port number.
|
||||
One or more of your domains use a different port, or none.
|
||||
</x-callout>
|
||||
|
||||
<x-callout type="danger" title="What will happen if you continue?" class="mb-4">
|
||||
@@ -199,11 +199,11 @@
|
||||
<div class="mt-4 flex flex-wrap justify-end gap-2 border-t border-neutral-200 pt-4 dark:border-white/[0.08]">
|
||||
<x-forms.button @click="modalOpen = false; $wire.call('cancelRemovePort')"
|
||||
class="w-auto">
|
||||
Keep port
|
||||
Keep required port
|
||||
</x-forms.button>
|
||||
<x-forms.button wire:click="confirmRemovePort" @click="modalOpen = false" class="w-auto"
|
||||
isError>
|
||||
Remove port anyway
|
||||
Use this port anyway
|
||||
</x-forms.button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -98,6 +98,12 @@
|
||||
title="{{ $row['url'] }}">
|
||||
{{ $row['url'] }}
|
||||
</a>
|
||||
@if (filled($row['internal_port'] ?? null) && (int) $row['internal_port'] > 0)
|
||||
<span class="table-badge shrink-0"
|
||||
title="{{ ($row['has_port_override'] ?? false) ? 'Custom internal port for this domain' : 'Inherited from the Coolify service port' }}">
|
||||
Internal port {{ $row['internal_port'] }}
|
||||
</span>
|
||||
@endif
|
||||
@endif
|
||||
@if ($isSuggested && ! empty($row['suggestion_label']))
|
||||
<span class="table-badge table-badge-warning shrink-0">{{ $row['suggestion_label'] }}</span>
|
||||
|
||||
Reference in New Issue
Block a user