============================== Running mod_wsgi-express ============================== ``mod_wsgi-express`` is the admin command installed alongside the ``mod_wsgi`` Python package. It builds the mod_wsgi Apache module against the Apache and Python on your host, generates a self-contained Apache configuration tuned for hosting a single WSGI application, and starts an Apache instance owned by your user. This page picks up from :doc:`../getting-started`, which already covers the first-run "Hello world" with ``mod_wsgi-express start-server``. Here the focus is on the operational shape: common options, running on privileged ports, dealing with non-standard Apache layouts, Django and Flask integration, and using ``mod_wsgi-express`` under a process supervisor or in a container. For installing the ``mod_wsgi`` package itself, see :doc:`installation-from-pypi`. Subcommands ----------- ``mod_wsgi-express`` is invoked as ``mod_wsgi-express ``. The commands fall into two groups. For running an Apache instance hosting your WSGI application: * ``start-server`` runs an Apache instance in the foreground, hosting the WSGI script you supply. This is the common case during development and the typical entry point under a process supervisor. * ``setup-server`` writes out the same configuration plus a generated ``apachectl`` wrapper, but does not start Apache. Used for daemonised init-script style deployments where Apache is started and stopped separately. See `Running on a privileged port`_ below. For wiring the pip-built mod_wsgi module into a system Apache: * ``module-config`` prints the ``LoadModule`` and ``WSGIPythonHome`` lines needed to reference the module from inside the Python install. * ``install-module`` copies the module into Apache's modules directory and prints the corresponding ``LoadModule`` line. * ``module-location`` prints just the filesystem path to the built module. The ``module-config`` and ``install-module`` paths are covered in detail under "Connecting the pip-built module to system Apache" in :doc:`installation-from-pypi`. Verifying the installation -------------------------- The ``mod_wsgi.diagnostics`` submodule ships two minimal WSGI applications usable as quick install checks before pointing ``mod_wsgi-express`` at a real application:: mod_wsgi-express start-server --application-type module \ mod_wsgi.diagnostics.environ This serves the diagnostic page at http://localhost:8000/. A successful request confirms that the Python interpreter, the built ``mod_wsgi.so``, the generated Apache configuration, and the request path through to the WSGI handler all line up. The bundled applications are: ``mod_wsgi.diagnostics.environ`` Diagnostic page showing the WSGI ``environ`` dictionary, the process and host environment, mod_wsgi process and server metrics, Apache build details, and the Python interpreter's locale and path settings. ``mod_wsgi.diagnostics.hello`` The smallest possible "Hello World!" WSGI application. Useful when the diagnostic page is too noisy and the goal is just to confirm that an HTTP response makes it back from a WSGI application running under ``mod_wsgi-express``. Common options -------------- The full option list is large; ``mod_wsgi-express start-server --help`` is the canonical reference. The options most likely to come up are: ``--port NUMBER`` Port to listen on. Defaults to 8000. ``--host IP-ADDRESS`` Host interface to bind. Defaults to all interfaces. ``--processes NUMBER`` Number of daemon-mode worker processes. Defaults to 1. ``--threads NUMBER`` Threads per worker process. Defaults to 5. ``--user USERNAME`` / ``--group GROUP`` User and group the daemon process should run as. Required when starting as root, ignored otherwise. See `Running on a privileged port`_. ``--reload-on-changes`` Restart the daemon process whenever any Python source file that the WSGI application has imported is modified, not just the WSGI entrypoint script itself. A background monitor thread polls ``sys.modules`` once a second, stat()s every loaded module's source file, and triggers a restart on the first change it sees. **For development use only.** It is not safe in production: every loaded module is stat()'d on every poll cycle (so cost scales with the size of the application), and any in-flight requests are interrupted when the daemon is restarted. Without this option, daemon-mode reloading still picks up changes to the WSGI entrypoint script file alone (the default mod_wsgi behaviour). See :doc:`reloading-source-code` for the broader reloading model. ``--log-to-terminal`` Write Apache's access and error logs to standard output and standard error rather than to files under the server root. Required when running under a process supervisor or in a container that expects logs on the terminal. ``--server-root DIRECTORY-PATH`` Where the generated configuration files and runtime state live. Defaults to a directory under ``/tmp``. Override this for ``setup-server`` so the configuration persists across reboots. ``--application-type TYPE`` Defaults to ``script`` (a WSGI script file specified by filesystem path). Can also be ``module`` (a Python module name imported through the standard import mechanism) or ``static`` (serve a directory of static files only). Hosting static files -------------------- For applications that do not have static-file routing wired up by their framework, ``mod_wsgi-express`` can serve static assets directly from Apache rather than routing them through the WSGI application. The ``--url-alias`` option maps a URL prefix to a file or directory on disk; it is the express equivalent of Apache's ``Alias`` directive. To serve a directory of CSS, JavaScript, and image assets at the ``/static/`` URL:: mod_wsgi-express start-server wsgi.py \ --url-alias /static/ /srv/myapp/static/ A ``GET /static/site.css`` request is now served by Apache directly out of ``/srv/myapp/static/site.css`` without entering the WSGI application. The option is repeatable, and the second argument can be either a directory or a single file. A typical mix:: mod_wsgi-express start-server wsgi.py \ --url-alias /static/ /srv/myapp/static/ \ --url-alias /media/ /srv/myapp/media/ \ --url-alias /favicon.ico /srv/myapp/static/favicon.ico \ --url-alias /robots.txt /srv/myapp/static/robots.txt The single-file form (the last two lines above) maps just that one file to the exact URL given. Apache requires longer/more-specific URL prefixes to be configured before shorter ones, but ``mod_wsgi-express`` sorts the aliases internally so the order on the command line does not matter. A separate ``--document-root`` option sets Apache's ``DocumentRoot`` directly. Files inside the document root are reachable at their corresponding URL paths without needing an alias. This is most useful when the WSGI application is mounted at a sub-URL via ``--mount-point`` and the document root holds the rest of the site:: mod_wsgi-express start-server wsgi.py \ --mount-point /api/ \ --document-root /srv/myapp/public/ In this example the WSGI application handles requests under ``/api/...`` while Apache serves the contents of ``/srv/myapp/public/`` at all other URLs. The default for ``--mount-point`` is ``/``, which is the typical "WSGI application at the root, static assets at sub-URLs" shape and is what the ``--url-alias`` examples above assume. When ``mod_wsgi-express`` runs behind a reverse proxy, static files served this way are subject to the same ``Location`` header rewriting and HTML-body URL leakage caveats as the WSGI application itself; see :doc:`running-behind-a-reverse-proxy`. Other static-file options ------------------------- Beyond ``--url-alias`` and ``--document-root``, a few options shape how Apache handles requests that map to the document root or to ``--url-alias``-mapped directories: ``--directory-index FILE-NAME`` Name of the index resource Apache serves when a request maps to a directory rather than a file (for example ``index.html``). Equivalent to Apache's ``DirectoryIndex``. Without it, a directory request is passed through to the WSGI application or, if the document root is the static target, returns 404. ``--directory-listing`` Enable Apache's automatic directory listing when a request maps to a directory and no ``--directory-index`` match is found. Off by default. Most useful with ``--application-type static``; rarely useful when a WSGI application is also mounted. ``--allow-override DIRECTIVE-TYPE`` Permit ``.htaccess`` files inside the document root or ``--url-alias``-mapped directories to override the named Apache directive types. Defaults to ``None`` (``.htaccess`` ignored). Repeatable to list more than one directive type. Equivalent to Apache's ``AllowOverride``. ``--error-document STATUS URL-PATH`` Replace Apache's default error page for the given HTTP status code with a static resource at the named URL. Repeatable. Equivalent to Apache's ``ErrorDocument``:: mod_wsgi-express start-server wsgi.py \ --error-document 404 /errors/404.html \ --error-document 500 /errors/500.html The named URL paths typically resolve to files served from the document root or from a ``--url-alias``-mapped directory. ``--error-override`` Make Apache's error documents replace the WSGI application's error responses. Without this flag the WSGI application's response body is sent through to the client as-is; with it, Apache substitutes the matching ``ErrorDocument`` page. Useful when the deployment should present a uniform error experience across the WSGI application and any co-hosted static content. Daemon mode only; has no effect under ``--embedded-mode``. Per-extension handlers and CGI scripts -------------------------------------- Two options route requests for files with specific extensions away from the WSGI application and into dedicated handlers. ``--add-handler EXTENSION SCRIPT-PATH`` Map files matching ``EXTENSION`` under the document root to a Python WSGI handler at ``SCRIPT-PATH``. ``EXTENSION`` includes the leading dot (for example ``.tmpl``). The handler module must define a WSGI callable named ``application``, or alternatively a function named ``handle_request``; optionally ``reload_required(resource)`` to control source reloading. Repeatable. Handlers run in the same WSGI execution context as the main application: the same daemon process group in default daemon mode, the Apache child workers under ``--embedded-mode``. The matched file's path is exposed to the handler via ``environ['SCRIPT_NAME']``:: mod_wsgi-express start-server wsgi.py \ --document-root /srv/myapp/public \ --add-handler .tmpl /srv/myapp/render_tmpl.py ``--with-cgi`` Enable plain Apache CGI handling for ``.cgi`` files under the document root. Loads Apache's ``mod_cgid`` (or ``mod_cgi`` where ``mod_cgid`` is unavailable) and emits ``AddHandler cgi-script .cgi``. Files with the ``.cgi`` extension that are also marked executable on the filesystem run as standalone CGI scripts in any language, following the standard CGI contract. This is not WSGI: each invocation forks a fresh process and exits when it finishes, independent of the WSGI application's daemon pool. The two mechanisms are complementary. ``--add-handler`` is for in-process Python handling of specific file types. ``--with-cgi`` is for legacy ``.cgi`` scripts that already exist in the document root and are not worth rewriting. Server name and virtual hosts ----------------------------- By default ``mod_wsgi-express`` accepts requests on the configured port regardless of the host header. The following options shape its name-based virtual-host behaviour, which matters when the express instance is fronted by a reverse proxy that routes by hostname, or when the same instance hosts more than one hostname. ``--server-name HOSTNAME`` The primary host name the server identifies as. Generates the Apache ``ServerName`` directive. When ``HOSTNAME`` begins with ``www.``, ``mod_wsgi-express`` also adds an automatic redirect from the parent domain (without ``www.``) to the ``www.`` form. ``--server-alias HOSTNAME`` Additional host name served by the same WSGI application. Generates the Apache ``ServerAlias`` directive. Repeatable, and wildcard patterns (``*.example.com``) are accepted. ``--allow-localhost`` Allow ``localhost`` (and ``127.0.0.1``) to reach the WSGI application even when ``--server-name`` is set to a different public hostname. By default the name-based virtual-host gate rejects requests that do not match the server name; this flag keeps a side door open for health checks, sidecars, and other on-host clients that connect by loopback. Process and application groups ------------------------------ Most users do not need to set either of these options. The defaults (``:`` for the daemon process group name, ``%{GLOBAL}`` for the application group, placing the application in the Python main interpreter) are correct for normal single-application deployments. Both options exist for testing, experimentation, and the cases below. ``--process-group NAME`` Override the WSGI daemon process group name used in the generated configuration. The default uses the listening host and port as the group name. Has no effect under ``--embedded-mode``. Useful when a stable, recognisable name is wanted for signal-driven recycling: with ``--process-group myapp`` set, the daemon appears as ``(wsgi:myapp)`` in ``ps`` output, so ``pkill -USR1 -f wsgi:myapp`` targets it directly without needing to know its host/port-derived default name. ``--application-group NAME`` Override the WSGI application group used by the generated handler directives. The default is ``%{GLOBAL}`` (the Python main interpreter); a name routes the application into a named sub-interpreter instead. The mod_wsgi ``%{ENV:VARIABLE}`` token is accepted as a value, in which case the application group is determined per request from an environment variable set by other means (typically a ``WSGIDispatchScript``). Combining ``--application-group %{ENV:VARIABLE}`` with a ``WSGIDispatchScript`` and the :doc:`../configuration-directives/WSGIPerInterpreterGIL` directive enabled via ``--include-file`` is the basis for experimenting with load-balancing requests across multiple sub-interpreters that each hold their own GIL. ``mod_wsgi-express`` does not have first-class options for the dispatch script or ``WSGIPerInterpreterGIL``, so both are wired up through ``--include-file`` alongside the dispatch script source file. See the :doc:`../configuration-directives/WSGIPerInterpreterGIL` directive page for a worked example. Free-threaded Python -------------------- A single option opts the express instance into running Python with the GIL disabled (PEP 703). See :doc:`gil-modes-and-free-threading` for the broader context, including when free-threading is the right choice and how it compares to per-interpreter GIL. ``--free-threading`` Emit a top-level :doc:`../configuration-directives/WSGIFreeThreading` ``On`` in the generated configuration so the Python interpreter runs without the GIL (PEP 703). Applies to both the single daemon process group Express creates and the embedded interpreter the Apache child uses for any auth or dispatch scripts. Requires a Python build configured with ``--disable-gil`` (typically distributed as ``python3.13t``, ``python3.14t``, and so on). If the running Python is not such a build, ``mod_wsgi-express`` exits at configuration time with an explanatory error rather than emitting a directive that the Apache process would warn about and ignore. For finer-grained scoping (free-threading for one process only, or for the embedded interpreter only), use ``--include-file`` with an explicit ```` container; see :doc:`gil-modes-and-free-threading` for the full set of recipes and a comparison with the per-interpreter GIL alternative. Environment plumbing -------------------- Several options shape the runtime environment the WSGI application sees, both at process startup and per request. ``--working-directory DIRECTORY-PATH`` The current working directory of the WSGI application. Defaults to the directory the ``mod_wsgi-express`` command was run from, which can be a surprising value (the user's home, the directory ``systemd`` placed the unit in, the directory ``cron`` ran the job from). Set this explicitly. The directory is also searched for Python imports unless the application later changes its working directory. ``--python-path DIRECTORY-PATH`` Additional directory added to ``sys.path``. Repeatable. ``.pth`` files in these directories are not processed; if ``.pth`` processing is needed, set ``PYTHONPATH`` via an ``--envvars-script`` instead. ``--python-eggs DIRECTORY-PATH`` Directory used for unpacking Python eggs. Defaults to a sub-directory of the server root. Override when the server root is on a tmpfs or transient filesystem and the egg cache should persist across restarts. ``--python-warnings SPEC`` Add an entry to the Python warnings filter, using the standard ``-W`` syntax (``action:message:category:module:lineno``). Repeatable; each occurrence is emitted as a separate :doc:`../configuration-directives/WSGIPythonWarnings` directive in the generated configuration. The most common form is just an action: ``--python-warnings error`` converts every warning into an exception, useful for catching deprecation regressions in CI. ``--locale NAME`` Locale for the WSGI process, equivalent to setting ``LC_ALL``. If unset and the inherited locale is ``C`` or ``POSIX``, ``mod_wsgi-express`` tries ``en_US.UTF-8``, then ``C.UTF-8``, falling back to the inherited locale if neither is available. The fallback chain avoids the silent ASCII-only behaviour that follows from running under ``C``. ``--setenv KEY VALUE`` Add a name/value pair to every request's WSGI ``environ`` dictionary. Repeatable. Useful for static configuration the application reads from ``environ`` rather than from the OS process environment. ``--passenv KEY`` Pass a named OS process environment variable into every request's WSGI ``environ`` dictionary as a name/value pair. Repeatable. The express invocation must already have the variable in its process environment (typically via the supervisor unit, the container runtime, or the user's shell). Compression ----------- ``--compress-responses`` Enable compression of common text-based response types (plain text, HTML, XML, CSS, JavaScript). Off by default. Generates the Apache ``mod_deflate`` configuration that compresses responses for clients advertising ``Accept-Encoding: gzip`` or ``deflate``. When ``mod_wsgi-express`` runs behind a front-end proxy, response compression is more often handled at the proxy than at the back-end. Using both is wasteful (double compression and decompression at the proxy), so enable this flag only when the express instance is the front-line server. Telemetry --------- mod_wsgi can stream per-process telemetry to a local ingester for live monitoring. Express has two ways to wire this up: the manual form (point the WSGI processes at an ingester running somewhere else) and the all-in-one shortcut (express runs the ingester alongside the WSGI application). See :doc:`external-telemetry-service` for the protocol, sample format and ingester architecture. ``--enable-telemetry`` Bundle the ingester and its web UI into the express instance. Express generates a service script under the server root that runs the ingester (via the ``mod_wsgi-telemetry`` package) in a ``WSGIDaemonProcess threads=0`` service daemon, emits the matching ``WSGITelemetryService`` directive so the WSGI processes report into the auto-derived socket, and exposes the web UI on ``127.0.0.1`` at the port given by ``--telemetry-ui-port``. Requires the ``mod_wsgi-telemetry`` package to be installed. Mutually exclusive with ``--telemetry-service`` and with a user-supplied ``--service-script telemetry ...``. ``--telemetry-ui-port NUMBER`` HTTP port the telemetry web UI binds to on ``127.0.0.1`` when ``--enable-telemetry`` is set. Defaults to ``8888``. Distinct values are needed when running more than one telemetry- enabled express instance on the same host. ``--telemetry-service TARGET`` Manual form: point the WSGI processes at an ingester that is *not* supervised by this express instance. ``TARGET`` is a ``unix:/path/to/socket`` value; remote UDP targets are not supported. Mutually exclusive with ``--enable-telemetry``. ``--telemetry-interval SECONDS`` Reporter sampling interval. Defaults to ``1.0``. Applies to both forms. ``--slow-requests SECONDS`` Threshold above which a still-running request is reported. Requires either ``--telemetry-service`` or ``--enable-telemetry`` to also be set. ``--telemetry-options ARGS`` Capture toggles passed verbatim to a ``WSGITelemetryOptions`` directive in the generated configuration. Repeatable. See the directive page for the full set of toggles. Running on a privileged port ---------------------------- To listen on a privileged port such as 80 or 443, ``mod_wsgi-express`` needs to be started as root. Apache's parent process binds the listening socket as root and then drops privileges; the ``--user`` and ``--group`` options say which account the daemon process should switch to. Most Linux distributions predefine a service account for Apache (e.g. ``www-data`` on Debian/Ubuntu, ``apache`` on RHEL/Fedora) which can be reused, or you can use any other dedicated account. There are two patterns, depending on whether the running process is supervised externally or expected to daemonise itself. Foreground under a process supervisor ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ For systemd, supervisord, or a container init that expects a foreground process, use ``start-server`` directly with ``--user`` and ``--group``:: sudo mod_wsgi-express start-server wsgi.py --port=80 \ --user www-data --group www-data \ --log-to-terminal The supervisor handles restart on failure; mod_wsgi-express itself stays in the foreground and writes logs to the terminal. Daemonised with a generated apachectl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ For a traditional init-script deployment where separate ``start`` / ``stop`` / ``restart`` commands are expected and the running process is meant to daemonise, use ``setup-server`` instead. It writes out the configuration and a wrapper ``apachectl`` script but does not start Apache:: sudo mod_wsgi-express setup-server wsgi.py --port=80 \ --user www-data --group www-data \ --server-root=/etc/mod_wsgi-express-80 Apache is then started, stopped, and restarted through the generated wrapper:: /etc/mod_wsgi-express-80/apachectl start /etc/mod_wsgi-express-80/apachectl stop /etc/mod_wsgi-express-80/apachectl restart The original ``setup-server`` options are cached inside the server root, so subsequent ``apachectl`` invocations reuse the same configuration. To change options, re-run ``setup-server`` with the new options. SELinux ~~~~~~~ On RHEL, Fedora, AlmaLinux, and Rocky Linux, SELinux is enforcing by default. The bundled SELinux policy expects Apache to start from a specific binary path and to read configuration from specific paths. Starting Apache through ``mod_wsgi-express`` will not match those expectations out of the box, and may fail with ``Permission denied`` errors that are not visible in the Apache error log because SELinux blocks them at the kernel boundary. Two workarounds: * Move the directory specified with ``--server-root`` to a location SELinux already permits Apache to read. * Adjust the SELinux policy to permit the ``--server-root`` location. For brief experiments, ``setenforce 0`` will disable SELinux enforcement until reboot, but is not appropriate for any kind of production use. Non-standard Apache layouts --------------------------- Several Linux distributions rename the Apache binary, or replace it with a shell script that performs additional setup before exec'ing the real binary. ``mod_wsgi-express`` looks for an executable called ``httpd`` by default, so a renamed binary will fail to start with a "command not found" style error. Use ``--httpd-executable`` to point at the real binary:: mod_wsgi-express start-server wsgi.py \ --httpd-executable=/usr/sbin/apache2 If the distribution has wrapped ``httpd`` with a shell script and the shell script is interfering with ``mod_wsgi-express`` (for example, by requiring root privileges to perform other setup steps), point ``--httpd-executable`` at whichever binary the shell script ultimately exec's. Django integration ------------------ ``mod_wsgi-express`` can be invoked through Django's ``manage.py`` so that it picks up the Django project's settings and static files automatically. Add ``mod_wsgi.express`` to ``INSTALLED_APPS`` in the Django settings module:: INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'mod_wsgi.express', ] Collect static assets into the directory the Django settings designate for them:: python manage.py collectstatic Then start the server through Django:: python manage.py runmodwsgi This is equivalent to ``mod_wsgi-express start-server`` against the Django project's ``wsgi.py``, with static-file URLs and asset roots wired up from the Django settings. For development, ``--reload-on-changes`` makes the daemon restart whenever any Python file the application has imported is modified (not just the WSGI script):: python manage.py runmodwsgi --reload-on-changes Use this only during development; see the option description above for why it is not appropriate for production. For the daemonised root deployment described above, the equivalent of ``setup-server`` is ``--setup-only``:: python manage.py runmodwsgi --setup-only --port=80 \ --user www-data --group www-data \ --server-root=/etc/mod_wsgi-express-80 The generated ``apachectl`` is then used in the same way as for the standalone ``setup-server`` flow. Flask integration ----------------- Flask applications work with ``mod_wsgi-express`` the same way any other WSGI application does, with one convention difference: the WSGI callable on a Flask application is conventionally named ``app`` rather than ``application``. ``mod_wsgi-express`` defaults to looking up ``application`` on the loaded module, so a Flask application needs the ``--callable-object`` option to point at the right attribute:: mod_wsgi-express start-server app.py --callable-object app This is the ``mod_wsgi-express`` equivalent of setting ``WSGICallableObject app`` in a hand-written Apache configuration. Either rename the Flask object to ``application`` in the source file, or pass ``--callable-object app`` (or ``WSGICallableObject app`` in manual configuration) to keep the Flask-conventional name. Process supervisors and containers ---------------------------------- When ``mod_wsgi-express`` runs under a process supervisor (systemd, supervisord, runit, s6) or as the main process inside a container, two things change relative to running it interactively: * Logs need to go to standard output and standard error rather than to files under the server root, so the supervisor or container runtime can collect them. Pass ``--log-to-terminal``. * Apache must remain in the foreground so the supervisor sees it as a running process. ``start-server`` already runs in the foreground, so no additional flag is needed. For a Dockerfile walkthrough including base-image package requirements, the PID 1 reaping behaviour, and running as a non-root user inside the container, see :doc:`installing-with-docker`. Logging ------- By default ``mod_wsgi-express`` writes its Apache error log to a file under the server root and does not write an access log at all. Several options shape what gets logged and where it goes. ``--log-to-terminal`` Send Apache's access and error logs to standard output / standard error rather than to files. Used under a process supervisor or in a container; see `Process supervisors and containers`_. When ``--log-directory`` is also set, ``--log-directory`` wins. ``--access-log`` Enable the Apache access log. Off by default; enabling it adds a ``CustomLog`` directive to the generated configuration. The destination is governed by ``--log-to-terminal``, ``--log-directory`` and ``--access-log-name``. ``--startup-log`` Enable a separate startup log file capturing Apache's own startup-phase output. Off by default; enable when troubleshooting startup failures. ``--log-directory DIRECTORY-PATH`` Directory the log files are written to. Defaults to the server root. Override to redirect logs to a persistent or distinct location. ``--log-level NAME`` Apache ``LogLevel`` value. Defaults to ``warn``. Raise to ``info`` or ``debug`` only when troubleshooting; verbose levels emit per-request detail and grow the log quickly. ``--access-log-name FILE-NAME`` / ``--error-log-name FILE-NAME`` / ``--startup-log-name FILE-NAME`` File names for the access, error and startup logs when they are written to the log directory. Defaults are ``access_log``, ``error_log`` and ``startup_log`` respectively. ``--access-log-format FORMAT`` Format string for access log records. The values ``common`` and ``combined`` are recognised as Apache log-format nicknames; any other value is used verbatim as the ``LogFormat`` directive value. ``--error-log-format FORMAT`` Format string for error log records. Used verbatim as the Apache ``ErrorLogFormat`` directive value. ``--rotate-logs`` Pipe log output through Apache's ``rotatelogs`` helper so files rotate at a size threshold. Off by default. Has no effect when ``--log-to-terminal`` is on, since rotation is meaningless against standard streams. ``--max-log-size MB`` Size threshold in megabytes for log rotation when ``--rotate-logs`` is on. Defaults to 5. ``--rotatelogs-executable FILE-PATH`` Path to the ``rotatelogs`` binary. Defaults to the one discovered alongside the system Apache; set when ``rotatelogs`` is in a non-standard location or has been renamed. Custom Apache configuration --------------------------- ``mod_wsgi-express`` generates a complete Apache configuration from its options, but a few escape hatches allow hand-written Apache directives or shell-level setup to be injected without giving up the ``mod_wsgi-express`` flow: ``--include-file FILE-PATH`` Path to a file of additional Apache directives appended at the end of the generated configuration. Use for directives that have no ``mod_wsgi-express`` option of their own (security headers, custom ``Location`` blocks, third-party module configuration). Repeatable. ``--rewrite-rules FILE-PATH`` Path to a file of ``mod_rewrite`` rules included inside the generated configuration. Defaults to ``rewrite.conf`` under the server root if such a file exists. Override when the rules live alongside the application source rather than inside the generated server root. ``--envvars-script FILE-PATH`` Path to a shell script sourced before Apache starts. Use to set process-level environment variables (``DATABASE_URL``, ``OAUTH_CLIENT_SECRET``, ``PYTHONPATH``) that the WSGI application reads at import time, or that other Apache modules consult during startup. Defaults to ``envvars`` under the server root if such a file exists. Auxiliary service processes --------------------------- ``mod_wsgi-express`` can run a long-lived auxiliary process alongside the WSGI application, supervised by the same Apache parent. Typical uses are a queue consumer, a metrics emitter, a periodic batch worker, or a WebSocket sidecar reached via ``--proxy-mount-point``. The mechanism is the *service script*: a Python script imported into a dedicated daemon process group that runs forever rather than handling HTTP requests. ``--service-script SERVICE SCRIPT-PATH`` Declare a service named ``SERVICE`` and start it by importing the script at ``SCRIPT-PATH`` into a dedicated daemon process group. The script's top-level code runs as the daemon process body; if it never returns (because it enters an event loop, for example) the daemon process simply runs that code until Apache shuts it down. Repeatable to declare more than one service. ``--service-user SERVICE USERNAME`` User the named service runs as. Required when starting as root; ignored otherwise. Analogous to ``--user``, but per service. ``--service-group SERVICE GROUP`` Group the named service runs as. Analogous to ``--group``, per service. ``--service-log-file SERVICE FILE-NAME`` Send the named service's log output to a separate file rather than the shared error log. Useful when the service is verbose and would otherwise crowd out the WSGI application's error log. For a worked example covering the ``WSGIDaemonProcess`` and ``WSGIImportScript`` pair the ``--service-script`` option translates into, the service-script lifecycle (no recycling triggers, only restart on Apache restart or external signal), and a running aiohttp-based metrics dashboard, see :doc:`hosting-websocket-applications`. Where to go next ---------------- * :doc:`../configuration` and the :doc:`../configuration-directives/WSGIDaemonProcess` directive for what ``mod_wsgi-express`` is generating under the hood. * :doc:`configuration-guidelines` for richer configuration examples once you outgrow ``mod_wsgi-express`` and move to a hand-written Apache configuration. * :doc:`processes-and-threading` for choosing values for ``--processes`` and ``--threads``. * :doc:`debugging-techniques` and :doc:`application-issues` when things go wrong.