Raspberry Pi 4でNext.js+SQLiteはどこまで動くか検証する

1. はじめに

校内で使用する資産管理Webアプリ「Asset-Trace」を、Raspberry Pi 4で動かせないか検討しています。今回はサンプルアプリではなく、実際に作成したNext.jsプロジェクトの中身を確認したうえで、測定項目を決めました。

想定しているのは、QRコードを使って備品を登録し、棚卸や検索を行うWebアプリです。利用者はPC、タブレット、スマートフォンから校内LAN経由でアクセスします。

想定用途
├─ 校内資産の一覧表示と検索
├─ QRコードを使った資産登録
├─ 棚卸時の情報更新
└─ 数人から数十人による利用

ただし、受け取ったのはアプリ本体で、Raspberry Pi 4上のベンチマークログではありません。そのため、開発PCで確認できたバージョンやデータ件数と、Piで測るべき性能値を分けて扱います。Raspberry Pi 4で何人まで快適に使えるか、応答時間が何ミリ秒になるか、といった数値はまだ断定しません。

この記事では、実際に測定するための構成、記録項目、負荷試験方法、SQLiteから別のデータベースへ移行する判断基準を先に整理します。測定後に結果欄を埋めることで、実測ベースの記事として完成させます。

2. Raspberry Pi 4を使う理由

Raspberry Pi 4を候補にする理由は、小型で校内LANへ設置しやすく、一般的なLinux環境としてNode.jsを動かせるためです。

今回の用途は、インターネット全体へ公開する大規模サービスではありません。校内LANまたは利用者を限定した環境で、数人から数十人が資産情報を検索・登録する想定です。

大規模な一般公開サービス
  → 今回の想定外

校内LANの資産管理
  → 今回の検証対象

小規模な個人開発サービス
  → 今回の検証対象

一方、Raspberry Pi 4には、一般的なサーバーPCと比べてCPU、メモリ、ストレージ、冷却、電源に制約があります。

Next.jsのビルドではCPU、メモリ、ストレージを使います。動的なページ生成やAPI処理ではCPUとメモリ、SQLiteの更新ではストレージの書き込み性能と待ち時間が影響する可能性があります。

「Raspberry Pi 4だから遅い」「数十人なら必ず十分」と先に決めず、実際のアプリとデータを使って測定する必要があります。

3. 検証環境

性能値は、Raspberry PiのRAM容量、OS、Node.js、ストレージ、ネットワーク、冷却方法によって変わります。測定結果と一緒に環境を記録します。

確認項目 検証環境
Raspberry Piのモデル Raspberry Pi 4【要確認:詳細モデル・リビジョン】
RAM容量 【要確認:Raspberry Pi 4のRAM容量】
OSとバージョン 【要確認:OSとバージョン】
64bitまたは32bit 【要確認:OSのアーキテクチャ】
Node.jsのバージョン 【要確認:Raspberry Piで使用するNode.jsのバージョン】
パッケージマネージャー npm(package-lock.jsonを確認)
Next.jsのバージョン 15.5.15(ロックファイルとインストール済みパッケージで確認)
Reactのバージョン 19.2.5
SQLiteライブラリ Node.js標準のnode:sqliteDatabaseSync
ストレージの種類 【要確認:microSD・USB SSD・NVMeなど】
ストレージの製品・容量 【要確認:使用ストレージ】
ネットワーク接続 【要確認:有線LANまたはWi-Fi】
冷却方法 【要確認:ヒートシンク・ファンなど】
電源アダプター 【要確認:使用する電源アダプター】

OSとアーキテクチャは、次のようなコマンドで確認できます。

cat /etc/os-release
uname -m

Node.jsとパッケージマネージャーも記録します。

node -v
npm -v

このプロジェクトのpackage.jsonではNext.jsが^15.3.3となっていましたが、package-lock.jsonと実際のインストール内容では15.5.15でした。再現性を保つため、Piではnpm installよりもロックファイルに従うnpm ciを使い、検証時のバージョンを改めて記録します。

