 Autor: [Adam Nadolny](/autorzy/adam-nadolny) Ekspert DevOps i infrastruktury · Zweryfikowano Kwiecień 2026

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

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 · 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 · 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 · link partnerski

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

## Powiązane strony

-   [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/)