【保存版】Synology NASにClaude Codeを常駐させたら、NASが日本語を話し始めた

Synology

「あのファイル、NASのどこに置いたっけ……?」

写真もコードも書類も、とりあえず全部NASに突っ込んでいる僕は、このセリフを月に何十回つぶやいているか分かりません。File Stationの検索窓に打ち込んで、待って、違って、また待って……。

そんなある日、ふと思いました。

NASの中にAI置けばよくない?

思いついたが吉日。SSHでログインして、Container Managerを開いて、気づけば深夜。結果から言うと——できました。しかも24時間常駐、iPhoneからどこでも操作可能、日本語で話しかけられる状態です。

この記事では、Synology NASにClaude Codeを常駐させる手順を、Dockerもtmuxもよくわからないというかたにも分かるように、一つずつ解説していきます。もちろん、僕が盛大にハマったポイント込みで。

なぜ「NASの中」でAIを動かすのか

「Macで動かせばいいじゃん」と思ったかた、正しいです。でも、NASで動かす理由が4つあります。

1. NASは24時間つけっぱなし

これが最大の理由です。MacBookは閉じたら止まりますが、NASは止まりません。つまり、AIに「あのフォルダ全部リネームしといて」と頼んで蓋を閉じても、NASの中のAIは黙々と作業を続けてくれます。処理を投げっぱなしにできる、というのはサーバーの特権です。

2. Remote Controlでどこからでも繋がる

Claude CodeにはRemote Controlという機能があって、NAS上で動いているセッションに、iPhoneのClaudeアプリのCodeタブから直接接続できます。電車の中から、自宅NASの中身を日本語で検索できるわけです。これはもう、ちょっとした魔法です。

3. WebサイトをAIに直接編集してもらえる

これは地味に効きます。僕自身このブログをSynology NASでホスティングしていますが、NASでWebサイトを立てているかたって、けっこう多いんじゃないでしょうか? そこにAIを住まわせてしまえば、いちいちエディタを開いてページを直さなくても、「あのページのここ直しといて」と指示するだけで編集してもらえます。ファイルはNASの中にあるので、AIの手がそのまま届くわけです。

ちなみに僕のkaylog.ioはWordPressなので、記事本文はデータベースの中。ここはファイル直編集では触れませんが、テーマやCSS、機能まわりのカスタマイズは指示だけでどんどん直せます。エディタを開く前に用事が終わる、あの感覚は一度味わうと戻れません。

4. なんでもNASに入れたいという浪漫

これまでこのブログでは、ブログ本体もPOSレジも野鳥のシューティングゲームも、全部NASの上で動かしてきました。「動くものは全部NASに入れたい」という病気にかかっている僕としては、AIだけ外に置いておくなんて選択肢はありません。

Kay’s Voice: 正直に言うと、4番目の理由が7割です。でも、動かしてみたら残りの3つの恩恵が想像以上でした。浪漫から入って実用に着地するの、自作勢あるあるだと思っています。

今回の舞台:3台あるうちの3番機

僕は仕事柄・趣味柄あわせて3台のSynology NASを運用しています。この記事では便宜上、NAS01・NAS02・NAS03と呼びます。

  • NAS03(DS1825+):今回の主役。CPUはRyzen V1500Bのx86_64機。開発用フォルダやPOSシステムが動いている本番機でもある
  • NAS02(DS1019+ / メモリ8GB):このブログ(kaylog.io)のWordPressが乗っているサーバー機

まずNAS03に構築し、動作が固まったあとNAS02にも同じ構成を移植しました。同じ手順で2台目が20分だったので、レシピとしての再現性はそれなりにあると思います。

🔍 Kay’s Check: 前提はx86_64(Intel / AMD)のモデルです。Ryzen搭載機やCeleron搭載機ならほぼ対象内。ARM系のエントリーモデルだと同じようにはいきませんのでご注意を。あとメモリは、余裕を見て4GB以上あると安心です。

そもそもDockerって何?なぜDockerなのか

ここでいきなり「Container Managerで」と言われても、多くの人は身構えます。なので先に一言だけ。

Dockerとは、NASの中に「小さな別のパソコン」を丸ごと1台作る仕組みです。

引っ越し用のコンテナをイメージしてください。中に必要な道具(今回はNode.jsとかgitとか)を全部詰め込んで、封をして、NASの上にポンと置く。中で何をしても、NAS本体(DSM)の環境は一切汚れません。要らなくなったらコンテナごと捨てられます。Synologyでは「Container Manager」というパッケージ名で提供されています。

