NGrok and Laravel

Stefan Bogdanescu

Founder & Senior Architect · 2026-06-29

Laravel Company

Bridging the Gap: Solving Ngrok URL Mismatches in Local Laravel Development

Deploying a local Laravel application to the internet using tools like ngrok is an incredibly useful step for testing, demonstrating features, or getting early feedback. However, as you’ve discovered, bridging the gap between your local development environment (like Laragon/Apache) and the public tunnel provided by ngrok often introduces frustrating issues, particularly concerning asset linking and routing.

This post dives deep into why this happens and provides a robust, developer-centric solution to ensure your Laravel application correctly serves content through the ngrok tunnel.

The Root of the Problem: Local vs. Public Context

The core issue stems from how Laravel is configured by default. When you develop locally, Laravel assumes it is running on http://localhost or site.dev. Any resource requests—whether for CSS files, images, or route generation—are based on this local context.

When you run ngrok http -host-header=rewrite site.dev:80, ngrok creates a secure tunnel that maps an external address (e.g., http://xxxxxx.ngrok.io) to your local server. However, the application itself still references its internal development domain (site.dev), leading to broken links and incorrect routing results when accessed via the public ngrok URL.

The Solution: Setting the Application Base URL

The correct approach is not to rely on low-level Apache configuration files (like httpd.conf) for application routing, but rather to inform the Laravel framework itself what its public base URL is. This ensures that all generated URLs and asset paths are relative to the external tunnel.

We need to explicitly tell Laravel what the public domain is so it can generate correct absolute links.

Step 1: Configure the Environment Variables

The most critical step is setting the application's base URL within your environment configuration. This allows Laravel’s helpers (like asset() or route generation) to prepend the ngrok address instead of site.dev.

In your .env file, you should define the public URL:

dotenv
APP_URL=http://number.ngrok.io

Replace number.ngrok.io with the actual dynamic address provided by your ngrok session. This variable acts as the single source of truth for all external references in your application.

Step 2: Verifying Application Configuration

While setting APP_URL in .env is usually sufficient, it’s good practice to verify how Laravel interprets this within its core configuration. For modern Laravel applications, these settings are managed by the framework's conventions, which aligns with best practices outlined by teams working on frameworks like those found at laravelcompany.com.

If you were manually overriding paths, you might check config/app.php to ensure no conflicting base URLs are defined, though typically, environment variables take precedence.

Resolving Asset and Routing Issues

Once you have set the APP_URL, Laravel should automatically adjust its behavior.

Fixing Asset Linking (CSS/Images)

If your assets were linking to site.dev/css/app.css, they will now correctly resolve to http://number.ngrok.io/css/app.css. Ensure you are using Laravel's built-in asset helpers:

Incorrect (Local Context):

html
<link href="/css/app.css" rel="stylesheet">

Correct (Using Blade Helpers):

html
<link href="{{ asset('css/app.css') }}" rel="stylesheet">

Fixing Routing

The same principle applies to route generation. When you use route('ngo'), Laravel will now prepend the configured APP_URL to generate the correct external link:

Incorrect (Local Context):

php
return site.dev . '/ngo'; // Or using route() without base setup

Correct (Using Route Helper with Base URL set):

php
// Assuming APP_URL is set in .env
return route('ngo'); // Laravel will generate: http://number.ngrok.io/ngo

Conclusion

Dealing with local development tunnels requires shifting focus from low-level server configuration to application-level configuration. By correctly setting the APP_URL in your environment variables, you empower Laravel to manage all external references automatically. This method is cleaner, more resilient, and adheres better to the principles of building scalable applications, which is a fundamental concept when developing with frameworks like Laravel. Use this approach to ensure your local testing seamlessly translates into a publicly accessible demonstration.