Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Note

This page assumes that you are using a Mac or something similar. This is especially true concerning the paths to Apache configuration files. However, the information here should also apply to other OS.

 

Table of Contents

Domains and /etc/hosts

This is an overview of the the multisite setup:

...

Note that we use only one domain - a subdomain of the "main domain" - to access the author instance (which is recommended practice).

To enable this without DNS, add the following line to your /etc/hosts file:

Code Pro
127.0.0.1		author.best-comics.net www.best-comics.net www.best-vinyl.net

Apache setup

Make sure you have a working Apache on your local machine. 

Helpful Apache commands

Whenever you change Apache configuration files, you have to restart the httpd process.

Restart the process

Code Block
sudo apachectl restart

Check the configuration

Code Block
apachectl configtest

Enable mod_proxy

Make sure your Apache has the module mod_proxy enabled.

Check the /etc/apache2/httpd.conf file and make sure the following line is not commented:

Code Block
LoadModule proxy_module libexec/apache2/mod_proxy.so

On a different OS, the path and suffix of the module may be different. 

If you edit the file, you must restart Apache.

Enable vhosts

We use virtual hosts configuration in this setup. You must make sure vhosts are enabled. Check the  /etc/apache2/httpd.conf filev and make sure the line with the include directive is not commented:

Code Pro
languagetext
# Virtual hosts
Include /private/etc/apache2/extra/httpd-vhosts.conf
If you edit the file, you must restart Apache.

Define virtual hosts

We want to redirect requests from <distinct-domain> to localhost:<port>/$context for at least one instance.

If vhosts is properly enabled, edit the /etc/apache2/extra/httpd-vhosts.conf file and add something similar to this:

Code Pro
<VirtualHost *:80>
    ServerName author.best-comics.net

    ProxyPass / http://localhost:8080/
    ProxyPassReverse / http://localhost:8080/

    ErrorLog "/private/var/log/apache2/projekt.local-error_log"
    CustomLog "/private/var/log/apache2/projekt.local-access_log" common    
</VirtualHost>
This configuration redirects the "author domain" author.best-comics.net to localhost:8080/magnoliaAuthor. The redirection works correctly, however, Tomcat still serves the pages from the context. Web resources do not load and redirections done by Magnolia are incorrect.

Try it out when you have completed all the steps above. You can access the login page. Looking at the source of the login page, you see that the paths to web resources start with /magnoliaAuthor. Logging in also fails since you are redirected to n incorrect path.

Tomcat adjustments to serve one context from root

We want to serve one instance from root to make sure the HTTP response body coming from Tomcat does not contain the context in the path.

Tip

Start with a Tomcat bundle of your choice, for a selection of bundles see list of preconfigured Magnolia bundles. If you want to test multisite scenarios, choose an EE pro bundle (such as magnolia-enterprise-pro-demo-bundle).

If want to get rid of the demo modules to start with a vanilla multisite module - remove the appropriate modules before you start the bundle for the first time. (On magnolia-enterprise-pro-demo-bundle delete the modules starting with magnolia-travel* from the folder magnolia-enterprise-x.y.z/apache-tomcat-8.5.5/webapps/magnoliaAuthor/WEB-INF/lib).

Before following the steps explained below, start the bundle as usual, to make sure both webapps magnoliaAuthor and magnoliaPublic are installed and work properly.


Table of Contents

Domains and /etc/hosts

This is an overview of the the multisite setup:


author instancepublic instance
comicsauthor.best-comics.netwww.best-comics.net
vinylauthor.best-comics.netwww.best-vinyl.net

Note that we use only one domain - a subdomain of the "main domain" - to access the author instance (which is recommended practice).

To enable this without DNS, add the following line to your /etc/hosts file:

Code Pro
127.0.0.1		author.best-comics.net www.best-comics.net www.best-vinyl.net


Apache setup

Make sure you have a working Apache on your local machine. 

Helpful Apache commands

Whenever you change Apache configuration files, you have to restart the httpd process.

Restart the process

Code Block
sudo apachectl restart

Check the configuration

Code Block
apachectl configtest

Enable mod_proxy, proxy_ajp_module

Make sure your Apache has the modules mod_proxy and proxy_ajp_module enabled.

Check the /etc/apache2/httpd.conf file and make sure the following lines are not commented:

Code Block
LoadModule proxy_module libexec/apache2/mod_proxy.so
# more line in between ...
LoadModule proxy_ajp_module libexec/apache2/mod_proxy_ajp.so

On a different OS, the path and suffix of the modules may be different. If you edit the file, you must restart Apache.

Enable vhosts

We use virtual hosts configuration in this setup. Make sure vhosts are enabled. Check the  /etc/apache2/httpd.conf file and ensure the line with the include directive is not commented:

