Raspberry Pi 5でInvenTree部品管理システムを運用する手順

プログラミング
  1. Docker版InvenTree本体 + Digi-Key 2Dコード登録補助アプリ + NAS自動バックアップ構成
  2. 0. この記事で作る構成
  3. 1. 前提条件
  4. 2. 公開用の置き換えルール
  5. 3. Docker / Docker Composeをインストールする
  6. 4. InvenTree本体用ディレクトリを作成する
  7. 5. InvenTree公式Docker Composeファイルを取得する
  8. 6. InvenTree本体用 .env を編集する
    1. 管理者アカウントの扱い
  9. 7. InvenTree本体の初期セットアップを実行する
  10. 8. InvenTree本体を起動する
  11. 9. InvenTree本体の基本運用コマンド
  12. 10. InvenTree本体構築後に確認すること
  13. 11. 最終構成
    1. 3.1 ハードウェア
    2. 3.2 ソフトウェア
    3. 3.3 URL構成
  14. 12. InvenTree側の運用設計
    1. 4.1 Stock Itemの単位
    2. 4.2 追加ラベルが必要なもの
    3. 4.3 追加ラベルを推奨するもの
    4. 4.4 数量根拠
    5. 4.5 写真を残した方がよいもの
  15. 13. InvenTree初期マスタ例
    1. 5.1 Location構成例
    2. 5.2 Category構成例
    3. 5.3 Parameter例
  16. 14. Quick Register用ディレクトリを作成する
  17. 15. Python仮想環境を作成する
    1. 7.1 zxing-cppの注意
  18. 16. Quick Register用 .env を作成する
  19. 17. InvenTree API Tokenを作成する
  20. 18. Digi-Key OAuth設定を行う
    1. 10.1 Digi-Key Developer Portal側
    2. 10.2 .env 側
    3. 10.3 よくある失敗
  21. 19. LAN内テスト用の自己署名証明書を作成する
  22. 20. Quick Registerを手動起動する
    1. 12.1 ERR_SSL_PROTOCOL_ERROR が出る場合
  23. 21. Quick Registerアプリの画面構成
    1. 13.1 Digi-Key OAuth login
    2. 13.2 カットテープ登録(写真)
    3. 13.3 2Dコード文字列から登録
  24. 22. 画像読取の問題と対策
    1. 14.1 撮影のコツ
  25. 23. 2Dコード文字列貼り付け対応
  26. 24. /scan-text と /register の実装上の注意
  27. 25. InvenTree API側の注意点
    1. 17.1 Manufacturer Part endpoint
    2. 17.2 Barcode Link
    3. 17.3 登録済みバーコードの再スキャン
    4. 17.4 数量更新
  28. 26. Quick Registerのファイル配置
  29. 27. Quick Registerをsystemdで常駐化する
    1. 19.1 手動起動中のuvicornを止める
    2. 19.2 serviceファイルを作成する
    3. 19.3 systemdへ反映する
    4. 19.4 ログ確認
    5. 19.5 再起動・停止・自動起動解除
    6. 19.6 systemd起動失敗時の確認
  30. 28. NASバックアップの考え方
    1. 20.1 NFSには通常のID/パスワード入力がない
    2. 20.2 PostgreSQLの実体ファイルを直接コピーしない
    3. 20.3 NFS相手に cp -a を使わない
  31. 29. NAS側でNFS共有を設定する
  32. 30. Raspberry Pi側でNFSクライアントを準備する
  33. 31. NFSの読み書きを確認する
  34. 32. /etc/fstab にNFS自動マウントを登録する
    1. 24.1 fstabオプションの意味
  35. 33. InvenTreeのバックアップを手動実行する
  36. 34. NASへの手動コピーを確認する
  37. 35. 自動バックアップスクリプトを作成する
  38. 36. systemd serviceを作成する
  39. 37. systemd timerを作成する
  40. 38. systemd timerを有効化する
  41. 39. システム全体の確認コマンド
  42. 40. バックアップ確認コマンド
  43. 41. 復元時に必要なファイル
  44. 42. 復元の大まかな流れ
  45. 43. 運用フロー
    1. 35.1 初回登録
    2. 35.2 登録済み品の数量変更
    3. 35.3 未登録品と登録済み品の分岐
  46. 44. 2Dコードリーダー導入判断
    1. 36.1 理由
    2. 36.2 選定条件
  47. 45. トラブルシュート
    1. 37.1 NFSはマウントできるが読めない
    2. 37.2 cp -a で ownership エラーが出る
    3. 37.3 timerが見つからない
    4. 37.4 backup serviceが失敗する
  48. 46. 公開してはいけないもの
  49. 47. 今後の改善候補
  50. 48. コマンド早見表
    1. Quick Register手動起動
    2. Quick Register systemd再起動
    3. Quick Registerログ確認
    4. 構文チェック
    5. 依存関係確認
    6. 8090番ポート確認
    7. uvicorn停止
    8. バックアップ手動実行
    9. バックアップtimer確認
    10. バックアップログ確認
    11. NASバックアップ一覧
  51. 49. 最終状態
  52. 参考情報

Docker版InvenTree本体 + Digi-Key 2Dコード登録補助アプリ + NAS自動バックアップ構成

対象環境: Raspberry Pi 5 / Raspberry Pi OS Lite 64-bit / Docker Compose版 InvenTree / FastAPI / systemd / NFS対応NAS

公開用メモ: 本記事では、実際のIPアドレス・ユーザー名・ホスト名・トークン・秘密鍵などはすべてプレースホルダに置き換えています。


0. この記事で作る構成

この記事では、Raspberry Pi 5上にDocker版InvenTreeを構築し、その後に以下の補助機能を追加します。

  1. Docker版 InvenTree本体
    • Raspberry Pi 5上でDocker Compose運用
    • PostgreSQL / Redis / InvenTree Server / Worker / Caddy Reverse Proxy 構成
    • 部品DB本体として使用
    • データ本体はRaspberry Pi側のNVMe SSDへ保存
  2. InvenTree Quick Register
    • Digi-Keyなどの袋ラベルに印字された2D DataMatrixを読み取る補助Webアプリ
    • FastAPI + uvicornで動作
    • Digi-Key Product2DBarcode APIでラベル内容を解釈
    • InvenTree APIで部品・仕入先・メーカー品番・在庫アイテム・バーコードリンクを作成
    • 登録済みStock Itemを再スキャンした場合は数量編集画面へ誘導
    • iPhone写真アップロード、または2Dコード文字列貼り付けに対応
  3. NAS自動バックアップ
    • InvenTree公式バックアップコマンドでDB・メディアをバックアップ
    • NFS経由でNASへ保存
    • systemd timerで毎日定時に自動実行
    • 31日より古いバックアップを自動削除
    • 復元に必要な docker-compose.yml / .env / config.yaml / Docker状態情報も保存

