Statamic URLs Showing Server IP Instead of Your Domain? Here's the Fix
You've deployed your Statamic site to production. Everything seems fine until you check your sitemap, or share a page, or look at any auto-generated URL—and it's showing your server's internal IP address instead of your actual domain.
http://192.168.1.50/blog/my-post
Instead of:
https://yourdomain.com/blog/my-post
If you're running behind RunCloud, Cloudflare, or any reverse proxy setup, this is almost certainly a trusted proxies issue.
A Note on Documentation
I want to be upfront: this issue is well-documented in Laravel's official documentation. The Configuring Trusted Proxies section covers exactly what's happening and how to fix it.
So why write this article?
Because when you're working primarily with Statamic—managing content, building templates, configuring blueprints—you're not necessarily thinking about Laravel middleware. Statamic does a great job of abstracting away most of the Laravel plumbing. You can build entire sites without touching bootstrap/app.php or thinking about HTTP request handling.
The problem surfaces when you deploy. Your local environment doesn't have a reverse proxy, so everything works. Then you push to production behind RunCloud or Cloudflare, and suddenly your sitemap has internal IPs, your Control Panel assets fail to load over HTTPS, and you're wondering what you broke.
This article exists to bridge that gap—to help Statamic developers who hit this issue recognise it as a Laravel configuration concern and point them to the right solution.
Why This Happens
When your application sits behind a reverse proxy (load balancer, CDN, managed hosting panel), it doesn't receive requests directly from the internet. The proxy forwards requests and adds special headers to communicate the original request details:
X-Forwarded-For— the client's real IP addressX-Forwarded-Host— the original domain requestedX-Forwarded-Proto— whether the original request was HTTP or HTTPSX-Forwarded-Port— the original port
By default, Laravel ignores these headers for security reasons. As the fideloper/TrustedProxy package documentation explains: the application needs to explicitly trust specific proxies before it will read these forwarded headers.
Without that trust configured, Laravel sees the proxy's internal request—not the original one from the user. This cascades into Statamic:
- Sitemap URLs generated by Statamic's SEO tools point to internal IPs
- Asset URLs in the Control Panel use HTTP instead of HTTPS
- Canonical URLs are wrong
- The
url()helper returns incorrect values throughout your templates
The Statamic GitHub discussions confirm this is a common issue for cloud deployments, with trusted proxies being the standard solution.
The Fix
Laravel's documentation provides the authoritative solution. In Laravel 11+ (which recent Statamic versions use), trusted proxies are configured in bootstrap/app.php:
use Illuminate\Http\Request;
->withMiddleware(function (Middleware $middleware): void {
$middleware->trustProxies(
at: '*',
headers: Request::HEADER_X_FORWARDED_FOR |
Request::HEADER_X_FORWARDED_HOST |
Request::HEADER_X_FORWARDED_PORT |
Request::HEADER_X_FORWARDED_PROTO
);
})
The at: '*' setting tells Laravel to trust all proxies. This is appropriate for most managed hosting scenarios where you don't know (or can't easily determine) your proxy's IP address.
Source: Laravel 12.x Documentation — Configuring Trusted Proxies
For Tighter Security
If your infrastructure allows it, you can specify exact proxy IPs instead of trusting all:
->withMiddleware(function (Middleware $middleware): void {
$middleware->trustProxies(
at: ['192.168.1.1', '10.0.0.0/8'],
headers: Request::HEADER_X_FORWARDED_FOR |
Request::HEADER_X_FORWARDED_HOST |
Request::HEADER_X_FORWARDED_PORT |
Request::HEADER_X_FORWARDED_PROTO
);
})
For Cloudflare specifically, they publish their IP ranges which you could hardcode. For most deployments behind managed services like RunCloud, DigitalOcean App Platform, or AWS load balancers, trusting all proxies is the practical choice.
After Deploying the Fix
Clear your caches to regenerate URLs with the correct domain:
php artisan cache:clear
php artisan config:clear
php artisan route:clear
php artisan statamic:stache:clear
If you're using Statamic's static caching, regenerate those pages too.
Statamic-Specific Symptoms
While the underlying cause is a Laravel configuration issue, the symptoms often manifest through Statamic features:
| Symptom | What's Happening |
|---|---|
| Sitemap shows internal IPs | Statamic's sitemap generator uses Laravel's URL helpers |
| CP assets fail to load (mixed content) | Asset URLs generated with HTTP instead of HTTPS |
| Canonical meta tags are wrong | SEO add-ons rely on correct URL generation |
| Glide image URLs use wrong domain | Image manipulation URLs inherit the incorrect base |
| Form redirects break | Post-submission redirects use internal addresses |
If you're seeing any of these after deploying to a managed hosting environment, trusted proxies should be your first check.
Common Deployment Scenarios
RunCloud + DigitalOcean
RunCloud manages your server and sits between users and your PHP application. It handles SSL termination—meaning HTTPS connections terminate at RunCloud, and your app receives HTTP requests internally. Without trusted proxies, Laravel thinks every request is HTTP.
Cloudflare
Cloudflare proxies your traffic for CDN and security benefits. Your server receives requests from Cloudflare's IP range, not from users directly. The original client information is in the X-Forwarded-* headers.
DigitalOcean App Platform
Similar to other PaaS offerings—your app runs behind their load balancers. The Statamic community has confirmed this requires trusted proxy configuration.
Laravel Forge
Even with Forge's streamlined deployment, if you're using a load balancer or CDN in front of your server, you'll need trusted proxies configured. Forge deploys to bare servers, so if you're accessing them directly (no proxy), you won't see this issue.
Verifying the Fix
After deploying and clearing caches:
-
Check your sitemap. Visit
/sitemap.xmland verify URLs use your domain with HTTPS. -
Test the
url()helper in Tinker:url('/test'); // Should return: https://yourdomain.com/test -
Check generated asset URLs. View page source and verify CSS/JS assets use the correct protocol and domain.
-
Test HTTPS detection:
request()->secure(); // Should return: true
The .env Side of This
Make sure your .env file has the correct APP_URL:
APP_URL=https://yourdomain.com
This is used as a fallback for artisan commands and queued jobs that don't have a request context. If this is wrong, some URL generation will still be incorrect even with trusted proxies configured.
Further Reading
- Laravel Documentation: Configuring Trusted Proxies — the authoritative source
- Symfony Documentation: How to Configure Symfony to Work behind a Load Balancer or a Reverse Proxy — Laravel builds on Symfony's HTTP foundation
- fideloper/TrustedProxy: GitHub Repository — historical context (now built into Laravel core)
- Statamic Discussions: CP routes served over HTTP — community confirmation of the issue
Summary
This isn't a Statamic bug or a gap in Statamic's documentation—it's standard Laravel behaviour that becomes relevant when you deploy behind a reverse proxy. The fix is well-documented in Laravel's official docs.
The reason it catches Statamic developers off guard is that you can work with Statamic extensively without ever touching Laravel's HTTP layer. Then you deploy to production, hit this issue, and don't immediately recognise it as a Laravel middleware concern.
If your Statamic site's URLs are showing internal IPs or HTTP instead of HTTPS after deployment: check trusted proxies first, and consult the Laravel documentation for the implementation details.
Deployment Giving You Headaches?
Book a free Discovery Audit and get expert guidance on your deployment challenges.
Book a Discovery Audit