diff --git a/nova/templates/bin/_nova-console-compute-init.sh.tpl b/nova/templates/bin/_nova-console-compute-init.sh.tpl
index b2fb92f0f4..365b9ba741 100644
--- a/nova/templates/bin/_nova-console-compute-init.sh.tpl
+++ b/nova/templates/bin/_nova-console-compute-init.sh.tpl
@@ -28,6 +28,10 @@ elif [ "${console_kind}" == "spice" ] ; then
     client_interface="{{- .Values.console.spice.compute.server_proxyclient_interface -}}"
     client_network_cidr="{{- .Values.console.spice.compute.server_proxyclient_network_cidr -}}"
     listen_ip="{{- .Values.conf.nova.spice.server_listen -}}"
+elif [ "${console_kind}" == "serial" ] ; then
+    client_address="{{- .Values.conf.nova.serial_console.proxyclient_address -}}"
+    client_interface="{{- .Values.console.serial.compute.server_proxyclient_interface -}}"
+    client_network_cidr="{{- .Values.console.serial.compute.server_proxyclient_network_cidr -}}"
 fi
 
 if [ -z "${client_address}" ] ; then
@@ -61,4 +65,9 @@ elif [ "${console_kind}" == "spice" ] ; then
 server_proxyclient_address = $client_address
 server_listen = $listen_ip
 EOF
+elif [ "${console_kind}" == "serial" ] ; then
+  cat > /tmp/pod-shared/nova-console.conf <<EOF
+[serial_console]
+proxyclient_address = $client_address
+EOF
 fi
diff --git a/nova/templates/bin/_nova-console-proxy-init.sh.tpl b/nova/templates/bin/_nova-console-proxy-init.sh.tpl
index 4eedda9e94..51a7b11152 100644
--- a/nova/templates/bin/_nova-console-proxy-init.sh.tpl
+++ b/nova/templates/bin/_nova-console-proxy-init.sh.tpl
@@ -28,6 +28,10 @@ elif [ "${console_kind}" == "spice" ] ; then
     client_interface="{{- .Values.console.spice.proxy.server_proxyclient_interface -}}"
     client_network_cidr="{{- .Values.console.spice.proxy.server_proxyclient_network_cidr -}}"
     listen_ip="{{- .Values.conf.nova.spice.server_listen -}}"
+elif [ "${console_kind}" == "serial" ] ; then
+    client_address="{{- .Values.conf.nova.serial_console.proxyclient_address -}}"
+    client_interface="{{- .Values.console.serial.proxy.server_proxyclient_interface -}}"
+    client_network_cidr="{{- .Values.console.serial.proxy.server_proxyclient_network_cidr -}}"
 fi
 
 if [ -z "${client_address}" ] ; then
@@ -59,4 +63,9 @@ cat <<EOF>/tmp/pod-shared/nova-spice.ini
 server_proxyclient_address = $client_address
 server_listen = $listen_ip
 EOF
+elif [ "${console_kind}" == "serial" ] ; then
+cat <<EOF>/tmp/pod-shared/nova-serial.ini
+[serial_console]
+proxyclient_address = $client_address
+EOF
 fi
diff --git a/nova/templates/bin/_nova-console-proxy.sh.tpl b/nova/templates/bin/_nova-console-proxy.sh.tpl
index 253a053898..d9f1472150 100644
--- a/nova/templates/bin/_nova-console-proxy.sh.tpl
+++ b/nova/templates/bin/_nova-console-proxy.sh.tpl
@@ -25,4 +25,8 @@ elif [ "${console_kind}" == "spice" ] ; then
     exec nova-spicehtml5proxy\
         --config-file /etc/nova/nova.conf \
         --config-file /tmp/pod-shared/nova-spice.ini
+elif [ "${console_kind}" == "serial" ] ; then
+    exec nova-serialproxy\
+        --config-file /etc/nova/nova.conf \
+        --config-file /tmp/pod-shared/nova-serial.ini
 fi
