Running with FrankenPHP
FrankenPHP is a PHP application server that packages a webserver (Caddy) and the PHP runtime into a single binary, with automatic HTTPS. Koel ships a Caddyfile.example at the project root to use with it.
Want a one-download install instead?
The Standalone Binary distribution from koel/franken packages FrankenPHP, Koel, and a launcher into a single archive. This page is for installing FrankenPHP yourself as the runtime for an existing Koel install.
FrankenPHP is only the runtime. Install Koel first via Pre-Compiled Archive or Building from Source, then use FrankenPHP as the webserver.
Install FrankenPHP
Pre-built binaries are published at frankenphp.dev/docs/#install. On Linux, the one-line installer fetches the right binary for your architecture:
curl https://frankenphp.dev/install.sh | sh
sudo mv frankenphp /usr/local/bin/Configure the Caddyfile
From the Koel project root:
cp Caddyfile.example CaddyfileEdit Caddyfile and replace localhost with the domain you'll serve from. Using a real public domain enables automatic HTTPS via Let's Encrypt.
Run it
frankenphp runThat's it — Koel is now served on port 443 (and 80, redirected to HTTPS).
Running artisan commands
FrankenPHP ships its own PHP, available via the php-cli subcommand. Any php artisan … from Koel's CLI documentation becomes:
frankenphp php-cli artisan <command>For example, frankenphp php-cli artisan migrate runs database migrations and frankenphp php-cli artisan koel:sync triggers a media scan. For convenience: alias artisan='frankenphp php-cli artisan'.
If you also have system PHP installed (e.g. for composer install), running php artisan <command> against it works the same — both share the same .env and database.
DB_HOST=localhost gotcha
If your .env has DB_HOST=localhost with MySQL, FrankenPHP's PHP will fail to find the MySQL socket and you'll see Checking database connection … ERROR when running koel:init, even though HTTP serving works fine. Fix it one of two ways:
- Override per-command:
DB_HOST=127.0.0.1 frankenphp php-cli artisan <command> - Or change
.envtoDB_HOST=127.0.0.1.
For FrankenPHP CLI options not covered here (worker mode, multi-domain serving, custom PHP flags, etc.), refer to the official FrankenPHP documentation.
Run as a systemd service (Ubuntu)
For a production deployment, run FrankenPHP under systemd so it starts on boot and restarts on failure. Create /etc/systemd/system/koel.service:
[Unit]
Description=Koel (FrankenPHP)
After=network.target
[Service]
Type=simple
User=www-data
WorkingDirectory=/var/www/koel
ExecStart=/usr/local/bin/frankenphp run
Restart=on-failure
AmbientCapabilities=CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
[Install]
WantedBy=multi-user.targetAdjust WorkingDirectory and User to match where Koel lives on your host. Then enable and start it:
sudo systemctl daemon-reload
sudo systemctl enable --now koel
sudo journalctl -u koel -fBehind a reverse proxy
If you're already running nginx (or another reverse proxy) and want to use FrankenPHP only as the PHP runtime, make two changes to your Caddyfile:
- Uncomment the
auto_https offandservers { trusted_proxies … }block at the top —Caddyfile.exampleships it commented and ready for this case. Adjust the trusted-proxies CIDR if the reverse proxy lives on a different host. - Bind the site block to a local port — change
localhost {to:8001 {and addbind 127.0.0.1as the first line inside the block. Everything else inside the site block stays as-is.
Then point your existing reverse proxy at 127.0.0.1:8001 and let it terminate TLS as before.