Menu
Szybki wybór
Hosting Domeny VPS SSL Kalkulator Porównania FAQ
Aktywne kody
Wszystkie kody rabatowe

Django — deployment na VPS z Gunicorn i Nginx

Opublikowano: 9 kwietnia 2026 · Kategoria: Python / VPS

Django w trybie deweloperskim (python manage.py runserver) nie nadaje się do produkcji — jest jednowątkowy, nie obsługuje wielu żądań jednocześnie i ma wyłączony wiele mechanizmów bezpieczeństwa. Produkcyjny stack Django to: Gunicorn (WSGI server) obsługuje Python, Nginx (reverse proxy) zarządza ruchem HTTP, systemd pilnuje procesów. Oto kompletna instrukcja deployment od zera.

Przygotowanie VPS — Python, PostgreSQL, Nginx

# Ubuntu 22.04 / Debian 12
sudo apt update && sudo apt upgrade -y

# Python 3.11+ i narzędzia
sudo apt install python3 python3-pip python3-venv python3-dev -y

# PostgreSQL
sudo apt install postgresql postgresql-contrib libpq-dev -y
sudo systemctl enable --now postgresql

# Nginx
sudo apt install nginx -y
sudo systemctl enable --now nginx

# Certbot (SSL)
sudo apt install certbot python3-certbot-nginx -y

# Utwórz użytkownika aplikacji (bez uprawnień root)
sudo adduser --system --group --home /var/www/django-app django

Konfiguracja PostgreSQL — baza i użytkownik

sudo -u postgres psql

CREATE DATABASE moja_baza_prod;
CREATE USER moja_baza_user WITH PASSWORD 'BezpieczneHaslo456!';
ALTER ROLE moja_baza_user SET client_encoding TO 'utf8';
ALTER ROLE moja_baza_user SET default_transaction_isolation TO 'read committed';
ALTER ROLE moja_baza_user SET timezone TO 'Europe/Warsaw';
GRANT ALL PRIVILEGES ON DATABASE moja_baza_prod TO moja_baza_user;
\q

Virtualenv i instalacja zależności

# Sklonuj projekt (lub skopiuj przez SFTP/rsync)
sudo mkdir -p /var/www/django-app
sudo chown django:django /var/www/django-app
sudo -u django git clone https://github.com/twoj/projekt.git /var/www/django-app

cd /var/www/django-app

# Utwórz i aktywuj virtualenv
sudo -u django python3 -m venv venv
sudo -u django venv/bin/pip install --upgrade pip

# Zainstaluj zależności
sudo -u django venv/bin/pip install -r requirements.txt
sudo -u django venv/bin/pip install gunicorn psycopg2-binary

settings.py dla produkcji

# settings_prod.py lub przez zmienne środowiskowe
import os

DEBUG = False

# Twoja domena / IP serwera
ALLOWED_HOSTS = ['twojadomena.pl', 'www.twojadomena.pl', '1.2.3.4']

# Baza danych (wartości z ENV — nie hardcoduj haseł!)
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': os.environ['DB_NAME'],
        'USER': os.environ['DB_USER'],
        'PASSWORD': os.environ['DB_PASSWORD'],
        'HOST': 'localhost',
        'PORT': '5432',
    }
}

# Pliki statyczne
STATIC_ROOT = '/var/www/django-app/staticfiles'
STATIC_URL = '/static/'

# Bezpieczeństwo HTTPS
SECURE_SSL_REDIRECT = True
SECURE_HSTS_SECONDS = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True

# Klucz z ENV
SECRET_KEY = os.environ['DJANGO_SECRET_KEY']
# Uruchom migracje i zbierz pliki statyczne
sudo -u django venv/bin/python manage.py migrate --settings=moj_projekt.settings_prod
sudo -u django venv/bin/python manage.py collectstatic --noinput --settings=moj_projekt.settings_prod

