💡

カメラ動画をWEBに表示しようとしたら地獄だった話

2023/06/25に公開

*記事中のURLにアフィリエイトリンクを使用する場合があります。

自己紹介

どうも初めまして、超貧困「株式会社NEXS(ネクシス)」の代表取締役「たぬき教祖」です。

*お仕事、ご相談お待ちしております。

今回はとある件でIPカメラの動画をWEBアプリケーション上に表示する必要がありました。
軽い気持ちで挑んだもののやってみると知らないことだらけ、何度も「これでいける!」と思ったものの、なんだかんだ2週間以上彷徨ったのでここに共有します。
細かく検証したりする時間はなくふわっと理解しておりますので、情報は間違ってるかもしれません。
役に立ったら評価してってねー

キーワード

キーワード多すぎて(ほぼ関係ないものもありますが)ざっと並べます。
IPカメラ(ネットワークカメラ)、RTSP、RTMP、HLS、QoS、Python、Node、npm、Deno、SSL、ws、wss、rtsp-relay、@ffmpeg-installer/ffmpeg、ffmpeg、node-media-server、Vue、Nuxt、Express、SSR、Firebase Hosting、Vercel、Render、エックスサーバー、VPS、pem、mkcert、Nginx、Ubuntu、nohup、forever、pm2

目的と背景

全体としてはIPカメラの動画を画像処理等云々するシステムです。
まあ論文公開されているのでいいでしょう。以下の論文のシステムをより実用的な形にするという話です。

極力動作環境を選ばず、ソフトのインストールを不要にするため、登録・設定用のアプリケーション及び画像処理を行うシステムをオンライン上に配置することになりました。
担当しているのは設定用のWEBアプリケーションで、動画を閲覧可能にしたいのですが、以下のような条件を考えます。

  • 極力安くしたい(本アプリ分は月1万円以内)
  • ユーザは何をするかわからない(高画質で動画を閲覧し続けるかも...)

答え

いきなりの答えですが、ナウい技術とかサーバレスとか考えず、エックスサーバーVPS借りてください。サーバの設定とか必要ですが、そこまで大変ではないはず。サーバの維持管理は大変かもしれませんが...
他の情報もざっくり下にあげます

