diff --git a/ansible/group_vars/all.yml b/ansible/group_vars/all.yml
index 8694f8e02e..e85abdc117 100644
--- a/ansible/group_vars/all.yml
+++ b/ansible/group_vars/all.yml
@@ -322,6 +322,7 @@ zookeeper_peer_port: "2888"
 zookeeper_quorum_port: "3888"
 
 zun_api_port: "9517"
+zun_wsproxy_port: "6784"
 
 opendaylight_clustering_port: "2550"
 opendaylight_restconf_port: "8087"
diff --git a/ansible/inventory/all-in-one b/ansible/inventory/all-in-one
index 4fe30343cf..0eb6b6641d 100644
--- a/ansible/inventory/all-in-one
+++ b/ansible/inventory/all-in-one
@@ -618,6 +618,9 @@ placement
 [zun-api:children]
 zun
 
+[zun-wsproxy:children]
+zun
+
 [zun-compute:children]
 compute
 
diff --git a/ansible/inventory/multinode b/ansible/inventory/multinode
index 2d5d24ee3d..1a223722c5 100644
--- a/ansible/inventory/multinode
+++ b/ansible/inventory/multinode
@@ -637,6 +637,9 @@ placement
 [zun-api:children]
 zun
 
+[zun-wsproxy:children]
+zun
+
 [zun-compute:children]
 compute
 
diff --git a/ansible/roles/haproxy/templates/haproxy.cfg.j2 b/ansible/roles/haproxy/templates/haproxy.cfg.j2
index cd8578c4d0..8ae2c546e4 100644
--- a/ansible/roles/haproxy/templates/haproxy.cfg.j2
+++ b/ansible/roles/haproxy/templates/haproxy.cfg.j2
@@ -1194,6 +1194,13 @@ listen zun_api
 {% for host in groups['zun-api'] %}
   server {{ hostvars[host]['ansible_hostname'] }} {{ hostvars[host]['ansible_' + hostvars[host]['api_interface']]['ipv4']['address'] }}:{{ zun_api_port }} check inter 2000 rise 2 fall 5
 {% endfor %}
+
+listen zun_wsproxy
+  bind {{ kolla_internal_vip_address }}:{{ zun_wsproxy_port }}
+  http-request del-header X-Forwarded-Proto if { ssl_fc }
+{% for host in groups['zun-wsproxy'] %}
+  server {{ hostvars[host]['ansible_hostname'] }} {{ hostvars[host]['ansible_' + hostvars[host]['api_interface']]['ipv4']['address'] }}:{{ zun_wsproxy_port }} check inter 2000 rise 2 fall 5
+{% endfor %}
 {% if haproxy_enable_external_vip | bool %}
 
 listen zun_api_external
@@ -1206,6 +1213,17 @@ listen zun_api_external
 {% for host in groups['zun-api'] %}
   server {{ hostvars[host]['ansible_hostname'] }} {{ hostvars[host]['ansible_' + hostvars[host]['api_interface']]['ipv4']['address'] }}:{{ zun_api_port }} check inter 2000 rise 2 fall 5
 {% endfor %}
+
+listen zun_wsproxy_external
+  bind {{ kolla_external_vip_address }}:{{ zun_wsproxy_port }} {{ tls_bind_info }}
+  http-request del-header X-Forwarded-Proto
+  http-request set-header X-Forwarded-Proto https if { ssl_fc }
+{% for http_option in haproxy_listen_http_extra %}
+  {{ http_option }}
+{% endfor %}
+{% for host in groups['zun-wsproxy'] %}
+  server {{ hostvars[host]['ansible_hostname'] }} {{ hostvars[host]['ansible_' + hostvars[host]['api_interface']]['ipv4']['address'] }}:{{ zun_wsproxy_port }} check inter 2000 rise 2 fall 5
+{% endfor %}
 {% endif %}
 {% endif %}
 
diff --git a/ansible/roles/zun/defaults/main.yml b/ansible/roles/zun/defaults/main.yml
index 1b5e29fef5..26d626d0ab 100644
--- a/ansible/roles/zun/defaults/main.yml
+++ b/ansible/roles/zun/defaults/main.yml
@@ -12,6 +12,16 @@ zun_services:
       - "/etc/localtime:/etc/localtime:ro"
       - "{{ kolla_dev_repos_directory ~ '/zun/zun:/var/lib/kolla/venv/lib/python2.7/site-packages/zun' if zun_dev_mode | bool else '' }}"
       - "kolla_logs:/var/log/kolla/"
+  zun-wsproxy:
+    container_name: zun_wsproxy
+    group: zun-wsproxy
+    enabled: true
+    image: "{{ zun_wsproxy_image_full }}"
+    volumes:
+      - "{{ node_config_directory }}/zun-wsproxy/:{{ container_config_directory }}/:ro"
+      - "/etc/localtime:/etc/localtime:ro"
+      - "{{ kolla_dev_repos_directory ~ '/zun/zun:/var/lib/kolla/venv/lib/python2.7/site-packages/zun' if zun_dev_mode | bool else '' }}"
+      - "kolla_logs:/var/log/kolla/"
   zun-compute:
     container_name: zun_compute
     group: zun-compute
@@ -40,14 +50,18 @@ zun_database_address: "{{ database_address }}:{{ database_port }}"
 zun_install_type: "{{ kolla_install_type }}"
 zun_tag: "{{ openstack_release }}"
 
