プログラマーのメモ書き

伊勢在住のプログラマーが気になることを気ままにメモったブログです

Roundcube で 1MB 超の添付ファイルが送れない

こちらの記事で書いたように、メールクライアントとして Roundcube を使っています(Roundcube は QNAP NAS 上で docker で動かしています)。

いままで、順調に使えていたのですが、先日添付ファイルを送ろうとしたら、エラーが表示されて、添付ファイルをアップロードすることができないという事態が発生しました。

取り急ぎは、元のメールアカウントの Web メールを使って送信したので、事なきを得たのですが、このままだとせっかく Roundcube を使っている意味がありません。

ということで、原因の調査をしてみたので、ことの顛末をメモっておきます。現在の環境は以下の通りです。

  • Roundcube: 1.5.3
  • QNAP TS-251+
  • QTS: 5.0.1.2425
  • Container Station: 2.6.7.44

制限が発生する添付ファイルのファイルサイズ

この現象に遭遇する以前から、添付ファイルは問題なく送れています。今回送ろうとしたのが、 Roundcube に切り替えてからは初の accessのファイル ( .accdb ) だったので、考えられる原因は2つあります。

  • ファイル種類の制限
  • ファイルサイズの制限

最初は前者かと思い、いろいろと調べていたのですが、どうもそれらしい制限が見当たりません。

ここまではブラウザとして Chrome を使っていたのですが、試に Firefox でやってみたところ、下記の画像のように『 Request Entitiy too large 』と表示されました。

あぁ、ファイルサイズが原因っぽいですね。

ということで、新規メールの作成を使ってテストしてみます。PDFファイルは何度も過去に送ったことのあるので、 PDF ファイルでいろいろなサイズの添付ファイルを試してみたところ、だいたい 1MB を超えるとアップロードに失敗するようです。

やっぱりこれっぽいですね。

現状の設定の確認

どこか設定を間違えていないか確認します。 Roundcube は docker-compose で立ち上げているのですが、それには

  roundcubemail:
    (略)
    environment:
      (略)
      - ROUNDCUBEMAIL_UPLOAD_MAX_FILESIZE=30M

と添付ファイルのサイズは 30MB まで OK と指定してあります。

念のため、 php info を確認すると

[ユーザ名@NAS名 application]$ docker exec -it myrc /bin/bash
root@74a3150b44ab:/var/www/html# php --info | grep -i max_size
post_max_size => 30M => 30M
root@74a3150b44ab:/var/www/html# 
root@74a3150b44ab:/var/www/html# php --info | grep -i max_filesize
upload_max_filesize => 30M => 30M

post_max_size , upload_max_filesize とも 30MB になってます。Roundcube 側の設定はここまで見る限り問題なさそうです。

こういう時はログを手がかかりに調べるのが常套手段なので、 NAS の Roundcube コンテナのコンソールを見て、標準出力に出てるログを確認してみます。

あれ?何にも出てません。

さて、こまったぞ。

原因

当初は、 Roundcube 自体の問題かと思い、いろいろと調べてたんですが、なかなか原因がわかりません。そのうち、(どういう経緯かは覚えていませんが)ふと、プロキシサーバーのサイズ制限、といった話題を目にしました。

ん?今の docker-compose で立ち上げた Roundcube は https 化するのにリバースプロキシとして https-portal を使ってた、ということを思い出しました。

ひょっとしたら、これかも。と思い調べてみると、見事ありました。

file size upload limit introduced by https-portal? · Issue #115 · SteveLTN/https-portal · GitHub

https-portal はデフォルトでボディサイズを制限しているとのことです。なるほどね。

で、 https-portal でひっかっかてるんだったら、 Roundcube 側にログがでないのもうなずけます。ということで、 https-portal のログを調べてみると、それっぽいのがあります。

ほぼ、これが原因と考えてよいでしょうね。

解決方法

じゃあ、上の記事を参考にして、設定を変更しようと思ったのですが、具体的にどうすればいいのかな? docker-compose.yml で設定変更できないかな?と思い、もうちょっと調べると、下記の記事が見つかりました。

Where to change docker nginx file upload limit? · Issue #173 · SteveLTN/https-portal · GitHub

どうも、 docker-compose.yaml の envirionment に書けば、反映されるようです。

ということで、 Container Station を開いて、『アプリケーションの編集』を押します。

docker-compose.yml が表示されるので、この内容に対して、

services:
  https-portal:
    (中略)
    environment:
    (中略)
      CLIENT_MAX_BODY_SIZE: 0

