Skip to content

Instantly share code, notes, and snippets.

@sunmeat
Last active May 20, 2026 09:14
Show Gist options
  • Select an option

  • Save sunmeat/4f9733398401a75e0c50d26a11dfd666 to your computer and use it in GitHub Desktop.

Select an option

Save sunmeat/4f9733398401a75e0c50d26a11dfd666 to your computer and use it in GitHub Desktop.
django render.com deployment checklist

Чеклист: деплой Django-проєкту на render.com

Виконайте всі кроки по порядку перед першим деплоєм (інструкція відносно загальна, тому можуть бути додаткові кроки)


1. Віртуальне середовище та залежності

1.1 Створіть та активуйте venv

python -m venv env
env\Scripts\activate

⚠️ Важливо: переконайтеся, що саме це середовище обране як інтерпретатор у VS Code — натисніть Ctrl+Shift+PPython: Select Interpreter → оберіть env. В Visual Studio 2026 - так само, через контекстне меню в Solution Explorer треба все перевірити!

1.2 Встановіть усі залежності в активоване середовище (версії на 20.05.2026, для вашого проєкту може бути +- інший список)

pip install Django==6.0.5
python.exe -m pip install --upgrade pip
pip install djangorestframework==3.17.1
pip install django-cors-headers==4.7.0
pip install django-filter==25.1
pip install requests==2.32.3
pip install Pillow==12.2.0
pip install gunicorn==23.0.0
pip install "whitenoise[brotli]==6.12.0"
pip install dj-database-url==2.3.0
pip install psycopg2-binary==2.9.12
pip install django-environ==0.12.0
pip install python-dotenv==1.2.2

1.3 Зафіксуйте залежності

pip freeze > requirements.txt

Якщо після встановлення нових пакетів — завжди оновлюйте requirements.txt цією командою!!!


2. Файл .env (локальна розробка)

Створіть файл .env у корені проєкту:

DEBUG=True
SECRET_KEY=lab#%!9bgg)qpnz+23*e&r#n9#qc#vks8&vg9yu49ax(^a6*r@

secret key generation

python -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())"

Не комітьте цей файл! Він має бути у .gitignore. На Render змінні передаються через Dashboard!


3. Файл .gitignore

# середовище
.env
venv/
env/
__pycache__/
*.pyc

# зібрана статика (Render збере її сам)
staticfiles/

# база даних SQLite (на продакшені буде PostgreSQL)
db.sqlite3

# IDE
.idea/
.vscode/

4. Налаштування settings.py

import os
import dj_database_url
from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent

# ── .env ──────────────────────────────────────────────────────────────────────
try:
    from dotenv import load_dotenv
    load_dotenv()
    print("✅ .env файл успішно завантажено")
except ImportError:
    print("⚠️ python-dotenv не встановлений")

# ── SECRET KEY ────────────────────────────────────────────────────────────────
SECRET_KEY = os.environ.get('SECRET_KEY')
if not SECRET_KEY:
    raise Exception("❌ SECRET_KEY не знайдено! Перевірте файл .env")

# ── DEBUG ─────────────────────────────────────────────────────────────────────
DEBUG = os.environ.get('DEBUG', 'True').lower() == 'true'

# ── ALLOWED HOSTS ─────────────────────────────────────────────────────────────
ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', '').split(',')
if not ALLOWED_HOSTS or ALLOWED_HOSTS == ['']:
    ALLOWED_HOSTS = ['localhost', '127.0.0.1', '0.0.0.0']

# ── INSTALLED APPS ────────────────────────────────────────────────────────────
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # сторонні
    'corsheaders',
    'django_filters',
    'rest_framework',
    # наші апки
    'app',
    'api',
]

# ── MIDDLEWARE ────────────────────────────────────────────────────────────────
MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware', # !!!
    'django.middleware.security.SecurityMiddleware',
    'whitenoise.middleware.WhiteNoiseMiddleware', # !!!
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'Rest.urls' # назва проєкта у вас буде своя, звісно
WSGI_APPLICATION = 'Rest.wsgi.application'

# ── DATABASE ──────────────────────────────────────────────────────────────────
if os.environ.get('DATABASE_URL'):
    DATABASES = {
        'default': dj_database_url.config(
            conn_max_age=600,
            conn_health_checks=True,
            ssl_require=True,
        )
    }
else:
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': BASE_DIR / 'db.sqlite3',
        }
    }

# ── TEMPLATES ─────────────────────────────────────────────────────────────────
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

# ── REST FRAMEWORK ────────────────────────────────────────────────────────────
REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'api.pagination.DefaultCursorPagination',
    'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'],
    'DEFAULT_THROTTLE_CLASSES': [
        'rest_framework.throttling.AnonRateThrottle',
        'rest_framework.throttling.UserRateThrottle',
    ],
    'DEFAULT_THROTTLE_RATES': {
        'anon': '10000/day',
        'user': '10000/day',
    },
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.BasicAuthentication',
    ],
}

# ── STATIC FILES ──────────────────────────────────────────────────────────────
STATIC_URL = '/static/'
STATIC_ROOT = BASE_DIR / 'staticfiles'
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'

# ── CORS ──────────────────────────────────────────────────────────────────────
CORS_ALLOW_ALL_ORIGINS = True   # на продакшені краще обмежити

# ── SECURITY (тільки продакшн) ────────────────────────────────────────────────
if not DEBUG:
    SECURE_SSL_REDIRECT = True
    SESSION_COOKIE_SECURE = True
    CSRF_COOKIE_SECURE = True
    SECURE_HSTS_SECONDS = 31536000
    SECURE_HSTS_INCLUDE_SUBDOMAINS = True
    SECURE_HSTS_PRELOAD = True

