Skip to the content
Documentation
Help Start
Reading in:
  • German: 9,059 of 9,059 pages
About the help in other languages
All help pages

Container images

How to bundle Exponential as a Docker or Podman image - the project ships no Dockerfile, so this page gives generic guidance - choosing a base, what goes in the image and what on volumes, the documented entry point that…

Download as PDF

Address: https://doc.exponential.earth/exphelp/viewer/help/bundlers/container-images.md

On this page

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

  1. What the sources say
  2. Choosing a base
  3. Image or volume
  4. An entry point
  5. Secrets and the database
  6. 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) and settings/override on a persistent volume. With SQLite, run one container that writes" (Containers, cloud and hosting panels).
  • exp:install is the method for "CI pipeline, container image, automated test environment" (4.5).

Choosing a base

RouteNotes
Your own image from a PHP 8.0+ baseinstall 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-velocitytagged <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:

  1. Start from the pinned base.
  2. Copy your bundle's composer.json and composer.lock; run composer install --no-dev --no-interaction as the user the site will run as.
  3. Add your site package files and import them, or plan to import at first start (Offline bundles).
  4. Regenerate autoloads (Caches and autoloads after building).
  5. Set ownership of the writable directories (File permissions).
  6. 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-user

Never 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

PathWhere
kernel/, lib/, vendor/, extension/, design/in the image
var/persistent volume
settings/overridepersistent volume
settings/siteaccesspersistent 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_PASSWORD in the container's environment.
  • "If the entry point runs as root, add --allow-root-user to the two exp:velocity commands."
  • Change --db to the database of your bundle (sqlite is the default, pgsql the recommended server).
  • Without --password, a 24-character password is generated and written to var/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 check passes in the image.
  • To do: No settings/override, settings/siteaccess, kickstart.ini, logs or caches from the build in the image.
  • To do: config.php in the image holds no secret (set at start with exp:config:set); exp:config:list --only-set --format=json checked 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.

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.

Something wrong on this page? Report an error

Documentation license

This documentation is free documentation, licensed under the GNU Free Documentation License 1.3 or later.

Exponential Copyright © 1998-2026 Exponential Foundation and 7x