メインコンテンツへスキップ
見出し画像

Ferdiumの公式サーバーが落ちるので、NASにAPIサーバーを立てた

    はじめに

    複数のチャットツールを1つにまとめる「Ferdium」を使っていて、こんな経験はありませんか。

    会社のパソコンで設定を整えたのに、別のMacを開いたら反映されていない。よく調べてみると、Ferdiumの公式アカウントサーバー(api.ferdium.org)が落ちていて同期が止まっている——。私はこれが何度か続き、そのたびに「また今日か」と作業の手を止めていました。

    外部のサーバーに依存している以上、こちらからできることは何もありません。そこで、Synology NASに自分専用のFerdiumサーバーを立てることにしました。

    この記事では、その構築手順を最初から最後まで解説します。あわせて、私が実際につまずいた2箇所も、症状から原因の特定までそのまま書きました。とくに2つ目は、Ferdiumに限らずDockerを使う人なら誰でも踏みうる落とし穴です。

    5000004818

    画像
    Ferdiumアプリ。1つのウィンドウに複数のサービスが並んでいる

    Ferdium-serverとは?自分専用サーバーで何が変わるのか

    Ferdium-serverは、Ferdiumの設定やサービス一覧を保管する「アカウントサーバー」を自分で立てられるようにしたソフトです。公式が配布しており、Dockerコンテナとして動かせます。

    Ferdiumは、追加したサービスやワークスペースの構成をアカウントに紐づけて保存し、複数の端末で同期します。この保存先が、標準では公式のサーバーになっています。保存先を自分のサーバーに切り替えるのが、今回やることです。

    自分で持つと、次の3点が変わります。

    • 公式サーバーが止まっても、自分の環境だけで同期が完結する

    • 設定データがNASの中に置かれる

    • 登録を自分だけに閉じられる(後述します)

    用意したもの

    • NAS:Synology DS923+ ─ Container Manager(旧Docker)が使えるモデルなら同様に構築できます

    • 独自ドメイン:example.com ─ エックスサーバードメインで管理

    • 回線:一般的な家庭用回線(動的IP) ─ 固定IPは不要です。理由は手順1で説明します

    • クライアント:Ferdiumデスクトップアプリ(Mac) ─ 設定済みの状態から切り替えました

    構築手順:5ステップで自分専用サーバーを立てる

    全体は5つのステップに分かれます。「外からNASに、暗号化された通信でたどり着けるようにする」のが前半3つ、「Ferdium本体を動かす」のが後半という組み立てです。

    手順1:SynologyのDDNSを有効にする

    まずDDNSを有効にして、xxxx.synology.me のようなホスト名を取得します。

    家庭用の回線は、多くの場合グローバルIPアドレスが定期的に変わります(動的IP)。IPアドレスを直接指定してしまうと、変わった瞬間につながらなくなります。DDNS(ダイナミックDNS)は、IPアドレスが変わっても同じホスト名で追いかけてくれる仕組みです。これがあるため、固定IPの契約は必要ありません。

    DSMの「コントロールパネル > 外部アクセス > DDNS」から追加できます。

    画像
    DSMのDDNS設定画面。ホスト名と外部アドレスは伏せています

    手順2:独自ドメインのサブドメインをCNAMEで紐付ける

    次に、独自ドメイン側で ferdium.example.com というサブドメインを発行し、手順1で取得したDDNSホスト名へ CNAMEレコードで向けます。

    ここでAレコード(IPアドレスを直接書く方式)を使わないのがポイントです。CNAMEは「このホスト名の先を見に行ってください」という転送の指定なので、回線のIPアドレスが変わっても、DDNS側が更新されれば自動で追従します。Aレコードにすると、IPが変わるたびに手で書き換えることになります。

    ferdium.example.com   CNAME   xxxx.synology.me

    手順3:Container ManagerでFerdium-serverを立てる

    DSMのContainer Managerでプロジェクトを作成し、次の docker-compose.yml でコンテナを起動します。これが最終形です。

    version: '3'
    services:
      ferdium-server:
        image: ferdium/ferdium-server:latest
        container_name: ferdium-server
        restart: unless-stopped
        ports:
          - "3333:3333"
        volumes:
          - /volume2/docker/ferdium-server/data:/data
        environment:
          - NODE_ENV=production
          - APP_URL=https://ferdium.example.com
          - IS_REGISTRATION_ENABLED=true
          - CONNECT_WITH_FRANZ=false

    volumes の行と NODE_ENV の行が、私がつまずいた2箇所です。この形にたどり着くまでに回り道をしましたので、後の「つまずいた2つのポイント」で詳しく書きます。

    画像
    Container Manager。ferdium-serverのプロジェクトが稼働している

    手順4:SSL証明書を取得し、「割り当て」まで確認する

    DSMの証明書機能で、ferdium.example.com 宛てのLet's Encrypt証明書を取得します。ここまでは画面の案内どおりに進められます。

    画像
    DSMの証明書一覧。ferdium.example.com の証明書が取得できている

    注意したいのは、取得したあとです。証明書は、取得しただけでは対象のサービスに紐づいているとは限りません。

    私の環境では、「コントロールパネル > セキュリティ > 証明書 > 設定」の構成一覧を開いたところ、ferdium.example.com の行に、別サービス(webmail.example.com)向けに取得したはずの証明書が割り当てられていました。取得すれば自動で正しく紐づく、と思い込んでいると見落とします。

    正しい手順は次のとおりです。

    1. コントロールパネル > セキュリティ > 証明書 > 設定 を開く

    2. 対象のサービス行(例:ferdium.example.com)の証明書プルダウンをクリック

    3. 同じドメイン名で取得した証明書を選ぶ

    4. 「OK」で保存する

    5. ブラウザで対象のURLを開き、証明書ビューアで発行先(CN)が意図したものになっているか確かめる

    画像
    「設定」を開いた構成一覧。サービスごとに、どの証明書を使うかを指定する

    なお「既定値としての証明書に設定します」というチェックは、どの証明書にも一致しないアクセスがあったときの予備を決めるものです。これを入れても、個別のサービスへの割り当てが保証されるわけではありません。

    手順5:リバースプロキシで外からコンテナにつなぐ

    最後に、DSMの逆プロキシ機能で、外部からのHTTPS(443番)のアクセスを、NASの内部で動いているコンテナ(localhost:3333)へ転送します。

    リバースプロキシは、建物の受付・案内係のようなものです。訪問者(外からのアクセス)は入口の受付に「ferdium.example.comに用がある」と伝えるだけで、受付が「それなら3333番の部屋です」と中まで取り次いでくれます。訪問者が部屋番号を知る必要はなく、部屋を移動しても受付の案内を変えるだけで済みます。

    • ソース プロトコル:HTTPS

    • ソース ホスト名:ferdium.example.com

    • ソース ポート:443

    • 宛先 プロトコル:HTTP

    • 宛先 ホスト名:localhost

    • 宛先 ポート:3333

    画像
    DSMのリバースプロキシ一覧。ferdium は 443 から localhost:3333 へ転送している


    つまずいた2つのポイント

    ここからが本題です。手順どおりに進めたつもりでも、私は2箇所で足を止めました。

    つまずき1:NODE_ENVを書かず、コンテナが起動と停止を繰り返した

    コンテナは起動するのに、数十秒から数分で「予期せず停止しました」という通知が出る。それが延々と繰り返され、気づけば通知が178件たまっていました。

    ログを見ると、原因はすぐ分かりました。

    "NODE_ENV" variable environment Missing E_MISSING_ENV_VALUE: Exception:

    Ferdium-serverはAdonisJSというフレームワークで作られており、起動時に必須の環境変数をチェックします。NODE_ENV が無いと、そこで例外を出して落ちる仕組みでした。

    docker-compose.yml に NODE_ENV=production を足して解決です。これは10分で済みました。問題は次です。

    つまずき2:マウント先を「/app配下だろう」と思い込んでいた

    最初、ボリュームの設定をこう書いていました。

    # 間違っていた設定
    volumes:
      - /volume2/docker/ferdium-server/data:/app/data

    「アプリ本体は /app の下に置かれることが多い」という一般的なDockerの慣習から、なんとなく /app/data だろうと決めてしまったのです。

    正解は /data でした。 Ferdium-server自体が DATA_DIR(既定値 /data)という環境変数を見て、データの書き込み先を決めていたためです。

    この食い違いから、一見つながらない症状が次々に出ました。時系列で並べます。

    症状1:ログに見慣れないメッセージが出る

    Database file '/data/ferdium.sqlite' not found. An empty database will be created.
    /entrypoint.sh: line 64: can't create /data/FERDIUM_APP_KEY.txt: nonexistent directory

    症状2:ファイルが1つも作られない

    File Stationでホスト側の data フォルダを開いても、ferdium.sqlite などが一切生成されていません。コンテナは動いているのに、中身が空のままでした。マウントされていない /data に書こうとしていたので、当然ホスト側には何も現れません。

    症状3:どんなメールアドレスでも「既に登録されています」と言われる

    Ferdiumアプリからアカウントを作ろうとすると、何を入れても既に登録済みだと表示されます。明らかに使っていない test12345@example.com のようなアドレスでも同じでした。ここで私は「サーバーに変なデータが残っているのだろうか」と、見当違いの方向を疑い始めました。

    調査:実際の通信を見た

    Chromeの開発者ツールのNetworkタブで、アプリが実際に受け取っているレスポンスを確認しました。

    {
      "message": "Invalid POST arguments",
      "messages": {
        "errors": [
          {
            "rule": "unique",
            "field": "email",
            "message": "unique validation failure"
          }
        ]
      },
      "status": 401
    }

    unique validation failure——重複チェックに引っかかった、という内容です。しかし本当にメールアドレスが重複していたわけではありませんでした。データベースのマイグレーション(テーブルを作る初期処理)が完了しておらず、重複チェックのクエリ自体が実行できずに失敗していたのが真相です。それがアプリ側では「登録済み」というメッセージになって表示されていました。

    解決

    マウント先を /app/data から /data に変更しました。修正後、File Stationの data フォルダに FERDIUM_APP_KEY.txt(33バイト)と ferdium.sqlite(88KB)が生成されているのを確認できました。アカウント作成も同期も、その場で通りました。

    ここから得た教訓

    Dockerコンテナのマウント先は、「アプリだから /app の下だろう」という慣習で決めてはいけない、ということです。どこに書き込むかは、そのイメージを作った人が決めていることで、統一のルールはありません。

    そして情けないことに、答えは最初から画面に出ていました。Container Managerの「コンテナ詳細」に表示される環境変数の一覧に、DATA_DIR=/data と書かれていたのです。私はそれを見ずに思い込みで設定していました。マウント先を決める前に、環境変数の一覧・Dockerfile・公式のdocker-compose.ymlサンプルのどれかを確認します。それだけで防げた回り道でした。

    画像
    コンテナ詳細の環境変数一覧。DATA_DIR に /data と書かれている

    Ferdiumアプリから接続し、後始末までやる

    サーバーが動いたら、Ferdiumアプリの接続先を切り替えます。

    1. Ferdiumアプリを開き、設定から Change Server を選ぶ

    2. 自分のサーバーのURL(例:https://ferdium.example.com)を入力する

    3. アカウントを新規作成し、ログインする

    4. サービスを追加して、別の端末でも同じ構成が出てくるか確かめる

    サーバーが正しく動いていれば、ブラウザで自分のサーバーのURLを開いたときに、この案内画面が表示されます。アプリの設定に進む前の確認に使えます。

    画像
    ブラウザで自分のサーバーを開いたところ。接続手順がそのまま案内されている

    登録を閉じる(忘れずにやっておきたい後始末)

    自分のアカウントを作り終えたら、docker-compose.yml の設定を次のように変えてコンテナを再起動します。

          - IS_REGISTRATION_ENABLED=false

    この値が true の間は、URLを知っている人なら誰でもアカウントを作れる状態です。構築直後は自分が登録するために true にしておく必要がありますが、済んだら閉じておきましょう。家族や同僚にも使ってもらう場合は、その人の登録が終わるまで true のままにして、後から false に戻す運用になります。

    実際にやってみて感じたこと

    構築より、思い込みを解くほうに時間がかかりました。

    手順そのものは、DDNS・CNAME・証明書・リバースプロキシと、Synology NASを使っている人なら一度は通る道です。特別に難しいところはありません。実際、詰まった2箇所はどちらも設定ファイルの1行で、直すのは一瞬でした。

    時間を溶かしたのは、「どんなメールアドレスでも登録済みと言われる」という症状から、マウント先の1行にたどり着くまでです。症状と原因の見た目がまったく似ていないため、アプリ側を疑い、サーバーのデータを疑い、と遠回りをしました。抜け出せたきっかけは、開発者ツールで実際のレスポンスを見たことです。画面に出ているメッセージ(「既に登録されています」)ではなく、その裏で返っている中身(unique validation failure と401)を見たら、DBが怪しいと分かりました。

    表示されているメッセージを、原因の説明だと思わないこと。 これは今回に限らず、トラブルシューティング全般に効く姿勢だと改めて感じました。

    そしてもう1つ。公式サーバーが落ちるたびに感じていた小さなストレスが、なくなりました。自分の家の中で完結しているので、誰かの都合で止まることがありません。NASを持っている方なら、試す価値はあると思います。

    よくある質問

    Q. 固定IPの契約がなくても構築できますか?

    できます。SynologyのDDNS機能でホスト名を取得し、独自ドメインのサブドメインからCNAMEで向ければ、IPアドレスが変わっても自動で追従します。今回の構成も一般的な家庭用回線(動的IP)です。

    Q. Synology以外のNASやサーバーでも同じようにできますか?

    Ferdium-serverはDockerコンテナなので、Dockerが動く環境であれば考え方は同じです。ただしDDNS・証明書・リバースプロキシの設定画面はそれぞれの製品で異なるため、この記事のDSMの画面そのままにはなりません。

    Q. コンテナは起動しているのに、アカウントが作れません。

    ホスト側のフォルダに ferdium.sqlite が生成されているか確認してみてください。生成されていなければ、この記事のつまずき2と同じで、ボリュームのマウント先が違っている可能性があります。Container Managerのコンテナ詳細から DATA_DIR の値を確認し、その値をマウント先に指定します。

    まとめ

    • 公式サーバーに依存せず、自分のNASの中だけでFerdiumの同期を完結できます。 必要なのはDDNS・サブドメインのCNAME・証明書・リバースプロキシ・コンテナの5つです

    • 固定IPは不要です。 DDNSとCNAMEの組み合わせで、IPアドレスの変化に自動で追従します

    • Dockerのマウント先を慣習で決めないこと。 DATA_DIR のような環境変数に答えが書かれています。今回いちばん時間を使ったのがここでした

    次回は、この構成にもう1つ足して、Ferdiumでは扱えない「普通のIMAPメール」を同じNASで見られるようにした話を書きます。同じドメイン・同じNASをそのまま使い回せます。

    ぜひ試してみてください。うまくいかない箇所や、こんな使い方をしているよという話があれば、コメントで教えていただけると嬉しいです。

     
     
    株式会社マジカルリミックス 代表取締役CEO 専門学校デジタルアーツ仙台 非常勤講師、仙台商工会議所窓口専門家、エキスパート・バンク登録専門家、みやぎ産業産業振興機構 登録専門家 クレジットカード70枚持ち。

    あなたへのおすすめ