You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 12:27:41