で、なぜDocker方式なのか。Claude Codeは公式のインストーラーをNASに直接叩き込むことも一応できるのですが、AIはDockerに入れることにしました。理由は4つです。

  • DSMのユーザーランドは極端に最小構成で、gitすら入っていない。Claude Codeが前提としている道具が足りない
  • DSMのアップデートで環境が変わっても、コンテナの中は無傷
  • Debianベースの素直な環境なので、足りないものはapt一発で足せる
  • マウントするフォルダを選ぶことで「AIに見せる範囲」を制御できる(これが地味に最重要)

4つめが効きます。NASの中身を全部見せるのは、いくらなんでも豪快すぎます。Dockerなら「このフォルダだけ見せる」「ここは読むだけ」がcompose.yamlの数行で決まります。

構築手順

準備するもの

  1. コントロールパネル → 端末とSNMP → SSHサービスを有効化
  2. パッケージセンターから Container Manager をインストール
  3. フォルダを2つ作成
    • /volume1/docker/claude(ビルド用の作業フォルダ)
    • /volume1/docker/claude/home認証情報の永続化用。ここが後で効いてきます)

Dockerfileを書く

Dockerfileは「コンテナの設計図」です。何をインストールした状態のコンテナを作るか、を書いたただのテキストファイルです。

dockerfile

FROM node:22-bookworm

