Multisite setup using folders

I’m setting up a client area that is essentially a series of micro sites that clients can log into their area. Ive gone over the forum and read the docs but i’m struggling a bit to solve this. I would like the pages accessed like this:

mydomain.com/clientone
mydomain.com/clienttwo
mydomain.com/clientthree

Clients should be able to login into the front side (not panel access). I want to password protect it. (i know how to do this, but is it possible on a multisite?)

These site are all identical. Shared blueprints, templates, snippets… everything. Only content and user accounts are unique to each.

The closest i have found on the forum to what i would like is using this in a site.php but its not quite right because its loading the folders based on the domain name reported by the server.

<?php
// site.php

$kirby   = kirby();
$domain  = server::get('server_name');

// Invalid subdomain redirects to fallbackdomain.com
$clients = array_diff(scandir(__DIR__.'/clients'), array('..', '.','.DS_Store'));

if (!in_array($domain, $clients)) {
    $client = 'fallbackdomain.com';
} else {
    $client = $domain;
}

// custom roots
$kirby->roots->content = __DIR__ . DS . 'clients' . DS . $client . DS . 'content';
$kirby->roots->avatars = __DIR__ . DS . 'clients' . DS . $client . DS . 'avatars';
$kirby->roots->thumbs  = __DIR__ . DS . 'clients' . DS . $client . DS . 'thumbs';
$kirby->roots->accounts  = __DIR__ . DS . 'clients' . DS . $client . DS . 'accounts';

How do i tweak this so that visiting mydomain.com/clientone displays content from /clients/clientsone

My folder structure is like this:

public
  kirby
  clients
      clientone
          content
          avatars
          thumbs
          accounts
      clienttwo
      clientthree
  panel
  site
index.php
site.php

Maybe this helps: Multisite not loading CSS/assets?

It looked like it might but reading through the thread, it did not work 100%. Any other ideas?

@texnixe Ok so i have almost a working solution.

I have pulled blueprints, fields, plugins, snippets, templates folders out of the site folder and into a common folder. I have then put a full copy of kirby into a client subfolder, and then symlinked those folders back into it. This allows me to share them among multiple sites.

It almost worked! Trouble is, i can only view the index page… if i navigate to sub pages, i get an apache server error (not a kirby whoops page, or a custom kirby error page).

The error is: The requested URL /index.php was not found on this server.

I tried adding a site.php with:

<?php

$kirby = kirby();
$kirby->roots = new Kirby\Roots(__DIR__);

That did not help though. Any ideas?

For clarity, heres my folder structure:

So, this is one of the clients folders now?

But if you do it like this, with each client being a separate installation and they only share some site folders, you don’t have to use symlinks but can link to these folders in your site.php as explained in the custom folder setup docs.

the Dama folder is a client folder…

I think the reason is that apaches webroot is set to the public folder root, and now there is no longer any index php file there. It should not be looking in there though because i am looking at a subpage.

Im trying to avoid having to map subdomains to each client sub folder as a webroot.

Oh. I can? When I read that I understood that was for rearranging a single site.

Yes, but now you basically have a single site. Your subfolders don’t share a Kirby installation anymore, all they share is the common folders.

Ok … i think… but i can still have unique content and panel logins for each subfolder?

I basically want each client subfolder treated as if it was a unique site, but share kirby between them to make it easier to maintain.

Well, yes, because each folder now is a separate Kirby installation. So these folders are completely independent, with the only difference that instead of using a subdomain, they live in a subfolder.

I think we have gone round in circles. It’s all very confusing. I think we have basically gone back to my original question.

How do I use a single instance of kirby but load unique content for subfolders with a structure like this (or similar):

public
  kirby
  clients
      clientone
          content
          avatars
          thumbs
          accounts
      clienttwo
      clientthree
  panel
  site
index.php
site.php

What do i need to put in site.php so that when i visit domain.com/clientone it loads the content, accounts and thumbs from there, NOT from example.com?

