Asosiy kontentga o‘tish

Maqolalar

Darslik · 2026-08-16 · ~4 daqiqa o‘qiladi · o'rta

Docker'siz production deploy: uv + gunicorn + systemd + nginx

#devops #linux #backend

Mundarija

Hamma joyda "deploy = Docker" deb o'rgatishadi. Lekin qo'lingizda 1GB RAM'lik, eski OS'li arzon VPS bo'lsa (yoki bitta serverda boshqa loyihalar ham yashasa), Docker ortiqcha yuk bo'lishi mumkin. Shu sayt — solijonov.uz — aynan shunday serverda, Docker'siz ishlayapti. Mana to'liq retsept.

Arxitektura#

Internet → nginx (443, TLS) → gunicorn (127.0.0.1:8001) → Django
                └── /static/ fayllarni to'g'ridan-to'g'ri beradi

nginx — tashqi eshik: HTTPS'ni tugatadi, static fayllarni o'zi beradi (Python'ga yuk tushmaydi), qolganini gunicorn'ga uzatadi. systemd — "qorovul": server qayta yuklansa yoki jarayon yiqilsa, o'zi qayta ko'taradi.

1. Python va kutubxonalar — uv bilan#

Eski serverlarda tizim Python'i qadimiy bo'ladi. uv buni bir buyruq bilan hal qiladi:

curl -LsSf https://astral.sh/uv/install.sh | sh
uv python install 3.13
cd /opt/mysite && uv sync --frozen --no-dev

--frozen — lockfile'dagi aynan shu versiyalar o'rnatiladi: lokalda qanday ishlagan bo'lsa, serverda ham shunday.

2. Gunicorn'ni systemd ostiga qo'yish#

/etc/systemd/system/mysite.service:

[Unit]
Description=Mysite (gunicorn)
After=network.target

[Service]
WorkingDirectory=/opt/mysite
Environment=DJANGO_SETTINGS_MODULE=config.settings.prod
ExecStart=/opt/mysite/.venv/bin/gunicorn config.wsgi:application --bind 127.0.0.1:8001 --workers 2
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable --now mysite

Restart=always + enable — ikki qator, lekin "server reboot bo'ldi, sayt o'lik" degan tungi qo'ng'iroqlardan qutqaradi. Workers soni: kichik server uchun 2 yetadi (formula: 2 × CPU + 1 — lekin RAM'ga qarab kamaytiring).

3. Nginx — proxy va static#

/etc/nginx/conf.d/mysite.conf:

server {
    listen 80;
    server_name mysite.uz www.mysite.uz;

    location /static/ {
        alias /opt/mysite/staticfiles/;
        expires 30d;
        add_header Cache-Control "public, immutable";
    }

    location / {
        proxy_pass http://127.0.0.1:8001;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

X-Forwarded-Proto muhim: Django SECURE_PROXY_SSL_HEADER orqali so'rov HTTPS'da kelganini shundan biladi.

4. HTTPS — certbot#

uv tool install certbot --with certbot-nginx
certbot --nginx -d mysite.uz -d www.mysite.uz

Certbot nginx konfigga TLS blokini o'zi yozadi. Yangilanishni cron'ga qo'ying: 17 3,15 * * * certbot renew --quiet — sertifikat muddati o'z-o'zidan uzayadi.

5. Deploy skripti#

Har deploy — bitta buyruq bo'lishi kerak. Bizniki qisqartirilgan ko'rinishda:

rsync -az --delete --exclude .venv --exclude .env ./ server:/opt/mysite/
ssh server "cd /opt/mysite && uv sync --frozen --no-dev \
  && .venv/bin/python manage.py collectstatic --noinput \
  && .venv/bin/python manage.py migrate --noinput \
  && systemctl restart mysite"

.envni ataylab sync qilmaymiz — sirlar serverda qoladi, tasodifan o'chmasin.

Docker qachon kerak, qachon yo'q#

Docker'siz yaxshi: bitta-ikkita loyiha, kichik server, tez boshlash, RAM tanqis. Docker yaxshi: ko'p xizmatli stack (Postgres, Redis, workerlar), jamoa, "mening mashinamda ishlagan edi" muammosi. Bu tanlov diniy emas — amaliy: bizga bugun yengillik kerak edi, ertaga server kattalashsa, compose faylimiz tayyor turibdi.

Savol qolsa — Telegram'da yozing, shu mavzuda video dars ham qilaman.