SORACOM Napter のポートマッピング設定を Node-RED から API で設定するメモ
この記事は SORACOM Advent Calendar 2025 の 7 日目の記事です。
SORACOM Napter のポートマッピング設定を Node-RED から API で設定するメモです。
背景
Napter によるポートマッピングの管理を SORACOM コンソールでなく API で GUI 付きでやってみたいときがあり、その時に Node-RED で丁寧にデータを見ながら行っているので、その知見をまとめておきます。
PortMapping API の仕様

SORACOM の Napter による転送設定はこちらの API で操作することができます。
リファレンス: SORACOM API リファレンス | SORACOM API 利用ガイド | ソラコムユーザーサイト - SORACOM Users
まずは認証キーの仕組み

Node-RED のフローはこちらです。
認証キーを準備しておいて /auth をアクセスして、API キーと API トークンを保管します。
global.resultSoracomAuth という形で Node-RED グローバル変数に入れて使いまわします。本来であれば、以後、API にアクセスを保持したいときはリフレッシュトークンが必要です。
今回は、試すのみなので、シンプルに取得した前提ですすめます。
ここで言いたいことは、Node-RED だけでも API キーと API トークンを取得して、リフレッシュトークンの仕組みもちゃんと作れるよということです。(これは未来でまた SORACOM の認証まわりで悩んだときのアドバイス)
実際のフロー

今回は GET メソッドでのポートマッピング一覧取得と POST メソッドのポートマッピング登録をシンプルに行うものです。
ポートマッピング一覧取得

ポートマッピング一覧取得から説明します。

ヘッダー設定の change ノードです。

グローバル変数からヘッダーに API キーと API トークンを設定します。

実際にアクセスする http request ノードです。

- メソッド
- GET
- URL
https://api.soracom.io/v1/port_mappings
- 出力形式
- JSON オブジェクト
に、設定に設定しています。これで一覧データにつながります。

inject ノードをクリックして実行すると、このようにポートマッピングの一覧データが配列で取得できます。
実際、この受け取った JSON データでフロントエンドで一覧を表示するとテンションが上がります。
ポートマッピング登録

ポートマッピング登録の説明をします。

こちらもヘッダー設定 change ノードについては先ほどの一覧と同様にグローバル変数からヘッダーに API キーと API トークンを設定します。

ポートマッピング詳細設定の中身です。

以下のような内容です。
{
"destination": {
"imsi": "{{{global.TargetSoracomIMSI}}}",
"port": 1880
},
"duration": 3600,
"source": {
"ipRanges": [
"XXX.XXX.XXX.XXX/32"
]
},
"tlsRequired": true
}
global.TargetSoracomIMSI には対象の SIM の IMSI を事前にグローバル変数で指定しているので {{{global.TargetSoracomIMSI}}} という形でデータが入ります。
あとは リファレンス: SORACOM API リファレンス | SORACOM API 利用ガイド | ソラコムユーザーサイト - SORACOM Users のポートマッピング登録のデータ内容を見つつ、設定をします。
この場合は 3600 秒(= 1時間)で 1880 ポートを開く設定です。
source.ipRanges の IP アドレスは、フロントエンドなどで取得した操作中でありポートマッピングを開放したいアクセス中の PC の IP アドレスを指定します。
Node-RED の場合、ダッシュボード操作からは IP アドレス情報がちゃんと降りてくるので活用できます。(これはこれで結構説明が長くなる知見なので、今回は割愛します。)

実際にアクセスする http request ノードです。

- メソッド
- POST
- URL
https://api.soracom.io/v1/port_mappings
- 出力形式
- JSON オブジェクト
に、設定に設定しています。これで登録につながります。

