Python and Virtual Environments Installation (venv): Complete Production Guide
Introduction
Python is one of the world's most popular programming languages, widely used for web development, data science, machine learning, automation, and DevOps. Virtual environments (venv) are essential for Python development, allowing you to create isolated Python environments for different projects with their own dependencies, preventing conflicts and ensuring reproducibility. This comprehensive guide covers Python installation, virtual environment management, and production deployment best practices.
What You'll Learn
- Installing Python 3 on Ubuntu/Debian and CentOS/Rocky Linux
- Managing multiple Python versions
- Creating and managing virtual environments with venv
- Installing and managing Python packages with pip
- Requirements.txt management for reproducible environments
- Production deployment strategies
- Performance optimization
- Security best practices
- Troubleshooting common issues
Why Use Virtual Environments?
- Dependency Isolation: Each project has its own dependencies
- Version Control: Different projects can use different package versions
- Reproducibility: Easy to replicate environments
- Clean System: Keep system Python clean and stable
- No Permission Issues: Install packages without sudo
- Testing: Test against different Python and package versions
Prerequisites
- Ubuntu 20.04+, Debian 10+, CentOS 8+, or Rocky Linux 8+
- Root or sudo access
- At least 512MB RAM
- 2GB free disk space
- Basic command line knowledge
Installation
Install Python 3
Ubuntu/Debian Installation
# Update package list
sudo apt update
# Install Python 3 (usually pre-installed)
sudo apt install -y python3 python3-pip python3-venv python3-dev
# Install additional tools
sudo apt install -y build-essential libssl-dev libffi-dev python3-setuptools
# Verify installation
python3 --version
pip3 --version
# Create python/pip aliases (optional)
echo 'alias python=python3' >> ~/.bashrc
echo 'alias pip=pip3' >> ~/.bashrc
source ~/.bashrc
CentOS/Rocky Linux Installation
# Update system
sudo dnf update -y
# Install Python 3
sudo dnf install -y python3 python3-pip python3-devel
# Install development tools
sudo dnf groupinstall -y "Development Tools"
# Verify installation
python3 --version
pip3 --version
# Create aliases
echo 'alias python=python3' >> ~/.bashrc
echo 'alias pip=pip3' >> ~/.bashrc
source ~/.bashrc
Install Specific Python Version
Using deadsnakes PPA (Ubuntu/Debian)
# Add deadsnakes PPA
sudo add-apt-repository ppa:deadsnakes/ppa -y
sudo apt update
# Install Python 3.11
sudo apt install -y python3.11 python3.11-venv python3.11-dev
# Install Python 3.10
sudo apt install -y python3.10 python3.10-venv python3.10-dev
# Verify
python3.11 --version
python3.10 --version
Using pyenv (All Distributions)
# Install dependencies
sudo apt install -y make build-essential libssl-dev zlib1g-dev \
libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm \
libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev \
libffi-dev liblzma-dev
# Install pyenv
curl https://pyenv.run | bash
# Add to ~/.bashrc
cat >> ~/.bashrc <<'EOF'
export PATH="$HOME/.pyenv/bin:$PATH"
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"
EOF
source ~/.bashrc
# Install Python versions
pyenv install 3.11.7
pyenv install 3.10.13
pyenv install 3.9.18
# List installed versions
pyenv versions
# Set global version
pyenv global 3.11.7
# Set local version for project
cd /path/to/project
pyenv local 3.10.13
Configuration
Virtual Environment Management
Creating Virtual Environments
# Create project directory
mkdir ~/myproject && cd ~/myproject
# Create virtual environment
python3 -m venv venv
# Create with specific Python version
python3.11 -m venv venv
# Create with system site packages (not recommended)
python3 -m venv venv --system-site-packages
# Verify creation
ls -la venv/
Activating Virtual Environments
# Activate virtual environment
source venv/bin/activate
# Your prompt should change to show (venv)
(venv) user@server:~/myproject$
# Verify Python is from virtual environment
which python
# Should show: /home/user/myproject/venv/bin/python
# Check Python version
python --version
# Deactivate when done
deactivate
Multiple Virtual Environments
# Create different environments for different projects
mkdir ~/project1 && cd ~/project1
python3 -m venv venv
mkdir ~/project2 && cd ~/project2
python3 -m venv venv
# Or use different names
mkdir ~/myapp && cd ~/myapp
python3 -m venv venv-dev
python3 -m venv venv-prod
python3 -m venv venv-test
pip Package Management
Installing Packages
# Activate virtual environment first
source venv/bin/activate
# Install single package
pip install requests
# Install specific version
pip install Django==4.2.7
# Install minimum version
pip install numpy>=1.24.0
# Install from requirements.txt
pip install -r requirements.txt
# Install in editable mode (for development)
pip install -e .
# Install from git repository
pip install git+https://github.com/user/repo.git
Managing Requirements
# List installed packages
pip list
# Show package details
pip show Django
# Generate requirements.txt
pip freeze > requirements.txt
# Generate with comments (better)
pip list --format=freeze > requirements.txt
# Create requirements-dev.txt for development dependencies
pip freeze > requirements-dev.txt
Upgrading Packages
# Upgrade single package
pip install --upgrade requests
# Upgrade pip itself
pip install --upgrade pip
# Upgrade all packages (careful!)
pip list --outdated
pip install --upgrade $(pip list --outdated --format=freeze | cut -d = -f 1)
Project Structure Best Practices
# Recommended Python project structure
myproject/
├── venv/ # Virtual environment (not in git)
├── src/ # Source code
│ ├── __init__.py
│ ├── main.py
│ └── utils.py
├── tests/ # Test files
│ ├── __init__.py
│ └── test_main.py
├── requirements.txt # Production dependencies
├── requirements-dev.txt # Development dependencies
├── .gitignore # Git ignore file
├── README.md # Project documentation
├── setup.py # Package setup (if distributing)
└── .env # Environment variables (not in git)
# Create structure
mkdir -p myproject/{src,tests}
cd myproject
python3 -m venv venv
touch src/{__init__.py,main.py,utils.py}
touch tests/{__init__.py,test_main.py}
touch requirements.txt requirements-dev.txt .gitignore README.md .env
# Create .gitignore
cat > .gitignore <<EOF
venv/
__pycache__/
*.pyc
*.pyo
*.pyd
.Python
*.so
*.egg
*.egg-info/
dist/
build/
.env
.venv
*.log
EOF
Deployment
Production Deployment Setup
Flask Application Example
# Create Flask project
mkdir flask-app && cd flask-app
python3 -m venv venv
source venv/bin/activate
# Install Flask
pip install Flask gunicorn python-dotenv
# Create app structure
mkdir app
cat > app/__init__.py <<'EOF'
from flask import Flask
def create_app():
app = Flask(__name__)
@app.route('/')
def index():
return {'message': 'Flask API is running', 'status': 'healthy'}
@app.route('/health')
def health():
return {'status': 'healthy'}
return app
EOF
# Create main application file
cat > wsgi.py <<'EOF'
from app import create_app
app = create_app()
if __name__ == '__main__':
app.run()
EOF
# Create requirements.txt
cat > requirements.txt <<EOF
Flask==3.0.0
gunicorn==21.2.0
python-dotenv==1.0.0
EOF
# Create .env file
cat > .env <<EOF
FLASK_APP=wsgi.py
FLASK_ENV=production
SECRET_KEY=your-secret-key-here
EOF
# Test locally
flask run
# Run with gunicorn (production)
gunicorn --bind 0.0.0.0:8000 --workers 4 wsgi:app
Django Application Example
# Create Django project
mkdir django-app && cd django-app
python3 -m venv venv
source venv/bin/activate
# Install Django
pip install Django psycopg2-binary gunicorn python-dotenv
# Create project
django-admin startproject mysite .
# Create requirements.txt
pip freeze > requirements.txt
# Create .env file
cat > .env <<EOF
DEBUG=False
SECRET_KEY=your-django-secret-key
DATABASE_URL=postgresql://user:pass@localhost:5432/dbname
ALLOWED_HOSTS=example.com,www.example.com
EOF
# Configure settings.py to use .env
pip install python-decouple
# In settings.py:
from decouple import config
SECRET_KEY = config('SECRET_KEY')
DEBUG = config('DEBUG', default=False, cast=bool)
ALLOWED_HOSTS = config('ALLOWED_HOSTS', default='').split(',')
# Run migrations
python manage.py migrate
# Collect static files
python manage.py collectstatic
# Run with gunicorn
gunicorn --bind 0.0.0.0:8000 --workers 4 mysite.wsgi:application
Systemd Service Configuration
# Create systemd service file
sudo bash -c 'cat > /etc/systemd/system/myapp.service <<EOF
[Unit]
Description=My Python Application
After=network.target
[Service]
User=www-data
Group=www-data
WorkingDirectory=/var/www/myapp
Environment="PATH=/var/www/myapp/venv/bin"
EnvironmentFile=/var/www/myapp/.env
ExecStart=/var/www/myapp/venv/bin/gunicorn \
--workers 4 \
--bind 0.0.0.0:8000 \
--timeout 120 \
--access-logfile /var/log/myapp/access.log \
--error-logfile /var/log/myapp/error.log \
wsgi:app
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF'
# Create log directory
sudo mkdir -p /var/log/myapp
sudo chown www-data:www-data /var/log/myapp
# Enable and start service
sudo systemctl daemon-reload
sudo systemctl enable myapp
sudo systemctl start myapp
sudo systemctl status myapp
Nginx Configuration
server {
listen 80;
server_name example.com www.example.com;
access_log /var/log/nginx/myapp-access.log;
error_log /var/log/nginx/myapp-error.log;
location / {
proxy_pass http://127.0.0.1:8000;
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;
proxy_redirect off;
# Timeouts
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
# Static files
location /static/ {
alias /var/www/myapp/static/;
expires 30d;
add_header Cache-Control "public, immutable";
}
# Media files
location /media/ {
alias /var/www/myapp/media/;
expires 7d;
}
}
Monitoring
Virtual Environment Status
# Check if in virtual environment
echo $VIRTUAL_ENV
# Show installed packages
pip list
# Show outdated packages
pip list --outdated
# Check package versions
pip show package-name
# Verify package integrity
pip check
Application Monitoring
# Monitor application logs
tail -f /var/log/myapp/error.log
# Check systemd service status
sudo systemctl status myapp
# View service logs
sudo journalctl -u myapp -f
# Check process
ps aux | grep gunicorn
# Monitor resources
htop
Python Performance Monitoring
# Install monitoring tools
pip install py-spy memory_profiler
# Profile memory usage
python -m memory_profiler script.py
# CPU profiling with py-spy
py-spy top --pid $(pgrep -f gunicorn)
# Generate flame graph
py-spy record -o profile.svg --pid $(pgrep -f gunicorn)
Troubleshooting
Virtual Environment Issues
Issue: venv not activating
# Recreate virtual environment
rm -rf venv
python3 -m venv venv
source venv/bin/activate
# Check activation script permissions
chmod +x venv/bin/activate
Issue: Wrong Python version in venv
# Create with specific Python
python3.11 -m venv venv
# Or use pyenv
pyenv local 3.11.7
python -m venv venv
Package Installation Issues
Issue: pip install fails
# Upgrade pip
pip install --upgrade pip setuptools wheel
# Install with verbose output
pip install package-name -v
# Clear pip cache
pip cache purge
# Install from source
pip install --no-binary :all: package-name
Issue: Permission denied
# Always use virtual environment
source venv/bin/activate
# Never use sudo with pip in venv
# If outside venv, use --user flag
pip install --user package-name
Application Errors
Issue: ModuleNotFoundError
# Ensure virtual environment is activated
source venv/bin/activate
# Verify package is installed
pip list | grep package-name
# Reinstall package
pip install --force-reinstall package-name
# Check PYTHONPATH
echo $PYTHONPATH
Issue: Dependency conflicts
# Check dependencies
pip check
# Show dependency tree
pip install pipdeptree
pipdeptree
# Create clean environment
deactivate
rm -rf venv
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
Security Best Practices
Secure Package Installation
# Always verify requirements.txt before installing
cat requirements.txt
# Use hash-checking mode
pip install -r requirements.txt --require-hashes
# Generate hashes
pip hash package-name
# Audit dependencies
pip install safety
safety check
# Or use pip-audit
pip install pip-audit
pip-audit
Environment Variables
# Never hardcode secrets
# Use python-dotenv
pip install python-dotenv
# Create .env file
cat > .env <<EOF
SECRET_KEY=your-secret-key
DATABASE_URL=postgresql://localhost/dbname
API_KEY=your-api-key
EOF
# Add to .gitignore
echo ".env" >> .gitignore
# In Python code
from dotenv import load_dotenv
import os
load_dotenv()
secret = os.getenv('SECRET_KEY')
Secure Virtual Environment
# Set proper permissions
chmod 750 venv
chmod 640 venv/pyvenv.cfg
# Remove world-readable permissions
find venv -type d -exec chmod 750 {} \;
find venv -type f -exec chmod 640 {} \;
# Make scripts executable
chmod 750 venv/bin/*
Performance Optimization
Optimized Requirements
# Separate production and development dependencies
cat > requirements.txt <<EOF
# Production dependencies only
Flask==3.0.0
gunicorn==21.2.0
psycopg2-binary==2.9.9
EOF
cat > requirements-dev.txt <<EOF
# Development dependencies
-r requirements.txt
pytest==7.4.3
black==23.12.0
flake8==6.1.0
mypy==1.7.1
EOF
# Install accordingly
pip install -r requirements.txt # Production
pip install -r requirements-dev.txt # Development
Python Optimization
# Use __slots__ for memory optimization
class MyClass:
__slots__ = ['attr1', 'attr2']
def __init__(self, attr1, attr2):
self.attr1 = attr1
self.attr2 = attr2
# Use generators for large datasets
def read_large_file(file_path):
with open(file_path) as f:
for line in f:
yield line.strip()
# Use list comprehensions
result = [x * 2 for x in range(1000)]
# Cache expensive operations
from functools import lru_cache
@lru_cache(maxsize=128)
def expensive_function(n):
# Expensive computation
return result
Gunicorn Optimization
# Optimal workers = (2 x CPU cores) + 1
gunicorn --workers 5 \
--worker-class sync \
--worker-connections 1000 \
--timeout 30 \
--keep-alive 5 \
--bind 0.0.0.0:8000 \
wsgi:app
# For async applications
gunicorn --workers 5 \
--worker-class uvicorn.workers.UvicornWorker \
--bind 0.0.0.0:8000 \
main:app
Conclusion
You've successfully set up Python with virtual environments for development and production. This isolated, reproducible approach ensures clean dependency management and professional Python application deployment.
Key Takeaways
- Virtual environments isolate project dependencies
- Use requirements.txt for reproducible environments
- Separate production and development dependencies
- Never install packages with sudo inside venv
- Use environment variables for sensitive configuration
- gunicorn + systemd provides production-ready deployment
Best Practices
- Always use virtual environments
- Keep requirements.txt up to date
- Use specific package versions in production
- Implement security audits regularly
- Monitor application performance
- Use process managers (systemd, supervisor)
- Keep Python and packages updated
Next Steps
- Set up automated testing (pytest)
- Implement CI/CD pipelines
- Configure monitoring and alerting
- Set up automated backups
- Implement logging aggregation
- Create disaster recovery procedures
Python virtual environments are fundamental to professional Python development. Master them for clean, maintainable, production-ready applications!
Happy coding!


