Nextcloudで日本語を含むPDFを開くと、ページが真っ白になることがありました。原因を探すのにも時間がかかり、別のPDFビューアーを使うしかないのかと悩んだ時期があります。
この問題を避けるため、私は以前からCMap用のファイルを、別の小さなnginxコンテナで配信しています。PHP2Shellへの対応をきっかけにNextcloudのコンテナを更新したあとも、その仕組みで日本語PDFを正常に表示できることを確認しました。そこで改めて気づいたのは、Dockerでアプリケーションを隔離していたからこそ、アプリケーション本体を変更せずに特定のリクエストだけ別のコンテナへ逃がせた、ということでした。
NextCloudをホストに直接入れていたころ
以前はNextcloudをサーバーのホストに直接インストールしていました。PHPやApacheなど、アプリケーションが必要とする環境をホストにそろえ、更新のたびに依存関係や設定を気にするのが大変でした。
Dockerへ移したとき、アプリケーションと実行環境をコンテナの中に閉じ込められることに、かなり解放された気持ちになりました。ホストに依存関係を積み上げなくてよい。これで保守もずっと楽になると思っていたのです。
PHP2Shell対応。Dockerでも結局苦労するんだ
ところが2026年10月、PHPの重大な脆弱性への対応としてNextcloudを更新することになりました。コンテナを使っていても、アプリケーションの状態を保ちながら更新作業を進める必要があります。どうやら、コンテナイメージをプルして既存のコンテナを再起動するだけでは、新しいイメージに切り替わらないようです。
PHP2Shellとは
PHP2Shellは、PHP本体の2件の脆弱性(CVE-2026-109618、CVE-2026-109619)を組み合わせた攻撃の呼び名です。2026年10月21日にPHP公式が修正版を公開し、翌22日にIPAが注意喚起を公表しました。メモリ不足時のエラー処理とリクエスト処理に関係する問題で、悪用されると遠隔から任意コードを実行されるおそれがあります。Nextcloud固有の脆弱性ではありません。
PHP公式が示す修正版は、PHP 8.2.35、8.3.36、8.4.27、8.5.12です。PHP 8.1以前は通常サポートが終了しているため、個別のバックポートの有無も含め、利用している提供元の情報を確認してください。Dockerでは、ホストにインストールされているPHPとコンテナ内のPHPは別の実行環境です。ホスト側だけでなく、コンテナ内で動作するPHPも確認しておくことが大切です。詳細はPHP公式の告知とIPAの注意喚起にあります。
Dockerイメージの更新とNextcloudアプリケーションの更新は、別々に確認する作業です。たとえば nextcloud:32-apache というタグだけでは、実際に動いているPHPが脆弱性修正版かどうかは分かりません。タグが指すイメージの内容は後から変わることがあり、新しいイメージを取得しても稼働中のコンテナは再作成するまで切り替わりません。起動中のコンテナで使われるPHPのバージョンを確かめる必要があります。Nextcloud側の関連Issueにも、イメージのタグだけで判断できない状況が報告されています。
DockerでNextcloudを運用している場合は、まずコンテナ内のPHPバージョンを確認できます。
docker exec <container_name> php -v
<container_name> は実際のNextcloudコンテナ名に置き換えます。このコマンドは稼働中のPHPを調べるだけで、更新操作ではありません。表示されたバージョン番号を系列ごとの修正版と比べるほか、OSディストリビューションが修正をバックポートしている場合は、そのベンダー情報も確認してください。必要な修正版と現在のサポート状況は、PHP公式資料で確認するのが確実です。
私はNextcloudを nextcloud:32-apache に更新したあと、2026年10月24日にコンテナ内で docker exec <container_name> php -v を実行し、PHP 8.3.36 (cli) と表示されることを確認しました。これはPHP 8.3系の修正版と一致します。確認したのはCLI版PHPであり、Apache経由のPHPを別途検証したわけではありません。また、更新前のPHPバージョンは記録していないため不明です。イメージタグの更新と、現在動作しているPHPランタイムの確認は別の作業だと実感しました。
長く悩んでいた日本語PDFの白紙問題
セキュリティ対応とは別に、NextcloudのPDFビューアーで日本語PDFが白紙になる問題も長く抱えていました。すべてのPDFで起きるわけではなく、表示できるものと、ページ全体が白くなるものがあります。原因や解決策を探して関連Issueにたどり着くのも簡単ではありませんでした。

