From f5130a79fd42ee746531ec9a78549d2c6e3ab849 Mon Sep 17 00:00:00 2001 From: Andrey Smakotin Date: Wed, 7 Jan 2026 20:50:35 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=B4=D0=BE=D0=BA=D1=83=D0=BC=D0=B5=D0=BD=D1=82?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D1=8F:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D1=8B=20=D0=BF=D1=80=D0=B5=D0=B4=D1=83=D0=BF?= =?UTF-8?q?=D1=80=D0=B5=D0=B6=D0=B4=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BE=20?= =?UTF-8?q?=D0=BF=D1=80=D0=B0=D0=B2=D0=B0=D1=85=20=D0=B4=D0=BE=D1=81=D1=82?= =?UTF-8?q?=D1=83=D0=BF=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ИНСТРУКЦИЯ_ОБНОВЛЕНИЕ.md: * Усилено предупреждение о необходимости настройки прав после КАЖДОГО обновления * Добавлены признаки проблемы: crash loop контейнера, 404 на тенантах * Подчёркнута критичность выполнения chown/chmod - DEPLOY_NAS.md: * Добавлены команды chown/chmod в раздел 'Обновление приложения' * Новый раздел 'Проблема 7': новый тенант возвращает 404 * Пошаговая диагностика: проверка домена в БД и логов контейнера * Объяснение причины: контейнер падает из-за Permission denied Теперь при проблемах после обновления кода пользователь сразу увидит, что нужно проверить права доступа на файлы проекта. --- myproject/docker/DEPLOY_NAS.md | 496 +++++++++++++++++++++++++++++++++ ИНСТРУКЦИЯ_ОБНОВЛЕНИЕ.md | 130 +++++++++ 2 files changed, 626 insertions(+) create mode 100644 myproject/docker/DEPLOY_NAS.md create mode 100644 ИНСТРУКЦИЯ_ОБНОВЛЕНИЕ.md diff --git a/myproject/docker/DEPLOY_NAS.md b/myproject/docker/DEPLOY_NAS.md new file mode 100644 index 0000000..c8658fd --- /dev/null +++ b/myproject/docker/DEPLOY_NAS.md @@ -0,0 +1,496 @@ +# Развёртывание на TerraMaster F2-424 (TOS 6) + +## Требования +- TerraMaster NAS с TOS 6 +- Docker и Docker Compose установлены +- SSH доступ к NAS +- 32 GB RAM (более чем достаточно) + +## Структура на NAS + +``` +/Volume1/DockerYAML/mix/ # Только docker-compose.yml +└── docker-compose.yml + +/Volume1/DockerAppsData/mixapp/ # Всё остальное +├── app/ # Код приложения (весь проект) +│ ├── myproject/ +│ ├── requirements.txt +│ └── docker/ +│ ├── Dockerfile +│ ├── entrypoint.sh +│ └── .env.docker +├── postgres/ # База данных PostgreSQL +├── redis/ # Данные Redis +├── media/ # Загруженные файлы (фото товаров) +└── static/ # Статические файлы Django +``` + +## Шаг 1: Подготовка директорий на NAS + +```bash +# Подключаемся к NAS по SSH +ssh admin@ + +# Создаём директории +mkdir -p /Volume1/DockerAppsData/mixapp/{app,postgres,redis,media,static} +mkdir -p /Volume1/DockerYAML/mix + +# Устанавливаем права (uid 1000 для контейнера appuser) +chown -R 1000:1000 /Volume1/DockerAppsData/mixapp/app +chown -R 1000:1000 /Volume1/DockerAppsData/mixapp/media +chown -R 1000:1000 /Volume1/DockerAppsData/mixapp/static +chmod -R u+rwX /Volume1/DockerAppsData/mixapp +``` + +## Шаг 2: Копирование файлов проекта на NAS + +### Вариант A: Через SCP (с Windows) +```powershell +# Из папки проекта на Windows +cd C:\Users\team_\Desktop\test_qwen + +# Копируем код приложения в папку данных +scp -r myproject requirements.txt docker .dockerignore admin@:/Volume1/DockerAppsData/mixapp/app/ + +# Копируем docker-compose.yml в папку YAML +scp docker/docker-compose.yml admin@:/Volume1/DockerYAML/mix/ +``` + +### Вариант B: Через общую папку SMB +1. Подключите сетевую папку NAS +2. Скопируйте содержимое папки проекта (`myproject/`, `requirements.txt`, `docker/` и т.д.) в `/Volume1/DockerAppsData/mixapp/app/` +3. Скопируйте `docker/docker-compose.yml` в `/Volume1/DockerYAML/mix/` + +## Шаг 3: Настройка переменных окружения + +```bash +# На NAS +cd /Volume1/DockerAppsData/mixapp/app/docker + +# Редактируем .env.docker +nano .env.docker +``` + +**ВАЖНО! Измените следующие значения:** + +```env +# Django settings +SECRET_KEY=ваш-очень-длинный-секретный-ключ-минимум-50-символов +DEBUG=False +ALLOWED_HOSTS=mix.smaa.by,*.mix.smaa.by,localhost,127.0.0.1 +CSRF_TRUSTED_ORIGINS=https://mix.smaa.by,https://*.mix.smaa.by +DOMAIN_NAME=mix.smaa.by + +# Database (PostgreSQL) +DB_NAME=inventory_db +DB_USER=postgres +DB_PASSWORD=ваш-надежный-пароль-postgres +DB_HOST=db +DB_PORT=5432 + +# Значения для официального образа Postgres (ДОЛЖНЫ СОВПАДАТЬ с DB_*) +POSTGRES_DB=inventory_db +POSTGRES_USER=postgres +POSTGRES_PASSWORD=ваш-надежный-пароль-postgres + +# Redis +REDIS_HOST=redis +REDIS_PORT=6379 +REDIS_DB=0 + +# Celery +CELERY_BROKER_URL=redis://redis:6379/0 + +# Tenant Admin (создаётся при первом запуске) +TENANT_ADMIN_EMAIL=admin@example.com +TENANT_ADMIN_PASSWORD=ваш-админ-пароль +TENANT_ADMIN_NAME=Admin + +# Django-tenants +PUBLIC_SCHEMA_DOMAIN=mix.smaa.by +TENANT_DOMAIN_BASE=mix.smaa.by +USE_HTTPS=True +``` + +### ⚠️ КРИТИЧЕСКИ ВАЖНО: + +1. **`DB_PASSWORD` и `POSTGRES_PASSWORD` ДОЛЖНЫ БЫТЬ ОДИНАКОВЫМИ!** + Иначе Django не сможет подключиться к PostgreSQL. + +2. **В `docker-compose.yml` у сервиса `db` НЕ должно быть блока `environment:`** + Все переменные читаются напрямую из `.env.docker` через `env_file`. + +3. **При смене пароля БД после первого запуска:** + Простое изменение `POSTGRES_PASSWORD` в `.env.docker` НЕ изменит пароль существующей базы. + Нужно пересоздать данные PostgreSQL: + ```bash + cd /Volume1/DockerYAML/mix + docker-compose down + rm -rf /Volume1/DockerAppsData/mixapp/postgres + docker-compose up -d --build + ``` + ⚠️ **Это удалит все данные в БД!** + +### Генерация SECRET_KEY: +```bash +python3 -c "import secrets; print(secrets.token_urlsafe(64))" +``` + +## Шаг 4: Исправление прав entrypoint.sh и файлов проекта + +```bash +# Конвертируем из Windows формата (CRLF -> LF) +cd /Volume1/DockerAppsData/mixapp/app/myproject/docker +sed -i 's/\r$//' entrypoint.sh +chmod +x entrypoint.sh + +# Убедитесь, что весь проект принадлежит UID 1000 (appuser внутри контейнера) +cd /Volume1/DockerAppsData/mixapp/app +chown -R 1000:1000 myproject +chmod -R u+rwX myproject +``` + +## Шаг 5: Сборка и запуск + +```bash +cd /Volume1/DockerYAML/mix + +# Запускаем в фоновом режиме (автоматически соберет образы, используя пути из yml) +docker-compose up -d --build + +# Проверяем статус +docker-compose ps + +# Смотрим логи +docker-compose logs -f +``` + +## Шаг 6: Первичная настройка + +При первом запуске автоматически: +1. Создаётся база данных PostgreSQL +2. Применяются миграции Django +3. Создаётся суперпользователь: `slamfromm@gmail.com` / `GKh^768&T9` +4. Собираются статические файлы + +### Проверка работоспособности: +```bash +# Проверяем что все контейнеры работают +docker-compose ps + +# Должны быть в статусе "Up": +# - mix_postgres +# - mix_redis +# - mix_web +# - mix_celery_worker +# - mix_celery_beat +``` + +## Шаг 7: Настройка Nginx (на NAS или внешний) + +### Пример конфигурации nginx: + +```nginx +# Upstream для Django +upstream mix_django { + server 127.0.0.1:8000; +} + +# HTTP -> HTTPS редирект +server { + listen 80; + server_name mix.smaa.by *.mix.smaa.by; + return 301 https://$host$request_uri; +} + +# HTTPS сервер +server { + listen 443 ssl http2; + server_name mix.smaa.by *.mix.smaa.by; + + # SSL сертификаты (Let's Encrypt или свои) + ssl_certificate /path/to/fullchain.pem; + ssl_certificate_key /path/to/privkey.pem; + + # Безопасность + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256; + ssl_prefer_server_ciphers off; + + # Лимиты + client_max_body_size 50M; + + # Статические файлы + location /static/ { + alias /Volume1/DockerAppsData/mixapp/static/; + expires 30d; + add_header Cache-Control "public, immutable"; + } + + # Медиа файлы + location /media/ { + alias /Volume1/DockerAppsData/mixapp/media/; + expires 7d; + add_header Cache-Control "public"; + } + + # Django приложение + location / { + proxy_pass http://mix_django; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + # WebSocket support (если понадобится) + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + # Таймауты + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + } +} +``` + +## Создание тенантов (магазинов) + +После запуска системы, войдите в админку `https://mix.smaa.by/admin/` и создайте: + +1. **Client (Тенант)** - новый магазин +2. **Domain** - привяжите домен, например `shop1.mix.smaa.by` + +### Через Django shell: +```bash +docker-compose exec web python manage.py shell +``` + +```python +from tenants.models import Client, Domain + +# Создаём тенант +tenant = Client( + schema_name='shop1', + name='Магазин 1', +) +tenant.save() + +# Привязываем домен +domain = Domain( + domain='shop1.mix.smaa.by', + tenant=tenant, + is_primary=True +) +domain.save() +``` + +## Полезные команды + +```bash +# Переходим в папку с docker-compose.yml +cd /Volume1/DockerYAML/mix + +# Перезапуск всех контейнеров +docker-compose restart + +# Перезапуск только web +docker-compose restart web + +# Просмотр логов конкретного сервиса +docker-compose logs -f web +docker-compose logs -f celery-worker + +# Выполнение команд Django +docker-compose exec web python manage.py shell +docker-compose exec web python manage.py createsuperuser +docker-compose exec web python manage.py migrate_schemas --shared + +# Остановка +docker-compose down + +# Остановка с удалением volumes (ОСТОРОЖНО - удалит данные!) +docker-compose down -v +``` + +## Резервное копирование + +### База данных: +```bash +# Создание бэкапа +docker-compose exec db pg_dump -U postgres inventory_db > backup_$(date +%Y%m%d).sql + +# Восстановление +cat backup.sql | docker-compose exec -T db psql -U postgres inventory_db +``` + +### Медиа файлы: +```bash +# Бэкап медиа +tar -czvf media_backup_$(date +%Y%m%d).tar.gz /Volume1/DockerAppsData/mixapp/media/ +``` + +## Обновление приложения + +```bash +cd /Volume1/DockerYAML/mix + +# Остановить контейнеры +docker-compose down + +# Обновить код в /Volume1/DockerAppsData/mixapp/app/ +# (скопировать новые файлы myproject/, requirements.txt, docker/) + +# ⚠️ КРИТИЧЕСКИ ВАЖНО: После КАЖДОГО обновления кода настроить права доступа! +cd /Volume1/DockerAppsData/mixapp/app +chown -R 1000:1000 myproject +chmod -R u+rwX myproject + +# Вернуться в папку с docker-compose.yml +cd /Volume1/DockerYAML/mix + +# Пересобрать образы +docker-compose build --no-cache + +# Запустить +docker-compose up -d +``` + +**⚠️ ВАЖНО:** Если после обновления кода контейнеры не запускаются или тенанты недоступны (404), +первым делом проверьте права доступа командами выше! + +## Мониторинг + +```bash +# Статус контейнеров +docker-compose ps + +# Использование ресурсов +docker stats + +# Логи в реальном времени +docker-compose logs -f --tail=100 +``` + +## Возможные проблемы + +### 1. Ошибка "permission denied" для entrypoint.sh +```bash +sed -i 's/\r$//' entrypoint.sh +chmod +x entrypoint.sh +``` + +### 2. PostgreSQL не запускается +```bash +# Проверьте логи +docker-compose logs db + +# Возможно нужны права на директорию +sudo chown -R 999:999 /Volume1/DockerAppsData/mixapp/postgres +``` + +### 3. Celery не подключается к Redis +```bash +# Проверьте что Redis запущен +docker-compose logs redis + +# Проверьте сеть +docker-compose exec web ping redis +``` + +### 4. Статические файлы не отображаются +```bash +# Пересоберите статику +docker-compose exec web python manage.py collectstatic --noinput + +# Проверьте права +sudo chown -R 1000:1000 /Volume1/DockerAppsData/mixapp/static +``` + +### 5. Ошибка "password authentication failed for user postgres" + +**Причина:** `DB_PASSWORD` и `POSTGRES_PASSWORD` в `.env.docker` не совпадают, или в `docker-compose.yml` у сервиса `db` есть блок `environment` с дефолтными значениями `${DB_PASSWORD:-postgres}`. + +**Решение:** +1. Откройте `/Volume1/DockerAppsData/mixapp/app/myproject/docker/.env.docker` +2. Убедитесь, что `DB_PASSWORD` и `POSTGRES_PASSWORD` **ОДИНАКОВЫЕ** +3. Проверьте `docker-compose.yml` — у сервиса `db` должно быть только `env_file`, **БЕЗ блока `environment`**: + ```yaml + db: + image: postgres:15-alpine + env_file: + - /Volume1/DockerAppsData/mixapp/app/myproject/docker/.env.docker + # НЕ ДОЛЖНО БЫТЬ: + # environment: + # - POSTGRES_PASSWORD=${DB_PASSWORD:-postgres} + ``` +4. Пересоздайте базу данных: + ```bash + cd /Volume1/DockerYAML/mix + docker-compose down + rm -rf /Volume1/DockerAppsData/mixapp/postgres + docker-compose up -d --build + ``` +5. Проверьте, что пароли совпадают внутри контейнера: + ```bash + docker exec -it mix_postgres env | grep -E 'POSTGRES_PASSWORD|DB_PASSWORD' + ``` + Оба должны показывать одинаковое значение. + +### 6. Ошибка "Permission denied" для /app/manage.py + +**Причина:** Файлы проекта на хосте принадлежат не тому пользователю (не UID 1000). + +**Решение:** +```bash +cd /Volume1/DockerAppsData/mixapp/app +chown -R 1000:1000 myproject +chmod -R u+rwX myproject + +cd /Volume1/DockerYAML/mix +docker-compose restart web celery-worker celery-beat +``` + +### 7. Новый тенант создан, но его поддомен возвращает HTTP 404 + +**Причина:** Чаще всего — контейнер `web` постоянно перезапускается из-за `Permission denied` на `/app/manage.py`, и Django не успевает запуститься. + +**Диагностика:** + +1. Проверьте, что домен создан в базе: + ```bash + docker exec -it mix_web python manage.py shell + ``` + ```python + from tenants.models import Client, Domain + for domain in Domain.objects.all(): + print(f"Domain: {domain.domain}, Tenant: {domain.tenant.schema_name}") + ``` + Если домен есть — проблема не в базе. + +2. Посмотрите логи контейнера: + ```bash + docker logs -f mix_web + ``` + + Если видите множество повторяющихся сообщений: + ``` + python: can't open file '/app/manage.py': [Errno 13] Permission denied + Waiting for PostgreSQL... + ``` + + Это значит, что контейнер падает и перезапускается. + +**Решение:** +```bash +cd /Volume1/DockerAppsData/mixapp/app +chown -R 1000:1000 myproject +chmod -R u+rwX myproject + +cd /Volume1/DockerYAML/mix +docker-compose restart web celery-worker celery-beat +``` + +После этого контейнер перестанет падать, Django запустится, и поддомен тенанта станет доступен. diff --git a/ИНСТРУКЦИЯ_ОБНОВЛЕНИЕ.md b/ИНСТРУКЦИЯ_ОБНОВЛЕНИЕ.md new file mode 100644 index 0000000..b6c215d --- /dev/null +++ b/ИНСТРУКЦИЯ_ОБНОВЛЕНИЕ.md @@ -0,0 +1,130 @@ +# ИНСТРУКЦИЯ ПО ОБНОВЛЕНИЮ ПРОЕКТА + +В связи с реструктуризацией проекта (перенос конфигов внутрь `myproject`), процедура обновления изменилась. + +## 1. Подготовка файлов + +Скопируйте обновленную папку `myproject` на сервер. +Она должна заменить (или обновить) текущую папку `.../app/myproject` на сервере. + +> **ВАЖНО:** +> Папки с данными (`postgres`, `redis`) и медиа-файлами (`media`, `static`) теперь живут: +> - База и Redis: Внутри `myproject/postgres` и `myproject/redis` (если вы ставили с нуля по новой схеме). +> - Медиа и Статика: На уровень выше, в папке `app/media` и `app/static`. +> +> **При копировании кода НЕ ЗАТРИТЕ папку `postgres` внутри `myproject`, если она там есть!** +> Лучше всего копировать с помощью `rsync` или заменять только файлы кода, не трогая папки данных. + +## 2. Настройка прав доступа + +**⚠️ КРИТИЧЕСКИ ВАЖНО:** После КАЖДОГО копирования файлов на сервер ОБЯЗАТЕЛЬНО настраивайте права доступа! + +Выполните следующие команды (путь может отличаться): + +```bash +# Установить владельца для всех файлов проекта (UID 1000 = пользователь appuser внутри контейнера) +chown -R 1000:1000 /Volume1/DockerAppsData/mixapp/app/myproject + +# Установить права доступа +chmod -R u+rwX /Volume1/DockerAppsData/mixapp/app/myproject +``` + +> **Почему это нужно?** +> Docker-контейнер работает от пользователя с UID 1000 (appuser). Если файлы принадлежат другому пользователю, +> могут возникнуть проблемы с доступом к файлам, записью логов, созданием медиа-файлов и т.д. +> +> **Признаки проблемы:** +> - Ошибка `python: can't open file '/app/manage.py': [Errno 13] Permission denied` +> - Контейнер `web` постоянно перезапускается (crash loop) +> - Новые поддомены тенантов возвращают 404 (контейнер не успевает запуститься) +> +> **⚠️ ВАЖНО:** Это нужно делать после КАЖДОГО обновления кода на сервере! + +## 3. Запуск обновления + +Весь запуск теперь производится из папки, где лежит `docker-compose.yml`. + +1. Зайдите в папку docker (на сервере это `/Volume1/DockerYAML/mix`): + ```bash + cd /Volume1/DockerYAML/mix + ``` + +2. Остановите текущие контейнеры (если нужно): + ```bash + docker-compose down + ``` + +3. Соберите и запустите контейнеры: + ```bash + docker-compose up -d --build + ``` + +## 4. Проверка + +Посмотрите статус контейнеров: +```bash +docker-compose ps +``` +Все должны быть `Up (healthy)`. + +## 5. Полезные команды + +**Все команды выполняются из `/Volume1/DockerYAML/mix`** (где лежит `docker-compose.yml`): + +```bash +cd /Volume1/DockerYAML/mix +``` + +**Посмотреть логи веб-сервера:** +```bash +docker-compose logs -f web +``` + +**Проверить переменные окружения внутри контейнера:** +```bash +# Для PostgreSQL +docker exec -it mix_postgres env | grep -E 'POSTGRES|DB_' + +# Для Django +docker exec -it mix_web env | grep -E 'DB_|SECRET' +``` + +**Принудительно перезапустить базу (с удалением данных!):** +Если нужно сбросить базу полностью: +```bash +docker-compose down +rm -rf /Volume1/DockerAppsData/mixapp/postgres +docker-compose up -d --build +``` +⚠️ **Это удалит все данные в БД!** + +## 6. Возможные проблемы + +### Ошибка "password authentication failed for user postgres" + +**Причина:** Пароли `DB_PASSWORD` и `POSTGRES_PASSWORD` в `.env.docker` не совпадают. + +**Решение:** +1. Откройте `/Volume1/DockerAppsData/mixapp/app/myproject/docker/.env.docker` +2. Убедитесь, что `DB_PASSWORD` и `POSTGRES_PASSWORD` **ОДИНАКОВЫЕ** +3. Пересоздайте базу: + ```bash + cd /Volume1/DockerYAML/mix + docker-compose down + rm -rf /Volume1/DockerAppsData/mixapp/postgres + docker-compose up -d --build + ``` + +### Ошибка "Permission denied" для /app/manage.py + +**Причина:** Файлы проекта принадлежат не UID 1000. + +**Решение:** +```bash +cd /Volume1/DockerAppsData/mixapp/app +chown -R 1000:1000 myproject +chmod -R u+rwX myproject + +cd /Volume1/DockerYAML/mix +docker-compose restart web celery-worker celery-beat +```