Should I use Multi-Tenancy?

Topics: Core, General, Troubleshooting
Feb 4, 2015 at 7:25 AM
Hey Guys, I wish to create a website/s [three for now] for my father's businesses that are all ridiculously similar in nature and functionality, but not so in appearance, content, and cliental.
As I have heard of Multi-tenancy brandished here and there, I was wondering if a Multi-tenanted Orchard Site would be suitable for such a situation? Therefore, I installed a fresh 1.8.1 instance and enabled Multi-tenancy, then added a tenant to test the concept [which I’m most likely not grasping].
Ultimately:
  • I would like to handle administration for all three entities/sites from one area [...I assumed from the Parent Site where the tenants would be created from – this doesn’t appear to be the case], with most Staff / Contractors having access to all sites, with a few users restricted to only one site.
  • I would use/create the same available/custom Modules, but have different frontend information and layouts for each site […when I installed some modules on the parent site, I expected them to propagate to the tenant sites – this is not so?].
  • Same Backend functionality: Administration / Users / Reports / Mail Generation / Calculations etc. for all the sites as a whole, whilst also allowing the aforementioned for individual sites only if so selected [...is this possible without investing a vast amount of time; admittedly, this: http://orcharddojo.net/blog/advanced-orchard-accessing-other-tenants-services scares me.
    Question is [of many I suppose], due to the fact I’m a designer rather than a developer, am I better off with a single/standard instance of orchard [...same admin and I can then restrict User access as normal] and manually partition/name/route pages to appear as separate websites via somehow [which I have seen before] changing templates on the fly [sorting DNS thereafter]. Hopefully someone can point me in the right direction – even with my poor descriptive skills sorry. Thanks for your time and any information / points you could pass on, Regards Dyr
Developer
Feb 4, 2015 at 2:58 PM
This indeed sounds like a good case of multi-tenancy. Let me try to clarify what is multi-tenancy: the feature lets you serve multiple Orchard websites from the same application, where these sites can use the same set of modules and themes from the app (however you can limit tenants to be able to only access a subset of those) but are completely separated from a content standpoint (their data storage is separated, including DB, media files, search indices...).

This means that:
  • You will only be able to handle administration separately for these sites (since the point is to have separate, separately administrable sites). On the upside you can customize what users can do on the different sites.
  • Apart from what you see on the Default tenant under the Tenants admin there is no other central management for all tenants.
  • By default all modules and themes in the app are available for all tenants.
In your case with only 3 tenants you'd benefit from multi-tenancy because:
  • it's easier to maintain an deploy just one app and
  • simpler and cheaper to host only one Orchard app than three.
You could even add a lot of modules and themes that are only useful for certain tenants only, it wouldn't bother you.
Feb 4, 2015 at 7:09 PM
Edited Feb 4, 2015 at 7:48 PM
Wow! Thanks for taking the time to produce such a wonderful explanation Piedone.
So, where Orchard Multi-tenancy falls short for my intentions, is that:
  • Central Administration Management for all tenants does not exist: could this be implemented relatively easily, I imagine not, for the developers would've done as much?
  • Therefore, I assume sharing of Content between the sites also doesn't exist -- I note that when adding a tenant you can select an existing DB [say, the Default Tenants for instance] and prefix the tables -- as the data would be stored in the same DB, I would have thought access to manipulating all the tenants data [joining tables] would've been somewhat straight-forward; again, could this be implemented without too much pain and is this the key http://orcharddojo.net/blog/advanced-orchard-accessing-other-tenants-services [do you know if others have tried]?
I know "could" is a fairly loose term, but in regards to someone who has only basic-to-intermediate coding skills, is there another solution / method I should explore / undertake [even at the cost of Multi-tenancy benefits: separation of concerns as described, etc., for achieving the above dot-pointed functionality is much more paramount]? Thanks so much for your time and enlightening me on the subject.
Kind Regards, Dyr
Developer
Feb 4, 2015 at 7:30 PM
I'm kind of passionate about multi-tenancy, having worked a lot on DotNest :-). You're quite welcome.
  1. Central administration would be needed to be written pretty much from the ground up (also using the techniques in the linked Orchard Dojo article) so this entirely depends on what exactly you need. Imagine how a module with a new content type, a custom editor and some custom admin listings is implemented (even if you're not an Orchard developer - yet :-) - you can get a general feeling about this by looking at e.g. the built-in Blogs module). Now you'd need something like that but with 15% more complexity (and development time, money...) due to all this working together with other tenants.
  2. Direct content sharing is also not implemented. You could go simple and e.g. use import/export to copy content between the site, otherwise you need the same techniques under the Dojo link. Then it doesn't really matter whether your tenants use the same or different DBs (as data access would go through Orchard services, without knowing about the specific DB when you write the code).
Related to import/export is the content deployment feature which will basically be a seamless import/export between two Orchard sites (currently Bertrand is working on this and it might be part of the 1.9 release). This might be something useful for your scenario.

With the given skill level I wouldn't try to implement a central administration but rather (and I'm not being condescending here!) adapt the expectation to the multi-tenancy architecture or to ditch it and rather implement the three sites in the same tenant. Orchard is pretty good in showing a different "face" depending on arbitrary logic (like domains in the URL) so you can implement something in a single tenant that for users will seem like three different websites (take a look at widget layers and shape template URL alternates as a start). For food for thought also see e.g.: http://english.orchardproject.hu/blog/how-to-create-a-minisite-inside-your-orchard-website (this is a completely uniquely looking site inside another tenant).
Feb 5, 2015 at 3:30 AM
Thanks Piedone, your advice is so much appreciated - and 'yes', I believe you're right on all accounts; hence, I've been trying to make a quick mock along the lines of your 'minisite' example. Second of all, so sorry to hassle you again with a follow-up question jeesh - embarrassed, being, how do you go about developing such on a local dev machine - as I imagine you've probably done so in the past with a much better strategy than mine. So far:
  • I've started with a fresh 1.8.1 install - enabled Multi-tenancy [only so I could add the other two hosts/websites via comma-separation to the default tenant.]
  • Edited my Hosts / Applicationhost.config etc. to sort binding with IIS Express -- basically I have localhost,alpha.localhost,beta.localhost [all works as expected]
But when I added the config from your example [just beta for now]:
        <rewrite>
        <rewriteMaps>
          <rewriteMap name="MapSSL" defaultValue="OFF">
            <add key="ON" value="https://" />
            <add key="OFF" value="http://" />
          </rewriteMap>
        </rewriteMaps>
        <rules>
          <rule name="beta redirect" enabled="true">
            <match url="^beta($|(/.*))" />
            <conditions>
              <add input="{HTTP_HOST}" pattern="^beta.localhost:30321/OrchardLocal/$" negate="true" />
            </conditions>
            <action type="Redirect" url="{MapSSL:{HTTPS}}beta.localhost:30321/OrchardLocal/{R:1}" />
          </rule>
          <rule name="beta rewrite" enabled="true" stopProcessing="true">
            <match url="^(Media|Themes|Modules|Core)" negate="true" />
            <conditions>
              <add input="{HTTP_HOST}" pattern="^beta.localhost:30321/OrchardLocal/$" />
            </conditions>
            <action type="Rewrite" url="beta{REQUEST_URI}" appendQueryString="false" />
          </rule>
        </rules>
      </rewrite>
the above partly works, but mostly doesnt: e.g's

http://localhost:30321/OrchardLocal/beta/ resolves to: http://beta.localhost:30321/OrchardLocal/ ...[correct]
http://localhost:30321/OrchardLocal/beta/home resolves to: http://beta.localhost:30321/home ...and returns a "Server Error: System.IO.FileNotFoundException"
beta.localhost:30321/OrchardLocal/beta/home/ resolves to: http://beta.localhost/home ...and returns 404

am i missing something glaringly obvious - perhaps the port number is an issue, or is there a better method I should choose to mock this situation? Again, thank you so much for all your help, Dyr
Developer
Feb 5, 2015 at 2:53 PM
Hmm, after a quick glimpse the rules seem all right, so I don't see anything obviously wrong. But you can test such rules from IIS Manager from under IIS Rewrite Rules, I'd encourage you to check there.
Feb 6, 2015 at 2:50 AM
Edited Feb 6, 2015 at 3:29 AM
Ok, so I was using IIS Express - now, i'm using my Local IIS with Rewrite Rules 2.0 installed - but still no success.
I've noted i'm having the same issue as azltdanh who commented on the original link at:
http://english.orchardproject.hu/blog/how-to-create-a-minisite-inside-your-orchard-website
...the error being the same as his:
"Cannot use a leading .. to exit above the top directory."
http://postimg.org/image/qk5lxiro7

[i've gotten leading errors in the past with images, say ../../pic.jpg going one past the root, when it should've been ../pic.jpg]

So I feel it's something to do with the rewrite construction:

<add input="{HTTP_HOST}" pattern="^beta.localhost/$" /> ...note the trailing forward slash, results in:
[HttpException]: The controller for path "/home" was not found or does not implement IController [...it should be '/beta/home'.]

and like previously mentioned:
<add input="{HTTP_HOST}" pattern="^beta.localhost$" /> ...note trailing slash removed, results in the "Cannot use a leading..." error

Image

...perhaps because I've enabled multi-tenancy, but only have the default operable with no other added -- the tenantPrefix ="" could be causing issues?

I've got to say it - I'm completely at a dead-end. Is there anything else you can recommend I investigate, thanks again for taking the time to read my posts very humbled, regards Dyr.

PS> I've also noted: http://beta.localhost/beta/home resolves to: http://beta.localhost//home
Developer
Feb 6, 2015 at 12:46 PM
Tenant prefix can be null, that's not an issue.

Noticed that for HTTP_HOST you used ^beta.localhost:30321/OrchardLocal/$ though the host will never be this. This is host+port+path (or URL). In the Orchard Hungary sample the rationale is that "if the host if the minisite's, rewrite the request to under a path prefix".
Feb 7, 2015 at 11:27 AM
Hey mate, I got a little lost with your last observation description, but understood the host part [i'm grasping URL rewrites a lot better now].
Anyhow, what i've ascertained, is:
  • Both rules by themselves work as expected [i.e. one rule-set commented out at a time], but when I combine the two, I get 404's.
  • Together, the redirect appears to work [figures, as apparently the redirect is client side] as the url visibly changes - but heaven knows what the rewrite is doing...I cant get fiddler4 to capture subdomains on local sys for some reason?...but from the 404's, it appears the 'beta/ is always missing on the request e.g. Requested URL: /home/ when it should be /beta/home/ etc.
    To make it easier, I reverted to IIS Express and the pattern you commented on:
          <rule name="beta redirect" enabled="true">
            <match url="^beta($|(/.*))" />
            <conditions>
              <add input="{HTTP_HOST}" pattern="^beta.localhost:30321/$" negate="true" />
            </conditions>
            <action type="Redirect" url="{MapSSL:{HTTPS}}beta.localhost:30321/OrchardLocal{R:1}" />
          </rule>
          
          <rule name="beta rewrite" enabled="true" stopProcessing="true">
            <match url="^(Media|Themes|Modules|Core)" negate="true" />
            <conditions>
              <add input="{HTTP_HOST}" pattern="^beta.localhost:30321/$" />
            </conditions>
            <action type="Rewrite" url="beta{REQUEST_URI}" appendQueryString="false" />
          </rule>
Thanks - and sincere apologies for my ineptness, Dyr