These ten questions run the length of the chapter, and each turns on behavior that catches working developers out. Every snippet is a complete file on the Ubuntu 225 setup of Installing Apache with mod_rewrite, mod_headers and mod_expires enabled, Options FollowSymLinks and AllowOverride All unless a question says otherwise, and DocumentRoot /var/www/example. show.php prints get: and the $_GET array as JSON; index.php prints front controller: and the requested path. Run nothing: write down the status, Location and body each request gets, and why. The answers, with the section each comes from, are in Appendix H.
Questions
# 1. The virtual host. What do /private/a.txt and /private/reports/q3.txt return?
<VirtualHost *:80>
ServerName example.com
DocumentRoot /var/www/example
<Directory /var/www/example/private>
Require all denied
</Directory>
<Location "/private/reports">
Require all granted
</Location>
</VirtualHost>
# 2. /var/www/example/.htaccess, then docs/.htaccess. new.html and current.html exist,
# and docs/ has no index page. Status and X-Trail for /old.html, /docs/legacy.html,
# /docs/old.html and /docs/?
Options -Indexes
Header append X-Trail "root"
RewriteEngine On
RewriteRule ^(.*)old\.html$ $1new.html [L]
# --- docs/.htaccess
Header append X-Trail "docs"
RewriteEngine On
RewriteRule ^legacy\.html$ current.html [L]
# 3. AllowOverride FileInfo only. Each line is the whole of a separate .htaccess.
# Which ones leave / working, and what do the others log?
Header set X-Test "1"
ExpiresActive On
FallbackResource /index.php
Options -Indexes
php_value memory_limit 256M# 4. /var/www/example/blog/.htaccess. Requests: /blog/about, /blog/post?id=5, /blog/old-post.
# Which line after RewriteEngine On repairs the redirect?
RewriteEngine On
RewriteRule ^/about$ about.php [L]
RewriteRule ^post\?id=(\d+)$ show.php?id=$1 [L]
RewriteRule ^old-post$ new-post [R=301,L]
# 5. Requests: /a?y=2, /b?y=2, /tag/rock%20roll and /tag/c++
RewriteEngine On
RewriteRule ^a$ show.php?x=1 [L]
RewriteRule ^b$ show.php?x=1 [QSA,L]
RewriteRule ^tag/(.+)$ show.php?tag=$1 [L]
# 5b. These two lines are then appended. What happens to all four requests?
RewriteCond %{HTTP:X-Api-Version} -ge 2
RewriteRule ^api/(.*)$ show.php?v=2&r=$1 [B,L]
# 6. Meant to hide index.php. Requests: /index.php, /products/7, /css/site.css.
# What one condition fixes the broken one?
RewriteEngine On
RewriteRule ^index\.php$ / [R=301,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [L]# 7. Requests: /docs/v1/install?os=linux, /docs/v10 and /old-page
Redirect 301 /docs/v1 /docs/v2
Redirect 301 /old-page /new-page
RewriteEngine On
RewriteRule ^old-page$ show.php?from=rewrite [L]
# 8. .env, .git/config and config.php.bak (PHP source with a password) all exist.
# What do /.env, /.git/config and /config.php.bak return?
<FilesMatch "^\.">
Require all denied
</FilesMatch>
# 9. Requests: /, /missing and /old. Status, Location, and which of the two headers?
Header set X-Frame-Options "DENY"
Header always set X-Content-Type-Options "nosniff"
ErrorDocument 404 https://example.com/errors/404.html
Redirect 301 /old /new# 10a. Copied unchanged from .htaccess into <VirtualHost>, with AllowOverride None, and
# configtest says Syntax OK. Requests: /old-blog/2026/post.html and /css/site.css
RewriteEngine On
RewriteRule ^old-blog/(.*)$ /blog/$1 [R=301,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
# 10b. The same four lines, unchanged, inside the virtual host's directory section.
# What do the two requests return now, and why?
<Directory /var/www/example>
RewriteEngine On
RewriteRule ^old-blog/(.*)$ /blog/$1 [R=301,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
</Directory>