Stage 1 of moving HUBzero Trac off the obsolete mod_python handler onto mod_wsgi,
keeping the existing Python 2 Trac environments. hzforge install trac automates
this; the steps below explain what it does and the gotchas it handles.
mod_python let you bind a handler to any <Location> and declare the mount point
with PythonOption TracUriRoot /tools/<name>. mod_wsgi has no such knob — Trac
derives its base URL from SCRIPT_NAME. hzforge restores that control with a small
WSGI shim that re-splits SCRIPT_NAME/PATH_INFO itself (see
architecture).
- Packages —
hubzero-trac-mysqlauthz(providesHubzeroPermissionStoreand thehubzeroplugincomponents the envs need); for mod_wsgi, the build toolchain (gcc,python2-devel,httpd-devel) and then Trac core +mod_wsgi==4.9.4via pip (the last Python-2-capable release). Thehubzero-tracmetapackage is deliberately skipped — its%postpip-installs Trac 1.0.13 + subvertpy, conflicting with hzforge's Trac pin and the SWIGsvn.corebindings we get fromsubversion-python. - Shim —
/opt/trac/wsgi/hubtrac.wsgi. - Module config — load mod_wsgi (
10-wsgi.conf), unload mod_python (10-python.conf→.disabled); the two interpreters can't coexist. - Drop-in —
00-forge-trac.confwithWSGIScriptAliasMatchrouting the Trac verbs to the shim, plus the/loginLDAP auth block. No CMS carve-out is needed because the alias self-diverts. - Validate + cut over —
apachectl configtest, then a full restart (a graceful reload cannot swap the embedded interpreter).
| Symptom | Cause | Handling |
|---|---|---|
Permission denied on an egg-info under apache; Trac 500s |
root umask 0077 makes pip files unreadable |
pip installs run with umask 022; conditional, package-scoped chmod a+rX only if apache actually can't import Trac |
mod_wsgi: cannot be used with mod_python → Configuration Failed, exiting |
both interpreter modules loaded | mod_python is unloaded as part of the cutover |
| httpd exits during a graceful reload | reload can't hot-swap the interpreter | hzforge does a full restart when the interpreter set changes |
| repo browser shows "Subversion support not available" | subversion-python SWIG bindings absent |
optional — installed only when the svn service is also installed |
A non-obvious detail when testing by hand: the hub vhost listens on a specific
public IP, not loopback, so probe it with
curl --resolve <fqdn>:443:<listen-ip> https://<fqdn>/tools/<env>/wiki.
sudo python3 hzforge.py doctor trac
Expect apachectl configtest: Syntax OK, apache can import Trac, the shim
present, and the interpreters matching disk. A live check:
curl -k --resolve <fqdn>:443:<ip> -o /dev/null -w '%{http_code}\n' \
https://<fqdn>/tools/<env>/wiki # 200 = Trac via mod_wsgi
Run hzforge install trac --python py36. The matrix swaps in:
- Rocky 8 stock
python3-mod_wsgi(Py3.6, 4.6.4-5.el8, from AppStream) — its RPM ships10-wsgi-python3.confwith theLoadModulewrapped in<IfModule !wsgi_module>, so hzforge just disables the py2710-wsgi.confinstead of writing its own. (py3.8/3.9/3.11/3.12 also exist in AppStream, but hzforge supports only py3.6 — it's the system Python, no module-stream juggling.) - Trac
>=1.6,<1.7via pip3. - AppStream
subversion:1.14module for the repo browser — the first stream shippingpython3-subversion(Apache Subversion 1.14 was the first release with Py3 SWIG bindings). Switching from a py27 host'ssubversion:1.10is a clean cutover hzforge performs automatically.
The drop-in, WSGI shim, and /login auth block carry over unchanged. py36 + mod_python is rejected — mod_python upstream is Python 2 only.
Still required before flipping a live env: the per-env Trac SQLite schema
upgrade (db29 → db45), best driven by letting Trac 1.6 run its own headless
DatabaseManager(env).upgrade(45). The Py2 hubzero plugins are already shipped as
dual-target py2.py3-none-any wheels (see plugins.md), so they load
on Py3.6 as-is.
Config-only — the Trac envs, SVN repos, trac.ini, and plugins are untouched:
sudo python3 hzforge.py uninstall trac # removes the drop-in, unloads mod_wsgi
Then restore the previous mod_python config if you had one.