(後略)  

のように CLIENT_MAX_BODY_SIZE を追加します( 0 はサイズチェックを行わないになります)。

編集後、『適用』ボタンを押します。

しばらくすると、コンテナが再起動するので、起動後、もう一度新規メール作成を選び、 1MB を超える添付ファイルを選択したら、問題なく添付できました!もちろん、送信も問題なくできます。

ずばり、これが原因だったんですね。

参考

ちなみに、最初は Chrome で試してたんですが、この時は『サーバーエラー』とだけ出てきていたので、何のことかさっぱりわかりませんでした。

で、試に Firefox でやってみたところ、上述のように『 Request Entitiy too large 』と表示されたという次第です。 にしても、(何かほかの理由原因が潜んでいるのかもしれませんが)ブラウザでエラーメッセージが変わるはやめてほしいです。

SSMS を 19.1 にアップデートしたら、 SQL Server に接続できなくなった

RDS で SQL Server を動かしてるのですが、 SQL Server を触る必要があるとき SSMS (SQL Server management Studio ) を使っています。

で、いままで、SSMS 18.9.2 を使っていたのですが、お盆明けから次の作業が始まるのを機に、アップデートすることにしました。

SSMS のサイトをみると、最新版として 19.1 がリリースされています。まあ、特に 18.x 系を使わなければならない特段の理由もないので、こちらにアップデートしました(というより、 18.x をアンインストールして、 19.1 を入れなおしました)。

問題ないだろうと、たかをくくって、今までと同じようにサーバーにつなげると、

とエラーがでて接続できません。あれれ?

このままでは仕事にならないので、慌てて対応をおこないました。せっかくなので、その際の作業をメモっておきます。

状況の再確認

幸い SSMS は 19.x 系と 18.x 系を同時に使うことができます。なので、18.x 系の最新版 18.12.1 をインストールして接続できるか確認してみます。 SSMS 18.12.1 をインストールして同じ SQL Server につないでみると、あら不思議、問題なく接続できました。

ということで、 SSMS 19.x に特有の現象のようです。

エラーの内容を確認

改めて、 SSMS 19.x で表示されたエラーを確認してみます。『証明書チェーン』とあるので、 SSL 関係っぽい感じです。『詳細の表示』を押すと、

のように詳しい情報が見れて、参考となるリンク先も表示してくれています。このリンク先を見てみると、こちらのページにリダイレクトされ、今回の問題に該当する下記のページにたどり着きました。

SQL Server に接続するとエラー メッセージが表示される - SQL Server | Microsoft Learn

今回のエラーが起きるのは2つの場合があるとのことなのですが、確か、 SQL Server の設定は、 SSL を常に使うようにしていたはずです。一応、確認してみます。

SQL Server 側の設定を確認

SQL Server 側では、クライアントからの接続時に SSL を使うかどうかは、 下記のように RDS のパラメータグループで設定します。

Microsoft SQL Server DB インスタンスでの SSL の使用 - Amazon Relational Database Service

で、今接続しようとしている SQL Server インスタンスのパラメータグループの rds.force.ssl の値を見ると、

と『1』 (true) になってますね。ということで、 SSL 接続が強制されるという設定になっていました。

対応方法

ということで、先ほどの記事でいうところのシナリオ1に該当しているため、今回のエラーになったようです。

念のため、 SSMS がインストールされている Windows 上の証明書を見てみると、『ユーザー証明書の管理』、『コンピュータの証明書の管理』共に、Amazon の証明書はインストールされていませんでした。

なるほどね。

ということで、証明書をインストールしてやれば、問題なく接続できると思われます。やってみます。

証明書のインストール

RDS の証明書は、こちらのページからダウンロードすることができます。今回は、対象となる SQL Server を動かしている東京リージョンの PKCS7 形式のファイルをダウンロードします。

次に、『ユーザー証明書の管理』を立ち上げ、『信頼されたルート証明機関』上で右クリックして、

『すべてのタスク』から『インポート』を選択します。

『次へ』で証明書フィルを指定する画面に進みます。

『参照』でファイルを指定するのですが、この際に、ファイルの種類を適切なものを選択してやります。

今回は『PKCS #7 証明書』を選びます。ファイルを選択したら、証明書をどこに配置するかを尋ねられます。

とりあえずテストということで、今回はデフォルト(信頼されたルート証明機関)のままとします。

確認画面が表示されるので、問題がなければ『完了』をおすと、

