Files
octopus/myproject/docker/DEPLOY_NAS.md
Andrey Smakotin f5130a79fd Обновлена документация: добавлены предупреждения о правах доступа
- ИНСТРУКЦИЯ_ОБНОВЛЕНИЕ.md:
  * Усилено предупреждение о необходимости настройки прав после КАЖДОГО обновления
  * Добавлены признаки проблемы: crash loop контейнера, 404 на тенантах
  * Подчёркнута критичность выполнения chown/chmod

- DEPLOY_NAS.md:
  * Добавлены команды chown/chmod в раздел 'Обновление приложения'
  * Новый раздел 'Проблема 7': новый тенант возвращает 404
  * Пошаговая диагностика: проверка домена в БД и логов контейнера
  * Объяснение причины: контейнер падает из-за Permission denied

Теперь при проблемах после обновления кода пользователь сразу увидит,
что нужно проверить права доступа на файлы проекта.
2026-01-07 20:50:35 +03:00

15 KiB
Raw Blame History

Развёртывание на 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

# Подключаемся к NAS по SSH
ssh admin@<NAS_IP>

# Создаём директории
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)

# Из папки проекта на Windows
cd C:\Users\team_\Desktop\test_qwen

# Копируем код приложения в папку данных
scp -r myproject requirements.txt docker .dockerignore admin@<NAS_IP>:/Volume1/DockerAppsData/mixapp/app/

# Копируем docker-compose.yml в папку YAML
scp docker/docker-compose.yml admin@<NAS_IP>:/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: Настройка переменных окружения

# На NAS
cd /Volume1/DockerAppsData/mixapp/app/docker

# Редактируем .env.docker
nano .env.docker

ВАЖНО! Измените следующие значения:

# 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:

    cd /Volume1/DockerYAML/mix
    docker-compose down
    rm -rf /Volume1/DockerAppsData/mixapp/postgres
    docker-compose up -d --build
    

    ⚠️ Это удалит все данные в БД!

Генерация SECRET_KEY:

python3 -c "import secrets; print(secrets.token_urlsafe(64))"

Шаг 4: Исправление прав entrypoint.sh и файлов проекта

# Конвертируем из 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: Сборка и запуск

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. Собираются статические файлы

Проверка работоспособности:

# Проверяем что все контейнеры работают
docker-compose ps

# Должны быть в статусе "Up":
# - mix_postgres
# - mix_redis
# - mix_web
# - mix_celery_worker
# - mix_celery_beat

Шаг 7: Настройка Nginx (на NAS или внешний)

Пример конфигурации 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:

docker-compose exec web python manage.py shell
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()

Полезные команды

# Переходим в папку с 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

Резервное копирование

База данных:

# Создание бэкапа
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

Медиа файлы:

# Бэкап медиа
tar -czvf media_backup_$(date +%Y%m%d).tar.gz /Volume1/DockerAppsData/mixapp/media/

Обновление приложения

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), первым делом проверьте права доступа командами выше!

Мониторинг

# Статус контейнеров
docker-compose ps

# Использование ресурсов
docker stats

# Логи в реальном времени
docker-compose logs -f --tail=100

Возможные проблемы

1. Ошибка "permission denied" для entrypoint.sh

sed -i 's/\r$//' entrypoint.sh
chmod +x entrypoint.sh

2. PostgreSQL не запускается

# Проверьте логи
docker-compose logs db

# Возможно нужны права на директорию
sudo chown -R 999:999 /Volume1/DockerAppsData/mixapp/postgres

3. Celery не подключается к Redis

# Проверьте что Redis запущен
docker-compose logs redis

# Проверьте сеть
docker-compose exec web ping redis

4. Статические файлы не отображаются

# Пересоберите статику
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:
    db:
      image: postgres:15-alpine
      env_file:
        - /Volume1/DockerAppsData/mixapp/app/myproject/docker/.env.docker
      # НЕ ДОЛЖНО БЫТЬ:
      # environment:
      #   - POSTGRES_PASSWORD=${DB_PASSWORD:-postgres}
    
  4. Пересоздайте базу данных:
    cd /Volume1/DockerYAML/mix
    docker-compose down
    rm -rf /Volume1/DockerAppsData/mixapp/postgres
    docker-compose up -d --build
    
  5. Проверьте, что пароли совпадают внутри контейнера:
    docker exec -it mix_postgres env | grep -E 'POSTGRES_PASSWORD|DB_PASSWORD'
    
    Оба должны показывать одинаковое значение.

6. Ошибка "Permission denied" для /app/manage.py

Причина: Файлы проекта на хосте принадлежат не тому пользователю (не UID 1000).

Решение:

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. Проверьте, что домен создан в базе:

    docker exec -it mix_web python manage.py shell
    
    from tenants.models import Client, Domain
    for domain in Domain.objects.all():
        print(f"Domain: {domain.domain}, Tenant: {domain.tenant.schema_name}")
    

    Если домен есть — проблема не в базе.

  2. Посмотрите логи контейнера:

    docker logs -f mix_web
    

    Если видите множество повторяющихся сообщений:

    python: can't open file '/app/manage.py': [Errno 13] Permission denied
    Waiting for PostgreSQL...
    

    Это значит, что контейнер падает и перезапускается.

Решение:

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 запустится, и поддомен тенанта станет доступен.