hermeneus's avatar

Laravel Vite: Assets blocked/Mixed Content issues in production environment

I'm hosting my App on an EC2-instance behind an Elastic Load Balancer which manages my SSL-Certificate. On this EC2-Instance my nginx-configuration is redirecting all http-Requests to https. I recently switched to Vite which caused me a lot of trouble. When I push my app to the server after calling npm run build my assets are blocked. In the browser console I get:

Mixed Content: The page at 'domain.com' was loaded over HTTPS, but requested an insecure ...

My Setup:

vite.config.js

export default defineConfig({
    server: {
        host: 'localhost',
    },
    plugins: [
        laravel([
            'resources/assets/sass/app.sass',
            // etc...
        ]),
        vue({
            template: {
                transformAssetUrls: {
                    base: null,
                    includeAbsolute: false,
                },
            },
        }),
    ],
});

Setting "https: true" in the server-block didn't help me.

.env

APP_ENV=production
APP_URL=https://domain.com
ASSET_URL=https://domain.com

In my blade template I'm using the Vite-directive:

@vite('resources/assets/sass/app.sass')

I tried the following solutions:

  • Setting $proxies = '*' in TrustProxies.php, which doesn't have any effect.
  • Setting URL::forceScheme('https'); in AppServiceProvider.php, which will load the assets but lead to a lot of other issues.

Somehow the @vite-directive is not resolving my assets as secure assets. With Laravel Mix I could just call secure_asset.

How can I fix this?

0 likes
24 replies
hermeneus's avatar

@Sinnbeck TrustProxies.php

protected $proxies = '*';
protected $headers = Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_HOST | Request::HEADER_X_FORWARDED_PORT | Request::HEADER_X_FORWARDED_PROTO | Request::HEADER_X_FORWARDED_PREFIX | Request::HEADER_X_FORWARDED_AWS_ELB;
2 likes
dikhimartin's avatar

@Sinnbeck This worked for me – thank you!

I really appreciate it, man. I hadn't set up TrustProxies in my project either, and that turned out to be the missing piece.

At first, I was really confused because my setup was working fine in some environments but not in others. Specifically:

  • ✅ It worked on my virtual server behind a load balancer.
  • ✅ It also worked when I deployed it to a static shared hosting with an Apache web server.
  • ❌ However, when running it wit h Nginx inside a Docker container, I kept running into Mixed Content issues, where assets were blocked due to being loaded over HTTP instead of HTTPS.

Solution: Configuring Trusted Proxies in Laravel 11

The key was properly configuring trusted proxies in Laravel. Since I'm using Laravel 11, I needed to set up a custom middleware for this.

Here’s what I did:

1️⃣ Create a new middleware file in:

app/Http/Middleware/TrustProxies.php

2️⃣ Update the middleware with the correct proxy headers:

<?php

namespace App\Http\Middleware;

use Illuminate\Http\Request;
use Fideloper\Proxy\TrustProxies as Middleware;

class TrustProxies extends Middleware
{
    protected $proxies = '*';

    protected $headers = Request::HEADER_X_FORWARDED_FOR |
                         Request::HEADER_X_FORWARDED_HOST |
                         Request::HEADER_X_FORWARDED_PORT |
                         Request::HEADER_X_FORWARDED_PROTO |
                         Request::HEADER_X_FORWARDED_PREFIX |
                         Request::HEADER_X_FORWARDED_AWS_ELB;
}

3️⃣ Register the middleware in app/Http/Kernel.php:

protected $middleware = [
    // Other middlewares...
    \App\Http\Middleware\TrustProxies::class,
];
1 like
Sinnbeck's avatar

Did you try recompiling with npm after adding

ASSET_URL=https://domain.com
5 likes
threeel's avatar

if you try to enforce it in the env that you want?

class AppServiceProvider extends ServiceProvider
{
    
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        if($this->app->environment('production')) {
            URL::forceScheme('https');
        }
    }
}
1 like
hermeneus's avatar

My problem was that I didnt have TrustedProxies.php in my middleware-folder but used the one in my vendor-folder. Which means that everytime I ran a Laravel update, my TrustedProxies.php was overwritten by the standard values.

TrustedProxies.php was moved to Middleware-folder in Laravel version 8 or so.

2 likes
bfuze's avatar

In the spirit of sharing I wanted to post my solution because I've run into this many times and none of the Vite related solutions helped. My use case is that I'm using Vite to compile assets. The site itself does not require Vite to run, but the @vite blade directive does not provide a way (afaik) to specify secure assets. Locally, I use DDev and would not encounter this issue, but when I moved the site to a cloud environment I would get the error: "The page at was loaded over HTTPS, but requested an insecure stylesheet". The solution for me was to add the following to the Apache virtualhost config for port 80 (and 443 if you want):

<VirtualHost *:80>
    RewriteEngine On
    RewriteCond %{HTTP:X-Forwarded-Proto} =https
    RewriteCond    %{DOCUMENT_ROOT}%{REQUEST_FILENAME} -d
    RewriteRule    ^(.+[^/])$           https://%{HTTP_HOST}/ [redirect,last]
    SetEnvIf X-Forwarded-Proto "https" HTTPS=on
</VirtualHost>

See also

DDev also puts this in :443 config, but I'm not sure that is necessary unless your site uses explicit insecure URLs. For me adding to :80 was all that was required. Hope this helps.

1 like
Macclinson's avatar

If you encounter a similar issue in the future while hosting a Laravel application with Vite as the compiler, follow these steps after building for production:

  1. Navigate to the 'public' folder in your Laravel project.
  2. Look for a folder named 'hot' within the 'public' directory.
  3. Delete the 'hot' folder.
  4. Once the 'hot' folder is deleted, your application should work correctly without any issues related to the Vite compiler."
7 likes
jsampson's avatar

@Macclinson This is what worked for me. Problem is the hot file keeps coming back and I have to constantly delete it. Is there a way to prevent that?

1 like
haifan420's avatar

for anyone wondering, this 'hot' file was generated from npm run dev, so probably some of you forgot to stop the dev server when moving your project folder to prod

jedjose's avatar

I am also encountering this issue, any fixes? Mixed Content: The page at 'domain.com' was loaded over HTTPS, but requested an insecure stylesheet '...css'. This request has been blocked; the content must be served over HTTPS.

1 like
jedjose's avatar

fixed it, I was solving this issue for about a day. If someone was having the same issue as mine, apparently what I did was to configure the default listener on load balancer (port 80) to redirect all http request to https.

1 like
jbarmanet's avatar

Just in case someone lands here for Laravel 11, where the TrustProxies.php file does not exist anymore, you can achieve @hermeneus proxy fix into bootstrap/app.php :

return Application::configure(basePath: dirname(__DIR__))
    // Your code…
    ->withMiddleware(function (Middleware $middleware) {
        $middleware->trustProxies(headers: Request::HEADER_X_FORWARDED_FOR |
            Request::HEADER_X_FORWARDED_HOST |
            Request::HEADER_X_FORWARDED_PORT |
            Request::HEADER_X_FORWARDED_PROTO |
            Request::HEADER_X_FORWARDED_AWS_ELB
        );
        $middleware->trustProxies(at: '*');
       // Rest of your code… ```
2 likes
Passioncorners's avatar

This seems to work for me on Laravel 11 in AppServiceProvider.php. This is the only file that I needed to update.

    public function register(): void
    {
        if ($this->app->environment('production') || $this->app->environment('dev')) {
            URL::forceScheme('https');
        }
    }

4 likes

Please or to participate in this conversation.