node.jsでベクトルタイルサーバを作成（レンタルサーバ編）Rocky Linux8

# はじめに

[こちらの記事](https://qiita.com/k96mz/items/d394f1ac0b71d80a93c0)で同様の内容を記載していましたが、サーバの選定が不適切でした。RHEL(Red Hat Enterprise Linux release) 8.10 (Ootpa)のテストサーバとして利用するつもりで、CentOS Linux 7を利用していましたが、RHEL8とCentOS7だと構成が大きく異なるため不適切でした。前回記事の最後に、エラーが出たのも古いCentOS7を使用していたからかもしれません。そこで今回は、Rocky Linux 8を利用したいと思います。Rocky LinuxはCentOS 8のサポート終了を受けて誕生した、Red Hat Enterprise Linux (RHEL)と完全互換性を持つオープンソースのディストリビューションです。
使用したコードは[こちら](https://github.com/k96mz/20241025hostingPracticeServerRockyLinux)にあります。

# レンタルサーバ環境
今回も、KAGOYAさんのVPSをレンタルすることにしました。

OS: Rocky Linux 8
メモリ：　1GB
ストレージ: 25GB SSD
node version: v16.20.2 ※nvmで管理
npm version: 8.19.4

# サーバへの接続
まずは、kagoyaさんのページでログイン用認証キーを取得します。その後、以下のようにすると、サーバへ接続出来ます。

```
ssh -i ~/.ssh/ログイン用認証キー番号.key root@サーバIPアドレス
```

オプションの-iは、「接続に使用する公開鍵ファイルを指定する」ものです。

公開鍵を作成したユーザの下のフォルダに以下のように置くことで、sshで接続ができるようになりました。
~/.ssh/authorized_keys

具体的には以下です。
```
ssh -i ~/.ssh/ログイン用認証キー番号.key ユーザ名@サーバIPアドレス
```

鍵ファイルの権限についても600（所有者のみが読み書き可能）と設定しました。
chmod 600 ~/.ssh/authorized_keys


## サーバへのファイルコピー
サーバへのファイルコピーは以下のコマンドを実行します。

```
scp -i ~/.ssh/ログイン用認証キー番.key -r ~/コピー元フォルダ root@サーバIPアドレス:~/ 
```


# FTP設定
サーバにFTP接続するために、FTP接続を待ち受けているデーモンの一つである「vsftpd」をサーバにインストールしました。こちらの[サイト](https://tech.sadari.co.jp/server-os/linux-server/linux-centos-ftp-install/)を参考にしました。さらに、ファイアウォールの設定を行いました。ポート21は自動的に開放されたようです。コマンドライン上での接続が成功しました。

次にFTP接続するために、ユーザー名とパスワードを設定しました。

以下のコマンドでユーザーを作成します。
```
adduser newusername
```

以下のコマンドでパスワードを設定します。
```
passwd newusername
```

[こちらのサイト](https://qiita.com/shinon_uk/items/d827848d9809420111f8)も参考にしました。

FileZillaでもうまくいきました。


# nvmのインストール
サーバにnvmをインストールしました。
インストール方法は[githubの公式サイト](https://github.com/nvm-sh/nvm)を参考にしました。

以下のコマンドでインストール出来ました。
```
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
```

インストール後にnvmコマンドが見つからないというメッセージが出る場合には、ターミナルを再起動するか、bash環境においては以下のコマンドを実行すると正常にnvmコマンドが使用できます。

```
source ~/.bashrc
```

## node.jsのインストール
nvmを利用して、開発環境のホスティングサーバに合わせて
node version: v16.20.2
をインストールします。

以下のコマンドでインストール出来るはずですが、tarコマンドがシステムにインストールされていないというエラーが発生しました。
```
nvm install v16.20.2
```

そのため、まずは以下のコマンドでtarコマンドをインストールします。
```
sudo yum install -y tar
```

しかし、またもやエラーが発生しました。現在のユーザがsudo権限を持っていないというエラーです。

rootユーザーでサーバにログインし直して、以下のコマンドを実行して、sudoersファイルを編集します。
```
visudo
```

ファイルの最後に以下の記述を加えました。これで記載のユーザ名はsudo権限を持つはずです。
```
ユーザ名 ALL=(ALL) ALL
```

再度、ユーザでサーバにログインし直して、tarコマンドをインストールしました。今度はうまくいきました。
次に、node.jsをインストールします。こちらもうまくいきました。


npmのバージョンは8.19.4がインストールされています。


# モジュールのインストール

以下のようにしてモジュールをインストールします。
```
npm install config express cors morgan winston winston-daily-rotate-file @mapbox/mbtiles spdy hjson hh-mm-ss
```

# 静的フォルダからベクトルタイルを配信
node app0.js
とするとエラーは発生はしないのですが、
http://サーバのIPアドレス:3000/
としても、ページが表示されません。どうやらサーバでポート3000を開放していないことが原因のようなので、開放しました。

```
sudo firewall-cmd --list-ports // 開放されたポートの確認
sudo firewall-cmd --add-port=3000/tcp --permanent // ポート3000を開放
sudo firewall-cmd --reload // 変更を反映させるためにファイアウォールを再読み込み
```

しかし、これでもウェブサイトは表示されません。
→後から試すと、なぜかうまく表示されました。

作成したユーザではうまく表示されないのかもしれないと思い、rootユーザとしてファイルをコピーするところから再度試してみました。そうするとなぜかウェブサイトは表示され、地図も表示されました。権限の問題などで作成したユーザではうまく表示されなかったのかもしれません。


# MBTilesファイルからベクトルタイルを配信
node app.js
とすることで、こちらも地図が表示されました。

以前の記事でsqlite3のバージョンについての注意事項について記載しましたが、今回はバージョンを意識しなくてもうまくいきました。やはり前回のエラーは、CentOSのバージョン7を利用していたことによるエラーのようです。今回は、node_modulesフォルダのsqlite3はバージョン5.1.7となっていました。


# httpからhttpsにする

# Let's Encryptを利用したSSLサーバー証明書の入手
作業し始めた時には、すでに取得したSSLサーバー証明書に現在のドメインを追加する方法を考えていましたが、エラーが発生してどうすることも出来なかったので、以前のVPSのサーバ（インスタンス）は全て削除し、再度新しいサーバを作成して、新たに証明書を取得することにしました。

## Nginxのインストール

[こちらのページ](https://certbot.eff.org/instructions?ws=nginx&os=snap)の方法を利用しようと思いましたが、まずはNginxのインストールが必要なようなので、インストールします。
[こちら](https://docs.nginx.com/nginx/admin-guide/installing-nginx/installing-nginx-open-source/)のNginxのページにインストール方法がありましたので、以下のコマンドを実行します。
```
sudo yum install epel-release
sudo yum update
sudo yum install nginx
sudo nginx -v
```
nginx version: nginx/1.14.1
がインストール出来ました。

[こちらのページ](https://kinsta.com/jp/knowledgebase/install-nginx/)にNginxの起動方法が記載されていました。
```
sudo systemctl start nginx
sudo systemctl enable nginx
```
とします。
その後、
http\://サーバIPアドレス
としても、Nginxのウェルカムページが表示されませんでした。

[こちらのページ](https://zenn.dev/aym613/scraps/0ccbc49bbb1200)のトラブルシューティングを試してみました。Webサーバ上から接続出来ましたが、外からは出来ないのでファイアウォールが原因のようです。以下のコマンドでポート80へのアクセスを有効にします。

```
sudo firewall-cmd --add-port=80/tcp --permanent
sudo firewall-cmd --reload
```

無事にNginxのウェルカムページが表示されました。

![スクリーンショット 2024-10-30 14.26.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3684675/00b4bdd5-05bd-e718-0a9a-8a47ee1fd519.png)

## Certbotを利用したSSLサーバー証明書の入手
[こちらのcertbotのページ](https://certbot.eff.org/instructions?ws=nginx&os=snap)
に沿って作業をします。

### snapdのインストール
snapとはパッケージ管理システムで、snapdとはそのデーモンです。snapdは、Snapパッケージのインストールや管理を行うためのインターフェースを提供します。
私は[こちら](https://snapcraft.io/docs/installing-snap-on-rocky)のrocky linuxのページのインストールを実行しました。

### Certbotのインストール

次に以下のようにしてCertbotをインストールします。
```
sudo snap install --classic certbot
```

Certbotコマンドを実行するために以下を実施
```
sudo ln -s /snap/bin/certbot /usr/bin/certbot
```

### 証明書入手
証明書入手のためのコマンドを実施
```
sudo certbot --nginx
```

表示に従ってドメイン名などを入力すると証明書が無事に発行されました。以下に保存されています。

Certificate is saved at:
/etc/letsencrypt/live/ドメイン名/fullchain.pem

Key is saved at:
/etc/letsencrypt/live/ドメイン名/privkey.pem

証明書の自動更新も行ってくれるようです。

### 期限の確認
以下のコマンドで証明書期限の確認ができます。
```
sudo certbot certificates
```
例えば、以下のように表示されます。

Expiry Date: 2025-03-29 20:09:11+00:00 (VALID: 59 days)

新しく作成された、cert.pemとprivkey.pemを必要なディレクトリに格納することで、正常なhttps接続が実行さ

### サーバの起動

```
node appHttps.js 
```
としてサーバを起動して、

https\://ドメイン名
とするとサイトが表示されました。

https\://IPアドレス
だとサイトが表示されないことがあります。どうやら、SSL証明書は通常、特定のドメイン名に対して発行されており、IPアドレスに対しては発行されていないからのようです。

### 証明書の場所変更
前回の記事に記載したとおり、以下の場所にコピーしました。cert.pemは名前も変更しています。

privkeyPath: ./key/privkey.pem
fullchainPath: ./key/cert.pem

node appHttps.js
を実行します。

## HTTPSでの地図表示
index.htmlのページからHTTPSのページに飛ぶことが出来ました。なぜか最初はうまくベクトルタイルが表示されませんでしたが、再度ページを読み込むと表示されました。挙動が不安定な気がします。何度も読み込むと、5回に1回くらい成功します。
結局は、作成したユーザでも地図は表示されましたが、引き続きは挙動は不安定です。
以下のスクリーンショットのように、「(failed)net::ERR_HTTP2_PROTOCOL_ERROR」というエラーメッセージが出ます。

![スクリーンショット 2024-11-11 14.45.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3684675/31f7f41b-d742-fec8-86de-b52dd8288247.png)

chromeで実験していましたが、Edgeでやってみるとなぜかエラーが出ませんでした。（しかし、後日試すと、やはりエラーが出ました。。）
chatGPTに聞いてみたところ、HTTP/2の仕様の実装の違いや、SSL/TLSの設定の不整合があるかもしれないとのことでした。

mapbox-gl.cssをあえて読み込まないと、エラーが発生する頻度が減るようです。サーバのメモリ容量が少ないためエラーが発生するのかもしれません。[元記事のGitHub](https://github.com/ubukawa/server-test-01/tree/main/htdocs)では、mapbox-gl_r.cssというファイル名ですが、map-pbf.htmlファイルなどでは、mapbox-gl.cssと記載されており、読み込みされていない状況です。

## maplibreの最新版でやってみる

もしかしたら、maplibreの最新版でやってみるとうまくいくかもしれないと思い、以下のファイルをダウンロードして試してみました。
```
curl -O https://unpkg.com/maplibre-gl@5.1.0/dist/maplibre-gl.js
curl -O https://unpkg.com/maplibre-gl@5.1.0/dist/maplibre-gl.css
```

しかし、エラーは解消されませんでした。

## maplibreのURL版でやってみる

コードを以下のように修正してやってみました。

```html: mapOs-pbf.html
<link
      rel="stylesheet"
      href="https://unpkg.com/maplibre-gl@4.1.3/dist/maplibre-gl.css"
    />
    <script src="https://unpkg.com/maplibre-gl@4.1.3/dist/maplibre-gl.js"></script>
```

そうすると無事に地図が表示されました。

![スクリーンショット 2025-02-04 9.45.14.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3684675/f32b342f-3a18-cae7-8092-1e1c95b875b1.jpeg)


（追記）
[こちらの記事](https://qiita.com/k96mz/items/ac5e4c8b59940ada3384)でエラー回避方法を記載しています。

# まとめ
自分なりに試行錯誤で行った過程を記録しました。Nginxのインストールも行いましたが、本当にインストールが必要だったかどうかなど、疑問点も多く今後もネットワーク関係について勉強していきたいと思います。

# Reference

https://qiita.com/k96mz/items/d394f1ac0b71d80a93c0

https://tech.sadari.co.jp/server-os/linux-server/linux-centos-ftp-install/

https://www.kagoya.jp/howto/it-glossary/security/lets-encrypt/

https://qiita.com/T-ubu/items/545d9f995ef7496a2ec4

https://github.com/ubukawa/server-test-01