この手順では、まずInvenTree本体を起動できる状態にしてから、Quick RegisterとNASバックアップを追加します。順番を逆にすると、Quick RegisterのAPI接続確認やバックアップコマンド確認ができません。


1. 前提条件

この記事は、以下が済んでいる状態から始めます。

Raspberry Pi OS Lite 64-bit がインストール済み
Raspberry PiへSSH接続できる
Raspberry Piに固定IPまたはDHCP予約を設定済み
Raspberry Piからインターネットへ接続できる
sudo可能なLinuxユーザーがある
NAS側でNFS共有を作成できる

まだDockerやInvenTree本体が入っていなくても、この手順内で構築します。


2. 公開用の置き換えルール

実環境の値をそのままブログに出すと、ネットワーク構成やユーザー名が見えてしまいます。この記事では、以下のように置き換えます。

種類公開用表記
Raspberry PiのIP<RASPI_IP>192.168.x.xxx
NASのIP<NAS_IP>192.168.x.xxx
Raspberry Piのホスト名<RASPI_HOSTNAME>任意
Linuxユーザー名<LINUX_USER>任意
NASのNFS Export<NAS_NFS_EXPORT><NAS_NFS_EXPORT> など
InvenTree DBユーザー名<INVENTREE_DB_USER>任意
InvenTree DBパスワード<INVENTREE_DB_PASSWORD_RANDOM>絶対に公開しない
InvenTree管理者ユーザー名<INVENTREE_ADMIN_USER>任意
InvenTree管理者パスワード<INVENTREE_ADMIN_PASSWORD>絶対に公開しない
InvenTree API Token<INVENTREE_TOKEN>絶対に公開しない
Digi-Key Client ID<DIGIKEY_CLIENT_ID>公開しない方が安全
Digi-Key Client Secret<DIGIKEY_CLIENT_SECRET>絶対に公開しない
Quick Registerアプリ秘密文字列<APP_SECRET_RANDOM>ランダム文字列

以降のコマンドでは、実行前にこれらを自分の環境の値へ置き換えてください。

自分用メモを残したい場合は、公開用MDとは別の非公開メモに以下を記録しておくと復旧時に役立ちます。

Raspberry Pi IP:
Raspberry Pi hostname:
Linux user:
InvenTree URL:
NAS IP:
NAS NFS export:
バックアップ保存先:

ただし、DBパスワード・InvenTree管理者パスワード・API Token・Digi-Key Client Secretは、ブログ、GitHub、Notionの公開ページには絶対に貼らないでください。


3. Docker / Docker Composeをインストールする

Raspberry Pi OSはDebian系なので、Docker公式APTリポジトリからDocker EngineとDocker Compose pluginを入れます。

最初にOSを更新します。

sudo apt update
sudo apt upgrade -y
sudo reboot

再起動後、再度SSH接続します。

古いDocker系パッケージが入っている場合は削除します。何も入っていない場合はエラーが出ても問題ありません。

for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do
  sudo apt remove -y "$pkg" 2>/dev/null || true
done

Docker公式GPGキーとAPTリポジトリを追加します。

sudo apt update
sudo apt install -y ca-certificates curl

sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL <https://download.docker.com/linux/debian/gpg> -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

CODENAME=$(. /etc/os-release && echo "$VERSION_CODENAME")
echo "Detected Debian codename:$CODENAME"

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] <https://download.docker.com/linux/debian\>
$CODENAME stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

sudo apt update

Raspberry Pi OSのバージョンによっては、$VERSION_CODENAME がDocker公式リポジトリ側のDebianコードネームと合わないことがあります。Raspberry Pi OS Bookwormの場合は、通常 bookworm になります。ここが bookworm 以外でリポジトリ取得に失敗する場合は、自分のOSに対応するDebianコードネームへ読み替えてください。

Docker EngineとDocker Compose pluginをインストールします。

sudo apt install -y \
  docker-ce \
  docker-ce-cli \
  containerd.io \
  docker-buildx-plugin \
  docker-compose-plugin

Dockerを有効化して起動します。

sudo systemctl enable --now docker
sudo systemctl status docker --no-pager

通常ユーザーで docker コマンドを使えるようにします。

sudo usermod -aG docker "$USER"

この設定は再ログイン後に有効になります。いったんSSHを切断して入り直すのが確実です。すぐ反映したい場合は以下でも可です。

newgrp docker

動作確認します。

docker run hello-world
docker compose version

ここまでで、dockerdocker compose が使える状態になります。


4. InvenTree本体用ディレクトリを作成する

InvenTree本体は /opt/inventree に置きます。

sudo mkdir -p /opt/inventree
sudo chown -R "$USER:$USER" /opt/inventree
cd /opt/inventree

InvenTree公式のDocker Compose構成では、以下の3ファイルを同じディレクトリへ置きます。

docker-compose.yml
.env
Caddyfile

本番運用ではInvenTreeのソースコード一式をcloneする必要はなく、公式の contrib/container/ にある3ファイルを使えば起動できます。


5. InvenTree公式Docker Composeファイルを取得する

以下のコマンドで、stableブランチのDocker Compose用ファイルを取得します。

cd /opt/inventree

curl -L -o docker-compose.yml \
  <https://raw.githubusercontent.com/inventree/inventree/stable/contrib/container/docker-compose.yml>

curl -L -o .env \
  <https://raw.githubusercontent.com/inventree/inventree/stable/contrib/container/.env>

curl -L -o Caddyfile \
  <https://raw.githubusercontent.com/inventree/inventree/stable/contrib/container/Caddyfile>

取得できたか確認します。

ls -la /opt/inventree

期待する状態です。

/opt/inventree
├─ docker-compose.yml
├─ .env
└─ Caddyfile

.env は秘密情報を含むため、権限を絞っておきます。

chmod 600 .env

6. InvenTree本体用 .env を編集する

.env を編集します。

cd /opt/inventree
nano .env

最低限、以下を自分の環境に合わせます。

COMPOSE_PROJECT_NAME=inventree
INVENTREE_TAG=stable

# InvenTreeへアクセスするURL
INVENTREE_SITE_URL="http://<RASPI_IP>"

# InvenTreeの永続データ保存先
INVENTREE_EXT_VOLUME=./inventree-data

# Caddy reverse proxyの公開ポート
INVENTREE_HTTP_PORT=80
INVENTREE_HTTPS_PORT=443

# ProductionではDEBUGにしない
INVENTREE_LOG_LEVEL=WARNING

# Pluginを使う場合はTrue
INVENTREE_PLUGINS_ENABLED=True

# Docker起動時の自動更新設定
INVENTREE_AUTO_UPDATE=True

# DB設定
INVENTREE_DB_ENGINE=postgresql
INVENTREE_DB_NAME=inventree
INVENTREE_DB_HOST=inventree-db
INVENTREE_DB_PORT=5432
INVENTREE_DB_USER=<INVENTREE_DB_USER>
INVENTREE_DB_PASSWORD=<INVENTREE_DB_PASSWORD_RANDOM>

