b13 / restricted-domains
Restrict single domains of a TYPO3 site to logged-in backend users.
Package info
github.com/b13/restricted-domains
Type:typo3-cms-extension
pkg:composer/b13/restricted-domains
Requires
- php: ^8.1
- typo3/cms-core: ^12.4 || ^13.4 || ^14.0 || ^15.0
- typo3/cms-fluid: ^12.4 || ^13.4 || ^14.0 || ^15.0
- typo3/cms-frontend: ^12.4 || ^13.4 || ^14.0 || ^15.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.51
- phpstan/phpstan: ^1.10 || ^2.0
- typo3/cms-backend: ^12.4 || ^13.4 || ^14.0 || ^15.0
- typo3/coding-standards: ^0.8
- typo3/testing-framework: ^8.0 || ^9.0
This package is auto-updated.
Last update: 2026-08-15 07:56:15 UTC
README
EXT:restricted_domains - Close single domains of a TYPO3 site for the public
A site is often reachable under more than one domain: the public one, plus a CMS/editing domain editors work on, plus whatever the staging setup adds. Those extra domains serve the very same page tree, so everything reachable there is duplicate content for crawlers and an unintended second entry point for visitors.
This extension closes such a domain for everybody but logged-in backend users.
Features
- Marks a whole site or a single base variant as "backend users only" - right in the site configuration
- Lets whole networks in without a login: office, VPN or monitoring addresses as an IP list, wildcard or CIDR range
- Works with a checkbox in the Sites backend module, no TypoScript and no template changes needed
- Answers denied requests with a
403 Forbidden(or404, if you prefer) and anX-Robots-Tag: noindex, nofollowheader - Ships a small, self-contained "access denied" page that links to the backend, and lets you rebrand it with your own Fluid template
- Leaves the TYPO3 backend itself untouched, so editors can always log in
- Supports TYPO3 v12.4, v13, v14 and v15 from a single extension version
Why did we create this extension?
Editing domains are a fact of life in bigger projects: cms.example.com next to www.example.com,
a staging domain next to both. Technically they are the same site, and TYPO3 happily delivers the
complete page tree under every one of them.
The usual workarounds all have a catch. Blocking the domain in the web server means editors cannot
preview anything. robots.txt and noindex are advisory and do nothing against a visitor who has
the URL. Basic authentication needs a second set of credentials that nobody wants to maintain, and
it breaks preview links.
EXT:restricted_domains uses the credentials that are already there - the backend login. If a
backend user is logged in, the domain behaves exactly as before, previews included. Everybody else
gets a 403.
Installation
Install this extension via composer req b13/restricted-domains or download it from the
TYPO3 Extension Repository and
activate it in the Extension Manager of your TYPO3 installation.
Configuration
Mark a domain as restricted in the site configuration - either in the Sites backend module or
directly in config/sites/<identifier>/config.yaml.
Restrict a single base variant:
base: 'https://www.example.com' baseVariants: - base: 'https://cms.example.com' condition: 'applicationContext == "Production/Editing"' requireBackendUserLogin: true
Base variant conditions are evaluated without a request - the variables at hand are
applicationContext, getenv() and the other ones TYPO3 offers for site configuration, but not
the host of the current request. A variant therefore describes the domain of an environment
(the editing instance, staging, local development), not a second domain served by the same
instance. To close a domain that the very same instance serves next to the public one, restrict
the site as a whole on that instance, or give the editing instance its own application context.
Restrict the site as a whole, no matter which domain it is served under:
base: 'https://staging.example.com' requireBackendUserLogin: true
The flag of the base variant that is active for the current request wins. Only if that variant does not carry the flag at all - or if no variant matches and the plain base is in use - the site-level flag applies. This way a single domain can opt in or out independently of the site.
Letting IP addresses in without a login
A restricted domain is not only open to logged-in backend users: requests coming from an address in
allowedIpAddresses are answered as well. That covers the office network, a VPN, an uptime monitor
or a screenshot service - anything that cannot log in but should still see the site.
base: 'https://staging.example.com' requireBackendUserLogin: true allowedIpAddresses: '192.168.0.0/24, 203.0.113.*, 2001:db8::/32'
The list uses the same notation as everywhere else in TYPO3: comma-separated, IPv4 and IPv6,
wildcards (192.168.*.*), CIDR ranges (192.168.0.0/24) and * for any address. A YAML list of
addresses works as well. Base variants carry the setting too, and a list on the active variant
takes precedence over the one of the site - an empty one, however, falls back to the site instead
of denying everybody:
baseVariants: - base: 'https://cms.example.com' condition: 'applicationContext == "Production/Editing"' requireBackendUserLogin: true allowedIpAddresses: '203.0.113.10'
The address is taken from TYPO3's NormalizedParams, so a setup behind a reverse proxy or load
balancer needs the usual $GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyIP'] configuration to
see the real client address - otherwise every visitor arrives with the proxy's address.
Leaving allowedIpAddresses empty (the default) means the backend login is the only way in.
What a denied request gets
A 403 Forbidden carrying a small, self-contained HTML page with a link to the backend, plus an
X-Robots-Tag: noindex, nofollow header. Both can be changed in the extension configuration:
| Setting | Default | Meaning |
|---|---|---|
statusCode |
403 |
403 states that the domain exists but is closed, 404 hides it entirely. |
templateRootPath |
EXT:restricted_domains/Resources/Private/Templates/ |
Point this at your own directory holding an AccessDenied.html to rebrand the page. |
The template is rendered with Fluid and gets {backendUri} assigned.
Known limitation
The core eID middleware (typo3/cms-frontend/eid) resolves ahead of this one, so extension eID
endpoints stay reachable on a restricted domain.
Compatibility
| Extension version | TYPO3 versions |
|---|---|
| 0.1.x | v12.4, v13, v14, v15 |
The extension talks to the view layer through a small adapter, because TYPO3 v13.3 introduced the
ViewFactory and v14 removed StandaloneView - so the "access denied" template renders the same on
every supported version, including your own template override.
Running the tests
composer install composer ci:tests:unit typo3DatabaseDriver=pdo_sqlite composer ci:tests:functional composer ci:php:cgl composer ci:php:stan
The functional tests send real frontend requests through the middleware stack, so they need a database - sqlite is the least setup, any other TYPO3-supported database works as well. CI runs the whole set against v12, v13 and v14 on the PHP versions each of them supports; the v15 job follows once v15 is released.
License
The extension is licensed under GPL v2+, same as the TYPO3 Core. For details see the LICENSE file in this repository.
Credits
This extension was created by Benni Mack in 2026 for b13 GmbH, Stuttgart.
Find more TYPO3 extensions we have developed that help us deliver value in client projects. As part of the way we work, we focus on testing and best practices to ensure long-term performance, reliability, and results in all our code.