マウント移行:コンテナデータを外部ドライブに置く
要点
~/Library/Containers/ と ~/Library/Group Containers/ のデータ(WeChat のチャット履歴、QQ Music のキャッシュ、App Store アプリのデータ)は、シンボリックリンクでは移せません。AppPorts 1.9.0 以降は、外部ドライブに専用の APFS データボリュームを作成し、データをコピーしてから、元のディレクトリにマウントします。アプリから見えるパスも署名も変わりません。
必要な条件は 3 つです。暗号化されていない APFS の外部ドライブを使うこと、移行後の初回起動時にアクセスを許可すること、アプリを開く前にドライブを接続することです。
使用する場面
「データディレクトリ」→「アプリデータ」でアプリを選択すると、Containers と Group Containers グループ内のディレクトリには「Migrate」の代わりに「マウント移行」ボタンが表示されます。ほかのグループ(Application Support、キャッシュなど)、ツールディレクトリ、カスタムディレクトリは、従来どおりシンボリックリンクで移行できます。
コンテナディレクトリが特別な理由と、メインアプリがサンドボックスかどうかで判断しない理由は、コンテナデータ、サンドボックスと署名 IDを参照してください。
「マウント移行」をクリックした後
AppPorts は最初に外部ストレージを読み取り専用で確認します。何も変更せず、結果に応じて次の操作を案内します。
| 確認結果 | 表示内容 | 選択できる操作 |
|---|---|---|
| 暗号化されていない APFS で、空き容量が十分 | ローカルで解放できる容量、初回アクセスの許可、通常使用時にドライブの接続が必要なこと | 「データを移行」で開始 |
| exFAT、NTFS、HFS+ など | 「この外部ストレージは exFAT フォーマットです」 | このままにする、別の場所を選択、準備方法を見る |
| 暗号化された APFS | 「この外部ストレージは暗号化されています」 | このままにする、暗号化されていない APFS の場所を選択 |
| 空き容量不足 | 必要な容量と現在の空き容量 | 空き容量を増やして再チェック、または別の場所を選択 |
| 外部ストレージ未選択 / 未接続 | 外部ストレージの選択または接続の案内 | 外部ストレージを選択、再チェック |
移行できなくても、何も変更する必要はありません。 アプリ本体、Application Support、キャッシュ、ツールディレクトリは、そのドライブに引き続き移行できます。コンテナデータだけをローカルに残せば、アプリは通常どおり使えます。後で移行したくなったら、APFS の外部ドライブを準備するに従って準備してください。
暗号化した APFS ドライブが現在非対応の理由
マウント移行で作成するデータボリュームは、元のボリュームのパスワードを引き継ぎません。そのまま移行すると、ローカルで FileVault に保護されていたチャット履歴が、パスワードのないボリュームに保存されます。自動ロック解除とパスワード管理を実装するまでは、AppPorts はこのように保護を黙って弱めることはしません。暗号化した外部ドライブを参照してください。
移行前の準備
- AppPorts を「アプリケーション」フォルダに入れ、そこから開いてください。 ログインエージェントには、継続して有効なアプリのパスが必要です。ダウンロードフォルダや DMG から直接実行すると、macOS が一時的な App Translocation のパスを使う場合があります。AppPorts はこのパスを検出すると新しいマウント移行をブロックし、インストールを案内します。AppPorts を移動または更新したら一度開いて、エージェントのパスを更新してください。パスが変わらなければエージェントを再読み込みしません。
- 移行するアプリを完全に終了してください。 AppPorts は実行状態を確認し、起動中の移行を許可しません。
- AppPorts にフルディスクアクセスが必要です。 コンテナのパスへのマウント自体がシステムで管理されているため、許可がないと失敗します。
- バックアップを検討してください。 どのデータ移行でも、重要なデータは先に別途バックアップすることをお勧めします。移行後のデータは外部ドライブにあり、Time Machine は通常外部ドライブをバックアップしません。必要に応じて「システム設定 › 一般 › Time Machine」のオプションで、対象のドライブがバックアップに含まれることを確認してください。
移行中に行う処理
- 外部ドライブの APFS コンテナに新しいボリュームを作成します。作成直後は
/Volumesに自動マウントしません。名前はAppPorts-<Bundle ID>-<目录名>-xxxxxxの形式で、同じドライブのほかのボリュームと空き容量を共有するため、サイズ指定は不要です。 - 新しいボリュームを
~/Library/Application Support/AppPorts/mounts/内に一時マウントし、AppPorts のコピー機能でディレクトリの内容をコピーします。ルートに.appports-mount-metadata.plistを書き込んでから、マウントを解除します。 - 元のディレクトリを同じボリューム上の安全用バックアップへ名前変更し、元のパスに空のディレクトリを作成します。新しいボリュームをそこにマウントし、実際に正しいボリュームであることを検証します。
~/Library/Application Support/AppPorts/container-mounts.plistにマウント記録を書き込み、ログイン時に自動で再マウントするエージェントをインストールします。最後に安全用バックアップを削除します。
外部ドライブの空き容量が不足していれば、ボリューム作成前に停止します。移行が完了する前に失敗した場合、AppPorts はロールバックを試みます。安全に完了できない場合はコピーを保持し、その保存先パスを示します。
移行は完了したものの、最後にローカルの安全用バックアップを削除できなかった場合、マウント済みのデータは引き続き使用できます。AppPorts は削除が残っているバックアップのパスを明示します。再度移行する必要はありません。
移行後は、mount コマンドでコンテナのパスへの直接マウントを確認できます。
/dev/disk7s5 on /Users/<user>/Library/Containers/com.tencent.xinWeChat/Data/Documents/xwechat_files (apfs, local, nodev, nosuid, journaled, noowners, nobrowse)移行後に初めてアプリを開くとき
システムが、アプリによるリムーバブルボリューム上のファイルへのアクセス許可を求めます。許可してください。外部ドライブ上のデータに対する macOS の通常の確認で、一度だけ表示されます。
拒否すると、アプリはデータがないものとして扱い、空の表示になります。「システム設定」→「プライバシーとセキュリティ」→「ファイルとフォルダ」(または「リムーバブルボリューム」)でそのアプリのアクセスを有効にしてください。あるいはターミナルで tccutil reset SystemPolicyRemovableVolumes <Bundle ID> を実行すると、次回に再度確認されます。
/System/Applications 内のシステムアプリはダイアログが出ず、通知なく拒否されます。AppPorts はもともとこれらのアプリを移行しません。
日常の使い方
アプリを開く前に外部ドライブを接続してください。 ドライブがないとき、マウントポイントはロックされた空のディレクトリ(アクセス権 000)になります。アプリには空のデータが見え、エラーは出ません。ローカルに新しいデータを書き込んで二重化することもありません。接続すると AppPorts がボリュームを自動で再マウントし、データが戻ります。
通常、データボリュームは Finder に表示されません。 AppPorts は nobrowse オプションでマウントするため、Finder のサイドバーやデスクトップには表示されません。接続直後の 1〜2 秒は、macOS が先に /Volumes に自動マウントし、アイコンが一瞬表示される場合がありますが、AppPorts の再マウント後に消えます。初期バージョンで移行したため今も Finder に表示されるボリュームは、次回の AppPorts 起動時またはドライブ接続時に、その場で非表示にします。マウント解除や再マウントは不要です。「ディスクユーティリティ」には AppPorts-… というボリュームが残ります。移行したデータそのものなので、そこで消去や削除をしないでください。
取り外す前にアプリを終了し、AppPorts の「マウント解除」をクリックするか、Finder で外部ドライブを取り出してください。 直接抜くと、直前数秒の書き込みが失われたり、データベースの修復が必要になったりする可能性があります。取り外しテストでは、APFS ボリュームで失われたのは最後の数トランザクションでした。実験記録:ドライブの取り外しテストを参照してください。
自動で再マウントするタイミング:
- AppPorts の実行中:起動時とボリュームが接続されたときに、接続済みで未マウントの記録を自動で再マウントします。
- AppPorts を開いていないとき:移行成功後にインストールするログインエージェントが、ログイン時と外部ドライブの接続時にバックグラウンドで再マウントし、終了します。最後の記録を復元すると、エージェントを自動的にアンインストールします。
- 起動直後にアプリを開くと、十数秒間は空のディレクトリを読む場合があります。システムがログイン項目より後にエージェントを起動するためです。一度アプリを終了して開き直してください。マウントポイントを空のまま維持することが最後の保護になります。アプリが先に起動しても空のディレクトリだけを読み、ローカルに新しいデータを書いて分岐することはありません。ボリュームが戻ると自然に復旧します。WeChat では 3 回の実測すべてで復旧しました。
macOS 12 などの旧システムでは管理者パスワードが必要です
macOS 27 では一般ユーザーが自分のディレクトリ内にボリュームをマウントできますが、macOS 12 では許可されないことを確認しました。このエラーが出ると、AppPorts はシステムの管理者パスワードダイアログを表示して再試行します。通常、1 回の移行で一度だけ確認します。ログインエージェントには画面がなく、パスワードを求められないため、これらのシステムではログイン後の自動再マウントはできません。AppPorts を開いてパスワードを入力するか、「アプリデータ」ページで「マウント」を手動でクリックしてください。13〜26 のどのバージョンから許可されるかは、まだ個別に検証していません。
状態と操作
| 状態 | 意味 | 利用できる操作 |
|---|---|---|
| マウント済み | ボリュームが元のディレクトリにマウントされ、アプリが通常どおり読み書きできる | マウント解除、Restore |
| マウント待ち | ボリュームは接続されているが未マウント。接続直後や手動で解除した場合など | マウント、Restore |
| 外部ドライブ未接続 | 対象のデータボリュームが見つからない。通常はドライブが未接続 | ドライブを接続すると AppPorts が自動で再マウント。接続済みの場合は下のトラブルシューティングを参照 |
**「Restore」**はボリュームのデータをローカルにコピーしてから、ボリュームと記録を削除します。外部ドライブは接続したままにしてください。
- 開始前にローカルの空き容量を確認し、不足していればその場で停止します。ボリュームと記録は変更しません。
- コピー後、AppPorts はまずマウント記録をクリーンアップ待ちの情報に変更し、自動再マウントを防いでからローカルのディレクトリに切り替えます。削除するのはマウント解除後に残った空のマウントポイントだけで、ディレクトリを再帰的に削除することはありません。
- ローカルのディレクトリへの切り替えが完了しなかった場合、ローカルの一時コピーと外部ボリュームを保持します。ローカルのコピーは、同じディレクトリ内の
.appports-restore-staging-…という隠しフォルダに残ります。AppPorts が示す保存先パスと案内に従って対処してください。 - ローカルのディレクトリへの復元が完了し、外部ボリュームの削除またはクリーンアップ記録の更新だけが失敗した場合は、復元は完了したもののクリーンアップは未完了であることを明示します。データディレクトリのページからクリーンアップを再試行できます。移行や復元を繰り返さないでください。
コピーがまだ残っているか確認できない場合は「クリーンアップ記録のみ削除」を選択できます。この操作ではローカルのバックアップや外部ボリュームを削除せず、再マウントも行わないため、残っているコピーは自分で削除する必要があります。
マウントポイントにローカルのファイルがある場合(ドライブ不在時にアプリが何らかの方法で書き込んだ場合など)、AppPorts はデータを隠さないよう、その上へのマウントを拒否します。ファイルを別の場所に移してからマウントしてください。
AppPorts を削除または移動する前に
マウント移行は、ログイン後に AppPorts のログインエージェントがボリュームを再マウントする仕組みです。AppPorts を削除する前に、「アプリデータ」でマウント移行したディレクトリを「Restore」してローカルに戻してください。 復元せず削除した場合もデータは外部ボリュームに無傷で残りますが、ログイン後に再マウントする処理がなくなり、アプリには空のディレクトリが見えます。AppPorts を再インストールして一度開けば再マウントできます。
更新や移動だけの場合は、新しい場所の AppPorts を一度開けば、エージェントの参照先を自動更新します。
トラブルシューティング
| 症状 | 対処 |
|---|---|
| 接続済みなのに「外部ドライブ未接続」と表示される | 「ディスクユーティリティ」で外部ドライブに AppPorts-… ボリュームが残っているか確認。残っていれば AppPorts のツールバーで更新するか、ドライブを再接続。削除されていれば、このディレクトリのデータは外部ドライブに残っていないため、バックアップから復元する必要がある |
| アプリを開くと空になっている | ディレクトリが「マウント済み」か確認。違う場合はドライブを接続するか「マウント」を実行。マウント済みでも空なら、初回起動時にアクセスを拒否していないか確認 |
| 「マウント」でマウントポイントが空でないと表示される | マウントポイントにローカルのファイルがある。内容を確認し、別の場所に移してからマウント |
| 移行や復元で、外部ストレージへバックグラウンド接続中と表示される | ログインエージェントがマウント中。数秒待って再試行 |
ディスクイメージを使わない理由
exFAT の利用者も多いため、exFAT 上に APFS ディスクイメージ(sparsebundle)を置いてマウントする方法を実際に試しました。アクセス許可のダイアログが出ず、性能は同等で、どの形式にも保存できるため、有望に見えました。
しかし、書き込み中に USB メモリを直接取り外すテストでは、APFS ボリュームは最後の数トランザクションを失うだけでデータベースを修復できたのに対し、ディスクイメージは 2 回とも全体を開けなくなり、中のすべてのデータにアクセスできなくなりました。イメージ自体の「目録」が数秒ごとに書き換えられ、その途中で取り外すと、全体が目録のない断片になるためです。完全なデータは実験記録:ドライブの取り外しテスト、ユーザー向けの説明は外部ドライブに APFS が必要な理由を参照してください。
このため、APFS ボリュームのみ対応しています。
技術的な詳細
自動再マウントのタイミング
- ログインエージェントは
~/Library/LaunchAgents/com.shimoko.AppPorts.container-mount.plistで、AppPorts --mount-agentを実行します。/Volumesも監視し、外部ドライブがシステムにマウントされるたびに実行します。2026-09-22 の起動時の実測では、「ログイン完了 → 4.6 秒後にエージェント起動 → 18 秒後に 2 ボリュームをコンテナのパスに再マウント」という順序でした。初期バージョンより約 19 秒早くなりましたが、ログイン項目のアプリは約 3 秒で起動していました。タイムラインと、さらに早められない理由は実験記録:ログイン前のマウントを参照してください。 - ドライブがすぐに現れなくても、一度試しただけで終了しません。 エージェントはプロセス内で
/Volumesを監視し、固定間隔でポーリングする代わりに、次の実際の変化を待って再試行します。起動時はシステムが混雑しており、ドライブの認識が数分遅れる場合があります。2026-09-23 の実測では起動後 2 分 33 秒でした。定期ポーリングでは、最も忙しい時期にdiskutilを無駄に実行するか、アプリの起動を逃します。イベントが届かない場合に備えて 20 秒ごとにも再確認し、全体の待機時間は 180 秒です。待機中はロックを保持しません。実測では、ボリュームが現れてからマウント完了まで約 1 秒でした。 - マウント前に
/Volumes/<卷名>を確認します。 起動時や接続時には、ほぼ必ずシステムが先にそこへマウントします。statfsとボリュームルートのマーカーの読み取りだけで、AppPorts のボリュームかどうかをマイクロ秒単位で確認でき、diskutil infoを一度省けます。2026-09-23 の起動時には、ログイン直後の負荷により、この問い合わせに 9 秒かかりました。処理全体で最も時間のかかる部分でした。システムによるボリューム名の変更やマーカーの欠落で識別できない場合だけ、diskutilに戻って確認します。 - マウント後は必ず検証します。
diskutil mount -mountPointには、ボリュームがすでにマウント済みの場合に、マウントポイントの指定を無視したままmountedを出力し、0 を返す挙動があります。起動時や接続時は macOS が先に/Volumesにマウントすることがよくあります。そのため毎回、目的のパスに実際にマウントされたかを確認します。違う場合は場所を再取得し、/Volumesから解除してマウントし直します。最大 3 回試行します。2026-09-21 と 09-23 にそれぞれ一度この状況があり、当時は失敗として中止したため、WeChat が空のディレクトリを読みました。 - 管理対象のボリュームだけを操作します。 マウント、マウント解除、復元の前には、マウントポイント上の Volume UUID が記録と一致するか確認します。別のボリュームがある場合はその場で停止し、解除、上書き、削除はしません。
- エージェントと AppPorts はプロセス間ロック(
~/Library/Application Support/AppPorts/operation.lock)を共有します。AppPorts がマウント移行、マウント解除、復元を実行中なら、エージェントは最大 120 秒待ち、取得できなければその回をスキップして、次の接続またはログインに任せます。逆に AppPorts がロックを取得できない場合は操作を開始せず、後で再試行するよう案内します。ロックを保持するのは各回のマウント処理中だけです。数分間ボリュームを待つ間は保持しないため、AppPorts の操作を妨げません。 - 移行記録ファイルを読み取れない場合は、空の記録として上書きせず、元のファイルを保持して記録の追加や削除を拒否します。
/etc/fstabは使用しません。実測ではUUID=形式でマウントできず、デバイス番号の形式では抜き差し後に番号が変わります。さらに、起動時の root によるマウントもアクセス権の制限を受けます。
ボリュームの Spotlight インデックス
システムはコンテナのパスにマウントされたボリュームを通常の外部ボリュームとして扱い、専用のインデックスを作成します。実測では WeChat の 2 ボリュームの .Spotlight-V100 が合計 110 MB あり、起動後も書き換えが続いていました。アプリデータへのシステムインデックスは役に立たないため、次のようにします。
- ボリューム作成後、ルートに空の
.metadata_never_indexを作成し、mds がボリューム全体をスキップするようにします。その時点ですでに.Spotlight-V100があれば、併せて削除します。 - マーカーはボリュームと一緒に保持されるため、ドライブの接続場所を変えたりマウント移行のマウントを復旧したりしても、作り直す必要はありません。
- このバージョン以前に移行したボリュームには、次回のマウント時に自動で追加します。
- ローカルへ復元するときにはマーカーをコピーしません。
.metadata_never_indexは.fseventsd、.Spotlight-V100と同様にスキップします。
確認用コマンド
# 挂载记录
plutil -p ~/Library/Application\ Support/AppPorts/container-mounts.plist
# 当前挂载
mount | grep Containers
# 登录代理
launchctl print gui/$(id -u)/com.shimoko.AppPorts.container-mount
# 卷根有没有防索引标记;系统的索引状态应为 Indexing disabled
ls -la "<挂载点路径>/.metadata_never_index"
mdutil -s "<挂载点路径>"
# 手动重挂(要在有完全磁盘访问权限的终端里执行;旧系统前面加 sudo)
diskutil mount nobrowse -mountPoint "<挂载点路径>" <Volume UUID>関連ドキュメント
- 外部ドライブに APFS が必要な理由
- コンテナデータ、サンドボックスと署名 ID
- macOS 27 へのアップグレード:旧方式からの切り替え方
- 実験記録:マウントポイント:この機能の根拠となる実験
