PostgreSQL Through SSH
Quick Guide Python → PostgreSQL Through SSH
PostgreSQL Through SSH
Quick Guide: Python → PostgreSQL Through SSH
1. Architecture
Your setup is:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Windows PC
│
▼
WSL2
│
│ SSH tunnel
│ localhost:15432
▼
Ubuntu laptop
│
│ localhost:5432
▼
PostgreSQL 18.6
│
▼
tompkins database
The important point:
- PostgreSQL port:
5432 - SSH tunnel port in WSL2:
15432 15432is only the local endpoint of the tunnel.
2. Verify PostgreSQL on Ubuntu
On Ubuntu:
1
sudo -u postgres psql -c "SHOW port;"
Expected:
1
5432
PostgreSQL is listening on:
1
127.0.0.1:5432
3. Create the SSH tunnel
From WSL2:
1
ssh -L 15432:127.0.0.1:5432 admin@192.168.1.65
Keep this terminal open.
The syntax is:
1
-L LOCAL_PORT:REMOTE_HOST:REMOTE_PORT
So:
1
2
3
4
5
15432:127.0.0.1:5432
│ │ │
│ │ └── PostgreSQL on Ubuntu
│ └───────────── Ubuntu's localhost
└────────────────────── WSL2 local port
4. Test the tunnel with psql
Open a second WSL2 terminal:
1
psql -h 127.0.0.1 -p 15432 -U postgres -d tompkins
Then:
1
SELECT version();
You successfully tested this with:
1
PostgreSQL 18.6
Exit:
1
\q
5. Set up Python
In WSL2:
1
2
3
4
5
6
7
mkdir -p ~/python-postgres
cd ~/python-postgres
python3 -m venv .venv
source .venv/bin/activate
pip install psycopg2-binary
6. Python connection
test_connection.py:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import psycopg2
conn = psycopg2.connect(
host="127.0.0.1",
port=15432,
dbname="tompkins",
user="postgres",
password="YOUR_PASSWORD"
)
print("Connected to PostgreSQL!")
cur = conn.cursor()
cur.execute("SELECT version();")
result = cur.fetchone()
print(result[0])
cur.close()
conn.close()
Run:
1
python3 test_connection.py
You successfully obtained:
1
2
Connected to PostgreSQL!
PostgreSQL 18.6 ...
7. What is happening?
Python connects to:
1
127.0.0.1:15432
SSH forwards that connection to:
1
Ubuntu 127.0.0.1:5432
PostgreSQL receives it normally.
So Python does not directly connect to:
1
192.168.1.65:5432
and PostgreSQL does not need to be exposed to the network.
8. Do you need to create the tunnel every time?
With the manual approach, yes.
Every time you need the connection:
1
ssh -L 15432:127.0.0.1:5432 admin@192.168.1.65
Then run Python in another terminal.
You can later simplify this with SSH configuration or background tunnels.
Current workflow
1
2
3
4
5
6
7
8
Terminal 1 — WSL2
ssh -L 15432:127.0.0.1:5432 admin@192.168.1.65
Terminal 2 — WSL2
cd ~/python-postgres
source .venv/bin/activate
python3 test_connection.py
This is the fundamental Python → SSH tunnel → remote PostgreSQL pattern.
This post is licensed under
CC BY 4.0
by the author.