Appearance
Multisite
Several sites in one application, each on its own domain with its own database, as a WordPress network; the Sites screen makes them.
kitloom/multisite · admins: kitloom/multisite-filament, kitloom/multisite-nova
Video lessons
Recorded in the Filament admin; the Nova admin works the same way.
Several sites in one application, each on its own domain with a database of its own — a network, as WordPress Multisite is one. One codebase, one deploy, one set of modules installed; every site has its own content, users, theme, settings and switched-on modules, because all of that lives in its database already. The host of the request chooses the site before anything else runs.
How it works
The site .env describes is the main site. The other sites are rows of the sites table in the main database, made on the Sites screen of the admin or with multisite:create. Each row says which hosts the site answers (the first is its address, the others redirect to it) and where its data is:
| Database | What it means |
|---|---|
| SQLite file of its own | storage/sites/<name>/database.sqlite. Nothing to set up; fine for small sites and for a server with a disk. |
| MySQL database of its own | A database and a user you made on the server; the host and port of the main connection unless the site names others. |
| The main database, with a table prefix | The site's tables beside the main site's, under a prefix of their own (shop_posts, …) — as a WordPress network keeps its sites. |
On a request, the host picks the row and the application points its database connection, its uploads folder (storage/sites/<name>/uploads, or a prefix sites/<name>/ on an S3 disk), its address and its cache namespace at the site, then boots as it always does — reading the active theme, the switched-on modules and every setting from that database. A site cannot see its neighbours: the Sites screen, the commands and the agent tools answer on the main site only.
The module is switched on in .env, not on the Modules screen: which modules are on is kept in a site's database, and which database that is depends on this switch.
KITLOOM_MULTISITE=true
KITLOOM_MULTISITE_UNKNOWN_HOST=main # or 404: a host no site has gets "No site at this address"APP_URL must be the main site's address: its host is the one that asks no question.
Setting up a site
Sites → Add new in the admin (or
php artisan multisite:create shop shop.example.com www.shop.example.com [email protected]): the name, the hosts, the database. Leave Set the database up now ticked: the migrations run, the administrator is made and WordPress's options are written. The password is shown once.DNS: the site's hosts to the server.
The web server: the hosts to the same application. Caddy answers every host of one site block; Nginx needs the
server_nameand, for the uploads,/storage/of each host served from that site's folder — the deployment guide has the blocks.Caches, on every deploy after
php artisan optimize:bashphp artisan multisite:optimizeEach site gets its own config, route, event and admin-component caches in
bootstrap/cache/sites/<name>/; without them a site still runs, uncached.
Open the site's admin from the row's Open admin and sign in as the administrator the setup made.
The console
Every artisan command takes --site=<name> and runs on that site: php artisan migrate --site=shop, php artisan queue:work --site=shop. KITLOOM_SITE=shop in the environment does the same.
bash
php artisan multisite:list # the sites, the main one first
php artisan multisite:create NAME HOST... --email= # a site and its database (--driver=sqlite|mysql|main, --no-install)
php artisan multisite:setup --site=NAME --email= # the database of a site made with --no-install: migrations, WordPress's install, the administrator
php artisan multisite:run all "migrate --force" # a command on the main site and every site, a process each
php artisan multisite:run sites "cache:clear" # every site but the main one
php artisan multisite:optimize # each site's caches; --clear removes themSetting a database up always runs as a process of its own, booted as that site (multisite:setup --site=…), whether the Sites screen, multisite:create or an agent asks for it: what the main site's process has read of its own roles and permissions must not answer for the new site. The administrator's password goes to that process in KITLOOM_USER_PASSWORD, never on the command line.
The scheduler needs the one cron line a Laravel site has, schedule:run on the main site: it runs every site's schedule in a process of its own, every minute.
Queued jobs carry the site that queued them, and the worker switches onto it before the job runs: one queue:work (or Horizon) serves the network. A module switched off on the main site has no code in that worker, so a site that has it on gets a worker of its own, queue:work --site=<name> — or the main site keeps every module on.
What stays per site, what is shared
Per site: the database (content, users, roles, settings, the active theme, the switched-on modules), the uploads, the page cache, kitloom/backup's archives (storage/sites/<name>/backups), the module caches. Shared: the code, the installed modules and themes, the built theme assets, .env (mail transport, keys), Redis (with a key prefix per site), the queue.
Deleting a site on the Sites screen takes it off the list; its database and files stay where they are. Pause keeps it on the list and shows its visitors a page saying it is paused.
Limits
- Users are per site: an account on one site is not an account on another. A WordPress network shares its users across sites; a network moved here gets the users copied into each site.
- The main site's migrations are what a new site gets: keep every module on while sites are made, or run
migrate --site=<name>after switching one on. - Laravel Nova checks its licence against the request's domain; ask Laravel about a licence for the network's domains before running Nova sites this way. Filament has no such check.
- Laravel Octane is not supported yet: a worker that keeps the application between requests would keep the site too.
Configuration
config/kitloom-multisite.php (php artisan vendor:publish --tag=kitloom-multisite-config): path (the sites' folders, storage/sites), caches_path, uploads_disk, main_connection (the name the main connection is kept under while a site runs), unknown_host, and the switches of the admin sections and the agent tools.
For AI agents
With kitloom/ai: multisite_list, multisite_create, multisite_set_state — the network read, a site made with its database set up, a site paused or resumed. On the main site only, for whoever may manage sites.
Tests
From the application that installs the package: php vendor/bin/phpunit --testsuite Multisite.