SQLiteには外部パッケージではなくNode.js標準のnode:sqliteを使っています。Node.js公式資料ではnode:sqliteはNode.js 22.5.0で追加され、DatabaseSyncのAPIは同期的に実行されます。今回の開発PCではNode.js 24.15.0とnpm 11.12.1を確認できましたが、これはRaspberry Pi上の実行環境ではありません。Piでも対応するNode.jsを用意し、node -vと実際の起動結果を記録します。

実アプリから確認できた構成

ソースコードと開発用データを読み取り専用で確認した結果は次のとおりです。個人名や認証情報は確認・掲載していません。

項目 確認結果
アプリ QRコード対応の校内資産管理Webアプリ
主なAPI 認証、状態の取得・保存、アカウント、管理者招待、資産エクスポート
DBファイル data/asset-trace.sqlite
ジャーナルモード WAL
同期設定 PRAGMA synchronous = NORMAL
DB接続 1つのDatabaseSyncをプロセス内で再利用
開発データ ユーザー4件、場所129件、資産8件、履歴42件、監査ログ46件、移管4件
確認時のファイルサイズ DB 77,824バイト、WAL 4,227,152バイト、SHM 32,768バイト

この件数とファイルサイズは、開発PC上で2026年7月20日に確認した状態です。Raspberry Pi 4の処理速度を示す実測値ではありません。また、WALファイルは動作状況やチェックポイントのタイミングで変化します。

4. システム構成

検証する通信構成は次のとおりです。

PC・タブレット・スマートフォン
              ↓
           校内LAN
              ↓
        Raspberry Pi 4
              ↓
     Next.js + Node.js
              ↓
            SQLite

Raspberry Pi 4上でNext.jsの本番サーバーとSQLiteを動かします。利用端末は校内LANを通してNext.jsへアクセスします。

SQLiteは別のデータベースサーバーへ通信するのではなく、アプリからデータベースファイルを読み書きします。

Raspberry Pi 4
├─ Node.js
│  └─ Next.js
    ├─ node:sqlite(DatabaseSync)
    └─ data/asset-trace.sqlite

このアプリのHTTP用スクリプトはポート3011、LAN向けHTTPSサーバーはポート3443を使う構成です。どちらを採用するかは運用方法に合わせます。カメラでQRコードを読む場合、ブラウザのセキュアコンテキストが必要になるため、LAN内HTTPSと端末側の証明書信頼設定も接続試験へ含めます。

校内LANで運用する場合は、Raspberry PiのIPアドレスが変わらないよう、ルーターやDHCPサーバーで予約する方法を検討します。固定IPの設定方法は学校のネットワーク方針に従います。

5. Next.jsを動かす

Node.jsを確認する

最初にNode.jsとnpmを確認します。

node -v
npm -v

Next.jsが要求するNode.jsの最低バージョンは更新されることがあります。インストールするNext.jsの公式ドキュメントとpackage.jsonを確認し、対応するNode.jsを使用します。

新しいNext.jsプロジェクトを作る

新規プロジェクトを作る場合の例です。

npx create-next-app@latest

対話形式でTypeScript、App Router、スタイルなどを選択します。生成される構成はcreate-next-appのバージョンで変わる可能性があります。

Raspberry Pi上で直接作成しても構いませんが、別PCで開発したプロジェクトをGitなどで取得し、Raspberry Pi上では依存関係のインストールと本番ビルドだけを行う方法もあります。

既存プロジェクトを動かす

既存プロジェクトの基本的な流れは次のとおりです。

npm ci
npm run build
npm run start

ロックファイルを使って依存関係を固定している場合は、プロジェクトの運用ルールに合ったインストールコマンドを使用します。npm、pnpm、yarnを途中で混在させないようにします。

npm run buildは本番用のビルドを作成し、npm run startは作成済みの本番ビルドを起動します。ビルドが正常に完了していない状態では、通常のnext startは使用できません。