PDF.jsは、日本語などの文字を表示するために、CMap(文字コードとグリフの対応表)というファイルを読み込みます。
ところが、Nextcloudの一部のApache構成では、CMapファイルが存在していてもHTTP 404になる問題が報告されています。
原因として指摘されているのが、Nextcloudの .htaccess にあるURLの書き換えルールです。
RewriteCond %{REQUEST_FILENAME} !\.(css|js|mjs|svg|gif|ico|jpg|jpeg|png|webp|html|otf|ttf|woff2?|map|webm|mp4|mp3|ogg|wav|flac|wasm|tflite)$
RewriteRule . index.php [PT,E=PATH_INFO:$1]
このルールの除外拡張子一覧には .bcmap が含まれていません。そのため、該当する構成ではCMapファイルへの要求が通常のファイル配信ではなく、Nextcloudの index.php に渡され、ファイルが存在していても404になる場合があります。詳しくはfiles_pdfviewerのIssue #873やNextcloud serverのIssue #63512で報告されています。
驚きのしくみ:CMapの要求だけをTraefikで振り分ける
私はこの問題を避けるため、CMap用のnginxコンテナを以前から運用しています。TraefikにCMapのURLを条件として登録し、そのパスへの要求だけをnginxへ振り分けます。nginxは共有されたCMapディレクトリから、alias でURLの残りの部分に対応するファイルを返します。それ以外のNextcloudへの通信は、従来どおりNextcloudコンテナへ向かいます。
そのため、Nextcloud本体の .htaccess やアプリケーションファイルを直接変更する必要がありません。PDFビューアーの更新時に本体側の変更が置き換わる心配を減らしつつ、役割を小さなコンテナに分けられる点が気に入っています。
リクエストの流れを図にすると、次のようになります。
以下は実運用の構成をもとに、ホスト名とホスト側パスを汎用化した例です。設定を共有しやすくするため一部を簡略化しており、このままの構成で動作を再検証したものではありません。reverseproxy はTraefikと共有する外部ネットワークを想定しています。
services:
cmap_proxy:
image: nginx:alpine
restart: unless-stopped
volumes:
- /srv/nextcloud/apps/files_pdfviewer/js/pdfjs/web/cmaps:/usr/share/nginx/html/cmaps:ro
- ./nginx.conf:/etc/nginx/nginx.conf:ro
networks:
- reverseproxy
labels:
traefik.enable: "true"
traefik.docker.network: reverseproxy
traefik.http.routers.cmaps.rule: "Host(`cloud.example.com`) && PathPrefix(`/apps/files_pdfviewer/js/pdfjs/web/cmaps/`)"
traefik.http.routers.cmaps.entrypoints: websecure
traefik.http.routers.cmaps.tls: "true"
traefik.http.services.cmaps.loadbalancer.server.port: "80"
networks:
reverseproxy:
external: true
nginx側では、CMapのURLプレフィックスをコンテナ内のディレクトリに対応付けます。
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
server {
listen 80;
server_name _;
location /apps/files_pdfviewer/js/pdfjs/web/cmaps/ {
alias /usr/share/nginx/html/cmaps/;
}
location / {
return 404;
}
}
}
Traefikのルールは cloud.example.com のCMap用URLプレフィックスだけに一致し、nginxは alias によってパスの後半をファイル名として扱います。既存のNextcloudルーターと共存させる場合、Traefikは通常ルール文字列の長さを優先度に使うため、このHostとPathPrefixを組み合わせたルールはHostだけのルールより優先されます。ただし、実環境で優先度を明示設定している場合は、そちらとの関係を確認してください。この設定は拡張子を .bcmap に限定していません。CMapディレクトリ内にあるファイルは拡張子にかかわらず配信され得るため、同ディレクトリにはCMap用ファイルだけを置く前提です。一方、このルールはCMap用URLプレフィックス以外の要求には一致せず、別の場所にある .json、.ftl、.pfb の要求を解決するものではありません。今回の回避策が扱うのはPDF.jsのCMapリソースです。PDF.js側でデータファイルをコントローラー経由で配信する案も議論されているので、files_pdfviewerのPull Request #1547も参照してください(2026年10月24日時点でOpen)。
更新後も動いていることを確認
今回、Nextcloudを nextcloud:32-apache に更新したあと、次のCMapファイルをHTTPSでGETし、HTTP 200が返ることを確認しました。
https://cloud.example.com/apps/files_pdfviewer/js/pdfjs/web/cmaps/Adobe-Japan1-UCS2.bcmap
また、利用者本人が日本語PDFを開いて正常に表示されることを確認しています。ただし、HTTP 200だけでPDF全体の描画や、応答したコンテナがnginxであることまで証明できるわけではありません。ここで確認したのは指定したCMapへの応答と、本人の環境でのPDF表示です。
結局、Dockerにしておいてよかった
Dockerに移っても、更新や脆弱性への対応に気を配る必要は残りました。それでも、Nextcloud本体を直接いじらず、Traefikで特定のリクエストを別の小さなコンテナへ振り分けられたのは、コンテナを分けていたからこそでした。
Dockerにすれば運用の苦労が消えるわけではありません。それでも、役割を分けて変更の影響範囲を小さくできる。長く困っていた日本語PDFの問題を振り返ると、結局Dockerにしておいてよかったと思います。
参考資料
- IPA:PHPの脆弱性対策について(CVE-2026-109618、CVE-2026-109619:PHP2shell)
- PHP公式:Security advisory / release information, 21 Oct 2026
- Nextcloud server Issue #65754: PHP CVEs
- Nextcloud files_pdfviewer Issue #873: Fail to render / load Japanese fonts
- Nextcloud server Issue #63512: PDF viewer rewrite rules
- Nextcloud files_pdfviewer Pull Request #1547