# Redis cache
INVENTREE_CACHE_ENABLED=True
INVENTREE_CACHE_HOST=inventree-cache
INVENTREE_CACHE_PORT=6379

# gunicorn
INVENTREE_GUNICORN_TIMEOUT=90

DBパスワードはランダム生成して使います。

openssl rand -base64 24

INVENTREE_SITE_URL は、LAN内で使うなら以下のようにします。

INVENTREE_SITE_URL="http://<RASPI_IP>"

ポート80を他の用途で使っている場合は、たとえば以下のようにホスト側ポートを変更します。

INVENTREE_SITE_URL="http://<RASPI_IP>:8080"
INVENTREE_HTTP_PORT=8080

この場合、後続のQuick Register側 INVENTREE_BASE_URL も同じURLへ合わせます。

管理者アカウントの扱い

.env には管理者アカウントを自動作成するための変数も用意されていますが、ブログ公開用の手順では手動作成を推奨します。

理由は、.env に管理者ユーザー名・パスワードを残したままバックアップやメモへ流れる事故を避けるためです。

手動作成する場合、以下のような行はコメントアウトのままで構いません。

#INVENTREE_ADMIN_USER=
#INVENTREE_ADMIN_PASSWORD=
#INVENTREE_ADMIN_EMAIL=

7. InvenTree本体の初期セットアップを実行する

まずDockerイメージを取得します。

cd /opt/inventree
docker compose pull

DB初期化・マイグレーション・静的ファイル更新を実行します。

docker compose run --rm inventree-server invoke update

管理者アカウントを作成します。

docker compose run --rm inventree-server invoke superuser

画面の指示に従って、管理者ユーザー名・メールアドレス・パスワードを設定します。

ここで作成した管理者パスワードは公開しないでください。自分用のパスワード管理ツールなどに保存します。


8. InvenTree本体を起動する

コンテナをバックグラウンドで起動します。

cd /opt/inventree
docker compose up -d

状態を確認します。

docker compose ps

代表的なサービスは以下です。

inventree-db       PostgreSQL database
inventree-cache    Redis cache
inventree-server   InvenTree web server
inventree-worker   background worker
inventree-proxy    Caddy reverse proxy

ログを確認します。

docker compose logs --tail=100

特定サービスだけ見る場合です。

docker compose logs --tail=100 inventree-server
docker compose logs --tail=100 inventree-proxy
docker compose logs --tail=100 inventree-db

Webブラウザで以下へアクセスします。

http://<RASPI_IP>

ポートを変えた場合は以下のようになります。

http://<RASPI_IP>:8080

ログイン画面が出て、作成した管理者アカウントでログインできればInvenTree本体の構築は完了です。


9. InvenTree本体の基本運用コマンド

以降の docker compose コマンドは、必ず docker-compose.yml があるディレクトリで実行します。

cd /opt/inventree

起動します。

docker compose up -d

停止します。

docker compose down

再起動します。

docker compose restart

状態を確認します。

docker compose ps

ログを追いかけます。

docker compose logs -f

InvenTreeを更新する場合は、基本的に以下の順で行います。

cd /opt/inventree

docker compose down
docker compose pull
docker compose run --rm inventree-server invoke update
docker compose up -d

更新前には、後述のNASバックアップが正常に取れていることを確認してから実行します。


10. InvenTree本体構築後に確認すること

Quick RegisterやNASバックアップへ進む前に、以下を確認します。

cd /opt/inventree

docker compose ps
curl -I <http://localhost>
curl -I http://<RASPI_IP>

Web UI側では、以下を確認します。

管理者アカウントでログインできる
部品カテゴリを作成できる
ロケーションを作成できる
API Token作成画面を開ける

ここまで通ってから、Quick Registerの構築へ進みます。


11. 最終構成

3.1 ハードウェア

Raspberry Pi 5
公式 Raspberry Pi M.2 HAT+
NVMe SSD
有線LAN
NFS対応NAS
ラベルプリンタ
必要に応じて2Dコードリーダー

2Dコードリーダーは必須ではありません。iPhoneなどで撮影した画像アップロードでも動きますが、大量登録をするなら2D Area Imager方式のリーダーがあるとかなり楽です。

3.2 ソフトウェア

Raspberry Pi OS Lite 64-bit
Docker / Docker Compose
InvenTree
PostgreSQL
Redis
Python仮想環境
FastAPI
uvicorn
Pillow
zxing-cpp
requests
python-dotenv
nfs-common
systemd service / timer

3.3 URL構成

InvenTree本体:
  http://<RASPI_IP>

Quick Register:
  https://<RASPI_IP>:8090

Digi-Key OAuth Callback:
  https://<RASPI_IP>:8090/digikey/callback

Digi-Key OAuthのCallback URLは、Digi-Key Developer Portal側と .env 側で完全一致している必要があります。http / https、IP、ポート、パス、末尾スラッシュの有無が1文字でも違うと失敗します。


12. InvenTree側の運用設計

4.1 Stock Itemの単位

リール: 1リール = 1 Stock Item
カットテープ: 原則1袋または1カットテープ = 1 Stock Item
チューブ: 1チューブ = 1 Stock Item
トレー: 1トレー = 1 Stock Item
UNKNOWN品: 1まとまり = 1 Stock Item

Digi-KeyやMouserの既存袋ラベルが残っているものは、基本的に既存ラベルを活用します。すべてのカットテープへ手動IDラベルを貼る必要はありません。

4.2 追加ラベルが必要なもの

ラベルなし
UNKNOWN品
複数種類が混在している袋
既存バーコードで識別できないもの

4.3 追加ラベルを推奨するもの

高価部品
重複バーコードの可能性があるもの
小分けしたもの
既存ラベルが劣化しているもの
頻繁に使うもの

4.4 数量根拠

数量根拠は、たとえば以下のように管理します。

COUNTED
SUPPLIER_LABEL
ESTIMATED
REEL_COUNTER
UNKNOWN

Digi-Key袋ラベルから登録したものは、基本的に SUPPLIER_LABEL とします。

4.5 写真を残した方がよいもの

UNKNOWN品
高価部品
ラベル不鮮明品
チップマウンタ用に向きが重要なリール
誤認しやすい部品

13. InvenTree初期マスタ例

5.1 Location構成例

SITE
├─ ORICON
│  ├─ ORC-01
│  ├─ ORC-02
│  ├─ ORC-03
│  ├─ ORC-04
│  ├─ ORC-05
│  └─ ORC-06
├─ REEL
│  ├─ REEL-R01
│  ├─ REEL-R02
│  ├─ REEL-R03
│  └─ REEL-R04
├─ WORK
│  ├─ INCOMING
│  ├─ COUNTING
│  ├─ NEED_LABEL
│  ├─ NEED_IDENTIFY
│  └─ READY
├─ TOOL
├─ PCB
├─ CABLE
└─ UNKNOWN

5.2 Category構成例

