How to create and manage subdomains in Laravel applications

Overview

Modern web applications usually perform more than one function. They often have:

  • more than one section
  • more than one service
  • a couple of clients

However, the more functionality the app has, the clumsier the route paths will be.

When are subdomains necessary?

Subdomains allow you to separate parts of your web application into smaller components with cleaner routes. Users can easily access and use subdomains independently, all under the same website.

What is a Subdomain?

Wikipedia defines a subdomain as follows:

In the DNSDomain Name System hierarchy, a subdomain is part of another domain.

For example, if a domain offers an online store as part of their website, example.com, it might use the subdomain shop.example.com.

Let’s say you have a website called mysite.com. You have a blog section, a store section, and a general website section for about and contact pages.

The website could have subdomains such as blog.mysite.com and store.mysite.com, and the main website would use the main domain.

Advantages of subdomains

  • Users can easily remember your website domains, which means they’ll be more likely to use your site.

  • The ability to split your large application into smaller groups, so it is easier to manage, debug, and update or upgrade.

  • Subdomains also allow for personalization — for example, a blog app could give each user their own subdomain (like username.domain.com).

  • Subdomains also let developers test versions of their applications before pushing them to production.

You can use beta.site.com to preview changes before deploying them to the main site.

Let’s see how all this works by building and testing an actual project.

How to create a new Laravel project

Use the Sail setup that Laravel ships with.


curl -s "https://laravel.build/example-app" | bash

You can use any other method you feel comfortable with. See the docs for more information.

Start the Laravel server


./vendor/bin/sail up -d

How to configure the route files

In your web.php file, you can define individual routes with their domain (or subdomain) as follows:


Route::get('/', function () {
    return 'First sub domain'; 
})->domain('blog.' . env('APP_URL'));

Now you can access the page at blog.domain.com.

More often than not, you’ll have more than one path in an application, like a domain and subdomains. So, it’s a good idea to use a route group to cover all the routes in the same domain or subdomain.


Route::domain('blog.' . env('APP_URL'))->group(function () {
    Route::get('posts', function () {
        return 'Second subdomain landing page';
    });

    Route::get('post/{id}', function ($id) {
        return 'Post ' . $id . ' in second subdomain';
    });
});

Now, all the routes for the domain can be handled in one place.

How to make subdomains dynamic

As mentioned earlier, you can use subdomains to allow personalization in web applications, so they need to be dynamic.

For example, Medium gives authors domains like username.domain.com.

You can do this easily in Laravel, as subdomains may be assigned route parameters, just like route URIs.

This allows you to capture a portion of the subdomain for usage in your route Closure or controller.


Route::domain('{username}.' . env('APP_URL'))->group(function () {
    Route::get('post/{id}', function ($username, $id) {
        return 'User ' . $username . ' is trying to read post ' . $id;
    });
});

In this example, you can have a domain such as zubair.domain.com with route parameters, too.

Route service providers

For very large applications, the web.php can get a bit messy if the routes keep increasing. It is best to split the routes into different files, preferably by subdomain.

In your RouteServiceProvider.php file, you’ll see the code below in the boot method:


public function boot() {
    $this->configureRateLimiting();
    $this->routes(function () {
        Route::prefix('api')
            ->middleware('api')
            ->namespace($this->namespace)
            ->group(base_path('routes/api.php'));              
        Route::middleware('web')
            ->namespace($this->namespace)
            ->group(base_path('routes/web.php'));
    });
}

This is Laravel’s default route configuration to separate API routes from web routes. We’ll use this same file to separate subdomains.

Add the following code to the method:

Route::domain('blog.' . env('APP_URL'))
    ->middleware('web')
    ->namespace($this->namespace)
    ->group(base_path('routes/blog.php'));

This tells Laravel to look for the route in the blog.php file whenever someone hits the blog.domain.com endpoint.

We can go on to create the blog.php file in the routes folder and add the following content:


<?php

use Illuminate\Support\Facades\Route;

Route::get('/', function () {
    return 'Route using separate file';
});

At this point, you’re done with all the code! All that’s left is some server configuration.

Server configuration

If you’re using a service such as Laravel Valet, it is way easier to set up.

In the root directory of your project, run the following:


valet link domain
valet link blog.domain

If you’re not using Laravel Valet, you can add the code below to your /etc/hosts/ file:


127.0.0.1   domain.test
127.0.0.1   blog.domain.test

This maps the domain to the IP.

Attributions:
  1. undefined by undefined
  2. undefined by undefined