|||||||||||||||||||||

なんぶ電子

- 更新: 

Laravelのデプロイ

LaravelをデプロイするためにPHPをBuildした様子

かつてLaravelの開発環境を設定していろいろ学んできましたが、いよいよデプロイです。

Windows10で開発したLaravel9のプロジェクトをDebian11にデプロイしました。Laravelのデプロイは基本的にはプロジェクト単位でコピーをして設定を変更するだけなのでさほど難しくはないものです。

ただLaravel9がPHPのバージョン8.0以上を要求しているのに対し、執筆時点のDebian11においてはAPTで取得できるPHPのバージョンは7.4だったので、apacheとPHPをmakeすることになりました。

手順は公式のガイドに従います。

Apacheのビルド

APTでbuild-essentialsインストールを終えているものとし、Apacheをビルドします。

Apacheから、httpd-2.4.54.tar.gz をダウンロードして展開します。

# cd /usr/local/src
# wget https://dlcdn.apache.org/httpd/httpd-2.4.54.tar.gz
# tar vzxf httpd-2.4.54.tar.gz
# cd httpd-2.4.54
# ./configure --enable-so
...
checking for APR... no

configureを実行すると、APRがないということです。INSTALLファイルを読むと、apr.apache.orgからダウンロードするようにとの事でした。

APRはプラットフォーム間の挙動差異を吸収してくれるツールのようです。configure -hで見てみても、これがない状態でビルドする方法はなさそうでした。

ダウンロードしたのち展開し、httpd-2.4.54ディレクトリにあるsrclibディレクトリの中に、バージョンを除去した形で移動させます。その後、--with-inculded-aprオプションをつけてconfigureを実行します。

# wget https://dlcdn.apache.org//apr/apr-1.7.0.tar.gz
# wget https://dlcdn.apache.org//apr/apr-util-1.6.1.tar.gz
# tar vzxf apr-1.7.0.tar.gz
# tar vzxf apr-util-1.6.1.tar.gz
# mv apr-1.7.0 httpd-2.4.54/srclib/apr
# mv apr-util-1.6.1 httpd-2.4.54/srclib/apr-util
# ./configure --enable-so --with-inculded-apr

PCREもが存在しないというエラーも出ました。PCREはPerl 5と同じ構文で正規表現を行うためのライブラリです。aptで「libpcre2-dev」をインストールしたところconfigureは通りましたが、ビルドでエラーになりました。PCRE2Project/pcre2から最新版をダウンロードしてビルドするのがいいと思いまいます。

make時に「 expat.h: そのようなファイルやディレクトリはありません 」というメッセージでエラーとなりました。こちらは「libexpat1-dev」をaptでインストールしたところ解消しました。。

デフォルトだとApacheバイナリ群は「/usr/local/apache2/」にインストールされます。設定ファイルはその中のconf/httpd.confとなっており、設定はすべてその中に記述します。APTからインストールした際のようなDebianのApache2の設定ディレクトリ群では設定をしないため、a2enmod等のコマンドは利用できません。

サーバーはbinディレクトリのapachectlから「start」や「stop」といった引数を渡してコントロールします。apachectlの他のコマンドについては公式ページに掲載されています。

公開するファイルの保存先であるhtdocsディレクトリも同じ場所に存在します。

コマンドを利用すれば起動はできますが、おそらくサービス(Systemd)として動かしたいと思います。これはAPT経由でインストールしたapacheサーバーのファイルを参考に次のようにしました。

apache2.service

[Unit]
Description=The Apache HTTP Server
After=network.target remote-fs.target nss-lookup.target
Documentation=https://httpd.apache.org/docs/2.4/

[Service]
Type=forking
Environment=APACHE_STARTED_BY_SYSTEMD=true
ExecStart=/usr/local/apache2/bin/apachectl start
ExecStop=/usr/local/apache2/bin/apachectl stop
ExecReload=/usr/local/apach2/apachectl graceful
PrivateTmp=true
Restart=on-abort

[Install]
WantedBy=multi-user.target

このファイルを/etc/systemd/system/ディレクトリに配置します。その後「systemctl enable apache2」を実行して自動化させます。

デフォルト以外の場所にインストールした場合は、Execのパスに注意してください。

またAPTでインストールした際は、apacheはwww-dataというユーザー権限で動くのでその設定もします。

ユーザーを作成します。

# useradd -s /bin/false www-data

次に、httpd.confのUserとGroupにwww-dataを設定します。

httpd.conf

# User daemon
# Group daemon
User www-data
Group www-data

サービスを再起動させて状態を確認します。httpのプロセスのユーザーが設定したwww-dataになっているものがあれば正常です。一部のプロセスはrootになっています。

# ps aux | grep www-data