開発モードと本番モードの違い

開発中は次のコマンドを使用します。

npm run dev

開発モードには、ファイル変更の検知、再コンパイル、エラー表示など、開発を助ける機能があります。コードを直しながら確認する用途に向いています。

本番運用では、次の流れにします。

npm run build
npm run start

本番ビルドでは、配信用にビルドされた状態で起動します。開発モードと本番モードでは処理内容やキャッシュの動作などが異なるため、性能検証もnpm run startで行います。

npm run devの結果だけで、本番時の性能を判断しないようにします。また、開発サーバーを校内向けの常時運用プロセスとして使い続けないようにします。

LAN内の別端末からアクセスする

必要に応じて、Next.jsをすべてのネットワークインターフェースで待ち受けるようにします。

npm run dev -- --hostname 0.0.0.0

npmでは、--より後ろの引数がNext.js CLIへ渡されます。

本番起動時に明示する例です。

npm run start -- --hostname 0.0.0.0

現在のNext.js CLIにはdevstart--hostnameオプションがありますが、既存プロジェクトの起動スクリプトやNext.jsのバージョンによって指定方法が異なる場合があります。実際のpackage.jsonと公式CLIリファレンスを確認してください。

Raspberry PiのLAN内IPアドレスは、次の例で確認できます。

hostname -I

このプロジェクトには、LAN用としてホスト0.0.0.0、ポート3011で起動するスクリプトがあります。

npm run start:lan

同じLAN内の端末から次の形式で開きます。

http://RASPBERRY_PI_IP:3011/

接続できない場合は、次を確認します。

  • Next.jsが127.0.0.1だけでなくLAN側でも待ち受けているか
  • Raspberry Piと利用端末が同じLANまたは相互通信可能なネットワークにいるか
  • OSのファイアウォールが使用ポートを許可しているか
  • Wi-Fiのクライアント分離機能で端末間通信が止められていないか
  • 学校のネットワークポリシーでサーバー公開が許可されているか

6. SQLiteを導入する

SQLiteを選ぶ理由

小規模な資産管理Webアプリの最初のデータベースとして、SQLiteには次の利点があります。

  • 初期設定が比較的簡単
  • データを単一のデータベースファイルとして管理できる
  • 小規模アプリに導入しやすい
  • 別のDBサーバープロセスが不要
  • Raspberry Pi上で常駐するプロセスを増やさずに済む
  • 適切な方法を使えばバックアップを作りやすい

MySQLやPostgreSQLのような別DBサーバーを最初から用意しなくても、Node.jsアプリからSQLiteライブラリを通して利用できます。

ただし、「単一ファイルだから、動作中にそのファイルだけをコピーすれば必ず安全」という意味ではありません。運用中の一貫したバックアップには、使用ライブラリが提供するバックアップ機能、SQLiteのOnline Backup APIに対応した方法、またはアプリを安全に停止してからコピーする方法を検討します。

今回のアプリはWALモードを有効にするため、運用中にはDB本体に加えて-wal-shmが存在します。確認時はDB本体よりWALの方が大きくなっていました。稼働中にDB本体だけをコピーする運用にはせず、停止後のコピー、SQLiteのバックアップAPI、チェックポイントを含む手順のいずれかを決め、復元テストまで行います。

SQLiteが向いている処理

今回の資産管理で考えると、次のような処理はSQLiteを検討しやすい用途です。

資産一覧の表示
資産番号や名称の検索
1件ずつの登録と更新
時々行う棚卸結果の保存
単一のNext.jsサーバーからの利用

読み取りが中心で、書き込み処理が短く、1台のアプリサーバーからデータベースを使う構成は比較的シンプルです。

SQLiteが苦手になりやすい処理

SQLiteは同時に複数の読み取りを扱えますが、通常の同一データベースファイルへの書き込みは一度に1ライターとして順番に処理されます。