inject ノードをクリックして実行すると、このようにポートマッピングに登録できたデータが取得できます。
削除 API ももちろんある
もちろん API で DELETE メソッドでしかるべき設定をすれば削除もできるのですが、デリケートな操作ですので、必要になったら実装する形でいいと思います。
私の場合でも、まず、登録と一覧が安定して、削除はコンソールで行うか時間切れを待つという形で初動は運用することが多いです。
フロー JSON はこちら
こちらの JSON のフローデータです。
[{"id":"6e5f88246524facf","type":"group","z":"7b778279626ef599","name":"PortMapping 設定","style":{"label":true},"nodes":["a1460734cc7a2897","bb70431a354506a7","d4f3136fdb0f8535","70406fad2b4caeb2","49cd87d3825337b6"],"x":54,"y":199,"w":732,"h":142},{"id":"a1460734cc7a2897","type":"inject","z":"7b778279626ef599","g":"6e5f88246524facf","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":180,"y":240,"wires":[["bb70431a354506a7"]]},{"id":"bb70431a354506a7","type":"change","z":"7b778279626ef599","g":"6e5f88246524facf","name":"ヘッダー設定","rules":[{"t":"set","p":"headers.X-Soracom-API-Key","pt":"msg","to":"resultSoracomAuth.apiKey","tot":"global"},{"t":"set","p":"headers.X-Soracom-Token","pt":"msg","to":"resultSoracomAuth.token","tot":"global"},{"t":"set","p":"payload","pt":"msg","to":"{}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":420,"y":240,"wires":[["49cd87d3825337b6"]]},{"id":"d4f3136fdb0f8535","type":"http request","z":"7b778279626ef599","g":"6e5f88246524facf","name":"POST /port_mappings","method":"POST","ret":"obj","paytoqs":"ignore","url":"https://api.soracom.io/v1/port_mappings","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":480,"y":300,"wires":[["70406fad2b4caeb2"]]},{"id":"70406fad2b4caeb2","type":"debug","z":"7b778279626ef599","g":"6e5f88246524facf","name":"debug 6","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":680,"y":300,"wires":[]},{"id":"49cd87d3825337b6","type":"template","z":"7b778279626ef599","g":"6e5f88246524facf","name":"ポートマッピング詳細設定","field":"payload","fieldType":"msg","format":"json","syntax":"mustache","template":"{\n \"destination\": {\n \"imsi\": \"{{{global.TargetSoracomIMSI}}}\",\n \"port\": 1880\n },\n \"duration\": 3600,\n \"source\": {\n \"ipRanges\": [\n \"XXX.XXX.XXX.XXX/32\"\n ]\n },\n \"tlsRequired\": true\n}","output":"json","x":220,"y":300,"wires":[["d4f3136fdb0f8535"]]},{"id":"95ac2a623051685d","type":"group","z":"7b778279626ef599","name":"PortMapping 一覧","style":{"label":true},"nodes":["b5c5b5489d9754bf","4708116bfd5d15a7","6af0064048699f95","22f5a55e4feab44b"],"x":54,"y":39,"w":732,"h":142},{"id":"b5c5b5489d9754bf","type":"inject","z":"7b778279626ef599","g":"95ac2a623051685d","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":180,"y":80,"wires":[["4708116bfd5d15a7"]]},{"id":"4708116bfd5d15a7","type":"change","z":"7b778279626ef599","g":"95ac2a623051685d","name":"ヘッダー設定","rules":[{"t":"set","p":"headers.X-Soracom-API-Key","pt":"msg","to":"resultSoracomAuth.apiKey","tot":"global"},{"t":"set","p":"headers.X-Soracom-Token","pt":"msg","to":"resultSoracomAuth.token","tot":"global"},{"t":"set","p":"payload","pt":"msg","to":"{}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":420,"y":80,"wires":[["6af0064048699f95"]]},{"id":"6af0064048699f95","type":"http request","z":"7b778279626ef599","g":"95ac2a623051685d","name":"GET /port_mappings","method":"GET","ret":"obj","paytoqs":"ignore","url":"https://api.soracom.io/v1/port_mappings","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":480,"y":140,"wires":[["22f5a55e4feab44b"]]},{"id":"22f5a55e4feab44b","type":"debug","z":"7b778279626ef599","g":"95ac2a623051685d","name":"debug 1","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":680,"y":140,"wires":[]}]
ポートマッピングの処理が API でできると、いろいろな仕組みに安全にアクセスできる組み込めるので楽しいです!