Gunicorn — konfiguracja

# Plik konfiguracji Gunicorn: /var/www/django-app/gunicorn.conf.py
bind = 'unix:/run/gunicorn/gunicorn.sock'   # Unix socket (szybszy niż TCP)
workers = 5                                  # (2 × CPU) + 1
worker_class = 'sync'                        # sync = domyślny, gevent = async I/O
timeout = 30                                 # sekundy przed zabiciem wolnego workera
keepalive = 5                                # sekundy keep-alive dla połączeń
max_requests = 1000                          # restart workera po N requestach (memory leak prevention)
max_requests_jitter = 100                    # losowość restartów
errorlog = '/var/log/gunicorn/error.log'
accesslog = '/var/log/gunicorn/access.log'
loglevel = 'warning'

systemd service dla Gunicorn

# /etc/systemd/system/gunicorn.service
[Unit]
Description=Gunicorn daemon dla Django
Requires=gunicorn.socket
After=network.target postgresql.service

[Service]
Type=notify
User=django
Group=django
RuntimeDirectory=gunicorn
WorkingDirectory=/var/www/django-app

# Zmienne środowiskowe (hasła, klucze) — poza kodem i poza git
EnvironmentFile=/etc/django-app/env

ExecStart=/var/www/django-app/venv/bin/gunicorn \
    --config /var/www/django-app/gunicorn.conf.py \
    moj_projekt.wsgi:application

ExecReload=/bin/kill -s HUP $MAINPID
KillMode=mixed
TimeoutStopSec=5
PrivateTmp=true
Restart=on-failure

[Install]
WantedBy=multi-user.target
# /etc/systemd/system/gunicorn.socket
[Unit]
Description=Gunicorn socket

[Socket]
ListenStream=/run/gunicorn/gunicorn.sock
SocketUser=www-data

[Install]
WantedBy=sockets.target
# Plik zmiennych środowiskowych (chmod 600!)
# /etc/django-app/env
DJANGO_SECRET_KEY=twoj-bardzo-dlugi-tajny-klucz-losowy-co-najmniej-50-znakow
DB_NAME=moja_baza_prod
DB_USER=moja_baza_user
DB_PASSWORD=BezpieczneHaslo456!
DJANGO_SETTINGS_MODULE=moj_projekt.settings_prod

# Uprawnienia
sudo chmod 600 /etc/django-app/env
sudo chown root:root /etc/django-app/env

# Włącz i uruchom
sudo mkdir -p /var/log/gunicorn && sudo chown django:django /var/log/gunicorn
sudo systemctl daemon-reload
sudo systemctl enable --now gunicorn.socket gunicorn.service
sudo systemctl status gunicorn

Nginx reverse proxy — konfiguracja

# /etc/nginx/sites-available/django-app
server {
    listen 80;
    server_name twojadomena.pl www.twojadomena.pl;

    # Przekierowanie na HTTPS (certbot doda automatycznie)
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    server_name twojadomena.pl www.twojadomena.pl;

    # SSL — certbot wypełni automatycznie
    ssl_certificate /etc/letsencrypt/live/twojadomena.pl/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/twojadomena.pl/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;

    # Pliki statyczne Django — serwowane bezpośrednio przez Nginx
    location /static/ {
        alias /var/www/django-app/staticfiles/;
        expires 30d;
        add_header Cache-Control "public, immutable";
    }

    location /media/ {
        alias /var/www/django-app/media/;
        expires 7d;
    }

    # Całą resztę kieruj do Gunicorn przez Unix socket
    location / {
        include proxy_params;
        proxy_pass http://unix:/run/gunicorn/gunicorn.sock;
        proxy_read_timeout 30s;
        proxy_connect_timeout 5s;
        client_max_body_size 20M;
    }
}
sudo ln -s /etc/nginx/sites-available/django-app /etc/nginx/sites-enabled/
sudo nginx -t                     # sprawdź składnię
sudo systemctl reload nginx