Electronic Components
├─ Passive
│  ├─ Resistors
│  ├─ Capacitors
│  ├─ Inductors
│  ├─ Ferrites
│  └─ Crystals and Oscillators
├─ Semiconductors
│  ├─ Diodes
│  ├─ Transistors
│  ├─ MOSFETs
│  ├─ Regulators
│  ├─ Op Amps
│  ├─ Logic
│  ├─ MCUs
│  ├─ Sensors
│  └─ RF
├─ Connectors
├─ Switches
├─ Modules
├─ PCBs
└─ Cables

Mechanical
Tools and Fixtures
Unknown

5.3 Parameter例

manufacturer
mpn
supplier
supplier_part_number
value
package
datasheet
count_basis
tape_width
reel_diameter
tape_pitch
orientation
feed_direction
tolerance
voltage_rating
power
dielectric
msl
rohs
lifecycle
marking
pin_count
altium_footprint
altium_component_id

14. Quick Register用ディレクトリを作成する

InvenTree本体のDocker Composeディレクトリは以下とします。

/opt/inventree

Quick Registerは、InvenTree本体とは分けて以下に配置します。

/opt/inventree-tools/quick-register

ディレクトリを作成します。

sudo mkdir -p /opt/inventree-tools
sudo chown -R $USER:$USER /opt/inventree-tools

cd /opt/inventree-tools
mkdir -p quick-register
cd quick-register

15. Python仮想環境を作成する

cd /opt/inventree-tools/quick-register

python3 -m venv .venv
source .venv/bin/activate

pip install --upgrade pip setuptools wheel

依存関係をインストールします。

pip install \
  fastapi==0.115.6 \
  "uvicorn[standard]==0.34.0" \
  python-multipart==0.0.20 \
  requests==2.32.3 \
  Pillow==11.0.0 \
  zxing-cpp==3.0.0 \
  python-dotenv==1.0.1

import確認をします。

python - <<'PY'
from PIL import Image, ImageOps, ImageFilter
import zxingcpp
from fastapi import FastAPI, File, Form, UploadFile
from fastapi.responses import HTMLResponse, RedirectResponse

print("imports OK")
PY

imports OK が出れば依存関係はOKです。

7.1 zxing-cppの注意

zxing-cpp==2.2.0 は、Python 3.13 / aarch64環境でwheelがなく、ソースビルドに落ちて失敗する場合があります。Raspberry Pi 5環境では zxing-cpp==3.0.0 を使うと通りやすいです。


16. Quick Register用 .env を作成する

cd /opt/inventree-tools/quick-register
nano .env

例です。実値は公開しないでください。

INVENTREE_URL=http://<RASPI_IP>
INVENTREE_TOKEN=<INVENTREE_TOKEN>

INVENTREE_DEFAULT_CATEGORY_ID=1
INVENTREE_DEFAULT_LOCATION_ID=1

DIGIKEY_CLIENT_ID=<DIGIKEY_CLIENT_ID>
DIGIKEY_CLIENT_SECRET=<DIGIKEY_CLIENT_SECRET>
DIGIKEY_REDIRECT_URI=https://<RASPI_IP>:8090/digikey/callback

APP_HOST=0.0.0.0
APP_PORT=8090
APP_SECRET=<APP_SECRET_RANDOM>

注意点です。

INVENTREE_TOKEN は InvenTree の API Token
DIGIKEY_CLIENT_SECRET は絶対にGitHubやブログに貼らない
DIGIKEY_REDIRECT_URI はDigi-Key Developer Portal側のCallback URLと完全一致させる
.env 全体を公開しない

17. InvenTree API Tokenを作成する

InvenTreeのWeb UIでAPI Tokenを作成します。

代表的な場所は以下です。

User Settings
→ API Tokens

または以下です。

Admin Center
→ Users
→ API Token

作成したTokenを .env に入れます。

INVENTREE_TOKEN=<INVENTREE_TOKEN>

18. Digi-Key OAuth設定を行う

10.1 Digi-Key Developer Portal側

Digi-Key Developer Portalでアプリを作成し、Callback URLに以下を登録します。

https://<RASPI_IP>:8090/digikey/callback

10.2 .env 側

.env 側も完全一致させます。

DIGIKEY_REDIRECT_URI=https://<RASPI_IP>:8090/digikey/callback

10.3 よくある失敗

たとえば以下のようなエラーが出ます。

{"ErrorCode":"invalid_request","Error":"Invalid redirection uri http://<RASPI_IP>:8090/digikey/callback"}

原因は、Digi-Key側または .env 側、もしくは起動中プロセスがまだ http://... を使っていることです。修正後はuvicornまたはsystemd serviceを再起動します。


19. LAN内テスト用の自己署名証明書を作成する

Digi-Key OAuth CallbackをHTTPSにするため、LAN内テスト用の自己署名証明書を作成します。

cd /opt/inventree-tools/quick-register
mkdir -p certs

openssl req -x509 -newkey rsa:2048 \
  -keyout certs/key.pem \
  -out certs/cert.pem \
  -days 365 \
  -nodes \
  -subj "/CN=<RASPI_IP>" \
  -addext "subjectAltName = IP:<RASPI_IP>"

確認します。

ls -l certs/key.pem certs/cert.pem

certs/key.pem は秘密鍵です。公開しないでください。


20. Quick Registerを手動起動する

アプリのソースコードを /opt/inventree-tools/quick-register/app/ 以下へ配置したうえで、手動起動します。

cd /opt/inventree-tools/quick-register
source .venv/bin/activate

uvicorn app.main:app \
  --host 0.0.0.0 \
  --port 8090 \
  --ssl-keyfile certs/key.pem \
  --ssl-certfile certs/cert.pem

ブラウザから以下にアクセスします。

https://<RASPI_IP>:8090

自己署名証明書なのでブラウザ警告が出ます。LAN内テスト用途であれば、詳細表示から続行します。

12.1 ERR_SSL_PROTOCOL_ERROR が出る場合

https://... にアクセスしているのにuvicornをSSLなしで起動していると発生します。

正しくは、起動時に以下を付けます。

--ssl-keyfile certs/key.pem
--ssl-certfile certs/cert.pem

21. Quick Registerアプリの画面構成

トップページには、主に以下の3機能を置きます。

13.1 Digi-Key OAuth login

Digi-Key APIを使うための認証です。最初に一度実行します。

13.2 カットテープ登録(写真)

iPhoneなどでDigi-Key袋ラベルの2D DataMatrixを撮影し、アップロードします。

写真アップロード
↓
Pillowで画像処理
↓
zxing-cppでDataMatrix読取
↓
Digi-Key Product2DBarcode API
↓
InvenTree登録画面

13.3 2Dコード文字列から登録

2Dコードリーダーや別のスキャナアプリで読んだ文字列を貼り付けます。

2Dコードリーダー/別アプリで読取
↓
文字列をtextareaへ貼り付け
↓
制御文字を補正
↓
Digi-Key Product2DBarcode API
↓
InvenTree登録画面

