diff --git a/src/op_mode/dynamic_dns.py b/src/op_mode/dynamic_dns.py
index 263a3b6a5..2cba33cc8 100755
--- a/src/op_mode/dynamic_dns.py
+++ b/src/op_mode/dynamic_dns.py
@@ -1,107 +1,101 @@
 #!/usr/bin/env python3
 #
 # Copyright (C) 2018-2020 VyOS maintainers and contributors
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License version 2 or later as
 # published by the Free Software Foundation.
 #
 # This program is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 # GNU General Public License for more details.
 #
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import os
 import argparse
-import jinja2
 import sys
 import time
+from tabulate import tabulate
 
 from vyos.config import Config
 from vyos.util import call
 
 cache_file = r'/run/ddclient/ddclient.cache'
 
-OUT_TMPL_SRC = """
-{% for entry in hosts %}
-ip address   : {{ entry.ip }}
-host-name    : {{ entry.host }}
-last update  : {{ entry.time }}
-update-status: {{ entry.status }}
+columns = {
+    'host':        'Hostname',
+    'ipv4':        'IPv4 address',
+    'status-ipv4': 'IPv4 status',
+    'ipv6':        'IPv6 address',
+    'status-ipv6': 'IPv6 status',
+    'mtime':       'Last update',
+}
+
+
+def _get_formatted_host_records(host_data):
+    data_entries = []
+    for entry in host_data:
+        data_entries.append([entry.get(key) for key in columns.keys()])
+
+    header = columns.values()
+    output = tabulate(data_entries, header, numalign='left')
+    return output
 
-{% endfor %}
-"""
 
 def show_status():
     # A ddclient status file must not always exist
     if not os.path.exists(cache_file):
         sys.exit(0)
 
-    data = {
-        'hosts': []
-    }
+    data = []
 
     with open(cache_file, 'r') as f:
         for line in f:
             if line.startswith('#'):
                 continue
 
-            outp = {
-                'host': '',
-                'ip': '',
-                'time': ''
-            }
-
-            if 'host=' in line:
-                host = line.split('host=')[1]
-                if host:
-                    outp['host'] = host.split(',')[0]
-
-            if 'ip=' in line:
-                ip = line.split('ip=')[1]
-                if ip:
-                    outp['ip'] = ip.split(',')[0]
-
-            if 'mtime=' in line:
-                mtime = line.split('mtime=')[1]
-                if mtime:
-                    outp['time'] = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(int(mtime.split(',')[0], base=10)))
+            props = {}
+            # ddclient cache rows have properties in 'key=value' format separated by comma
+            # we pick up the ones we are interested in
+            for kvraw in line.split(' ')[0].split(','):
+                k, v = kvraw.split('=')
+                if k in columns.keys():
+                    props[k] = v
 
-            if 'status=' in line:
-                status = line.split('status=')[1]
-                if status:
-                    outp['status'] = status.split(',')[0]
+            # Convert mtime to human readable format
+            if 'mtime' in props:
+                props['mtime'] = time.strftime(
+                    "%Y-%m-%d %H:%M:%S", time.localtime(int(props['mtime'], base=10)))
 
-            data['hosts'].append(outp)
+            data.append(props)
 
-    tmpl = jinja2.Template(OUT_TMPL_SRC)
-    print(tmpl.render(data))
+    print(_get_formatted_host_records(data))
 
 
 def update_ddns():
     call('systemctl stop ddclient.service')
     if os.path.exists(cache_file):
         os.remove(cache_file)
     call('systemctl start ddclient.service')
 
 
 if __name__ == '__main__':
     parser = argparse.ArgumentParser()
     group = parser.add_mutually_exclusive_group()
     group.add_argument("--status", help="Show DDNS status", action="store_true")
     group.add_argument("--update", help="Update DDNS on a given interface", action="store_true")
     args = parser.parse_args()
 
     # Do nothing if service is not configured
     c = Config()
     if not c.exists_effective('service dns dynamic'):
         print("Dynamic DNS not configured")
         sys.exit(1)
 
     if args.status:
         show_status()
     elif args.update:
         update_ddns()