How-to
Apache directives in ScalWS
This page maps the Apache httpd directives people use most to their ScalWS equivalent and says which ones scalwsctl migrate apache converts for you.
For the migration itself, see Migrating from Apache.
How to read the table
The column “Converted by scalwsctl migrate” uses four values:
- yes: the migration turns the directive into a site file key.
- ignored (not needed): the migration skips it without a note, because ScalWS does this by itself or has no setting for it.
- reported as TODO: the directive is not converted; the migration writes a
# TODO:line with the source file and line into the site file. - no: the migration does not read the directive at all, and there is no note.
What the migration reads:
- It follows
IncludeandIncludeOptional(relative toServerRoot, a directory includes every file in it) and reads every<VirtualHost>block. Directives outside a<VirtualHost>(apache2.conf,mods-enabled/*.conf,conf-enabled/*.conf) are not read, so a directive that is only set there gets no note. <IfModule>,<IfDefine>and<IfVersion>are transparent: their content counts as part of the virtual host.- Inside other sections (
<Directory>,<Location>,<Files>,<FilesMatch>, …) a directive that the migration does not handle is dropped without a note. The directives it handles anywhere are listed in the rows below (for exampleHeader,SetHandler,AllowOverride, access rules (Require,Order,Allow,Deny),RewriteRule).
Links in the “ScalWS equivalent” column go to the configuration reference.
Site keys are shown as they appear in a site file; the same keys exist under
tenants[].applications[] in the full configuration form.
Many per-directory settings have a direct equivalent in ScalWS’s .htaccess support,
enabled per site with htaccess: true. It
covers mod_rewrite, Redirect/RedirectMatch, Require/Order/Allow/Deny,
<Files>/<FilesMatch>, ErrorDocument, DirectoryIndex, Header and Expires*.
Virtual hosts, names and files
| Directive | ScalWS equivalent | Converted by scalwsctl migrate | Notes |
|---|---|---|---|
Listen | server.listeners | no | Outside <VirtualHost>. Listeners are server-wide, not per site. |
<VirtualHost> | one site file | yes | Each block becomes a virtual host. *:443 marks it as HTTPS. An HTTP host that only redirects to HTTPS and the HTTPS host with the same ServerName become one site with https_redirect. |
ServerName | domain | yes | A :port suffix is removed. A block without a usable name is skipped. |
ServerAlias | aliases, www | yes | www.<domain> becomes www: alias; a separate host for www.<domain> that only redirects to the bare domain becomes www: redirect. Names that are not domains are dropped with a note. |
DocumentRoot | root | yes | |
DirectoryIndex | static.index, php.index | yes | Written to php.index for a PHP site when a name ends in .php, otherwise to static.index when it differs from index.html. Also supported in .htaccess. |
<Directory> with AllowOverride | htaccess | yes | Any AllowOverride other than None, in any <Directory> of the host, gives htaccess: true. ScalWS then reads .htaccess files from the site’s root down to the requested directory. Other directives inside <Directory> are dropped without a note (see above). |
Options | none | ignored (not needed) | ScalWS never lists directories and never follows absolute symlinks. |
Alias | routes with a static runtime | reported as TODO | A static route does not strip its prefix by itself (route /assets with root /srv/app/public serves /srv/app/public/assets/…). Works when the aliased directory’s name matches the URL prefix; otherwise set the route’s rewrite.prefix to replace the prefix. |
Access control
| Directive | ScalWS equivalent | Converted by scalwsctl migrate | Notes |
|---|---|---|---|
Require, Order, Allow, Deny | .htaccess Require, security.deny_paths | reported as TODO | Every access rule except Require all granted (the default) is reported as TODO with its section, in the virtual host and inside <Directory>/<Location>; none is dropped silently. Re-create address restrictions in .htaccess (Require [not] ip …, Require local, Order/Allow/Deny, answered 403) or close paths for everyone with deny_paths (answered 404). Require valid-user, user, group, host, env are not supported and close the directory with 403 in .htaccess. |
AuthType, AuthName, AuthUserFile | routes[].basic_auth | reported as TODO | A route’s basic_auth checks an htpasswd file (users_file, bcrypt, SHA-256/512 crypt or Apache MD5 entries) with a realm. In .htaccess, Auth* directives are not supported and close the directory with 403 rather than publish it. |
.htaccess (mod_rewrite, mod_alias, mod_headers, mod_expires, access) | htaccess | yes | Converted from AllowOverride. Supported: RewriteEngine, RewriteBase, RewriteCond, RewriteRule (flags L, END, R=code, NC, QSA, QSD, NE, F, G, S=n, C), Redirect, RedirectPermanent, RedirectTemp, RedirectMatch, Require, Order/Allow/Deny, <Files>, <FilesMatch>, <IfModule>, ErrorDocument, DirectoryIndex, Header set|append|add|unset, ExpiresActive, ExpiresByType, ExpiresDefault. Refused and logged: [P], RewriteMap, SetHandler, AddHandler, php_value, php_flag, php_admin_*, regular expressions with look-around or back-references inside the pattern. Files up to 64 KiB and 1000 directives; edits apply within 2 seconds. |
mod_security (SecRuleEngine, SecRule, …) | security.deny_paths, security.rate_limits | reported as TODO | ScalWS has no rule-based web application firewall. Closest: deny_paths, per-path rate_limits, the deny rules of an application profile, and the built-in protections (strict request parsing, path normalisation, dotfiles never served). |
Redirects and rewrites
| Directive | ScalWS equivalent | Converted by scalwsctl migrate | Notes |
|---|---|---|---|
Redirect, RedirectPermanent | redirect, https_redirect | yes | Only a redirect of / is converted: to https:// on the same host it becomes https_redirect, to another origin a redirect runtime that keeps the path (status permanent/301, temp/302, seeother/303; default 302, RedirectPermanent 301). Redirects of other paths are reported; they work in .htaccess. |
RedirectMatch, RedirectTemp | .htaccess RedirectMatch / RedirectTemp | reported as TODO | Reported when set directly in the virtual host; inside a section they are dropped without a note. |
RewriteEngine | .htaccess RewriteEngine | ignored (not needed) | |
RewriteCond, RewriteRule | https_redirect, .htaccess RewriteRule | yes | Only the HTTPS redirect is converted: a RewriteCond on %{HTTPS}, %{SERVER_NAME} or %{HTTP_HOST} followed by a RewriteRule to https:// on the same host (certbot’s pattern) becomes https_redirect: true. Every other RewriteRule is reported as TODO, with the hint to move it into .htaccess. |
ErrorDocument | .htaccess ErrorDocument | reported as TODO | With htaccess: true: a local document is served with the original status, a URL redirects (302), text is sent as is. |
Proxying and application runtimes
| Directive | ScalWS equivalent | Converted by scalwsctl migrate | Notes |
|---|---|---|---|
ProxyPass | proxy.upstream, routes | yes | Only directly in the virtual host (inside <Location> it is dropped without a note). ProxyPass / URL sets the site’s proxy; ProxyPass /path URL becomes a route; ProxyPass /path ! is skipped. The target becomes its origin (http://host:port); a target path, or a / target under another prefix (ProxyPass /api http://b/), is reported as TODO, because Apache maps the prefix and a ScalWS route sends the full request path unless it sets rewrite.prefix. balancer:// groups are not converted: define a pool in the main configuration’s upstreams and use it from proxy.backends (see load balancing). |
ProxyPassReverse | none | reported as TODO | ScalWS does not rewrite Location headers from the upstream. Send the right Host with preserve_host so the application builds correct URLs. |
ProxyPreserveHost | proxy.preserve_host | yes | On gives preserve_host: true for the site’s proxy and every proxy route; without it the migration sets false (ScalWS’s own default is true). |
SetHandler "proxy:unix:…|fcgi://localhost" / proxy:fcgi://host:port | php.fastcgi | yes | The PHP-FPM socket becomes unix:/run/php/…sock, a TCP address tcp:host:port. Usually inside <FilesMatch \.php$>, which is fine. ProxyPassMatch to fcgi:// with php in the pattern is converted too. Other SetHandler values are reported. ScalWS can also run PHP-FPM itself with php.fpm. |
mod_php (LoadModule php_module, SetHandler application/x-httpd-php, php_value) | php.fpm, php.fpm.ini | no | mod_php is configured outside the virtual hosts, so a mod_php site migrates as a static site: add php to it. ScalWS runs PHP only through FastCGI, as an existing pool (php.fastcgi) or a managed PHP-FPM (php.fpm); php_value settings go to php.fpm.ini. SetHandler application/x-httpd-php in the virtual host is reported as TODO, and so is php_value set directly in it. |
ScriptAlias (CGI) | none | reported as TODO | CGI is not supported. Closest: run the program as an HTTP service and use a proxy route. |
WSGIScriptAlias, WSGIDaemonProcess | python with python.mode wsgi and python.app | reported as TODO | ScalWS starts the application server (gunicorn, uvicorn or hypercorn) from python.virtualenv and supervises it. |
Passenger (PassengerEnabled, PassengerAppRoot, …) | node, python, proxy | reported as TODO | Node.js and Python applications run as managed runtimes. There is no Ruby runtime: run the Ruby application server yourself and proxy to it. |
TLS
| Directive | ScalWS equivalent | Converted by scalwsctl migrate | Notes |
|---|---|---|---|
SSLEngine on | tls | yes | Marks the host as HTTPS. With server.acme.enabled the site gets tls: auto (a certificate from Let’s Encrypt); otherwise tls: manual and a TODO to add the certificate to the HTTPS listener. |
SSLCertificateFile | tls, server.listeners[].tls.certificates | yes | Marks the host as HTTPS like SSLEngine on. The file is named in the TODO when ACME is off; it is not copied. |
SSLCertificateKeyFile, SSLCertificateChainFile | server.listeners[].tls.certificates[].key | ignored (not needed) | For tls: manual, the certificate file holds the chain (end-entity first) and key the private key. |
SSLProtocol, SSLCipherSuite, SSLHonorCipherOrder, SSLCompression, SSLSessionTickets, SSLUseStapling, SSLOpenSSLConfCmd, Protocols | none | ignored (not needed) | No settings: TLS 1.2 and 1.3 with forward-secret AEAD suites, no OCSP stapling. HTTP/2 is always on (ALPN h2); HTTP/3 is server.listeners[].http3. |
Headers, caching and compression
| Directive | ScalWS equivalent | Converted by scalwsctl migrate | Notes |
|---|---|---|---|
Header | .htaccess Header | reported as TODO | Reported also inside sections. No site-level key for response headers; a route can set them with response_headers. With htaccess: true, Header [always] set|append|add|unset in .htaccess (no env=/expr= conditions; hop-by-hop and framing headers cannot be changed). ScalWS adds no Strict-Transport-Security by itself. |
ExpiresActive, ExpiresByType | .htaccess ExpiresActive, ExpiresByType, ExpiresDefault | reported as TODO | Reported also inside sections. |
mod_cache (CacheEnable, CacheDefaultExpire, …) | cache, server.cache | reported as TODO | Reported when set in the virtual host. ScalWS caches per site with cache (bypass paths, cookies and query parameters, default_ttl, stale_while_revalidate) in the shared memory and optional disk store of server.cache. |
mod_deflate (AddOutputFilterByType DEFLATE, SetOutputFilter) | static.precompressed | no | Usually set in mods-enabled/deflate.conf, which is not read (in a virtual host it is reported). ScalWS does not compress responses on the fly; with precompressed: true the static runtime serves an existing <file>.br or <file>.gz. In .htaccess, AddOutputFilterByType is ignored. |
Limits and timeouts
| Directive | ScalWS equivalent | Converted by scalwsctl migrate | Notes |
|---|---|---|---|
LimitRequestBody | server.limits.max_request_body_bytes | reported as TODO | Reported when set in the virtual host; inside <Directory> it is dropped without a note. Server-wide (default 10 MiB); a route can override it with max_body. A larger Content-Length gets 413. |
Timeout | server.limits.header_read_timeout, server.limits.body_read_timeout, server.limits.write_timeout, proxy.response_timeout | no | Usually global. ScalWS splits it: request head (15 s), gap between body chunks (30 s), stalled writes (60 s), and per runtime the time to the upstream’s response headers. In a virtual host it is reported. |
KeepAlive, KeepAliveTimeout | server.limits.idle_timeout | no | Usually global. There is no setting to turn keep-alive off; idle connections are closed after idle_timeout (default 60 s). In a virtual host they are reported. |
Logging and client addresses
| Directive | ScalWS equivalent | Converted by scalwsctl migrate | Notes |
|---|---|---|---|
CustomLog | server.logging.access_log, server.logging.format | ignored (not needed) | One line per request, on by default, json or text, written to the service log (journalctl -u scalwsd; under scalws-controller each instance’s own file, see logs). No per-site log files or custom formats. |
ErrorLog, LogLevel | server.logging.level | ignored (not needed) | Also to the service log. |
RemoteIPHeader, RemoteIPTrustedProxy | server.trusted_proxies, server.listeners[].proxy_protocol | reported as TODO | Reported when set in the virtual host (mod_remoteip is usually configured globally). For requests from a trusted peer, the client is the right-most X-Forwarded-For entry that is not itself a trusted proxy. Only X-Forwarded-For and the PROXY protocol are read: other headers (X-Real-IP, a CDN’s own header) are not supported. |