# Uzyskaj certyfikat SSL (Let's Encrypt)
sudo certbot --nginx -d twojadomena.pl -d www.twojadomena.pl

# Sprawdź automatyczne odnawianie
sudo certbot renew --dry-run

Weryfikacja i logi

# Status serwisów
sudo systemctl status gunicorn nginx postgresql

# Logi w czasie rzeczywistym
sudo journalctl -u gunicorn -f              # Gunicorn (systemd logi)
sudo tail -f /var/log/gunicorn/error.log   # Gunicorn error log
sudo tail -f /var/log/nginx/error.log      # Nginx error log

# Test aplikacji
curl -I https://twojadomena.pl             # sprawdź nagłówki HTTP
curl https://twojadomena.pl/api/health/    # endpoint health check

Najczęstsze pytania

Ile workerów Gunicorn ustawić dla Django? +
Standardowa reguła: workers = (2 × liczba_CPU) + 1. Dla VPS z 2 CPU: 5 workerów. Dla VPS z 4 CPU: 9 workerów. Każdy worker to osobny proces Python — zajmuje ~50-100 MB RAM. Dla VPS z 2 GB RAM i 2 CPU: 5 workerów × ~80 MB = ~400 MB dla Gunicorn, zostawiając resztę dla PostgreSQL, OS i innych procesów. Monitoruj zużycie RAM i dostosuj. Przy długich requestach (raporty, eksporty) rozważ Gunicorn z gevent lub Celery dla zadań asynchronicznych.
Czym różni się Gunicorn od uWSGI? +
Oba są WSGI serwerami dla Python. Gunicorn (Green Unicorn) jest prostszy w konfiguracji — domyślna instalacja i kilka parametrów wystarczą. uWSGI jest bardziej elastyczny i wydajniejszy w ekstremalnych przypadkach, ale ma znacznie bardziej skomplikowaną konfigurację (setki opcji). Dla większości projektów Django — Gunicorn jest wystarczający i zalecanym wyborem. uWSGI warto rozważyć gdy potrzebujesz specyficznych funkcji (emperor mode dla wielu aplikacji, zaawansowane protokoły jak uwsgi protocol z Nginx bez HTTP overhead).
Jak bezpiecznie przechowywać zmienne środowiskowe (SECRET_KEY, hasła) w Django na VPS? +
Kilka metod: (1) Plik .env + python-decouple lub python-dotenv — plik .env poza repozytorium git, biblioteka ładuje zmienne do os.environ. Łatwe w użyciu, ale plik .env na dysku. (2) systemd EnvironmentFile=/etc/django-app/env — zmienne załadowane przez systemd do procesu Gunicorn. Bezpieczniejsze bo dostęp kontroluje systemd (uprawnienia 600). (3) Vault/AWS Secrets Manager — dla krytycznych projektów enterprise. Najprościej i bezpiecznie: EnvironmentFile w konfiguracji systemd z uprawnieniami 600 root:root.
Jak zdeployować aktualizację Django bez przestoju? +
Procedura zero-downtime deploy: (1) Podciągnij nowy kod: git pull origin main. (2) Aktywuj virtualenv i zaktualizuj zależności: pip install -r requirements.txt. (3) Uruchom migracje: python manage.py migrate (przy kompatybilnych migracjach — nie ma problemu z uruchomieniem przed restartem). (4) Skompiluj statyki: python manage.py collectstatic --noinput. (5) Zrestartuj Gunicorn gracefully: sudo systemctl reload gunicorn (lub kill -HUP pid_mastera) — Gunicorn masterowy process foruje nowe workery zanim zabije stare. Nginx przez cały czas kieruje ruch przez socket.

Sprawdź oferty pasujące do tego scenariusza

Poniżej masz szybkie przejścia do ofert i stron z kodami rabatowymi tam, gdzie są dostępne.