こんな感じです。
何故Nuxt3(Vue3)時代にNuxt2かというと、「rtsp-relay」などのライブラリが基本的にExpress前提だからです。Nuxt3では標準では「nitoro」が使われているとかなんとか( https://nuxt.com/docs/guide/concepts/server-engine )。めんどくさいことになりそうなのでNuxt2にしました。
なおReactとかでもよいと思います。私がVue派なだけです。

本題

カメラの選定

何はともあれカメラを買わないことには始まりません。色々調べたところストリーミングのプロトコルは「RTSP」と「RTMP」がメジャーらしかったので両方に対応していて、かつ1万円以下で買えるものを探しました。ついでにONVIFや画質等条件も気にしつつ、適当に3,4種類買ったと思いますが、取り合えず「H.View 防犯カメラ ( https://amzn.asia/d/aHwii2I )」で検証をしました。

言語・環境の選定

【画像処理パート】はPythonで書かれています。負荷が大きく、契約に対して自動でサーバの立ち上げ等々を行いたかったのでDockerのコンテナにしてAWSのECSで動かすようにしました。

一方、【登録・設定用のアプリケーション】は、ユーザがどこからでも環境を問わずにアクセスできるよう、WEBアプリケーションとして開発することにしました。
WEBアプリ、といっても開発可能な言語(バックエンド)は様々ですが、料金や機能を考慮したとき、そもそも選択肢に残ったのは「Python」「JavaScript(NodeJS)」でした。
で、まあ、個人的にPythonは嫌いだったので、嫌いだったので()、取り合えずJavaScriptでやってみることにしました。最終的にVPSになるのだから究極言語は何でもよかったわけですが、この時はそんな選択肢になろうとは思ってもおりませんでした。
*JSとTSは特別区別はしてません

WEBで動画を再生する

そもそもWEB上で直接再生は...

できません。
WEBでストリーミング再生を実装したことがなかったので、頑張ればカメラからの動画を直接再生できると思ってました。多分Adobe Flash Playerの時代には、RTMPのストリーミングが再生できたのだと思います。しかし、Flash Playerを追放した現代では再生できません(多分)。

-----------余談
私が最初に学習した言語はActionScript3でした。8,9年前くらい、まさかこんなすぐになくなるとはね...
あれ以来ブラウザゲームも下火になり、しょうがないとはいえ代価もないのにFlashを追放した罪は大きい。

RTSPでの挑戦(RTSPかRTMPか)

RTSPでいくかRTMPでいくか、色々調べた結果RTMPはどうやら古いらしい、ということでRTSPを使うことにしました。今にしてみると必ずしもRTMPの方が古いということもありません。どちらもレガシーです。
*問題は「ではIPカメラで用いられる有用な代価のプロトコルは?」といっても特にないことでしょう。HLSのような形式は十分な計算、ストレージ、応答を確保する必要があります。IPカメラは割と時代に取り残されているオーパーツかも。YouTubeの配信でも結局RTMPですよね。

rtsp-relay

定番のライブラリ検索タイムです。色々調べた感じ「rtsp-relay」というライブラリが簡単に動かせそうでした(ここまでかなり時間かかってます)。
*私が「Express」を意識した、直接扱ったのはこの時が初めてです。当然いつも裏側で無意識に動いていたわけですが、適当に勉強しながら動かしました。特に難しいこともないですね。

さて、まず結果としては、取り合えずLAN内のカメラ映像をWEBブラウザに表示することには成功しました。
*ここからまだまだ長い

ポート開放

LAN内のカメラに外部からアクセスできるようにしたい、ということでポート開放が必要です。ここもそんなに複雑なことはないです。諸々数時間はかかってますが、以下のページ等の方法で特に問題ありません。
https://bouhancamera-choice.com/networkcamera-connect
*セキュリティは意識してください

また、今どきのネットワークはIPが再起動などのたびにころころ変わる契約が多いと思います。「ipconfig」とかこの辺( https://www.cman.jp/network/support/go_access.cgi )のサイトで確認してください。

外部からアクセスしてみる

外部から映像を確認してみます。取り合えず見てみるには「VLC Media Player」がおすすめです。RTSPでもRTMPでも閲覧できます。
で、結果としては、めっちゃ不安定!です。音声は基本的に来ていました。でもほとんどの場合は映像が来ません。色々アプリ変えてもダメでした。
一番時間を使ったのは多分この辺です。

後々エラーを調べたりする中で、どうやら動画が表示されているのはパケットが破棄されてほとんど届いてないっぽい、ということがわかってきました。

QoSという謎の設定

取り合えず原因を調べるため、いろんな設定、条件、閲覧ソフトを使いました。すっげー手探りです。その中で設定してみると少しだけ表示が改善されたのが「QoS」という謎の項目でした。よく意味が分からないままいじってます。
QoS:

QoS(Quality of Service)とは、ネットワーク上のサービスを安定して使えるようにするために、データを通す順番や量を調整する技術のことです。
https://network.yamaha.com/knowledge/qos

とのことです。TTLみたいなもんかねえ。よくわからない、というか、これを設定するだけで優先されるならそのうち皆が設定して結局意味なくなる気もするが、、、ともかく今は多少なり機能しているようなのでQoSを設定しました。
結果としては、動画が全く表示されない、ということはなくなりました。とはいえ、動画の半分ほどは上手く届いてない状況でした。

RTMPを試してみる

さて、状況として、実はここでお手上げでした。来た道を引き返すしかなくなり、RTSPを捨ててRTMPで試すことにしました。
*実はその他にJPEG形式で配信する方法などもあり、それはそれでうまくいきました。が、やっぱりそれは本道ではないので、安定した方法を目指して没にしました。

rtsp-relay(rtmp-relay)

RTSPからRTMPへの切り替えは実はかなり簡単です。rtsp-relayの中のRTSPのURL(?)を設定する箇所にRTMPのURLを設定するだけです。rtsp-relayに限らず、ほとんどのライブラリはこの方法で動作します。何故かというと、この手のストリーム系ライブラリはほぼ間違いなく「FFmpeg」で処理させているからです。
FFmpeg:

FFmpeg(エフエフエムペグ)は動画と音声を記録・変換・再生するためのフリーソフトウェアである
By Wiki。

FFmpegが同じような入力でRTSPもRTMPも受け付けるため、基本的に互換性があります。
*注意 パスワードが設定されているカメラはRTSPとRTMPのURL形式で以下の差があります。(厳密にはもうちょっと色々あります)
RTSP:rtsp://ユーザ名:パスワード@IPアドレス:554/live/main
RTMP:rtmp://IPアドレス:1935/livemain?user=ユーザ名&password=パスワード

さあ、RTMPで試してみる、と、なんとうまく表示されるではありませんか。
これが実に安定している。パケットの到着時間の影響か速度が微妙に一定ではない感じはありますが、RTSPで苦労したのがウソのように綺麗に受け取ることができ、遅延もおよそ0.5秒程度と快適です。
これで光明が見えた、気がしていました、この時は。

で、Nuxtでどうやって動かすの

取り合えずExpressで動かすことは成功しました。とはいえ、今更フロントをネイティブで(現代のフレームワークなしで)作成するのは無理があります。欲を言えば使い慣れたNuxt2で動くことを期待しました。とすれば、まずSSRは大前提です。これまでSSRのバックエンドはほぼ意識せずに(APIを除く)使ってきましたが、Nuxtのバックエンドがどこでどのように走っているか理解する必要がありました。
さて、始めにも書きましたが、何故Nuxt3ではなくNuxt2を使うかですが、「rtsp-relay」などのライブラリが基本的に「Express」前提だからです。Nuxt3では「nitoro」が使われてめんどくさいことになりそうです。

-----------余談
私が開発を本格的に始めた6年ほど前はまだVueやReactが日本に浸透していませんでした。当時はjQueryを使ったり使わなかったりして、今よりめちゃめちゃ大変な開発をしていました。つまり、できないわけではありませんが、とはいえ、一生戻りたくはない、です、はい。

答え:serverMiddleware を使う

NuxtでWebSocketなどの継続処理を行う場合「serverMiddleware」を使用します。動画再生のように継続的に処理を行いたい場合、当然REST APIのような形では実装できません。
「serverMiddleware」は、通常ページに遷移する前の認証情報の確認に使用するので、何となくページ遷移前に一時的に動作するイメージでしたが、どうやら継続して動作してくれるようです。

「server-middleware」フォルダを作成。その下に「ws.js」のようなファイルを作成。以下のように設定すれば動きます。

nuxt.config.js
serverMiddleware: [
	'~/server-middleware/ws.js'
],
/server-middleware/ws.js
const express = require('express');
const app = express();
const expressWs = require('express-ws')(app);
const {proxy: proxy} = require('rtsp-relay')(app);

const port = 2000;
const handler = proxy({
  url: `rtmp://IPアドレス:1935/livemain?user=ユーザ名&password=パスワード`,
  verbose: true,
});
app.ws('/api/stream', handler);
app.listen(port, function () {
  console.log(`port ${port} started`);
});
module.exports = {handler: app};

https://github.com/k-yle/rtsp-relay とほぼ同じですが、いくつか注意点としては、

  • 「const expressWs = require('express-ws')(app);」が必要です。通常Expressを呼んでいれば「app.ws()」が使用できますが(多分)、Nuxtに上書きされているのか、明示的に呼ぶ必要があります。
  • 「module.exports = {handler: app};」モジュールとしてエクスポートする必要があります。
  • 「verbose」をtrueにするとログが表示されます。

フロント側はまあVuetify使用していますが、ざっくり以下の感じです。

/pages/index.vue
<template>
  <div>
    <v-card>
      <v-card-actions>
        <canvas ref="canvas" style="max-width: 100%;"/>
      </v-card-actions>
      <v-card-actions>
        <v-btn color="primary" @click="play">play</v-btn>
      </v-card-actions>
    </v-card>
  </div>
</template>
<script>
import {loadPlayer} from 'rtsp-relay/browser';
export default {
  data() {
    return {};
  },
  methods: (
    play() {
      const canvas = this.$refs.canvas;
      loadPlayer({
        url: `ws://${location.host.split(":")[0]}:2000/api/stream`,
        canvas: canvas,
      });
    },
  },
};
</script>

さて、わかってしまえば楽です。これでかんせーい!!
なわけがないんですよね。

経過・挫折

答えから先に書きましたが、最初は上手く接続できず挫折してます。その時の話も書いておきます。
NuxtのSSRでの実装に失敗しましたが、フロントはNuxtを使用したいため、フロント(static)をNuxt、バックエンドをExpressに切り分けて、別々のサーバで運用する方法を考えました。この方法の利点としては

  • 様々な環境が利用できる
  • フロントはSPAで実装して適当なサーバどこにでも置ける
  • 動作に安定性が見込まれる

ということがあると思います。一方

  • ページ閲覧者がいなくてもバックエンドが動作し続ける
  • プロジェクトが分割されて管理やデバッグが少し面倒になる

という欠点もあります。
ま、欠点があるといっても、実装できないよりはよいのでこの方針で進めました。手間取ったのはバックエンドのデプロイ先です。常に待機させておかなければいけないので、実行時間の限られているものは選択できません。

Deno

色々調べてたどり着いたのが「Deno Deploy」です。
Deno( https://deno.com/ )とは

Denoは、Node.jsの製作者であるRyan Dahlによって作られた、新しいJS/TSランタイムです。すっごい雑に説明すると、Node.jsのイケてなかったところを改良したものがDenoになります。
https://qiita.com/azukiazusa/items/8238c0c68ed525377883

だそうです。
Deno DeployはWebSocketも使えそうな気配があり、書き方は少し異なるものの、無料で試せそうだし、試しておきたい技術だし、プロジェクトがすっきりするので使ってみました。

Deno Deployで、、、、駄目

結果的にはダメでした。Deno自体はかなり面白かったです。取り合えずデプロイもできました。ただ、まず躓いたのがパッケージのインポート。Denoのインポート方法は3つもあります。まず一つはこれまでのNpmのpackage、node_moduleを引き継いだもの。これは3つの中では邪道で、本意ではないが互換性や機能の不足のためにつけられている機能です。
以下の2つの方法が正道で、特に後者は推奨されている方法になります。

import express from "https://esm.sh/express@4";
import express from "npm:express@4";

ところが、この後者が比較的新しい方法で、まだDeno Deployでは使えません。
前者か邪道を利用する必要があります。

ところが動かない、「@ffmpeg-installer/ffmpeg」

推奨の方法では動いたものの、前者及びpackageを用いた方法ではローカルでもDeno Deployでも動作しませんでした。原因としては「FFmpeg」が見つからないとのこと。「rtsp-relay」ではFFmpegを利用しており、そのFFmpegは「@ffmpeg-installer/ffmpeg」によって環境に合わせたFFmpegがダウンロードされる仕組みになっています。
@ffmpeg-installer/ffmpeg( https://www.npmjs.com/package/@ffmpeg-installer/ffmpeg )
これによってNpm環境ではnode_module内にffmpegがダウンロードされ利用できるのですが、Denoでは基本的には「package」や「node_module」は存在せず、その扱いも異なるため、うまくFFmpegまでのパスがつながりません。ローカル環境では無理やりフォルダ構成をいじってやれば解決できましたが、Deno Deployではそれができず、断念することになりました。

デプロイ先を探す

実際にデプロイして動かすまで安心できません。この時点で想定していたデプロイ先は「Firebase Hosting」×「Firebase Functions」と「Vercel」、場合によっては「Heroku」という感じ。

Vercel(50MB問題)

最初に試したのがVercelです。Nuxt3よりは手間があるものの、Nuxt2でも比較的簡単にデプロイできます。ところが、Vercelを使用したことのある多くの方が突き当たる問題、50MB問題にぶち当たりました。パッケージ整理しましたが、そもそもNuxt2の時点で多分結構辛いと思われます。rtsp-relay等必要なライブラリだけで50MBを超えるので、Vercelは断念することになりました。
*なお恐らく、50MB制限がなくとも正しく動作はしないと思われます。

render

Vercelが駄目、とはいえFirebaseはだいぶめんどくさい。ついでにどうやらHerokuは無料利用ができなくなった模様。そこで新しいデプロイ環境を探しました。
参考になったのが以下の記事、この記事を参考に色々調べた結果「render」を使用してみることにしました。
https://zenn.dev/imah/articles/a41e889dbf54da

renderの感想としては「素」って感じです。どういうことかというと、例えばGitHubからプロジェクトを連携して読み込んだ後、「npm install」等の実行は自動ではしてくれません。
ビルドコマンドの設定に、通常「nuxt build」と書くところを「npm install && nuxt build」と書くような対応を自分でする必要があります。
他にも、サポートがなんか悪いというか、見当違いというか、あまり機能していないようにも見えます。

また、Nodeのバージョンが14であるのも少し引っかかるところです。メジャーなバージョンとはいえ、最近では16や18を使っている方が多いと思いますので、エラーが出たらNodeのバージョンを指定するのが良いと思います。バージョン指定の方法は色々ありますが、「.node-version」ファイルを作るのが一番楽でよいと思います( https://render.com/docs/node-version )。

renderの落とし穴1 通信量と料金

さて、デプロイも完了し、renderでクリアか、、、というとそんなことはありませんでした。2つの大きな落とし穴が。renderの料金( https://render.com/pricing )を見ると「Free Bandwidth」の項目があります。これ直訳で帯域幅なんですが,,,どうみてもこれ転送量ですよね??質問したわけではないので確かではないですが、どう見ても帯域幅の話ではなく転送量の話してると思います。で、転送量として無料プランで計算してみます。受信は無料のようなので、動画の配信分がかかるはずです。で、これも適当計算で全く参考にならないと思いますが、ユーザ一人が1台のPCで1カ月開きっぱなしにした場合、動画が1時間で5GBの通信を発生させるとすると、5GB×24時間×30日で3600GB。毎月100GBまで無料なので3500GBの料金、100GBあたり30ドルで30ドル×35で1050ドル。はい、優に10万円超えてきましたね。
つまり、この仕組みでは怖すぎておいそれと使えないわけです。

料金問題の補足

さて、ここまで読んでくださった方、がどれほどいるか、いないと思いますが、動画の配信をしてくれるサービスはAWSの中にもあると思いますし、例えば「WOWZA( https://www.wowza.com/ )」のようなストリーミングサービスもあります。この記事を読んでいる方はまずそっちを試せよ、と思われた方もいるかと思います。はい、書いてはいませんでしたが実は試してます。ですが、結局この通信の転送量による莫大な料金が問題でして、自前で作ることになってます。

renderの落とし穴2 SSL・wss問題

ところで、昨今のデプロイ環境は非常にめんどくさいことに優秀で、「Let's Encrypt」なんかを利用して最初からhttpsで接続でき、httpでアクセスしてもリダイレクトされるようになっています。
これがほとほと困りもので、「rtsp-relay」では WebSocket(ws) を使用してクライアントにJS-MPEGを送信しますが、https通信では暗号化された「wss」を使用する必要があります。ご存じの通り、httpsで接続したページにhttpやwsが混ざっているとエラーになるからです。当然、ブラウザの設定によりこれを無理やり回避する方法はありますが、ユーザにその操作を強いることは現実的ではありません。
では、wssを用いるにはどうするべきか、、、当然鍵情報が必要です。renderが鍵情報をくれるでしょうか?否です。独自ドメインの設定をすれば自分で鍵を設定できる、、、かどうかは正直調べてもよくわかりませんでした。その先結局動くかわからないのにそれを試すのはちょっとハードルが高いです。

とはいえローカル(Nuxt)のHttps化

独自の鍵が使える環境に備えてNuxtのhttps化をしました。以下のページが参考になります。
https://qiita.com/nobita_x009/items/0ce13d7ba08a287fbf94

「mkcert」初めて知りましたがこれめっちゃ便利ですね。

大幅な方向転換 「HLS」×「Node-Media-Server」

鍵情報が貰えず、必ずhttpsで接続される以上、この方法は手詰まりになりました。
ここで大幅に方向を転換し、httpを使用した動画配信方式「HLS」を試すことにしました。「RTMP」をNodeで「HLS」に変換して配信できるライブラリに「Node-Media-Server」があります。というわけで、「HLS」×「Node-Media-Server」の構成を試しました。
Node-Media-Server:https://github.com/illuspas/Node-Media-Server
HLS:

HLSはHTTP Live Streamingの略であり、Apple社が独自に開発した規格です。iOSだけでなく、Android(ネイティブ)や多くのWebブラウザで再生可能であり、AbemaTVのようなライブ配信サービスにも採用されています。
https://jp.vcube.com/sdk/blog/hls-http-live-streaming.html

さて、HLSはvideoタグで再生できるので詳細は省きます。以下のサイトなどが参考になると思います。
https://blog.webico.work/webmovie-hls

Node-Media-Serverを利用したバックエンドは一例を以下に示します。

media-server.js
const NodeMediaServer = require('node-media-server');
const ffmpegPath = require('@ffmpeg-installer/ffmpeg').path;
console.log(ffmpegPath);
const config = {
  rtmp: {
    port: 1935,
    chunk_size: 60000,
    gop_cache: true,
    ping: 30,
    ping_timeout: 60
  },
  http: {
    port: 8000,
    mediaroot: './media',
    allow_origin: '*'
  },
  trans: {
    ffmpeg: ffmpegPath,
    tasks: [
      {
        app: 'live',
        hls: true,
        hlsFlags: '[hls_time=2:hls_list_size=3:hls_flags=delete_segments]',
        hlsKeep: false,
        dash: true,
        dashFlags: '[f=dash:window_size=3:extra_window_size=5]',
        dashKeep: false
      }
    ]
  }
};
let nms = new NodeMediaServer(config)

nms.run();

「hlsKeep」や「dashKeep」を「true」にするとデータがガンガンたまってストレージを圧迫するので、今回の用途では「false」にします。

で、これもローカルではうまくいったので「render」にデプロイしてみたのですが,,,
結論から言うと動きませんでした。
詳細な原因は不明ですが、renderのサーバが、サーバに送り付けたRTMPを受信していなかったので、サーバがhttpのリクエスト以外ははじいているか、パケットが破棄されているか、ファイアウォール的な何かが弾いたのか、、、まあわかりませんが、取り合えずうまくいかずお手上げとなりました。

ついにエックスサーバー

いやー長かった。ようやくここまで来ました。いやここまで戻ってきました、ほぼ振り出しです。
諸々やればやるほど問題が出てくるので、結局VPSを借りることにしました。とはいえ、AWSのEC2などしっかりしたものを使えば通信料でお金がかかります。日本の適当なサーバを借りるのが良いと考えました。

VPS選定

参考にしたのは以下のページ。
https://tomato-code.com/4128/
どれも使用したことはありませんが、まあなんとなく「エックスサーバー」は高いけど安定、みたいなイメージがあったのでエックスサーバに決めました。

選択したOSはUbuntu、アプリケーションとしてNodeを選びました。
Ubuntuを使用したのは初めてでしたが、Linuxのディストリビューションなのでさして難しいところもないと思います。CentOSの終了もあって、これから出番は増えると思います。

アプリケーションとしてNodeを選びましたが、バージョンはまさかの10、ほぼ意味はないです。

エックスサーバ×Node、Nginxの構成

私は以下のページを参考にしました。丸っとそのままにはいかないかもしれませんが、ほぼこのままで問題ないと思います。
https://gadgelaun.com/?p=42840

タスクの常駐化、永続化

例えば「Tera Term」で「node app.js」をしてタスクを実行した場合、コンソールを閉じればタスクも終了します。そうならないためにタスクの永続化が必要です。
それを行うキーワードは「nohup」「forever」「pm2」あたりですが、「pm2」がよさそうだったのでこれを使用しました。
以下の記事などが参考になると思います。
https://zenn.dev/dokokade/articles/452b5376f9e260

例えば「npm run start」する場合は、代わりに以下のように実行します。

pm2 start npm --name task-name -- start

エックスサーバ×Nuxt

例えば以下のような記事がありますが、まあ正直ほぼあてにはなりません(ごめんなさい)。
https://dev.ore-shika.com/post/nuxtjs-install-server/

取り合えずプロジェクトをエックスサーバに突っ込んで、「npm i」「nuxt build」「nuxt start(pm2 start npm --name task-name -- start)」してあげれば普通に動きました。

Gitの設定

毎回WinSCPなどでプロジェクトをサーバにアップするのはかなり手間がかかります。サーバにGitをインストールしてSSHの設定をし、サーバからクローン、デプロイ、更新時にはマージしてデプロイ、これでかなりすっきり実行できると思います。
以下が参考になると思います。
https://inno-tech-life.com/dev/infra/git_ssh_github/
https://docs.github.com/ja/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent?platform=linux

さあ、これで問題はほぼ解決です。
後はそのまま使うなり、独自ドメインを設定するなり、鍵を入れてSSLするなり、セキュリティを気にするなり、まあ頑張ればよいと思います。

おわりに

色々言い残したこと
まずUbuntuは起動後「apt update」と「apt upgrade」したほうが良いと思います。
あと、エックスサーバーVPSではストレージを画面で確認できないので「df -h --total」みたいなコマンドで容量を確認する必要があります。
また、Nodeの更新などが終わった後など、定期的にコンソールを再起動してあげたほうが良いです。

ここまで閲覧いただきまして誠にありがとうございます。
IPカメラ方面の技術はかなり停滞しているなあ、という感想と、後はやはり動画分野はかなりお金がかかるなあという感覚を持ちました。WEB、ソフトウェア、アプリ、サーバ、画像処理、AI、AWS等々、結構広く携わってきたと思ってましたが、まだ初歩的ながら全然未知の世界があって、かなり勉強になりました。IT分野は突き詰めなくともあまりに広大で、勉強を怠ることのできない大変や分野ですね。「情報」の価値とはすさまじいものです。

あと、記事書くだけ書くのもなんかなあ、と思ってエックスサーバーだけアフィリエイトリンクにしてます。なんか軽く調べた感じ駄目でもなさそうだったので、駄目だったら教えてください。
ほんとはAmazonのリンクも変えたかったのですが力尽きました。

もしお役に立ちましたら、コメントでも残していっていただけると幸いです。

Discussion