-zun_compute_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ zun_install_type }}-zun-compute"
-zun_compute_tag: "{{ zun_tag }}"
-zun_compute_image_full: "{{ zun_compute_image }}:{{ zun_compute_tag }}"
-
 zun_api_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ zun_install_type }}-zun-api"
 zun_api_tag: "{{ zun_tag }}"
 zun_api_image_full: "{{ zun_api_image }}:{{ zun_api_tag }}"
 
+zun_wsproxy_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ zun_install_type }}-zun-wsproxy"
+zun_wsproxy_tag: "{{ zun_tag }}"
+zun_wsproxy_image_full: "{{ zun_wsproxy_image }}:{{ zun_wsproxy_tag }}"
+
+zun_compute_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ zun_install_type }}-zun-compute"
+zun_compute_tag: "{{ zun_tag }}"
+zun_compute_image_full: "{{ zun_compute_image }}:{{ zun_compute_tag }}"
+
 
 ####################
 ## OpenStack
diff --git a/ansible/roles/zun/handlers/main.yml b/ansible/roles/zun/handlers/main.yml
index 4daa3dbfbf..e2d60d5320 100644
--- a/ansible/roles/zun/handlers/main.yml
+++ b/ansible/roles/zun/handlers/main.yml
@@ -25,6 +25,30 @@
       or policy_overwriting.changed | bool
       or zun_api_container.changed | bool
 
+- name: Restart zun-wsproxy container
+  vars:
+    service_name: "zun-wsproxy"
+    service: "{{ zun_services[service_name] }}"
+    config_json: "{{ zun_config_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    zun_conf: "{{ zun_confs.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    policy_overwriting: "{{ zun_policy_overwriting.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    zun_wsproxy_container: "{{ check_zun_containers.results|selectattr('item.key', 'equalto', service_name)|first }}"
+  kolla_docker:
+    action: "recreate_or_restart_container"
+    common_options: "{{ docker_common_options }}"
+    name: "{{ service.container_name }}"
+    image: "{{ service.image }}"
+    privileged: "{{ service.privileged | default(False) }}"
+    volumes: "{{ service.volumes|reject('equalto', '')|list }}"
+  when:
+    - kolla_action != "config"
+    - inventory_hostname in groups[service.group]
+    - service.enabled | bool
+    - config_json.changed | bool
+      or zun_conf.changed | bool
+      or policy_overwriting.changed | bool
+      or zun_wsproxy_container.changed | bool
+
 - name: Restart zun-compute container
   vars:
     service_name: "zun-compute"
diff --git a/ansible/roles/zun/tasks/precheck.yml b/ansible/roles/zun/tasks/precheck.yml
index c565d804f5..49c4107345 100644
--- a/ansible/roles/zun/tasks/precheck.yml
+++ b/ansible/roles/zun/tasks/precheck.yml
@@ -3,6 +3,7 @@
   kolla_container_facts:
     name:
       - zun_api
+      - zun_wsproxy
   register: container_facts
 
 - name: Checking free port for Zun API
@@ -15,3 +16,14 @@
   when:
     - container_facts['zun_api'] is not defined
     - inventory_hostname in groups['zun-api']
+
+- name: Checking free port for Zun WSproxy
+  wait_for:
+    host: "{{ api_interface_address }}"
+    port: "{{ zun_wsproxy_port }}"
+    connect_timeout: 1
+    timeout: 1
+    state: stopped
+  when:
+    - container_facts['zun_wsproxy'] is not defined
+    - inventory_hostname in groups['zun-wsproxy']
diff --git a/ansible/roles/zun/templates/zun-wsproxy.json.j2 b/ansible/roles/zun/templates/zun-wsproxy.json.j2
new file mode 100644
index 0000000000..90defc385e
--- /dev/null
+++ b/ansible/roles/zun/templates/zun-wsproxy.json.j2
@@ -0,0 +1,24 @@
+{
+    "command": "zun-wsproxy --config-file /etc/zun/zun.conf",
+    "config_files": [
+        {
+            "source": "{{ container_config_directory }}/zun.conf",
+            "dest": "/etc/zun/zun.conf",
+            "owner": "zun",
+            "perm": "0600"
+        }{% if zun_policy_file is defined %},
+        {
+            "source": "{{ container_config_directory }}/{{ zun_policy_file }}",
+            "dest": "/etc/zun/{{ zun_policy_file }}",
+            "owner": "zun",
+            "perm": "0600"
+        }{% endif %}
+    ],
+    "permissions": [
+        {
+            "path": "/var/log/kolla/zun",
+            "owner": "zun:kolla",
+            "recurse": true
+        }
+    ]
+}
diff --git a/ansible/roles/zun/templates/zun.conf.j2 b/ansible/roles/zun/templates/zun.conf.j2
index f931f2a3eb..5c14c9dbc3 100644
--- a/ansible/roles/zun/templates/zun.conf.j2
+++ b/ansible/roles/zun/templates/zun.conf.j2
@@ -104,3 +104,8 @@ lock_path = /var/lib/zun/tmp
 [oslo_policy]
 policy_file = {{ zun_policy_file }}
 {% endif %}
+
+[websocket_proxy]
+wsproxy_host = {{ api_interface_address }}
+wsproxy_port = {{ zun_wsproxy_port }}
+base_url = ws://{{ kolla_external_fqdn }}:{{ zun_wsproxy_port }}