Files
cloud-apache-container/configs/litespeed/site-template.tpl
shadowdaoandClaude Opus 5.5 74648ba34b fix(security): deny config/VCS dotfiles over HTTP on standalone cac and cac-litespeed
Measured on .148: standalone cac served /.env with its contents, and
cac-litespeed served /.env even at mode 0640 (OLS runs as the customer uid
there). shared-httpd and shared-ols already deny these via WHP's drop-ins; the
standalone tiers never got them.

- cac: new configs/whp-security.conf in /etc/httpd/conf.d — the same named
  FilesMatch + DirectoryMatch list as WHP's shared-httpd-security.conf,
  re-rooted to /home.
- cac-litespeed: the same `context exp:` regex as WHP's shared-ols vhconf
  template, added to the vhost template.

Named list (.user.ini .env* .git .svn .hg .bzr .ht* .whp .site-builder), not a
blanket dotfile deny, so /.well-known/ stays reachable. HTTP only: PHP still
reads these files from disk.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 16:31:56 -07:00

110 lines
4.1 KiB
Smarty

## OLS vhTemplate for the per-customer vhost. Mirrors the structure of the
## upstream docker.conf template but with our paths and LSCache wiring.
## Templated vars (envsubst): $user
##
## $VH_NAME, $VH_ROOT, $DOC_ROOT, $SERVER_ROOT are OLS macros — they MUST
## stay literal in the output (not in the envsubst allow-list).
allowSymbolLink 1
enableScript 1
restrained 1
## No setUIDMode — OLS itself runs as ${user} (set at server level by
## create-vhost-litespeed.sh), so lsphp inherits that uid without needing
## suEXEC per request. This is the key to single-lsphp-instance topology:
## with setUIDMode 2, each httpd worker had to lscgid-spawn its own lsphp
## (= N opcache shmem segments). Without it, ONE persistent lsphp parent
## serves all httpd workers via the shared socket, and LSAPI children-mode
## actually works (1 parent + N children = 1 shmem segment).
##
## Safe because cac-litespeed is one-customer-per-container — the container
## boundary IS the privsep boundary.
vhRoot /home/${user}/public_html/
configFile $SERVER_ROOT/conf/vhosts/$VH_NAME/vhconf.conf
virtualHostConfig {
docRoot $VH_ROOT
## Drop-in log paths matching cac:phpNN (Apache+FPM bundled) so existing
## WHP log-gathering code (whp-traffic-aggregator.php, process-log-review.php,
## customer-facing log views) keeps working unchanged for migrated sites.
## Customer's "Apache access log" is just OLS's access log under the same
## filename. No `.log` suffix — matches the bundled cac convention.
errorlog /home/${user}/logs/apache/error_log {
useServer 0
logLevel WARN
rollingSize 10M
keepDays 14
compressArchive 1
}
accesslog /home/${user}/logs/apache/access_log {
useServer 0
rollingSize 10M
keepDays 7
compressArchive 1
}
index {
useServer 0
indexFiles index.php, index.html
autoIndex 0
}
## LSCache plugin owns Cache-Control / Expires entirely — server-level
## expires off so we don't double-emit headers.
expires {
enableExpires 0
}
accessControl {
allow *
}
context / {
location $DOC_ROOT/
allowBrowse 1
rewrite {
enable 1
inherit 0
autoLoadHtaccess 1
RewriteFile .htaccess
}
addDefaultCharset off
}
## SECURITY: never serve config / VCS dotfiles over HTTP. Same named list as
## WHP's shared-ols vhconf template (first `context exp:` there) and
## shared-httpd's 000-whp-security.conf. Measured on .148: this tier served
## /.env even at mode 0640, because OLS runs as the customer uid here. An
## `exp:` regex context wins over the `context /` prefix context regardless
## of order (measured on OLS 1.8.4 for shared-ols), so a customer .htaccess
## cannot reopen it. Named, not blanket "^\.": /.well-known/ (ACME,
## security.txt, app-site-association) must stay reachable.
context exp:^/(.*/)?\.(user\.ini|env|git|svn|hg|bzr|ht|whp|site-builder) {
allowBrowse 0
}
rewrite {
enable 1
autoLoadHtaccess 1
logLevel 0
## Force HTTPS — OLS 1.8 listener-level rewrites don't apply per-vhost,
## so the redirect lives here. The RewriteCond guards against an infinite
## loop (SERVER_PORT=80 means "this request came in on the HTTP listener,
## not HTTPS"). Per-customer .htaccess rules still apply (autoLoadHtaccess).
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [L,R=301]
}
## Per-vhost LSCache storage. The server-level `module cache` block in
## stock httpd_config.conf is already enabled (ls_enabled 1); the LSCWP
## plugin flips cache on/off per request via X-LiteSpeed-Cache-Control.
module cache {
storagePath /home/${user}/lscache
checkPrivateCache 1
checkPublicCache 1
enableCache 0
enablePrivateCache 0
}
}