问题描述
我想出了下面的解决方案。我已经留下了第二个更新以获得更多说明。
背景
我有一个 discord 机器人,它是使用 discord.js 库用 JavaScript 编写的,我自己已经研究了近两年。一年多前,我开始使用 MysqL 进行数据库查询等。这是在我本地的 Windows 10 机器上。由于这在当时只是一个小型业余爱好项目,我并不太担心只有一个 MysqL 实例用于开发和生产。最后,大约 9 个月前,我能够在运行 Ubuntu 18.04 的 Linode 服务器上启动并运行机器人,以及在那里运行的 MysqL 数据库副本。
到目前为止,通过这种设置,一切都运行得很顺利。我使用 Windows PC 上的本地数据库进行开发和测试,然后将更新推送到生产数据库所在的 Linode 上的 Ubuntu 18.04 服务器。此外,为了以防万一这有帮助,我在进行开发时确实在我的 PC 上本地运行机器人。有两个 discord 机器人带有两个独特的令牌(一个用于生产,一个用于开发),以便我可以在进行更新时保持生产中的一个运行。我没有像生产机器人那样在服务器上 24/7 全天候运行开发机器人。
然而,最近,我的一个朋友(自称为“for-loop extraordinaire”)开始帮助我进行开发。因此,我们认为现在也是让开发数据库 24/7 全天候活动的好时机,这样无论我在不在,他都可以在机器人上工作。这就是我们解决问题的地方。
问题
我在下面留下了更新,因为我已切换到 MysqL2
软件包以尝试寻找解决方案。
所以,如果不是很明显,我的目标很简单:我希望我的机器人(在我或我朋友的 Windows 机器上使用 node.js 在本地运行时)连接到托管在其上的远程数据库我的 Ubuntu 18.04 服务器,在云端,而不是我的本地网络。我不害怕承认我远不是一个好的 Web 开发人员,所以我不知道这些东西是如何工作的后勤或来龙去脉。我能走到这一步真是个奇迹。但我认为它会像连接到本地 MysqL 实例一样简单。但是,当我运行代码时,控制台会向我吐出这个错误。
Error: connect ECONNREFUSED LINODE.IP.ADDRESS.HERE:3306
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1141:16)
--------------------
at Protocol._enqueue (D:\Users\path\node_modules\MysqL\lib\protocol\Protocol.js:144:48)
at Protocol.handshake (D:\Users\path\node_modules\MysqL\lib\protocol\Protocol.js:51:23)
at Connection.connect (D:\Users\path\node_modules\MysqL\lib\Connection.js:119:18)
at Object.<anonymous> (D:\Users\path\bot\index.js:118:5)
at Module._compile (internal/modules/cjs/loader.js:1138:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1158:10)
at Module.load (internal/modules/cjs/loader.js:986:32)
at Function.Module._load (internal/modules/cjs/loader.js:879:14)
at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:71:12)
at internal/main/run_main_module.js:17:47 {
errno: 'ECONNREFUSED',code: 'ECONNREFUSED',syscall: 'connect',address: 'LINODE.IP.ADDRESS.HERE',port: 3306,fatal: true
}
以下是我的代码的当前设置方式:
const MysqL = require("MysqL")
//CONNECT TO MysqL
var con = MysqL.createConnection({
host: 'example.com',user: 'user',password: 'pass',database: 'botDB',charset: "utf8mb4"
});
//CONNECTED TO DATABASE
con.connect(err => {
if (err) { throw err };
console.log("My database is up and running!")
})
当 host
为 localhost
(显然)时,此方法完美无缺,但当尝试远程连接到 Linode 上的服务器时,它只是拒绝。我试过 Linode URL (example.com
) 和 IP (LINODE.IP.ADDRESS.HERE
) 地址,都给我同样的错误。我也知道 Node 的 MysqL2
包存在,我只是还没有切换。如果切换实际上有助于解决这个问题,请告诉我。
我尝试过的解决方案
我在本网站上尝试了多个类似问题的多个答案,例如 this one 和 this,但是没有一个解决方案有效(包括添加 socketPath
或更改 {{1 }} 等)
我已尝试将 port
文件中的 bind-address
更改为 MysqLd.cnf
和 0.0.0.0
,这两者确实允许机器人连接到数据库,但是访问仍然被拒绝实际读取数据库本身。我所知道的是它至少已连接(尽管现在再次尝试给我留下了错误消息)
*
MysqL 是最新的,所以这与我不使用 code: 'ER_NOT_SUPPORTED_AUTH_MODE',errno: 1251,sqlMessage: 'Client does not support authentication protocol requested by server; consider upgrading MysqL client',sqlState: '08004',fatal: true
有关系吗?无论如何,我不喜欢这个选项,但我想我至少会尝试一下。
我最后的手段是创建一个 SSH 隧道来连接到数据库。再说一次,我仍然是一个 web 开发新手,所以我并不完全知道我在做什么,但我遵循了 this guide here,但是替换了我需要的代码,最终得到了一个完全独立的 SSH 连接错误.如果绝对需要 SSH 来完成我想要的,那么请告诉我,我将就此提出一个新问题。我只是想在这里提及它以表明我至少尝试过。
更新
我尝试了 Archil's solution,虽然现在我已经切换到 MysqL2
,但它确实让我对 MysqL 的身份验证系统有了更好的了解,这让我受益匪浅首先切换。不幸的是,Archil 的回答和 MysqL2
升级都给了我同样的错误:
MysqL2
...尽管我已授予 {
code: 'ER_ACCESS_DENIED_ERROR',errno: 1045,sqlState: '28000',sqlMessage: "Access denied for user 'root'@'MY.LOCAL.IP.ADDRESS' (using password: YES)"
}
所有权限。
无论如何,这都不是我的首选方式。如果有更安全的解决方案,我会很乐意接受。既然我已经安装了 'root'@'%'
,我将继续尝试不同的解决方案。
更新 2
在进一步研究之后,我发现权限并没有像我想象的那样为我尝试连接到服务器的用户设置。一旦我解决了这个问题,它确实连接了,但是当机器人启动时被查询的表之一显示为空。原来它不存在!
我制作了一份生产数据库的副本,作为新开发数据库的基础。问题是,我的本地(旧)开发数据库中缺少 的表。这让我相信机器人正在与 MysqL 连接,但没有从数据库中读取任何内容。我添加了正确的表格,效果很好!我在下面留下了一个包含更具体步骤的解决方案,以防其他像我这样的新手 Web 开发人员找到此页面。感谢您的帮助!
解决方法
关于如何获得此解决方案,我已经进行了第二次更新。
简而言之,将 bind-address
设置为 0.0.0.0
确实有效。如果您使用原始的 mysql
软件包,则需要遵循 Archil's solution。如果您正在使用 mysql2
并且仍然有错误(或者如果 Archil 的回答不适用于 mysql
),请确保您尝试连接的用户的 double-check the permissions使用:
SHOW GRANTS FOR 'user'@'%';
假设您像我一样尝试远程连接,如果您还没有,则需要使用“%”通配符创建一个用户。
此时它应该连接,就像对我一样,如果之后有任何错误,可能与数据库本身中的表有关。
,我已经回答https://stackoverflow.com/a/50547109/4089212
请检查。 您需要更改 mySQL 的身份验证模式。
,就我而言 (mariadb),我已设法将文件中的绑定地址更改为 0.0.0.0:
sudo nano /etc/mysql/mariadb.conf.d/50-server.cnf
重新启动后,我设法连接到数据库:
service mysql restart
您可能需要在文件夹 /etc/mysql/mariadb.conf.d/
只需查找绑定地址(可能有一个像 127.0.0.1 这样的 IP 地址)