I am currently developing a project where people can come into my Laravel project and create their own one-page website.
Now I would like to have them be to able to point their own custom domain to a specific Laravel route.
There's only one path that will "receive" all the domains, for example
[Customer 1]
have ABC.com
ABC.com -> point to -> mylaravelproject.com/route1
[Custom 2]
have DEF.com
DEF.com -> point to -> mylaravelproject.com/route1
And I will just let the code in Laravel route file detect the domain, and display the content dynamically
/routes/web.php
$thankyoupages = Thankyoupage::whereNotNull('domain')->get();
foreach( $thankyoupages as $ty ) {
Route::group(['domain' => $ty->domain], function() use ($ty) {
Route::get("/", function() use($ty) {
$data = [
"ty" => $ty,
"pixels" => json_decode($ty->pixels)
];
return view('thankyous.thankyoupage', $data);
});
});
}
My questions are:
[1] Are there any (easy) ways to achieve this?
[2] Do I have to alter Vhosts of Apache dynamically? or do I need reverse proxy?
[3] How to config the domain in order to achieve this? Just point A record to server's IP? or should I use CNAME?
Thank you in advance
For handle dynamically domains in one laravel project I came to the following solution after a lot of searching and experimenting in one of my projects. It's not ideal you may impove on your own.
First all your domain must be added A record or CName in dns records
from DNS managers. A record pointed to your server IP works perfectly
Add your route list new group by domain example:
Route::group(['domain' => '{domain}'], function () {
$url = Request::getHost();
$full_url = url('/');
Helper::domain($url, $full_url);
// Your routes list ...
}
Also, we will need send dynamically domain name in diferent part of your application for instance in controller. For that I added new helper function to Helper class:
class Helper
{
public static $domain;
public static $full_domain;
public static $autoload_static_data;
public static $position;
public static function domain($domain,$full_domain)
{
Helper::$domain=$domain;
Helper::$full_domain=$full_domain;
$domain_info=domain_info();
if ($full_domain==env('APP_URL') || $full_domain==env('APP_URL_WITHOUT_WWW')) {
return true;
}
if ($domain==env('APP_PROTOCOLESS_URL') || str_replace('www.','',$domain)==env('APP_PROTOCOLESS_URL')) {
return true;
}
$domain=str_replace('www.','',$domain);
Helper::$domain=$domain;
if (!Cache::has(Helper::$domain)) {
$value = Cache::remember(Helper::$domain, 600,function () {
$data=\App\Domain::where('domain',Helper::$domain)->where('status',1)->first();
if (empty($data)) {
abort(404);//or you can make custom 404 page
}
$info['domain_id']=$data->id;
$info['user_id']=$data->user_id;
$info['domain_name']= Helper::$domain;
$info['full_domain']= Helper::$full_domain;
$info['plan']=json_decode($data->information);
return $info;
});
}
}
You must save all your domain in database. In my case it was domains table and Domain model. You can verify domain and get all related information separately by domain.
Inside your server to handle all your domains in single webroot folder you can use ServerAlias * (wildcards)
Nginx in your configuration inside server block for server_name you can use regex
If you do not understand or have additional questions, you can ask via comment
Related
What I need:
My app has a public domain
All routes in my Admin controller should be opened only if the remote domain is domain1.com and also in local environment.
Currently: if I put the admin panel route in the group, it is not visible in local environment any more, making it difficult to develop.
// My secret domain, accessible only for admins
Route::group(['domain'=>'domain1.com'],function(){
Route::get('admin-panel', [App\Http\Controllers\Control\AdminController::class, 'admin_panel']);
});
// To be accessible both in domain1.com and domain2.com:
Route::get('homepage', [App\Http\Controllers\Control\PagesController::class, 'homepage']);
Solutions
My current solution:
in route file web.php I add extra line
if( \App::environment() == 'local') {
Route::get('admin-panel', [App\Http\Controllers\Control\AdminController::class, 'admin_panel']);
}
but it is a crude, temporary fix.
TODO:
Either in route file or in the controller. A filter in a controller (for all or selected methods) would be best.
An if clause checking if either the environment is local or the domain is domain1.com
Thank you.
I think laravel not support something like that. But you can declare the routes to a function variable and then use it in each domain.
$adminRoutes = function() {
Route::get('admin-panel', [App\Http\Controllers\Control\AdminController::class, 'admin_panel']);
};
Route::group(array('domain' => 'domain1.com'), $adminRoutes);
Route::group(array('domain' => 'localhost'), $adminRoutes)
I already have the answer, I would like to share the solution with those who need it.
How to use multiple domains with different pages and routes in Laravel?
I spent many hours looking for solutions, but nothing concrete, always with complex and messy codes, in the end I developed a practical solution with clean code.
1 - Firstly, it is necessary to centralize the laravel in a single domain, then you must point the other domains to the main domain, you can access your dns manager and use the CNAME record for this.
2 - In your Laravel you must create a Controller the home page with the following content, replacing what is necessary:
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index(Request $request)
{
$origin = array("mydomain.com", "mydomain2.com");
$domain = parse_url(request()->root())['host'];
if (in_array($domain, $origin)) {
if ($domain === 'mydomain.com') {
return view('myview'));
}
if ($domain === 'mydomain2.com') {
return view('myview2'));
}
} else{
return view('unauthorized');
}
}
3 - Finally (optional), create a route with the urls that will be accessible only by that domain, do so:
Route::group(array('domain' => 'mydomain.com'), function () {
/* routes here */
Route::get('/', 'YouController#index');
});
Route::group(array('domain' => 'mydomain2.com'), function () {
/* routes here */
Route::get('/', 'YouController#index');
});
You must change mydomain.com and mydomain2.com to the domain you want, else{} you must replace unauthorized with a valid view, this is what will appear when the domain is not listed, if you want you can do the o server also shows nothing.
I want to prevent access to some of my app routes from other domain except listed. It success using below code:
$loginRoutes = function() {
Route::get('/', 'HomeController#index')->name('home');
};
Route::domain('domain1.com')->group($loginRoutes);
Route::domain('domain2.com')->group($loginRoutes);
Route::domain('localhost')->group($loginRoutes);
But the problem is when I call {{route('home')}}, the URL always becomes the domain at the last line of the routes.php(at above case is http://localhost ). How to make it to current domain?
My current solution:
if (isset($_SERVER["HTTP_HOST"]) && $_SERVER["HTTP_HOST"] == "domain1.com") {
Route::domain('domain1.com')->group($loginRoutes);
}elseif (isset($_SERVER["HTTP_HOST"]) && $_SERVER["HTTP_HOST"] == "domain2.com") {
Route::domain('domain2.com')->group($loginRoutes);
}
It's work but I think it's dirty. I have a lot of domains/subdomain and also the routes too.
I need solution on route directly, because I have a lot of routes, if I update each controller it's will take a long time. Maybe edit route provider or laravel vendor code is also no problem.
I am also using PHP 7.3 and Laravel 5.7
I actually use this routing for my domains.
Maybe this is not exactly what you asked, but you can try something like this
// To get the routes from other domains
// Always add the new domains here
$loginRoutes = function() {
Route::get('/', 'HomeController#index')->name('home');
};
Route::group(array('domain' => 'domain1.com'), $loginRoutes);
Route::group(array('domain' => 'domain2.com'), $loginRoutes);
Route::group(array('domain' => 'domain3.com'), $loginRoutes);
If you want to handle something at the domain level. In your controller (HomeController#index), you can get the current domain and do whatever you want. To get exact domain I have used like this:
class HomeController extends Controller
{
public function index()
{
$domain = parse_url(request()->root())['host'];
if ($domain == 'domain1.com'){
// do something
}
...
}
...
}
That way I can handle different things for each domain.
Just to make it more complete, we can take the domains from a table/query and dynamically create the routes.
$domains = Cache::get('partners')->where('status', '=', 'A')->where('domain', '<>', '')->all();
$loginRoutes = function() {
Route::get('/', 'HomeController# index')->name('home');
};
foreach ($domains as $domain) {
Route::group(array('domain' => $domain->dominio_externo), $loginRoutes);
}
It has been working for me. I hope to help you.
You can maybe try something like this :
Route::pattern('domainPattern', '(domain1.com|domain2.com|localhost)');
$loginRoutes = function() {
Route::get('/', 'HomeController#index')->name('home');
};
Route::group(['domain' => '{domainPattern}'], $loginRoutes);
If I understand your issue, you just want to filter domains. Using regex, you can do it. You could try the following code:
Route::domain('{domain}')->group($loginRoutes)->where('domain', '\b(domain1\.com|domain2\.com|localhost)\b');
Details:
\b: we get exactly the string.
\.: in regex, the character . means any character. So, we have to escape . using backslash.
Note:
You might get an error, because I can not check the results. Let me know any errors you encounter.
I want to prevent access to some of my app routes from other domain
except listed. It success using below code:
I think you are right with your thoughts about a better, more laravel-core based solution for this problem.
Every route handling method you define in a controller file recieves a request. In standard laravel this is an object of type Illuminate\Http\Request.
You can extend this class with a custom class - let's say "AdminRequest". This extended class than offers authorization methods which will check if the Auth:user has the correct role, session values or whatever you want in your app.
I guess this is more flexible and clean - in your controller you only have to change the definition of the request you recieve in that controller method. Validation messages and everything else can be wrapped in the custom request class.
See this also:
How to Use custom request (make:request)? (laravel) Method App\Http\Requests\Custom::doesExistI does not exist
Extend Request class in Laravel 5
for preventing access to a certain route, its a bad design to inject a Route into these structure:
Route::domain('domain1.com')->group($loginRoutes);
Route::domain('domain2.com')->group($loginRoutes);
Route::domain('localhost')->group($loginRoutes);
since it defines route multiple time, and only the last will be override the others.
you can check this by php artisan route:list .
the laravel way to handle this situation (access management ) is to use middleware
class DomainValid
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$domain = $request->server->get('SERVER_NAME');
if (in_array($domain , ['domain1.com','domain2.com','localhost'] )) {
return $next($request);
}
abort(403);
}
}
and use it like this:
use App\Http\Middleware\DomainValid;
Route::get('/', 'HomeController#index')->name('home')->middleware(DomainValid::class);
so it will be only ONE home route.
I would like to use one server that uses a base Laravel installation, and have subdomains that reference that installation. All the subdomains will be the same like an SaaS.
I've looked around and the databases connections are easy, but I'm wondering if you can do this intelligently with the same codebase for subdomains.
The subdomains world include the minimal needed files for its subdomain -- perhaps, the public index and bootstrap? Hopefully without symlinking everything.
I'm not worried about the server configuration, I just would like to be pointed in the right direction for Laravel code, like middleware to handle the request then point to that subdomain?
A lot of threads I've read don't have an answer that seems standard, any ideas or links?
Also, if it were a multi server setup wouldn't one be OK with an NFS server for the core?
With laravel you can check the URL without using subdomains but just group routing requests.
Route groups may also be used to handle sub-domain routing.
Sub-domains may be assigned route parameters just like route URIs,
allowing you to capture a portion of the sub-domain for usage in your
route or controller. The sub-domain may be specified using
the domain key on the group attribute array:
Route::group(['domain' => '{account}.myapp.com'], function () {
Route::get('user/{id}', function ($account, $id) {
// your code
});
});
Read more about this on laravel documentation https://laravel.com/docs/5.4/routing#route-group-sub-domain-routing
BOUNTY
You can also supply more parameters to the same Route::group, that could be, for example
Route::group(['domain' => '{subdomain}.{domain}.{tld}'], function () {
Route::get('user/{id}', function ($account, $id) {
// your code
});
});
In the same time, you can decide to limit the domain parameters you are going to accept using the Route::pattern definition.
Route::pattern('subdomain', '(dev|www)');
Route::pattern('domain', '(example)');
Route::pattern('tld', '(com|net|org)');
Route::group(['domain' => '{subdomain}.{domain}'], function () {
Route::get('user/{id}', function ($account, $id) {
// your code
});
});
In this previous example, all the following domains will be accepted and correctly routed
www.example.com
www.example.org
www.example.net
dev.example.com
dev.example.org
dev.example.net
I have an asp.net mvc3 website. It replaced an older php website. Many people have parts of the site bookmarked in reference to the .php locations and I would like to add those back into the asp.net site as simple forwards to the new location. So mysite/product.php would redirect to mysite/usermap/product.cshtml for example. When I insert the product.php into the directory and use an anchor href to it, I am prompted to open it with a certain program or save it. Any ideas?
You could make a small redirection controller, and add a route to match something like mysite/{id}.php.
Then in that controller
public ActionResult Index(string id)
{
return RedirectToActionPermanent("Product", "YourExistingController", id);
}
edit
In your global.asax.cs file
public void RegisterRoutes(RouteCollection routes)
{
// you likely already have this line
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
// assuming you have a route like this for your existing controllers.
// I prefixed this route with "mysite/usermap" because you use that in your example in the question
routes.MapRoute(
"Default",
"mysite/usermap/{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
// route to match old urls
routes.MapRoute(
"OldUrls",
"mysite/{oldpath}.php",
new { Controller = "OldPathRedirection", action = "PerformRedirection", oldpath = "" }
);
}
Then you would define an OldPathRedirectionController (Controllers/OldPathRedirectionController.cs most likely)
public class OldPathRedirectionController : Controller
{
// probably shouldn't just have this hard coded here for production use.
// maps product.php -> ProductController, someotherfile.php -> HomeController.
private Dictionary<string, string> controllerMap = new Dictionary<string, string>()
{
{ "product", "Product" },
{ "someotherfile", "Home" }
};
// This will just call the Index action on the found controller.
public ActionResult PerformRedirection(string oldpath)
{
if (!string.IsNullOrEmpty(oldpath) && controllerMap.ContainsKey(oldpath))
{
return RedirectToActionPermanent("Index", controllerMap[oldpath]);
}
else
{
// this is an error state. oldpath wasn't in our map of old php files to new controllers
return HttpNotFoundResult();
}
}
}
I cleaned that up a little from the original recommendation. That hopefully should be enough to get you started! Obvious changes are to not hardcode the map of php filenames to mvc controllers, and perhaps altering the route to allow extra params if you require that.
If you are using IIS7 the Url rewrite module is great. Here is the page: http://www.iis.net/download/urlrewrite
When I insert the product.php into the directory and use an anchor href to it, I am prompted to open it with a certain program or save it. Any ideas?
Update the handler mappings manually. However I am pretty sure when you install PHP for IIS (http://php.iis.net/) it will do it for you.
Install PHP into IIS using this site. http://php.iis.net/