Search by

caprel / laravel-ops

Install and diagnose the deployment of a Laravel application: cron entry, queue worker, log rotation, scanner trap, dependency audit

Maintainers

Package info

inligit.fr/cap-rel/laravel/laravel-ops

pkg:composer/caprel/laravel-ops

Transparency log

Statistics

Installs: 7

Dependents: 0

Suggesters: 0

v1.0.0 2026-09-07 20:08 UTC

This package is not auto-updated.

Last update: 2026-09-07 23:53:11 UTC


README

make ci answers "is the code sound". This package answers the other question, the one nothing used to ask: is what runs on this server complete?

It carries the deployment commands that used to be copied from one project to the next:

CommandWhat it does
install:doctorDiagnoses the deployment: environment, dependencies, database, queue, scheduler, worker, assets
install:cronRenders and installs the /etc/cron.d entry running the scheduler
install:supervisorRenders and installs the Supervisor program running the queue worker
install:logrotateRenders and installs the rotation of the logs Laravel does not rotate itself
install:fail2banRenders and installs the filter and jails of the scanner trap
ops:security-auditRuns composer audit and npm audit, and mails new advisories

Installation

composer require caprel/laravel-ops

The commands are available right away. Two things are worth publishing:

# The deployment templates, into deploy/ of the project. Version them there.
php artisan vendor:publish --tag=ops-deploy

# The configuration, only when a path or a repair command has to change.
php artisan vendor:publish --tag=ops-config

Publish config/ops.php whole: the merge with the defaults of the package happens on the top-level keys only, so a file holding a partial cron section replaces the whole section instead of completing it.

The templates are templates

Everything under deploy/ carries {{APP_PATH}}, {{PHP}}, {{USER}}, {{LOG_DIR}}, {{APP_SLUG}}: the install:* commands render them with the values of the running deployment. Never copy one of those files into /etc with cp, and never hand-edit the generated file:

  • Supervisor refuses a program whose stdout_logfile directory does not exist, and it refuses the WHOLE file with it (CANT_REREAD), taking every other program declared there down;
  • logrotate and fail2ban say nothing at all, and simply never rotate nor ban;
  • a hand-edited file in /etc is reverted by the next deploy.

Every command accepts --print (render to stdout, write nothing), --root (prefix every target, to inspect a whole tree), --force (replace a target whose content differs) and --user / --group / --php.

Diagnosing

php artisan install:doctor          # readable table
php artisan install:doctor --json   # same content for a probe

Three statuses, and a return code that follows: OK, WARN (return code 0), FAIL (non-zero, so the command plugs into external monitoring as it is).

Every line that is not OK carries the command that repairs it, and that command is the one of the project: make migrate rather than php artisan migrate when the Makefile wraps the rights and the --force. A project that deploys differently overrides ops.fix_commands and the doctor stops naming a target that does not exist there.

Checks that concern the server keep quiet when the server is not there: no /etc/cron.d on this machine means the cron check passes with a mention, because a diagnosis that shouts on a workstation stops being read anywhere.

Dependency audit

ops:security-audit runs both audits, and mails the result to ops.security.recipient (OPS_SECURITY_EMAIL), falling back to the address the application sends its mail from. The same list of advisories is reported once, not every morning: a daily mail that never changes stops being read within a week, and the day a critical advisory appears in it nobody notices.

Schedule it in routes/console.php:

Schedule::command('ops:security-audit')->dailyAt('06:00');

An application with its own mail layout points the views at its own, rather than publishing those of the package:

'security' => [
    'views' => [
        'html' => 'emails.security-audit',
        'text' => 'emails.security-audit-text',
    ],
],

Tests

composer ci        # pint + phpstan + phpunit

The suite runs every command against a throwaway deployment built in a temporary directory, whose deploy/ holds the stubs this package publishes: what the tests cover is what a project gets.