読み取り中心
  → SQLiteを検討しやすい

書き込みが短く、順番待ちできる
  → 実測して判断

多数の長い書き込みが同時発生
  → 待ち時間やロックエラーを検証

そのため、利用者が20人いるか50人いるかだけでは判断できません。全員が一覧を読むだけなのか、棚卸開始時に一斉にQRコードを読み取り、登録・更新を連続実行するのかで負荷が変わります。

今回使っているDatabaseSyncは、すべてのAPIを同期的に実行します。SQLの実行中はNode.js側の処理を占有するため、ロックエラーだけでなく、HTTPリクエストの待ち時間が伸びないかも確認が必要です。

さらに、現在の保存処理は変更した1件だけをUPDATEする方式ではありません。PUT /api/stateでアプリ全体の状態を受け取り、BEGIN IMMEDIATEから始まる1回のトランザクション内で6テーブルを削除し、全データを入れ直してからCOMMITしています。

ブラウザが全状態をPUT
        ↓
BEGIN IMMEDIATE
        ↓
users・locations・assets・履歴などを全削除
        ↓
受け取った全状態を再INSERT
        ↓
COMMIT

この方式では、資産件数や履歴件数が増えるほど1回の保存量も増えます。また、2人が少し古い状態を基に同時更新すると、後から保存した全状態が先の変更を上書きする可能性があります。性能だけでなく、更新の取りこぼしが起きないかも検証対象です。実運用前には、資産1件単位のSQL更新、楽観的ロック用のバージョン番号、競合時の再読込などを検討します。

データベースファイルの配置

SQLiteファイルは、Next.jsのpublicなど、ブラウザから静的ファイルとして取得できるディレクトリへ置きません。

置かない例
  project/public/database.sqlite

配置候補
  Web公開されず、サービス実行ユーザーだけが読めるデータ領域

実際の保存場所は、バックアップ、権限、ストレージ構成、デプロイ方法を考えて決めます。

7. 性能を測定する

性能測定では、Raspberry Pi本体の状態、HTTPアクセス、SQLite処理を分けて記録します。

測定条件をそろえる

比較するときは、次の条件を記録します。

  • 同じアプリのコミットまたはビルド
  • 同じNode.js・Next.js・SQLiteライブラリ
  • 同じデータ件数
  • 同じネットワーク接続
  • 同じ冷却とケース
  • 同じ電源
  • 本番モードで起動
  • 測定クライアントをRaspberry Piとは別のPCで動かす
  • 測定前のウォームアップ有無
  • microSDとSSDで比較する場合は、ストレージ以外の条件をそろえる

1回だけの結果では、バックグラウンド処理やキャッシュの影響を受けることがあります。複数回測定し、各回の条件と結果を残します。回数は実験計画として決め、実際に行った回数を記事へ記録します。

システム状態を確認する

メモリは次のようなコマンドで確認できます。

free -h

CPUとプロセスの状態は、次の候補があります。

top
ps -eo pid,comm,%cpu,%mem,rss --sort=-rss

ストレージ残量を確認します。

df -h

Raspberry Pi OSでvcgencmdが利用できる場合、SoC温度とスロットリング履歴を確認できます。

vcgencmd measure_temp
vcgencmd get_throttled

get_throttledの値はビットごとに意味があるため、表示された値を自己判断で読み替えず、Raspberry Pi公式ドキュメントと照合します。

ビルド時間の測定例です。

/usr/bin/time -v npm run build

使用OSに/usr/bin/timeが入っていない場合は、利用できる計測方法を確認します。

HTTP負荷試験

負荷試験ツールの候補には、ApacheBench、hey、wrkなどがあります。

ApacheBenchを使う例です。

ab -n 1000 -c 10 http://RASPBERRY_PI_IP:3011/

この例では、合計1000リクエストを、同時実行数10で送ります。これは測定条件の例であり、実測結果ではありません。

ツールのインストール方法、対応OS、出力項目は異なります。使用するツールの公式ドキュメントを確認してください。

