Python Forum
Python app for ssh tunneling and opening web app
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Python app for ssh tunneling and opening web app
#1
Hi all,

This is my very first message, so few words about me. I’m a Data Engineer and mostly do scripting in Python, but recently I’ve created few web apps in Flask in a docker container, also looking into Django a bit.

Sinse security policy requires working through ssh tunneling, I have created a document for the team about creating ssh key and setting up a tunnel. Though for internal usage it is ok, our external users are less technically advanced and we would need to simplify the process.

This is how I create a tunnel:

Output:
ssh -L 3081:172.16.0.4:81 [email protected] -C -N
In this case browser url to access web app would be: http://127.0.0.1:3081/

Now I’m trying to write an app that creates an ssh tunnel and opens the url automatically. I’d need someone experienced with ssh tunneling to look into it and advise where is the issue.


import sys
import paramiko
from PyQt5.QtCore import QUrl
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout
from PyQt5.QtWebEngineWidgets import QWebEngineView

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("cool app")
        self.setGeometry(150, 150, 900, 700)

        # Create a web browser widget
        self.browser = QWebEngineView()
        self.browser.setUrl(QUrl("http://172.16.0.4:81"))

        # Create a layout for the main window
        layout = QVBoxLayout()
        layout.addWidget(self.browser)

        # Create a central widget and set the layout
        central_widget = QWidget()
        central_widget.setLayout(layout)
        self.setCentralWidget(central_widget)

        # Create an SSH tunnel to the Azure Virtual Machine
        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        ssh_key = paramiko.RSAKey.from_private_key_file('/home/user1/.ssh/id_rsa')
        ssh.connect('example.com', username='u1', pkey=ssh_key, port=22, timeout=100)
        ssh_transport = ssh.get_transport()
        ssh_channel = ssh_transport.open_channel('direct-tcpip', ('172.16.0.4', 81), ('172.16.0.4', 81))

        # Set the web browser URL to use the SSH tunnel
        self.browser.setUrl(QUrl("http://172.16.0.4:81"))

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())
Honestly, I don't really understand what exactly I'm doing here
ssh_channel = ssh_transport.open_channel('direct-tcpip', ('172.16.0.4', 81), ('172.16.0.4', 81))
I believe those two tuples should not be equal, I tried different combinations of ('172.16.0.4', 81) and ('127.0.0.1', 3081) - none of them worked.

For now the app opens the window, but after some time of waiting it shows error:

172.16.0.4 took too long to respond.

(or 127.0.0.1 took too long to respond.)

Please advise.

reposted: https://discuss.python.org/t/create-app-...-app/38722
buran write Nov-15-2023, 11:56 AM:
Please, use proper tags when post code, traceback, output, etc. This time I have added tags for you.
See BBcode help for more info.
Reply
#2
Console version works fine this way:
from sshtunnel import SSHTunnelForwarder
import requests

ssh_host = 'example.com'
ssh_user = 'user1'
local_port = 3081
remote_host = '172.16.0.4'
remote_port = 81
ssh_private_key_path = "/path/to/private/key"

with SSHTunnelForwarder(
    (ssh_host, 22),
    ssh_username=ssh_user,
    ssh_private_key=ssh_private_key_path,
    remote_bind_address=(remote_host, remote_port),
    local_bind_address=('127.0.0.1', local_port)
) as tunnel:
    response = requests.get(f'http://127.0.0.1:{local_port}/login')
    print(response.text)
Output:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Login</title> </head> <body> <h1>Login</h1> ... </body> </html>
but GUI version somehow returns error:
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtCore import QUrl
from sshtunnel import SSHTunnelForwarder
import sys

ssh_host = 'example.com'
ssh_user = 'user1'
local_port = 3081
remote_host = '172.16.0.4'
remote_port = 81
ssh_private_key_path = "/path/to/private/key"

class MainWindow(QMainWindow):
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)
        self.browser = QWebEngineView()
        self.setCentralWidget(self.browser)

    def set_tunnel(self, tunnel):
        self.tunnel = tunnel

    def load_url(self):
        self.browser.setUrl(QUrl(f'http://127.0.0.1:{local_port}/login'))

app = QApplication(sys.argv)

with SSHTunnelForwarder(
    (ssh_host, 22),
    ssh_username=ssh_user,
    ssh_private_key=ssh_private_key_path,
    remote_bind_address=(remote_host, remote_port),
    local_bind_address=('127.0.0.1', local_port)
) as tunnel:
    window = MainWindow()
    window.set_tunnel(tunnel)
    window.load_url()
    window.show()

sys.exit(app.exec_())
Output:
127.0.0.1 refused to connect.
Any idea why??...
Reply
#3
sys.exit(app.exec_())
This was outside of the with tunnel so the tunnel was closed before the gui starts.
Finally works OK now...
Reply
#4
Please review my repository: https://github.com/marchelloUA/ssh_tunnel_wrapper
It works perfectly fine for my needs and I’m totally happy with it, though for public usage I would need your opinion…
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020