What if you use the site.php from the multi-site documentation but replace server::get('server_name'); with the server and the path to the folder? And the same in the domains array, instead of putting different domains, put the domain name and subfolder? Have never tested this…

Hmmm. It’s not happy. I tried this:

<?php

//site.php

$kirby   = kirby();
$domain  = server::get('server_name').'/clients/';
$domains = array($domain.'clientone', $domain.'clienttwo');

if(in_array($domain, $domains)) {

// custom roots
$kirby->roots->content = __DIR__ . DS . 'clients' . DS . $client . DS . 'content';
$kirby->roots->avatars = __DIR__ . DS . 'clients' . DS . $client . DS . 'avatars';
$kirby->roots->thumbs = __DIR__ . DS . 'clients' . DS . $client . DS . 'thumbs';
$kirby->roots->accounts = __DIR__ . DS . 'clients' . DS . $client . DS . 'accounts';

// custom urls
$kirby->urls->index    = url::scheme() . '://' . 'clients/' . $client;
$kirby->urls->content  = $kirby->urls->index . DS . $client . DS . 'content';
$kirby->urls->avatars  = $kirby->urls->index . DS . $client . DS . 'avatars';
$kirby->urls->thumbs   = $kirby->urls->index . DS . $client . DS . 'thumbs';
$kirby->urls->accounts   = $kirby->urls->index . 'clients' . DS . $client . DS . 'accounts';

}

If i navigate to example.com/clients/clientone i get an apache 403 forbidden.

Am i missing something?

Come to think of it, the site.php doesn’t even have a chance to kick in if you call a subfolder of the domain. Maybe it would make more sense if you’d setup subdomains for the clients? Or let’s ask @lukasbestle :slightly_smiling_face:

I guess I could, but that will make a real mess of my nice tidy VPS. i was hoping to avoid that. As you say, maybe @lukasbestle has an idea :slight_smile:

Thanks for the help so far.

Maybe i am going about this all wrong. Perhaps theres another solution to the same problem. Heres what i need:

  • A single instance of kirby (so that im only keeping one instance upto date, and theres one set of templates, snippets and blueprints).
  • Clients should be able to log in to their page and their page only, with no panel access. They should be able to see any child pages of this page, but only after logging in.
  • Absolutly no chance whatsoever that Client A can see Client B’s pages. The content is private and confidential.

What are my options?

Easiest way: Create pages for each client. Use authentication. For each page, you can use a user field where you define who may access a page (and its subfolders).

See also: https://getkirby.com/docs/panel/permissions#using-permissions-for-frontend-features

Ok that looks like a solution.

Is it possible to have a single login page, rather then one for each client? It will redirect them to their page after logging in.

Yes, that’s doable (and some more characters).

For some reason I cant seem to make this happen.

I have a login setup that works, and I have this in my client pages that checks if the site user matches the page author field:

<?php if(!$site->user()) go('/') ?>
<?php

$username = $site->user();
$clientname = $page->author();

if($username == $clientname): ?>

    <p>You have access</p>

<?php else: ?>

    <p>You do not have access</p>

<?php endif ?>

If i login through the form, it redirects to the page matching the username but it says I dont have access, which is wrong.

My controller looks like this

<?php

return function($site, $pages, $page) {

  // don't show the login screen to already logged in users
  if($site->user())

  $user = $site->user();

  if (!empty($user)) {

  go('/' . $user);

  } else {

    // handle the form submission
    if(r::is('post') and get('login')) {

      // fetch the user by username and run the
      // login method with the password
      if($user = $site->user(get('username')) and $user->login(get('password'))) {
        // redirect to the homepage
        // if the login was successful

        $usersname = $site->user(get('username'));

        go('/' . $user);

      } else {
        // make sure the alert is being
        // displayed in the template
        $error = true;
      }

    } else {
      // nothing has been submitted
      // nothing has gone wrong
      $error = false;
    }


  return array('error' => $error);

  }

};

What am i doing wrong?