License drivers for resale
Three ways the installer can check a license key — and an honest note on what that achieves.
This page is for people reselling the panel itself, or any application built from it. The installer asks for a license key on its second step; this is what happens to that key.
The driver is set in config/installer.php before you build the archive. It defaults to none, so a fresh clone installs without a license server standing by.
| Driver | Checks against | Revocable | Needs network |
|---|---|---|---|
none |
Nothing — any key of 8+ characters | – | No |
remote |
A license API you host | Yes | Yes |
signed |
An embedded Ed25519 public key | No | No |
The key is verified once, during install. Nothing phones home afterwards, so a buyer’s site can never break because your license server had an outage.
remote#
Point the driver at your own instance of this panel. Its /api/v1/license/activate and /api/v1/license/verify endpoints already speak exactly the request and response shape the driver expects — so the copies you sell can be licensed from the same panel you sell them with.
A firewalled or unreachable host is reported as “license server unreachable” rather than as a bad key, so a buyer with a network problem does not open a ticket about their receipt.
signed#
Generate a keypair once, keep the signing key, ship only the public key:
php artisan license:issue --keypair
Put the public key in config/installer.php. Put the signing key in your password manager and never ship it. Then issue a key per sale:
LICENSE_SIGNING_KEY=<hex> php artisan license:issue "Jane Doe"
LICENSE_SIGNING_KEY=<hex> php artisan license:issue "Jane Doe" --expires=2027-01-01
This works on air-gapped hosting and needs no server of yours to stay up. The trade-off is that an issued key cannot be revoked — pair it with --expires if that matters to you.
What license checking can and cannot do#
The panel ships as readable PHP. A determined buyer can open config/installer.php and switch the driver off.
Treat license checking as a deterrent that keeps honest customers honest, not as enforcement. It is worth saying plainly rather than pretending otherwise: businesses that budget for the leakage and compete on support and updates do consistently better than ones that spend their engineering time on protection schemes.
Building the archive#
./scripts/build-zip.sh
The script refuses to produce an archive containing .env, storage/app/settings.json (your Paddle keys), or storage/app/installed.json (which would lock the buyer out of their own wizard). It fails if .env.example is missing, since the installer cannot bootstrap without it, and it asserts that every runtime directory is present — an archive that lost storage/framework/sessions would 500 on every request before the buyer ever reached the wizard.