Community Server - Setting Up Multiple Communities
Community Server ("CS") supports multiple communities with a single installation of the software (and a single database).
However, if you want true independence of those communities, as you would get when setting up multiple portals in DotNetNuke, for example, that is not easy to achieve in CS version 2.1. However, I believe it can be done.
By true independence, I mean, for example, that the navigation menus of each community should be independent so that if you want to add navigation tabs to one community without affecting the others, you can do that. Other factors include things like not having conflicts between content folder names: if two communities name a photo gallery "My Gallery" that should not lead to problems. And, of course, all the configuration options (including those in communityserver.config, SiteUrls.config and web.config) should be independent.
Here is the approach I am taking. (This approach is now at version 2, but it should still be considered experimental. I do have it working on my web server, but I have not been using it long enough to verify that I have covered all possible situations.)
In the steps below, you will notice that I did not edit SiteUrls.config to change the locations of blogs, files, or photos. I considered doing that in order to give each community separate locations for these items by only changing the config file, but it doesn't work as well as I would like. One approach I considered would have added another folder name in the path, and that made the URL longer by one path. I personally didn't like that. Another approach to editing SiteUrls.config that I considered was to just give each folder a unique name for each community. For example, the folder blogs would become Domain1Blogs in the SiteUrls.config file for Domain1. That might not be a bad approach, but I didn't use it because it mixed the custom content for each community with the generic content of the application files in a way I didn't like. There doesn't seem to be a perfect solution given CS's approach to URL rewriting, but the approach I took below represented the best compromise I could find while still achieving my goals. (In the future, after I become more familiar with the Community Server source code, I may look into incorporating UrlRewritingNet.UrlRewrite because it doesn't require physical folders the way CS's approach does. Now, on to the steps.
I installed CS on my web server at C:\InetPub\CommunityServer\Web. I installed it in one physical location with one database and I didn't do anything out of the ordinary in this installation. Below is my folder structure.
I added empty folders for my two independent communities, called Domain1 and Domain2. As this implies, each of my communities has its own domain name and I used the actual names for the folders. (Don't use a generic folder name like Domain1 used in this example.) You can add as many communities as you wish using this procedure, but I assume two in this example.
Edit the config files to establish any settings that you want to have apply to all the communities. One of these changes will be to modify the communityserver.config file to set enableVirtualization="true" (the default is false). You can find this setting in the "Core" section. Go ahead and do that now.
Copy all the files (not the folders) in Web to Domain1 and Domain2. (You could actually remove these files from Web afterwards if you don't plan to use that "default" community. But you might find having that default community operational is useful for administration purposes.)
The folders Domain1 and Domain2 will now contain Web.config, SiteUrls.config, communityserver.config, Default.aspx, login.aspx, etc. I count 16 files.
Use NTFS Link (more info here) to create junctions in Domain1 for all the folders in Web (except Themes, blogs, files, and photos). Do the same for Domain2. Excluding the Themes folder gives complete independence in skinning each community. You need to exclude the blogs, files and photos folders to give each community's content complete independence.
I count 18 folders linked by the "Create Junction Here" function in NTFS link. These folders include bin, aspnet_client, bin, etc., all the way to User and Utility.
Now copy, in the normal fashion, the folders you excluded when creating the junctions. Copy them from Web to Domain1 and again to Domain2.
Now you have only one set of binaries (in the bin folder), even though the junctions make it appear that there is a bin folder inside each community's root folder. There is indeed only a single bin folder. There is just one set of most of the application files too. However, you have multiple copies of a few folders where Community Server's virtualization shortcomings have to be overcome through physically separate files/folders.
The next two steps are courtesy of vmarquez and haathi on the CS forums:
- In the web.config file for Domain1 search for applicationName and change the value. In my case, I found applicationName="dev" and replaced it with applicationName="Domain1" in 3 places.
- Also in web.config change the cookieName value in the roleManager section from ".CSRoles" to ".Domain1Roles".
Repeat the above two steps for Domain2.
I researched these steps before setting up my own server, and I took the advice above right from the start. However, I also noticed that I could (and possibly must) go into Control Panel > Administration > Membership > Cookies and Anonymous Settings and specify values for the following items:
- Roles Cookie Name (I used .Domain1Roles)
- Anonymous Cookie Name (I used Domain1Anonymous)
- Cookie Domain (I used domain1.com)
Knowing that .TEXT actually stores the configuration values in the database and uses the config files for initial default values only, I assume Community Server is doing the same thing. Therefore, I'm not sure how much is gained by changing the values for the cookies in web.config. In my case, it didn't seem to have an effect on the initial (and incorrect) values that were present in the Control Panel.
In IIS, I set up new web sites (not virtual directories) for Domain1 and Domain2. My web server is running Windows Server 2003, so I can set up multiple web sites. However, new virtual directories will also work.
I pointed the web site for Domain1 to C:\InetPub\CommunityServer\Domain1. I set up a second new web site for Domain2 and pointed it at C:\InetPub\CommunityServer\Domain2. I set up host headers for each web site. Otherwise, nothing special is required in the IIS settings for these web sites.
In your Community Server database, run the cs_system_CreateCommunity stored procedure for each of the communities. More info about this proc is here: http://developer.communityserver.org/default.aspx/CS.MultipleCommunityInstallations. You can also find a nice (and simple) summary at Dave Burke's blog. What it boils down to is executing this sproc with your own parameters.
DECLARE @return_value int
EXEC @return_value = [dbo].[cs_system_CreateCommunity]
@SiteUrl = N'Domain1.com',
@ApplicationName = N'Domain1.com',
@AdminEmail = N'yourname@Domain1.com',
@AdminUserName = N'YourAdmin',
@AdminPassword = N'YourPassword',
@PasswordFormat = 0,
@CreateSamples = 0
SELECT 'Return Value' = @return_value
NOTE: Every time I have used a PasswordFormat=1, I have been unable to sign in to the admin account that gets created. If this happens to you, join as another user, then access your CS database with a tool such as SQL Server Management Studio. Copy the Password and PasswordSalt from the account you created to the admin account. You can then sign in with the admin account and set the password as you desire.
My hope is to improve these steps even further in the future (unless Community Server 3.0 addresses this issue before then). As I discover improvements, I'll update this post.
Also, I want you to know that I have this setup working, but I have only been using it for a few weeks. As I continue to customize CS or add more communities, I may find that there are some disadvantages to my approach. If that turns out to be the case, I'll let you know. My expectation is that - in the worst case - there may be another folder or two that needs to be duplicated rather than symbolically linked.
If you are responsible for backing up your web server, you may want to give a little thought to how your backup software handles symbolic links. It might see the folder content as completely independent and create multiple backups of the same files. I personally excluded the folders Domain1 and Domain2 from my backup settings. When I create custom themes for those domains, I will manually backup those themes. I do not know how a restore would handle the symbolic links either.
You might also want to give some thought to whether you want to run each web site in its own application pool or run all Community Server sites in a single application pool in IIS. I'm running mine all in a single application pool, but I can easily change that in the future if I wish.
Summary: The setup I have described centralizes all file system content (except Themes) in one place on the file system because that was my goal. I didn't want multiple copies of Community Server installed in order to support multiple separate communities. I wanted one copy of the software and one database with multiple independent communities. However, anywhere CS has a "break down" in its virtualization architecture, something will have to be duplicated on the file system. The need to duplicate SiteUrls.config, for example, led to the whole symbolic linking approach which essentially allows multiple config files for one installation of the software. The need to have independent themes led to the requirement to copy/duplicate the Themes folder. If you have special needs, you may find yourself duplicating other storage folders. And at some point, if there are more than a few duplicated folders, it may make sense to either reorganize the default CS folder structure or just skip the symbolic links completely and settle for multiple copies of the software.