\ No newline at end of file
diff --git a/nova/templates/certificates.yaml b/nova/templates/certificates.yaml
index a1385e3bba..b53babbc41 100644
--- a/nova/templates/certificates.yaml
+++ b/nova/templates/certificates.yaml
@@ -27,4 +27,7 @@ limitations under the License.
 {{- if .Values.manifests.deployment_spiceproxy }}
 {{ dict "envAll" . "service" "compute_spice_proxy" "type" "internal" | include "helm-toolkit.manifests.certificates" }}
 {{- end }}
+{{- if .Values.manifests.deployment_serialproxy }}
+{{ dict "envAll" . "service" "compute_serial_proxy" "type" "internal" | include "helm-toolkit.manifests.certificates" }}
+{{- end }}
 {{- end -}}
diff --git a/nova/templates/configmap-etc.yaml b/nova/templates/configmap-etc.yaml
index 6f00a1ce2a..96617dbdd4 100644
--- a/nova/templates/configmap-etc.yaml
+++ b/nova/templates/configmap-etc.yaml
@@ -211,6 +211,18 @@ limitations under the License.
 {{- end -}}
 {{- end -}}
 
+{{- if eq .Values.console.console_kind "serial"}}
+{{- $_ := "false" | set .Values.conf.nova.vnc "enabled" -}}
+{{- $_ := "false" | set .Values.conf.nova.spice "enabled" -}}
+{{- $_ := "true" | set .Values.conf.nova.serial_console "enabled" -}}
+{{- if empty .Values.conf.nova.serial_console.base_url -}}
+{{- $_ := tuple "compute_serial_proxy" "public" "serial_proxy" . | include "helm-toolkit.endpoints.keystone_endpoint_uri_lookup" | set .Values.conf.nova.serial_console "base_url" -}}
+{{- end -}}
+{{- if empty .Values.conf.nova.serial_console.serialproxy_port -}}
+{{- $_ := tuple "compute_serial_proxy" "internal" "serial_proxy" . | include "helm-toolkit.endpoints.endpoint_port_lookup" | set .Values.conf.nova.serial_console "serialproxy_port" -}}
+{{- end -}}
+{{- end -}}
+
 {{- if empty .Values.conf.nova.ironic.api_endpoint -}}
 {{- $_ := tuple "baremetal" "internal" "api" . | include "helm-toolkit.endpoints.keystone_endpoint_uri_lookup" | set .Values.conf.nova.ironic "api_endpoint" -}}
 {{- end -}}
diff --git a/nova/templates/daemonset-compute.yaml b/nova/templates/daemonset-compute.yaml
index 3ad00ff2df..9124898d51 100644
--- a/nova/templates/daemonset-compute.yaml
+++ b/nova/templates/daemonset-compute.yaml
@@ -229,6 +229,25 @@ spec:
               readOnly: true
             - name: pod-shared
               mountPath: /tmp/pod-shared