# ── INTERNATIONALIZATION ──────────────────────────────────────────────────────
LANGUAGE_CODE = 'uk'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_TZ = True

# ── CACHE ─────────────────────────────────────────────────────────────────────
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
        'LOCATION': 'unique-snowflake',
    }
}

5. Файл build.sh

Створіть у корені проєкту файл build.sh:

#!/usr/bin/env bash
# exit on error
set -o errexit

echo "Installing dependencies..."
pip install -r requirements.txt

echo "Collecting static files..."
python manage.py collectstatic --noinput --clear

echo "Running migrations..."
python manage.py migrate --noinput

echo "Build completed successfully!"

⚠️ Після створення файлу зробіть його виконуваним (для Linux/Mac або через Git Bash, на вінді цей крок пропускаємо):

chmod +x build.sh

6. Файл render.yaml

Створіть у корені проєкту файл render.yaml:

services:
  - type: web
    name: alexflow # тут можна поставити назву вашого сервісу на рендері, не принципово
    env: python
    plan: free

    buildCommand: ./build.sh
    startCommand: >
      gunicorn Rest.wsgi:application --log-level info

    envVars:
      - key: SECRET_KEY
        generateValue: true
        sync: false

      - key: DEBUG
        value: "False"

      - key: ALLOWED_HOSTS
        value: ".onrender.com"

      - key: PYTHON_VERSION
        value: "3.14"

databases:
  - name: my-django-db
    databaseName: mydb
    user: myuser
    plan: free

⚠️ Зверніть увагу: блок databases знаходиться на одному рівні з services, не всередині нього.


7. Команди деплою в Render Dashboard

Shell на Render у безкоштовному плані — платний!!! Тому всі потрібні дії виконуються у Start Command.

Build Command

./build.sh

(міграції та статика вже всередині build.sh)

Start Command

python manage.py migrate && python manage.py shell -c "from django.contrib.auth import get_user_model; User=get_user_model(); User.objects.filter(username='alex').exists() or User.objects.create_superuser('alex','','1')" && python manage.py seed && gunicorn Rest.wsgi:application --log-level info

Ця команда при кожному старті:

  1. Виконує міграції (якщо є нові)
  2. Створює суперюзера alex (якщо ще не існує, собі створіть інший логін та пароль)
  3. Запускає seed (наповнення даними) - при кожному редеплої!!!
  4. Стартує Gunicorn

8. Змінні середовища на Render

Перейдіть: Render Dashboard → ваш сервіс → Environment

Змінна Значення
SECRET_KEY Натисніть Generate або вставте свій
DEBUG False
ALLOWED_HOSTS .onrender.com
DATABASE_URL Додається автоматично після підключення PostgreSQL, руками писати не треба

9. Публікація на GitHub

Відкрийте Git Bash у папці проєкту та виконайте по порядку:

# 1. Ініціалізація git (якщо ще не зроблено)
git init

# 2. Додаємо всі файли (з урахуванням .gitignore!)
git add .

# 3. Перший коміт
git commit -m "Initial commit"

# 4. Підключаємо GitHub-репозиторій (заміни на свій)
git remote add origin https://github.com/ВАШ_ЮЗЕРНЕЙМ/НАЗВА_РЕПО.git

# 5. Перейменовуємо гілку в main і пушимо
git branch -M main
git push -u origin main

Якщо репозиторій вже існує і там є файли (наприклад, ліцензія):

# Спочатку підтягуємо те, що є на GitHub
git pull origin main --allow-unrelated-histories

# Потім пушимо свої зміни
git push -u origin main

✅ Гілка обов'язково має називатися main — саме її слухає Render!


10. Фінальний чеклист перед деплоєм

  • venv створено, активовано, інтерпретатор обраний у VS Code / VS 2026 / PyCharm
  • Усі пакети встановлені саме у venv
  • requirements.txt актуальний і містить gunicorn, whitenoise, dj-database-url, psycopg2-binary
  • build.sh створено та додано до репозиторію
  • render.yaml створено та налаштовано
  • DEBUG = False через змінну середовища на рендері, в локальному проєкті залишаємо тру
  • SECRET_KEY береться зі змінної середовища
  • ALLOWED_HOSTS містить .onrender.com
  • DATABASES налаштована через dj-database-url
  • WhiteNoiseMiddleware підключено після SecurityMiddleware
  • STATIC_ROOT вказано, collectstatic виконується без помилок
  • .env файл у .gitignore і не запушений
  • Гілка main, всі зміни запушено

Часті помилки

Помилка Причина Рішення
ModuleNotFoundError: No module named 'gunicorn' Gunicorn не у requirements.txt Додайте і перезапуште
ALLOWED_HOSTS error Домен Render не вказано Додайте .onrender.com
Статика не завантажується WhiteNoise не підключено або стоїть не там Перевірте порядок у MIDDLEWARE
django.db.utils.OperationalError Міграції не виконано Перевірте build.sh або Start Command
Invalid HTTP_HOST header Змінна ALLOWED_HOSTS порожня Перевірте Environment Variables на Render
./build.sh: Permission denied Файл не є виконуваним Виконайте chmod +x build.sh і перезапуште

Підказка: після кожного деплою перевіряйте логи у Render Dashboard → Logs. Більшість проблем видно там одразу. Успіхів :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment