Skip to the content
Documentation

htaccess example

No ratings yet

Exponential 6 ships its Apache rewrite rules in two templates in the installation root: .htaccess_root for a normal site, and .htaccess_root_static, which also serves the pages of the static cache. Copy one of them to .htaccess with the console; do not write your own from older examples.

Put .htaccess into place

./console exp:setup:status                     # where .htaccess and config.php come from
./console exp:setup:htaccess                   # a dry run: shows what would be copied
./console exp:setup:htaccess --apply           # copies .htaccess_root to .htaccess
./console exp:setup:htaccess --static --apply  # or .htaccess_root_static

A new .htaccess gets the template's mode (and, run as root with --allow-root-user, its owner). When a .htaccess that differs is already there, the command shows the diff and leaves it alone; --force --apply backs it up to var/backup/setup/<time>/ and replaces it. Without the console, cp .htaccess_root .htaccess does the same copy. The same command puts config.php into place: ./console exp:setup:config --apply copies config.php-RECOMMENDED.

Apache reads .htaccess only when the virtual host allows it (AllowOverride All) and mod_rewrite is loaded. A 404 for every page usually means one of the two is missing.

What the rules do

These are the active rules of .htaccess_root in 6.0.15, without their comments:

DirectoryIndex index.php
RewriteEngine On
RewriteRule (^|/)\.(?!well-known(/|$)) - [R=404,L]
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^.+/[^/]+\.(php[0-9]?|phtml|phar)$ - [R=404,L]
RewriteRule ^api/ index_rest.php [L]
RewriteRule ^index_rest\.php - [L]
RewriteRule ^([^/]+/)?content/treemenu.* index_treemenu.php [L]
RewriteRule ^var/([^/]+/)?storage/images(-versioned)?/.* - [L]
<IfModule mod_headers.c>
    <FilesMatch "(?i)\.svgz?$">
        Header always set Content-Security-Policy "sandbox; default-src 'none'; style-src 'unsafe-inline'"
        Header always set X-Content-Type-Options "nosniff"
    </FilesMatch>
</IfModule>
RewriteRule ^var/([^/]+/)?storage/pdf/[A-Za-z0-9][A-Za-z0-9._-]*\.pdf$ - [L]
RewriteRule ^var/([^/]+/)?storage/original/image/.+\.(png|jpe?g|gif|webp|svg)$ - [L]
RewriteRule ^var/([^/]+/)?cache/(texttoimage|public)/.* - [L]
RewriteRule ^design/[^/]+/(stylesheets|images|javascript|fonts)/.* - [L]
RewriteRule ^share/icons/.* - [L]
RewriteRule ^extension/[^/]+/icons/[A-Za-z0-9_/-]+\.(svg|png|gif)$ - [L]
RewriteRule ^extension/[^/]+/design/[^/]+/(stylesheets|flash|images|lib|javascripts?|fonts|vendor|media)/.* - [L]
RewriteRule ^packages/styles/.+/(stylesheets|images|javascript)/[^/]+/.* - [L]
RewriteRule ^packages/styles/.+/thumbnail/.* - [L]
RewriteRule ^var/storage/packages/.+\.(png|jpe?g|gif|webp)$ - [L]
RewriteRule ^favicon\.ico - [L]
RewriteRule ^design/standard/images/favicon\.ico - [L]
RewriteRule ^robots\.txt - [L]
RewriteRule ^index\.js$ - [L]
RewriteRule ^sw\.js$ - [L]
RewriteRule ^w3c/p3p\.xml - [L]
RewriteRule .* index.php
  • Dot files and dot directories (.git, .env, .htaccess) answer 404, except .well-known.
  • A PHP script below the root never runs because its path was asked for.
  • /api/ goes to the REST API (index_rest.php); content/treemenu to index_treemenu.php.
  • Images, uploaded files, the public caches (packed scripts and styles) and the static files of designs and extensions are served as they are; uploaded SVG images are sandboxed.
  • Everything else goes to index.php, which answers settings/, var/, vendor/ and kernel/ with a page or a 404, never with the file.

Do not remove a security rule to make something work. After an upgrade, compare: ./console exp:setup:htaccess shows the diff between your .htaccess and the new template. A line-by-line explanation, with the optional sections in the comments of the template: Apache .htaccess example and Setting up .htaccess and config.php from the console.

For production, the rules belong in the virtual host with AllowOverride None, which is much faster: see Virtual host example.

Contributors

Comments

Add a comment

Comments are read by a moderator before they appear.