起動パラメータから Node-RED エディタ画面の有効・無効を出し分けるメモ

起動パラメータから Node-RED エディタ画面の有効・無効を出し分けるメモです。

やりたいこと

Node-RED を別ポート・別フローで個別実行する処理を package.json の npm run コマンドでまとめたメモ

こちらをベースに進めます。

「Node-RED エディタ画面の有効・無効を出し分ける」というのは、たとえば、

  • 手元の環境(ローカル)の場合はバックエンドとしての Node-RED をゴリゴリ編集するのでエディタ画面は有効にしていじくり倒したい
  • 上記の仕組みをサーバーに公開して動かすときは、セキュリティの観点からエディタ画面は無効にしたい

という用途を考えています。

サーバーに公開するときの注意ポイントとしてはいくつかあります。ざっと自分の経験から上げると。

  • adminAuth 編集によるログインユーザーとパスワードの導入が正攻法だが、慣れてないと、それなりに対応が大変
    • ここに書かれているパスワード認証 を導入するとログインユーザーとパスワードが設定できるので正攻法ではある
    • ではあるが、なにぶん node-red admin hash-pw でパスワードを生成したあと、それをコピーして、setting.js の adminAuth 部分を JSON を壊さないように慎重に編集する必要がある
    • adminAuth で JSON 構造が壊れているような編集ミス、あるいはパスワードの入力を間違ってて入れないみたいな入力ミスは慣れてないと原因が特定しにくい
    • 仕事ではこの対応をおススメするけど、慣れてない人のために追加マニュアルが必要だったり、デリケートな部分なので私がやってしまったりする。
  • 上記がうまくいったとしてエディタ画面で公開サーバーがいじれても注意すべきところは多い。おもに作業面。
    • 一人で作業するとき
      • 一人開発でも公開サーバーで編集したものの手元の開発データとの同期は大切
      • プロジェクト機能で Git 連携できなくはないがフローに焦点が当たっていて、それ以外の環境部分の同期も大切
    • 発展して複数人が共同作業するとき
      • 勝手に編集した時にお互いにどうするか?など、その複数人の間での同期の取り決めが必要
  • かといって、ログインユーザーとパスワードなしで公開は危なすぎる。
    • 誰でも入れる。ノーガード。
    • エディタ画面のURL乱数にすれば少しはましだけど、もしもURLが分かってしまうとサーバーの中身が好き勝手変えれてしまう(これはこわい)

ということを考えると、最初に挙げたような起動パラメータから Node-RED のエディタ画面を有効・無効を出し分けることで、 いっそのこと公開時はエディタ画面は無効して開発時だけ有効してしまおう という手は、上記の懸念がかなり気にしなくてよくなるので有効手段だなと思っています。

httpAdminRoot パラメータで有効・無効を切り替える

ローカルでNode-REDを実行する ところに書かれているように、Node-RED 1.1.0 から起動オプション -D で setting.js で設定したパラメータを上書きできます。

エディタ画面のパラメータでいえば、設定 にあるとおり httpAdminRoot/admin にすればエディタ画面が http://localhost:1880/admin でアクセスできるようになり有効化されていて、 false にすれば無効化されます。

ちなみに、似たもので disableEditor パラメータはあるようです。ただ、これは、エディタ画面は無効にしても Admin API がアクセスできちゃうようなので、やはり今回は管理に関するものは全部閉じたいので httpAdminRoot がいいですね。

対応してみる

ということで、Node-RED を別ポート・別フローで個別実行する処理を package.json の npm run コマンドでまとめたメモ を元に環境構築した Node-RED プロジェクトを作ります。

{
  "name": "node-red-switch-editor-access",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "node-red": "node-red -p 18801 -u ./node-red_dir -s ./node-red_dir/settings.js",
    "init":"npm run init:mkdir && npm run init:get-settings.js",
    "init:mkdir":"node -e \"console.log('[START] mkdir-node-red_dir');const fs = require('fs');const path_nodered_dir = './node-red_dir';if (fs.existsSync(path_nodered_dir)) {console.log( '[ALERT] ' + path_nodered_dir + ' has existed!');} else {console.log('[OK] mkdir -> ' + path_nodered_dir );fs.mkdirSync(path_nodered_dir);}\"",
    "init:get-settings.js": "node -e \"const url = 'https://raw.githubusercontent.com/node-red/node-red/master/packages/node_modules/node-red/settings.js';const stream_output_path = './node-red_dir/settings.js';if (fs.existsSync(stream_output_path)) {console.log( '[ALERT] ' + stream_output_path + ' has existed!');} else {console.log('[START] download settings.js ...');const https = require('https');const fs = require('fs');const stream = fs.createWriteStream(stream_output_path);https.get(url, function(res){res.pipe(stream);res.on('end', function () {stream.close();console.log('[OK] got settings.js! -> ' + stream_output_path);});});}\""
  },
  "keywords": [],
  "author": "",
  "license": "MIT"
}

