iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more
Need a server to try this on? Antihost offers Linux VPS plans with NVMe storage, full root access and a 14-day free trial.
Yes. An Ubuntu LAMP server can host Python and PHP side by side. Install Apache and Ubuntu’s libapache2-mod-wsgi-py3 package, place the Python application in a project-owned virtual environment, expose an application WSGI callable, and map it with WSGIScriptAlias in a virtual host. Run the app in an isolated mod_wsgi daemon process, leave PHP locations handled by Apache’s PHP module, test the configuration, and add HTTPS before publishing the site.
What the finished setup looks like
Apache remains the public web server. It receives requests on ports 80 and 443, selects a virtual host from the host name, and then routes each URL according to its handler:
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Repair Windows errors before they cause bigger problems3Fix the driver behind crashes, sound loss and screen glitches- PHP URLs are handled by the PHP module already used by the LAMP site.
- Python WSGI URLs are sent through
WSGIScriptAliasto a WSGI entry file. - Static assets such as CSS, JavaScript, images, and downloadable files are served directly by Apache when an
Aliasis configured.
mod_wsgi loads Python into Apache-managed processes and calls the WSGI application for matching requests. In the recommended daemon arrangement, the Python application receives its own mod_wsgi process group instead of sharing an application process with unrelated Apache modules.
| Component | Role | Typical location or command |
|---|---|---|
| Ubuntu | Operating system and package manager | apt |
| Apache HTTP Server | Public HTTP/HTTPS listener, virtual hosts, static files, PHP routing | /etc/apache2/ |
| mod_wsgi | Connects Apache to a Python WSGI callable | libapache2-mod-wsgi-py3 |
| Virtual environment | Isolates the application’s Python packages | /srv/myapp/.venv |
| WSGI entry file | Exports a callable named application |
/srv/myapp/myapp.wsgi |
| Database | Optional application data service in the LAMP stack | Use the database engine and credentials required by the app |
Requirements and boundaries to check first
- An Ubuntu server with administrative access and enough memory for Apache, PHP, the Python application, and its database workload.
- The application must be WSGI-compatible, as Flask and Django are. FastAPI and Starlette are ASGI frameworks and do not natively run on a WSGI server.
- The Python interpreter used to create the virtual environment must be compatible with the Python installation against which mod_wsgi was built.
- The application files and virtual environment must be readable and traversable by the Apache service account. A private home directory that denies traversal will cause import or permission failures.
- For public traffic, DNS should point the site name to the server and firewall rules should allow the required HTTP and HTTPS ports.
Ubuntu’s supported package route is Apache plus libapache2-mod-wsgi-py3. A virtual environment separates packages, but it cannot change the Python version embedded in the mod_wsgi module.
#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.
Install Apache and Ubuntu’s mod_wsgi package
Update package metadata and install Apache:
sudo apt update
sudo apt install apache2
Install the distribution WSGI module:
sudo apt install libapache2-mod-wsgi-py3
Ubuntu enables the module automatically when the package is installed. If it was disabled previously, enable it explicitly and restart Apache after changing modules:
sudo a2enmod wsgi
sudo systemctl restart apache2
Confirm that Apache can see the module:
apache2ctl -M | grep wsgi
The command should show a loaded WSGI module. If it does not, inspect the package installation and run sudo a2enmod wsgi again before continuing.
Create an application directory and virtual environment
Keep deployable application code in a service-oriented path such as /srv/myapp, rather than in a user’s home directory with restrictive permissions. Create the directory, install the Python virtual-environment support if it is not already present, and create the environment with the system interpreter:
sudo mkdir -p /srv/myapp
sudo apt install python3 python3-venv
sudo python3 -m venv /srv/myapp/.venv
Copy or deploy the application into /srv/myapp. Install the exact, pinned dependencies with the virtual environment’s interpreter:
sudo /srv/myapp/.venv/bin/python -m pip install --upgrade pip
sudo /srv/myapp/.venv/bin/python -m pip install -r /srv/myapp/requirements.txt
Do not assume that activating a shell environment changes what Apache uses. Apache will use the interpreter and packages selected by the mod_wsgi daemon configuration. The environment should be created with the same Python installation used to build the installed mod_wsgi module; a virtual environment built with a different Python major or minor version cannot make that module load another interpreter.
Set ownership deliberately. A common pattern is to let a deployment account own releases while granting the Apache service account read and execute access. The exact account names and permissions depend on your deployment process, but Apache must be able to traverse every parent directory, read the WSGI file and Python modules, and read static files.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →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.
Expose the WSGI application
mod_wsgi looks for a callable named application. The file can have any name, but a .wsgi suffix makes its purpose clear.
Flask entry file
If your Flask package defines an object named app in myapp/__init__.py or another importable module, create /srv/myapp/myapp.wsgi:
from myapp import app as application
The directory containing the myapp package must be on Python’s import path. The daemon configuration below supplies /srv/myapp as python-path.
Django entry file
Django normally generates a WSGI module inside the project package. A typical generated file contains:
Recommended Free Tools
import 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. Use the project’s real settings module name, and verify that the Django package is installed in the selected virtual environment.
Configure an Apache virtual host in daemon mode
Create a site file under /etc/apache2/sites-available/, for example /etc/apache2/sites-available/myapp.conf. The following example mounts the Python application at /myapp and serves its static directory directly:
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.
<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, the URL prefix, the project path, and the static directory with values from your deployment. The important directives are:
| Directive | Purpose |
|---|---|
WSGIDaemonProcess |
Creates a named daemon process group and selects the virtual environment and project import path. |
WSGIProcessGroup |
Assigns requests handled by this virtual host to that daemon group. |
WSGIScriptAlias |
Maps a URL prefix to the WSGI script that exposes application. |
Alias |
Maps a URL for files Apache should serve without invoking Python. |
<Directory> |
Grants Apache permission to serve or read the specified filesystem path. |
Do not expose the entire project directory as a downloadable directory. The broad <Directory /srv/myapp> permission is convenient for a simple deployment, but a hardened configuration can grant access only to the WSGI file and the specific static or media directories while keeping source files inaccessible to direct requests.
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteEnable the site, validate Apache, and make the first request
- Enable the virtual host:
sudo a2ensite myapp.conf - Check Apache’s syntax before reloading:
sudo apache2ctl configtestContinue only when it reports
Syntax OK. - Reload Apache so existing connections are handled gracefully:
sudo systemctl reload apache2 - Request the mapped URL locally or from a browser, such as
http://example.com/myapp/. - Watch the site-specific and global logs while testing:
sudo tail -f /var/log/apache2/myapp-error.log sudo tail -f /var/log/apache2/error.log
If you changed a loaded module rather than only a virtual host, restart Apache instead of relying on a reload:
sudo systemctl restart apache2
Flask-specific deployment details
Keep the Flask application object importable without running a development server. The WSGI file should import the object; it should not call app.run(). Environment-specific settings, secrets, and database URLs should be provided through the service’s environment or a protected configuration mechanism rather than committed to source control.
When the application is mounted below a prefix such as /myapp, confirm that URL generation, static paths, and any framework proxy settings understand that prefix. If the application is intended to occupy the whole host name, map the root URL instead:
WSGIScriptAlias / /srv/myapp/myapp.wsgi
Use one approach consistently; defining overlapping aliases can make it unclear which handler receives a request.
Free tools Windows power users keep installed
One-click scans. No signup required.
Rank #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
Django-specific deployment details
Run Django’s deployment preparation commands with the virtual environment’s interpreter. For a project that uses collected static files, a typical command is:
sudo /srv/myapp/.venv/bin/python /srv/myapp/manage.py collectstatic
Point the Apache Alias at the directory configured by Django’s STATIC_ROOT. Keep user-uploaded media in a separate directory and grant Apache read access only when the application’s policy allows direct downloads. Database migrations should be run as a controlled deployment step, not automatically on every Apache request.
Serve PHP and Python on the same Ubuntu server
Apache chooses a handler by URL and configuration, so a LAMP site can keep PHP at one set of paths and route Python at another. For example, an existing document root can continue to serve /index.php, while /myapp/ is handled by WSGIScriptAlias. Use separate virtual hosts when the applications have different domain names; use URL prefixes only when the applications are designed to coexist under one host.
| Requirement | Recommended arrangement |
|---|---|
| PHP and Python on different domains | One Apache virtual host per domain, with the appropriate handler in each host. |
| PHP at the root and Python under a path | Keep the PHP document root and add a non-overlapping WSGIScriptAlias such as /myapp. |
| Shared static assets | Use explicit Apache Alias directives and directory permissions; do not make Python generate files Apache can serve directly. |
| Different Python runtimes | Do not attempt to select another runtime with a second virtual environment in the same Apache instance; use separate mod_wsgi instances and a proxying front end. |
Test for accidental URL overlap. A broad WSGI alias at / will capture requests that you expected PHP or static-file rules to handle.
Static files, uploads, and permissions
Serving static files directly from Apache avoids sending every image, stylesheet, or JavaScript request through Python. Use an Alias and a matching <Directory> block for each public directory. Keep application source, virtual-environment files, private configuration, and logs outside publicly aliased paths.
- Grant read permission to files and execute permission on each parent directory Apache must traverse.
- Use a dedicated media directory for user uploads and decide explicitly whether uploads are public.
- Do not grant write permission to the Apache account across the whole application tree. If the app must write uploads, limit write access to the upload directory.
- After each deployment, verify that the static URL returns the file directly and that a private source file cannot be downloaded.
WSGI versus ASGI: when Apache alone is not enough
Flask and Django can expose WSGI callables, so mod_wsgi is suitable for them when their dependencies and deployment mode are compatible. FastAPI and Starlette are ASGI frameworks; they do not natively run on a WSGI server. For those applications, run an ASGI-compatible server as a separate process and configure Apache as a reverse proxy to that process. The proxy design should include a local bind address, a controlled service account, timeout settings appropriate to the application, and log forwarding. Do not point WSGIScriptAlias at an ASGI application and expect it to work.
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.
Python versions and mod_wsgi limits
Apache loads one copy of the mod_wsgi module, and that module has one Python library linked into it. Consequently, one Apache instance cannot simultaneously host one application requiring Python 3.10 and another requiring Python 3.12 merely by giving each application a different virtual environment. Virtual environments isolate packages, not the interpreter embedded in mod_wsgi.
| Situation | What works | What does not |
|---|---|---|
| Several apps using the same linked Python version | Separate virtual environments and separate daemon process groups. | Sharing one environment when dependency versions conflict. |
| Apps requiring different linked Python versions | Separate mod_wsgi-express instances, each built for its Python, behind a front-end Apache proxy. | Trying to solve the mismatch with python-home alone. |
| Distribution mod_wsgi versus a PyPI-built module | Use the Ubuntu package for the system Python, or build mod_wsgi deliberately for the desired interpreter and operate that instance separately. | Mixing a module built for one interpreter with a virtual environment created by another. |
The distribution package is the simplest supported path on Ubuntu. A custom PyPI-built mod_wsgi can be appropriate when an application needs a Python version not provided by the distribution package, but it adds build, upgrade, and service-management responsibilities.
Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Embedded mode versus daemon mode
In embedded mode, mod_wsgi runs application code inside Apache worker processes. Daemon mode gives the application a named process group with its own restart and resource boundary. For ordinary deployments, daemon mode is the safer default because it reduces interaction with unrelated Apache modules and makes per-application virtual-environment settings explicit.
| Characteristic | Embedded mode | Daemon mode |
|---|---|---|
| Process ownership | Apache worker processes | Dedicated mod_wsgi daemon processes |
| Isolation from other sites | Lower | Higher |
| Per-application Python settings | Less explicit | Configured with WSGIDaemonProcess |
| Default choice for separate production apps | Usually not preferred | Usually preferred |
Add HTTPS before public exposure
Do not leave a production login, session cookie, admin interface, or API on plain HTTP. Ubuntu documents Apache’s SSL module and a default SSL virtual-host configuration. Enable SSL support and the default SSL site when appropriate:
sudo a2enmod ssl
sudo a2ensite default-ssl
sudo systemctl reload apache2
Install a certificate through a separately verified certificate workflow, then configure the certificate and key paths in the TLS virtual host. Replace the example HTTP virtual host’s ServerName, preserve the same WSGI daemon and alias rules in the HTTPS host, and redirect HTTP to HTTPS only after confirming the secure host works. Protect the private key with restrictive filesystem permissions and renew certificates before expiry.
Troubleshooting by symptom
Apache reports a syntax error
- Run
sudo apache2ctl configtestand fix the first reported file and line before addressing later messages. - Check that
WSGIDaemonProcess,WSGIProcessGroup, andWSGIScriptAliasare spelled exactly and appear in a context supported by your installed module. - Confirm that the site file is enabled and that a duplicate virtual host is not receiving the request.
The browser returns HTTP 500
- Read the site-specific error log and the global Apache error log at the moment of the request.
- Look for an import error, missing package, syntax error, database connection failure, or permission denial.
- Run the import manually with the same virtual-environment interpreter:
sudo -u www-data /srv/myapp/.venv/bin/python -c "from myapp import app; print(app)"Adjust the module and service account to your deployment.
- Verify that
python-homepoints to the virtual environment itself and thatpython-pathpoints to the directory containing the application package.
The application imports locally but not under Apache
- Your shell may be using a different Python executable or a different current directory.
- Check the permissions on every parent directory between
/and the project files. - Confirm that dependencies were installed into
/srv/myapp/.venv, not into a user’s unrelated environment. - Ensure the WSGI file exports
applicationand does not start a development server.
Static files return 404 or 403
- Compare the URL in the browser with the exact
Aliasprefix. - Check that the filesystem path exists and that the
<Directory>block grants access. - For a 403, inspect directory traversal and file-read permissions for the Apache service account.
- For Django, run
collectstaticand point the alias atSTATIC_ROOT, not at an arbitrary source directory.
The wrong application or PHP handles the request
- Check the requested host name and the order of enabled virtual hosts.
- Look for overlapping aliases, especially a root-level
WSGIScriptAlias /that captures PHP or static paths. - Use separate host names when URL-prefix routing would create ambiguous ownership.
A different Python version is required
Changing only python-home will not change the Python linked into mod_wsgi. Build or install a mod_wsgi instance for the required interpreter, run it separately, and place a front-end Apache in proxy mode when multiple interpreter versions must be served on one machine.
Production checklist
- Pin application dependencies and record the Python version used to create the virtual environment.
- Run Apache’s configuration check before every reload.
- Keep WSGI applications in daemon mode unless a specific compatibility reason requires another arrangement.
- Separate application source, private settings, static files, and user uploads.
- Give Apache only the read or write permissions it actually needs.
- Configure application and Apache logs, then rotate and monitor them.
- Test failure recovery: restart Apache, redeploy a dependency, and verify that the site returns without manual shell activation.
- Use HTTPS for every public endpoint and protect certificate keys.
- Back up application data and database contents independently of the web-server configuration.
- For ASGI applications, use an ASGI server and reverse-proxy architecture rather than mod_wsgi.
Choosing the deployment shape
| Need | Recommended design | Reason |
|---|---|---|
| One Flask or Django app on Ubuntu | Ubuntu Apache, distribution mod_wsgi, one virtual environment, daemon mode | Uses the supported package path with clear process isolation. |
| Several WSGI apps on the same Python version | One daemon process group and virtual environment per app | Separates package sets while sharing the Apache-linked interpreter. |
| PHP and one Python app on one domain | Keep PHP in its existing document root and map Python under a non-overlapping prefix | Apache can dispatch each URL family to its correct handler. |
| Python apps needing different interpreter versions | Separate mod_wsgi instances behind a proxying Apache | One Apache-loaded mod_wsgi module cannot link two Python versions. |
| FastAPI or Starlette | ASGI server behind Apache reverse proxy | These frameworks are ASGI, not native WSGI applications. |
Commands at a glance
sudo apt update
sudo apt install apache2 libapache2-mod-wsgi-py3 python3-venv
sudo a2enmod wsgi
sudo mkdir -p /srv/myapp
sudo python3 -m venv /srv/myapp/.venv
sudo /srv/myapp/.venv/bin/python -m pip install -r /srv/myapp/requirements.txt
sudo a2ensite myapp.conf
sudo apache2ctl configtest
sudo systemctl reload apache2
The commands install the server components and prepare the environment; the application’s WSGI file, virtual-host paths, permissions, dependency list, database settings, and HTTPS certificate still need to be configured for the particular project.
Quick Recap
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.

