diff --git a/apps/assets/automations/base/manager.py b/apps/assets/automations/base/manager.py
index 950b3aebf..cece49de9 100644
--- a/apps/assets/automations/base/manager.py
+++ b/apps/assets/automations/base/manager.py
@@ -1,14 +1,16 @@
 import json
 import os
 import shutil
+import yaml
+
 from collections import defaultdict
 from hashlib import md5
 from socket import gethostname
 
-import yaml
 from django.conf import settings
 from django.utils import timezone
 from django.utils.translation import gettext as _
+from sshtunnel import SSHTunnelForwarder
 
 from assets.automations.methods import platform_automation_methods
 from common.utils import get_logger, lazyproperty
@@ -40,6 +42,7 @@ class BasePlaybookManager:
         # 避免一个 playbook 中包含太多的主机
         self.method_hosts_mapper = defaultdict(list)
         self.playbooks = []
+        self.gateway_servers = dict()
 
     @property
     def platform_automation_methods(self):
@@ -198,16 +201,59 @@ class BasePlaybookManager:
     def on_runner_failed(self, runner, e):
         print("Runner failed: {} {}".format(e, self))
 
-    def before_runner_start(self, runner):
-        pass
+    @staticmethod
+    def file_to_json(path):
+        with open(path, 'r') as f:
+            d = json.load(f)
+        return d
 
     @staticmethod
-    def delete_sensitive_data(path):
+    def json_to_file(path, data):
+        with open(path, 'w') as f:
+            json.dump(data, f)
+
+    def local_gateway_prepare(self, runner):
+        info = self.file_to_json(runner.inventory)
+        servers = []
+        for k, host in info['all']['hosts'].items():
+            jms_asset, jms_gateway = host['jms_asset'], host.get('gateway')
+            if not jms_gateway:
+                continue
+            server = SSHTunnelForwarder(
+                (jms_gateway['address'], jms_gateway['port']),
+                ssh_username=jms_gateway['username'],
+                ssh_password=jms_gateway['secret'],
+                remote_bind_address=(jms_asset['address'], jms_asset['port'])
+            )
+            server.start()
+            jms_asset['address'] = '127.0.0.1'
+            jms_asset['port'] = server.local_bind_port
+            servers.append(server)
+        self.json_to_file(runner.inventory, info)
+        self.gateway_servers[runner.id] = servers
+
+    def local_gateway_clean(self, runner):
+        servers = self.gateway_servers.get(runner.id, [])
+        try:
+            for s in servers:
+                print('Server down: %s' % s)
+                s.stop()
+        except Exception:
+            pass
+
+    def before_runner_start(self, runner):
+        self.local_gateway_prepare(runner)
+
+    def after_runner_end(self, runner):
+        self.delete_sensitive_data(runner.inventory)
+        self.local_gateway_clean(runner)
+
+    def delete_sensitive_data(self, path):
         if settings.DEBUG_DEV:
             return
 
-        with open(path, 'r') as f:
-            d = json.load(f)
+        d = self.file_to_json(path)
+
         def delete_keys(d, keys_to_delete):
             """
             递归函数:删除嵌套字典中的指定键
@@ -221,9 +267,9 @@ class BasePlaybookManager:
                 else:
                     delete_keys(d[key], keys_to_delete)
             return d
+
         d = delete_keys(d, ['secret', 'ansible_password'])
-        with open(path, 'w') as f:
-            json.dump(d, f)
+        self.json_to_file(path, d)
 
     def run(self, *args, **kwargs):
         runners = self.get_runners()
@@ -242,10 +288,10 @@ class BasePlaybookManager:
             self.before_runner_start(runner)
             try:
                 cb = runner.run(**kwargs)
-                self.delete_sensitive_data(runner.inventory)
                 self.on_runner_success(runner, cb)
             except Exception as e:
                 self.on_runner_failed(runner, e)
+            self.after_runner_end(runner)
             print('\n')
         self.execution.status = 'success'
         self.execution.date_finished = timezone.now()
diff --git a/apps/ops/ansible/inventory.py b/apps/ops/ansible/inventory.py
index 01cdbd87d..339039585 100644
--- a/apps/ops/ansible/inventory.py
+++ b/apps/ops/ansible/inventory.py
@@ -131,13 +131,10 @@ class JMSInventory:
 
         if ansible_connection == 'local':
             if gateway:
-                host['ansible_host'] = gateway.address
-                host['ansible_port'] = gateway.port
-                host['ansible_user'] = gateway.username
-                host['ansible_password'] = gateway.password
-                host['ansible_connection'] = 'smart'
-            else:
-                host['ansible_connection'] = 'local'
+                host['gateway'] = {
+                    'address': gateway.address, 'port': gateway.port,
+                    'username': gateway.username, 'secret': gateway.password
+                }
         else:
             self.make_ssh_account_vars(host, asset, account, automation, protocols, platform, gateway)
         return host
diff --git a/requirements/requirements.txt b/requirements/requirements.txt
index 0bea030c0..8ef8712ab 100644
--- a/requirements/requirements.txt
+++ b/requirements/requirements.txt
@@ -39,6 +39,7 @@ requests==2.28.0
 jms-storage==0.0.44
 simplejson==3.17.6
 six==1.16.0
+sshtunnel==0.4.0
 sshpubkeys==3.3.1
 uritemplate==4.1.1
 urllib3==1.26.9