1.  [Strona główna](/) ›
2.  [Baza wiedzy](/baza-wiedzy/) ›
3.  Django deployment na VPS

# Django - deployment na VPS z Gunicorn i Nginx

Opublikowano: 9 kwietnia 2026 · Kategoria: Python / VPS

⚡ W skrócie · 10 min czytania

-   Django production deployment krok po kroku: virtualenv, settings.py dla produkcji, Gunicorn WSGI, systemd service, Nginx reverse proxy przez Unix socket, certbot SSL, PostgreSQL, collectstatic, zmienne ENV.
-   Przygotowanie VPS - Python, PostgreSQL, Nginx.
-   Konfiguracja PostgreSQL - baza i użytkownik.
-   Virtualenv i instalacja zależności.
-   settings.py dla produkcji.

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.

Contabo

Tani VPS z 4 GB RAM - wystarczy dla Django + PostgreSQL + Redis na produkcji

Python ready

[Aktywuj rabat →](/out/contabo/#reklama "Contabo")

#Reklama · link partnerski

[Zobacz kod rabatowy →](/kody-rabatowe/contabo/)

Mikrus

Mikrus VPS - tani start dla Django projektów i API (od 15 PLN/msc)

Tani start

[Aktywuj rabat →](/out/mikrus/#reklama "Mikrus")

#Reklama · link partnerski

[Zobacz kod rabatowy →](/kody-rabatowe/mikrus/)

Hostido

VPS z SSD NVMe i pełnym dostępem root - idealny dla Django w produkcji

NVMe SSD

[Aktywuj rabat →](/out/hostido/#reklama "Hostido")

#Reklama · link partnerski

[Zobacz kod rabatowy →](/kody-rabatowe/hostido/)

## Powiązane strony

-   [Ranking i porównanie VPS
    
    Aktualne ceny VPS z pełnym kosztem 2-letnim (TCO) i bez ukrytych opłat odnowienia.
    
    ](/vps/)
-   [Nginx virtual host - konfiguracja](/baza-wiedzy/nginx-vhost-konfiguracja/)
-   [Laravel na hostingu - deployment](/baza-wiedzy/laravel-na-hostingu/)
-   [Docker na VPS - instalacja i Compose](/baza-wiedzy/docker-na-vps/)
-   [Let's Encrypt SSL - automatyzacja](/baza-wiedzy/ssl-lets-encrypt-automatyzacja/)
-   [Wszystkie artykuły](/baza-wiedzy/)
-   [Jaki VPS wybrać?](/jaki-vps-wybrac/)

Autor: [Redakcja HostGrade.pl](/autorzy/) Zespół redakcyjny · Aktualizacja: 9 kwietnia 2026

Artykuły HostGrade.pl przygotowuje i aktualizuje redakcja serwisu. Ceny startowe, ceny odnowienia i warunki planów sprawdzamy w cennikach i regulaminach dostawców, a potem liczymy całkowity koszt za 2 lata (cena startowa plus odnowienia). Zasady zbierania danych i liczenia kosztów opisujemy na stronie Metodologia. Linki partnerskie oznaczamy jako #reklama.

[O redakcji i metodologii →](/autorzy/)