Laravel 12 Domain Redirect: Multiple Domains to New Domain (with SSL/Certbot Support)

Laravel 12 Domain Redirect: Multiple Domains to New Domain (with SSL/Certbot Support)

Abishek R Srikaanth

Sat, Jan 17, 2026

When your company goes through a rebrand or domain migration, one of the most critical technical tasks is ensuring all traffic from old domains seamlessly redirects to your new domain. But there's a catch: if you're not careful, you can break SSL certificate validation and prevent Certbot from renewing your certificates.

In this guide, I'll show you how to create a Laravel 12 global middleware that handles multiple old domain redirects while keeping Certbot happy.

The Challenge

We needed to accomplish several things:

  1. Redirect all traffic from multiple old domains to a single new domain

  2. Preserve the entire URL structure (paths and query parameters)

  3. Use 301 (permanent) redirects for SEO benefits

  4. Allow Certbot/Let's Encrypt validation requests to pass through without redirection

  5. Make it work globally across the entire Laravel application

The Solution: A Custom Global Middleware

Laravel 12's middleware system is perfect for this use case. Here's the complete middleware implementation:

Step 1: Create the Middleware

Create a new file at app/Http/Middleware/RedirectToNewDomain.php:

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class RedirectToNewDomain
{
    /**
     * The old domains to redirect from
     */
    protected array $oldDomains = [
        'old-domain.com',
        'www.old-domain.com',
        'another-old-domain.com',
        'www.another-old-domain.com',
    ];

    /**
     * The new domain to redirect to
     */
    protected string $newDomain = 'new-domain.com';

    /**
     * Handle an incoming request.
     *
     * @param  \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response)  $next
     */
    public function handle(Request $request, Closure $next): Response
    {
        // Allow Certbot validation requests to pass through
        if ($this->isCertbotRequest($request)) {
            return $next($request);
        }

        // Check if the request is coming from any of the old domains
        if (in_array($request->getHost(), $this->oldDomains)) {
            // Build the new URL with the same path and query parameters
            $newUrl = $request->getScheme() . '://' . $this->newDomain . $request->getRequestUri();
            
            // Perform a 301 permanent redirect
            return redirect($newUrl, 301);
        }

        return $next($request);
    }

    /**
     * Determine if the request is from Certbot for SSL validation
     */
    protected function isCertbotRequest(Request $request): bool
    {
        // Check if the request path starts with /.well-known/acme-challenge/
        if ($request->is('.well-known/acme-challenge/*')) {
            return true;
        }

        // Optional: Also check User-Agent for Certbot
        $userAgent = $request->userAgent();
        if ($userAgent && str_contains(strtolower($userAgent), 'certbot')) {
            return true;
        }

        return false;
    }
}

Step 2: Register the Middleware Globally

In Laravel 12, middleware registration happens in bootstrap/app.php. Open that file and add your middleware using the prepend() method:

<?php

use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;

return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        commands: __DIR__.'/../routes/console.php',
        health: '/up',
    )
    ->withMiddleware(function (Middleware $middleware) {
        // Domain redirect middleware - runs first
        $middleware->prepend(\App\Http\Middleware\RedirectToNewDomain::class);
    })
    ->withExceptions(function (Exceptions $exceptions) {
        //
    })->create();

Step 3: Configure Your Domains

Update the $oldDomains array with all your legacy domains and set the $newDomain to your new domain:

protected array $oldDomains = [
    'youroldsite.com',
    'www.youroldsite.com',
    'legacy-brand.com',
    'www.legacy-brand.com',
];

protected string $newDomain = 'yournewsite.com';

How It Works

The middleware operates with a simple but effective logic flow:

  1. Certbot Check First: Before doing anything else, it checks if the request is from Certbot by examining the URL path (.well-known/acme-challenge/*) and optionally the user agent. If it's a Certbot request, it allows it through without redirection.

  2. Domain Matching: It checks if the incoming request's host matches any domain in the $oldDomains array.

  3. URL Preservation: If there's a match, it constructs a new URL using the same scheme (HTTP/HTTPS), the new domain, and the complete request URI (which includes the path and all query parameters).

  4. 301 Redirect: It performs a permanent redirect (301) to signal to search engines that this is a permanent move.

Why Use prepend() Instead of append()?

When registering the middleware, we use prepend() rather than append(). This ensures the redirect happens as early as possible in the request lifecycle, before other middleware processes the request. This is more efficient and prevents unnecessary processing of requests that will ultimately be redirected anyway.

Making It Environment-Aware (Optional)

If you want to make the domains configurable via environment variables, you can modify the middleware constructor:

protected array $oldDomains;
protected string $newDomain;

public function __construct()
{
    $this->oldDomains = explode(',', config('app.old_domains', 'old-domain.com'));
    $this->newDomain = config('app.new_domain', 'new-domain.com');
}

Then add to config/app.php:

'old_domains' => env('OLD_DOMAINS', 'old-domain.com,www.old-domain.com'),
'new_domain' => env('NEW_DOMAIN', 'new-domain.com'),

And in your .env file:

OLD_DOMAINS="oldsite.com,www.oldsite.com,legacy.com"
NEW_DOMAIN="newsite.com"

Testing Your Implementation

To verify everything works correctly:

  1. Test redirects: Visit your old domains and confirm they redirect to the new domain with paths and query parameters intact.

    • Example: http://old-domain.com/blog/post?id=123 should redirect to http://new-domain.com/blog/post?id=123

  2. Test Certbot: Ensure SSL certificate renewal still works by checking that /.well-known/acme-challenge/ requests on old domains are not redirected.

  3. Check redirect type: Use browser developer tools or a tool like curl -I to confirm the response code is 301 (permanent redirect).

SEO Considerations

Using 301 redirects is crucial for maintaining your search engine rankings. This tells search engines that:

  • The move is permanent

  • All link equity should transfer to the new domain

  • The old URLs should be replaced with new ones in their index

Make sure to also update your Google Search Console and other webmaster tools to reflect the domain change.

Conclusion

With this simple middleware solution, you can handle complex multi-domain redirects in Laravel 12 while maintaining SSL certificate functionality. The implementation is clean, maintainable, and follows Laravel best practices.

The key takeaways:

  • Use global middleware for domain-wide redirects

  • Always preserve URL structure for user experience and SEO

  • Protect Certbot validation paths to maintain SSL certificates

  • Use 301 redirects for permanent domain changes

  • Register the middleware with prepend() for early execution

Have you implemented domain redirects in Laravel? What challenges did you face? Let me know in the comments below!

CONTACT US

Get in touch and let us know how we can help

Name *
Email *
Phone *
WorkDoneRight Logo
Copyright 2026 WorkDoneRight | Privacy Policy