Chienomi

ローカル同期システムでクラウドドライブを代替する

Live With Linux::server

事の起こりは、MEGAがリログしたら、なぜか/の同期が/MEGAの同期になってバーストしてしまったことである。

このバーストで同期が壊れたため、MEGAの同期を停止して一度削除して再同期することを考えていた。 が、間違ってSSH端末で操作し、削除もまたMEGAに同期させてしまった。

間の悪いことに、そのとき3台がオンラインであった。 これらからすべての同期データが消えてしまったのである。

幸いにも同期しているホストがもうひとつあり、データそのものは無事であった。

そこでこのデータをまずは書き戻そうとしたが、今度は同じフォルダが重複している扱いとなり、ファイル操作自体ができなくなってしまった。

とりあえず一旦サポートに投げ、そもそもバーストしていて当面使えないということから代替手段を用意することにした。

まずすべきこと

最後1台のホストにデータが残っているが、同期されると消えてしまう。

そこでまずはバックアップすることが大事である。 MEGA (megasync)はデスクトップアプリであり、ユーザーでログインしなければ同期されることはない(cliで同期している人は別である)。

最初に、対象ホストをブートする。 ブートしないで救出する必要はないし、ブートしなければ救出できないが、勢いでログインしてしまわないように注意する必要がある。 自動ログインを有効にしている人は、オフラインで救出するか、ブートオプションでsystemd.unit=multi-user.targetを付加するなど工夫が必要になる。

なお、megasyncはデフォルトで自動起動に遅延が入っているので、その状態であれば間違ってログインしても素早くログアウトすれば間に合う。 しかし、危険である。

起動後の救出方法は簡単なのは2つ。

ひとつは、仮想コンソールで操作する。Ctrl+Alt+F3とかだ。 よくF2を説明する人がいるが、私の環境だとtty2はSDDMがデフォルトで使うので適さない。

もうひとつはSSHを使う方法だ。SSHログインできる状態になっている必要がある。

SSHが使えるなら、rsyncで

rsync -av foo.local:MEGA/ ~/MEGA.bak/

みたいにして取り込む方法もある。

ファイルが保全できたら、一旦MEGAの同期を停止する。 穏当にやるなら、MEGAのサイトからデバイスをログアウトさせる。 確実に止めるなら

rm ~/.local/share/data/"MEGA Limited"

簡単な代替手段

私のMEGAの使い方としては、まず

  • 素のフォルダ
  • EncFSで暗号化されたフォルダ

の2種類がある。 そして、それらそれぞれの上に

  • 素のファイル
  • リポジトリ

の2種類がある。

つまりは、ファイルシステムとしてアクセスできる必要がある。

また、この構成はMEGAの暗号化を前提にしており、クラウドセーフではない。 平文ファイルの安全性を担保しなければならない。

ふと思い出したのが、Dynabookの存在。 Core i5-2520Mという、古いプロセッサを搭載したラップトップであり、キーボードとヒンジが壊れている。 YouTubeを動かすのも厳しい性能をしているが、ファイルサーバーくらいならば使えるだろう。

オンプレミスで運用するローカルサーバーならば、(dm-crypt上に乗せることで)平文ファイルの安全性を気にせずに済む。 ファイルアクセスという点では、最も簡単な話をすればSSHFSで共有すれば良い。 この場合、ファイル同期ではなくファイル共有になるため、注意点は別途存在するが、一旦動くようにするという意味では問題ない。

なお、MEGAはモバイルで使うファイルの共有という意味ももたせているが、一旦それについては忘れることにする。

ラップトップサーバーのセットアップ

セットアップの容易さをとって、いつもどおりManjaro Cinnamonでセットアップした。 Manjaro Cinnamonは依存関係の薄い、かなり小さなイメージになっているため、削っていく使い方もしやすい。

ハードウェア的にはHDDが使われているため、余っていた128GBの2.5inch SSDを搭載させた。 ディスク容量に余裕がないため、ディスクの使い方には配慮が必要。

インストールが終わったら

sudo systemctl enable --now sshd

でsshdを起動して、アップデートや必要なパッケージのインストールを済ませる。 Manjaroを使ったため、メインデスクトップのパッケージキャッシュをSSHFSで共有してディスク使用も減らした。

続いてsshdの設定だが、無難に

AddressFamily inet
Ciphers aes128-ctr,aes128-gcm@openssh.com,aes128-cbc
DenyUsers *
AuthenticationMethods publickey

Match Address 127.0.*.*,192.168.*.*,10.0.*.*
  DenyUsers root

という感じ。

再起動前に鍵登録を忘れずに。

あとは再起動して安定運用状態にし、

rsync -av ~/MEGA/ dynabook.local:MEGA/

で同期、この同期先を使うようにすることで共有できる。

Unison

やはり同期したい

というわけでSSHFSによる共有ができるようになったわけだが、ちょっと問題がある。