大量処理では、写真アップロードより文字列貼り付けの方が安定します。


22. 画像読取の問題と対策

Digi-KeyのDataMatrixは小さいため、iPhone写真からの読取が安定しないことがあります。

主な原因です。

画像が高解像度すぎて処理が重い
DataMatrixが小さい
ピンボケ
反射
斜め撮影
ラベル全体を写しすぎてDataMatrixが小さくなる
iPhoneのHEIC/Live Photo等の影響

app/barcode.py 側では、以下のような処理を入れると読み取りやすくなります。

EXIF回転補正
グレースケール化
コントラスト補正
中央クロップ
2倍拡大
シャープ化
90/180/270度回転
軽量処理 → crop fallback → heavy fallback

ただし、最初から重い処理を総当たりすると20秒程度かかることがあります。軽量処理で先に読みに行き、読めない時だけ重いfallbackへ進む方が実用的です。

14.1 撮影のコツ

2Dコードを画面中央に置く
2Dコードを画面の1/4〜1/3くらいの大きさにする
ラベル全体は写らなくてよい
真上から撮る
反射を避ける
ピントが合うまで待つ

23. 2Dコード文字列貼り付け対応

iPhoneの別スキャンアプリなどではDataMatrix自体は読めても、Digi-Keyラベル内の区切り制御文字がスペースに置換されることがあります。

例です。

[)> 06 P<ORDER_CODE> 1P<SUPPLIER_PART> 30<ORDER_CODE> ...

本来必要な構造は以下です。

[)> RS 06 GS P<ORDER_CODE> GS 1P<SUPPLIER_PART> GS ...

つまり、RS/GSの制御文字が失われています。

対策として、normalize_pasted_barcode() のような関数で以下を吸収します。

\x1d
\x1e
\u001d
\u001e
[GS]
[RS]
<GS>
<RS>
␝
␞
スペース区切りに潰れたDigi-Key形式

スペース区切りになったDigi-Key形式は、以下のように復元できます。

if len(tokens) >= 3 and tokens[0] == "[)>" and tokens[1] in ("06", "05"):
    fmt = tokens[1]
    fields = tokens[2:]
    return "[)>" + "\x1e" + fmt + "\x1d" + "\x1d".join(fields) + "\x1e" + "\x04"

24. /scan-text と /register の実装上の注意

以下のようなエラーが出ることがあります。

{"detail":[{"type":"missing","loc":["query","text"],"msg":"Field required","input":null}]}

原因は、FastAPIがフォームではなくURLクエリの text を要求していることです。

また、デコレータを誤って通常関数に付けてしまうと、意図しないエンドポイントになります。

悪い例です。

@app.post("/register", response_class=HTMLResponse)
def normalize_pasted_barcode(text: str) -> str:
    ...

修正方針です。

normalize_pasted_barcode() は通常関数にする
/scan-text は barcode_text: str = Form(...) を受け取る
/register は location_id / category_id / quantity を受け取る
写真読取と文字列読取で共通の handle_raw_barcode() を使う
登録済みバーコードなら数量編集画面へ
未登録バーコードならDigi-Key APIで初回登録画面へ

25. InvenTree API側の注意点

17.1 Manufacturer Part endpoint

Manufacturer Partを作成するエンドポイントを間違えると404になります。

誤りです。

/api/company/manufacturer-part/

正しくはこちらです。

/api/company/part/manufacturer/

実装例です。

def get_or_create_manufacturer_part(self, *, part_id: int, manufacturer_id: int, mpn: str) -> dict:
    if mpn:
        res = self.get(
            "/api/company/part/manufacturer/",
            part=part_id,
            manufacturer=manufacturer_id,
            MPN=mpn,
        )
        item = self.first_result(res)
        if item:
            return item

    return self.post(
        "/api/company/part/manufacturer/",
        {
            "part": part_id,
            "manufacturer": manufacturer_id,
            "MPN": mpn or "",
        },
    )

17.2 Barcode Link

初回登録後、Digi-Keyの生バーコード文字列をInvenTree Stock Itemへリンクします。

def link_barcode_to_stock_item(self, *, barcode: str, stock_item_id: int) -> dict:
    return self.post("/api/barcode/link/", {
        "barcode": barcode,
        "stockitem": stock_item_id,
    })

17.3 登録済みバーコードの再スキャン

同じバーコードを再度読んだ場合、InvenTreeの /api/barcode/ へ投げます。

def scan_barcode(self, barcode: str) -> dict:
    return self.post("/api/barcode/", {
        "barcode": barcode,
    })

Stock Itemが見つかれば数量編集画面を出します。

17.4 数量更新

MVPではStock Itemの quantity を直接PATCHします。

def update_stock_quantity_direct(self, *, stock_item_id: int, quantity: int, note: str = "") -> dict:
    return self.patch(f"/api/stock/{stock_item_id}/", {
        "quantity": quantity,
    })

この方法は、在庫履歴付きのAdd / Remove / Count操作ではありません。MVPとしては使えますが、正式運用ではInvenTreeの在庫操作APIへ寄せる余地があります。


26. Quick Registerのファイル配置

構成例です。

/opt/inventree-tools/quick-register
├─ .env
├─ .venv/
├─ certs/
│  ├─ cert.pem
│  └─ key.pem
├─ app/
│  ├─ __init__.py
│  ├─ main.py
│  ├─ barcode.py
│  ├─ config.py
│  ├─ digikey.py
│  └─ inventree_client.py
└─ data/
   ├─ uploads/
   └─ last_scan.json

構文チェックをします。

cd /opt/inventree-tools/quick-register
source .venv/bin/activate

python -m py_compile app/main.py app/inventree_client.py app/barcode.py

何も出なければOKです。


27. Quick Registerをsystemdで常駐化する

手動起動で動作確認できたら、systemdで常駐化します。

19.1 手動起動中のuvicornを止める

pkill -f "uvicorn app.main:app"

確認します。

ps aux | grep uvicorn

19.2 serviceファイルを作成する

sudo nano /etc/systemd/system/inventree-quick-register.service

内容です。

[Unit]
Description=InvenTree Quick Register
After=network-online.target docker.service
Wants=network-online.target

[Service]
Type=simple
User=<LINUX_USER>
Group=<LINUX_USER>
WorkingDirectory=/opt/inventree-tools/quick-register
Environment=PATH=/opt/inventree-tools/quick-register/.venv/bin
ExecStart=/opt/inventree-tools/quick-register/.venv/bin/uvicorn app.main:app --host 0.0.0.0 --port 8090 --ssl-keyfile certs/key.pem --ssl-certfile certs/cert.pem
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

ユーザー名は以下で確認します。

whoami

19.3 systemdへ反映する

sudo systemctl daemon-reload
sudo systemctl enable inventree-quick-register
sudo systemctl start inventree-quick-register

状態確認です。

sudo systemctl status inventree-quick-register

active (running) ならOKです。

