エックスサーバーでDrupal 11を構築して実際に詰まった6つの問題
自社サイトにブログを新設するにあたって、エックスサーバーにDrupal11を構築しました。
共用サーバー(エックスサーバー)に入れています。
しかし、インストールして終わりではありません。
実際にはいくつかの箇所でエラーや想定外の挙動に遭遇しました。
共用サーバーにDrupalは無理」と書かれた記事をいくつか見かけましたが、結論から言えば問題なく動きます。
ただし、スムーズには進みませんでした。
この記事は、実際に手を動かした記録です。
手順そのものより、どこで詰まって、なぜそうなったのかに紙幅を割きます。
同じ構成を考えている方の時間を節約できれば幸いです。
前提と最終構成
| 項目 | 内容 |
|---|---|
| サーバー | エックスサーバー(共用) |
| Drupal | 11.4.5 |
| PHP | Web 8.3.30 / CLI 8.4.20 |
| DB | MariaDB 10.11 |
| Composer | 2.10.2(自前で設置) |
| 公開URL | example.co.jp/blog/ |
| 実体の置き場 | ~/drupal-blog/(公開ディレクトリの外) |
既存の会社サイトは静的HTML+自社CMSで動いており、その一部として /blog を増設する形です。
サブドメインではなくサブディレクトリを選んだのは、既存ドメインの評価をそのまま活かしたかったからです。
Drupalを選んだ理由
WordPressではなくDrupalにした理由は3つあります。
- コンテンツ構造をコアで定義できる:コンテンツタイプとフィールドが標準機能です。プラグインで後付けする構造ではありません
- Viewsが標準搭載:一覧・絞り込み・並び替えをGUIで組める。コードを書かずにJSON出力にも切り替えられます
- 自社CMSの設計を検証したかった:自分で作っているCMSがDrupalの思想を参照しているので、本家の運用感を確かめたかった
逆に、更新の手間はWordPressより明確に重いです。
管理画面からワンクリック、とはいきません。ここは後述します。
この選定の経緯は、Drupalを選んだ理由|WordPressや他のCMSを使わなかった理由で詳しく書いています。
第1部:手順
詰まった箇所を含めて順に説明します。インストール手順だけを確認したい場合は、エックスサーバーにDrupal 11をインストールする手順|SSH+Composerで構築にまとめてあります。
4-1. SSHを通す
Drupalの導入にはComposerが要ります。
FTPだけでは完結しません。まずSSHを使える状態にします。
エックスサーバーのSSHは公開鍵認証のみです。
パスワードでは入れません。手元で鍵を作り、公開鍵だけをサーバーに登録します。
mkdir "$env:USERPROFILE\.ssh"ssh-keygen -t ed25519 -C "myblog" -f "$env:USERPROFILE\.ssh\xsdrupal"Get-Content "$env:USERPROFILE\.ssh\xsdrupal.pub" | Set-Clipboard
ssh-keygen は、保存先フォルダを自動では作りません。
.ssh が無い状態で実行すると No such file or directory で落ちます。先に mkdir してください。
サーバーパネル →「SSH設定」→「+ 公開鍵を登録」。
ここで「登録方式:手動」を選びます。既定は「自動生成」(サーバー側で鍵を作って秘密鍵をダウンロードさせる方式)になっていますが、秘密鍵が通信経路を通るので、手元で作った方が安全です。
ssh -i "$env:USERPROFILE\.ssh\xsdrupal" -p 10022 サーバーID@サーバーID.xsrv.jp
ポートは 10022 です。
22番ではありません。
つまずき①:登録直後は必ず弾かれる
公開鍵を登録してすぐ接続すると Permission denied (publickey) になります。
私は鍵の貼り付けミスを疑って公開鍵を何度も見直しましたが、原因は設定の反映待ちでした。
5分ほど置いて再実行したら、あっさり通りました。
切り分けには -v を付けるのが有効です。
Server accepts key の行が出ていれば鍵は受理されているので、残るはパスフレーズだけ、と判断できます。
4-2. PHPとComposerを用意する
エックスサーバーのCLI既定PHPは古いことがあります。
私の環境では 8.0.30 でした。Drupal11は、PHP 8.3以上が必要です。
php -vls -d /opt/php-* 2>/dev/null
バージョン別のバイナリが /opt/php-8.4.20/bin/php のような形で用意されているので、こちらを使います。
Composerも既定は 2.5.8 で、Drupal 11 の要求(2.7.0以上)に届きません。
共用サーバーの標準版は書き換えられないので、自分専用のものをホームディレクトリに置きます。
mkdir -p ~/bin && cd ~/opt/php-8.4.20/bin/php -r "copy('https://getcomposer.org/installer','composer-setup.php');"/opt/php-8.4.20/bin/php composer-setup.php --install-dir=$HOME/bin --filename=composer/opt/php-8.4.20/bin/php -r "unlink('composer-setup.php');"
毎回フルパスを打つのは現実的でないので、パスを通します。
export PATH="$HOME/bin:/opt/php-8.4.20/bin:$PATH"
これを ~/.bash_profile に追記し、source ~/.bash_profile で反映させます。php -v が 8.4.20、composer -V が 2.10.2 になれば成功です。
4-3. Drupalを取得して配置する
cd ~composer create-project drupal/recommended-project:^11 drupal-blog
3$301C10分、約165MBです。
ここで配置を考えます。Drupalは web/ が公開ディレクトリで、その一つ上に vendor/(外部ライブラリ約1万ファイル)が置かれます。vendor を公開ディレクトリの中に入れたくないので、プロジェクト本体をホーム直下に置き、web/ だけをシンボリックリンクで公開します。
ln -s ~/drupal-blog/web ~/example.co.jp/public_html/blog
結果として、こういう構造になります。
| パス | 公開 | 中身 |
|---|---|---|
| ~/drupal-blog/vendor/ | されない | 外部ライブラリ |
| ~/drupal-blog/web/ | される | Drupal本体 |
| public_html/blog | される | 上記へのシンボリックリンク |
エックスサーバーではシンボリックリンクが問題なく機能しました。FollowSymLinks が無効で403になるケースを警戒していましたが、杞憂でした。
Drupal同梱の .htaccess(約8.7KB)もそのまま動きます。php_value や Header always set が多数書かれているので500エラーを覚悟していましたが、こちらも問題なし。
この2点は、事前の心配が完全に外れました。
4-4. 既存サイトとの衝突を確認する
/blog を作る前に、既存の .htaccess を必ず読んでください。ルートに RewriteRule . /index.html [L] のようなキャッチオール指定があると、Drupalのルーティングが全部潰されます。
私の場合、ルートの .htaccess にあったのは以下の4つだけで、いずれも /blog に干渉しませんでした。
- HTTPS+非www統一(301)
/index.htmlから/への正規化sitemap.xmlをsitemap.phpへ(ルート直下限定)- 特定3ファイルのみSSI有効化(FilesMatch で限定)
なお、/blog 配下にDrupalの .htaccess が置かれると、そこで RewriteEngine on が再宣言され、親のルールは継承されません。HTTPS強制が /blog 以下で効かなくなるので、Drupal側で別途対応が要ります。
つまずき②:/blog に先客がいた
自社CMSで作った空のブログ枠が既に置かれていました。
sitemap.xml と category/ があり、Googleにインデックスされている可能性がありました。
記事数を確認したところ0件だったので退避しましたが、FTPで消さずに mv で公開ディレクトリの外へ移動させました。削除は取り返しがつきませんが、移動ならいつでも戻せます。
稼働中のドメインを触るときの基本動作だと思っています。
4-5. データベースを作る
サーバーパネルから MySQL(MariaDB)を作成します。
- DB名に記号は使えません。
drupal-blogもdrupal_blogも弾かれ、drupalblogで通りました - 文字コードは utf8mb4 を選択
- DBユーザーは新規に作る。既存ユーザーを流用すると、Drupalが侵害された際に他のDBまで到達されます。
settings.phpにはDB認証情報が平文で書かれるので、1DBにつき1ユーザーが原則です - ホスト名は localhost
DBを作った後、ユーザーにアクセス権を付与する操作を忘れないでください。
エックスサーバーはDB作成とユーザー作成が別々で、紐付けを忘れるとインストーラーで接続エラーになります。
4-6. インストーラーを走らせる
ブラウザで https://example.co.jp/blog/ を開くと、自動的にインストーラーへ飛びます。
言語(日本語)→ プロファイル(標準)→ 要件チェック → DB接続 → インストール → サイト設定、という流れです。
管理者ユーザー名に admin は使わないでください。
Drupalのログインパスは /user/login で固定なので、ユーザー名が推測できると総当たりの的になります。
4-7. 公開前の後始末
インストール直後にやることが3つあります。
- 検証用に置いたファイルの削除
settings.phpを読み取り専用に(chmod 444、ディレクトリは555)- 信頼するホストの設定
3番目は settings.php の末尾に以下を追記します。
$settings['trusted_host_patterns'] = [ '^example\.co\.jp$',];
これを省くと、HTTPホストヘッダを偽装され、パスワードリセットのメールに攻撃者のドメインへのリンクが生成される、といった手口が成立します。ステータスレポートでも警告が出るので、必ず設定してください。
第2部:詰まった箇所
ここからが本題です。手順どおりに進めても、6箇所で止まりました。
つまずき③:設定は正しいのに「要件が満たされていません」
インストーラーの要件チェックで、この1点だけ赤くなりました。
Unicode ライブラリー:エラーMultibyte string input conversion in PHP is active and must be disabled.
「mbstring.encoding_translation を無効にせよ」という指示です。ところが .user.ini を見ると、すでに Off になっている。ここで15分ほど溶かしました。
原因1:.user.ini はシンボリックリンク先には効かない
まず気づいたのは、そもそもこの .user.ini が読まれていないことでした。
.user.ini は、実ファイルシステム上のパスを基準に、そのディレクトリと上位を辿って適用されます。Drupalの実体は ~/drupal-blog/web/ にあり、public_html/ の配下ではありません。
だから公開ディレクトリ側の設定は届いていなかったのです。シンボリックリンク構成を選んだ副作用でした。
なお .user.ini は、PHPが300秒キャッシュします。
書き換えた直後にブラウザを更新しても反映されません。5分待つ以外に手はありません。何度もリロードして「効いていない」と焦らないでください。
原因2:Off では通らない。0 にする必要がある
5分待って再試行。まだ同じエラー。
実測してみます。
var_dump(ini_get("mbstring.encoding_translation"));// string(0) ""
空文字列でした。設定としては無効です。
ではなぜDrupalはエラーを出すのか。Drupalのチェックはこうなっています。
if (ini_get('mbstring.encoding_translation') != 0) { return static::STATUS_ERROR;}
PHP 8では空文字と0の比較が真になります。
PHP 8.0で文字列と数値の比較ルールが変更され、非数値の文字列と数値を比べるとき、数値側が文字列に変換されるようになりました。結果として「有効になっている」と誤判定されます。
Off と書いても ini_get() は空文字を返すので、判定は通りません。
明示的に 0 を書く必要がありました。
mbstring.encoding_translation = 0
これで ini_get() が "0" を返すようになり、要件チェックを突破しました。
エックスサーバーのように mbstring 設定を明示的に持つ日本語向け環境で起きやすい問題だと思います。
つまずき④:コンテンツタイプが存在しない
インストールが終わり、コンテンツタイプを見に行くと「コンテンツタイプがありません。」
「標準」プロファイルでインストールすれば「記事」と「ベーシックページ」が入っているはずです。drush status を見ても Install profile: standard でした。それでも実際は0件。
原因の追究より作り直す方が早いと判断しました。コンテンツタイプは定義にすぎないので、手で作れば標準と同じものになります。ついでに body フィールドも無かったので、フィールドストレージから作りました。
つまずき⑤:フィールドを作ったのに投稿画面に出ない
カテゴリ・スラッグ・タグ・画像の各フィールドをコマンドで作成し、定義も確認できました。ところが投稿画面にはタイトルしか出ません。
Drupalはフィールドを3層で管理しています。
| 層 | 役割 |
|---|---|
| Field Storage | データの入れ物。型とDB構造 |
| Field Config | どのコンテンツタイプに、どのラベルで、必須か |
| Display | どの画面に、どの順で、どの入力部品で出すか |
管理画面から作れば3つとも同時に登録されますが、コマンドで作ると最初の2つしか作られません。
3層目が空だから画面に出ない、というだけの話でした。
分離の恩恵もあります。同じフィールドに対して用途別の表示を複数持てるので、記事ページでは全文、一覧では概要だけ、と切り替えられます。抽象度と引き換えの複雑さです。
つまずき⑥:カテゴリのURLだけ404
URL設計は /blog/カテゴリ/記事スラッグ にしました。
カテゴリと記事の両方にスラッグ用フィールドを持たせ、pathautoで組み立てます。
記事は一発で /blog/tech/test-article が生成されました。
ところが /blog/tech は404。一括生成を実行しても「生成対象なし」と返ってきます。
トークンは正常に解決されているのに、です。
エイリアス生成そのものを叩いてみると、ちゃんと値が返る。ただし1点だけ違和感がありました。
["source"] => "/taxonomy/term/3"["alias"] => "/tech"["langcode"] => "ja"
langcode が ja になっていました。
ボキャブラリー作成時に「ボキャブラリーの言語:日本語」と設定したのが効いています。
多言語モジュールが無効な環境では、エイリアスの言語とルーティングの解決が噛み合わず、結果として404になります。und(言語未指定)で作り直したら、即座に表示されました。
教訓として、pathautoは「エンティティ保存時にエイリアスを作る」仕組みです。
パターンを設定する前に作ったコンテンツには、エイリアスが付きません。
私はカテゴリを先に4件登録してからパターンを作ったので、この順序でも引っかかりました。
成功したこと
失敗ばかり書きましたが、事前の心配が外れて助かった点もあります。
- シンボリックリンクが素直に動いた。
403だった場合は構成を変える予定でしたが、不要でした - Drupal同梱の .htaccess がそのまま通った。
php_value を含む記述はエックスサーバーで500エラーになりますが、実際には問題なく動作しました - ステータスレポートが警告1件で収まった。
残った1件も「Drupal 12でHTML5バリデーションの既定値が変わる」という予告で、実害はありません - メモリが潤沢だった。
CLIが2000M、Web側が1G。Composerでメモリ不足に陥る心配はありませんでした。
これから導入する方へ
SSHは通しておいた方がいいです。
Drupalは公式にtarball配布を続けており、FTPだけでもインストールは可能です。
ただし運用が厳しくなります。
- 月次のセキュリティ更新で数千ファイルをFTP上書きすることになる。転送が途中で失敗すると中途半端な状態でサイトが落ちます
- contribモジュールが入らないことがある。
自前のComposer依存を宣言しているモジュールは、tarball構成と互換性がありません - 後からComposer管理へ移行するのが非常に面倒
初回10分の作業で、以後の運用が楽になります。ここは通しておくべきです。
SSHの設定手順は、XServerにSSHで接続する方法|Windows・Macの設定手順を初心者向けに解説で初心者向けに解説しています。
記事を書く前に決めること
URLは公開後に変えられない資産です。以下は最初に確定させてください。
- カテゴリをURLに含めるか:もし含めるなら、カテゴリの変更がURLの変更になります
- 日本語タイトルをどう扱うか:自動変換に任せると日本語URLが生まれます。共有時にパーセントエンコードされて長大になるので、私は英数字スラッグを手入力する運用にしました
- 細分化の余地をどこに逃がすか:カテゴリを増やすとURLが揺れます。
私はカテゴリを4つで固定し、細かい分類はタグに持たせました。
タグはURLに影響しないので、いくら増やしても安全です
この3つ目が、今回いちばん効いている設計判断だと思っています。
更新の重さは受け入れる必要がある
Drupalは2年周期でメジャーバージョンが来ます。
WordPressのように「5年前のサイトがそのまま動く」世界ではありません。
その代わり、コンテンツ構造を最初から設計できます。
あとから拡張するのではなく、最初から自分の形で作れる。
この差をどう評価するかが、選定の分かれ目だと思います。
この記事は実際の構築ログをもとに書いています。
環境やバージョンによって挙動は変わるので、手順は自分の環境で確認しながら進めてください。
まとめ
エックスサーバーでもDrupal 11は動かせます。
ただし、実際に構築するとPHPやComposer、Drupalの設定など、 いくつかの箇所で確認が必要になります。
今回紹介した6つも、単純に「Drupalが悪い」という話ではありません。 サーバー、PHP、Composer、Drupalの設定がそれぞれ関係しています。
Drupalを使いたいものの、 「どのサーバーで構築すればいいのか分からない」 「既存サイトから移行できるのか分からない」 「構築後の運用まで考えると自社で対応するのが難しい」 という場合は、ご相談ください。
必要な構成を確認したうえで、 Drupalが適しているのか、別のCMSが適しているのかも含めてご提案します。