websites monitoring CyberApis - Changelog #6

Cyberapis v0.13.0 — cyberapis.pl domain, Cloudflare, and dark mode

Cloudflare + Laravel — how not to lose requests behind a proxy

Placing a Laravel application behind Cloudflare introduces an intermediary layer that changes everything the app knows about an incoming request. The client's IP address disappears — replaced by Cloudflare's IP. The protocol (HTTP vs HTTPS) may differ on the origin side from what the browser sees. And the port? Symfony's Request::getPort() tries to read it from X-Forwarded-Port or X-Forwarded-Host headers — if Nginx doesn't forward them (or forwards them empty), the app gets a 500.

The solution is trustProxies() — but done carefully. Trusting '*' works but is dangerous on shared hosts. In Cyberapis v0.13.0, we configured trust for specific headers only: FOR (X-Forwarded-For), PROTO (X-Forwarded-Proto), PREFIX (X-Forwarded-Prefix), and HEADER_X_FORWARDED_AWS_ELB. We deliberately exclude HOST and PORT, which with empty values from Nginx were causing Symfony errors.

The cyberapis.pl domain now operates through Cloudflare (AAAA IPv6 to Mikrus VPS), and the application correctly identifies real client IPs, protocol, and no longer throws 500s on empty X-Forwarded headers.

New Features

cyberapis.pl domain via Cloudflare

DNS configuration: AAAA IPv6 to Mikrus VPS, SSL Flexible on Cloudflare. trustProxies('*') in bootstrap/app.php configured for Cloudflare headers.

Frontend documentation

docs/FRONTEND_CONTEXT.md — describing the public layout, footer structure, Tailwind/CSS pitfalls, link audit notes, and production deploy status.

Tailwind v4 — @plugin @tailwindcss/typography

Support for prose and dark:prose-invert in app.css — essential for correct blog article content rendering.

Bug Fixes

Production HTTP 500 behind Cloudflare

Empty X-Forwarded-Host / X-Forwarded-Port from Nginx caused Symfony Request::getPort() errors. trustProxies now trusts only FOR, PROTO, PREFIX, and AWS ELB headers — not empty host/port.

Dark mode for /docs/* pages

Replaced dark:bg-gray-900/dark:text-white (which didn't work due to Tailwind build ordering) with explicit .docs-page-section/.docs-content rules in style.css — the same pattern used for blog and legal pages.

Dark mode — monitoring table

Font colors were too dark on a dark background. Added explicit .dark .monitoring-list rules.

Monitoring pause mode — frontend indicator

The public page showed "Check in progress…" instead of the pause indicator. getNextCheckIsoAttribute() now returns null when is_paused, and countdown.js shows the translated pause message.

Footer in light mode

Explicit background colors in style.css, since Tailwind bg-gray-* classes were sometimes missing from the production CSS bundle.

External confirmation — curl --fail

The callback curl in GitHub Actions now uses the --fail flag, so HTTP 4xx/5xx responses fail the workflow step.

Render probe — Chrome cleanup scoped

Cleanup limited to the current ephemeral profile; lock/job overlap timeout raised to 420s. CSS timing artifacts stored as informational successes (not false alerts).

Changes & Improvements

Monitoring table — unified frontend/backend

HTML table layout with monitoring-* CSS classes unified with the Filament view. Pause indicator, 60-second countdown grace window.

Footer — new two-row layout

Top row gray-900 (logo + link columns), bottom row gray-950 (copyright + version). Accent top edge via .site-footer::before in style.css.