各ホストは同期ファイルのうちの暗号化されているディレクトリをログイン時に自動的にマウントするようになっており、これはSSHFSをマウントするタイミングよりも(自然な状態では)早い。 よって、単にSSHFSで共有しただけではこのような自動マウントを遅延させる必要がある上に、サーバーのavailabilityに強く依存することになる。

そして、これはそれぞれのホストに仕込まなくてはいけない。 つまり、面倒だ。

そう考えると、やはり同期のほうが扱いやすい。

ならどのような方法で同期するか。

多くの人が考えるのはNextCloudだろう。Dynabookというオンプレミスサーバーを用意したので、ここにNextCloudを組むことは考えられる。 だが、NextCloudはかなり面倒だ。不必要な手間がかかるという意味でも、効率という意味でも、動作上の問題という意味でも、正直あまり採用したくない。

望ましいのは、純粋にファイルベースの同期ができるようにすることだ。 MEGAへの復旧に妨げにもなってほしくない。

そこで採用したのがUnisonである。

Unisonとは

UnisonはOCamlで書かれた、ファイル同期ツールである。 unix likeなシステム以外にもWindowsでも動作するらしい。

Unison自体は、サーバーとの間でSSHを使ってファイルを同期する。 この同期は、ファイル更新のdiffとコピー機能である。

Unisonは同期するクライアントにソフトウェアを導入していれば良く、ファイルホストは「SSHでログインしてファイルを置くことができる」を満たしていればそれで良い。

Unison自体は起動されたときに更新状態を確認し、プロンプトを表示するものである。 自動的に解決可能な状態であれば、プロンプトを表示させないこともできる。 更新によって勝手に同期したりはしないが、そのようなことを可能にするために組み合わせるプログラムとしてunison-fsnotifyが付属し、inotifyが利用可能なシステムで使うことができる。

GUIプログラムも付属している。

基本的な使い方

まず初期設定を行う必要があるのだが、GUIを使ったほうがわかりやすいので、

unison-gui

で設定を行う。

注意点として、同期情報はSSHで指定するホスト名ごとに固有であり、.ssh/configHostを変更するなど、同一ホストに対してでもホスト名が変化すると新しい同期として扱われる。

Unisonには同期ごとに「プロファイル」を使用する。 これにより、複数のディレクトリを同期することも可能である。

同期設定が終わったらunison-guiを用いて同期することもできるが、自動化したいだろう。 まず、コマンドラインで使うには

unison ${profile}

となる。このプロファイルはGUIで設定したものと同じ名前だ。 これによって対話的に同期が行われる。

自動同期が可能な状態で非対話的に同期するには

unison -batch -auto ${profile}

となる。

Systemd + Systemd Timer

UnisonをSystemdユニットにすることで自動化が可能。 unisonコマンドに-auto-batchを組み合わせることで、conflictしなければ自動で進行させることができる。

今回のunisonは実行して同期したら終了するので、oneshotユニットとなる。

[Unit]
Description=Sync files via unison

[Service]
Type=oneshot
ExecStart=/usr/bin/unison -batch -auto MEGA

さらにTimerユニットを作り、定期的に同期を行う。

[Unit]
Description=Automatic sync via Unison

[Timer]
OnBootSec=5min
OnUnitInactiveSec=5min

[Install]
WantedBy=timers.target

失敗時をカバーするようにはしていないが、だいぶ脱線するので略。

Systemd + inotify

Unisonにはファイルシステムの変更を検知するunison-fsmonitorが付属している。 (Macだと動かないらしい。)

これの使い方はごく単純に、-repeat=watchオプションを指定するだけだ。 同期フォルダ以下のファイル数にもよるが、自動検出されるようになって利便性は高い。 一方で同期頻度が増えることで、アプリが自動更新するファイルがあると複数ホスト同時オンラインではconflictしやすい。

これを利用する場合、.timerユニットは不要であり、代わりに再起動を指定する必要がある。 また、タイプも起動したプロセスがそのままサーバーとして動作するsimpleを指定する必要がある。

[Unit]
Description=Sync files via unison

[Service]
Type=simple
ExecStart=unison -auto -batch -repeat=watch MEGA
Restart=always
RestartSec=300

[Install]
WantedBy=default.target

MEGAの復旧と顛末

そんなことで崩壊してしまったMEGAだが、サポートから「アカウントの再読み込みを試して」と即日返ってきたので、試したところファイルがおかしいのは解決し、ファイルを全部抹消することができた。

全部抹消できたので全部アップロードもできる。 抹消すれば容量は0になり、転送容量はダウンロードにしかかからないのでアップロードは可能なためだ。

さらに私のMEGAアカウントはかなり古い(50GB時代のもの)ため、転送バーストは1日で回復するようになっており、翌日には正常化した。

このように、1日かけて代替手段を構築したのだが、結果的には単に1日待っても良かったということになった。

ありがとう、MEGA。君は素晴らしい。

ちなみに、Proアカウントならデータを消し飛ばした時点で巻き戻しで復旧が可能。 その前の、おかしなクラウドデータが同期されたのも、巻き戻しで対応可能だった。