NodeJS通过SSH连接远程PostgreSQL时遭遇pg_hba.conf认证失败问题求助
解决通过SSH隧道连接远程PostgreSQL的问题
看起来你核心的问题是没有通过SSH隧道做端口转发——你只是建立了SSH连接到服务器,但数据库请求还是直接从你的本地机器发往远程数据库,而不是通过SSH隧道转发到服务器内部的PostgreSQL服务。这就导致了pg_hba.conf的认证错误,因为服务器的PostgreSQL配置只允许localhost(服务器内部)的连接,拒绝外部IP的直接请求。
下面是具体的解决方案和代码修改:
关键思路
我们需要通过SSH建立本地端口转发:把你本地机器的某个端口(比如5433)映射到远程服务器的localhost:5432(也就是你手动连接时用的PostgreSQL地址)。这样你的代码连接本地的5433端口,就相当于通过SSH隧道连接到服务器内部的PostgreSQL服务,完全符合你手动连接的逻辑。
修改后的代码示例
1. 更新SSH连接代码(serverConn.js)
添加端口转发逻辑,确保数据库请求通过隧道转发:
const { Client } = require('ssh2'); const { readFileSync } = require('fs'); const databaseConnectionParams = require('./databaseConn'); // 端口转发配置:本地端口 -> 远程服务器的PostgreSQL地址 const LOCAL_PORT = 5433; const REMOTE_DB_HOST = 'localhost'; const REMOTE_DB_PORT = 5432; function connectToServer() { const conn = new Client(); conn.on('ready', () => { console.log('Client :: ready'); // 设置本地端口转发 conn.forwardLocal(LOCAL_PORT, REMOTE_DB_HOST, REMOTE_DB_PORT, (err) => { if (err) { console.error('Failed to set up port forwarding:', err); return; } console.log(`Port forwarding active: localhost:${LOCAL_PORT} -> ${REMOTE_DB_HOST}:${REMOTE_DB_PORT}`); // 端口转发成功后再连接数据库 databaseConnectionParams.auth(); }); // 保留uptime测试(可选) conn.exec('uptime', (err, stream) => { if (err) throw err; stream.on('data', (data) => console.log('STDOUT: ' + data)) .stderr.on('data', (data) => console.log('STDERR: ' + data)); }); }); // 监听SSH连接错误 conn.on('error', (err) => console.error('SSH connection error:', err)); // 建立SSH连接 conn.connect({ host: 'xx.xx.xx.xx', username: 'username', privateKey: readFileSync('src/key/id_rsa') }); } exports.connectToServer = connectToServer;
2. 修正数据库配置(env.js)
现在连接本地转发的端口,关闭SSL(SSH隧道已经加密,不需要额外SSL):
const env = { database: 'databasename', username: 'username', password: 'password', host: 'localhost', // 连接本地转发端口 port: 5433, // 和上面配置的LOCAL_PORT一致 dialect: 'postgres', ssl: false, // 隧道已加密,关闭PostgreSQL SSL pool: { max: 5, min: 0, acquire: 30000, // 修正拼写错误:aquire -> acquire idle: 10000 } }; module.exports = env;
3. 修正Sequelize连接逻辑(databaseConn.js)
用authenticate()代替validate()(前者才会实际建立数据库连接),并添加端口参数:
const envParam = require('./env.js'); const { Sequelize } = require('sequelize'); const sequelize = new Sequelize(envParam.database, envParam.username, envParam.password, { host: envParam.host, port: envParam.port, // 新增端口参数 dialect: envParam.dialect, ssl: envParam.ssl, pool: { max: envParam.pool.max, min: envParam.pool.min, acquire: envParam.pool.acquire, idle: envParam.pool.idle } }); async function auth() { try { console.log('trying to connect'); await sequelize.authenticate(); // 实际建立数据库连接 console.log('Database connection successful!'); } catch (error) { console.error('Unable to connect to the database:', error); } } exports.auth = auth;
为什么之前的方法无效?
- 你之前的SSH连接只是登录了服务器,但数据库请求还是从本地直接发往远程数据库IP,而服务器的pg_hba.conf不允许外部IP的直接连接。
- SSL问题是因为直接连接远程IP需要SSL验证,但通过隧道后,你连接的是服务器内部的localhost,不需要SSL,关闭即可解决。
validate()方法只是检查配置格式,不会实际建立数据库连接,所以之前的代码根本没尝试真实连接。
额外注意事项
- 如果本地5433端口被占用,可以换成其他未被使用的端口(比如5434),记得同步修改env.js里的port参数。
- SSH连接必须保持打开状态,数据库连接才能正常工作,不要在建立隧道后关闭SSH客户端。
内容的提问来源于stack exchange,提问作者Suhhs
相关产品推荐
相关产品推荐