19.4 ログ確認

直近ログです。

journalctl -u inventree-quick-register -n 80 --no-pager

リアルタイムログです。

journalctl -u inventree-quick-register -f

19.5 再起動・停止・自動起動解除

sudo systemctl restart inventree-quick-register
sudo systemctl stop inventree-quick-register
sudo systemctl disable inventree-quick-register

19.6 systemd起動失敗時の確認

sudo systemctl status inventree-quick-register
journalctl -u inventree-quick-register -n 100 --no-pager

よくある原因です。

certs/key.pem が存在しない
certs/cert.pem が存在しない
User が違う
Group が違う
WorkingDirectory が違う
.venv/bin/uvicorn が存在しない
.env が読めていない
8090番ポートを手動起動のuvicornがまだ使っている

確認コマンドです。

cd /opt/inventree-tools/quick-register

ls -l .venv/bin/uvicorn
ls -l certs/key.pem certs/cert.pem
ls -l .env
ss -ltnp | grep 8090

28. NASバックアップの考え方

ここからは、InvenTree本体のバックアップをNASへ保存する設定です。

重要な考え方は3つあります。

20.1 NFSには通常のID/パスワード入力がない

SMB共有と違い、NFSでは一般的にユーザー名とパスワードでログインしません。

NFSでは主に以下でアクセス制御します。

接続元IPアドレス
UID/GID
NAS側のNFS権限
Squash設定
共有フォルダ側の権限

Raspberry PiのIPだけをNAS側で許可します。

20.2 PostgreSQLの実体ファイルを直接コピーしない

InvenTreeはDBを使うため、DBの実体ファイルを動作中に直接コピーすると整合性が崩れる可能性があります。

そのため、InvenTree公式のバックアップコマンドを使います。

docker compose run --rm inventree-server invoke backup

これにより、DBバックアップとメディアファイルのバックアップが生成されます。

20.3 NFS相手に cp -a を使わない

cp -a は所有者情報や権限まで保持しようとします。

NFS経由のNAS共有では、所有者情報の保持に失敗して以下のようなエラーが出ることがあります。

cp: failed to preserve ownership: Operation not permitted

今回の用途では、NAS上で元のLinux所有者を完全に保持する必要はありません。そのため、コピー時は以下を使います。

cp -r --no-preserve=ownership,mode コピー元 コピー先

29. NAS側でNFS共有を設定する

Synology DSMの場合は、まずNFSを有効化します。

コントロールパネル
  → ファイルサービス
  → NFS を有効化

次に、バックアップ用共有フォルダを作成します。

共有フォルダ名: 任意
NFSパス: <NAS_NFS_EXPORT>

共有フォルダのNFS権限で、Raspberry Piだけを許可します。

ホスト名またはIP: <RASPI_IP>
権限: 読み取り/書き込み
セキュリティ: sys
Squash: 環境に応じて設定

動作確認時だけ、必要に応じてSquash設定を緩めます。ただし、許可IPは必ずRaspberry Piだけに絞ります。


30. Raspberry Pi側でNFSクライアントを準備する

sudo apt update
sudo apt install -y nfs-common

マウント先を作成します。

sudo mkdir -p /mnt/nas_backup

手動マウントします。

sudo mount -t nfs <NAS_IP>:<NAS_NFS_EXPORT> /mnt/nas_backup

マウント確認です。

mount | grep nas_backup

確認例です。

<NAS_IP>:<NAS_NFS_EXPORT> on /mnt/nas_backup type nfs4 (rw,relatime,vers=4.0,...)

31. NFSの読み書きを確認する

読み取り確認です。

ls -la /mnt/nas_backup

書き込み確認です。

touch /mnt/nas_backup/test_from_raspi.txt
ls -la /mnt/nas_backup

通常ユーザーで失敗する場合は、sudoでも確認します。

sudo touch /mnt/nas_backup/test_from_raspi_sudo.txt
sudo ls -la /mnt/nas_backup

この時点で、読み取り権限・書き込み権限の両方を確認しておきます。


32. /etc/fstab にNFS自動マウントを登録する

起動時に自動マウントするため、/etc/fstab に登録します。

sudo nano /etc/fstab

以下を追加します。

<NAS_IP>:<NAS_NFS_EXPORT> /mnt/nas_backup nfs defaults,nofail,x-systemd.automount,_netdev 0 0

設定を反映します。

sudo systemctl daemon-reload
sudo mount -a

確認します。

mount | grep nas_backup
df -h | grep nas_backup

24.1 fstabオプションの意味

defaults:
  標準的なマウントオプション

nofail:
  NASが不在でもRaspberry Piの起動を止めない

x-systemd.automount:
  systemdのautomountを使い、必要時にマウントする

_netdev:
  ネットワークデバイスが必要なマウントであることを示す

33. InvenTreeのバックアップを手動実行する

InvenTreeのDocker Composeディレクトリへ移動します。

cd /opt/inventree

Docker Composeサービス名を確認します。

docker compose ps

InvenTree公式バックアップを実行します。

docker compose run --rm inventree-server invoke backup

バックアップファイルは、一般的に以下のような場所に生成されます。

/opt/inventree/inventree-data/backup

生成されるファイル例です。

InvenTree-db-YYYY-MM-DD-HHMMSS.psql.bin.gz
InvenTree-db-YYYY-MM-DD-HHMMSS.psql.bin.gz.metadata
InvenTree-media-YYYY-MM-DD-HHMMSS.tar.gz

34. NASへの手動コピーを確認する

日時付き保存先を作成します。

BACKUP_DATE=$(date +'%Y-%m-%d_%H-%M-%S')
NAS_DEST="/mnt/nas_backup/inventree/${BACKUP_DATE}"
sudo mkdir -p "$NAS_DEST"

NFS上では cp -a で所有者情報の保持に失敗する場合があります。そのため、以下を使います。

sudo cp -r --no-preserve=ownership,mode /opt/inventree/inventree-data/backup "$NAS_DEST"/

コピー後、NAS上に保存されているか確認します。

ls -lh "$NAS_DEST"
ls -lh "$NAS_DEST/backup"

35. 自動バックアップスクリプトを作成する

sudo nano /usr/local/sbin/inventree-backup-to-nas.sh

内容です。

#!/usr/bin/env bash
set -euo pipefail

# ===== 設定 =====
INVENTREE_DIR="/opt/inventree"
SERVER_SERVICE="inventree-server"

NAS_MOUNT="/mnt/nas_backup"
NAS_ROOT="${NAS_MOUNT}/inventree"
RETENTION_DAYS=31

DATE="$(date +'%Y-%m-%d_%H-%M-%S')"
NAS_DEST="${NAS_ROOT}/${DATE}"

# ===== 開始 =====
echo "== InvenTree backup start:${DATE} =="

# NASマウント確認
if !mountpoint -q "$NAS_MOUNT"; then
  echo "ERROR:${NAS_MOUNT} is not mounted" >&2
  exit 1
