2026 年 5 月 5 日 14 時、複数の デスクトップクライアントが「アクセスしようとしているリソースは現在ロックされており、変更できません」というエラーを画面いっぱいに並べました。サーバー側で テーブルを確認すると、エントリ数は 663,899 件。同期は完全に止まっていました。
本記事では、緊急復旧(30 分)から、真因究明、Redis ロックバックエンドへの恒久移行までを、実コマンドと数値で記録します。
まず緊急復旧 — 30 分で同期を戻す
ロック詰まりが起きた時点で、サーバー側で確認すべきは 1 点だけです。
``bash`
docker exec nextcloud-db mariadb -u root -p"$DB_PASS" nextcloud \
-e 'SELECT COUNT(*) FROM oc_file_locks;'
返ってきた件数が 500 を超えていたら異常、5,000 を超えていたら復旧操作が必要です。当方は 663,899 件でした。
復旧手順は 3 ステップ。 を有効にしてから、ロックテーブルを TRUNCATE します。
`bash1. メンテナンスモード ON(同期セッションを切断)
docker exec --user www-data nextcloud-app php occ maintenance:mode --on
2. ロックテーブルを空にする
docker exec nextcloud-db mariadb -u root -p"$DB_PASS" nextcloud \ -e 'TRUNCATE TABLE oc_file_locks;'3. メンテナンスモード OFF
docker exec --user www-data nextcloud-app php occ maintenance:mode --off `
当方は所要 5 分で 663,899 件を 0 件まで落とし、status.php が
{"maintenance":false} を返すまで復旧しました。ただしこれは対症療法で、原因を取り除かなければ再発します。
💡 KEY TAKEAWAYS
oc_file_locks の TRUNCATE は安全ですが、メンテナンスモード ON 必須。ON せずに削除すると同期セッションが破壊されます。
真因 — 3 つの要素が共謀していた

Nextcloud 同期ロック詰まりの構造
ログを
nextcloud.log から is locked パターンで grep し、remoteAddr と userAgent で集計したところ、以下が判明しました。
要素 観測結果 同期クライアント数 4 台(Mac × 2、Windows × 2) クライアントバージョン 33.0.2 / 33.0.3 / 33.0.4 が混在 同期対象に含まれていた問題ファイル 、.next/cache、/.sst(各 100MB 超) DB()、 未設定
3 つが共謀した結果として、秒間数百件のペースで Lock 取得 → リリース要求が連鎖し、最終的に DB ロックテーブルが詰まったわけです。
真因 1: 複数クライアントの並行同期
Master-Replica 思想(メイン編集 1 台、他は閲覧)でなく、4 台すべてが書き込み権を持って同じフォルダを並行同期していました。古いバージョンのクライアントは新しい除外設定を尊重せず、新しいクライアントが除外したファイルを再アップロードする無限ループが起きていました。
真因 2: ビルド成果物が同期対象
node_modules 配下には Next.js 16 系で 10 万ファイル超、.next/cache/webpack/0.pack は単一で 295 MB。これが同期対象に入ると、1 ファイルあたり Lock 取得 → リリースが走り、サーバー側の DB がボトルネックになります。
真因 3: ロックバックエンドが DB
Nextcloud の公式ドキュメントも「 を Redis に設定すれば DB 負荷が大幅に下がる」と明記しています。当方サーバーは初期インストール状態のままで
memcache.locking` 未設定 → DB ロック使用、という最も負荷が高い構成でした。恒久対策 — Redis ロック化の実装
DB ロックを Redis ロックに切り替える手順です。Nextcloud 公式 Docker イメージは redis.config.php という上書きファイルが標準で含まれており、環境変数 REDIS_HOST を渡すだけで自動的に Redis ロックが有効になります。
Step 1: docker-compose.yml に Redis サービス追加
``yaml
services:
nextcloud-redis:
image: redis:7-alpine
container_name: nextcloud-redis
restart: always
command: ["redis-server", "--save", "", "--appendonly", "no"]
networks:
- nextcloud-net
nextcloud-app:
# 既存設定 +
environment:
REDIS_HOST: nextcloud-redis
REDIS_HOST_PORT: 6379
depends_on:
- nextcloud-db
- nextcloud-redis
`
save "" と appendonly no でディスク永続化を無効化しています。ロック情報は揮発性で十分(コンテナ再起動で消えても問題ない)。
Step 2: 起動 + 再起動
`bash`
docker compose up -d nextcloud-redis # Redis を先に起動
docker compose up -d nextcloud-app # nextcloud-app を再生成(env 変数反映)
ここで nextcloud-app の再起動が必須です。env 変数は再起動するまで反映されません。
Step 3: 動作確認
`bashRedis 接続確認
docker exec nextcloud-app php -r '$r = new Redis(); $r->connect("nextcloud-redis", 6379); echo $r->ping();'→ +PONG
設定反映確認
docker exec --user www-data nextcloud-app php occ config:system:get memcache.locking→ \OC\Memcache\Redis
Redis にキーが書かれているか
docker exec nextcloud-redis redis-cli DBSIZE→ 正の整数(11 など)
`
当方の場合、切り替え後 5 分間で
oc_file_locks の件数は 0 のまま、Redis 側の DBSIZE は安定して 10〜20 件で推移しました。これが正常な状態です。
💡 KEY TAKEAWAYS
Redis ロックは標準でサポートされているのに、デフォルト OFF。
docker-compose.yml に Redis サービスと REDIS_HOST env 変数を足すだけで有効化できます。
ハマりポイント 3 つ — 実体験ベース

Nextcloud Redis 化で踏んだ 3 つの罠
落とし穴 1: 設定ファイルの重ね順を見落とす
Nextcloud は
/var/www/html/config/ 配下の *.config.php をアルファベット順に読み込みます。apcu.config.php が memcache.local を に上書き、redis.config.php が memcache.locking を Redis に上書きします。
occ config:system:set memcache.local --value='\OC\Memcache\Redis' で上書きしようとしても、後から読まれる apcu.config.php で APCu に戻されてしまいます。
突破:
memcache.local は APCu のままがベストプラクティス(in-process キャッシュで最速)。Redis 化すべきは memcache.locking と memcache.distributed のみ。これは redis.config.php が自動で処理します。
落とし穴 2: 環境変数を追加してもコンテナ再起動を忘れる
docker-compose.yml に REDIS_HOST: nextcloud-redis を追加しただけでは、稼働中の nextcloud-app コンテナには反映されません。docker compose up -d nextcloud-app で再生成するか、docker restart nextcloud-app で再起動が必要です。
これを忘れると
redis.config.php の if (getenv('REDIS_HOST')) が false で評価され、Redis ロック設定が無効化されたまま稼働します。当方も初回はここで詰まり、occ config:system:get memcache.locking が空を返して気づきました。
`bash
env 変数の反映確認
docker exec nextcloud-app sh -c 'echo "REDIS_HOST=$REDIS_HOST"'
→ 空ならコンテナ再起動が必要
`
落とし穴 3: Nextcloud Desktop 側の除外パターンに IME が混入
クライアント側で「無視リストを編集」ダイアログから
node_modules や .next を追加する際、日本語 IME が ON のまま入力すると .turbo…(U+2026 三点リーダー)のような不可視文字が混入します。.turbo` ではマッチしないので、除外設定が機能しません。
突破: 除外パターン入力時は IME を強制 OFF(英数モード)にする。追加した行を再度ダブルクリックして文字列を確認する習慣をつける。
次のアクション
セルフホスト Nextcloud は構築の容易さと引き換えに「初期設定が最低限」で出荷されます。本番運用に耐えるには、Redis ロック化・除外パターン整理・バックアップ計画の 3 点が欠かせません。
本シリーズの第 2 回では、当方が同じ事故をきっかけに構築した「Cloudflare R2 + restic で月 22 円バックアップ」(翌日公開)、第 3 回では「Dropbox 代替を自社で組む判断軸」(翌々日公開)を扱います。
「Nextcloud 同期が重い・止まる」「自社にどの構成が合うか判断したい」という方は、まず 細マッチョ企業診断 で運用体力の現在地を把握ください。神経系(判断速度)・耐久力(継続力)・筋力(実行力)の 5 軸で、どこを優先的に補強すべきかが見える化されます。
EXBANK では Nextcloud の構築・運用代行も承っています。事故対応より「事故を起こさない体制づくり」から始めましょう。
