Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Multidomain Bundle Laravel Package

kunstmaan/multidomain-bundle

A Symfony bundle that adds multi-domain support to Kunstmaan CMS, letting a single installation serve several domains with their own hosts, locales, and content. Configure domains, route requests to the right site, and manage per-domain settings without duplicating your application.

View on GitHub
Deep Wiki
Context7

Getting Started

Read this first: it is a Symfony bundle, not a Laravel package. kunstmaan/multidomain-bundle is an add-on for KunstmaanCMS (kunstmaan/bundles-cms), built on Symfony's HTTP kernel, Doctrine, and the Kunstmaan node/page tree. There is no service provider, no config/multidomain.php, and no way to composer require it into a Laravel app. What you can port is the pattern — host header to site/locale resolution — which in Laravel is a config array plus ~40 lines of middleware.

If you are actually working in a Kunstmaan/Symfony codebase, the minimum path is:

  1. composer require kunstmaan/multidomain-bundle alongside a compatible kunstmaan/bundles-cms version (check the bundle's composer.json constraints first — this is an old, low-traffic package and version alignment is the most common first-day failure).
  2. Register the bundle in app/AppKernel.php (or config/bundles.php on Symfony 4+ Flex-style setups), after the Kunstmaan CMS bundles.
  3. Add the config block — the authoritative schema is DependencyInjection/Configuration.php inside the bundle, not the README. Typically it looks like:
kunstmaan_multi_domain:
    hosts:
        example.com:
            default_locale: en
            locales: [en, de]
        example.fr:
            default_locale: fr
            locales: [fr]
  1. Clear cache and hit each hostname with curl -H "Host: example.fr" http://localhost:8000/ and confirm the locale and content change.

First use case to validate: two public hostnames serving the same node tree, each with a different default locale, plus a separate admin host. If your default_locale swap works and your page URLs stop leaking the wrong host, the bundle is doing its job.

Where to look first, in order: DependencyInjection/Configuration.php (what config actually exists), the request/kernel.request listener (how host is resolved and what happens on a miss), and the domain/configuration service (the extension point you will decorate).

Implementation Patterns

Config as the single source of truth for the host map. Put every hostname — production, staging, and local — in config, and derive everything else (canonical URLs, hreflang, sitemaps, robots) from that map. Hardcoding a second list of domains in a Twig template or a controller is how multi-domain sites drift.

Keep the admin/backend host separate from frontend hosts. If the CMS backend answers on the same host as a site, host-based resolution will fight your security config and your cache. Give it its own hostname and exclude it from the frontend listener where possible.

Always generate absolute URLs from the resolved domain, not from the current Request. In CLI, cron, and queue contexts there is no request host, so absolute_url() falls back to router.request_context. Set the host explicitly before generating URLs:

$context = $this->router->getContext();
$context->setHost($domain->getHost());
$context->setScheme('https');

Do this in sitemap generators, mail builders, and any command that emits links. Otherwise your nightly sitemap is full of http://localhost.

Locale negotiation as a fallback chain: host default locale → explicit user choice (session/query) → Accept-Language → global default. The bundle handles the first hop; the rest is your listener with a higher priority.

Per-domain SEO surfaces. Generate one sitemap per host, one robots.txt per host (via a controller keyed off the resolved domain), and emit hreflang alternates by iterating the same host map. This is the payoff of centralising the config.

Cache keys must include the host. Any full-page cache, Varnish rule, Cloudflare cache rule, or Symfony HttpCache setup needs Host in the key. A page cached from example.fr served to example.com is the classic multi-domain outage.

Test with explicit hosts. In functional tests, request the full URL ($client->request('GET', 'https://example.fr/page')) rather than a path, and assert on locale/content per host. If you use X-Forwarded-Host in tests, configure trusted proxies or the listener won't see it.

Gotchas and Tips

  • Host is attacker-controlled. The bundle trusts the header by design. Only honour X-Forwarded-Host behind framework.trusted_proxies/trusted_hosts, and decide deliberately what an unknown host does — a 404, a redirect to a canonical host, or a silent fallback to the first domain. Silent fallback is a duplicate-content and SEO trap.
  • Ports and trailing dots. localhost:8000 and example.com. are not localhost and example.com. Normalise in your resolution layer or dev will work and production will not (or vice versa).
  • default_locale must be inside locales. A mismatch produces either a redirect loop or a 404 on the homepage, depending on how your locale listener is ordered. Assert this at container build time if you can.
  • CLI and workers have no host. Console commands, SitemapBundle generators, and Messenger/queue consumers all run without a Request. Anything that resolves a domain must be given one explicitly — make the domain a command argument rather than letting it default.
  • Ordering against your locale listener. kernel.request priority matters: if Symfony's LocaleListener runs first, the host-derived locale is overwritten. Check priorities with debug:event-dispatcher kernel.request when the wrong locale "randomly" appears.
  • Extension point is decoration, not configuration. Where the config tree is too coarse (e.g. per-domain feature flags, per-domain templates), decorate the domain configuration service or add a compiler pass rather than patching the bundle. Forking works but you will be on your own at the next bundles-cms upgrade.
  • Health check the maintenance status before you commit. This package sits at zero stars and no dependents, with an opportunity score in the mid-30s — it is effectively an internal component of KunstmaanCMS that was split out. Pin an exact version, read the source, and treat the code as the documentation.
  • If you are on Laravel, do not bridge it. Reimplement the pattern: a sites config keyed by host, a ResolveSite middleware that runs before SetLocale in the web group, URL::defaults() or an overridden UrlGenerator for absolute links, and Cache::tags()/host-prefixed keys. That gives you the same behaviour in a fraction of the surface area, with no Symfony/Doctrine coupling.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment