Use Apache with Ubuntu’s packaged WSGI module, a project-owned virtual environment, and an Apache daemon process group. The supported path is apache2 plus libapache2-mod-wsgi-py3. Apache can then route Python WSGI requests to Flask or Django while continuing to serve PHP, static files, and other sites on the same server. Put the project under a service-readable directory such as /srv/myapp, expose an application callable from a WSGI file, map it with WSGIScriptAlias, test the configuration, and reload Apache.
Need a server to try this on? Antihost offers Linux VPS plans with NVMe storage, full root access and a 14-day free trial.
This design is for WSGI frameworks. FastAPI and Starlette are ASGI frameworks and need an ASGI server behind a proxy instead of being loaded directly by mod_wsgi.
As an Amazon Associate I earn from qualifying purchases.
What Apache, Python and LAMP are doing together
Apache is the public HTTP server. It accepts a request, selects a virtual host, and either serves a file directly or passes the request to a handler. PHP requests can continue through the server’s existing PHP setup, while a URL such as /myapp is handed to mod_wsgi. mod_wsgi loads Python into Apache-managed processes and invokes the WSGI callable exposed by your application.
Ubuntu’s server documentation treats Apache as part of a LAMP-style stack that can include Linux, Apache, MySQL and Python. In practice, adding a Python site does not require removing PHP. You can keep a PHP document root such as /var/www/html and give the Python application its own URL prefix or hostname.
#1 Best Overall
- Read Before You Buy — No Video Output: These adapters support charging and USB 2.0 data transfer, but cannot transmit video signals. Except for standard USB webcams (which use USB data only), they are not compatible with HDMI/DisplayPort cables, video-capable USB-C hubs, or docking stations with video output.
- Convert USB-A Ports to USB-C: Designed to connect USB-C earphones, cables, flash drives, card readers, and other USB-C accessories to standard USB-A ports. Plug-and-play with no drivers or software required.
- Aluminum Alloy Housing: Built with a sturdy aluminum alloy shell that aids in heat dissipation and protects against daily wear and scratches. Designed to maintain a stable and secure connection.
- Compact & Travel-Friendly: The ultra-compact design allows the adapter to stay plugged into your device without blocking adjacent ports or adding bulk, reducing wear and tear on your original USB ports.
- 12-Month Warranty: Backed by a 12-month manufacturer warranty for peace of mind. Designed to meet strict quality control standards for reliable everyday performance.
Typical request flow
- The browser requests
https://example.com/myapp/. - Apache selects the matching virtual host.
WSGIScriptAliasmaps the URL to a WSGI script.- mod_wsgi starts or reuses the configured daemon process group.
- The daemon imports your WSGI module and calls its
applicationobject. - The response returns through Apache, which can still serve static assets directly.
Prerequisites and a safe project layout
You need an Ubuntu server with administrative access, a DNS name if the application will be public, and an application that supports WSGI. Install the Python interpreter and virtual-environment support from Ubuntu’s packages, and keep the deployment in a path Apache can traverse.
- A supported Ubuntu installation with
sudoaccess. - Apache 2 installed from Ubuntu packages.
- Python 3 and the
venvmodule. - A WSGI-compatible Flask, Django or similar application.
- Application dependencies pinned in a requirements file or equivalent package manifest.
- A project directory outside an inaccessible home directory, for example
/srv/myapp. - A DNS record and firewall rules appropriate for HTTP and, later, HTTPS.
A layout like this keeps code, the virtual environment and static files easy to address from Apache:
Free tools Windows power users keep installed
One-click scans. No signup required.
/srv/myapp/
├── .venv/
├── requirements.txt
├── myapp.wsgi
├── myapp/ # Flask package, or Django project package
└── static/ # files Apache can serve directly
The Apache service account must be able to read the WSGI file, import the package and traverse every parent directory. Do not make the whole tree writable by the web service; grant write access only to directories that genuinely need it.
Install Apache and Ubuntu’s mod_wsgi package
- Update package indexes.
sudo apt update - Install Apache.
sudo apt install apache2 - Install the distribution WSGI module.
sudo apt install libapache2-mod-wsgi-py3Ubuntu enables this module automatically in the normal package installation. If it was disabled previously, enable it explicitly:
sudo a2enmod wsgi
Restart Apache after changing loaded modules:
sudo systemctl restart apache2
The Ubuntu package is the simplest supported route because it is built for the distribution’s Python integration. A PyPI-built mod_wsgi is another option when you need a different build, but it introduces a critical constraint: the module is compiled against one specific Python installation.
Create the application virtual environment
Create the environment with the same Python installation used to build the mod_wsgi module. A virtual environment isolates packages; it does not change the Python version embedded in mod_wsgi.
The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Rank #2
- 5-in-1 USB-C Hub: Experience comprehensive connectivity featuring a Power Delivery input, two USB-A 2.0 ports, a USB-A 3.0 port, and an HDMI port. (Note: The USB-C power delivery input port is only for connecting an external wall charger to power your laptop and cannot power peripheral devices.)
- 90W Pass-Through Charging: Achieve optimal charging with 90W pass-through power to your laptop, supported by a total input of 100W, with the hub reserving 10W for operational efficiency. (Note: Wall charger not included.)
- Quick Data Transfers: Accelerate your productivity with rapid data transfers using a high-speed 5Gbps USB 3.0 port and two 480Mbps USB 2.0 ports.
- 4K HDMI Display: Enhance your visual experience with a hub capable of delivering 4K resolution at 30Hz in both mirror and extend modes. Please note that this hub is compatible with MacBook (macOS 12 and newer), Windows 10 and 11, ChromeOS, and laptops equipped with DP Alt Mode and Power Delivery. Note: This device is not compatible with Linux.
- What You Get: Anker USB-C Hub (5-in-1, 4K HDMI), welcome guide, 18-month warranty, and our friendly customer service.
sudo mkdir -p /srv/myapp
sudo chown -R $USER:$USER /srv/myapp
cd /srv/myapp
python3 -m venv .venv
. .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -r requirements.txt
If your project does not yet have a dependency file, install its framework and then record the exact versions in one. For a deployment, install those pinned dependencies into /srv/myapp/.venv, not into the system interpreter. Leave the environment in a location Apache can read; a virtual environment inside a private home directory commonly fails because Apache cannot traverse the home directory even when the files themselves are readable.
Flask package example
Suppose the project contains /srv/myapp/myapp/__init__.py and that module creates a Flask object named app. The virtual environment must contain Flask and every package imported by that module:
cd /srv/myapp
. .venv/bin/activate
python -m pip install Flask
python -m pip freeze > requirements.txt
Use your project’s normal dependency-management process instead of overwriting a carefully maintained lock file with pip freeze.
Django package example
A Django project generated with django-admin normally includes a generated wsgi.py. Install Django and the project’s dependencies into the same environment, then identify the directory containing that file, for example /srv/myapp/project/wsgi.py.
Create a WSGI entry file
mod_wsgi looks for a module that exposes an object named application. The object is the WSGI callable; a file that merely defines a framework app under another name will not work until it aliases that object.
Flask
Create /srv/myapp/myapp.wsgi:
from myapp import app as application
The import must succeed when run with the project directory on Python’s path. If your Flask object is created by a factory, call that factory in the WSGI file instead:
Rank #3
- Sleek 7-in-1 USB-C Hub: Features an HDMI port, two USB-A 3.0 ports, and a USB-C data port, each providing 5Gbps transfer speeds. It also includes a USB-C PD input port for charging up to 100W and dual SD and TF card slots, all in a compact design.
- Flawless 4K@60Hz Video with HDMI: Delivers exceptional clarity and smoothness with its 4K@60Hz HDMI port, making it ideal for high-definition presentations and entertainment. (Note: Only the HDMI port supports video projection; the USB-C port is for data transfer only.)
- Double Up on Efficiency: The two USB-A 3.0 ports and a USB-C port support a fast 5Gbps data rate, significantly boosting your transfer speeds and improving productivity.
- Fast and Reliable 85W Charging: Offers high-capacity, speedy charging for laptops up to 85W, so you spend less time tethered to an outlet and more time being productive.
- What You Get: Anker USB-C Hub (7-in-1), welcome guide, 18-month warranty, and our friendly customer service.
from myapp import create_app
application = create_app()
Keep startup work deterministic. Import-time errors, missing environment variables and database connection failures appear as Apache 500 responses, so verify the application can import with the deployment environment before blaming Apache.
Django
Django’s generated WSGI module normally already contains the required callable:
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Fix the driver behind crashes, sound loss and screen glitches3Repair Windows errors before they cause bigger problemsimport os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings')
application = get_wsgi_application()
You can point Apache directly at that generated file, or create a small wrapper that imports it. The value of DJANGO_SETTINGS_MODULE must match the project package and the module must be importable from the path supplied to the daemon process.
Configure an Apache virtual host
Create a site file under /etc/apache2/sites-available/, for example /etc/apache2/sites-available/myapp.conf. This example gives the application the /myapp URL prefix and runs it in daemon mode:
<VirtualHost *:80>
ServerName example.com
WSGIDaemonProcess myapp
python-home=/srv/myapp/.venv
python-path=/srv/myapp
WSGIProcessGroup myapp
WSGIScriptAlias /myapp /srv/myapp/myapp.wsgi
<Directory /srv/myapp>
Require all granted
</Directory>
Alias /myapp/static/ /srv/myapp/static/
<Directory /srv/myapp/static>
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/myapp-error.log
CustomLog ${APACHE_LOG_DIR}/myapp-access.log combined
</VirtualHost>
Replace example.com with the hostname in your DNS record. If the application should own the whole hostname, map the root URL instead:
WSGIScriptAlias / /srv/myapp/myapp.wsgi
Use a distinct virtual host and hostname when you want PHP and Python sites to have independent routing. A URL-prefix deployment is convenient when an existing PHP site must remain at the root.
Windows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallOutdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchRank #4
- Dual Converters, Infinite Potential:Includes 2× USB C male to USB A female adapters and 2× USB A male to USB C female adapters. Perfect for a wide range of uses—tablets with Bluetooth keyboards, expand USB ports on macbook, and more. Two different converters for all your daily needs
- Next-Level 10Gbps & 3A Charging: No more slow 480Mbps, this usb to usb c adapter has a transfer speed of up to 10Gbps, allowing you to do more transferring in less time. This usb adapter fits both USB A and USB C charger, supporting up to 3A fast charging
- Upgraded Exquisite Craftsmanship: With an aluminum alloy housing and metal connector, the usbc to usb adapter is extremely durable and sturdy. Rigorously tested to withstand more than 10,000 times of plugging and unplugging, ensuring long-lasting performance
- Broad Compatible: The usb c to usb adapter widely supports all USB C/ USB A devices like laptops, tablets, cellphones, car chargers, and phone chargers. Such as compatible with MacBook Pro/Air 2023/2022, Thunderbolt 4/3 Devices,Apple MagSafe Watch 9/8/7/SE/Ultra, iPad Pro 2022/2021, Samsung Galaxy S23/S20/S10, and iPhone 17/16/15 Pro. Plug and play
- Please Note: To reach 10Gbps speed, keep the cable under 3.3 ft. For USB A Male to USB C adapters, try flipping the USB C connector. USB C Male to USB A adapters support bidirectional 10Gbps transfer within 3.3 ft
What each directive controls
| Directive | Purpose |
|---|---|
WSGIDaemonProcess |
Creates a named daemon process group and associates it with the virtual environment and project path. |
WSGIProcessGroup |
Selects that daemon group for requests handled by this virtual host. |
WSGIScriptAlias |
Maps a URL path to the WSGI script that exposes application. |
Alias |
Lets Apache serve static files without sending them through Python. |
Require all granted |
Allows Apache to serve the selected directory; limit the directory scope rather than granting access to unrelated paths. |
Daemon mode is the usual choice for an ordinary deployment because the application gets its own process group instead of sharing an application process with unrelated Apache modules. The process group still uses the one Python version linked into the loaded mod_wsgi module.
Enable the site, validate it and reload Apache
- Enable the virtual host:
sudo a2ensite myapp.conf
- Check the complete Apache configuration before reloading:
sudo apachectl configtest
Continue only when the result is Syntax OK. A typo in a virtual-host file can otherwise prevent Apache from reloading.
- Reload Apache so existing connections are handled gracefully:
sudo systemctl reload apache2
- Request the application URL and inspect the dedicated error log if the browser reports a 500:
sudo tail -f /var/log/apache2/myapp-error.log
sudo tail -f /var/log/apache2/error.log
For a first test, use the exact URL represented by the alias, such as http://example.com/myapp/. A request to the wrong hostname can select a different virtual host and make a correct Python configuration appear broken.
Serve PHP and Python on the same Ubuntu server
Yes. Apache chooses a handler by URL, virtual host and file mapping. Keep PHP at the existing document root and assign Python a separate prefix or host:
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
| Request | Typical handler |
|---|---|
http://example.com/index.php |
Existing PHP handler or PHP-FPM configuration |
http://example.com/myapp/ |
mod_wsgi through WSGIScriptAlias |
http://example.com/myapp/static/site.css |
Apache Alias, not Python |
Avoid overlapping aliases. If WSGIScriptAlias / is used at the root of a virtual host, that host is dedicated to Python; do not expect PHP files in the same root to be selected automatically. Use separate hostnames or a narrower prefix when both applications need to coexist.
Choose embedded mode, daemon mode or separate instances
| Deployment choice | When it fits | Important boundary |
|---|---|---|
| Embedded mod_wsgi | Simple internal setups where the application can share Apache worker processes. | The application shares process space with other Apache work and modules. |
| Daemon-mode mod_wsgi | Most standalone Flask or Django deployments. | Still uses the Python version linked into this Apache’s mod_wsgi module. |
| Separate mod_wsgi-express instances | Applications that genuinely require different linked Python versions. | Put a front-end Apache in proxy mode and manage each instance separately. |
| ASGI server behind Apache | FastAPI, Starlette and other ASGI applications. | These frameworks do not natively run on a WSGI server. |
Daemon mode isolates the application process group, but it is not a Python-version boundary. Treat it as process and package isolation, not as a way to load a second interpreter into the same Apache.
Best Value
- 5-in-1 Connectivity: Equipped with a 4K HDMI port, a 5 Gbps USB-C data port, two 5 Gbps USB-A ports, and a USB C 100W PD-IN port. Note: The USB C 100W PD-IN port supports only charging and does not support data transfer devices such as headphones or speakers.
- Powerful Pass-Through Charging: Supports up to 85W pass-through charging so you can power up your laptop while you use the hub. Note: Pass-through charging requires a charger (not included). Note: To achieve full power for iPad, we recommend using a 45W wall charger.
- Transfer Files in Seconds: Move files to and from your laptop at speeds of up to 5 Gbps via the USB-C and USB-A data ports. Note: The USB C 5Gbps Data port does not support video output.
- HD Display: Connect to the HDMI port to stream or mirror content to an external monitor in resolutions of up to 4K@30Hz. Note: The USB-C ports do not support video output.
- What You Get: Anker 332 USB-C Hub (5-in-1), welcome guide, our worry-free 18-month warranty, and friendly customer service.
Understand the one-Python-version limit
Apache loads one copy of mod_wsgi, and that module has one Python library bound into it. You can create several virtual environments for separate applications, but those environments must be compatible with that linked Python version. A virtual environment made with Python 3.12 cannot make a mod_wsgi module built for Python 3.10 execute 3.12 code.
When two applications require different Python versions, run separate mod_wsgi-express instances built for the respective interpreters and place a front-end Apache in proxy mode. If you do not need that split, standardize the server on one supported Python build and use per-project virtual environments.
FastAPI and Starlette require an ASGI design
FastAPI and Starlette are ASGI frameworks. They do not natively run on a WSGI server, so pointing WSGIScriptAlias at an ASGI application is the wrong architecture. Start an ASGI-compatible server for the application and configure Apache as the public-facing reverse proxy. Keep the ASGI process supervised, bind it to a private interface or socket, and let Apache handle the public hostname, TLS and static files.
Flask and Django can be deployed through their WSGI interfaces as described above. Some newer framework features may also have ASGI entry points; choose the interface that matches the server you intend to run rather than forcing an adapter into mod_wsgi.
Static files, uploads and permissions
Static assets should normally be served by Apache with Alias. This avoids spending Python worker time on immutable CSS, JavaScript and image files. Ensure the target directory is readable and every parent directory is traversable by Apache.
Keep user uploads separate from executable source code. If the application needs to write uploads, grant write permission only to that upload directory and do not make the entire project tree writable. A 403 response usually indicates a filesystem traversal or Apache authorization problem; a 404 for a static asset often means the URL prefix and Alias target do not match.
Add HTTPS before public exposure
Do not expose a production login or API over HTTP alone. Ubuntu documents enabling mod_ssl and using a default SSL virtual-host file. Obtain a certificate through a separately verified certificate workflow, configure the certificate and key in the SSL virtual host, and redirect ordinary HTTP traffic to HTTPS after testing.
Keep the same WSGI mapping in the HTTPS virtual host. Verify that cookies, absolute URLs, API callbacks and any proxy headers are correct under the secure scheme. Renew certificates before expiry and test the renewal process rather than waiting for an outage.
Troubleshoot failures in the order they occur
| Symptom | Likely cause | Check or fix |
|---|---|---|
| Apache will not reload | Syntax error or an invalid directive. | Run sudo apachectl configtest; correct the reported file and line before retrying. |
| 404 at the application URL | Wrong hostname, URL prefix or WSGI script path. | Confirm the selected virtual host, the exact WSGIScriptAlias path and that the file exists. |
| 500 with an import error | Dependency missing, wrong python-path or an application startup exception. |
Read the Apache error log, activate the deployment environment manually and test the same import. |
| 500 mentioning an incompatible Python package | The virtual environment was created with a Python version different from mod_wsgi’s linked interpreter. | Rebuild the environment with the matching Python installation or use a separate mod_wsgi instance. |
| 403 for the WSGI file or static directory | Apache cannot traverse a parent directory or the directory rule does not grant access. | Check ownership and execute permissions on each parent, then review the relevant <Directory> block. |
| Static files return the application’s HTML | The Alias is missing, ordered incorrectly or points to the wrong directory. |
Make the static URL and filesystem target explicit and reload Apache. |
| PHP works but Python does not | The request is landing in a different virtual host or the Python alias overlaps the PHP document root. | Test the configured hostname and use a distinct prefix or virtual host for Python. |
Read both Apache’s global error log and the application-specific log. A browser’s generic 500 page hides the useful traceback; the server log identifies whether the failure happened while importing Python, loading the WSGI script, checking permissions or executing application code.
Quick Recap
Production readiness checklist
- Apache and
libapache2-mod-wsgi-py3are installed from Ubuntu packages. - The WSGI module is enabled, and Apache was restarted after module changes.
- The virtual environment was created with the Python installation compatible with mod_wsgi.
- Dependencies are installed and pinned inside that environment.
- The WSGI file exposes an
applicationcallable. - The virtual host uses
WSGIScriptAliasand a named daemon process group. - Static files are mapped with
Aliasand are not needlessly served through Python. - Apache configuration passes
apachectl configtestbefore every reload. - Application and Apache logs are monitored for import, permission and runtime errors.
- PHP and Python routes do not overlap accidentally.
- Applications needing different linked Python versions use separate mod_wsgi instances.
- ASGI applications use an ASGI server and proxy architecture instead of mod_wsgi.
- HTTPS, certificate renewal and secure redirects are configured before public launch.
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →




