concept-image / laravel-checks
Laravel Checks: Spatie Laravel Health with extra checks (public/index.php, unexpected files, exposed files, SMTP), a publishable health configuration and a publishable service provider registering the production health checks.
Package info
gitlab.com/concept-image-public/laravel-checks/
pkg:composer/concept-image/laravel-checks
Requires
- php: ^8.3
- illuminate/console: ^12.0|^13.0
- illuminate/http: ^12.0|^13.0
- illuminate/mail: ^12.0|^13.0
- illuminate/support: ^12.0|^13.0
- spatie/laravel-health: ^1.40
- spatie/security-advisories-health-check: ^1.4
Requires (Dev)
- larastan/larastan: ^3.0
- laravel/pint: ^1.18
- orchestra/testbench: ^10.0|^11.0
- pestphp/pest: ^4.0|^5.0
- pestphp/pest-plugin-arch: ^4.0|^5.0
Suggests
- laravel/horizon: Required by the Horizon check, commented out in the published provider.
Provides
None
Conflicts
None
Replaces
None
README
Extra Spatie Laravel Health checks for production Laravel applications, and an install command that publishes a ChecksServiceProvider registering the usual production checks. Each project then adds, removes or tweaks its checks in PHP.
Requirements
- PHP 8.3 or higher
- Laravel 12 or 13
The package installs spatie/laravel-health and spatie/security-advisories-health-check: don't require them in the application.
Installation
composer require concept-image/laravel-checks
php artisan laravel-checks:install
The install command publishes config/health.php and app/Providers/ChecksServiceProvider.php, and adds the provider to bootstrap/providers.php. Files that already exist are kept. To publish one of them only:
php artisan vendor:publish --tag=laravel-checks-config
php artisan vendor:publish --tag=laravel-checks-provider
Health configuration
config/health.php is the Spatie Laravel Health configuration with these defaults:
- results kept in memory (
InMemoryHealthResultStore): nothing is stored in the database; - the Oh Dear endpoint enabled, running the checks on each call (
always_send_fresh_results); - notifications off (
HEALTH_NOTIFICATIONS_ENABLED): Oh Dear alerts instead.
Set these variables in .env:
| Variable | Meaning |
|---|---|
OH_DEAR_HEALTH_CHECK_SECRET | Secret shown in the Application Health settings of Oh Dear |
OH_DEAR_HEALTH_CHECK_URL | Endpoint path to enter in Oh Dear (default /oh-dear-health-check-results); use a hard-to-guess path |
HEALTH_NOTIFICATIONS_ENABLED, HEALTH_TO_ADDRESS | Optional mail notifications |
The package itself registers no check: the published provider owns the list.
Published provider
final class ChecksServiceProvider extends ServiceProvider
{
public function boot(): void
{
Health::checks([
CacheCheck::new(),
DebugModeCheck::new(),
EnvironmentCheck::new()->expectEnvironment('production'),
// \Spatie\Health\Checks\Checks\HorizonCheck::new(),
OptimizedAppCheck::new(),
// \Spatie\Health\Checks\Checks\RedisCheck::new(),
SecurityAdvisoriesCheck::new(),
IndexCheck::new(),
ExposedFilesCheck::new(),
SmtpCheck::new(),
UnexpectedFilesCheck::new(),
]);
}
}
Uncomment Horizon (requires laravel/horizon) and Redis when the project uses them, and use the fluent options of each check, for example SmtpCheck::new()->mailer('ses-smtp').
Checks shipped by the package
| Check | Fails when |
|---|---|
IndexCheck | public/index.php differs from the Laravel skeleton file of the installed major version (warning when it cannot be fetched) |
ExposedFilesCheck | .env, .htaccess, artisan, auth.json, composer.json or composer.lock is served by APP_URL (warning when it cannot be reached) |
SmtpCheck | the mailer (the default one, or ->mailer()) is not an SMTP mailer, or cannot connect and authenticate to its server |
UnexpectedFilesCheck | the project root or public/ contains a file or directory outside the allowed lists, or the project contains any *.sql* file |
SmtpCheck opens an SMTP session (connection, EHLO, TLS, authentication) and closes it: no email is sent.
ExposedFilesCheck requests each path on APP_URL (or ->baseUrl()) without following redirects: a file is exposed when it answers with a 2xx status and a non-HTML body, so catch-all routes and HTML error pages are not reported. Change the list with ->paths([...]) or ->addPaths([...]).
UnexpectedFilesCheck compares the entries of the project root and of public/, hidden ones included, with allowlists:
| Location | Files | Directories |
|---|---|---|
| project root | .env, artisan, auth.json, composer.json, composer.lock | app, bootstrap, config, database, lang, public, resources, routes, storage, vendor |
public/ | .htaccess, apple-touch-icon.png, favicon.ico, favicon.svg, index.php, robots.txt | build, css, fonts, js, storage |
Anything else (tests/, .git/, package.json, public/hot, public/info.php…) is reported. Allow more entries with ->allowRootFiles([...]), ->allowRootDirectories([...]), ->allowPublicFiles([...]) and ->allowPublicDirectories([...]), for example a REVISION file written by the deployment tool.
It also fails on any SQL file at any depth (.sql, .sql.gz, .sql.zip…, whatever the case), symbolic links followed so a shared storage/ is scanned: SQL files are never deployed, so one found on the server is a dump left behind, possibly holding personal data. vendor/ and node_modules/ are skipped; exclude more directories with ->excludeFromSqlScan([...]).
Testing
composer ci
Changelog
See CHANGELOG.
License
The MIT License (MIT). See License File.