Code Pro
languagetext
# Virtual hosts
Include /private/etc/apache2/extra/httpd-vhosts.conf

If you edit the file, you must restart Apache.

Define virtual hosts

If vhosts is properly enabled, edit the /etc/apache2/extra/httpd-vhosts.conf file and add something similar to this:

Code Pro
languagebash
linenumberstrue
<VirtualHost *:80>
    ServerName author.best-comics.net
#    ProxyPass / http://localhost:8080/
#    ProxyPassReverse / http://localhost:8080/
	ProxyPass / ajp://localhost:8009/
    ProxyPassReverse / ajp://localhost:8009/

    ErrorLog "/private/var/log/apache2/projekt.local-error_log"
    CustomLog "/private/var/log/apache2/projekt.local-access_log" common    
</VirtualHost>

Using ajp

See lines 3, 4 above which are commented: At first sight one may think that these ProxyPass rules should be sufficient. However, they're not. Some things will work, but especially the multisite setup won't do what we expect (sad).

Tip

Use the ajp protocoll to redirect from apache to Tomcat.

mod_jk is a known variant which works too, see apache documentation.

Since we use ajp - the ajp connector must be configured in the Tomcat server.xml - which is the case in the default server.xml which is provided by a Magnolia bundle. In the server.xml of your Tomcat you should find an entry as this:

Code Pro
<Connector port="8009" enableLookups="false" redirectPort="8443" protocol="AJP/1.3" /> 

This is the connector to which apache will redirect to.

Redirecting to Tomcat root

The apache redirect points to the Tomcat root context (see lines 5, 6 in the excerpt from httpd-vhosts.conf shown above).

Redirecting to ajp://localhost:8009/magnoliaAuthor - would work, but again, only partially. (Try it out, if you want to have fun.) Web resources would not load and redirections done by Magnolia would be incorrect. 


So, since the apache redirect points to the Tomcat root context, we must make sure that the webapp magnoliaAuthor is served from the root context. This needs a few modifications on Tomcat (see below).

Tomcat adjustments to serve one context from root

I guess there are different possible solutions to serve a Magnolia instance from Tomcat root context. Here comes one:

Use the <Context> directive which allows to define the path of a webapp.

Code Pro
<Context path="" docBase="magnoliaAuthor" />

The empty string ("") as value of the path attribute ensures to serve the webapp magnoliaAuthor from the root context.


<?xml version="1.0" encoding="UTF-8"?> <Server port="8005" shutdown="SHUTDOWN"> <Listener className="org.apache.catalina.startup.VersionLoggerListener" /> <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" /> <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" /> <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" /> <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" /> <GlobalNamingResources> <Resource name="UserDatabase" auth="Container" type="org.apache.catalina.UserDatabase" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" pathname="conf/tomcat-users.xml" /> </GlobalNamingResources> <Service name="Catalina"> <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> <Connector port="8009" enableLookups="false" redirectPort="8443" protocol="AJP/1.3" /> <Engine name="Catalina" defaultHost="localhost"> <Realm className="org.apache.catalina.realm.LockOutRealm"> <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/> </Realm> <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> <!-- server author from root --> <Context path="" docBase="magnoliaAuthor" /> <Valve
Expand
titleClick here to expand to see the complete server.xml
Code Pro
languagexml
titleserver.xml
linenumberstrue
<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN">
  <Listener className="org.apache.catalina.startup.VersionLoggerListener" />
  <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
  <Listener
Expand
titleClick here to expand to see the server.xml
Code Pro
languagexml
titleserver.xml
linenumberstrue
 className="org.apache.catalina.
valves
core.
AccessLogValve
ThreadLocalLeakPreventionListener" 
directory="logs" prefix="localhost_access_log" suffix=".txt" pattern="%h %l %u %t &quot;%r&quot; %s %b" />
/>


  <GlobalNamingResources>
    <Resource name="UserDatabase" auth="Container"
              
</Host>
type="org.apache.catalina.UserDatabase"
           
</Engine>
  
</Service> </Server>See line 37 - We ensure the context magnoliaAuthor is served from root. Note that Tomcat can only serve one webapp from root within the same host, and even within the same service.

...

It works. The same can be done with the context magnoliaPublic instead of magnoliaAuthor.

Usage in a production environment

In a productive environment, you probably have 2 hosts / servers in different networks, in which one server contains one Tomcat serving a single instance. If this is true, the setup described above is feasible.

Note

Use in a production environment at your own risk. This page is not intended as a guide for a System administrator. 

Serve both contexts from root

Now we expand the setup above to make sure we can access the Magnolia instances with the following domains:

...

www.best-comics.net

www.best-vinyl.net

Virtual hosts configuration

We add two more virtual hosts to Apache. Here is the httpd-vhosts.conf with three virtual hosts, one for the author instance and two for the public instance:

Code Pro
languagetext
linenumberstrue
<VirtualHost *:80>
    ServerName author.best-comics.net

    ProxyPass / http://localhost:8080/
    ProxyPassReverse / http://localhost:8080/
</VirtualHost>

<VirtualHost *:80>
    ServerName www.best-comics.net

    ProxyPass / http://localhost:8081/
    ProxyPassReverse / http://localhost:8081/
</VirtualHost>

<VirtualHost *:80>
    ServerName www.best-vinyl.net

    ProxyPass / http://localhost:8081/
    ProxyPassReverse / http://localhost:8081/
</VirtualHost>
Lines 11-12, 18-19: Note that the hosts www.best-comics.net and www.best-vinyl.net are redirected to localhost on port 8081, whereas author.best-comics.net redirects to localhost on port 8080.

(warning) The lines configuring the log files of the virtual hosts have been removed to keep this configuration excerpt small.

Tomcat adjustments

As mentioned above, one Tomcat host cannot serve two contexts from root. 

One solution is to have two running Tomcats, however, starting and stoping may be a bit time-consuming.

Instead, we can do the following:

  • Define two <Service> sections in the server.xml.
  • Each <Service>:
    • Has a <Connector> with a distinct port.
    • Serves from its own webapps directory.
    • Defines one host which wraps exactly one context to be served from root.

webapps directory

We assume that the bundle has already been started once and that both webapps have been properly installed.

This is the adapted Tomcat directory structure:

Code Pro
├── bin
├── conf
├── lib
├── webapps
│   ├── ROOT
│   └── magnoliaAuthor
└── webapps2
    └── magnoliaPublic

  • Create the folder webapps2.
  • Move the webapp magnoliaPublic to webapps2.

 

server.xml

...

languagexml
linenumberstrue

...

 description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml" />
  </GlobalNamingResources>


  <Service name="Catalina">

    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />


	<Connector port="8009" enableLookups="false" redirectPort="8443" protocol="AJP/1.3" />

    <Engine name="Catalina" defaultHost="localhost">

      <Realm className="org.apache.catalina.realm.LockOutRealm">
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
               resourceName="UserDatabase"/>
      </Realm>

      <Host name="localhost"  appBase="webapps" unpackWARs="true" autoDeploy="true">
		<!-- serve magnoliaAuthor from root -->  
		<Context path="" docBase="magnoliaAuthor" />
    
	    <Valve className="org.apache.catalina.valves.AccessLogValve" 
			directory="logs" 
			prefix="localhost_access_log" 
			suffix=".txt" pattern="%h %l %u %t &quot;%r&quot; %s %b" />
      </Host>
	  
    </Engine>
	
  </Service>
  
</Server>

See line 37: Added <Context> directive.

Tomcat can serve only one webapp from root within the same host and within the same service.

Image Added

It works.

However, since now we have only one context served from root. 

Usage in a production environment

In a productive environment, you probably have 2 hosts / servers in different networks, in which one server contains one Tomcat serving a single instance. If this is true, the setup described above is feasible.

Note

Use in a production environment at your own risk. This page is not intended as a guide for a System administrator. 

Serve both contexts from root from localhost

The following, extended setup allows to run and access both Magnolia instances from one Tomcat instance. 

(warning) Once again, this is a not required setup for productive environments, but it works fine on a local development machine.

These is the demanded setup:

author instancepublic instance
author.best-comics.net

www.best-comics.net

www.best-vinyl.net

Keep in mind that we already have defined redirects to localhost  for these three domains  (in the /etc/hosts file).

Virtual hosts configuration

In summary we need three virtual hosts on Apache - here is the modified httpd-vhosts.conf with one virtual host for the author instance and two for the public instances:

Code Pro
languagebash
linenumberstrue
<VirtualHost *:80>
    ServerName author.best-comics.net
	ProxyPass / ajp://localhost:8009/
    ProxyPassReverse / ajp://localhost:8009/
</VirtualHost>

<VirtualHost *:80>
    ServerName www.best-comics.net
	ProxyPass / ajp://localhost:8010/
    ProxyPassReverse / ajp://localhost:8010/
</VirtualHost>

<VirtualHost *:80>
    ServerName www.best-vinyl.net
	ProxyPass / ajp://localhost:8010/
    ProxyPassReverse / ajp://localhost:8010/
</VirtualHost>
  • Lines 3-4: author.best-comics.net redirects to localhost on port 8080
    => author instance
  • Lines 9-10, 15-16: www.best-comics.net and www.best-vinyl.net are redirected to localhost on port 8081
    => public instance
  • The lines configuring the log files of the virtual hosts have been removed to keep this configuration excerpt small.

Tomcat adjustments

As mentioned above, one Tomcat host cannot serve two contexts from root. 