fi

# InvenTreeディレクトリへ移動
cd "$INVENTREE_DIR"

# Docker Compose確認
echo "== Checking docker compose services =="
docker compose ps

# InvenTree公式バックアップ実行
echo "== Running InvenTree native backup =="
docker compose run --rm "$SERVER_SERVICE" invoke backup

# バックアップディレクトリ確認
echo "== Searching backup directory =="
BACKUP_DIR="$(find "$INVENTREE_DIR" -type d -name backup | head -n 1)"

if [ -z "$BACKUP_DIR" ]; then
  echo "ERROR: backup directory not found" >&2
  exit 1
fi

echo "Backup directory:$BACKUP_DIR"

# NAS側保存先作成
echo "== Creating NAS destination =="
mkdir -p "$NAS_DEST/backup"

# バックアップファイルをNASへコピー
echo "== Copying backup files to NAS =="
cp -r --no-preserve=ownership,mode "$BACKUP_DIR"/. "$NAS_DEST/backup"/

# 復元用の設定ファイルも保存
echo "== Copying compose/config files =="
cp --no-preserve=ownership,mode docker-compose.yml "$NAS_DEST"/ 2>/dev/null || true
cp --no-preserve=ownership,mode .env "$NAS_DEST"/ 2>/dev/null || true
cp --no-preserve=ownership,mode config.yaml "$NAS_DEST"/ 2>/dev/null || true

# Docker状態を記録
echo "== Writing metadata =="
docker compose ps > "$NAS_DEST/docker-compose-ps.txt"
docker compose images > "$NAS_DEST/docker-compose-images.txt"

# チェックサム作成
echo "== Writing checksum =="
find "$NAS_DEST" -type f -exec sha256sum {} \; > "$NAS_DEST/SHA256SUMS.txt"

# 古いバックアップを削除
echo "== Cleaning old backups older than${RETENTION_DAYS} days =="
find "$NAS_ROOT" -mindepth 1 -maxdepth 1 -type d -mtime +"$RETENTION_DAYS" -print -exec rm -rf {} \;

echo "== Backup completed =="
echo "$NAS_DEST"

実行権限を付けます。

sudo chmod +x /usr/local/sbin/inventree-backup-to-nas.sh

手動実行で確認します。

sudo /usr/local/sbin/inventree-backup-to-nas.sh

成功時は以下のように表示されます。

== Backup completed ==
/mnt/nas_backup/inventree/YYYY-MM-DD_HH-MM-SS

36. systemd serviceを作成する

バックアップ処理をsystemdから実行できるようにします。

sudo nano /etc/systemd/system/inventree-backup.service

内容です。

[Unit]
Description=Backup InvenTree to NAS
Wants=network-online.target
After=network-online.target docker.service
RequiresMountsFor=/mnt/nas_backup

[Service]
Type=oneshot
ExecStart=/usr/local/sbin/inventree-backup-to-nas.sh

設定の意味です。

Type=oneshot:
  常駐サービスではなく、一度実行して終了するタイプ

After=network-online.target docker.service:
  ネットワークとDockerの後に実行する

RequiresMountsFor=/mnt/nas_backup:
  /mnt/nas_backup が必要なマウントであることをsystemdに伝える

37. systemd timerを作成する

毎日定時にバックアップを実行します。

sudo nano /etc/systemd/system/inventree-backup.timer

内容です。

[Unit]
Description=Run InvenTree backup to NAS daily

[Timer]
OnCalendar=*-*-* 03:30:00
Persistent=true
RandomizedDelaySec=300

[Install]
WantedBy=timers.target

設定の意味です。

OnCalendar=*-*-* 03:30:00:
  毎日03:30に実行する

Persistent=true:
  実行予定時刻にRaspberry Piが停止していた場合、次回起動後に未実行分を実行する

RandomizedDelaySec=300:
  実行時刻を最大300秒ランダムに遅らせる

完全に03:30ぴったりにしたい場合は、以下の行を削除します。

RandomizedDelaySec=300

38. systemd timerを有効化する

sudo systemctl daemon-reload
sudo systemctl enable --now inventree-backup.timer

タイマー確認です。

systemctl list-timers --all | grep inventree

serviceの確認です。

systemctl status inventree-backup.service

timerの確認です。

systemctl status inventree-backup.timer

systemd経由で手動実行テストします。

sudo systemctl start inventree-backup.service

ログ確認です。

journalctl -u inventree-backup.service -n 100 --no-pager

39. システム全体の確認コマンド

Raspberry Pi全体のsystemd状態を確認します。

systemctl is-system-running

失敗しているunitを確認します。

systemctl --failed

関連サービスの有効化状態を確認します。

systemctl list-unit-files --type=service --state=enabled | grep -Ei 'docker|container|inventree|nfs|network|ssh|backup' || true

動作中サービスを確認します。

systemctl list-units --type=service --state=running | grep -Ei 'docker|container|inventree|nfs|network|ssh|backup' || true

timer一覧を確認します。

systemctl list-timers --all | grep -Ei 'inventree|backup|nfs|nas' || true

マウント状態を確認します。

mount | grep -Ei 'nas|nfs|backup' || true
df -h | grep nas_backup || true

fstabの関連行を確認します。

grep -Ei 'nfs|nas|backup' /etc/fstab || true

Docker状態を確認します。

systemctl is-enabled docker
systemctl is-active docker

InvenTreeコンテナ状態を確認します。

cd /opt/inventree
docker compose ps

40. バックアップ確認コマンド

NAS上のバックアップ一覧を確認します。

ls -lh /mnt/nas_backup/inventree

最新のバックアップ内容を確認します。

ls -lh /mnt/nas_backup/inventree/$(ls -1 /mnt/nas_backup/inventree | tail -n 1)

バックアップファイルを探します。

find /mnt/nas_backup/inventree -type f | tail -n 50

古いバックアップ削除対象を確認します。

find /mnt/nas_backup/inventree -mindepth 1 -maxdepth 1 -type d -mtime +31 -print

41. 復元時に必要なファイル

バックアップ先には、少なくとも以下を保存します。

backup/
  InvenTree-db-YYYY-MM-DD-HHMMSS.psql.bin.gz
  InvenTree-db-YYYY-MM-DD-HHMMSS.psql.bin.gz.metadata
  InvenTree-media-YYYY-MM-DD-HHMMSS.tar.gz

docker-compose.yml
.env
config.yaml
docker-compose-ps.txt
docker-compose-images.txt
SHA256SUMS.txt

.env には秘密情報が含まれる可能性があるため、ブログ・GitHub・Notionなどに中身を貼らないでください。


42. 復元の大まかな流れ

復元時は以下の考え方で行います。

1. 新しいRaspberry PiまたはLinux機にDockerを入れる
2. /opt/inventree を用意する
3. docker-compose.yml と .env をバックアップから戻す
4. InvenTreeのバージョンをバックアップ取得時点に合わせる
5. InvenTreeコンテナを起動する
6. InvenTreeのrestoreコマンドでDBとmediaを復元する
7. docker compose ps とWeb画面で正常性確認する

