レンタルサーバーのMySQLに他サーバーからSSH+Node.jsで接続する

レンタルサーバー(たとえばXサーバー)のMySQLに、他サーバーにデプロイしたNode.jsアプリから接続する方法についてメモ。

前知識

基本的に、どのレンタルサーバーも外部から直接MySQLに接続することは許可していないらしい。

たとえば、ローカルのPCから

mysql -u username -p -h ホスト名 --port 3306 データベース名

みたいなコマンドで直接続することはできません。

おそらく、セキュリティのために以下の設定をしているためだと思われます。

  • ファイアウォールでポートを開放していない
  • MySQLの設定ファイル(mysqld.cnf)でbind-addressが設定されている

 

なのでこのような場合、SSH接続してSSH経由でポートフォワーディングしてMySQLの3306番に接続する・・・という手順を踏むと接続できるぽいです。ポートフォワーディングというのは「このポートにアクセスがきたら、このポートに転送してね!」みたいなやつです。

sshコマンドで言うと、以下のとおりです。

ssh -L 3306:localhost:3306 {ユーザー名}@{接続先ホスト} -i {秘密鍵ファイル}

 

これをNode.jsのプロセス上で実行させたい・・・というのがこの記事の内容です。

tunnel-sshでポートフォワーディング

いろいろ方法はあるっぽいのですが、以下のライブラリを使うと手軽っぽいです。

tunnel-ssh – npm

 

TypeScriptを使う場合は、以下のDefinitelyTypedが用意されていますが、これは最新版のtunnel-sshに対応していないぽいので使えません。
これを使う場合は古いバージョンを使う必要があります。

@types/tunnel-ssh – npm

 

ただ、tunnel-sshのissueを見ると、有志の人が「型定義(.d.ts)作ったよ」なコメントしてくれてたので、これを利用します。

作成するファイル

上のissueの内容をもとに型定義ファイルをつくります。

参考:TypeScriptで自作の型定義ファイルを追加する

 

つぎに以下の2つのファイルをつくります。

createSSHTunnelToMySQLPort.ts

import { createTunnel } from "tunnel-ssh";
import fs from "fs";

export async function createSSHTunnelToMySQLPort() {
  const PORT = 3306; //MySQLのポート番号
  const TUNNEL_OPTION = {
    autoClose: true,
  };
  const SERVER_ONTION = {
    port: PORT,
  };
  const SSH_OPTION = {
    username: "SSH接続に必要なユーザー名",
    host: "SSH接続に必要なホスト名",//Xサーバーの場合は「sv○○.xserver.jp」みたいなやつ,
    port: "SSH接続に必要なポート名", //Xサーバーの場合は10022
    privateKey: fs.readFileSync("src/backend/秘密鍵.key"),
  };

  const FORWARD_OPTION = {
    srcAddr: "localhost",
    srcPort: PORT,
    dstAddr: "localhost",
    dstPort: PORT,
  };

  await createTunnel(TUNNEL_OPTION, SERVER_ONTION, SSH_OPTION, FORWARD_OPTION);
}

 

index.ts

import mysql from "mysql2/promise";
import { createSSHTunnelToMySQLPort } from "src/backend/createSSHTunnelToMySQLPort";

(async () => {
  await createSSHTunnelToMySQLPort();

  const connection = await mysql.createConnection({
    host: "localhost",
    user: "レンタルサーバーのMySQLのユーザー名",
    password: "レンタルサーバーのMySQLのパスワード",
    database: "接続するデータベース名",
  });

  const sql = "SELECT * FROM `hoge`";
  try {
    const [result] = await connection.query(sql);
    console.log(result);
    connection.destroy();
  } catch (error) {
    console.log("データベースでなんらかのエラー")
  }
})();

 

そして、レンタルサーバーのMySQL上でhogeというテーブルを作ります。

ここでは以下のようなテーブルにしました(idカラムがあるだけのテーブル)。

CREATE TABLE IF NOT EXISTS `hoge` (
`id` int(40) unsigned DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

 

そしてレコードも適当にいくつか挿入します。

INSERT INTO `hoge`(`id`) VALUES (1);
INSERT INTO `hoge`(`id`) VALUES (2);

 

この状態で、ローカルでts-node index.tsを実行すると、以下のような結果になります。

ちなみにts-nodeでpathエイリアスを使う場合は、tsconfig-pathsというパッケージが追加でインストールしないとMODULE_NOT_FOUNDというエラーが出てしまいます。
(ここらへんの俺俺ルールが多すぎてTypeScriptややこしいですよね😑)

参考:ts-node で path alias が効かないにハマる – かもメモ

 

これで、Node.jsからレンタルサーバー上のMySQLにアクセスできたことが確認できました。

余談:ChatGPTに書かせてみた

ChatGPTで、以下のように質問したらすごく良い感じのコードを書いてくれました。

動くかどうかは試してないですが、ザッと見た感じ

  • 間違っていたとしても微修正すれば動きそうですし、
  • 関数もとてもキレイにかかれてるし、

ChatGPTすげえええええええええってなりました。関数の説明も簡潔で分かりやすいですし、マジですごすぎる。

わざわざ自分で書く必要なかった説・・・。

というか今の時点でこれだけ精度が高いのなら、近いうちに「AIにコードを書かせてエンジニアはコードレビューだけする」みたいな時代が来るんでしょうね確実に。すごい時代だぜ・・・。

 

おわり

Node.js
スポンサーリンク
この記事を書いた人
penpen

1991生まれ。WEBエンジニア。

技術スタック:TypeScript/Next.js/Express/Docker/AWS

フォローする
フォローする

コメント

タイトルとURLをコピーしました