We achieve this by the the following:

  • Define two <Service> sections in the server.xml.
  • Each <Service>:
    • Has  <Connector>s with distinct ports.
      • AJP connector
      • HTTP connector *
    • Serves from its own webapps directory.
    • Defines one host which wraps exactly one context to be served from root.

*) Actually the AJP connector would be sufficient to use tomcat via apache. However, if you also keep the HTTP connector, you can access tomcat also directly. And we also will use the HTTP connector for JCR activations from author to public context.

webapps directory

We assume that the bundle has already been started once and that both webapps have been properly installed.

This is the adapted Tomcat directory structure:

Code Pro
├── bin
├── conf
├── lib
├── webapps
│   ├── ROOT
│   └── magnoliaAuthor
└── webapps2
    └── magnoliaPublic


  • Create the folder webapps2.
  • Move the webapp magnoliaPublic to webapps2.
  • You may want delete the webapp ROOT, you won't be able to access it anymore.


server.xml

This is the server.xml:

Code Pro
languagexml
linenumberstrue
<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN">
  <Listener className="org.apache.catalina.startup.VersionLoggerListener" />
  <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
  <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />


  <GlobalNamingResources>
    <Resource name="UserDatabase" auth="Container"
              type="org.apache.catalina.UserDatabase

...

"
              

...

description="

...

User database that can be updated and saved"
              

...

factory="

...

org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml" />
  </GlobalNamingResources>


  

...

<Service name="

...

Catalina"

...

>
    <Connector port="8080" protocol="HTTP/1.1"
      

...

 

...

        

...

connectionTimeout="

...

20000"
      

...

      

...

   

...

redirectPort="

...

8443" 

...

/>
	<Connector port="8009" enableLookups="

...

false" 

...

redirectPort="

...

8443" 

...

protocol="

...

AJP/1.3" />
    <Engine name="Catalina" defaultHost="localhost">
      

...

<Realm className="org.apache.catalina.

...

realm.

...

LockOutRealm">
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/>
      </

...

Realm>
    

...

  <Host name="localhost"  appBase="webapps" unpackWARs="true" autoDeploy="true">
		<Context path="" docBase="magnoliaAuthor" />
	    <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="localhost_access_log" suffix=".txt" pattern="%h %l %u %t &quot;%r&quot; %s %b" />
      </Host>
    </Engine>
  </Service>
  
  <Service name="Catalina2">
    <Connector port="8081" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8444" />
	<Connector port="8010" enableLookups="false" redirectPort="8444" protocol="AJP/1.3" />
    <Engine name="Catalina2" defaultHost="localhost">
      <Realm className="org.apache.catalina.realm.LockOutRealm">
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/>
      </Realm>
      <Host name="localhost"  appBase="webapps2" unpackWARs="true" autoDeploy="true">
		<Context path="" docBase="magnoliaPublic" />
	    <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="localhost_access_log" suffix=".txt" pattern="%h %l %u %t &quot;%r&quot; %s %b" />
      </Host>
    </Engine>
  </Service>
  
  
  
</Server>

Note the following:

  • There are two <Service> sections, their name attributes have different values.
  • Every <Service> has its own <Connector>s with distinct ports
  • Each connector must have its own distinct ports on the attributes port and redirectPort.
  • The port of the AJP-<Connector> is the same port to which we redirect on the Apache virtual host configuration.

Final adjustments on the Magnolia instance

Adjust the subscriber for content activation

To ensure content activation still works, you have to adjust the property /server/activation/subscribers/magnoliaPublic8080@URL:

Advanced Tables - Table Plus
heading0
multiplefalse
enableHeadingAttributesfalse
enableSortingfalse
classm5-configuration-tree
enableHighlightingfalse
Node nameValue

Mgnl f
server


Mgnl f
activation


Mgnl f
subscribers


Mgnl n
magnoliaPublic8080


Mgnl n
subscriptions


Mgnl p
URL

http://localhost:8081

 Note that the activation is using the HTTP connector.

URLs of the final setup

If you have all done correctly - you can access the Magnolia instance by the following URLs

author instance
author.best-comics.netvia Apache and AJP connector
author.best-comics.net:8080via Tomcat and HTTP connector
localhost:8080
public instance
www.best-comics.netvia Apache and AJP connector
www.best-comics.net:8081via Tomcat and HTTP connector
www.best-vinyl.netvia Apache and AJP connector
www.best-vinyl.net:8081via Tomcat and HTTP connector
localhost:8081
  • There are two <Service> sections, their name attributes have different values.
  • Every <Service> has its own <Connector>
  • Each connector must have its own distinct ports on the attributes port and redirectPort.
  • The port of the <Connector> is the same port to which we redirect on the Apache virtual host configuration.

 

...