# Развёртывание на 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 chown -R 1000:1000 /Volume1/DockerYAML/mix ``` ## Шаг 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=* 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 # Platform Admin (администратор платформы - создаётся автоматически) PLATFORM_ADMIN_EMAIL=admin@mix.smaa.by PLATFORM_ADMIN_PASSWORD=ваш-надёжный-пароль-минимум-16-символов PLATFORM_ADMIN_NAME=Platform 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. Собираются статические файлы 4. Создаётся public tenant 5. **Создаётся PlatformAdmin** из переменных `PLATFORM_ADMIN_*` в `.env.docker` ### Проверка работоспособности: ```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; } } ``` ## Создание тенантов (магазинов) **Рекомендуемый способ:** Через форму регистрации и активацию в админке. 1. Пользователь заполняет форму на `https://mix.smaa.by/register/` 2. PlatformAdmin входит в `https://mix.smaa.by/admin/` 3. В разделе "Заявки на регистрацию" нажимает "Активировать" При активации автоматически: - Создаётся тенант и домен - Применяются миграции - Создаётся владелец (CustomUser) - Инициализируются данные (склад, статусы и т.д.) - Отправляется email с ссылкой для установки пароля ### Архитектура пользователей | Модель | Schema | Доступ | |--------|--------|--------| | `PlatformAdmin` | public | Django Admin везде | | `CustomUser` | tenant | Только фронтенд | PlatformAdmin может войти в Django Admin любого тенанта для техподдержки. ## Полезные команды ```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 запустится, и поддомен тенанта станет доступен.