root     ... /usr/local/apache2/bin/httpd -k start
www-data ... /usr/local/apache2/bin/httpd -k start
...

PHPのビルド

PHPをビルドします。まず公式のインストールガイドにあるように--with-apxs2=/usr/local/apache2/bin/apxs指定します。apacheをビルドしたのはこのためです。

LaravelのPHP要件であるもののうち、デフォルトで有効にならない次の拡張ライブラリを設定します。

  • BCMath

    --enable-bcmath

  • cURL

    --with-curl

  • Mbstring

    --enable-mbstring

  • OpenSSL

    --with-openssl

  • PCRE

    公式のWebのドキュメントにはデフォルトでソースにバンドルされているPCREが利用されるとの記述があったので、なにも指定しなかったところ「 Unable to start pcre module in Unknown on line 0 」というエラーに遭遇しました。そこでapacheインストール時にビルドしたPCREを利用するように「--with-external-pcre=[ライブラリのディレクトリ」と指定しています。

  • PDO

    PDO自体は有効になっていますが、MySQL(MariaDB)を使うなら、--with-pdo-mysqlを指定する必要があります。Postgreの場合は--with-pdo-pgsqlを指定します。

MariadbやopenSSLの他必要なアプリをインストールしておきます。筆者の環境では他にpkg-configやlibxml2-dev、libssl-dev(openssl)、libsqlite3-dev、libcurl4-openssl-dev(curl)、libonig-dev(Oniguruma正規表現ライブラリ)、zlib1g-dev(圧縮ライブラリ)が必要になりました。

# apt install mariadb-server openssl pkg-config ...
# wget https://www.php.net/distributions/php-8.1.9.tar.gz
# tar vzxf php-8.1.9.tar.gz
# cd php-8.1.9.tar.gz
# ./configure --with-apxs2=/usr/local/apache2/bin/apxs --enable-bcmath --with-curl --enable-mbstring --with-openssl --with-pdo-mysql --with-zlib --with-external-pcre=/usr/local/lib

# make 
# make test
# make install

make testを事項するように促されますので、実行します。おそらくいくつかは失敗するのではないかと思います。

これらの対処方法は@IT:「PHPテスト失敗の原因を追究する」が参考になります。

例えば次のようなエラーが出たとします。

Bug #78014 (Preloaded classes may depend on non-preloaded classes due to unresolved consts) [ext/opcache/tests/bug78014.phpt]

この時ソースディレクトリにある「ext/opcache/tests/bug78014.phpt」に定義されているテストが実行されます。その内容から状況を判断します。

今回は、opcache関連のエラーがいくつか出ました。make testを管理者権限で実行したためだと判断しました。opcacheのコードの事前ロードではroot権限での実行が禁止されています。ユーザー権限でテストをすると該当のエラーは出ませんでした(代わりroot権限でテストした際には出ないエラーが出ましたが)。

PHPの設定

httpd.confにおけるPHPのLoadModuleのエントリーは--with-apxs2オプションをを付けてビルド・インストールした流れの中で自動的に加わっていると思います。それが出力されているのが確認できたら、.phpの拡張子をもつファイルをPHPとしてパースする設定の記述をします。

httpd.conf

...
<FilesMatch \.php$>
  SetHandler application/x-httpd-php
</FilesMatch>
...

PHPの設定ファイルはソースディレクトリからphp.ini-developmentまたはphp.ini-production、ファイルをコピー・リネームして配置します。デフォルトだと/usr/local/lib/php.iniに配置する決まりになっています。

Laravelプロジェクトのデプロイ

前置きが長くなりましたが、本番サーバーにLaravelプロジェクトをデプロイします。

サーバーにcomposerがない場合はリンク先を参考にインストールします。

# php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
# php -r "if (hash_file('sha384', 'composer-setup.php') === '55ce33d7678c5a611085589f1f3ddf8b3c52d662cd01d4ba75c0ee0459970c2200a51f492d557530c71c15d8dba01eae') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
# php composer-setup.php
# php -r "unlink('composer-setup.php');"

作業後に作業ディレクトリ「composer.phar」という名前で実行ファイルができます。これは後からオートローダ―を最適化する際に利用します。binディレクトリなどパスの通った場所から、composerというシンボリックリンクを張ります。

同様にNode.js環境もインストールします。Node.jsのインストールはNVMを使って行うのがいいと思います。

LinuxにおけるNVMは実行したユーザーのホームディレクトリに.nvmとして保存されます。実行ファイルへのパスはスクリプトが.bashrcファイルに記述してくれますが、初回時はうまく反映されていないことがあります。which nvm等の応答がなかったら再ログインしてみてください。またroot環境でインストールしてしまうと、ユーザー環境からは利用できない場所にインストールされてしまいますので注意が必要です。

$ wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
$ nvm install --lts
$ nvm use インストールされたバージョン

nvmをアンインストールしたい場合は.nvmディレクトリを削除するだけです。npmの実行ファイルは.nvmディレクトリの下流にありますが、エラーログ等はユーザーディレクトリ内の.npmディレクトリに保存されるようですので、nvmアンインストール時にはそれも削除します。

この後の手順は次のようになります。

  1. ファイルのコピー

    基本的にプロジェクトディレクトリをコピーします。「/node_modules,/public/build,/storage/*.key,/vendor,.phpunit.result.cache」など通常.gitignoreに含まれるディレクトリ以外のすべてが対象となります。

    後々のことを考えるとgitを利用して開発側でアップロードしたgitレポジトリを本番側でcloneした方が便利だと思いますが、この時デフォルトだと、.envファイルは含まれないので別途生成するかコピーします。

    コピーしたファイルとディレクトリの所有権はこのあとcomposerやnpmを実行するユーザーにしておきます。

  2. APP_KEYの再生成

    .envファイルに設定してあるAPP_KEYを生成または再生成します。

    $ php artisan key:generate   
    
  3. 環境をプロダクションモードに

    .envファイル中の「APP_ENV」の値を「local」から「production」にします。

  4. デバッグモードの解除

    .envファイル中の「APP_DEBUG」の値をfalseにします。APP_ENVの後に出現する設定なのでここで紹介していますが、この値をfalseに設定すると実行時に詳細なエラーメッセージが出なくなりますので、稼働を確認してからの方がいいかもしれません。

  5. APP_URLの設定

    デフォルトでapp.testとなっているURLを正規のものに変えます。

  6. データベースの設定

    初回のデプロイ時は環境によってデータベースにユーザー登録等が必要になります。またマイグレーションやシードも必要に応じて実行します。

    bootstrapに相当する場所(サービスなど)にデータベーステーブルが存在することが前提のコードが書かれていると、例外がスローされてphp artisanコマンドを実行できない場合があります。コードを直すか、それが難しければ開発側のデータベースのテーブルをダンプしたものを本番側でインポートします。MySQL(MariaDB)におけるダンプ・インポートの方法は次の通りです。

    $ mysqldump -u ユーザー名 -p データベース名 --default-character-set=binary>dump.sql
    
    $ mysql-u ユーザー名 -p データベース名 --default-character-set=binary<dump.sql
    
  7. JavaScriptのビルド

    JavaScriptの環境自体は既に設定済みだと思いますので、ビルドのコマンドを実行するだけです。buildしてから本番環境にコピーする方法も試してみたのですが、やり方が悪かったのか@viteディレクティブが本番環境にならずうまくいきませんでした。

    $ npm run build
    

    ビルド時に、次のようなエラーが出た場合はstack overflowを参考に、/etc/sysctl.confのファイルウォッチャーの制限を変更します。

    System limit for number of file watchers reached

    /etc/sysctl.conf

    ...
    fs.inotify.max_user_watches = 16384
    ...

    ここで設定した値は適当です。筆者の環境ではデフォルト値が8192だったので倍にしました。変更後、「sysctl -p」で設定を反映させます。

  8. オートローダの最適化

    Composerのクラスオートローダの最適化をします。ここで先ほどインストールしたcomposer.pharを使います。composerは管理者権限で実行すると警告がでます。

    $ composer.phar install --optimize-autoloader --no-dev
    
  9. configの最適化

    構成ファイルをひとつのキャッシュファイルにまとめます。新しい環境でconfigのキャッシュしないと古い環境のものが使われてしまい、思わぬエラーに悩まされることになります。

    $ php artisan config:cache
    
  10. ルートの最適化

    すべてのルート登録をキャッシュ ファイル内の 1 つのメソッド呼び出しに減らします。

    $ php artisan route:cache
    
  11. ビューの最適化

    すべての Blade ビューをプリコンパイルします。

    $ php artisan view:cache
    

すべて終えたら、エントリーポイントであるpublicディレクトリ内のindex.phpにアクセスして意図したように表示できるかチェックします。

開発環境がWindowsでデプロイはLinuxという場合は、ファイルの大文字と小文字の違いが識別されるようになる上に権限の概念も加わりますので注意が必要です。

筆者の場合はphp artisanコマンド等でautoload_real.phpでエラーとなって何もできなかったのですが、composer.jsonのautoload上のパスの中のappのaが大文字になっていました。

...
"autoload": {
  "files": [
     "app/helpers/OriginalHelper.php"
  ]
},
...

また上記の値を修正したら「composer dump-autoload」を実行してautoloaderを更新することも必要です。

細かな設定

稼働が確認できたら細かな設定をします。

htdocs以下のファイルやディレクトリの所有権の設定の仕方はいろいろな考え方があるとは思いますが、stack overflow:「How to set up file permissions for Laravel?」に答えのひとつがありました。

ただ先のサイトのまま従ってしまうと、本番環境でnpm run buildが実行できなくなってしまいます。なので筆者は次のようにしました。

  1. ファイルのコピー

    筆者の環境のumaskの値は0022です。

  2. 「composer install」「npm update」を実行
  3. 所有権を、編集ユーザー:apacheグループに変更
    # chown -R edit-user:www-data プロジェクトdir/
  4. すべてのファイルから「その他」の書き込み権限と実行権限を削除
    # find プロジェクトdir/ -type f | xargs chmod o-wx
  5. すべてのディレクトリから「その他」の書き込み権限を削除
    # find プロジェクトdir/ -type d | xargs chmod o-w
  6. すべてのファイルに「グループ」の書き込み権限を追加
    # find プロジェクトdir/ -type f | xargs chmod g+w
  7. すべてのディレクトリに「グループ」の書き込み権限を追加
    # find プロジェクトdir/ -type d | xargs chmod g+w

そのほかphp.iniを修正してエラーの出力と止めたり、apacheの設定でディレクトリ指定時のファイルのリストを止めたりします。

apacheのhttpd.confのdir_moduleを使って、publicディレクトリにアクセスした際にindex.phpを表示させようとすると、次のようなエラーになりうまくいきませんでした。

The GET method is not supported for this route. Supported methods: HEAD, POST, PUT, PATCH, DELETE, OPTIONS.

それに対する回避策は、index.htmlファイルを作ってidnex.phpにリダイレクトするようにするのが簡単です。

index.html

...
<head>
<!-- metaで書くパターン-->
<meta http-equiv="refresh" content="0;URL='./index.php'"/>

<!-- jsで書くパターン-->
<script>
  window.onload = function () {
    location.replace("./index.php");
  };
</script>

ただ、他に設定しなければならないものもありますので、.htaccessファイルとmod_rewriteを使って次のようにするのがいいと思います。

.htaccessファイルを利用するために、httpd.confでは設定の上書きを許可します。同時に、ファイルのリストの出力をやめ、mod_rewriteを有効にします。

httpd.conf

...

# mod_rewriteを有効に(コメントアウトを外す)
LoadModule rewrite_module modules/mod_rewrite.so

...
<Directory "/usr/local/apache2/htdocs">
...
  # Indexesを消してファイル一覧を出さないようにする
  Options FollowSymLinks
  
  # NoneからAllに変えて設定の上書きを許可する
  AllowOverride All
  
</Directory>

プロジェクトディレクトリ直下のデータを読み込まれるのはよくないので、下流のディレクトリを参照できないようにします。

プロジェクトデイレクトリ/.htaccess

...
<Files "*">
  deny from all
</Files>

publicディレクトリだけは例外に指定します。プロジェクトのpublicディレクトリにはLaravelが生成した.htaccessファイルが存在しますので、それに追記します。

ここにルートアクセスの際のリダイレクトも追加します。

プロジェクトデイレクトリ/public/.htaccess

...
<IfModule mod_rewrite.c>
  <IfModule mod_negotiation.c>
    Options -MultiViews -Indexes
  </IfModule>

  RewriteEngine On

  # Handle Authorization Header
  RewriteCond %{HTTP:Authorization} .
  RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

  # Redirect Trailing Slashes If Not A Folder...
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_URI} (.+)/$
  RewriteRule ^ %1 [L,R=301]

  # Send Requests To Front Controller...
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteRule ^ index.php [L]

  # pulicディレクトリアクセス時のリダイレクト設定
  RewriteRule ^$ %{REQUEST_URI}index.php [L,R]
</IfModule>

# ファイル読み込み例外設定
<Files "*">
 allow from all
</Files>

参考にさせていただきましたサイトの皆様、ありがとうございました。

筆者紹介


自分の写真
がーふぁ、とか、ふぃんてっく、とか世の中すっかりハイテクになってしまいました。プログラムのコーディングに触れることもある筆者ですが、自分の作業は硯と筆で文字をかいているみたいな古臭いものだと思っています。 今やこんな風にブログを書くことすらAIにとって代わられそうなほど技術は進んでいます。 生活やビジネスでPCを活用しようとするとき、そんな第一線の技術と比べてしまうとやる気が失せてしまいがちですが、おいしいお惣菜をネットで注文できる時代でも、手作りの味はすたれていません。 提示されたもの(アプリ)に自分を合わせるのでなく、自分の活動にあったアプリを作る。それがPC活用の基本なんじゃなかと思います。 そんな意見に同調していただける方向けにLinuxのDebianOSをはじめとした基本無料のアプリの使い方を紹介できたらなと考えています。

広告