のように、インストールしてよいか確認されるので、問題なければ、『はい』を押してインストールしていきます。無事にインストールできると、

のように、Amazon の証明書が一覧に出てきます。

テスト

この状態で、もう一度 SSMS 19.1 を使って接続してみます。すると、今度は、

というエラーが表示されます。『プリンシパル名』?

『プリンシパル名』がピンときてないのですが、今の接続時のサーバー名の書き方は、RDS のインスタンスのエンドポイント名が長ったらしいので、 自分のドメインの DNS で CNAME を割り当てて、それを指定しています。でも、証明書だと、ドメイン名がきっちり一致する必要があるので、これのことじゃないかな?と思われます。

ということで、CNAME の名前ではなく、 RDS で割り当てられたエンドポイント名で接続するように直すと、おぉ、問題なく接続できました。

別の方法

さきほどの記事には、もう一つの解決方法も載っていて、 SSMS ならサーバーへ接続する際に『オプション』を押して、

『接続プロパティ』の『サーバー証明書を信頼する』にチェックをつければ、問題なく接続できます。この方法だと、証明書のインストールも不要だし、CNAMEを使った接続でも問題ありません。

原因

さて、SSMS 18.x では問題なかったのに、 SSMS 19.x ではエラーになったのはなんでなんだろう?と疑問が残ります。 SSMS 19.x のリリースノートを見ても、ぴったりのものが見当たりません。

ただ、 SSMS 19.0 のリリースノートを見ると、 クライアントドライバーが変更になったという記述があります。 また、こちらの記事に、 SQL Serveer 用のいくつかのドライバーが、ある時期から暗号化のデフォルト値が変更になったという説明がありました。

ということから推測すると、 SSMS 19.x からの暗号化の扱いが変わったととらえることができそうですね。とはいえ、もやもやが残るなー。

大事なことなんだから、もうちょっとわかりやすく『変わったよ』と書いといてくれればいいのになー。

結局

で、結局どうするかですが、 SSMS でつなぐときは、『サーバー証明書を信頼する』にチェックをつける形でいこうと思います。

Roundcube の立ち上げ : https での接続を可能にする (3/3)

前回の記事の続きです。今回は、 docker コンテナを起動して運用するところまでやってみます。

どこで稼働させるか?

いままで、 Rainloop は aws の EC2(スポットインスタンス)で運用していました。でも、無理に EC2 を使わずとも、 NAS 上で動かせればそれでいいのではないか?と思うようになりました。というのも、

  • メールクライアントなので、自分以外は誰も使わない
  • NAS 側に問題が起きても、 IMAP での運用なので、最悪は元のメールアカウントの Webメールを使えばよい
  • コンテナに問題が起きても、 docker で立ち上げなおしてメールアカウントを再設定すれば、(大きな遅延なく)復旧できる
  • aws で Elastic IP の有料化の話がでてきた

と考えた次第です。

ということで、いままでの検討を踏まえて、最終的に NAS の Container Station で起動することを目指します。

https での接続

本番環境として稼働させるとなると気になるのは、 Container Station で Roundcube を立ち上げると、https ではなく http での接続になっているの点です。

これ https 化するのにいい方法ないかな?と調べてみると、 docker のコンテナを立ち上げる際に、 https-portal というコンテナを使えば、めっちゃ簡単に https 接続を実現してくれるということがわかりました。

これらの記事でも触れてますが、 https-portal はリバースプロキシとして動作して、httpsでの接続を元のコンテナの公開ポート(httpプロトコルのポート)に振るという動作をしてくれます。

早速試してみます。こんな感じに docker-compose.yml を用意します。

version: '3'

services:
  https-portal:
    image: steveltn/https-portal:1
    ports:
      - '80:80'
      - '443:443'
    restart: always
    environment:
      DOMAINS: 'test.xxxx.yyyy.zzzz -> http://roundcubemail:80'
      # STAGE: 'production'
      # FORCE_RENEW: 'true'
  
  roundcubemail:
    image: myroundcube:latest
    container_name: myrc
#    restart: unless-stopped
    volumes:
      - ./www:/var/www/html
      - ./db/sqlite:/var/roundcube/db
#    ports:
#      - 9001:80
    environment:
      - ROUNDCUBEMAIL_DB_TYPE=sqlite
      - ROUNDCUBEMAIL_SKIN=elastic
      - ROUNDCUBEMAIL_DEFAULT_HOST=ssl://メールサーバー
      - ROUNDCUBEMAIL_DEFAULT_PORT=993
      - ROUNDCUBEMAIL_SMTP_SERVER=ssl://メールサーバー
      - ROUNDCUBEMAIL_SMTP_PORT=465