+{{ if $mounts_nova_compute.volumeMounts }}{{ toYaml $mounts_nova_compute.volumeMounts | indent 12 }}{{ end }}
+        {{ end }}
+        {{- if eq .Values.console.console_kind "serial"}}
+        - name: nova-compute-serial-init
+{{ tuple $envAll "nova_compute" | include "helm-toolkit.snippets.image" | indent 10 }}
+{{ tuple $envAll $envAll.Values.pod.resources.compute | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+{{ dict "envAll" $envAll "application" "nova" "container" "nova_compute_serial_init" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }}
+          command:
+            - /tmp/nova-console-compute-init.sh
+          terminationMessagePath: /var/log/termination-log
+          volumeMounts:
+            - name: pod-tmp
+              mountPath: /tmp
+            - name: nova-bin
+              mountPath: /tmp/nova-console-compute-init.sh
+              subPath: nova-console-compute-init.sh
+              readOnly: true
+            - name: pod-shared
+              mountPath: /tmp/pod-shared
 {{ if $mounts_nova_compute.volumeMounts }}{{ toYaml $mounts_nova_compute.volumeMounts | indent 12 }}{{ end }}
         {{ end }}
         {{- if ( has "tungstenfabric" .Values.network.backend ) }}
diff --git a/nova/templates/deployment-serialproxy.yaml b/nova/templates/deployment-serialproxy.yaml
new file mode 100644
index 0000000000..ec2148c6c7
--- /dev/null
+++ b/nova/templates/deployment-serialproxy.yaml
@@ -0,0 +1,155 @@
+{{/*
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/}}
+
+{{- define "novaSerialproxyLivenessProbeTemplate" }}
+tcpSocket:
+  port: {{ tuple "compute_serial_proxy" "internal" "serial_proxy" . | include "helm-toolkit.endpoints.endpoint_port_lookup" }}
+{{- end }}
+
+{{- define "novaSerialproxyReadinessProbeTemplate" }}
+tcpSocket:
+  port: {{ tuple "compute_serial_proxy" "internal" "serial_proxy" . | include "helm-toolkit.endpoints.endpoint_port_lookup" }}
+{{- end }}
+
+{{- if and .Values.manifests.deployment_serialproxy ( eq .Values.console.console_kind "serial" )}}
+{{- $envAll := . }}
+
+{{- $mounts_nova_serialproxy := .Values.pod.mounts.nova_serialproxy.nova_serialproxy }}
+{{- $mounts_nova_serialproxy_init := .Values.pod.mounts.nova_serialproxy.init_serialproxy }}
+
+{{- $serviceAccountName := "nova-serialproxy" }}
+{{ tuple $envAll "serialproxy" $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: nova-serialproxy
+  annotations:
+    {{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" }}
+  labels:
+{{ tuple $envAll "nova" "serial-proxy" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }}
+spec:
+  replicas: {{ .Values.pod.replicas.serialproxy }}
+  selector:
+    matchLabels:
+{{ tuple $envAll "nova" "serial-proxy" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 6 }}
+{{ tuple $envAll | include "helm-toolkit.snippets.kubernetes_upgrades_deployment" | indent 2 }}
+  template:
+    metadata:
+      labels:
+{{ tuple $envAll "nova" "serial-proxy" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
+      annotations:
+{{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" | indent 8 }}
+        configmap-bin-hash: {{ tuple "configmap-bin.yaml" . | include "helm-toolkit.utils.hash" }}
+        configmap-etc-hash: {{ tuple "configmap-etc.yaml" . | include "helm-toolkit.utils.hash" }}
+{{ tuple "nova_serialproxy" . | include "helm-toolkit.snippets.custom_pod_annotations" | indent 8 }}
+{{ dict "envAll" $envAll "podName" "nova-serialproxy" "containerNames" (list "nova-serialproxy" "nova-serialproxy-init-assets" "nova-serialproxy-init" "init") | include "helm-toolkit.snippets.kubernetes_mandatory_access_control_annotation" | indent 8 }}
+    spec:
+      serviceAccountName: {{ $serviceAccountName }}
+{{ dict "envAll" $envAll "application" "nova" | include "helm-toolkit.snippets.kubernetes_pod_security_context" | indent 6 }}
+      affinity:
+{{ tuple $envAll "nova" "serial-proxy" | include "helm-toolkit.snippets.kubernetes_pod_anti_affinity" | indent 8 }}
+      nodeSelector:
+        {{ .Values.labels.serialproxy.node_selector_key }}: {{ .Values.labels.serialproxy.node_selector_value }}
+{{ if $envAll.Values.pod.tolerations.nova.enabled }}
+{{ tuple $envAll "nova" | include "helm-toolkit.snippets.kubernetes_tolerations" | indent 6 }}
+{{ end }}
+{{- if .Values.pod.useHostNetwork.serialproxy }}
+      hostNetwork: true
+      dnsPolicy: ClusterFirstWithHostNet
+{{- end }}
+      initContainers:
+{{ tuple $envAll "serialproxy" $mounts_nova_serialproxy_init | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 8 }}
+        - name: nova-serialproxy-init
+{{ tuple $envAll "nova_serialproxy" | include "helm-toolkit.snippets.image" | indent 10 }}
+{{ tuple $envAll $envAll.Values.pod.resources.serialproxy | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+{{ dict "envAll" $envAll "application" "nova" "container" "nova_serialproxy_init" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }}
+          command:
+            - /tmp/nova-console-proxy-init.sh
+          volumeMounts:
+            - name: pod-tmp
+              mountPath: /tmp
+            - name: nova-bin
+              mountPath: /tmp/nova-console-proxy-init.sh
+              subPath: nova-console-proxy-init.sh
+              readOnly: true
+            - name: nova-etc
+              mountPath: /etc/nova/nova.conf
+              subPath: nova.conf
+              readOnly: true
+            {{- if .Values.conf.nova.DEFAULT.log_config_append }}
+            - name: nova-etc
+              mountPath: {{ .Values.conf.nova.DEFAULT.log_config_append }}
+              subPath: {{ base .Values.conf.nova.DEFAULT.log_config_append }}
+              readOnly: true
+            {{- end }}
+            - name: pod-shared
+              mountPath: /tmp/pod-shared
+      containers:
+        - name: nova-serialproxy
+{{ tuple $envAll "nova_serialproxy" | include "helm-toolkit.snippets.image" | indent 10 }}
+{{ tuple $envAll $envAll.Values.pod.resources.serialproxy | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+{{ dict "envAll" $envAll "application" "nova" "container" "nova_serialproxy" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }}
+{{ dict "envAll" $envAll "component" "serialproxy" "container" "default" "type" "liveness" "probeTemplate" (include "novaSerialproxyLivenessProbeTemplate" $envAll | fromYaml) | include "helm-toolkit.snippets.kubernetes_probe" | indent 10 }}
+{{ dict "envAll" $envAll "component" "serialproxy" "container" "default" "type" "readiness" "probeTemplate" (include "novaSerialproxyReadinessProbeTemplate" $envAll | fromYaml) | include "helm-toolkit.snippets.kubernetes_probe" | indent 10 }}
+          command:
+            - /tmp/nova-console-proxy.sh
+          ports:
+            - name: n-serial
+              containerPort: {{ tuple "compute_serial_proxy" "internal" "serial_proxy" . | include "helm-toolkit.endpoints.endpoint_port_lookup" }}
+          volumeMounts:
+            - name: pod-tmp
+              mountPath: /tmp
+            - name: nova-bin
+              mountPath: /tmp/nova-console-proxy.sh
+              subPath: nova-console-proxy.sh
+              readOnly: true
+            - name: nova-etc
+              mountPath: /etc/nova/nova.conf
+              subPath: nova.conf
+              readOnly: true
+            - name: nova-etc
+              mountPath: /etc/nova/logging.conf
+              subPath: logging.conf
+              readOnly: true
+            - name: pod-usr-share-serial
+              mountPath: /usr/share/serial
+              readOnly: true
+            - name: pod-shared
+              mountPath: /tmp/pod-shared
+
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.endpoints.oslo_db.auth.admin.secret.tls.internal "path" "/etc/mysql/certs" | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.secrets.tls.compute_serial_proxy.serialproxy.internal "path" "/etc/nova/certs" | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
+{{- dict "enabled" $envAll.Values.manifests.certificates "name" $envAll.Values.endpoints.oslo_messaging.auth.admin.secret.tls.internal "path" "/etc/rabbitmq/certs" | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
+{{ if $mounts_nova_serialproxy.volumeMounts }}{{ toYaml $mounts_nova_serialproxy.volumeMounts | indent 12 }}{{ end }}
+      volumes:
+        - name: pod-tmp
+          emptyDir: {}
+        - name: nova-bin
+          configMap:
+            name: nova-bin
+            defaultMode: 0555
+        - name: nova-etc
+          secret:
+            secretName: nova-etc
+            defaultMode: 0444
+        - name: pod-usr-share-serial
+          emptyDir: {}
+        - name: pod-shared
+          emptyDir: {}
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.endpoints.oslo_db.auth.admin.secret.tls.internal | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.secrets.tls.compute_serial_proxy.serialproxy.internal | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
+{{- dict "enabled" $envAll.Values.manifests.certificates "name" $envAll.Values.endpoints.oslo_messaging.auth.admin.secret.tls.internal | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
+{{ if $mounts_nova_serialproxy.volumes }}{{ toYaml $mounts_nova_serialproxy.volumes | indent 8 }}{{ end }}
+{{- end }}
diff --git a/nova/templates/ingress-serialproxy.yaml b/nova/templates/ingress-serialproxy.yaml
new file mode 100644
index 0000000000..a439bdc95a
--- /dev/null
+++ b/nova/templates/ingress-serialproxy.yaml
@@ -0,0 +1,23 @@
+{{/*
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/}}
+
+{{- if and .Values.manifests.ingress_serialproxy .Values.network.serialproxy.ingress.public (eq .Values.console.console_kind "serial") }}
+{{- $envAll := . }}
+{{- $ingressOpts := dict "envAll" $envAll "backendService" "serialproxy" "backendServiceType" "compute_serial_proxy" "backendPort" "n-serial" -}}
+{{- $secretName := $envAll.Values.secrets.tls.compute_serial_proxy.serialproxy.internal -}}
+{{- if and .Values.manifests.certificates $secretName }}
+{{- $_ := set $ingressOpts "certIssuer" .Values.endpoints.compute_serial_proxy.host_fqdn_override.default.tls.issuerRef.name -}}
+{{- end }}
+{{ $ingressOpts | include "helm-toolkit.manifests.ingress" }}
+{{- end }}
diff --git a/nova/templates/service-ingress-serialproxy.yaml b/nova/templates/service-ingress-serialproxy.yaml
new file mode 100644
index 0000000000..346d51dfef
--- /dev/null
+++ b/nova/templates/service-ingress-serialproxy.yaml
@@ -0,0 +1,18 @@
+{{/*
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/}}
+
+{{- if and .Values.manifests.service_ingress_serialproxy .Values.network.serialproxy.ingress.public (eq .Values.console.console_kind "serial") }}
+{{- $serviceIngressOpts := dict "envAll" . "backendServiceType" "compute_serial_proxy" -}}
+{{ $serviceIngressOpts | include "helm-toolkit.manifests.service_ingress" }}
+{{- end }}
diff --git a/nova/templates/service-serialproxy.yaml b/nova/templates/service-serialproxy.yaml
new file mode 100644
index 0000000000..088dd2d746
--- /dev/null
+++ b/nova/templates/service-serialproxy.yaml
@@ -0,0 +1,34 @@
+{{/*
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/}}
+
+{{- if and .Values.manifests.service_serialproxy ( eq .Values.console.console_kind "serial" ) }}
+{{- $envAll := . }}
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ tuple "compute_serial_proxy" "internal" . | include "helm-toolkit.endpoints.hostname_short_endpoint_lookup" }}
+spec:
+  ports:
+  - name: n-serial
+    port: {{ tuple "compute_serial_proxy" "internal" "serial_proxy" . | include "helm-toolkit.endpoints.endpoint_port_lookup" }}
+    {{ if .Values.network.serialproxy.node_port.enabled }}
+    nodePort: {{ .Values.network.serialproxy.node_port.port }}
+    {{ end }}
+  selector:
+{{ tuple $envAll "noa" "serial-proxy" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }}
+  {{ if .Values.network.serialproxy.node_port.enabled }}
+  type: NodePort
+  {{ end }}
+{{- end }}
diff --git a/nova/values.yaml b/nova/values.yaml
index 80454ce44d..45613eb426 100644
--- a/nova/values.yaml
+++ b/nova/values.yaml
@@ -44,6 +44,9 @@ labels:
   scheduler:
     node_selector_key: openstack-control-plane
     node_selector_value: enabled
+  serialproxy:
+    node_selector_key: openstack-control-plane
+    node_selector_value: enabled
   spiceproxy:
     node_selector_key: openstack-control-plane
     node_selector_value: enabled
@@ -78,6 +81,7 @@ images:
     # NOTE(portdirect): we simply use the ceph config helper here,
     # as it has both oscli and jq.
     nova_service_cleaner: 'docker.io/openstackhelm/ceph-config-helper:latest-ubuntu_jammy'
+    nova_serialproxy: quay.io/airshipit/nova:2024.1-ubuntu_jammy
     nova_spiceproxy: quay.io/airshipit/nova:2024.1-ubuntu_jammy
     nova_spiceproxy_assets: quay.io/airshipit/nova:2024.1-ubuntu_jammy
     test: docker.io/xrally/xrally-openstack:2.0.0
@@ -246,6 +250,17 @@ network:
     node_port:
       enabled: false
       port: 30680
+  serialproxy:
+    ingress:
+      public: true
+      classes:
+        namespace: "nginx"
+        cluster: "nginx-cluster"
+      annotations:
+        nginx.ingress.kubernetes.io/rewrite-target: /
+    node_port:
+      enabled: false
+      port: 30683
   spiceproxy:
     ingress:
       public: true
@@ -461,6 +476,12 @@ dependencies:
       services:
         - endpoint: internal
           service: oslo_db
+    serialproxy:
+      jobs:
+        - nova-db-sync
+      services:
+        - endpoint: internal
+          service: oslo_db
     spiceproxy:
       jobs:
         - nova-db-sync
@@ -499,6 +520,16 @@ console:
   # serial | spice | novnc | none
   console_kind: novnc
   serial:
+    compute:
+      # IF blank, search default routing interface
+      server_proxyclient_interface: null
+      # or set network cidr
+      server_proxyclient_network_cidr: 0/0
+    proxy:
+      # IF blank, search default routing interface
+      server_proxyclient_interface: null
+      # or set network cidr
+      server_proxyclient_network_cidr: 0/0
   spice:
     compute:
       # IF blank, search default routing interface
@@ -1412,6 +1443,10 @@ conf:
       server_listen: 0.0.0.0
       # This would be set by each compute nodes's ip
       # server_proxyclient_address: 127.0.0.1
+    serial_console:
+      serialproxy_host: 0.0.0.0
+      # This would be set by each compute nodes's ip
+      # proxyclient_address: 127.0.0.1
     conductor:
       workers: 1
     scheduler:
@@ -1638,6 +1673,10 @@ secrets:
       spiceproxy:
         public: nova-spiceproxy-tls-public
         internal: nova-spiceproxy-tls-proxy
+    compute_serial_proxy:
+      serialproxy:
+        public: nova-serialproxy-tls-public
+        internal: nova-serialproxy-tls-proxy
   oci_image_registry:
     nova: nova-oci-image-registry
 
@@ -1934,6 +1973,21 @@ endpoints:
         commonName: nova-novncproxy
         usages:
           - client auth
+  compute_serial_proxy:
+    name: nova
+    hosts:
+      default: nova-serialproxy
+      public: serialproxy
+    host_fqdn_override:
+      default: null
+    scheme:
+      default: 'ws'
+    path:
+      default: /serial_auto.html
+    port:
+      serial_proxy:
+        default: 6083
+        public: 80
   compute_spice_proxy:
     name: nova
     hosts:
@@ -2129,6 +2183,20 @@ pod:
             initialDelaySeconds: 80
             periodSeconds: 90
             timeoutSeconds: 70
+    serialproxy:
+      default:
+        liveness:
+          enabled: True
+          params:
+            initialDelaySeconds: 30
+            periodSeconds: 60
+            timeoutSeconds: 15
+        readiness:
+          enabled: True
+          params:
+            initialDelaySeconds: 30
+            periodSeconds: 60
+            timeoutSeconds: 15
     compute-spice-proxy:
       default:
         liveness:
@@ -2160,6 +2228,9 @@ pod:
         nova_compute_vnc_init:
           readOnlyRootFilesystem: true
           allowPrivilegeEscalation: false
+        nova_compute_serial_init:
+          readOnlyRootFilesystem: true
+          allowPrivilegeEscalation: false
         nova_compute_spice_init:
           readOnlyRootFilesystem: true
           allowPrivilegeEscalation: false
@@ -2195,6 +2266,12 @@ pod:
         nova_scheduler:
           readOnlyRootFilesystem: true
           allowPrivilegeEscalation: false
+        nova_serialproxy_init:
+          readOnlyRootFilesystem: true
+          allowPrivilegeEscalation: false
+        nova_serialproxy:
+          readOnlyRootFilesystem: true
+          allowPrivilegeEscalation: false
         nova_spiceproxy_init:
           readOnlyRootFilesystem: true
           allowPrivilegeEscalation: false
@@ -2323,6 +2400,11 @@ pod:
       nova_novncproxy:
         volumeMounts:
         volumes:
+    nova_serialproxy:
+      init_serialproxy: null
+      nova_serialproxy:
+        volumeMounts:
+        volumes:
     nova_spiceproxy:
       init_spiceproxy: null
       nova_spiceproxy:
@@ -2341,6 +2423,7 @@ pod:
     conductor: 1
     scheduler: 1
     novncproxy: 1
+    serialproxy: 1
     spiceproxy: 1
   lifecycle:
     upgrades:
@@ -2424,6 +2507,13 @@ pod:
       limits:
         memory: "1024Mi"
         cpu: "2000m"
+    serialproxy:
+      requests:
+        memory: "128Mi"
+        cpu: "100m"
+      limits:
+        memory: "1024Mi"
+        cpu: "2000m"
     spiceproxy:
       requests:
         memory: "128Mi"
@@ -2564,10 +2654,12 @@ manifests:
   deployment_api_osapi: true
   deployment_conductor: true
   deployment_novncproxy: true
+  deployment_serialproxy: true
   deployment_spiceproxy: true
   deployment_scheduler: true
   ingress_metadata: true
   ingress_novncproxy: true
+  ingress_serialproxy: true
   ingress_spiceproxy: true
   ingress_osapi: true
   job_bootstrap: true
@@ -2594,10 +2686,12 @@ manifests:
   secret_registry: true
   service_ingress_metadata: true
   service_ingress_novncproxy: true
+  service_ingress_serialproxy: true
   service_ingress_spiceproxy: true
   service_ingress_osapi: true
   service_metadata: true
   service_novncproxy: true
+  service_serialproxy: true
   service_spiceproxy: true
   service_osapi: true
   statefulset_compute_ironic: false
diff --git a/releasenotes/notes/nova-c59fc7469b3a8500.yaml b/releasenotes/notes/nova-c59fc7469b3a8500.yaml
new file mode 100644
index 0000000000..418db78dac
--- /dev/null
+++ b/releasenotes/notes/nova-c59fc7469b3a8500.yaml
@@ -0,0 +1,4 @@
+---
+nova:
+  - Add serialproxy support
+...
diff --git a/values_overrides/nova/tls.yaml b/values_overrides/nova/tls.yaml
index ef3d438592..5cf2d727a6 100644
--- a/values_overrides/nova/tls.yaml
+++ b/values_overrides/nova/tls.yaml
@@ -175,6 +175,16 @@ endpoints:
             kind: ClusterIssuer
     scheme:
       default: https
+  compute_serial_proxy:
+    host_fqdn_override:
+      default:
+        tls:
+          secretName: nova-tls-serialproxy
+          issuerRef:
+            name: ca-issuer
+            kind: ClusterIssuer
+    scheme:
+      default: wss
   placement:
     host_fqdn_override:
       default: