⥠Quick Start - Python Web Stack
# Install Python 3 with web development essentials
sudo dnf install -y python3 python3-pip python3-devel python3-mod_wsgi python3-PyMySQL python3-virtualenv && pip3 install --user flask django fastapi uvicorn gunicorn pymysql sqlalchemy --break-system-packages
ð System Information
Target Systems & Python Version
- Oracle Enterprise Linux 8 (OEL8)
- Red Hat Enterprise Linux 8 (RHEL8)
- CentOS 8 / Rocky Linux 8 / AlmaLinux 8
- Python Version: 3.6+ (default in RHEL8 is Python 3.6-3.9 depending on release)
- Python 3.11+: Available via AppStream modules
ð Web Server Options
- Apache + mod_wsgi: Traditional, well-tested, good for mixed environments
- Gunicorn + Nginx: Modern, scalable, recommended for production
- uWSGI + Nginx: High performance, complex configuration
- Uvicorn/Hypercorn: For ASGI apps (FastAPI, async frameworks)
ðĶ System Packages (DNF/YUM)
Python Core
python3
Python 3 interpreter
python3-pip
Python package installer (pip)
python3-devel
Development headers (needed for compiled packages)
python3-virtualenv
Virtual environment creation
python3-setuptools
Python package installation tools
python3-wheel
Wheel package format support
Database Drivers (System Packages)
python3-PyMySQL
Pure Python MySQL/MariaDB driver
python3-psycopg2
PostgreSQL driver
python3-sqlalchemy
SQL toolkit and ORM (if available in repos)
Web Server Integration
python3-mod_wsgi
Apache WSGI module for Python 3
nginx
High-performance web server (alternative to Apache)
Development Tools
gcc
C compiler (for building Python packages)
gcc-c++
C++ compiler
make
Build automation tool
git
Version control
ð§ Installation Steps
Step 1: Install System Packages
Complete System Package Installation
sudo dnf install -y \
python3 \
python3-pip \
python3-devel \
python3-virtualenv \
python3-setuptools \
python3-wheel \
python3-mod_wsgi \
python3-PyMySQL \
gcc \
gcc-c++ \
make \
git
Step 2: Verify Python Installation
Version Check
# Check Python version
python3 --version
# Check pip version
pip3 --version
# Check which Python
which python3
# Check installed packages
pip3 list
ðĶ Python Packages (via pip)
â ïļ RHEL8 pip Restriction
RHEL8 requires --break-system-packages flag when using pip outside virtual environments. For production, always use virtual environments!
Web Frameworks
Flask
Micro web framework
Django
Full-featured web framework
FastAPI
Modern async API framework
Pyramid
Flexible web framework
Tornado
Async web framework
WSGI/ASGI Servers
gunicorn
Python WSGI HTTP Server (recommended!)
uvicorn
ASGI server for FastAPI
hypercorn
ASGI server (alternative to uvicorn)
uwsgi
High-performance application server
Database Libraries
PyMySQL
Pure Python MySQL/MariaDB driver
mysql-connector-python
Oracle's official MySQL driver
SQLAlchemy
SQL toolkit and ORM
psycopg2-binary
PostgreSQL driver (binary distribution)
redis
Redis client
Essential Web Development Packages
requests
HTTP library
Jinja2
Template engine (included with Flask)
python-dotenv
Environment variable management
pydantic
Data validation (required for FastAPI)
python-multipart
Form data parsing (for FastAPI)
Install Python Packages
Install via pip (User Install)
# Install web frameworks
pip3 install --user \
flask \
django \
fastapi \
--break-system-packages
# Install WSGI/ASGI servers
pip3 install --user \
gunicorn \
uvicorn[standard] \
--break-system-packages
# Install database drivers
pip3 install --user \
pymysql \
sqlalchemy \
--break-system-packages
# Install utilities
pip3 install --user \
requests \
python-dotenv \
pydantic \
python-multipart \
--break-system-packages
ð Virtual Environments (Best Practice!)
ðĄ Always Use Virtual Environments
Virtual environments isolate project dependencies, prevent conflicts, and make deployment reproducible. Never install packages system-wide in production!
Create and Use Virtual Environment
Virtual Environment Workflow
# Create project directory
mkdir -p /var/www/myapp
cd /var/www/myapp
# Create virtual environment
python3 -m venv venv
# Activate virtual environment
source venv/bin/activate
# Upgrade pip in venv
pip install --upgrade pip
# Install packages (no --break-system-packages needed in venv!)
pip install flask gunicorn pymysql sqlalchemy
# Create requirements.txt
pip freeze > requirements.txt
# Deactivate when done
deactivate
# Later: Recreate environment from requirements.txt
source venv/bin/activate
pip install -r requirements.txt
ðķïļ Flask Application Setup
Flask - Micro Web Framework
Lightweight, flexible, perfect for small to medium applications and APIs. Easy to learn, great for beginners.
Flask Installation & Project Structure
Flask Project Setup
# Create project directory
sudo mkdir -p /var/www/flask-app
cd /var/www/flask-app
# Create virtual environment
python3 -m venv venv
source venv/bin/activate
# Install Flask with database support
pip install flask gunicorn pymysql sqlalchemy flask-sqlalchemy
# Create project structure
mkdir -p app/{static,templates}
touch app/__init__.py
touch app/routes.py
touch app/models.py
touch config.py
touch wsgi.py
touch .env
# Set ownership
sudo chown -R apache:apache /var/www/flask-app
Flask Application - Basic Structure
/var/www/flask-app/app/__init__.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import os
db = SQLAlchemy()
def create_app():
app = Flask(__name__)
# Configuration
app.config['SECRET_KEY'] = os.getenv('SECRET_KEY', 'dev-secret-key-change-in-production')
app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv(
'DATABASE_URL',
'mysql+pymysql://webapp_user:YourPassword@localhost/webapp_db'
)
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# Initialize extensions
db.init_app(app)
# Register blueprints
from app import routes
app.register_blueprint(routes.bp)
return app
Flask Routes
/var/www/flask-app/app/routes.py
from flask import Blueprint, render_template, jsonify
from app import db
import sys
bp = Blueprint('main', __name__)
@bp.route('/')
def index():
return render_template('index.html',
title='Flask App',
python_version=sys.version)
@bp.route('/api/health')
def health():
# Check database connection
try:
db.session.execute('SELECT 1')
db_status = 'connected'
except Exception as e:
db_status = f'error: {str(e)}'
return jsonify({
'status': 'ok',
'database': db_status,
'python_version': sys.version
})
@bp.route('/api/users')
def users():
# Example database query
try:
result = db.session.execute(
'SELECT * FROM users LIMIT 10'
)
users = [dict(row) for row in result]
return jsonify(users)
except Exception as e:
return jsonify({'error': str(e)}), 500
WSGI Entry Point
/var/www/flask-app/wsgi.py
from app import create_app
app = create_app()
if __name__ == '__main__':
app.run()
Run Flask Development Server
Flask Development
# Activate virtual environment
source venv/bin/activate
# Set environment variables
export FLASK_APP=wsgi.py
export FLASK_ENV=development
# Run development server
flask run --host=0.0.0.0 --port=5000
# Or use gunicorn (production-like)
gunicorn --bind 0.0.0.0:5000 wsgi:app
ðļ Django Application Setup
Django - Full-Featured Web Framework
Batteries-included framework. Perfect for large applications. Built-in admin, ORM, authentication, and more.
Django Installation & Project Creation
Django Project Setup
# Create project directory
sudo mkdir -p /var/www/django-app
cd /var/www/django-app
# Create virtual environment
python3 -m venv venv
source venv/bin/activate
# Install Django with database support
pip install django gunicorn pymysql mysqlclient
# Create Django project
django-admin startproject myproject .
# Create an app
python manage.py startapp myapp
# Set ownership
sudo chown -R apache:apache /var/www/django-app
Django Settings (Database Configuration)
/var/www/django-app/myproject/settings.py
# Key settings for MySQL/MariaDB
import os
import pymysql
# Use PyMySQL as MySQLdb
pymysql.install_as_MySQLdb()
# Security
SECRET_KEY = os.getenv('SECRET_KEY', 'change-me-in-production')
DEBUG = os.getenv('DEBUG', 'False') == 'True'
ALLOWED_HOSTS = ['localhost', '127.0.0.1', 'your-domain.com']
# Database - Works with MySQL or MariaDB!
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'webapp_db',
'USER': 'webapp_user',
'PASSWORD': 'YourPassword',
'HOST': 'localhost',
'PORT': '3306',
'OPTIONS': {
'charset': 'utf8mb4',
'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
},
}
}
# Static files
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
# Add your app to INSTALLED_APPS
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'myapp',
]
Django Database Setup
Django Migrations & Admin
# Activate virtual environment
source venv/bin/activate
# Create database tables
python manage.py migrate
# Create superuser for admin
python manage.py createsuperuser
# Collect static files
python manage.py collectstatic --noinput
# Run development server
python manage.py runserver 0.0.0.0:8000
# Or use gunicorn (production)
gunicorn --bind 0.0.0.0:8000 myproject.wsgi:application
⥠FastAPI Application Setup
FastAPI - Modern Async API Framework
High performance, automatic API documentation, async support, type hints. Perfect for APIs and microservices.
FastAPI Installation
FastAPI Project Setup
# Create project directory
sudo mkdir -p /var/www/fastapi-app
cd /var/www/fastapi-app
# Create virtual environment
python3 -m venv venv
source venv/bin/activate
# Install FastAPI with all extras
pip install 'fastapi[all]' uvicorn[standard] pymysql sqlalchemy
# Create project structure
mkdir -p app
touch app/__init__.py
touch app/main.py
touch app/database.py
touch app/models.py
# Set ownership
sudo chown -R apache:apache /var/www/fastapi-app
FastAPI Application
/var/www/fastapi-app/app/main.py
from fastapi import FastAPI, Depends
from sqlalchemy.orm import Session
from app.database import engine, get_db
from pydantic import BaseModel
import sys
app = FastAPI(
title="FastAPI Application",
description="Python web app with database connectivity",
version="1.0.0"
)
@app.get("/")
def read_root():
return {
"message": "Welcome to FastAPI",
"python_version": sys.version,
"docs": "/docs"
}
@app.get("/health")
def health_check(db: Session = Depends(get_db)):
try:
# Test database connection
db.execute("SELECT 1")
db_status = "connected"
except Exception as e:
db_status = f"error: {str(e)}"
return {
"status": "ok",
"database": db_status
}
# Example Pydantic model
class User(BaseModel):
name: str
email: str
@app.post("/api/users")
def create_user(user: User, db: Session = Depends(get_db)):
# Insert user into database
result = db.execute(
"INSERT INTO users (name, email) VALUES (:name, :email)",
{"name": user.name, "email": user.email}
)
db.commit()
return {"id": result.lastrowid, **user.dict()}
@app.get("/api/users")
def get_users(db: Session = Depends(get_db)):
result = db.execute("SELECT * FROM users LIMIT 10")
users = [dict(row) for row in result]
return users
FastAPI Database Connection
/var/www/fastapi-app/app/database.py
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, declarative_base
# Database URL - Works with MySQL or MariaDB!
DATABASE_URL = "mysql+pymysql://webapp_user:YourPassword@localhost/webapp_db"
engine = create_engine(DATABASE_URL, pool_pre_ping=True)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
# Dependency
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
Run FastAPI Application
FastAPI Development & Production
# Activate virtual environment
source venv/bin/activate
# Development server (auto-reload)
uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload
# Production server (multiple workers)
uvicorn app.main:app --host 0.0.0.0 --port 8000 --workers 4
# Access automatic API documentation:
# http://your-server:8000/docs (Swagger UI)
# http://your-server:8000/redoc (ReDoc)
ðŠķ Apache + mod_wsgi Deployment
Apache Configuration for Flask/Django
/etc/httpd/conf.d/python-app.conf
<VirtualHost *:80>
ServerName example.com
ServerAdmin webmaster@example.com
# WSGI Configuration
WSGIDaemonProcess myapp \
python-home=/var/www/flask-app/venv \
python-path=/var/www/flask-app \
processes=2 \
threads=15 \
display-name=%{GROUP}
WSGIProcessGroup myapp
WSGIScriptAlias / /var/www/flask-app/wsgi.py
# Directory permissions
<Directory /var/www/flask-app>
WSGIProcessGroup myapp
WSGIApplicationGroup %{GLOBAL}
Require all granted
</Directory>
# Static files (for Django)
Alias /static/ /var/www/flask-app/static/
<Directory /var/www/flask-app/static>
Require all granted
</Directory>
# Logging
ErrorLog /var/log/httpd/python-app-error.log
CustomLog /var/log/httpd/python-app-access.log combined
</VirtualHost>
Enable and Test Apache Configuration
Apache Deployment Steps
# Set proper permissions
sudo chown -R apache:apache /var/www/flask-app
# Set SELinux contexts
sudo semanage fcontext -a -t httpd_sys_content_t "/var/www/flask-app(/.*)?"
sudo semanage fcontext -a -t httpd_sys_script_exec_t "/var/www/flask-app/wsgi.py"
sudo restorecon -Rv /var/www/flask-app
# Enable database connectivity
sudo setsebool -P httpd_can_network_connect_db on
# Test configuration
sudo apachectl configtest
# Restart Apache
sudo systemctl restart httpd
ðĶ Gunicorn + Nginx Deployment (Recommended)
ðĄ Why Gunicorn + Nginx?
This combination is the modern standard for Python web apps:
- Gunicorn handles Python application serving
- Nginx handles static files, SSL, load balancing, and reverse proxy
- Better performance than mod_wsgi for pure Python apps
- Easier to scale horizontally
Install Nginx
Nginx Installation
sudo dnf install -y nginx
sudo systemctl enable nginx
sudo systemctl start nginx
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
Systemd Service for Gunicorn
/etc/systemd/system/gunicorn-myapp.service
[Unit]
Description=Gunicorn daemon for Flask/Django app
After=network.target
[Service]
Type=notify
User=apache
Group=apache
WorkingDirectory=/var/www/flask-app
Environment="PATH=/var/www/flask-app/venv/bin"
# For Flask:
ExecStart=/var/www/flask-app/venv/bin/gunicorn \
--workers 3 \
--bind unix:/run/gunicorn-myapp.sock \
--access-logfile /var/log/gunicorn/access.log \
--error-logfile /var/log/gunicorn/error.log \
wsgi:app
# For Django:
# ExecStart=/var/www/django-app/venv/bin/gunicorn \
# --workers 3 \
# --bind unix:/run/gunicorn-myapp.sock \
# myproject.wsgi:application
# For FastAPI (use uvicorn instead):
# ExecStart=/var/www/fastapi-app/venv/bin/uvicorn \
# --workers 4 \
# --bind unix:/run/gunicorn-myapp.sock \
# app.main:app
ExecReload=/bin/kill -s HUP $MAINPID
KillMode=mixed
TimeoutStopSec=5
PrivateTmp=true
[Install]
WantedBy=multi-user.target
Nginx Reverse Proxy Configuration
/etc/nginx/conf.d/python-app.conf
server {
listen 80;
server_name example.com www.example.com;
# Logging
access_log /var/log/nginx/python-app-access.log;
error_log /var/log/nginx/python-app-error.log;
# Static files (for Django)
location /static/ {
alias /var/www/flask-app/staticfiles/;
expires 30d;
add_header Cache-Control "public, immutable";
}
# Media files (uploads)
location /media/ {
alias /var/www/flask-app/media/;
}
# Proxy to Gunicorn
location / {
proxy_pass http://unix:/run/gunicorn-myapp.sock;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Timeouts
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
}
Enable Gunicorn Service
Start Gunicorn + Nginx
# Create log directory
sudo mkdir -p /var/log/gunicorn
sudo chown apache:apache /var/log/gunicorn
# Reload systemd
sudo systemctl daemon-reload
# Enable and start Gunicorn
sudo systemctl enable gunicorn-myapp
sudo systemctl start gunicorn-myapp
# Check status
sudo systemctl status gunicorn-myapp
# Test Nginx configuration
sudo nginx -t
# Restart Nginx
sudo systemctl restart nginx
# Check logs
sudo tail -f /var/log/gunicorn/error.log
sudo tail -f /var/log/nginx/python-app-error.log
ð SELinux Configuration
SELinux for Python Web Apps
SELinux Setup
# Allow network connections (database, APIs)
sudo setsebool -P httpd_can_network_connect on
sudo setsebool -P httpd_can_network_connect_db on
# Set contexts for application directory
sudo semanage fcontext -a -t httpd_sys_content_t "/var/www/flask-app(/.*)?"
sudo semanage fcontext -a -t httpd_sys_script_exec_t "/var/www/flask-app/wsgi.py"
sudo semanage fcontext -a -t httpd_sys_rw_content_t "/var/www/flask-app/media(/.*)?"
# For Gunicorn socket
sudo semanage fcontext -a -t httpd_var_run_t "/run/gunicorn-myapp.sock"
# Restore contexts
sudo restorecon -Rv /var/www/flask-app
sudo restorecon -Rv /run/gunicorn-myapp.sock
# Check for denials
sudo ausearch -m avc -ts recent | grep python
ðū Database Connection Examples
PyMySQL (Works with MySQL & MariaDB)
PyMySQL Connection Example
pymysql_example.py
import pymysql
from contextlib import contextmanager
@contextmanager
def get_db_connection():
conn = pymysql.connect(
host='localhost',
user='webapp_user',
password='YourPassword',
database='webapp_db',
charset='utf8mb4',
cursorclass=pymysql.cursors.DictCursor
)
try:
yield conn
conn.commit()
except Exception:
conn.rollback()
raise
finally:
conn.close()
# Usage
with get_db_connection() as conn:
with conn.cursor() as cursor:
cursor.execute("SELECT * FROM users WHERE id = %s", (1,))
user = cursor.fetchone()
print(user)
SQLAlchemy ORM (Recommended)
SQLAlchemy Connection
sqlalchemy_example.py
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import sessionmaker, declarative_base
# Database URL - Works with MySQL or MariaDB!
DATABASE_URL = "mysql+pymysql://webapp_user:YourPassword@localhost/webapp_db"
engine = create_engine(DATABASE_URL, pool_pre_ping=True)
Session = sessionmaker(bind=engine)
Base = declarative_base()
# Define model
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String(100))
email = Column(String(100))
# Usage
session = Session()
try:
user = session.query(User).filter_by(id=1).first()
print(f"User: {user.name} ({user.email})")
finally:
session.close()
ð Troubleshooting
Common Issues
| Problem | Solution |
|---|---|
| Can't connect to database | SELinux: setsebool -P httpd_can_network_connect_db onCheck credentials and socket path |
| pip install fails | Install python3-devel and gccUse --break-system-packages outside venv |
| ModuleNotFoundError | Activate virtual environment Check PYTHONPATH in systemd service |
| 502 Bad Gateway (Nginx) | Check Gunicorn is running Verify socket path in Nginx config Check SELinux contexts on socket |
| Permission denied errors | chown -R apache:apache /var/www/apprestorecon -Rv /var/www/app |
Useful Commands
# Check Python version
python3 --version
# List installed packages
pip3 list
# Check virtual environment
which python
echo $VIRTUAL_ENV
# Test database connectivity
python3 -c "import pymysql; pymysql.connect(host='localhost', user='webapp_user', password='YourPassword', database='webapp_db')"
# Check Gunicorn status
sudo systemctl status gunicorn-myapp
sudo journalctl -u gunicorn-myapp -f
# Test Nginx config
sudo nginx -t
# Check SELinux denials
sudo ausearch -m avc -ts recent | grep python
# View application logs
sudo tail -f /var/log/gunicorn/error.log
â Best Practices Summary
ðĄ Python Web Development Best Practices
- Always use virtual environments - Never install packages system-wide in production
- Use requirements.txt - Pin all dependencies for reproducible deployments
- Environment variables - Never hardcode secrets, use .env files or environment variables
- Gunicorn + Nginx - Preferred over Apache mod_wsgi for pure Python apps
- Database connection pooling - Use SQLAlchemy or configure pool settings
- SELinux - Configure it properly, don't disable it
- Logging - Configure proper application logging, not just print statements
- Async when needed - Use FastAPI/asyncio for high-concurrency APIs
- Static files - Let Nginx serve them, not Python
- Security - Keep dependencies updated, use security headers, validate input
ð Framework Quick Reference
| Framework | Best For | Production Server | Dev Server |
|---|---|---|---|
| Flask | Small-medium apps, APIs, microservices | Gunicorn | flask run |
| Django | Large apps, admin interfaces, CMS | Gunicorn | manage.py runserver |
| FastAPI | Modern APIs, async, microservices | Uvicorn/Gunicorn | uvicorn --reload |