Skip to content

Multisite

v7.4+ Single-installation

Intro

Since v7.4+, XalokNext supports a simpler variant of multisite - a single installation can serve different sites. This benefits from a simplified configuration.

Configuration

The single-installation configuration is done through .env files, to enable loading it from this file:

yaml
# app/config/parameters/local.yml
wf_cms_admin.multisite:
  env: true

Then add a .env file in the root directory with a WF_CMS_MULTISITE variable that contains the json encoded definition of sites:

shell
WF_CMS_MULTISITE='{
    "defaultSite": "site1",
    "sites": {
        "site1":{
            "title": "Site number 1",
            "base_url":       "https://admin.common.tld",
            "public_url":     "https://site1.tld",
            "images_domain":  "https://imagenes.site1.tld",
            "imghandler_url": "https://imghandler.site1.url",
            "environment": {
                "S3_BUCKET": "site1-bucket",
                "S3_BUCKET_THUMBS": "site1-bucket-thumbs"
            }
        },
        "site2":{
            "title": "Site number 2",
            "base_url":       "https://admin.common.tld",
            "public_url":     "https://site2.tld",
            "images_domain":  "https://imagenes.site2.tld",
            "imghandler_url": "https://imghandler.site2.url",
            "environment": {
                "S3_BUCKET": "site2-bucket",
                "S3_BUCKET_THUMBS": "site2-bucket-thumbs"
            }
        },
    }
}'

Note: Since this file is not part of the normal configuration files for Symfony, every change to this file must be followed by clearing the Symfony cache. Note: If using a non-default port (e.g.: 8000), this must be part of the URLs configured above (e.g.: "base_url": "http://site1.localhost:8000")

  • defaultSite: the name (key) of the site to be used when a site cannot be determined, e.g.: when using Symfony commands.
  • sites: an array with sites definition, indexed by a key. Note, the key should be kept fairly short (below 10 chars), as it's being used amongst other things in naming site-specific Redis keys.

For each site, its definition can include:

  • title: the name of the site that is displayed in the admin site selector (dropdown menu next to the Xalok logo)
  • base_url: the base admin URL - note that for single-installations there is a unique admin domain for all sites
  • public_url: the base public URL
  • images_domain: keeps the _domain name for historical reasons, but it's actually the base URL for the images - used to prefix the images' URL.
  • imghandler_url: the base URL for the "imghandler" - the domain under which thumbnails that are not already created are being served
  • environment: a list of environment variables that are site-specific. Read the Site-specific environment variables section for details.

Loading sites

The sites are also stored in the database, to allow separating the entities (e.g.: categories, articles) by site. After changing the sites in the WF_CMS_MULTISITE environment variable, one needs to run:

shell
./app/admin/console --env=prod wf:cms:multisite:load

Note: Only the site key is kept in the database, so any other changes don't require running this. Note: Remember to clear Symfony's cache before running this command. Note: This command adds the sites to the database only if they don't exist, so running it multiple times won't have negative consequences

Migrating data

If there's already a database that holds the data for one of the sites and the project needs to migrate to multisite single-installation, XalokNext offers a command to assign existing entities to one of the sites:

shell
./app/admin/console --env=prod wf:cms:multisite:switch https://site1.tld

For performance reasons, this updates the database through SQL queries directly, that is - it doesn't hydrate entities. So one must follow this with a reindex of ElasticSearch.

Site-specific environment variables

Each site can define its own environment variables (see the sites[X].environment configuration above. Note that in order to avoid duplication, all the main keys are also registered (uppercased) as environment variables, e.g.: BASE_URL, PUBLIC_URL, IMAGES_DOMAIN - without the need to specify them (also) in sites[X].environment.

To use the values of these variables as parameters:

yaml
# app/config/parameters/local.yml
parameters:
  images_domain: '%env(IMAGES_DOMAIN)%' # this comes from `sites[X].images_domain
  s3_bucket: '%env(S3_BUCKET)%' # this comes from `sites[X].environment.S3_BUCKET
  s3_bucket_thumbs: '%env(S3_BUCKET_THUMBS)%'

Configuring the parameters using environment variables means that their value will be determined at request time, depending on which site is being served (public/images URLs) or depending on which site has been chosen to work on in the admin.

Note: The S3 buckets must be configured for each site independent of each-other in order to ease the redirection (imagenes.site1.tld -> imghandler.site1.tld) when a thumbnail wasn't previously created.

Multi-installation

Intro

The multi-installation variant supposes that each project will get its own installation (different repositories/projects). This relies on the wf_user tables being in sync across the different projects. That means that when starting a subsequent project, the wf_user table must be copied as it is in the first project. Once the multisite multi-installation is setup, changes to the users of one site are synced automatically to other installations.

nginx

nginx must be configured to switch the document root based on the value of wf_cms_site cookie:

nginx
map $cookie_wf_cms_site $site {
    default "site1dir";

    site1       site1dir;
    site2       site2dir;
}
server {
    listen 80;
    server_name admin.multisite.tld;
    root /var/www/$site/web;
}

In addition to the admin.multisite.tld, each of the installations must be accessible separately (admin.site1.tld, admin.site2.tld), for tools that don't send the cookie, like make wf_assets.

.make-config

The ADMIN_HOST is used for make wf_assets, which doesn't send the wf_cms_site cookie. Thus, it must be set to the individual CMS installation host (admin.site1.tld, etc.)

CMS parameters

Sessions

All installations must be configured to read/write sessions in the same directory:

yml
# app/admin/config/config_prod.yml
framework:
    session:
        save_path: /tmp/wfcms_session

admin_url

The admin_url parameter is used by the client-side application, so it needs to point to the "joint" domain (https://admin.multisite.tld/)

wf_cms_admin.multisite

wf_cms_admin.multisite parameter must be configured on all sites with a list of available sites

yaml
# app/config/parameters/local.yml
wf_cms_admin.multisite:
    multiinstallation: true
    sites:
        site1:
            base_url: admin.site1.tld
            public_url: site1.tld
            images_domain: img.site1.tld
            images_base_url: /files
        site2:
            base_url: admin.site2.tld
            public_url: site2.tld
            images_domain: img.site2.tld
            images_base_url: /files

The base_url is used to display (for example) in site1, when searching for images from site2. The user already has the wf_cms_site set to site1, so nginx would point to the /uploads directory of site1. To solve this, the images have the full path https://site2_base_url/uploads/...

Troubleshooting

Out of sync users table

If a site was added to the multisite config without importing the users table first, the easiest way to sync the users table is to load the fixtures and import the users table from an existing website:

make load_fixtures

Warning: This will delete the entire content from the DB - it should only be ran in DEV or PRE environments.

Note: this command refuses to run if the ADMIN_SF_ENV variable is set to prod in .make-config. Change it to dev temporarily, before running the command. Don't forget to set it back to prod once the fixtures are reloaded.

After reloading the fixtures, import a dump of the wf_users table from the currently running project.