zilleali/mikrotik-laravel
A Laravel package for managing MikroTik RouterOS routers from PHP. Connect via the RouterOS API to run commands and automate common tasks such as hotspot and PPPoE user management, interface monitoring, and queue configuration, with Laravel-friendly configuration and service provider integration.
v1.8.0 is a feature release on top of a maintenance train dominated by Dependabot bumps. The headline is FleetManager — multi-router management plus router scoping fixes. Everything else (guzzle 7.15.2, league/commonmark 2.10.0 via Aikido security autofix, laravel/framework 12.69.3, spatie/ssh 1.13.2, phpstan 2.2.9, php-cs-fixer 3.95.18) is housekeeping you get for free on composer update.
Minimal steps:
composer require zilleali/mikrotik-laravel (or composer update zilleali/mikrotik-laravel if you're coming from v1.7.x — no breaking changes signalled, but re-publish config if you've customised it, see Gotchas).php artisan vendor:publish --tag=mikrotik-config. This is where per-router credentials live.config/mikrotik.php. With FleetManager in play, the config is now the single registry of devices rather than a flat "one connection" block — each entry needs host/username/password (and port, timeout, SSL flags where relevant).php artisan tinker against one router before touching the fleet API. If a single connection works, FleetManager is just iteration over the same driver.First use case to reach for: a scheduled health/audit command that loops the fleet and reports identity, uptime, RouterOS version, and interface status. It exercises credential resolution, per-router scoping, and error handling in one go — which is exactly the surface the scoping fixes in this release touched.
Fleet iteration for reporting. The natural FleetManager workflow is "resolve the list of routers from config, then run the same read-only operation against each." Wrap it in a queued job per router rather than a foreach in a command, so one unreachable device doesn't stall the run and you get retry semantics. Fan-out with Bus::batch() and keep the router name as the batch key so failures are attributable.
Scoped single-router access. The scoping fixes in v1.8.0 matter most when you have more than one router in config but want to act on exactly one. Prefer resolving a named router explicitly at the call site (Mikrotik::router('branch-office') style) over relying on a default connection — implicit defaults are what historically caused operations to land on the wrong device. Treat the router name as a required argument in your own service classes; don't let it be nullable.
Service wrapper, not facade-everywhere. Put a thin RouterService/FleetService in app/Services that owns credential lookup and router selection. Controllers and jobs then call domain methods (suspendHotspotUser($router, $user)) instead of the package facade. This keeps the package swappable and gives you one place to add logging, metrics, and tenant guards.
Multi-tenant / multi-site scoping. With FleetManager, the common real-world pattern is tenant → router mapping. Store the router key on the tenant/site model, resolve it once at request or job start, and pass it down. Because the fleet is now a first-class concept, do the authorisation check (can this user touch this router?) in the wrapper, not in the view. The scoping fixes make cross-router leakage less likely, but your own code should still never accept a router identifier straight from a request payload.
Mutations: idempotency and read-back. For writes (firewall rules, address lists, hotspot users, queue changes) do write → read-back → assert. RouterOS is eventually-consistent enough that a "successful" API call doesn't guarantee the entry exists as expected. Pair this with a Cache::lock("mikrotik:{$router}") per device if you have concurrent jobs — RouterOS dislikes parallel config writes.
Scheduling and observability. Schedule a fleet-wide poll every N minutes, write results to a router_status table, and alert on transition (up→down) rather than state. Log the router name and the RouterOS command in every exception context; you will need it. Wrap all fleet calls in try/catch that distinguishes connection/auth failure (retry later, mark device down) from API-level failure (bad command, surface immediately).
Bulk operations. For pushing a config template across the fleet, build a "desired state" array, diff it against a read of current state, and only apply the delta. With many routers this turns an N×M operation into something sane and makes dry-run mode trivial — worth having before you let FleetManager point at production.
league/commonmark bump is a security fix. v1.8.0 pulls 2.10.0 via Aikido. If you've pinned league/commonmark in your root composer.json (some apps do, for markdown rendering), the security fix won't apply — check composer why league/commonmark and let it float to ^2.10 if you can.composer update will drag the framework forward. Run the test suite; Laravel 12 minor bumps occasionally shift deprecation noise.vendor:publish. If config/mikrotik.php gained fleet/router-registry keys, your existing file won't have them — diff the package's config/mikrotik.php against yours after upgrading and merge by hand.spatie/ssh / raw RouterOS API output for a failing router before blaming the package. Most "the package is broken" reports turn out to be credentials, disabled API service on the device, or a firewall rule on port 8728/8729.How can I help you explore Laravel packages today?