Restrict HTTP access
This chapter explains how to configure your web server (Apache, NGINX, IIS) to prevent public access to sensitive files in a TYPO3 installation. TYPO3 can be installed in classic (non-Composer) or Composer-based mode, and web server configuration differs significantly between the two. This chapter outlines recommendations for both setups.
If you are looking to control which system users and processes can access files at the operating system level, see Secure file permissions (operating system level).
Table of contents
Composer-based installations
For Composer-based TYPO3 installations, the public document root is typically
the public/
directory. All web-accessible files are
placed in this folder, while all sensitive and internal application files
(e.g., vendor/
, .git/
, configuration files) are stored outside
the document root by default.
This layout significantly reduces the risk of accidental exposure of sensitive files, eliminating the need for complex blacklisting rules.
Recommendations for Composer-based installations:
- Ensure the web server document root points to the
public/
directory only. - Verify that all non-public files (e.g.,
composer.
,json .env
,vendor/
,config/
) are outside of this directory. - Keep your
public/.
(Apache) or server config (NGINX/IIS) files updated to deny access to any critical files inside the public folder.htaccess - Store downloadable files that are only intended for authenticated users in File storage located outside the document root. Deliver them programmatically to authenticated users, for example using extensions like leuchtfeuer/secure-downloads .
Classic-mode installations
In classic TYPO3 installations (without Composer), all files are contained in the web root directory. This increases the risk of accidental exposure of internal files. For example, temporary files such as backups or logs may become accessible unless explicitly protected.
Restricting access to sensitive files
Some experts recommend denying access to certain file types (e.g.,
.bak
, .tmp
, .sql
, .old
) using web server rules
like Apache's Files
directive. This helps prevent downloads of
sensitive files that have accidentally been placed in the document root.
However, this is a workaround — not a real solution. The proper approach is to ensure sensitive files are never stored in the web root at all. Blocking access by file name patterns is unreliable, as future file names cannot be predicted.
Verification of access restrictions in Classic-mode installations
Administrators must verify that access to sensitive files is properly denied.
Attempting to access any of the following files should result in an HTTP 403
error:
https://
example. org/. git/ index https://
example. org/ INSTALL. md https://
example. org/ INSTALL. txt https://
example. org/ Change Log https://
example. org/ composer. json https://
example. org/ composer. lock https://
example. org/ vendor/ autoload. php https://
example. org/ typo3_ src/ Build/ package. json https://
example. org/ typo3_ src/ bin/ typo3 https://
example. org/ typo3_ src/ INSTALL. md https://
example. org/ typo3_ src/ INSTALL. txt https://
example. org/ typo3_ src/ Change Log https://
example. org/ typo3_ src/ vendor/ autoload. php https://
example. org/ typo3conf/ system/ settings. php https://
example. org/ typo3conf/ system/ additional. php https://
example. org/ typo3temp/ var/ log/ https://
example. org/ typo3temp/ var/ session/ https://
example. org/ typo3temp/ var/ tests/ https://
example. org/ typo3/ sysext/ core/ composer. json https://
example. org/ typo3/ sysext/ core/ ext_ tables. sql https://
example. org/ typo3/ sysext/ core/ Configuration/ Services. yaml https://
example. org/ typo3/ sysext/ extbase/ ext_ typoscript_ setup. txt https://
example. org/ typo3/ sysext/ extbase/ ext_ typoscript_ setup. typoscript https://
example. org/ typo3/ sysext/ felogin/ Configuration/ Flex Forms/ Login. xml https://
example. org/ typo3/ sysext/ backend/ Resources/ Private/ Language/ locallang. xlf https://
example. org/ typo3/ sysext/ backend/ Tests/ Unit/ Utility/ Fixtures/ clear. gif https://
example. org/ typo3/ sysext/ belog/ Configuration/ Typo Script/ setup. txt https://
example. org/ typo3/ sysext/ belog/ Configuration/ Typo Script/ setup. typoscript
Apache and Microsoft IIS web servers
In classic mode, TYPO3 automatically creates default web server config files
(.htaccess
for Apache, web.
for IIS) to deny access to
common sensitive files and directories.
These blacklist-style rules require ongoing maintenance. Administrators should regularly compare their config files with the TYPO3 reference templates:
- EXT:install/Resources/Private/FolderStructureTemplateFiles/root-htaccess (GitHub)
- EXT:install/Resources/Private/FolderStructureTemplateFiles/root-web-config (GitHub)
See Verify webserver configuration (.htaccess) for updating config files after major version upgrades.
NGINX Web Servers configuration (both installation modes)
NGINX does not support .htaccess
or similar per-directory configuration
so TYPO3 cannot install default protection automatically. Instead, administrators
must include appropriate deny rules in the virtual host configuration.
A sample configuration is provided by DDEV:
# Support for WebP
map $http_accept $webp_suffix {
default "";
"~*webp" ".webp";
}
# /index.php is used for TYPO3 v14+
# /typo3/index.php is used for TYPO3 pre-v14
map $typo3_index_exists $typo3_index {
default "/index.php";
1 "/typo3/index.php";
}
server {
listen 80 default_server;
listen 443 ssl default_server;
root {{ .Docroot }};
ssl_certificate /etc/ssl/certs/master.crt;
ssl_certificate_key /etc/ssl/certs/master.key;
include /etc/nginx/monitoring.conf;
index index.php index.htm index.html;
# Disable sendfile as per https://docs.vagrantup.com/v2/synced-folders/virtualbox.html
sendfile off;
error_log /dev/stdout info;
access_log /var/log/nginx/access.log;
# Security: Content-Security-Policy
# =================================
#
# Add CSP header for possible vulnerable files stored in fileadmin see:
# * https://typo3.org/security/advisory/typo3-psa-2019-010
# * https://docs.typo3.org/m/typo3/reference-coreapi/master/en-us/Security/GuidelinesAdministrators/ContentSecurityPolicy.html
# * https://github.com/TYPO3/TYPO3.CMS/blob/master/typo3/sysext/install/Resources/Private/FolderStructureTemplateFiles/resources-root-htaccess
# matching requested *.pdf files only (strict rules block Safari showing PDF documents)
location ~ /(?:fileadmin|uploads)/.*\.pdf$ {
add_header Content-Security-Policy "default-src 'self' 'unsafe-inline'; script-src 'none'; object-src 'self'; plugin-types application/pdf;";
}
# matching anything else, using negative lookbehind pattern
location ~ /(?:fileadmin|uploads)/.*(?<!\.pdf)$ {
add_header Content-Security-Policy "default-src 'self'; script-src 'none'; style-src 'none'; object-src 'none';";
# Deliver media files as WebP if available. The file as WebP must be in
# the same place (Original: "example.jpg", WebP: "example.jpg.webp").
try_files $uri$webp_suffix $uri =404;
}
# TYPO3 11 Frontend URL rewriting support
location / {
absolute_redirect off;
try_files $uri $uri/ /index.php$is_args$args;
}
# TYPO3 11 Backend URL rewriting support
location = /typo3 {
rewrite ^ /typo3/;
}
# check if /typo3/index.php exists
set $typo3_index_exists 0;
if (-f $document_root/typo3/index.php) {
set $typo3_index_exists 1;
}
location /typo3/ {
absolute_redirect off;
try_files $uri $typo3_index$is_args$args;
}
# pass the PHP scripts to FastCGI server listening on socket
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/run/php-fpm.sock;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_intercept_errors off;
# fastcgi_read_timeout should match max_execution_time in php.ini
fastcgi_read_timeout 10m;
fastcgi_param SERVER_NAME $host;
fastcgi_param HTTPS $fcgi_https;
# Pass the X-Accel-* headers to facilitate testing.
fastcgi_pass_header "X-Accel-Buffering";
fastcgi_pass_header "X-Accel-Charset";
fastcgi_pass_header "X-Accel-Expires";
fastcgi_pass_header "X-Accel-Limit-Rate";
fastcgi_pass_header "X-Accel-Redirect";
}
# Compressing resource files will save bandwidth and so improve loading speed especially for users
# with slower internet connections. TYPO3 can compress the .js and .css files for you.
# *) Set $GLOBALS['TYPO3_CONF_VARS']['BE']['compressionLevel'] = 9 for the Backend
# *) Set $GLOBALS['TYPO3_CONF_VARS']['FE']['compressionLevel'] = 9 together with the TypoScript properties
# config.compressJs and config.compressCss for GZIP compression of Frontend JS and CSS files.
location ~ \.js\.gzip$ {
add_header Content-Encoding gzip;
gzip off;
types { text/javascript gzip; }
}
location ~ \.css\.gzip$ {
add_header Content-Encoding gzip;
gzip off;
types { text/css gzip; }
}
# Prevent clients from accessing hidden files (starting with a dot)
# This is particularly important if you store .htpasswd files in the site hierarchy
# Access to `/.well-known/` is allowed.
# https://www.mnot.net/blog/2010/04/07/well-known
# https://tools.ietf.org/html/rfc5785
location ~* /\.(?!well-known\/) {
deny all;
}
# Prevent clients from accessing to backup/config/source files
location ~* (?:\.(?:bak|conf|dist|fla|in[ci]|log|psd|sh|sql|sw[op])|~)$ {
deny all;
}
location = /favicon.ico {
log_not_found off;
access_log off;
}
# TYPO3 - Block access to composer files
location ~* composer\.(?:json|lock) {
deny all;
}
# TYPO3 - Block access to flexform files
location ~* flexform[^.]*\.xml {
deny all;
}
# TYPO3 - Block access to language files
location ~* locallang[^.]*\.(?:xml|xlf)$ {
deny all;
}
# TYPO3 - Block access to static typoscript files
location ~* ext_conf_template\.txt|ext_typoscript_constants\.(?:txt|typoscript)|ext_typoscript_setup\.(?:txt|typoscript) {
deny all;
}
# TYPO3 - Block access to miscellaneous protected files
location ~* /.*\.(?:bak|co?nf|cfg|ya?ml|ts|typoscript|dist|fla|in[ci]|log|sh|sql)$ {
deny all;
}
# TYPO3 - Block access to recycler and temporary directories
location ~ _(?:recycler|temp)_/ {
deny all;
}
# TYPO3 - Block access to configuration files stored in fileadmin
location ~ fileadmin/(?:templates)/.*\.(?:txt|ts|typoscript)$ {
deny all;
}
# TYPO3 - Block access to libaries, source and temporary compiled data
location ~ ^(?:vendor|typo3_src|typo3temp/var) {
deny all;
}
# TYPO3 - Block access to protected extension directories
location ~ (?:typo3conf/ext|typo3/sysext|typo3/ext)/[^/]+/(?:Configuration|Resources/Private|Tests?|Documentation|docs?)/ {
deny all;
}
if (!-e $request_filename) {
rewrite ^/(.+)\.(\d+)\.(php|js|css|png|jpg|gif|gzip)$ /$1.$3 last;
}
include /etc/nginx/common.d/*.conf;
include /mnt/ddev_config/nginx/*.conf;
}
This example is taken from DDEV webserver config.