robertboes/laravel-cloudflare-proxies
Laravel package for handling Cloudflare proxy IPs so your app sees the real visitor IP. It helps configure trusted proxies and resolve client addresses correctly behind Cloudflare, keeping rate limiting, logging, and security checks accurate.
Architecture fit. The package is a narrow, single-concern Laravel add-on that sits at the HTTP boundary: it participates in trusted-proxy / client-IP resolution and re-evaluates its proxy list at runtime rather than only at boot. That makes it a leaf dependency — no domain model, no persistence, no queue or event surface. Architecturally it is cheap to adopt and cheap to remove, which is the main reason it is worth evaluating at all at v0.1.x.
Integration feasibility. Adoption appears to be composer install plus a publishable config, with behaviour gated behind a refresh flag. There are no migrations and no data-model coupling. The compatibility claim in v0.1.1 — working "on every Symfony version" allowed by Laravel 12 — is the important part: it implies the package spans multiple Symfony minors whose IP-classification constants differ, and it has now normalised that difference itself instead of inheriting it.
Technical risk. Three risks dominate, in order:
X-Forwarded-For spoofing (client-IP-based rate limits, audit logs, IP allowlists, and sometimes session/geo logic all inherit the forged value). Too restrictive a list silently breaks legitimate traffic. Both failure directions are quiet, not loud.IpUtils::PRIVATE_SUBNETS, which does not include 100.64.0.0/10 (carrier-grade NAT) or the documentation ranges on the Symfony versions Laravel 12 permits. On those versions, CGNAT addresses would have been treated as publicly routable and therefore acceptable as trusted proxies — an over-permissive default that only manifests on some dependency combinations. That is a correctness and security fix, not a feature.Key questions.
refresh re-resolve on every request, on a schedule, or on cache miss? This drives both latency and the staleness failure mode.Confidence is low: this assessment is derived from a single release note and the package's observable surface, not from source review.
Stack fit. Targets Laravel 12 and the Symfony 7.x line Laravel 12 allows. Because the pre-fix behaviour varied by Symfony minor, the package's own compatibility statement is the thing to verify, not assume — "works on every Symfony version" is a claim a TPM should ask to see proven in CI before it is relied on.
Migration path. There is no incumbent to migrate from. The practical path is: add as a direct dependency with an explicit version pin, keep refresh disabled by default in config/, and enable it per-environment. Treat the pin as temporary scaffolding to be revisited once a 1.0 lands or the maintainer's release cadence is observable.
Compatibility. Two compatibility checks matter more than the composer solver:
100.64.0.0/10. This is not hypothetical: some cloud NAT gateways, container overlay networks, and ISP-side NAT present client or hop addresses in CGNAT space. If a real hop sits there, v0.1.1 will reject it and the fix becomes a regression for that deployment.Also flag the documentation ranges (192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24, 2001:db8::/32). Rejecting them is correct in production, but any internal fixtures, seeds, or staging harnesses built on TEST-NET addresses will change behaviour after upgrade.
Sequencing.
100.64.0.0/10, 192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24, and 2001:db8::/32 are rejected as trusted proxies, plus that genuine RFC1918 hops are still accepted.refresh in staging and observe resolved client IPs for a full traffic cycle, including at least one proxy rotation.refresh on for a subset, watching for shifts in client-IP distribution.Maintenance. Expect churn. A package at 0.1.1 with a security-relevant fix in its second release has no track record of API stability; budget for reading every changelog and re-running the compatibility matrix on each bump. Assign an internal owner — this is not a "set and forget" dependency because its failure mode is silent.
Support. Likely a small or single-maintainer project. Assume community-only support, no SLA, and no guaranteed CVE turnaround. The mitigation is keeping the surface small (one config file, one flag) so the package can be replaced with a few dozen lines of in-house IP classification if it goes stale. That exit path should be written down, not assumed.
Scaling. Compute cost is negligible. The scaling question is refresh frequency: if the list re-resolves per request, it adds latency and, worse, introduces a per-request dependency on whatever upstream the refresh consults. Prefer resolve-on-cache-miss with a bounded TTL. The trusted-proxy list is also per-node state, so in a horizontally scaled fleet different nodes can briefly disagree during a rotation — worth knowing before debugging an inconsistent-IP incident.
Failure modes.
X-Forwarded-For spoofing. This is the reason to upgrade rather than defer.Ramp-up. Low for a Laravel developer to install; moderate to operate correctly. The package itself is simple — the difficulty is that trusted-proxy semantics are widely misunderstood, and this package's whole value proposition is getting a subtle part of them right. Budget half a day for the installing engineer plus a short runbook covering: which addresses are trusted and why, how to verify the resolved client IP, what the refresh cadence is, and how to disable refresh under pressure. The v0.1.1 upgrade is worth taking specifically because it closes a version-dependent over-permissiveness — but only after confirming no real hop lives in the address ranges it now rejects.
How can I help you explore Laravel packages today?