復元前には、バックアップ取得時のDockerイメージ情報を確認します。

cat docker-compose-images.txt

チェックサム確認です。

sha256sum -c SHA256SUMS.txt

43. 運用フロー

35.1 初回登録

1. Quick Registerを開く
2. Digi-Key OAuth loginを済ませる
3. 2Dコードを読む
   - 写真アップロード
   - または文字列貼り付け
4. Digi-Key APIの読取結果を確認
5. Location / Category / Quantityを確認
6. InvenTreeに登録
7. 登録完了

35.2 登録済み品の数量変更

1. 同じ2Dコードを読む
2. InvenTreeのBarcode LinkからStock Itemを検出
3. 数量編集画面が出る
4. New Quantityを入力
5. 更新

35.3 未登録品と登録済み品の分岐

バーコード読取
↓
InvenTree /api/barcode/ に問い合わせ
↓
Stock Itemが見つかる
  → 数量編集画面
Stock Itemが見つからない
  → Digi-Key APIで初回登録

44. 2Dコードリーダー導入判断

大量登録では2Dコードリーダー導入を推奨します。

36.1 理由

iPhone写真アップロード方式は以下に左右されます。

ピント
反射
角度
画像サイズ
DataMatrixの小ささ
画像処理時間

2Dコードリーダーは専用レンズ・照明・デコーダを持つため、大量のDigi-Key袋ラベル処理では安定します。

36.2 選定条件

必須条件です。

2D Area Imager方式
DataMatrix ECC200対応
GS1 DataMatrix対応
QR対応
USB HIDキーボード入力対応
読み取り後Enter送信を設定可能

あると便利です。

Bluetooth HID対応
制御文字を可視化または保持できる設定

避けるものです。

1Dレーザースキャナ
QR専用リーダー
DataMatrix非対応
制御文字を勝手に削除するもの

45. トラブルシュート

37.1 NFSはマウントできるが読めない

症状です。

ls: cannot open directory '/mnt/nas_backup': Permission denied

見るべき場所です。

NAS管理画面
  → 共有フォルダ
  → バックアップ用共有フォルダ
  → NFS権限

確認項目です。

ホスト名またはIP: <RASPI_IP>
権限: 読み取り/書き込み
セキュリティ: sys
Squash設定
共有フォルダ自体の権限

37.2 cp -a で ownership エラーが出る

症状です。

cp: failed to preserve ownership: Operation not permitted

原因です。

NFS経由のNAS共有で、Linux側の所有者情報をそのまま保存できない。

対策です。

cp -r --no-preserve=ownership,mode コピー元 コピー先

37.3 timerが見つからない

確認します。

systemctl list-timers --all | grep inventree

再読み込みします。

sudo systemctl daemon-reload

有効化します。

sudo systemctl enable --now inventree-backup.timer

37.4 backup serviceが失敗する

ログを見ます。

journalctl -u inventree-backup.service -n 100 --no-pager

よくある原因です。

/mnt/nas_backup がマウントされていない
Dockerが起動していない
SERVER_SERVICE名が実際のdocker composeサービス名と違う
/opt/inventree のパスが違う
NFS側の書き込み権限がない

サービス名を確認します。

cd /opt/inventree
docker compose ps

inventree-server ではなく server などの場合は、スクリプト内の以下を変更します。

SERVER_SERVICE="inventree-server"

46. 公開してはいけないもの

以下はブログ・GitHub・Notionなどに貼らないでください。

.env 全体
INVENTREE_TOKEN
DIGIKEY_CLIENT_SECRET
Digi-Key OAuth refresh token
digikey_token.json
certs/key.pem
実運用のIPアドレス
実運用のホスト名
実ユーザー名
NASの実共有パス

Quick Registerは在庫DBへの登録権限を持つため、基本はLAN内限定で使います。外部から使う場合は、ポート開放ではなくVPN経由にします。


47. 今後の改善候補

在庫履歴付き数量操作
  - Count
  - Add
  - Remove
  - Transfer

Mouserラベル対応
  - ラベル形式を確認して別パーサを追加

ラベル印刷連携
  - UNKNOWN品ラベル
  - InvenTree内部QRラベル
  - 小分け品ラベル
  - 高価品ラベル

Altium連携
  - MPN
  - footprint
  - component ID
  - supplier PN
  - lifecycle
  - datasheet

48. コマンド早見表

Quick Register手動起動

cd /opt/inventree-tools/quick-register
source .venv/bin/activate

uvicorn app.main:app \
  --host 0.0.0.0 \
  --port 8090 \
  --ssl-keyfile certs/key.pem \
  --ssl-certfile certs/cert.pem

Quick Register systemd再起動

sudo systemctl restart inventree-quick-register
sudo systemctl status inventree-quick-register

Quick Registerログ確認

journalctl -u inventree-quick-register -n 100 --no-pager
journalctl -u inventree-quick-register -f

構文チェック

cd /opt/inventree-tools/quick-register
source .venv/bin/activate

python -m py_compile app/main.py app/inventree_client.py app/barcode.py

依存関係確認

python - <<'PY'
from PIL import Image, ImageOps, ImageFilter
import zxingcpp
from fastapi import FastAPI, File, Form, UploadFile
from fastapi.responses import HTMLResponse, RedirectResponse

print("imports OK")
PY

8090番ポート確認

ss -ltnp | grep 8090

uvicorn停止

pkill -f "uvicorn app.main:app"

バックアップ手動実行

sudo /usr/local/sbin/inventree-backup-to-nas.sh

バックアップtimer確認

systemctl status inventree-backup.timer
systemctl list-timers --all | grep inventree

バックアップログ確認

journalctl -u inventree-backup.service -n 100 --no-pager

NASバックアップ一覧

ls -lh /mnt/nas_backup/inventree

49. 最終状態

この構成で、以下が成立します。

Quick Registerをsystemdで常駐化
Digi-Key袋ラベルからInvenTreeへ登録補助
登録済みバーコードの再スキャンで数量編集
InvenTree公式バックアップを取得
NASへNFS経由で保存
毎日03:30に自動実行
31日より古いバックアップを自動削除
復元に必要なcompose/env/metadata/checksumも保存
systemdで実行状況とログを確認可能

参考情報

  • InvenTree公式ドキュメント: Docker Production Server
  • InvenTree公式ドキュメント: Configuration
  • InvenTree公式ドキュメント: Invoke Tool
  • Docker公式ドキュメント: Install Docker Engine on Debian
  • Docker公式ドキュメント: Docker Compose install overview

公式ドキュメントは更新されるため、実際に構築するタイミングで最新の内容も確認してください。特にInvenTreeのDocker Composeファイル、.env、Caddyfileは、公式のstableブランチ側が変わる可能性があります。

コメント

タイトルとURLをコピーしました