How to build Multi-Domain Laravel Application
Recently I built a custom ecommerce SaaS platform for B2B-specific niche. The app was built using Laravel framework and allows users to create their own shops under the app subdomain (so-called multi-tenancy app).
While I won't share any links or information about the real project, I'll share my thoughts, experience and useful tips and tricks I've learned while developing that application.
For the purpose of this article I created really small-application which contains only basic features for multi-domain app. The project is open-source and available on the GitHub.
I hope this article will be useful for you and help you better understand how to create such kind of applications .
To give you a better idea of what we'll be building, I've included a few screenshots of our demo application.
Registration page:
User dashboard:
Prerequisites
Let's assume the following:
- Our main domain is example.com, it's not our app yet, it's a front-page of our service, containing pricing information, blog, contact page, etc;
- app.example.com - is the entry point of our app, users can sign up here and open a shop under custom subdomain.
- admin.example.com - is the application control panel where we can see the key metrics of our app, manage the subscriptions, etc. No one except of us should have an access to this area;
- {shop}.example.com - a user's storefront, e.g. acme.example.com.
Let's also describe main entities of our application:
User - is an entity, representing a real person (e.g. who may login or register);
A User may be a Customer on certain shops and Manager (or Owner) on another shops;
A Manager - is an entity who have an access to the shop admin panel
If Manager is the owner of the store - he also can access to the additional areas of the shop management panel: such as billing, staff management, etc.
A Customer - entity representing customer for that shop. Please note: a Customer will not always attached to the User, as it's assumed that shop managers could create customers and assign orders to them manually.
Shop - an entity representing an online store for certain company. Shop domain is unique accross our platform.
Database Design and Models
Our database structure may looks as follow:
By the way, I've used https://www.quickdatabasediagrams.com/ to prototype the database structure.
Please, note: In your app you probably would add some extra tables, like Products, Orders, Billing, etc.
Application Routes
We can split all our routes into 4 specific groups:
app.example.com - General app routes, where user can register and open new shop (as shown on the screenhots above);
admin.example.com - App management routes, where super amin can view the app metrics, manage users, etc. Please note: I'd recommend you to use another subdomain in real-world application and setup additional protection for security reasons.
It may looks as follow:
{shop}.example.com - User's shop frontend. In our app it's just a simple static page as show on the screenshot below:
{shop}.example.com/admin - Store management panel, only store owners and managers can have an access to this area.
Middleware
We'll be using custom middleware in our project. For example, we'll need to verify shop domain, check if the user is a shop manager or if user is an app administrator and so on.
CheckShopDomain
Is Shop Manager
Is App Admin
Handling subdomains routes
Working with subdomain routes may looks a little bit distracting at the beginning, as we used wildcard domain in our route we'll need to pass the subdomain into all our routes, for example:
route('shop.home'['subdomain'=>request()->route('subdomain')])
I guess you agree with me that it's not looks good
What we can do here?
So, we can create a small helper function which will add the subdomain attribute to the route for us, it may looks as follow:
Sharing Session between domains
One thing you may notice is that session isn't saved when the user is logged-in in one store and goes to another. To fix that issue, we'll need to add a SESSION_DOMAIN variable to our .env file, for example:
SESSION_DOMAIN='.example.com'
That's all, now user session will be shared across all shops/subdomains in our app.
Provision the super admin
I will not go into details in this article, as I wrote a short article a while ago where I explained how to create an admin user in Laravel application.
What's not included in this project
As this is not fully-featured project, we haven't included a lot of features a real-world app may have, such as:
- Billing/Subscription Management
- Application Metrics;
- Shop Management;
- Force HTTPS;
- Custom domain mapping;
- Email verification and activation;
That's all, thank you for reading!
The application source code is available on GitHub: https://github.com/DigitalWheat/Multi-Domain-Laravel
Thank you for your time, I hope you enjoyed this article! Feel free to shoot me a tweet if you have any questions or feedback!