負荷生成ツールは、可能ならRaspberry Piとは別の有線LAN接続PCで動かします。同じRaspberry Pi上で負荷を生成すると、負荷生成側のCPUやメモリも測定結果へ混ざります。

実アプリの読み取りと書き込みを分ける

トップページだけでは、資産管理アプリの実際の負荷は分かりません。次の処理を分けて測定します。

未認証のトップページ表示
認証済みのGET /api/state
ブラウザ上での資産検索
資産詳細表示
QRコード読取後のPUT /api/state
複数ユーザーによる同時更新
資産一覧のエクスポート

GET /api/statePUT /api/stateは認証Cookieが必要です。ApacheBenchでトップページだけを連打しても、DBを含む実際の操作は再現できません。認証済みのテストユーザーと複製したテストDBを用意し、Cookie、HTTPメソッド、JSON本文を送れるツールまたは専用の負荷試験スクリプトを使います。秘密情報や実ユーザーのCookieをログへ残さないよう注意します。

QRコードのカメラ読取はクライアント側の処理も含むため、API負荷試験とは別に実機のスマートフォンやタブレットで確認します。APIが速くても、証明書が信頼されておらずカメラ権限を取得できない場合は、現場では使用できません。

APIの登録処理へ大量アクセスする場合は、必ずテスト用データベースとテスト用データを使用します。本番の資産データへ負荷試験を行うと、大量の重複登録、更新、削除が発生する危険があります。

負荷試験前にバックアップを取り、テスト終了後にデータを破棄できる構成にします。

8. 測定結果

以下はRaspberry Pi 4上の測定結果を記入する欄です。プロジェクトの構成と開発データ件数は確認できましたが、Pi上の性能値はすべて未測定です。

システム測定

測定項目 結果
OS起動後のメモリ使用量 【実測値:OS起動後のメモリ使用量】
Next.js起動後のメモリ使用量 【実測値:アイドル時のメモリ使用量】
CPUアイドル使用率 【実測値:CPUアイドル使用率】
Next.jsビルド時間 【実測値:Next.jsのビルド時間】
サーバー起動時間 【実測値:Next.jsサーバー起動時間】
CPU温度 【実測値:CPU温度】

アクセス測定

条件 平均応答時間 エラー数
1ユーザー 【実測値:1人アクセス時の平均応答時間】 【実測値:1人アクセス時のエラー数】
5ユーザー 【実測値:5人同時アクセス時の平均応答時間】 【実測値:5人同時アクセス時のエラー数】
10ユーザー 【実測値:10人同時アクセス時の応答時間】 【実測値:10人同時アクセス時のエラー数】
20ユーザー 【実測値:20人同時アクセス時の平均応答時間】 【実測値:20人同時アクセス時のエラー数】
50ユーザー 【実測値:50人同時アクセス時の平均応答時間】 【実測値:50人同時アクセス時のエラー数】

平均応答時間だけでなく、可能であれば最小値、最大値、パーセンタイル、タイムアウト、HTTPエラーの内訳も記録します。ただし、測定していない指標は結果として掲載しません。

データベース測定

操作 結果 状態
一覧表示 【実測値:一覧表示の処理時間】 未検証
1件登録 【実測値:1件登録の処理時間】 未検証
100件連続登録 【実測値:100件連続登録の処理時間】 未検証
検索 【実測値:検索処理時間】 未検証
更新 【実測値:更新処理時間】 未検証
削除 【実測値:削除処理時間】 未検証
複数ユーザーによる同時書き込み 【実測値:同時書き込み時の処理時間とエラー】 未検証

実アプリでは、上の一般的なSQL測定に加えて次も記録します。

実アプリの測定 記録する内容
GET /api/state 平均・p95応答時間、レスポンスサイズ、HTTPエラー
1回のPUT /api/state 応答時間、送信JSONサイズ、トランザクション時間
5・10・20人の同時更新 成功数、失敗数、最大待ち時間、更新取りこぼし
データ増加後の保存 資産・履歴件数、応答時間、Node.jsのCPU・メモリ
WALの増加 試験前後のDB・WALサイズ、チェックポイント結果

