Why Bagisto Needs More Than a Certificate

Installing a Let's Encrypt certificate is only the first step toward a working HTTPS storefront. Bagisto is built on Laravel, which means nearly every generated link — product images, CSS and JS bundles under /public/themes and /public/vendor, the checkout form action, password-reset emails, and the admin panel at /admin — is produced by helper functions such as asset(), url(), and route(). Those helpers read their scheme and host from the application configuration, not from the browser's address bar. If the stored configuration still points at http://, Bagisto will happily serve pages over a padlocked connection while emitting insecure asset references, and the browser will block them.

The practical result is a storefront that looks broken even though the certificate is valid: unstyled pages because the CSS was blocked, non-functional AJAX cart updates, and a checkout step that silently fails. On the Hostiso stack — LiteSpeed in front of PHP on CloudLinux/AlmaLinux — there is an additional wrinkle. LiteSpeed frequently terminates TLS and passes the request to PHP with the original connection details carried in forwarded headers. If Laravel does not trust those headers, Request::isSecure() returns false, url() downgrades to http://, and redirect loops appear because the application keeps trying to "upgrade" a request it believes is insecure.

Because you are operating as an unprivileged hosting user, every fix here lives inside your account: the AutoSSL/Let's Encrypt panel, the Bagisto .env file, the config/ cache, .htaccess in public_html, and .user.ini. No server daemons, virtual host files, or global settings are involved. Understanding where each URL originates is what turns a confusing "HTTPS doesn't work" ticket into three precise edits.

Issuing the Certificate and Forcing HTTPS

Start with the certificate. In cPanel Jupiter, open Security → SSL/TLS Status, tick the storefront domain and any www or store subdomains used by your Bagisto channels, then choose Run AutoSSL. On DirectAdmin Evolution, go to Account Manager → SSL Certificates, select Free & automatic certificate from Let's Encrypt, and include every hostname your channels resolve to. If you run Bagisto across multiple subdomains, each one needs coverage or that channel will throw a certificate-name-mismatch warning. Allow a few minutes for DNS validation; AutoSSL retries hourly if a hostname is not yet pointed at the server.

Once the certificate is active, redirect all HTTP traffic. Bagisto's document root should be the public directory, so the .htaccess you edit lives at public_html/.htaccess (or the subdomain's public folder). Add the redirect above Laravel's existing rewrite block so it runs first:

<IfModule mod_rewrite.c>
    RewriteEngine On

    # Force HTTPS (LiteSpeed sets HTTPS=on after TLS termination)
    RewriteCond %{HTTPS} !=on [OR]
    RewriteCond %{HTTP:X-Forwarded-Proto} !https
    RewriteCond %{HTTP_HOST} ^(.*)$ [NC]
    RewriteRule ^(.*)$ https://%1/$1 [R=301,L]

    # Bagisto / Laravel front controller
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ index.php [L]
</IfModule>

The double condition matters on LiteSpeed: checking both %{HTTPS} and X-Forwarded-Proto covers setups where TLS is terminated upstream and the backend connection arrives as plain HTTP with the real scheme in a header. Without the second condition you can create an infinite redirect — the browser is already on HTTPS, but PHP sees HTTP and bounces it again.

If you prefer to enforce HTTPS at the panel level, cPanel's Domains interface exposes a Force HTTPS Redirect toggle per domain. That is fine for simple sites, but keep it consistent with your .htaccess — enabling both an aggressive panel redirect and a broad rule can double-hop requests. Pick one authoritative place for the redirect and leave the other neutral.

APP_URL, Proxy Trust, and Clearing the Config Cache

With the certificate issued and redirects in place, point Bagisto at the correct canonical URL. Open File Manager, navigate to the Bagisto root (one level above public), enable Show Hidden Files, and edit .env. The scheme here feeds every generated link:

APP_URL=https://yourstore.com
ASSET_URL=https://yourstore.com
SESSION_SECURE_COOKIE=true

Setting ASSET_URL explicitly stops Bagisto from guessing the scheme for theme and vendor assets, and SESSION_SECURE_COOKIE=true ensures the session cookie carries the Secure flag so it is never transmitted over plain HTTP. Next, make Laravel trust the LiteSpeed forwarding headers. Bagisto ships with App\Http\Middleware\TrustProxies in app/Http/Middleware/TrustProxies.php. Edit it so the proxy list is permissive for the local reverse setup and all forwarded headers are honored:

protected $proxies = '*';

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

With trusted proxies configured, Request::isSecure() correctly returns true when the X-Forwarded-Proto: https header is present, and the generated URLs stop downgrading. The change is inert until you clear Laravel's cached configuration, which is the step most often forgotten on shared hosting where there is no SSH prompt. Create a small maintenance route or use the scheduled-cron approach, but the simplest account-level method is a one-off PHP file placed temporarily in the Bagisto root:

<?php
require __DIR__.'/vendor/autoload.php';
$app = require __DIR__.'/bootstrap/app.php';
$kernel = $app->make(Illuminate\Contracts\Console\Kernel::class);
$kernel->call('config:clear');
$kernel->call('cache:clear');
$kernel->call('view:clear');
$kernel->call('route:clear');
echo 'Caches cleared';

Run it once in the browser, confirm the output, then delete the file immediately so it is not left exposed. Deleting the file is a small security hygiene step in the same spirit as the broader hardening advice in our Sentrifugo security hardening guide. If your PHP version was recently switched in cPanel → MultiPHP Manager or DirectAdmin → PHP Selector, re-run the script afterward, since the opcode and config caches are tied to the active interpreter.

Clearing Mixed Content and Verifying the Result

Even with correct configuration, legacy data can keep the padlock broken. Bagisto stores absolute URLs in a few places: product and category descriptions edited in the WYSIWYG, CMS pages under Admin → CMS → Pages, theme customization blocks, and channel logo/favicon paths under Admin → Configuration → General → Channels. If any of those contain hardcoded http://yourstore.com/... references, the browser flags mixed content regardless of your .env. Open each channel in the AdminCP and re-save the logo and image fields so Bagisto rewrites them against the new secure base URL.

For content stored in the database, use phpMyAdmin rather than guessing. Back up first with Export → Quick → SQL, then run a targeted update against the tables that hold HTML, for example:

UPDATE cms_pages
SET html_content = REPLACE(html_content, 'http://yourstore.com', 'https://yourstore.com');

UPDATE core_config
SET value = REPLACE(value, 'http://yourstore.com', 'https://yourstore.com')
WHERE value LIKE 'http://yourstore.com%';

Keep the search string fully qualified with your own domain so you never rewrite legitimate external links to third-party sites. As a defensive layer for any remaining references in templates you cannot easily edit, add an upgrade directive to the storefront .htaccess so browsers attempt HTTPS before reporting a block:

<IfModule mod_headers.c>
    Header always set Content-Security-Policy "upgrade-insecure-requests"
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
</IfModule>

Introduce HSTS only after you are confident every hostname has a valid certificate and HTTPS is stable, because the max-age directive instructs browsers to refuse plain HTTP for that duration. To verify, open the storefront in a private window, trigger the browser console, and reload. A clean result shows no "Mixed Content" warnings, assets loading from https://, and the cart and checkout AJAX calls returning 200 responses. Check /admin as well, since the panel's grid and media manager make heavy use of generated asset URLs. If something still downgrades, inspect storage/logs/laravel.log and your account's error_log for URL-generation or session-cookie warnings, which usually point back to a stale config cache or a missed hardcoded value. Working through issuance, APP_URL and proxy trust, then mixed-content cleanup in that order resolves nearly every Bagisto HTTPS case without touching anything above your hosting account.