Installation Issues
mod_wsgi is a small package but its build depends on both Apache and Python, and various install problems can arise as a result. Common causes include an incomplete Python installation, multiple Python versions on the host, or platform-specific build-toolchain quirks. This page lists known problems and workarounds.
If your problem is not covered here, also see Configuration Issues and Application Issues.
Missing Python Header Files
Compiling mod_wsgi from source requires Python’s development headers. On Linux distributions where Python is split into a runtime package and a separate developer package, the developer package is often not installed by default and the build will fail with errors like:
mod_wsgi.c:113:20: error: Python.h: No such file or directory
mod_wsgi.c:114:21: error: compile.h: No such file or directory
mod_wsgi.c:115:18: error: node.h: No such file or directory
mod_wsgi.c:116:20: error: osdefs.h: No such file or directory
mod_wsgi.c:119:2: error: #error Sorry, mod_wsgi requires at least Python 3.10.0.
Install the developer package for the Python you are using. The name
varies by distribution but is typically the runtime package name with
-dev appended (python3-dev on Debian/Ubuntu) or -devel
(python3-devel on RHEL/Fedora).
Linker Relocation Errors Against The Python Static Library
When building mod_wsgi on a 64-bit Linux system against a Python
installation that provides only a static library
(libpython3.X.a), the link step can fail with an error of the
following shape:
/usr/bin/ld: /path/to/libpython3.X.a(abstract.o): \
relocation R_X86_64_32S against symbol `_Py_NoneStruct' \
can not be used when making a shared object; \
recompile with -fPIC
/usr/bin/ld: failed to set dynamic section sizes: bad value
collect2: error: ld returned 1 exit status
The exact relocation type cited can be R_X86_64_32,
R_X86_64_32S, or R_X86_64_PC32 depending on the linker
version and which Python symbols are involved. The defining
feature of the error is the trailing message “can not be used
when making a shared object; recompile with -fPIC”.
The root cause is that the static Python library being linked
into mod_wsgi.so was not compiled with position-independent
code. The mod_wsgi module is itself a shared object, so every
object linked into it must be position-independent. Object files
inside libpython3.X.a were not, and the link fails.
Historically this error appeared when a 32-bit Python static
library was being linked into a 64-bit mod_wsgi build, which is
where the older form of this section’s title comes from. On
modern systems the more common cause is simply that Python was
built without --enable-shared: the resulting libpython.a
is not position-independent and the same relocation error appears
even on a fully 64-bit system.
The fix is to use a Python build that provides a shared library
(libpython3.X.so) rather than only a static one. Most
distribution Python packages, Homebrew Python, and python.org
installers ship Python with --enable-shared and so already
provide a shared library. If you are using a hand-built Python
that does not, rebuild it with:
./configure --enable-shared
make
make install
See also the “Lack Of Python Shared Library” section below.
Multiple Python Versions
If multiple Python installations are present on the host — for
example a system Python plus a pyenv- or uv-managed Python,
or a python.org installer alongside a Homebrew Python — and you need
mod_wsgi to use a specific one, pass --with-python to
configure when building:
./configure --with-python=/usr/local/bin/python3.12
This is enough when the chosen Python and any other Pythons on the
host share the same installation prefix. If they do not — for
example the chosen Python is at /usr/local while another Python
is at /usr — Apache may fail to find the Python library files
at startup.
The Python interpreter determines its installation prefix at startup
by looking up its own executable on PATH and taking the parent
of that location. The PATH Apache inherits at startup is
typically only the system default, so if Python’s bin directory
is not on Apache’s PATH the Python embedded in mod_wsgi will
find /usr/bin/python3 rather than the intended
/usr/local/bin/python3, and use /usr as its installation
prefix instead of /usr/local.
If there is no Python installation under /usr matching the
version mod_wsgi was built against, Apache’s error log will show:
'import site' failed; use -v for traceback
and any request to a WSGI application will fail because nothing beyond the built-in modules is importable.
If there is a Python installation under /usr of the same
major and minor version (but not the one mod_wsgi was built
against), startup may succeed but at runtime imports may resolve to
a different installation than expected. Imports may fail entirely
or — worse — silently pick up incompatible third-party modules.
To direct mod_wsgi to the right Python installation explicitly, use
the WSGIPythonHome directive:
WSGIPythonHome /usr/local
The value should be a normalised path corresponding to the
sys.prefix of the Python you built mod_wsgi against:
>>> import sys
>>> sys.prefix
'/usr/local'
A less-preferred alternative is to extend Apache’s PATH so the
intended Python is found first. For a standard Apache installation,
edit the envvars file in the same directory as the Apache
executable:
PATH=/usr/local/bin:$PATH
export PATH
To verify which Python installation is actually being used at
runtime, deploy a small WSGI script that prints sys.prefix and
sys.path to stderr:
import sys
def application(environ, start_response):
status = '200 OK'
output = b'Hello World!'
response_headers = [('Content-type', 'text/plain'),
('Content-Length', str(len(output)))]
start_response(status, response_headers)
print('sys.prefix = %s' % repr(sys.prefix), file=sys.stderr)
print('sys.path = %s' % repr(sys.path), file=sys.stderr)
return [output]
Python Patch Level Mismatch
If the Python installation is upgraded to a newer patch-level revision without rebuilding mod_wsgi, you will likely see a warning of the following form (logged with the WSGI0099 error code; see Error Reference) in the Apache error log when Python is being initialised:
[Sat Jan 01 12:34:56.789012 2026] [wsgi:warn] [pid 12345] WSGI0099: Compiled for Python/3.12.0 but runtime using Python/3.12.1.
The warning indicates that a newer Python version is now being used than the one mod_wsgi was originally compiled against.
If both Pythons were installed with --enable-shared, this is
generally harmless: the Python library is linked dynamically at
runtime, so the upgrade is picked up automatically.
If --enable-shared was not used and the static Python library is
embedded into mod_wsgi.so, the embedded library code will be
older than the Python modules and extension modules now present in
the Python installation. Behaviour in this case is undefined and you
should rebuild mod_wsgi against the upgraded Python.