100件連続登録は、1件ずつ別トランザクションにするのか、まとめて処理するのかで意味が変わります。現在の実装では1件だけを保存するAPIではなく、全状態をPUTして全表を入れ直します。そのため、一般的なSQLite単体ベンチマークと、実APIの測定結果を混同しないようにします。

microSDとSSDの比較結果

測定項目 microSD USB SSDまたは比較対象
npm install 【実測値】 【実測値】
npm run build 【実測値】 【実測値】
Next.js起動 【実測値】 【実測値】
SQLite一覧表示 【実測値】 【実測値】
SQLite連続登録 【実測値】 【実測値】
CPU温度 【実測値】 【実測値】
エラー数 【実測値】 【実測値】

比較を実施していない場合は、表へ「未検証」と記入します。

9. microSDとSSDの違い

Raspberry PiでNext.jsとSQLiteを使うとき、ストレージは性能と安定性の確認対象になります。

観点 microSD USB SSDなど
Next.jsのビルド 多数のファイル読み書きがあるため実測が必要 同じ条件で比較する
npm install 小さなファイルを多く扱うため実測が必要 同じ依存関係で比較する
ログ書き込み 継続的な書き込み量とローテーションを確認 継続的な書き込み量とローテーションを確認
SQLite トランザクションと同期書き込みの影響を測定 同じDBと処理で測定
耐久性 製品品質と書き込み量に依存 製品品質と書き込み量に依存
バックアップ イメージまたはファイル単位の手順を決める イメージまたはファイル単位の手順を決める

一般にストレージ性能はビルド、依存関係の展開、ログ、SQLiteの読み書きへ影響します。しかし、今回の環境でmicroSDとSSDが何倍違うかは測定していないため、数値は書きません。

比較する場合は、同じOS、Node.js、プロジェクト、データベース、データ件数、ネットワーク、冷却条件を使います。

変えるもの
  ストレージ

そろえるもの
  OS・アプリ・データ・ネットワーク・冷却・電源

また、速さだけでなく、突然の電源断、ログ量、データベース更新頻度、バックアップからの復元手順も評価します。

USB SSDやNVMeを使用する場合は、接続アダプター、電力供給、起動方式、Raspberry Pi 4との相性も確認します。実際の構成を環境表へ記録してください。

10. 数十人規模で使えるか

数十人という利用者数だけでは、SQLiteとRaspberry Pi 4で十分か判断できません。

たとえば、30人がログインしていても、ほとんどが一覧を読んでいるだけなら、データベースへの書き込みは少ない可能性があります。一方、棚卸開始直後に30人が同時にQRコードを読み取り、登録や更新を繰り返すなら、短時間に書き込みが集中します。

同じ30人でも負荷は異なる

一覧を時々読む30人
  → 読み取り中心

QR登録を一斉に行う30人
  → 書き込み集中

今回の資産管理アプリでは、少なくとも次の利用場面を分けて試します。

  • 通常時の資産検索
  • 管理者による1件登録
  • 複数教室からの同時閲覧
  • 棚卸開始時の同時更新
  • QRコード読み取り後の連続登録
  • CSV出力や集計などの重い処理

判断には、平均応答時間だけでなく、最大待ち時間、タイムアウト、SQLiteのロック関連エラー、CPU温度、スロットリング、メモリ不足、ストレージ待ちを確認します。

想定されるボトルネック

部位 影響しやすい処理 確認内容
CPU Next.jsビルド、動的レンダリング、集計、QR生成 CPU使用率、温度、スロットリング
メモリ Next.jsビルド、Node.jsプロセス、依存関係 使用量、スワップ、OOMの有無
ストレージ npm install、ビルド、ログ、SQLite更新 待ち時間、空き容量、エラー
ネットワーク 大きな画像、Wi-Fi、多数端末 有線・Wi-Fi、遅延、切断
電源・冷却 高負荷の継続 低電圧、温度、クロック制限

