SSD Nodes Learn Hosting plans →
ガイド Matt Connor著者 Matt Connor ・更新日 2026-08-01

Ubuntu 24.04でLAMPスタックを構築する方法

Ubuntu 24.04にApache、MariaDB、PHP 8.3を導入し、PHP-FPMで高速化する手順を解説します。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 apache2

aptを実行すると、サービスが開始され、有効化されます。以下のコマンドで確認してください。

systemctl status apache2

active (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 list

ApacheApache FullApache Secureが表示されます。Apacheはポート80のみ、Apache Secureはポート443のみ、Apache Fullはその両方です。最後にTLSを追加するため、Apache Fullを選択してください。

sudo ufw allow OpenSSH
sudo ufw allow "Apache Full"
sudo ufw enable

ufw enableを実行するに、OpenSSHを許可してください。ufwはデフォルトですべての着信トラフィックを拒否します。SSHルールを設定せずに有効化すると、有効になった瞬間に接続が切断されます。現在のセッションは維持されますが、再接続は不可能になります。sudo ufw statusで確認してください。OpenSSHApache Full、およびそれらのv6対応版がすべてALLOWと表示されている必要があります。

ステップ 3 - MariaDBのインストールとセキュリティ設定

sudo apt install -y mariadb-server
systemctl status mariadb

Ubuntu 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 apache2

a2enconf 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 apache2

apache2ctl configtestSyntax OK と表示されるはずです。 a2dissite 000-default の行は忘れられがちです。これが、後でデフォルトページが消えないように見える原因であり、トラブルシューティングのセクションで解説しています。

ステップ 6 - PHPの動作確認とテストファイルの削除

アプリケーションのルートディレクトリに1行のPHPファイルを作成します。

echo "<?php phpinfo();" | sudo tee /var/www/testapp/info.php

http://app.example.com/info.php にアクセスします。正しく設定されていれば、紫とグレーの長い PHP Version 8.3.x テーブルが表示され、読み込まれているモジュールの一覧が確認できます。その中の Server API 行が FPM/FastCGI となっていることを確認してください。この最後の行は、リクエストが mod_php ではなく PHP-FPM を経由していることを示しています。

確認後、直ちにファイルを削除します。

sudo rm /var/www/testapp/info.php

phpinfo() には、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' でユーザーを作成してください。別のマシンからデータベースにアクセスする必要がある場合に限り、ファイアウォールルールと組み合わせて @'%' を使用します。

Step 8 - CertbotによるHTTPSの追加

ログインフォームをプレーンなHTTPで提供するとパスワードが平文で送信され、現在のすべてのブラウザで「保護されていない通信」と警告されます。Certbotを使用すれば、1つのコマンドでこれを解決できます。Apacheプラグインを使用してインストールしてください。

sudo apt install -y certbot python3-certbot-apache
sudo certbot --apache

Certbotはここで2つのプラグインを使用します。apache authenticatorは、実行中のApacheを通じてチャレンジファイルを一時的に提供することで、ドメインの所有権を証明します。次にapache installerがバーチャルホストを書き換えて443ブロックを追加し、新しい証明書を指定して、すべてのHTTPトラフィックをHTTPSへデフォルトでリダイレクトします。Certbot 2.0以降、リダイレクトに関する質問は表示されません。プレーンなHTTPでの提供を継続する必要がある場合は、--no-redirectを渡してください。Step 5で正しいServerNameを設定しているため、Certbotは自動的にドメインを検出します。証明書の有効期限は90日間です。パッケージには証明書を自動更新するsystemdタイマーが含まれています。sudo certbot renew --dry-runでタイマーを確認してください。末尾がCongratulations, all simulated renewals succeededとなっていれば正常です。

チャレンジの全手順、更新タイマー、DNSおよびファイアウォールの要件については、CertbotとApacheを使用した無料の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 で失敗します。これは mysqldump だけが sudo を継承しているためです。--single-transaction を使用すると、InnoDBテーブルをロックせずに一貫性のあるスナップショットを取得できます。これに /var/www/etc/apache2/sites-availabletar を組み合わせれば、これらのファイルから新しいVPS上にスタック全体を再構築可能です。

アップグレードは通常の sudo apt update && sudo apt upgrade です。注意が必要なのは PHPのバージョンアップ です。将来のUbuntuでデフォルトがPHP 8.4に移行すると、apt が 8.3 と並行して php8.4-fpm をインストールする場合があります。その際、ソケットが /run/php/php8.4-fpm.sock になり、Apacheの設定が古い 8.3 のソケットを指したままになることがあります。新しい設定(sudo a2enconf php8.4-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.conftestapp.conf よりも先にソートされます。リクエストのホスト名が ServerName と一致していないか、sudo a2dissite 000-default を実行していないことが原因です。sudo systemctl reload apache2 でデフォルト設定を無効化し、apache2ctl -S で確認してください。このコマンドはバーチャルホストのマップを表示し、どの設定がデフォルトを保持しているかを示します。ブラウザのキャッシュもクリアしてください。古いページの 200 OK レスポンスがキャッシュに残っている可能性があります。

.php ファイルが実行されずにダウンロードされる。 info.php を開くと、ブラウザが <?php のソースコードを含むファイルをダウンロードするか、プレーンテキストとして表示してしまいます。これはPHPハンドラが関連付けられていないため、Apacheがファイルを静的アセットとして処理している状態です。sudo a2enmod proxy_fcgi または sudo a2enconf php8.3-fpm をスキップしたか、その後にApacheを再起動していないことが原因です。3つすべて(ステップ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)なサーバー上の 127.0.0.1 に対してTCP接続を試みています。そのため、MariaDBは両者を異なるホストとして扱います。localhost はUnixソケット、127.0.0.1 はTCPを指します。アプリケーションの接続先ホストを localhost に指定してソケットを使用させるか、フレームワークがTCPしかサポートしていない場合は '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バージョンを指している(アップグレード後に 8.3 しか動いていないのに php8.4 ソケットを参照している)、または DocumentRoot と実際のディレクトリの不一致によりファイルが物理的に存在しない場合です。ls -l /run/php/ でソケットの存在を確認し、DocumentRoot がファイルの場所と一致していることを確認した上で、php8.3-fpmapache2 の両方を再起動してください。

再起動のたびに AH00558: apache2: Could not reliably determine the server's fully qualified domain name が表示される。 これはエラーではなく無害な警告です。Apacheはグローバルな ServerName が設定されていないことを通知しています。/etc/apache2/conf-available/servername.confServerName 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_fcgisudo a2enconf php8.3-fpm、またはその後の Apache 再起動のいずれかが漏れている可能性があります。これら3つの手順をすべて実行してリロードし、apache2ctl -M | grep fcgiproxy_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 を追加するにはどうすればよいですか?

certbotpython3-certbot-apache をインストールし、ドメインの A レコードをサーバーに向けた後、sudo certbot --apache を実行してください。Apache 用の認証プログラムが実行中の Apache を通じてドメインの所有権を証明し、インストーラーがポート 443 用のバーチャルホストを書き換えて自動更新を設定します。Certbot と Apache の詳細な手順では、チャレンジ、更新タイマー、および一般的な失敗モードについて解説しています。

#lamp#apache#mariadb#php-fpm#ubuntu