RUN apt-get update && apt-get install -y --no-install-recommends \
    git ripgrep jq less procps tmux \
    poppler-utils \
    exiftool \
    python3 python3-pip \
    && rm -rf /var/lib/apt/lists/*

RUN pip3 install --break-system-packages openpyxl pandas

RUN npm install -g @anthropic-ai/claude-code

ENV TZ=Asia/Tokyo
ENV LANG=C.UTF-8
ENV LC_ALL=C.UTF-8
WORKDIR /workspace
CMD ["sleep", "infinity"]

何を入れているのか、意味が分かると愛着が湧くので簡単に。

  • ripgrep:超高速な全文検索ツール。Claude Codeの検索能力の中核。後述する「検索が一瞬」の正体はこいつです
  • git:差分管理・コミット操作に必須
  • tmux:常駐化の要。これも後で詳しく
  • poppler-utils / exiftool / openpyxl:PDFの中身検索、写真のEXIF読み取り、Excel読み取り用。NASに眠っている資料を掘るなら入れておくと世界が広がります
  • ENV LANG / LC_ALLこれがないと日本語表示が壊滅します。詳しくはハマりポイントで

compose.yamlを書く

compose.yamlは「そのコンテナをどう動かすか」の設定ファイルです。

yaml

services:
  claude:
    build: .
    image: claude-code-nas:latest
    container_name: claude-code
    tty: true
    stdin_open: true
    volumes:
      - /volume1/docker/claude/home:/root/.claude   # 認証の永続化
      - /volume1/homes/Kay:/workspace/kay:ro         # ホーム全体(読み取り専用)
      - /volume1/homes/Kay/Devs:/workspace/kay/Devs  # 開発フォルダのみ書き込み可
    cpuset: "0-3"
    mem_limit: 4g
    restart: unless-stopped

ここが今回の設計の肝です。

  • ネストマウント:ホーム全体を:ro(読み取り専用)で見せつつ、開発用のDevsだけ書き込み可を上から重ねています。「全部読めるけど、書けるのはここだけ」という、いちばん安心できる形です
  • cpusetでCPUコアを4つに限定、mem_limitでメモリ4GBに制限。本番サービスが同居しているNASなので、資源は物理的に分けておきます
  • restart: unless-stoppedで、NAS再起動時にコンテナが自動で立ち上がります

🔍 Kay’s Check: home:/root/.claude の行は聖域です。ここに認証情報が保存されるので、この行を崩すと再ログインからやり直しになります。compose.yamlをいじるときは、この1行だけは絶対に触らないでください。(1回やらかしました)

ビルドして起動して、認証

bash

cd /volume1/docker/claude
sudo docker compose up -d --build
sudo docker exec -it claude-code claude

初回起動でテーマ選択などの画面が出るので、進めていくとOAuth認証用のURLが表示されます。そのURLをPCやスマホのブラウザで開いてログインし、表示されたコードをターミナルに貼り付けるだけ。NASにブラウザは要りません。

/root/.claudeを永続化してあるので、認証は最初の一度きりです。

Kay’s Voice: ここで一瞬固まりました。「URLが出ない……」と。実は最初のテーマ選択画面で止まっていただけでした。画面をちゃんと読め、という当たり前の教訓。

エイリアスとCLAUDE.md

毎回長いコマンドを打つのは苦行なので、~/.profileにエイリアスを追加します。

bash

alias cc='sudo docker exec -it -e LANG=C.UTF-8 -e LC_ALL=C.UTF-8 claude-code tmux -u attach -t cc'

これで、SSHからccと2文字打つだけでAIの前に座れます。

あわせて、作業フォルダにCLAUDE.mdを置きます。これはClaude Codeが自動で読む「その場所のルールブック」です。僕はフォルダ構成の説明と、こう書きました。

本番稼働中のシステムは、変更前に必ず確認を取ること。

たった一行ですが、これがガードレールとして本当に効きます。

tmuxって何?——「閉じても消えない部屋」を作る

さて、ここまでで動くようにはなりました。でも問題があります。SSHを切断すると、セッションが死にます。

そこで登場するのがtmuxです。

tmuxとは、ターミナルの中に「閉じても消えない部屋」を作るソフトです。

普通、SSHで繋いだターミナルは、接続を切った瞬間に中でやっていた作業も終了します。tmuxは、その作業を別室に隔離してくれます。ドアを閉めて帰っても、部屋の中では作業が続いている。翌朝もう一度ドアを開けると、昨日の続きがそのまま残っている。そういうものです。

なので運用のルールはこうなります。

  • 部屋から出るとき:Ctrl+B を押して離してから D(デタッチ。セッションは生き続ける)
  • /exitは使わない(部屋そのものを取り壊す操作。Remote Controlの接続も切れます)

🔍 Kay’s Check: Ctrl+B → D は同時押しではなく2段階です。Ctrlを押しながらBを押して、いったん両方離して、それからD。Macの場合の「control」キーです(commandではありません)。ここ、僕は3回くらい間違えました。

iPhoneから操作する:Remote Control

ここからが本番です。tmuxの中でClaude Codeをこう起動します。

bash

claude --remote-control

これだけで、iPhoneのClaudeアプリのCodeタブから、NAS上のセッションに直接接続できます

重要なのは、スマホはあくまで「窓」だということ。実際の処理もファイルアクセスも、全部NASの中で完結しています。スマホの電池もギガも減りません。

🔍 Kay’s Check: Remote Controlの利用にはPro / Max等のサブスクリプションでのOAuthログインが必要です。APIキーやsetup-tokenでのトークン認証では使えません。

起動時の自動復帰と、月1回の自動アップデート

ここまで作ったら、あとは無人化です。DSMのタスクスケジューラに2つ登録します。

ブートアップタスク(NAS起動時に自動復帰)

「作成 → トリガーされたタスク → ユーザー指定のスクリプト」、ユーザーはroot、イベントは「ブートアップ」。

bash

#!/bin/bash
sleep 90
DOCKER=/usr/local/bin/docker
$DOCKER exec claude-code tmux kill-session -t cc 2>/dev/null
$DOCKER exec claude-code tmux new -d -s cc -c /workspace/kay/Devs
sleep 5
$DOCKER exec claude-code tmux send-keys -t cc 'claude --remote-control' Enter
  • sleep 90:コンテナの起動完了待ち。焦らない
  • kill-session → newの順にすることで、手動で「実行」ボタンを押して再テストしても壊れません(冪等)
  • claudeをtmuxの起動コマンドに直接渡す方式もありますが、エラーが出た瞬間にセッションごと消えて原因が分からなくなるので、bashの部屋を先に作ってからsend-keysで打ち込む方式が正解でした

月次アップデートタスク(毎月1回・深夜)

bash

#!/bin/bash
cd /volume1/docker/claude
DOCKER=/usr/local/bin/docker
$DOCKER compose build --no-cache && $DOCKER compose up -d || exit 1
sleep 15
$DOCKER exec claude-code tmux new -d -s cc -c /workspace/kay/Devs
sleep 5
$DOCKER exec claude-code tmux send-keys -t cc 'claude --remote-control' Enter
$DOCKER image prune -f
  • --no-cacheが肝。これがないとnpmのインストール層がキャッシュされて、いつまでも古いバージョンのままです
  • && ... || exit 1:ビルドに失敗したら現行環境を維持します。壊れた状態で朝を迎えないための保険
  • image prune -f:古いイメージの自動掃除

これで、メンテナンスすら自動になりました。

ハマりポイント集(この記事の本体)

きれいに書いてきましたが、実際はここからが長かったです。同じ道を通る人のために、全部置いていきます。

1. compose.yamlが「invalid leading UTF-8 octet」

エディタがUTF-16やBOM付きで保存していたのが原因でした。SSHからヒアドキュメント(tee << 'EOF')で書けば、確実にBOMなしUTF-8になります。

ちなみにDSMにはfileコマンドがないので、判定はこれで。

bash

head -c 4 compose.yaml | od -An -tx1

ff feならUTF-16、ef bb bfならBOM付きUTF-8です。

2. 「NanoCPUs can not be set」

DSMのカーネルはDockerのCFSクォータ(cpus:指定)に対応していません。cpuset: "0-3"のコア割り当て方式に変更して解決。むしろ物理的にコアを分けるので、本番サービスとの隔離という意味では確実です。

3. 「Bind mount failed: does not exist」

マウント元のフォルダが実在しないとコンテナが起動しません。僕の場合、開発フォルダが/volume1/devではなく/volume1/homes/Kay/Devsにあっただけでした。パスの大文字小文字は別物Devsdevs)なので要注意。

4. コンテナに直接入れたものは消える

docker exec ... apt-get installで入れたものはそのコンテナ限りです。compose.yamlを変更してコンテナが再作成されると、きれいに消えます。tmuxが消えたときは本気で焦りました。

恒久化したいものは必ずDockerfileに書いて、イメージに焼き込む。 これが鉄則です。

5. タスクスケジューラの罠3連発

  • PATHが最小限なので、dockerはフルパスで書く(/usr/local/bin/docker。DSMのバージョンによっては/var/packages/ContainerManager/target/usr/bin/docker
  • 出力保存がデフォルトOFF。「設定」から出力結果の保存を有効化しないと、失敗しても何も分かりません
  • そして最大の罠。タスクを別のNASに登録していた

……はい。「動かない、なぜだ」と1時間ほど格闘した挙げ句、ブラウザのタブがNAS02のDSMだった、というオチです。複数台運用しているかたは、まずタイトルバーのホスト名を確認してください。

6. マウントパスを変えたら信頼確認が出る

Claude Codeは作業フォルダをパスで記憶しているので、マウントパスを変えると初回の信頼確認ダイアログで止まります。一度attachして承認してあげてください。

7. 日本語が化ける(入力した文字も読めない)

node公式イメージは素の状態だとUTF-8ロケールが未設定で、tmuxが全角文字の幅を計算できません。結果、打った文字が消えたり重なったりします。

解決は、DockerfileにENV LANG=C.UTF-8ENV LC_ALL=C.UTF-8を焼き込むこと。attach側もtmux -u-e LANG=...を付けます。

🔍 Kay’s Check: この症状、英語だけ使っているうちは絶対に表面化しません。日本語を打った瞬間に発症します。海外の解説記事に載っていないのはそのせいです。

おまけ:画面の状態を確認する裏技

トラブルシュート中、「今どういう画面になってる?」を確認するのに、スクリーンショットを撮るより確実な方法があります。

bash

tmux capture-pane -t cc -p

これでtmux内の画面がそのままテキストで吐き出されます。以後、僕のトラブルシュートはこれが標準になりました。

実際に使ってみた:検索が一瞬すぎて笑った

さて、本題です。何ができるのか。

日本語でファイルを探せる。しかも一瞬。

「◯◯ファイルを探して」

これが体感1〜2秒で返ってきます。File Stationの検索窓とは次元が違う速度です。正体は前述のripgrepで、数万ファイルを舐めても一瞬です。「NASの検索ってこんなに速かったの?」と本気で驚きました。

ファイルの中身を見て教えてもらうことも

「〇〇フォルダにある、▢▢PDFファイルの内容を読んで、△△について教えて!」 「あの写真には何が写ってる?」こんな感じ質問をすると、ちゃんと答えが返ってきます!

一括リネーム・整理も自然言語で。

「このフォルダのファイル名、先頭の日付を YYYY-MM-DD 形式に揃えて」

これだけで済みます。今までAutomatorやシェルスクリプトを書いていた作業が、話しかけるだけになりました。しかもNAS内で完結するので、巨大ファイルをネットワーク越しに転送する必要がありません。ここがローカルのMacで動かすAIとの決定的な差です。

設定ファイルの調査・修正。

「Web Stationの設定ファイルを読んで、いま何のサイトが動いてるか一覧にして」——こういう、自分で書いたのに忘れている設定の棚卸しが本当に楽です。

セキュリティと運用の注意点

便利ですが、無防備に使うものではありません。僕が守っているルールを共有します。

  • 見せる範囲はマウントで制御する。見せたくない共有フォルダは、そもそもマウントしない。参照だけでいいものは:ro
  • CLAUDE.mdに本番システムの注意書きを入れる。「変更前に必ず確認を取ること」の一文が保険になります
  • コンテナ内はroot動作なので、AIが新規作成したファイルはroot所有になります。Web公開フォルダなどでは必要に応じてchown
  • 本番サービスと同居させるならcpusetmem_limitで資源を隔離する
  • Remote Control使用中は、会話ログがAnthropicのサーバー経由で同期されます(実行とファイルアクセスはNASローカルで完結)
  • compose.yamlなどの設定ファイルはchmod 600で権限を絞る

まとめ

  • Synology NAS(x86_64機)にClaude Codeを常駐させることはできる。方式はContainer Manager(Docker)一択
  • tmuxでセッションを常駐化し、Remote ControlでiPhoneからどこでも接続
  • タスクスケジューラでNAS起動時の自動復帰と、月1回の自動アップデートまで無人化
  • ハマりどころは、文字コード・CPU制限方式・日本語ロケール・タスクスケジューラの罠。特にLANG/LC_ALLの焼き込みは必須
  • 見せる範囲はマウントで制御。:roとCLAUDE.mdがガードレール
  • 日常操作はたった2つ。SSHからcc、抜けるときはCtrl+B → D

そして次回、事件が起きます

……と、きれいにまとまったところで終われば良かったのですが。

NASの中に24時間働くAIがいるという状況は、「じゃあ次は何を作らせよう」という危険な思考を生みます。ブログもPOSレジもゲームもNASで動かしてきた僕が、次に目をつけたのは——Synology純正の「USB Copy」でした。

野鳥を撮るかたなら分かると思うのですが、あのパッケージ、メモリカードをフォーマットすると登録したタスクが呼び出せなくなるんです。カードの性能維持のためにフォーマットは大事。でもフォーマットすると設定が飛ぶ。この矛盾に、僕は長いことモヤモヤしていました。

そこで、NAS常駐のClaudeと一緒に自作してみたところ——本家より使いやすいものができてしまいました。

挿す → ピッ → ピッピッ → アイコンごと消えるので、そのまま抜くだけ。しかもiPhoneから「USB Copyして」と話しかけても動きます。

次回はその全記録です。自動排出だけで5段階の迷宮に迷い込んだ話も含めて、洗いざらい書きます。お楽しみに。

コメント

  1. caos より:

    NASにAI常駐か、さすがに思いつかなかったわ
    codexはスマホから使えるので
    MacBookかメインPCを起動してる時なら
    どこにいてもcodexがなんでもやってくれます
    それがNASだけで、ロマンや‼️

    • Kay Kay より:

      Caosさん、ありがとうございます!
      自分のあらゆるデータの母艦で、それらのデータに対して指示が出せる!
      データ活用の可能性が一気に広がりました。

  2. aoao より:

    こんにちは、はじめまして
    記事興味深く拝見しました。
    2点ほど質問あります。
    1)Kayさんが実施しているClaudeCodeコンテナ常駐ですが、CPUやメモリ使用量って、
      どれくらいでしょうか?
      というのも、以前私はOllamaをDS720+でコンテナ常駐させてみたのですが、CPU100%
      はりつきで全然使いものにならなかったです。
    2)ClaudeCodeはやはり月額使用料払ってらっしゃいますか?

    • Kay Kay より:

      aoao様

      ブログ記事をお読みいただきありがとうございます!また、お返事が遅くなりまして申し訳ありませんm(_ _)m

      当ブログのサーバーとなっているDS1019+(8GB)にClaudeCodeを常駐させていますが、CPUもメモリも負荷が高くなることはありません。実測しましたところ、アイドル時で CPU 1%未満・メモリ約270MB程度でした。

      おそらくですが、お使いのOllamaでは推論自体NASのリソースを使って行いますが、Claude CodeはAnthropicのサーバーサイドで行われているためこの違いが出ているのだと思います。

      また、サブスクについては私は月額100ドルのMaxプランに入っています。Remote ControlにはサブスクのOAuthログインが必要ですので、Pro以上のサブスクが必要になります。

      ご参考になりましたら

      また何かありましたらお気軽にご相談ください!

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