Roundcube 側は前回の記事で作ったイメージを指定しています(大きくは公式のイメージと異なりません)。 https-portal は上記の参考サイトに書かれているほぼそのままです。

test.xxxx.yyyy.zzzz に来たものを roundcubemail に振る設定ですね。

公開設定

これで、テストをしてもよかったのですが、 Container Station (NAS)がルータ(NVR510)の内側にいるので、ルータに穴をあける必要があります。

NVR510 内のサーバーを公開するにはこちらの記事などで触れていますので、詳しく書きませんが、ポイントは2か所です。

  • NAT ディスクプリタの編集:ルータの指定のポートに来たものを Container Station の https-portal のポートに転送します
  • IP フィルタの編集:内側から外側に戻るパケットを許可するルールにしてやります

特に、後者の IPフィルタについては、こちらの記事で触れたように、不正アクセス検知のパケット廃棄との兼ね合いがあるので、忘れないよう設定してやります。

接続テスト

ここまで準備できたら、さきほどの docker-compose.yml をつかって、 Container Station で起動します。 https-portal コンテナが証明書を取得するのにしばらく待ちます(コンソール画面に進行状況が表示されるのでしばし待ちます)。

上記のようにコンソールに done と表示されれば、準備完了です。完了したら、早速ブラウザから、 test.xxxx.yyyy.zzzz にアクセスしてみます。

https-portal が staging なので、証明書が信頼できないとエラーが出てきますが、無視して接続すると、ちゃんと https で接続できます。

https のポートを変更

https-portal の説明を読むと、 80 と 443 を開けておかないといけないっぽいのですが、

などからすると、 https のポート番号は変更できるようなので、これも試してみます。もちろん、テスト時は、ルータ側のポート番号も併せて変更しています。

https のポート番号を変更しても問題ないですね。

ただ、 https のポート番号を変更すると、 http で接続した際に自動的に https にリダイレクトされるのですが、リダイレクト先が 443 なので、この状態だと接続できないようになります。その点だけ注意する必要があります。

QNAP の Container Station で運用

ということで、最終的なコンテナステーションで起動するための docker-compose.yml を下記のようにします。

version: '3'

services:
  https-portal:
    image: steveltn/https-portal:1
    ports:
#      - '80:80'
#      - '443:443'
      - 'xxxx:80'
      - 'yyyy:443'
    restart: always
    volumes:
      - ./data/ssl_certs:/var/lib/https-portal
    environment:
      DOMAINS: 'xxxx.yyyy.zzzz -> http://roundcubemail:80'
      STAGE: 'production'
      # FORCE_RENEW: 'true'
  
  roundcubemail:
    image: myroundcube:latest
    container_name: myrc
#    restart: unless-stopped
    volumes:
      - ./www:/var/www/html
      - ./db/sqlite:/var/roundcube/db
#    ports:
#      - 9001:80
    environment:
      - ROUNDCUBEMAIL_DB_TYPE=sqlite
      - ROUNDCUBEMAIL_SKIN=elastic
      - ROUNDCUBEMAIL_DEFAULT_HOST=ssl://メールサーバー名
      - ROUNDCUBEMAIL_DEFAULT_PORT=993
      - ROUNDCUBEMAIL_SMTP_SERVER=ssl://メールサーバー
      - ROUNDCUBEMAIL_SMTP_PORT=465
      - ROUNDCUBEMAIL_UPLOAD_MAX_FILESIZE=30M

https-portal の http 用のポート番号も変更しています。というのも、ルータで 80 番に来たものを上記の xxxx にポート番号を変更しているためです(80 番は NAS の別のサービスで使いたいので空けておきたいのです)。このようにしても、外部からは 80 番ポートを呼ぶことができるので、問題ないはずです。

また、 https-portal で取得した証明書を NAS 側から確認できるように volumes を追加しています。あと、 Roundcube の添付ファイルのファイルサイズを指定しています。

これで、コンテナを起動します。問題なく起動できたら、 QNAP に SSH でログインして、下記コマンドを実行して ident_switch をインストールして、有効化します。

[ユーザ名@NAS名 application]$ docker exec -it myrc composer require boressoft/ident_switch --update-no-dev --no-interaction

これで、完了です!

ちなみに、スマホから公衆回線経由でアクセスしてもレスポンス的にも問題なかったです。