どれが実際のボトルネックになるかは、実測後に判断します。

11. SQLiteの限界

SQLiteからMySQLやPostgreSQLへの移行を検討する条件は、単純な利用人数だけではありません。

次のような状況が増えたら、クライアント・サーバー型データベースを検討します。

  • 同時書き込みが頻繁に発生する
  • 書き込みトランザクションが長い
  • 複数のアプリサーバーから同じDBへ接続したい
  • データ量が大きくなり、単一ファイル運用が負担になった
  • 高度なユーザー・ロール・権限管理が必要
  • バックアップ、ポイントインタイムリカバリ、レプリケーションを強化したい
  • 外部サービスとして利用者が増加した
  • 集計や複雑なクエリが通常運用へ影響する

特に、SQLiteのデータベースファイルをネットワーク共有へ置き、複数のアプリサーバーから直接読み書きする構成は、安易に採用しません。SQLite公式資料でも、多数のクライアントがネットワーク越しに同じデータベースを利用する用途では、クライアント・サーバー型DBが候補になります。

単一のNext.jsサーバー
  ↓
ローカルSQLite
  → 小規模構成の候補

複数のNext.jsサーバー
  ↓
共有DBが必要
  → MySQL・PostgreSQLを検討

移行を考えるときは、ORMやデータアクセス層が特定のSQLite固有機能へ強く依存していないか、マイグレーション手順、型の違い、バックアップと切り戻しも確認します。

12. 安定運用の設定

動作確認ができても、ターミナルから手動起動したままでは、再起動や異常終了のたびに操作が必要です。

自動起動

Linuxではsystemd、またはNode.js向けのプロセスマネージャーを使用する方法があります。

systemdユニットの考え方を示す例です。

[Unit]
Description=Asset Management Next.js App
After=network.target

[Service]
Type=simple
User=YOUR_USER
WorkingDirectory=/srv/asset-app
Environment=NODE_ENV=production
ExecStart=/usr/bin/npm run start -- --hostname 0.0.0.0
Restart=on-failure

[Install]
WantedBy=multi-user.target

ユーザー名、作業ディレクトリ、npmの絶対パスは環境に合わせます。

which npm

nvmなどでNode.jsを導入している場合、systemdから同じNode.jsやnpmが見えないことがあります。サービス実行ユーザーの環境と絶対パスを確認します。

ログ管理

ログを無制限に保存すると、ストレージを圧迫します。

  • systemd journalの使用量を確認する
  • アプリログのローテーションを設定する
  • 認証情報や個人情報をログへ出しすぎない
  • エラーを検知できる方法を用意する

SQLiteのバックアップ

バックアップは、コピーできたことではなく、復元できることまで確認します。

  • アプリを停止して一貫した状態でコピーする
  • 使用ライブラリが対応するオンラインバックアップ方法を使う
  • SQLiteのOnline Backup APIやVACUUM INTOに対応した方法を検討する
  • バックアップを別のストレージや別端末へ保管する
  • 定期的にテスト環境へ復元する

ジャーナルモードや使用ライブラリによっては、データベース本体以外の関連ファイルが一時的に存在します。動作中のファイルを確認せずに一部だけコピーする運用は避けます。

電源と冷却

書き込み中の突然の電源断は、OS、ストレージ、データベースへ影響する可能性があります。

  • 適切な電源アダプターを使用する
  • UPSの導入を検討する
  • 停電時に安全にシャットダウンする方法を決める
  • ヒートシンクやファンを用意する
  • 高負荷時の温度とスロットリングを測定する

定期確認

  • ストレージ残量
  • CPU温度
  • 低電圧やスロットリング履歴
  • バックアップの成否
  • Node.jsプロセスの再起動回数
  • OSとNode.jsのセキュリティ更新
  • SQLiteファイルの所有者と権限
  • LAN内IPアドレス

