見出し画像

CakePHP4をvercel上で動かす

vercel、好きです。個人であればHOBBY枠でそれなりに動いちゃうのでいつも重宝しているvercel(旧now)ですが、もちろんPHPも動かすことができます。

しかしながら、CakePHPをvercelで動かしたサンプルや情報があまり見つからなかったので、ここにメモしておきます。開発やテスト用の環境なので細かいところの調整が不十分な可能性も大いにありますが、何かの参考になれば幸いです。

プロジェクトを作る

まずは普通にcakephp4のプロジェクトを作ります。

composer create-project --prefer-dist cakephp/app:4.* vercel-cakephp-app
cd vercel-cakephp-app

次に、Heroku同様Build時にcomposerが--no-devで実行されるっぽいので、DebugKitをrequireに移動しておきます。このあたりはvercel側の設定でcomposerなりのコマンドを調整すれば不要かもしれないです。

composer require cakephp/debug_kit

この状態でサーバを起動すると、もちろん動きます

bin/cake server

Welcome to CakePHP v4.2.3 Console
-------------------------------------------------------------------------------
App : src
Path: /home/smith/vercel-cakephp-app/src/
DocumentRoot: /Users/smith/Development/vercel-cakephp-app/webroot
Ini Path: 
-------------------------------------------------------------------------------
built-in server is running in http://localhost:8765/
You can exit with `CTRL-C`

vercelに必要なファイルを追加する

github連携でデプロイする場合は、.gitignoreがあるので、vendor以下など余計なファイルが送られることはありませんが、nowコマンドで直接vercelにデプロイする場合、このままではvendorなども送信していまいます。

よって、.nowignoreを作成します。(.gitignoreと同様で問題なさそう)
ちなみに、これって.vercelignoreでもいいのかもしれない??

 cp .gitignore .nowignore

これで、vercelのbuild時にファイル多すぎてコケるなどはなくなります。

続いて、vercel.jsonを作成します。cakephpの場合、とりあえず全てをwebroot/index.phpにルーティングすれば良いのですが、vercelの仕様上、サーバレスで動かすにはapi/以下でないとダメっぽいです。

なので、api/index.phpというファイルを作成してあげて、そこでwebroot/index.phpを読み込みます。

[api/index.php]

<?php
require __DIR__.'/../webroot/index.php

そして、vercel.jsonは以下の通り。img/js/css/fontはそのままルーティングしときます。ちなみに、php8系がvercel-php@0.4.0で動くっぽいですが、ext-intlが無いっぽくcakephpが動かなかったので0.3.1にしてます。このあたりはその時々で最新にしてもらえれば。

{
   "version": 2,
   "functions": {
    "api/index.php": {
        "runtime": "vercel-php@0.3.1"
    }
   },
   "routes": [
       {
           "src": "/(css|js)/(.*)",
           "dest": "webroot/$1/$2"
       },
       {
           "src": "/(.*)",
           "dest": "api/index.php"
       }
   ]
}

これで、最低限vercelで動くかたちになりました。

環境変数の設定

環境変数はvercel.jsonで設定するパターンと、Project Settingsで設定するパターンの2つあります。公式では、後者を推奨しているようで、後者であればproduction, development, previewなどのステージングによって切り替えることができます。両方指定した場合は、ファイルのほうが優先されるっぽいです。

今回はテンプレートなので、一旦vercel.jsonに書いていきますが、DEBUGなどだけでもProject Settingsに分けたほうが運用的には可かもしれないです。

ということで、最低限の環境変数をvercel.jsonに追加します。

{
   "version": 2,
   "functions": {
       "api/index.php": {
           "runtime": "vercel-php@0.3.1"
       }
   },
   "routes": [
       {
           "src": "/(css|js|img|font)/(.*)",
           "dest": "webroot/$1/$2"
       },
       {
           "src": "/(.*)",
           "dest": "api/index.php"
       }
   ],
   "env": {
       "DEBUG": "true",
       "SECURITY_SALT": "____SALT____",
       "APP_NAME": "__CAKEPHP_ON_VERCEL__",
       "APP_ENCODING": "UTF-8",
       "APP_DEFAULT_LOCALE": "en_US",
       "APP_DEFAULT_TIMEZONE" : "UTC"
   }
}

ログの出力先

vercelでは/tmp以下以外についてファイルの書き込みが出来ないため、デフォルトの/logs以下にログを残そうとすると怒られます。

アプローチとしては

- config/path.phpでログの出力先を/tmpにする
- ログの出力先を標準出力/標準エラーにする

ですが、せっかくvercelを使ってるので、後者でいきたいと思います。

config/app.phpのLogをFileLogからConsoleLogに変更し、出力先を変更します。

'Log' => [
       'debug' => [
           'className' => \Cake\Log\Engine\ConsoleLog::class,
           'stream' => 'php://stdout',
           'outputAs' => \Cake\Console\ConsoleOutput::PLAIN,
           'url' => env('LOG_DEBUG_URL', null),
           'scopes' => false,
           'levels' => ['notice', 'info', 'debug'],
       ],
       'error' => [
           'className' => \Cake\Log\Engine\ConsoleLog::class,
           'stream' => 'php://stderr',
           'outputAs' => \Cake\Console\ConsoleOutput::PLAIN,
           'url' => env('LOG_ERROR_URL', null),
           'scopes' => false,
           'levels' => ['warning', 'error', 'critical', 'alert', 'emergency'],
       ],
       // To enable this dedicated query log, you need set your datasource's log flag to true
       'queries' => [
           'className' => \Cake\Log\Engine\ConsoleLog::class,
           'stream' => 'php://stdout',
           'outputAs' => \Cake\Console\ConsoleOutput::PLAIN,
           'url' => env('LOG_QUERIES_URL', null),
           'scopes' => ['queriesLog'],
       ],

あまりログを出しすぎると鬱陶しいので、debug以外切ってしまってもいいかもしれないです。

その他の細かい調整

config/pathでTMPやcacheを全て/tmp/に変更しました。

また、環境変数でデータベースのdefaultのユーザを設定できるようにしました。

最後に

駆け足で設定したので、実際に開発をすると不都合が出てくる可能性もありますが、なにかあれば追記していきます。

今回設定したものは以下のgithubにあります。ご自由にどうぞ!


この記事が参加している募集

最近の学び

この記事が気に入ったらサポートをしてみませんか?