Ubuntu 24.04でLAMP環境を構築する方法
Ubuntu 24.04でApache、MariaDB、PHP 8.3とPHP-FPMを設定します。unix_socket認証、名前ベースのvhost、Certbotによる無料HTTPSまで、連携時のエラーと対処法も解説します。
構築するもの
LAMPスタックは、Ubuntu 24.04サーバー上で動作する4つのコンポーネントで構成されます。基盤となるLinux、HTTPリクエストを処理するApache、データを保持するMariaDB、そしてコードを実行するPHP 8.3です。最終的には、名前ベースのバーチャルホストが実際のアプリケーションディレクトリを配信し、最小権限の専用ユーザーを持つデータベースが作成され、PHP-FPM経由でPHPがApacheに接続され、さらにLet's Encryptの無料証明書が適用された状態になります。
インストール自体は4つの apt コマンドで行われます。このガイドの大部分は各コンポーネント間の連携設定に割かれています。新規スタックで発生しやすいミスとして、ページが真っ白になる、ソースコードがブラウザにダウンロードファイルとして表示される、あるいはインストールしたばかりのデータベースにアクセスできないといった問題があります。これらにはそれぞれ特有の兆候があり、以下に表示されるエラーメッセージとともに解説します。
前提条件と注意点
Ubuntu 24.04のKVM VPSを用意し、sudo権限を持つユーザーまたはrootでログインできる状態を想定します。また、パブリックIPv4アドレスが必要です。最小構成のスタックは1 GBのRAMで動作しますが、データベースを利用するアプリケーションを運用する場合は2 GBを推奨します。MariaDBのデフォルトバッファと複数のPHP-FPMワーカーが、最初の1 GBをすぐに消費するためです。
最後に実行するCertbotを正常に動作させるため、以下の2点を事前に準備してください。まず、VPSのパブリックIPを指すAレコードを持つドメイン名が必要です。Let's EncryptはHTTP経由でドメイン名を検証するため、IPアドレスのみでは証明書を取得できません。次に、インターネットから80番ポートと443番ポートへアクセス可能である必要があります。多くのプロバイダーでは、コントロールパネル上のネットワークファイアウォールと、サーバー内の ufw の両方でポートを開放する必要があります。DNSの変更が反映されるまで最大1時間かかる場合があるため、最初にAレコードを設定しておけば、必要なタイミングで利用可能になります。
ステップ 1 - Apacheのインストールとデフォルトページの確認
sudo apt update
sudo apt install -y apache2aptを実行すると、サービスが開始され、有効化されます。以下のコマンドで確認してください。
systemctl status apache2active (running)と表示されている行があることを確認してください。次に、ブラウザでhttp://YOUR_SERVER_IP/を開きます。大きな「It works!」というバナーが表示されたApache2 Ubuntu Default Pageが表示されれば成功です。これはApacheが正常に動作している証拠であり、エラーではありません。このページは/var/www/html/index.htmlに配置されており、デフォルトのバーチャルホストである000-default.confによって配信されています。これらは後ほど無効化しますが、現時点では表示されることが正常な状態です。
ページが読み込まれないにもかかわらず、systemctlでプロセスが実行中であると表示される場合は、ファイアウォールが通信を遮断しています。次のステップで対処します。
ステップ 2 - HTTPおよびHTTPS用のファイアウォールを開放する
apache2パッケージは、3つのufwアプリケーションプロファイルを登録します。以下のコマンドで一覧を表示してください。
sudo ufw app listApache、Apache Full、Apache Secureが表示されます。Apacheはポート80のみ、Apache Secureはポート443のみ、Apache Fullはその両方です。最後にTLSを追加するため、Apache Fullを選択してください。
sudo ufw allow OpenSSH
sudo ufw allow "Apache Full"
sudo ufw enableufw enableを実行する前に、OpenSSHを許可してください。ufwはデフォルトですべての着信トラフィックを拒否します。SSHルールを設定せずに有効化すると、有効になった瞬間に接続が切断されます。現在のセッションは維持されますが、再接続は不可能になります。sudo ufw statusで確認してください。OpenSSH、Apache Full、およびそれらのv6対応版がすべてALLOWと表示されている必要があります。
ステップ 3 - MariaDBのインストールとセキュリティ設定
sudo apt install -y mariadb-server
systemctl status mariadbUbuntu 24.04は長期サポートリリースであるMariaDB 10.11を提供しているため、外部リポジトリは不要です。サービスが実行されている状態で、以下のコマンドでセキュリティを強化します。
sudo mysql_secure_installationプロンプトはEnterキーを連打せず、内容を確認してください。current root passwordを求められたら、まだ設定されていないためEnterキーを押します。"Switch to unix_socket authentication?"と聞かれた場合、このパッケージでは既に有効になっているため、どちらを選んでも結果は変わりません。nを押してください。次の段落で説明する理由により、"Change the root password?"にはnと答えます。残りの質問にはすべてYと答えてください。これにより、匿名ユーザーの削除、リモートからのrootログイン禁止、テスト用データベースの削除、権限テーブルの再読み込みが行われます。
ここが最も混乱しやすい部分です。UbuntuのMariaDBでは、rootデータベースアカウントはパスワードではなくunix_socket認証を使用します。つまり、データベースは既に認証済みのオペレーティングシステムユーザーを信頼します。そのため、rootシェルからは以下のコマンドで動作します。
sudo mysql...すると、パスワードを求められることなくMariaDB [(none)]>プロンプトが表示されます。権限のないユーザーで同じコマンドを実行すると拒否されますが、これがこの仕組みの目的です。データベースのrootアクセスはサーバー上のsudoと結びついており、盗難、フィッシング、総当たり攻撃の対象となるパスワードが存在しません。これはパスワードよりも安全であるため、設定を変更しないでください。ここから導かれるルールは、アプリケーションをrootアカウントに接続させないことです。アプリケーションごとに専用のユーザーを作成してください(ステップ 7)。TCP経由でユーザー名とパスワードを使用して接続するアプリケーションはソケット認証を使用できず、各アプリケーションを自身のデータベースのみに制限する必要があるためです。
ステップ 4 - PHP 8.3 と PHP-FPM のインストール
Ubuntu 24.04 のデフォルトの PHP は 8.3 です。FPM プロセスマネージャと、一般的なアプリケーションが必要とする拡張機能をインストールします。
sudo apt install -y php8.3-fpm php8.3-mysql php8.3-cli \
php8.3-curl php8.3-xml php8.3-mbstring php8.3-zipそのリストに含まれていない libapache2-mod-php に注意してください。この古いパッケージは、すべての Apache プロセス内に PHP インタプリタを埋め込みます。シンプルですが、スクリプトを処理する場合でも静的画像を表示する場合でも、すべてのワーカーが PHP のコピーを保持し、両者のライフサイクルが共有されます。また、これは Apache の最も効率の悪い MPM である prefork でしか動作しません。一方、PHP-FPM は PHP を独自のプロセスプールとして実行し、Apache はソケット経由でこれと通信します。これにより、Apache は静的ファイルに対してスレッドベースの event MPM を使用し、PHP リクエストのみを FPM に渡すことができます。プールは Web サーバーとは独立して調整可能であり、将来的に nginx をフロントに配置する場合でも、全く同じ FPM 設定をそのまま利用できます。これが現在デフォルトとなっているのには正当な理由があります。
Apache は proxy_fcgi モジュールを通じて FPM に接続します。このモジュールを有効にし、FPM パッケージが配置した設定を有効にしてから、再起動します。
sudo a2enmod proxy_fcgi setenvif
sudo a2enconf php8.3-fpm
sudo systemctl restart apache2a2enconf php8.3-fpm は /etc/apache2/conf-available/php8.3-fpm.conf をアクティブにします。これには、PHP ファイルを FPM ソケットにルーティングするルールが含まれています。その核心部分は、すべての .php ファイルに一致し、それを /run/php/php8.3-fpm.sock のソケットに転送する設定です。
<FilesMatch ".+\.ph(ar|p|tml)$">
SetHandler "proxy:unix:/run/php/php8.3-fpm.sock|fcgi://localhost"
</FilesMatch>このファイルを編集する必要はありません。最初から正しく設定されています。しかし、ソケットのパスを知っておくことは、「PHP が実行されずにダウンロードされる」や「Primary script unknown」といったエラーが発生した際の診断に役立ちます。これらはどちらも、Apache と FPM 間でこのソケットや背後のファイルに関する認識が一致していないことが原因です。
Step 5 - アプリケーション用の名前ベースのバーチャルホスト
名前ベースのバーチャルホストを使用すると、1つのIPアドレスで複数のサイトを運用できます。Apacheはリクエスト内の Host: ヘッダーに基づいてサイトを選択します。デフォルトの /var/www/html から離れた場所に、アプリケーション用のディレクトリを作成してください。
sudo mkdir -p /var/www/testapp
sudo chown -R www-data:www-data /var/www/testapp
sudo chmod -R 755 /var/www/testapp所有権の設定は重要です。UbuntuではApacheとPHP-FPMの両方が www-data ユーザーとして実行されます。そのため、Webサーバーが読み取る必要のあるファイルや、アップロードフォルダのようにアプリケーションが書き込む必要のあるディレクトリは、 www-data が所有している必要があります。ログインユーザーとしてファイルを編集する場合は、ファイルを自身で所有し、自分のユーザーを www-data グループに追加するのが一般的なパターンです。単純なデプロイであれば、 www-data:www-data に設定するのが最も無難です。
/etc/apache2/sites-available/testapp.conf にバーチャルホストを作成します。
<VirtualHost *:80>
ServerName app.example.com
DocumentRoot /var/www/testapp
<Directory /var/www/testapp>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/testapp-error.log
CustomLog ${APACHE_LOG_DIR}/testapp-access.log combined
</VirtualHost>ServerName を実際のドメインに設定してください。 Options -Indexes は、インデックスファイルが存在しない場合にApacheがディレクトリ一覧を表示するのを防ぎます。これがないと、訪問者がソースツリーを閲覧できてしまいます。 AllowOverride All は .htaccess ファイルを有効にします。これはほとんどのPHPアプリケーションがきれいなURLのために必要としますが、不要であれば None に設定することでわずかな速度向上が見込めます。このサイトを有効にし、デフォルトを無効化し、設定を確認してリロードします。
sudo a2ensite testapp
sudo a2dissite 000-default
sudo apache2ctl configtest
sudo systemctl reload apache2apache2ctl configtest は Syntax OK と表示されるはずです。 a2dissite 000-default の行は忘れられがちです。これが、後でデフォルトページが消えないように見える原因であり、トラブルシューティングのセクションで解説しています。
ステップ 6 - PHPの動作確認とテストファイルの削除
アプリケーションのルートディレクトリに1行のPHPファイルを作成します。
echo "<?php phpinfo();" | sudo tee /var/www/testapp/info.phphttp://app.example.com/info.php にアクセスします。正しく設定されていれば、紫とグレーの長い PHP Version 8.3.x テーブルが表示され、読み込まれているモジュールの一覧が確認できます。その中の Server API 行が FPM/FastCGI となっていることを確認してください。この最後の行は、リクエストが mod_php ではなく PHP-FPM を経由していることを示しています。
確認後、直ちにファイルを削除します。
sudo rm /var/www/testapp/info.phpphpinfo() には、PHPの正確なバージョン、読み込まれているすべての拡張機能、ファイルパス、環境変数の詳細が含まれています。これは、既知の脆弱性を持つバージョンを探している攻撃者にとって非常に有益な情報です。これはテスト用であり、機能ではありません。ページを確認したらすぐに削除してください。ブラウザでテーブルが表示されず、info.php の ダウンロード が求められる場合は、PHPとApacheの連携が正しく行われていません。他の作業を行う前に、失敗時のセクションを確認してください。
ステップ 7 - アプリケーション用データベースと最小権限ユーザーの作成
ソケット認証された root としてデータベースを開きます。
sudo mysql次に、データベースを1つ作成し、そのデータベースのみを操作対象とするユーザーを作成します。
CREATE DATABASE appdb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'appuser'@'localhost' IDENTIFIED BY 'a-long-random-password';
GRANT ALL PRIVILEGES ON appdb.* TO 'appuser'@'localhost';
FLUSH PRIVILEGES;
EXIT;ここでは3つの意図的な選択を行っています。utf8mb4 は4バイトの完全な UTF-8 です。古い utf8 エイリアスは絵文字や一部の CJK 文字を切り捨てるため、常に utf8mb4 を使用してください。権限付与は appdb.* に対して行い、*.* に対しては行いません。これにより、このユーザーは自身のデータベースのみを操作でき、アプリケーションで SQL インジェクションが発生しても他のサイトのテーブルを読み取られることはありません。また、'appuser'@'localhost' はアカウントの接続元をローカルホストのみに制限します。
そのユーザーとしてテストを行います。
mysql -u appuser -p appdbパスワードを求められ、MariaDB [appdb]> プロンプトが表示されます。-h フラグがないことに注目してください。これを指定しないことで、クライアントはローカルの Unix ソケット経由で接続します。これが MariaDB における localhost の定義です。知っておくべき注意点として、MySQL および MariaDB では、localhost は Unix ソケットを意味し、127.0.0.1 は TCP 接続を意味します。 標準的な Ubuntu 24.04 の MariaDB では、127.0.0.1 からの TCP 接続はサーバー側で localhost に解決されるため、どちらもアカウントと一致します。しかし、skip-name-resolve が有効なサーバー(一般的なパフォーマンス調整であり、多くのコンテナイメージでは標準)では、両者は異なるホストとして扱われます。そのため、127.0.0.1 に接続するアプリケーションは、パスワードが正しくても ERROR 1045 (28000): Access denied for user 'appuser'@'127.0.0.1' (using password: YES) で拒否されます。
したがって、アプリケーションの接続先ホストは localhost、ユーザーは appuser、データベースは appdb に設定し、root は使用しないでください。PHP の mysqli および PDO は、ホストが文字列 localhost である場合に Unix ソケットへ切り替わり、作成したアカウントと一致します。フレームワークが数値の TCP ホストを要求する場合は、実際の接続方法に合わせて 'appuser'@'127.0.0.1' でユーザーを作成してください。別のマシンからデータベースにアクセスする必要がある場合に限り、ファイアウォールルールと組み合わせて @'%' を使用します。
ステップ 8 - Certbot で HTTPS を追加する
ログインフォームを平文の HTTP で提供すると、パスワードが平文で送信されます。また、現在の主要なブラウザーではページに「安全ではありません」と表示されます。Certbot を使えば、1 つのコマンドで HTTPS を設定できます。Apache プラグインとともにインストールします。
sudo apt install -y certbot python3-certbot-apache
sudo certbot --apacheここでは、Certbot の 2 つのプラグインを使用します。apache authenticator は、稼働中の Apache を通じて一時的に challenge ファイルを提供し、ドメインを管理していることを証明します。続いて apache installer が virtual host を書き換え、443 ブロックを追加して新しい証明書を指定し、デフォルトで HTTP のすべてのトラフィックを HTTPS にリダイレクトします。Certbot は version 1.4.0 (May 2020) 以降、リダイレクトを確認しなくなりました。そのため、平文の HTTP も提供し続ける必要がある場合は --no-redirect を指定します。Step 5 で実際の ServerName を設定しているため、Certbot はドメインを自動的に検出します。現在発行される証明書の有効期間は 90 days です (Let's Encrypt はデフォルトの有効期間を 10 February 2027 に 64 days、16 February 2028 に 45 days へ短縮します)。また、パッケージによって証明書を更新する systemd timer がインストールされます。sudo certbot renew --dry-run で timer を確認してください。出力の末尾は Congratulations, all simulated renewals succeeded になります。
challenge、更新 timer、DNS と firewall の要件について詳しくは、関連ガイド Apache で Certbot を使用して無料の Let's Encrypt TLS 証明書を発行するを参照してください。
バックアップ、アップグレード、堅牢化
状態を保持する 2 つの対象、データベースと Web ルートをバックアップします。毎晩の論理ダンプが最も単純で信頼性の高い方法です。sudo sh -c 'mysqldump --all-databases --single-transaction | gzip > /root/db-$(date +%F).sql.gz' その後、サーバーの外部へコピーします。パイプライン全体を sudo sh -c で囲むことが重要です。これを行わないと、シェルは > /root/... リダイレクトを自分のユーザーとして実行し、Permission denied で失敗します。sudo を継承するのは mysqldump だけだからです。--single-transaction を使うと、ロックせずに InnoDB テーブルの一貫したスナップショットを取得できます。これに /var/www と /etc/apache2/sites-available の tar を組み合わせれば、これらのファイルから新しい VPS 上にスタック全体を再構築できます。
アップグレードは通常の sudo apt update && sudo apt upgrade です。リリースアップグレードで問題になりやすいのは、PHP のバージョン更新です。Ubuntu 26.04 LTS では PHP 8.5 がデフォルトになり、この環境でインストールした php8.3-* パッケージはそのリリースに存在しません。そのため、アップグレード後は php8.5-fpm を実行することになり、ソケットは /run/php/php8.5-fpm.sock に変わりますが、Apache の設定は 8.3 のソケットを参照したままです。新しい conf(sudo a2enconf php8.5-fpm)を有効にし、古い設定を無効にしてください。そうしないと、通常のアップグレード後にサイトが Primary script unknown を返し始めます。PHP のリリースは LTS ディストリビューションより速く進むため、パッチバージョンを固定するのではなく、現在の PHP リリースノートを確認してください。
初日に実施する価値がある堅牢化は 2 つあります。1 つ目は、サーバーに SSH を監視する Fail2Ban を導入することです。公開 VPS には数分以内に自動化されたログイン試行が届くため、小さな jail でも、ban の前に数千回の試行を少数に抑えられます。2 つ目は、Apache の仮想ホスト、MariaDB のデータベース、ユーザーをファイルの手編集ではなくブラウザーで管理したい場合に、Webmin の Web ベースのコントロールパネルを使うことです。これはこの構成と同じスタック上で動作し、先ほど作成した設定ファイルを操作します。どちらも各コンポーネントの理解に代わるものではありませんが、日常的な運用の手間を減らせます。
失敗する場合と表示される文字列
デフォルトページが消えません。 バーチャルホストを編集して再読み込みしても、ブラウザーに "Apache2 Ubuntu Default Page" とその "It works!" バナーが表示され続けます。Apache は最初に一致したバーチャルホストを提供します。ServerName がリクエストに一致しない場合は、アルファベット順で最初の設定が選択されます。000-default.conf は testapp.conf より先になります。リクエストのホスト名が ServerName に一致していないか、sudo a2dissite 000-default を実行していない可能性があります。デフォルトを無効化し、sudo systemctl reload apache2 を実行してください。apache2ctl -S で確認すると、バーチャルホストの対応表が表示され、デフォルトを所有している設定を確認できます。ブラウザーのキャッシュも削除してください。古いページの 200 応答がキャッシュされ、表示され続けることがあります。
.php ファイルが実行されず、ダウンロードされます。 info.php を開くと、ブラウザーが <?php のソースをそのまま含むファイルをダウンロードしたり、プレーンテキストとして表示したりします。PHP ハンドラーが関連付けられていないため、Apache がファイルを静的アセットとして提供しています。sudo a2enmod proxy_fcgi を省略した、sudo a2enconf php8.3-fpm を実行していない、またはその後に Apache を再起動していない可能性があります。3 つすべてを実行してください(Step 4)。その後、再読み込みします。apache2ctl -M | grep fcgi でモジュールが読み込まれていることを確認します。proxy_fcgi_module が一覧に表示されるはずです。これは見た目の問題ではなく、ソースコードの漏えいです。実際のデータをサーバーに置く前に修正してください。
ERROR 1698 (28000): Access denied for user 'root'@'localhost'。 sudo を付けずに mysql -u root または mariadb -u root を実行しています。root アカウントは unix_socket 認証を使用するため、OS ユーザーが実際に root の場合だけ認証されます。修正方法は sudo mysql です。-u root もパスワードも必要ありません。このメッセージは、ソケット認証が正しく動作している場合に想定される動作です。インストールが壊れているわけではありません。
アプリケーションから、正しいパスワードを指定して ERROR 1045 (28000): Access denied for user 'appuser'@'127.0.0.1'。アカウントは 'appuser'@'localhost' として存在します。しかし、ホスト名解決が無効なサーバー(skip-name-resolve)で、アプリケーションが TCP 経由で 127.0.0.1 に接続しています。そのため、MariaDB は両者を異なるホストとして扱います。localhost は Unix ソケット、127.0.0.1 は TCP です。アプリケーションの接続先ホストを localhost に変更すると、ソケットが使用され、アカウントと一致します。フレームワークが TCP しか使用できない場合は、2 つ目のアカウント 'appuser'@'127.0.0.1' を作成してください。
/var/log/apache2/testapp-error.log 内の AH01071: Got error 'Primary script unknown'。ブラウザーには File not found. が表示されます。Apache はリクエストを PHP-FPM に渡しましたが、FPM は Apache が指定したパスにスクリプトを見つけられませんでした。主な原因は 2 つあります。設定内の FPM ソケットが、インストールされていない PHP バージョンを指している場合です。たとえば、リリースアップグレードで PHP 8.5 に移行した後も、8.3 のソケットが設定されたままになっています。もう 1 つは、DocumentRoot により、実際のディレクトリと設定上のディレクトリが一致せず、ファイルが本当に存在しない場合です。ls -l /run/php/ でソケットの存在を確認し、DocumentRoot がファイルの実際の場所と一致していることを確認します。その後、php8.3-fpm(または実際にインストールされている PHP-FPM のバージョン)と apache2 の両方を再起動します。
再起動するたびに AH00558: apache2: Could not reliably determine the server's fully qualified domain name が表示されます。これは無害な警告であり、エラーではありません。Apache はグローバルな ServerName が設定されていないと通知しています。/etc/apache2/conf-available/servername.conf に ServerName your.domain を記述し、sudo a2enconf servername を実行すると警告を抑制できます。
Apache の起動時に (98)Address already in use: AH00072: make_sock: could not bind to address 0.0.0.0:80 が表示されます。別の Web サーバーがすでにポート 80 を使用しています。以前の実験で残った nginx が原因であることがよくあります。sudo ss -ltnp | grep :80 でプロセスを特定し、Apache を起動する前に別のサービスを停止して無効化してください。
FAQ
mod_php か PHP-FPM のどちらを使うべきですか?
PHP-FPM を使用してください。mod_php はすべての Apache プロセスにインタプリタを埋め込み、低速な prefork MPM の使用を強制するため、静的画像を提供する場合でも Apache が PHP のオーバーヘッドを抱えることになります。PHP-FPM は PHP を独立してチューニング可能な別個のプールとして実行し、Apache はソケット経由でこれにアクセスします。また、より高速なスレッドベースの event MPM と連携でき、後で nginx に移行する際も変更が不要です。これが現代の標準であり、mod_php はプロセス内動作に依存するレガシーアプリケーションでのみ意味を持ちます。
ブラウザで PHP ファイルを実行できず、ダウンロードされてしまうのはなぜですか?
PHP ハンドラが関連付けられていないため、Apache が .php ファイルを静的なダウンロード対象として扱っています。FPM を使用する Ubuntu 24.04 の場合、sudo a2enmod proxy_fcgi、sudo a2enconf php8.3-fpm、またはその後の Apache 再起動のいずれかが漏れている可能性があります。これら3つの手順をすべて実行してリロードし、apache2ctl -M | grep fcgi で proxy_fcgi_module がリストに含まれていることを確認してください。修正するまでサーバーはソースコードを漏洩している状態であるため、緊急の対応が必要です。
正しいパスワードを入力しても MariaDB で root アクセスが拒否されるのはなぜですか?
Ubuntu の MariaDB はパスワードを設定していない場合、root アカウントを unix_socket で認証し、オペレーティングシステムの root ユーザーと紐付けるためです。通常のシェルから mysql -u root を実行すると、設計上 ERROR 1698 (28000): Access denied for user 'root'@'localhost' が返されます。代わりに sudo mysql で接続し、root を再利用するのではなく、アプリケーションごとにパスワード認証を行う個別のユーザーを作成してください。
LAMP サイトに HTTPS を追加するにはどうすればよいですか?
certbot と python3-certbot-apache をインストールし、ドメインの A レコードをサーバーに向けた後、sudo certbot --apache を実行してください。Apache 用の認証プログラムが実行中の Apache を通じてドメインの所有権を証明し、インストーラーがポート 443 用のバーチャルホストを書き換えて自動更新を設定します。Certbot と Apache の詳細な手順では、チャレンジ、更新タイマー、および一般的な失敗モードについて解説しています。