anjanesh's avatar

Multi Sites Network

I want to create a multi-site application in Laravel 12.

domain1.com, domain2.com, domain3.com ... domainN.com will all point to the same laravel app on my server with each site showing different content based on the domain name.

Django's "sites framework" out of the box provides this functionality - whats the Laravel equivalent of this ?

1 like
2 replies
LaryAI's avatar
Level 58

To create a multi-site application in Laravel where different domains point to the same application but display different content based on the domain, you can follow these steps:

  1. Domain Routing: Use Laravel's routing capabilities to handle different domains. You can use the Request facade to determine the current domain and route requests accordingly.

  2. Middleware: Create a middleware to detect the domain and set configurations or load specific data based on the domain.

  3. Database Structure: You might want to have a sites table in your database to store information about each site, such as domain name, settings, and any other site-specific data.

  4. Service Provider: Use a service provider to bind site-specific configurations or services based on the domain.

Here's a basic example to get you started:

  1. Create Middleware: Generate a middleware to handle domain-specific logic.

    php artisan make:middleware DomainMiddleware
    
  2. Middleware Logic: In the handle method of your middleware, determine the domain and set configurations.

    namespace App\Http\Middleware;
    
    use Closure;
    use Illuminate\Http\Request;
    use App\Models\Site;
    
    class DomainMiddleware
    {
        public function handle(Request $request, Closure $next)
        {
            $host = $request->getHost();
            $site = Site::where('domain', $host)->first();
    
            if (!$site) {
                abort(404, 'Site not found');
            }
    
            // Set site-specific configurations
            config(['app.site' => $site]);
    
            return $next($request);
        }
    }
    
  3. Register Middleware: Register your middleware in app/Http/Kernel.php.

    protected $middlewareGroups = [
        'web' => [
            // Other middleware
            \App\Http\Middleware\DomainMiddleware::class,
        ],
    ];
    
  4. Routing: Use routes to handle requests. You can use the domain information from the middleware to load different views or controllers.

    Route::get('/', function () {
        $site = config('app.site');
        return view('welcome', ['site' => $site]);
    });
    
  5. Database Table: Create a sites table to store domain-specific data.

    Schema::create('sites', function (Blueprint $table) {
        $table->id();
        $table->string('domain')->unique();
        $table->string('name');
        $table->timestamps();
    });
    
  6. Service Provider: Optionally, create a service provider to bind services or configurations based on the domain.

This setup allows you to handle multiple domains with a single Laravel application, similar to Django's sites framework. You can expand this by adding more domain-specific logic, such as loading different themes, configurations, or content.

martinbean's avatar

@anjanesh Subdomain routing. Although it’s a misnomer as you can use this for top-level domain routing; I do exactly this in a multi-tenant CMS I have which shows a different website and content based on the domain name used to access the application:

Route::domain('{website:domain}')->group(function () {
    // Website routes...
});

This will look up a Website model based on its domain attribute, and inject it in to controller actions in this route group.

For example, given the route:

Route::domain('{website:domain}')->group(function () {
    Route::get('articles', [ArticleController::class, 'index');
});

The corresponding controller and action would look like this:

class ArticleController extends Controller
{
    public function index(Website $website)
    {
        $articles = $website->articles()->latest()->paginate();

        return view('website.article.index')->with([
            'articles' => $articles,
        ]);
    }
}

Because the Website model instance is injected as a route parameter, you can then query related records through its relations without having to using horrible global scopes that other people may suggest.

Please or to participate in this conversation.