学校のネットワークへ接続する前に、校内ネットワーク管理者へ、サーバー設置、固定IP、使用ポート、認証、ログ、バックアップの方針を確認します。

13. セキュリティ

LAN内だけのサービスでも、認証なしでよいとは限りません。校内LANには多数の端末や利用者が接続する可能性があります。

  • 一般利用者と管理者の認証を実装する
  • 管理画面を誰でも開ける状態にしない
  • 資産登録、更新、削除の権限を分ける
  • Google OAuthなどを使う場合はクライアントシークレットを安全に管理する
  • .envをGitへ含めない
  • SQLiteファイルをWeb公開ディレクトリへ置かない
  • SQLiteファイルをサービス実行ユーザー以外から必要なく読めないようにする
  • Raspberry Pi OSの初期パスワードを使い続けない
  • SSHの公開範囲と認証方法を確認する
  • OS、Node.js、Next.js、SQLiteライブラリを更新する
  • 操作ログに必要以上の個人情報を残さない

.envには、OAuthの秘密情報、セッション用シークレット、外部APIキーなどが入る可能性があります。GitHubへpushする前に.gitignoreを確認します。

SQLiteファイルがWebからダウンロードできる場所にあると、資産情報やユーザー情報がまとめて漏れる危険があります。URLから取得できないデータ領域へ保存します。

個人情報や学校の資産情報を扱う場合は、個人の判断だけで運用を始めず、学校の管理者や情報セキュリティ担当者から許可を得ます。保存期間、閲覧権限、バックアップ、廃棄方法も決めます。

14. 結論

構成上はRaspberry Pi 4でもNext.jsとSQLiteを動作させられます。ただし、今回想定している資産管理システムに十分な性能があるかは、同時アクセスと書き込み処理の実測後に判断する必要があります。

ソースコードからは、Next.js 15.5.15、Node.js標準のnode:sqlite、WALモードで構成されており、Piへ持っていくための前提は整理できました。一方、保存のたびに全テーブルを再作成する実装は、データ増加時の処理時間と同時更新の整合性が重要な確認点です。少人数だから問題ないとは決めず、実データに近い件数でPUT /api/stateを測ります。

現時点では、次の測定値が未入力です。

【実測値:Next.jsのビルド時間】
【実測値:アイドル時のメモリ使用量】
【実測値:10人同時アクセス時の応答時間】
【実測値:SQLite同時書き込み時の結果】
【実測値:高負荷時のCPU温度】

このため、「数十人規模なら問題なく使える」「microSDでも十分」「SSDへ変えれば必ず解決する」といった最終評価はまだできません。

最終判断では、次を確認します。

通常利用時の応答時間
棚卸時の同時書き込み
エラーとタイムアウト
メモリ不足の有無
温度とスロットリング
ストレージの待ち時間と耐久性
バックアップからの復元

15. まとめ

Raspberry Pi 4、Next.js、SQLiteを組み合わせると、別のDBサーバーを用意しない比較的シンプルな構成を作れます。

校内端末
  ↓ LAN
Raspberry Pi 4
  ↓
Next.js本番サーバー
  ↓
SQLite

今回のような資産管理アプリでは、利用者数だけでなく、一覧表示とQR登録の割合、同時書き込みの集中、トランザクションの長さが重要です。

検証では、システム状態、アクセス負荷、SQLite処理を分けて測定します。microSDとSSDを比較する場合も、実測していない速度差は書かず、同じ条件で結果を記録します。

運用へ進む場合は、systemdなどによる自動起動、ログ管理、一貫したバックアップ、冷却、電源断対策、固定IP、更新、ファイル権限、校内ネットワーク管理者への確認が必要です。

実測結果がそろった後、この記事の表へ値を入力し、通常利用と棚卸時の両方で許容できるかを判断します。

参考にした公式情報