Kết nối PostgreSQL trên VPS qua SSH Tunnel từ máy local
Dùng SSH Tunnel để máy dev kết nối PostgreSQL trên VPS mà không phải mở port 5432 ra internet, kèm cách cấu hình DATABASE_URL cho môi trường local và production.
Mục lục
Port 5432 của PostgreSQL trên VPS thường bị tường lửa chặn (và nên như vậy), nên máy
dev không kết nối thẳng vào database được. SSH Tunnel giải quyết việc này: nó ánh xạ
một port trên máy local sang port 5432 của VPS qua kết nối SSH đã mã hóa. Bài này
hướng dẫn mở tunnel và cấu hình .env cho từng môi trường (local / production).
Trong toàn bài, thay <username> bằng user SSH trên VPS, <server-ip> bằng IP VPS,
còn <db_user>, <password>, <database_name> là thông tin database của bạn.
~/.ssh/id_ed25519 là đường dẫn private key SSH - đổi lại nếu key của bạn tên khác.
Tóm tắt nhanh
Local - SSH Tunnel:
# Mở terminal riêng, giữ chạy suốt phiên làm việc
ssh -L 5432:localhost:5432 <username>@<server-ip> -i ~/.ssh/id_ed25519 -N# .env.local
DATABASE_URL=postgresql://<db_user>:<password>@localhost:5432/<database_name>Production (deploy chung VPS với database):
# .env.production
DATABASE_URL=postgresql://<db_user>:<password>@localhost:5432/<database_name>Trên production, backend chạy cùng VPS với PostgreSQL nên dùng thẳng localhost -
không cần SSH Tunnel.
1. Hiểu mô hình kết nối
+------------------+ SSH Tunnel +------------------+
| Máy local | ---- port 5432 -------------> | VPS |
| (máy dev) | ssh -L 5432:localhost:5432 | PostgreSQL |
| | | :5432 |
+------------------+ +------------------+- Local: máy dev không truy cập thẳng được database trên VPS (port 5432 thường bị firewall chặn) -> dùng SSH Tunnel để ánh xạ port 5432 local sang port 5432 của VPS.
- Production: backend deploy cùng VPS với database -> dùng
localhosttrực tiếp.
2. Tạo SSH Tunnel cho local dev
Mở một terminal riêng và chạy:
ssh -L 5432:localhost:5432 <username>@<server-ip> -i ~/.ssh/id_ed25519 -N| Flag | Ý nghĩa |
|---|---|
-L 5432:localhost:5432 | Forward port 5432 local sang port 5432 trên VPS |
<username>@<server-ip> | User SSH và IP của VPS |
-i ~/.ssh/id_ed25519 | Đường dẫn tới private key SSH |
-N | Không mở shell, chỉ giữ tunnel |
Terminal này phải giữ mở trong suốt phiên làm việc. Đóng terminal là mất kết nối database.
3. Cấu hình .env.local cho local dev
DATABASE_URL=postgresql://<db_user>:<password>@localhost:5432/<database_name>Vì SSH tunnel đã ánh xạ localhost:5432 sang VPS, backend sẽ kết nối database bình
thường như thể database nằm ngay trên máy local.
4. Cấu hình .env.production khi deploy chung VPS
DATABASE_URL=postgresql://<db_user>:<password>@localhost:5432/<database_name>Khi backend deploy cùng VPS với PostgreSQL, localhost trỏ thẳng tới database trên
cùng máy - không cần tunnel hay IP công khai.
5. Nâng cao: chạy SSH Tunnel ở background
Nếu không muốn giữ terminal mở, có thể chạy tunnel ở background:
ssh -f -N -L 5432:localhost:5432 <username>@<server-ip> -i ~/.ssh/id_ed25519| Flag | Ý nghĩa |
|---|---|
-f | Chạy ở background sau khi xác thực |
-N | Không mở shell |
Để tắt tunnel đang chạy background (macOS / Linux):
# Tìm PID
ps aux | grep "ssh -f -N -L"
# Kill process
kill <PID>Trên Windows (PowerShell):
# Tìm PID
Get-Process ssh | Where-Object { $_.CommandLine -like "*5432*" }
# Kill process
Stop-Process -Id <PID>6. Nâng cao: xử lý trùng port
Nếu máy local đã có PostgreSQL chạy trên port 5432, cho tunnel dùng port local khác:
ssh -L 5433:localhost:5432 <username>@<server-ip> -i ~/.ssh/id_ed25519 -NVà cập nhật .env.local:
DATABASE_URL=postgresql://<db_user>:<password>@localhost:5433/<database_name>Cách ngược lại - giữ tunnel ở 5432 và đổi port của PostgreSQL local - được mô tả trong bài Clone database PostgreSQL từ VPS về máy local Windows.
Xử lý sự cố
| Triệu chứng | Nguyên nhân | Cách xử lý |
|---|---|---|
Connection refused trên local | SSH tunnel chưa chạy hoặc đã bị đóng | Kiểm tra terminal đang giữ tunnel, chạy lại lệnh SSH |
Address already in use | Port 5432 local đã bị chiếm (PostgreSQL local đang chạy) | Dùng port khác: -L 5433:localhost:5432 |
Permission denied (publickey) | Sai đường dẫn key hoặc key chưa được thêm vào VPS | Kiểm tra đường dẫn sau -i, đảm bảo public key có trong ~/.ssh/authorized_keys trên VPS |
Network is unreachable | VPS không online hoặc IP đã thay đổi | Kiểm tra ping tới VPS, xác nhận lại IP |
| Tunnel tự ngắt sau một thời gian | Server timeout do idle | Thêm -o ServerAliveInterval=60 vào lệnh SSH |
Lệnh đầy đủ để giữ tunnel ổn định:
ssh -L 5432:localhost:5432 <username>@<server-ip> \
-i ~/.ssh/id_ed25519 \
-N \
-o ServerAliveInterval=60 \
-o ServerAliveCountMax=3