8

我正在尝试使用 django 连接到远程 mysql 数据库。
文档指定需要先打开 SSH 隧道才能连接到数据库。
是否有一个 python 库可以在设置某些设置时打开 SSH 隧道?

4

5 回答 5

10

您可以尝试paramiko转发功能。有关 paramiko 的概述,请参见此处

于 2010-12-06T08:13:37.467 回答
7

尝试使用sshtunnel 包

这很简单:

pip install sshtunnel
python -m sshtunnel -U vagrant -P vagrant -L :3306 -R 127.0.0.1:3306 -p 2222 localhost

披露:我是这个包的作者和维护者。

于 2015-06-17T20:08:37.997 回答
5

这是 Python3 的代码片段(但您应该能够毫无困难地将其改造成 Python2)。它在单独的线程中运行 SSH 隧道;然后主线程通过 SSH 隧道获取网络流量。

在此示例中,ssh 隧道将本地端口 2222 转发到 localhost 上的端口 80。主要活动包括跑步

curl http://localhost:2222

即,从端口 2222 获取网页。

SshTunnel 类初始化有 4 个参数,本地和远程端口、远程用户和远程主机。它所做的就是通过以下方式启动 SSH:

ssh -N -L localport:remotehost:remoteport remoteuser@remotehost

为了完成这项工作,您需要对 remoteuser@remotehost 进行无密码登录(通过远程服务器上已知的 ~/.ssh/id_rsa.pub)。这样运行的 ssh 隧道在一个线程上;主要任务必须在另一个。ssh 隧道线程被标记为守护进程,因此一旦主要活动终止,它将自动停止。

我没有提供完整的 MySQL 连接示例,因为它应该是不言自明的。一旦 SshTunnel 设置了本地 TCP 端口,您就可以连接到它——无论是通过您的 MySQL 客户端、curl 还是其他方式。

import subprocess
import time
import threading

class SshTunnel(threading.Thread):
    def __init__(self, localport, remoteport, remoteuser, remotehost):
        threading.Thread.__init__(self)
        self.localport = localport      # Local port to listen to
        self.remoteport = remoteport    # Remote port on remotehost
        self.remoteuser = remoteuser    # Remote user on remotehost
        self.remotehost = remotehost    # What host do we send traffic to
        self.daemon = True              # So that thread will exit when
                                        # main non-daemon thread finishes

    def run(self):
        if subprocess.call([
            'ssh', '-N',
                   '-L', str(self.localport) + ':' + self.remotehost + ':' + str(self.remoteport),
                   self.remoteuser + '@' + self.remotehost ]):
            raise Exception ('ssh tunnel setup failed')


if __name__ == '__main__':
    tunnel = SshTunnel(2222, 80, 'karel', 'localhost')
    tunnel.start()
    time.sleep(1)
    subprocess.call(['curl', 'http://localhost:2222'])
于 2014-10-30T15:08:23.893 回答
2

这是一个可以放入代码中的小类:

import subprocess
import random
import tempfile

class SSHTunnel:

    def __init__(self, host, user, port, key, remote_port):
        self.host = host
        self.user = user
        self.port = port
        self.key = key
        self.remote_port = remote_port
        # Get a temporary file name
        tmpfile = tempfile.NamedTemporaryFile()
        tmpfile.close()
        self.socket = tmpfile.name
        self.local_port = random.randint(10000, 65535)
        self.local_host = '127.0.0.1'
        self.open = False

    def start(self):
        exit_status = subprocess.call(['ssh', '-MfN',
            '-S', self.socket,
            '-i', self.key,
            '-p', self.port,
            '-l', self.user,
            '-L', '{}:{}:{}'.format(self.local_port, self.local_host, self.remote_port),
            '-o', 'ExitOnForwardFailure=True',
            self.host
        ])
        if exit_status != 0:
            raise Exception('SSH tunnel failed with status: {}'.format(exit_status))
        if self.send_control_command('check') != 0:
            raise Exception('SSH tunnel failed to check')
        self.open = True

    def stop(self):
        if self.open:
            if self.send_control_command('exit') != 0:
                raise Exception('SSH tunnel failed to exit')
            self.open = False

    def send_control_command(self, cmd):
        return subprocess.check_call(['ssh', '-S', self.socket, '-O', cmd, '-l', self.user, self.host])

    def __enter__(self):
        self.start()
        return self

    def __exit__(self, type, value, traceback):
        self.stop()

以下是您可以使用它的方法,例如使用 MySQL(通常是端口 3306):

with SSHTunnel('database.server.com', 'you', '22', '/path/to/private_key', '3306') as tunnel:
    print "Connected on port {} at {}".format(tunnel.local_port, tunnel.local_host)
于 2016-04-07T19:34:57.067 回答
0

我是否可以建议尝试pyngrok以编程ngrok方式为您管理隧道?完全披露,我是它的开发者。这里是SSH 示例,这里是 Django 示例,但安装起来很简单:pyngrok

pip install pyngrok

并使用它:

from pyngrok import ngrok

# <NgrokTunnel: "tcp://0.tcp.ngrok.io:12345" -> "localhost:22">
ssh_tunnel = ngrok.connect(22, "tcp")

或者公开你的 MySQL 数据库:

# <NgrokTunnel: "tcp://0.tcp.ngrok.io:12346" -> "localhost:3306">
mysql_tunnel = ngrok.connect(3306, "tcp")

或者暴露给 Django 开发服务器:

# <NgrokTunnel: "http://<public_sub>.ngrok.io" -> "http://localhost:8000">
http_tunnel = ngrok.connect(8000)
于 2020-05-06T18:16:29.627 回答