diff --git a/app/kubernetes/components/datatables/applications-datatable/applicationsDatatableController.js b/app/kubernetes/components/datatables/applications-datatable/applicationsDatatableController.js
index 099ee534d..86b4b34c0 100644
--- a/app/kubernetes/components/datatables/applications-datatable/applicationsDatatableController.js
+++ b/app/kubernetes/components/datatables/applications-datatable/applicationsDatatableController.js
@@ -4,6 +4,8 @@ import KubernetesNamespaceHelper from 'Kubernetes/helpers/namespaceHelper';
import { KubernetesConfigurationKinds } from 'Kubernetes/models/configuration/models';
import { KubernetesApplicationDeploymentTypes, KubernetesApplicationTypes } from 'Kubernetes/models/application/models/appConstants';
+import { getSchemeFromPort } from '@/react/common/network-utils';
+
angular.module('portainer.kubernetes').controller('KubernetesApplicationsDatatableController', [
'$scope',
'$controller',
@@ -105,7 +107,10 @@ angular.module('portainer.kubernetes').controller('KubernetesApplicationsDatatab
// Map all load balancer service ports to ip address
let loadBalancerURLs = [];
if (item.LoadBalancerIPAddress) {
- loadBalancerURLs = item.PublishedPorts.map((pp) => `http://${item.LoadBalancerIPAddress}:${pp.Port}`);
+ loadBalancerURLs = item.PublishedPorts.map((pp) => {
+ const scheme = getSchemeFromPort(pp.Port);
+ return `${scheme}://${item.LoadBalancerIPAddress}:${pp.Port}`;
+ });
}
// combine ingress urls
diff --git a/app/react/azure/container-instances/ListView/columns/ports.tsx b/app/react/azure/container-instances/ListView/columns/ports.tsx
index 24bb8deb7..11d4d8408 100644
--- a/app/react/azure/container-instances/ListView/columns/ports.tsx
+++ b/app/react/azure/container-instances/ListView/columns/ports.tsx
@@ -3,6 +3,7 @@ import { CellContext } from '@tanstack/react-table';
import { ContainerGroup } from '@/react/azure/types';
import { getPorts } from '@/react/azure/utils';
+import { getSchemeFromPort } from '@/react/common/network-utils';
import { Icon } from '@@/Icon';
@@ -27,10 +28,17 @@ function PortsCell({
return '-';
}
- return ports.map((port) => (
-
-
- {ip}:{port.host}
-
- ));
+ return ports.map((port) => {
+ const scheme = getSchemeFromPort(port.host);
+ return (
+
+
+ {ip}:{port.host}
+
+ );
+ });
}
diff --git a/app/react/common/network-utils.ts b/app/react/common/network-utils.ts
new file mode 100644
index 000000000..426dc4be7
--- /dev/null
+++ b/app/react/common/network-utils.ts
@@ -0,0 +1,8 @@
+export function getSchemeFromPort(port?: number): 'http' | 'https' {
+ if (!port) {
+ return 'http';
+ }
+
+ const hostPort = String(port);
+ return hostPort.endsWith('443') ? 'https' : 'http';
+}
diff --git a/app/react/docker/containers/ListView/ContainersDatatable/columns/ports.tsx b/app/react/docker/containers/ListView/ContainersDatatable/columns/ports.tsx
index 0b4f280cc..1c560f873 100644
--- a/app/react/docker/containers/ListView/ContainersDatatable/columns/ports.tsx
+++ b/app/react/docker/containers/ListView/ContainersDatatable/columns/ports.tsx
@@ -3,6 +3,7 @@ import { ExternalLink } from 'lucide-react';
import { CellContext } from '@tanstack/react-table';
import type { DockerContainer } from '@/react/docker/containers/types';
+import { getSchemeFromPort } from '@/react/common/network-utils';
import { Icon } from '@@/Icon';
@@ -31,18 +32,46 @@ function Cell({ row }: CellContext) {
return '-';
}
- const { PublicURL: publicUrl } = environment;
+ const publicURL = getPublicUrl(environment.PublicURL);
- return _.uniqBy(ports, 'public').map((port) => (
-
-
- {port.public}:{port.private}
-
- ));
+ return _.uniqBy(ports, 'public').map((port) => {
+ let url = publicURL || port.host || '';
+ if (!url.startsWith('http')) {
+ const scheme = getSchemeFromPort(port.private);
+ url = `${scheme}://${url}`;
+ }
+ url = `${url}:${port.public}`;
+
+ return (
+
+
+ {port.public}:{port.private}
+
+ );
+ });
+}
+
+function getPublicUrl(url?: string): string {
+ if (!url) {
+ return '';
+ }
+
+ // Add protocol if missing
+ const u =
+ url.startsWith('http://') || url.startsWith('https://')
+ ? url
+ : `http://${url}`;
+
+ try {
+ const parsedUrl = new URL(u);
+ return `${parsedUrl.protocol}://${parsedUrl.hostname}`;
+ } catch (error) {
+ return '';
+ }
}
diff --git a/app/react/docker/services/ListView/ServicesDatatable/columns/ports.tsx b/app/react/docker/services/ListView/ServicesDatatable/columns/ports.tsx
index 926d942b3..3f57e3f8f 100644
--- a/app/react/docker/services/ListView/ServicesDatatable/columns/ports.tsx
+++ b/app/react/docker/services/ListView/ServicesDatatable/columns/ports.tsx
@@ -3,6 +3,7 @@ import { CellContext } from '@tanstack/react-table';
import { ServiceViewModel } from '@/docker/models/service';
import { useCurrentEnvironment } from '@/react/hooks/useCurrentEnvironment';
+import { getSchemeFromPort } from '@/react/common/network-utils';
import { Icon } from '@@/Icon';
@@ -40,16 +41,20 @@ function Cell({
return ports
.filter((port) => port.PublishedPort)
- .map((port) => (
-
-
- {port.PublishedPort}:{port.TargetPort}
-
- ));
+ .map((port) => {
+ const scheme = getSchemeFromPort(port.TargetPort);
+
+ return (
+
+
+ {port.PublishedPort}:{port.TargetPort}
+
+ );
+ });
}