Container images
This page is for bundlers who publish Exponential as a container image. The Exponential repository contains no Dockerfile or compose file; the guidance below is generic and built on what the documentation states. Velocity, the web server that is part of Exponential, does publish images you can build on.
Warning
.htaccess slows down every request. When .htaccess files are enabled (AllowOverride anything but None), let alone
used, Apache looks for them and reads and evaluates them on every request, in every directory of the path, and
page loading times go up drastically (measured). The only real fix is to switch the feature off for
the virtual host: AllowOverride None in the HTTPS virtual host, and the rules in the virtual host's own
configuration as mod_rewrite rules. That is far faster in production speed tests and well worth the time it takes
to optimize a production configuration. Switch over right away: copy the rules of the
example HTTPS virtual host into your virtual host (with the static cache, also
staticcache_offload.conf), set AllowOverride None, run apachectl configtest, reload Apache and
test the site. The same rules for other servers: nginx, LiteSpeed,
Caddy, IIS, Velocity (built in); where virtual host rules go in a control
panel: Plesk, cPanel, DirectAdmin, ISPConfig.
On LiteSpeed or OpenLiteSpeed, the server's own page cache can also answer anonymous visitors and crawlers without PHP: Page caching with LiteSpeed and OpenLiteSpeed.
Contents
- What the sources say
- Choosing a base
- Image or volume
- An entry point
- Secrets and the database
- Image checklist
What the sources say
- "Docker and Podman (Linux containers) are tier 2, known to work" (Operating system support).
- "Any image with PHP 8 and the extensions above runs Exponential ... Keep
var/(storage, logs, the SQLite database) andsettings/overrideon a persistent volume. With SQLite, run one container that writes" (Containers, cloud and hosting panels). exp:installis the method for "CI pipeline, container image, automated test environment" (4.5).
Choosing a base
| Route | Notes |
|---|---|
| Your own image from a PHP 8.0+ base | install every required PHP extension: dom, xsl, intl, mbstring, iconv, zlib, one database extension, gd or ImageMagick, and for Velocity sockets, pcntl, openssl |
Velocity's image ghcr.io/se7enxweb/exponential-velocity | tagged <release>-php<version>-<variant>; "Pin a fixed tag in production"; the standard variant is "what the documentation assumes" |
Source: Containers: Docker and Podman. Whichever base,
run php bin/php/console exp:velocity ext check inside the built image in your pipeline.
A generic build, in words rather than a Dockerfile:
- Start from the pinned base.
- Copy your bundle's
composer.jsonandcomposer.lock; runcomposer install --no-dev --no-interactionas the user the site will run as. - Add your site package files and import them, or plan to import at first start (Offline bundles).
- Regenerate autoloads (Caches and autoloads after building).
- Set ownership of the writable directories (File permissions).
- Add the entry point below; do not run the installer during the build.
Steps 4 and 5 are also the place for .htaccess (when the image runs Apache) and config.php. The commands ask
nothing, end with PASS: or FAIL: and change nothing on a second run; a build step usually runs as root, so give
--allow-root-user and the site's user:
php bin/php/console exp:setup:htaccess --apply --allow-root-user --owner=www-data:www-data
php bin/php/console exp:setup:config --apply --allow-root-user --owner=www-data:www-data
php bin/php/console exp:config:set EZP_INI_FILEMTIME_CHECK false --apply --allow-root-userNever bake a password into config.php in the image. Set such values at start, in the entry point, from the
container's environment:
php bin/php/console exp:config:set CLUSTER_STORAGE_HOST "$CLUSTER_DB_HOST" --apply --allow-root-user
php bin/php/console exp:config:set CLUSTER_STORAGE_PASS --value="$CLUSTER_DB_PASS" --apply --allow-root-user(Setting up .htaccess and config.php from the console).
Image or volume
| Path | Where |
|---|---|
kernel/, lib/, vendor/, extension/, design/ | in the image |
var/ | persistent volume |
settings/override | persistent volume |
settings/siteaccess | persistent volume |
"Never bake settings/override into an image: it holds the database credentials"
(Containers). Decide the user ID once for the image and
the volume, and keep it.
An entry point
The documented minimal entry point "installs once, then starts the server and stays in the foreground while it runs" (4.6):
#!/usr/bin/env bash
set -euo pipefail
cd /srv/exponential
if ! grep -q '^\[DatabaseSettings\]' settings/override/site.ini.append.php 2>/dev/null; then
php bin/php/console exp:install --apply \
--db=mysql --db-host="${DB_HOST}" --db-name="${DB_NAME}" --db-user="${DB_USER}" \
--url="${SITE_URL}" --email="${ADMIN_EMAIL}" --password="${ADMIN_PASSWORD}"
fi
php bin/php/console exp:velocity start
# exp:velocity start runs the server in the background and returns; status exits 0 while it runs
while php bin/php/console exp:velocity status >/dev/null 2>&1; do sleep 30; done
echo "Velocity stopped" >&2
exit 1- Pass
EXP_INSTALL_DB_PASSWORDin the container's environment. - "If the entry point runs as
root, add--allow-root-userto the twoexp:velocitycommands." - Change
--dbto the database of your bundle (sqliteis the default,pgsqlthe recommended server). - Without
--password, a 24-character password is generated and written tovar/log/initial-admin-password; tell the recipient how to read it once.
Secrets and the database
- SQLite: one writing container per database file; "SQLite's WAL needs shared memory on one host".
- Several replicas: a database server ("PostgreSQL first"), shared storage for
var/storage, and sessions every container can read (Kubernetes). - Cron still has to run: a scheduler container sharing the volumes, as the same user (Containers).
Image checklist
- To do: Base image pinned by tag or digest; Composer from the lock file;
--no-dev. - To do:
exp:velocity ext checkpasses in the image. - To do: No
settings/override,settings/siteaccess,kickstart.ini, logs or caches from the build in the image. - To do:
config.phpin the image holds no secret (set at start withexp:config:set);exp:config:list --only-set --format=jsonchecked in CI. - To do: Volumes documented:
var/,settings/override,settings/siteaccess. - To do: The entry point installs once and keeps the main process alive.
- To do: The source of every GPL component is offered (GPL obligations).
- To do: Labels or notes name the Exponential version and your bundle version.
Related pages
- Containers: Docker and Podman
- First boot and install once
- Velocity in a bundle
- Setting up .htaccess and config.php from the console
- Free documentation: this page is free to copy, translate and improve under the GNU FDL 1.3.
Become an Exponential Partner
Partners share their information, provide funding, contribute back and develop the products with us, and that is how Exponential grows. A partner website and dashboard are planned for mid-2027: please become a partner today to speed up our growth rate and land new features faster.