もともとの設定はこのようになっています。

まず有効の設定

node-red_dir/setting.js の中身を直接編集して httpAdminRoot を

httpAdminRoot: '/admin',

にします。 2021/09/16 現在デフォルトの設定ファイルだと、すでにこの設定がコメントアウトされて存在しているので、コメントアウトを外す形でもいいでしょう。

npm run node-red

この設定を済ませて Node-RED をこのコマンドで再起動します。

image

すると http://localhost:18801/admin で管理画面にアクセスできます。

無効にする上書き設定パラメータ -D コマンドをためす

エディタ画面無効のコマンドを作ります。ローカルでNode-REDを実行する を参考にしつつ httpAdminRoot false で上書きします。

node-red -p 18801 -u ./node-red_dir -s ./node-red_dir/settings.js -D httpAdminRoot=false

-D httpAdminRoot=false をつけて上書きを命じています。Node-RED を一度終了して、こちらのコマンドを実行して試してみます。

image

http://localhost:18801/admin をアクセスしてもエディタ画面が見えず無効になっています。これで「設定ファイルをそのまま使うとエディタ画面が /admin で有効になるが、 -D httpAdminRoot=false パラメータをつけて設定を上書きした起動をすればエディタ画面が無効になる」ということがコマンドで実現できました。

16 Sep 11:53:42 - [info] Node-RED version: v2.0.5
16 Sep 11:53:42 - [info] Node.js  version: v14.17.5
16 Sep 11:53:42 - [info] Windows_NT 10.0.19042 x64 LE
16 Sep 11:53:43 - [info] Loading palette nodes
16 Sep 11:53:43 - [info] Settings file  : 
16 Sep 11:53:43 - [info] Context store  : 'default' [module=memory]
16 Sep 11:53:43 - [info] User directory : 
16 Sep 11:53:43 - [warn] Projects disabled : editorTheme.projects.enabled=false
16 Sep 11:53:43 - [info] Flows file     : 
16 Sep 11:53:43 - [info] Admin UI disabled
16 Sep 11:53:43 - [info] Server now running at http://127.0.0.1:18801
16 Sep 11:53:43 - [info] Creating new flow file
16 Sep 11:53:43 - [warn]

実は起動時に [info] Admin UI disabled が出ているので、動作が判断しやすいです。

無効にするコマンドを npm scripts に反映

ということで、npm scripts にも別起動できるように反映していきます。

{
  "name": "node-red-switch-editor-access",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "node-red-no-editor":"node-red -p 18801 -u ./node-red_dir -s ./node-red_dir/settings.js -D httpAdminRoot=false",
    "node-red": "node-red -p 18801 -u ./node-red_dir -s ./node-red_dir/settings.js",
    "init":"npm run init:mkdir && npm run init:get-settings.js",
    "init:mkdir":"node -e \"console.log('[START] mkdir-node-red_dir');const fs = require('fs');const path_nodered_dir = './node-red_dir';if (fs.existsSync(path_nodered_dir)) {console.log( '[ALERT] ' + path_nodered_dir + ' has existed!');} else {console.log('[OK] mkdir -> ' + path_nodered_dir );fs.mkdirSync(path_nodered_dir);}\"",
    "init:get-settings.js": "node -e \"const url = 'https://raw.githubusercontent.com/node-red/node-red/master/packages/node_modules/node-red/settings.js';const stream_output_path = './node-red_dir/settings.js';if (fs.existsSync(stream_output_path)) {console.log( '[ALERT] ' + stream_output_path + ' has existed!');} else {console.log('[START] download settings.js ...');const https = require('https');const fs = require('fs');const stream = fs.createWriteStream(stream_output_path);https.get(url, function(res){res.pipe(stream);res.on('end', function () {stream.close();console.log('[OK] got settings.js! -> ' + stream_output_path);});});}\""
  },
  "keywords": [],
  "author": "",
  "license": "MIT"
}

scripts に "node-red-no-editor":"node-red -p 18801 -u ./node-red_dir -s ./node-red_dir/settings.js -D httpAdminRoot=false", を加えました。

npm run node-red-no-editor

これを実行してみます!

image

起動ログにも [info] Admin UI disabled が出てアクセスできないことを確認できました。

開発時は npm run node-red で動かし、公開サーバーでは npm run node-red-no-editor で動かせば「公開時はエディタ画面が無効で、開発時はエディタ画面で編集できる」状況が作れそうですね!

あくまでひとつのアプローチではありますが、なかなか使えそうです。試してみます。