djangolinuxcicd

How to Deploy Django API without zero downtime?


I need to implement a zero-downtime CI/CD deployment pipeline for my Django API on an on-premises Linux server to ensure seamless updates without interrupting active users, similar to the previous maintenance-free setup.


Solution

  • You may want to try :
    Deploy to a new directory -> Update symlink (current) -> Gracefully reload Gunicorn (kill -HUP) -> Keep Nginx active as a reverse proxy

    Example:

    1. Use a Versioned Directory Structure - Deploy each version into its own timestamped folder:

    
    /var/www/myproject/
    ├── current -> /var/www/myproject/releases/2025-05-06-1230/
    ├── releases/
    │   ├── 2025-05-06-1230/
    │   ├── 2025-05-05-1700/
    ├── shared/  (media/, static/, .env etc.)
    

    In your CI/CD pipeline (e.g., GitLab CI, Jenkins, or Bash script):

    # Timestamped release path
    RELEASE_DIR="/var/www/myproject/releases/$(date +%Y-%m-%d-%H%M)"
    mkdir -p $RELEASE_DIR
    
    # Clone or copy project files
    git clone https://your-repo.git $RELEASE_DIR
    cd $RELEASE_DIR
    
    # Setup virtual environment
    source /var/www/myproject/venv/bin/activate
    
    # Install dependencies
    pip install -r requirements.txt
    
    # Migrate DB and collect static
    python manage.py migrate --noinput
    python manage.py collectstatic --noinput
    
    # Point "current" symlink to new release
    ln -sfn $RELEASE_DIR /var/www/myproject/current
    
    # Reload Gunicorn gracefully
    kill -HUP `cat /run/gunicorn.pid`
    

    Use Gunicorn's --pid flag and HUP signal to gracefully reload:

    gunicorn --pid /run/gunicorn.pid ...
    kill -HUP `cat /run/gunicorn.pid`
    

    Use Nginx to proxy requests to Gunicorn, which adds buffering and reliability:

    location / {
        proxy_pass http://unix:/run/gunicorn.sock;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }