# Page check

After each production release goes live, Nimbus Land loads your app's home page the way a visitor's browser does. If the page references its styles or scripts over plain HTTP, the browser will refuse to load them, and the app's **Overview** tells you. The page check runs for every app, with nothing to switch on. It is separate from [security scanning](security-scanning.md), which you turn on per app.

The usual cause is a framework that doesn't know the visitor used HTTPS. Nimbus Land handles HTTPS at its edge and forwards each request to your app over plain HTTP with the header `X-Forwarded-Proto: https`. A framework that doesn't trust that header builds `http://` URLs for its assets, and the browser blocks them on an HTTPS page. The page shows up unstyled even though the build, the release and the logs all look healthy.

## What is checked, and when

- **When.** Within about five minutes of a new production release going live, and whenever someone chooses **Check again** on the Overview.
- **Where.** The home page (`/`) on each public production address: the app's `nimbusapps.ca` address and, once verified, its [custom domain](custom-domains.md). Each address gets one HTTPS request, following at most three redirects that stay on that address.
- **What is reported.** An HTML page that loads a stylesheet, script, preload or module preload over `http://`. Images, media and links don't count, because browsers upgrade or tolerate them, and neither does `http://` text inside inline scripts or comments. A page whose content security policy includes `upgrade-insecure-requests` is fine, because the browser upgrades those URLs itself.
- **What is not checked.** Other pages, `fetch()` calls, fonts loaded from CSS, and anything past the first 64 KiB of the page. Apps that are stopped, have no live production release, or require sign-in are not checked. If the page times out, errors or redirects to another address, the result is "not checked" and nothing is shown.

Only the latest result for each address is kept: the outcome, when it ran, which release was checked, and up to three blocked URLs (without query strings). The page itself is read in memory and discarded. Results are visible to members of the app's organization and are deleted with the app.

## How the requests look to your app

Page check requests carry this user agent:

```
NimbusLand-SecurityScan/1 (page-check; +https://nimbusland.ca/docs/page-check)
```

They are left out of your app's Traffic and Analytics and never count toward the **Site down**, **Visitors seeing errors** or **Site slow** alerts.

## When styles or scripts are blocked

The Overview's **Needs attention** section shows **Page loads styles or scripts over HTTP**, with the first blocked URL, how to fix it and a link to the page. Members who can manage the app can choose **Check again** (once a minute). The fix depends on whose URL it is.

**Your app's own address.** Your framework doesn't trust the forwarded HTTPS header. Only Nimbus Land's edge can reach your app, so it is safe to trust every proxy:

- [PHP apps](php.md) without a `Procfile` (Laravel, Symfony, WordPress, plain PHP): deploy again. The web server Nimbus Land configures for these apps already marks HTTPS requests as HTTPS.
- Laravel with its own `Procfile`: `$middleware->trustProxies(at: '*')` in `bootstrap/app.php` (Laravel 11 and later), or `protected $proxies = '*';` in the `TrustProxies` middleware (Laravel 10).
- Django: `SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")` in your settings.
- Other frameworks: set their trusted-proxy option.

**Another site's address** (a CDN link, or a URL in a theme setting): change it to `https://`.

**A static site:** use `https://` or a relative path in the site's HTML.

If the fix doesn't need a new release (a setting or an environment variable change), choose **Check again**. The warning clears when the next check finds nothing blocked.
