django
Markdown

baremetal

  1. Create Server & Initial Setup:
# Connect to server
ssh root@your_ip_address

# Update system
sudo apt update
sudo apt upgrade

# Install required packages (for pip)
sudo apt install python3-pip python3-dev libpq-dev postgresql postgresql-contrib nginx certbot python3-certbot-nginx supervisor

# For uv: Install the above packages (except python3-pip) and then install uv
sudo apt install python3-dev libpq-dev postgresql postgresql-contrib nginx certbot python3-certbot-nginx supervisor python3
curl -LsSf https://astral.sh/uv/install.sh | sh
  1. Configure PostgreSQL:
# Login to PostgreSQL
sudo -u postgres psql

# Create database and user
CREATE DATABASE project1;
CREATE USER project1user WITH PASSWORD 'project1password';
ALTER ROLE project1user SET client_encoding TO 'utf8';
ALTER ROLE project1user SET default_transaction_isolation TO 'read committed';
ALTER ROLE project1user SET timezone TO 'UTC';
GRANT ALL PRIVILEGES ON DATABASE project1 TO project1user;
  1. Setup Project Environment:
# Create project directory
mkdir /webapps
cd /webapps
mkdir project1
cd project1

# Create virtual environment
# For pip:
python3 -m venv env
# For uv:
uv venv env

# Create user group and project user
sudo groupadd --system webapps
sudo useradd --system --gid webapps --shell /bin/bash --home /webapps/project1 project1user

# Set correct permissions
sudo chown -R project1user:webapps .
  1. Project Setup:
# Clone your project from GitHub
git clone your_repository_url

# Create .env file
vi .env
# Add:
SECRET_KEY=your_secret_key
DB_PASSWORD=your_database_password

# Activate virtual environment
source env/bin/activate

# Install requirements
# For pip:
pip install -r requirements.txt

# For uv (choose one):
uv pip install -r requirements.txt
# OR
uv install -r requirements.txt

# Optional: If using uv with lock files
# Generate lock file locally before deployment:
uv pip compile requirements.txt -o requirements.lock
# Install from lock file on server:
uv pip sync requirements.lock

# Run migrations
python manage.py migrate --settings=project1.settings_prod
  1. Configure Gunicorn:
# Create Gunicorn start script
vi env/bin/gunicorn_start

# Add the script content:
#!/bin/bash
NAME="project1"
DIR=/webapps/project1/project1
SOCKFILE=/webapps/project1/run/gunicorn.sock
USER=project1user
GROUP=webapps
NUM_WORKERS=3
DJANGO_SETTINGS_MODULE=project1.settings_prod
DJANGO_WSGI_MODULE=project1.wsgi
timeout=120

cd $DIR
source ../env/bin/activate

# Add this line if using uv:
export UV_VIRTUALENV=1

export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE
export PYTHONPATH=$DIR:$PYTHONPATH

RUNDIR=$(dirname $SOCKFILE)
test -d $RUNDIR || mkdir -p $RUNDIR

exec ../env/bin/gunicorn ${DJANGO_WSGI_MODULE}:application \
  --name $NAME \
  --workers $NUM_WORKERS \
  --timeout $timeout \
  --user=$USER \
  --group=$GROUP \
  --bind=unix:$SOCKFILE \
  --log-level=debug
  1. Configure Supervisor:
# Create supervisor config
sudo vi /etc/supervisor/conf.d/project1.conf

# Add:
[program:project1]
command=/webapps/project1/env/bin/gunicorn_start
user=project1user
autostart=true
autorestart=true
redirect_stderr=true
stdout_logfile=/webapps/project1/logs/supervisor.log

# Create logs directory
mkdir logs
sudo chown project1user:webapps logs

# Reread and update supervisor
sudo supervisorctl reread
sudo supervisorctl update
  1. Configure Nginx:
# Remove default config
sudo rm /etc/nginx/sites-available/default
sudo rm /etc/nginx/sites-enabled/default

# Create new config
sudo vi /etc/nginx/sites-available/project1

# Add Nginx configuration:
upstream project1_app_server {
    server unix:/webapps/project1/run/gunicorn.sock fail_timeout=0;
}

server {
    listen 80;
    server_name project1.example.com;

    access_log /webapps/project1/logs/nginx-access.log;
    error_log /webapps/project1/logs/nginx-error.log;

    location /static/ {
        alias /webapps/project1/project1/static/;
    }

    location /media/ {
        alias /webapps/project1/project1/media/;
    }

    location / {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_pass http://project1_app_server;
    }
}

# Create symbolic link
sudo ln -s /etc/nginx/sites-available/project1 /etc/nginx/sites-enabled/project1

# Start Nginx
sudo service nginx start
  1. SSL Setup:
# Get SSL certificate
sudo certbot --nginx -d yourdomain.com

For deploying additional projects, repeat steps 2-8 with appropriate name changes (project2, project2user, etc.).

The main differences when using uv are:

  • Installation of uv instead of pip
  • Using uv venv instead of python3 -m venv
  • Different package installation commands with uv
  • Addition of export UV_VIRTUALENV=1 in the Gunicorn script
  • Optional use of lock files for more reproducible deployments

All other steps remain the same regardless of whether you use pip or uv.