diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..a8522da --- /dev/null +++ b/.dockerignore @@ -0,0 +1,31 @@ +# Git +.git +.gitignore + +# Python +__pycache__ +*.pyc +*.pyo +*.pyd +.Python +env/ +venv/ +.venv/ + +# Node.js +node_modules/ +frontend-assembly/node_modules/ +npm-debug.log + +# Django +db.sqlite3 +media/ +staticfiles/ +public/static/static_collected/ + +# IDE +.idea/ +.vscode/ + +# Env +.env diff --git a/.env.example b/.env.example index 5ab72c4..3868361 100644 --- a/.env.example +++ b/.env.example @@ -5,3 +5,7 @@ DEBUG=True SECRET_KEY=change-me-in-production ALLOWED_HOSTS=localhost,127.0.0.1,0.0.0.0 + +# Доверенные источники для CSRF (важно для Docker/Nginx) +# Укажите здесь URL, по которому вы заходите на сайт (с протоколом и портом) +CSRF_TRUSTED_ORIGINS=http://localhost:8000,http://127.0.0.1:8000,http://0.0.0.0:8000 diff --git a/Dockerfile b/Dockerfile index 497352a..9e7779b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,22 @@ +# --- Stage 1: Сборка фронтенда (CodeMirror) --- +FROM node:20-slim as frontend-builder + +WORKDIR /app/frontend + +# Копируем файлы зависимостей +COPY frontend-assembly/package.json frontend-assembly/package-lock.json ./ + +# Устанавливаем зависимости (включая devDependencies для сборки) +RUN npm ci + +# Копируем исходники +COPY frontend-assembly/ ./ + +# Собираем бандл через npm script +RUN npm run build + + +# --- Stage 2: Сборка бэкенда (Django) --- FROM python:3.13-slim # Настройки Python @@ -22,6 +41,12 @@ RUN useradd -m -r appuser # Копируем код проекта COPY . /app/ +# Создаем папку для данных и статики, чтобы у appuser были права +RUN mkdir -p /app/data /app/public/static_collected + +# Копируем собранный фронтенд из первого стейджа +COPY --from=frontend-builder /app/frontend/dist/editor.js /app/public/static/codemirror/editor.js + # Меняем владельца папки RUN chown -R appuser:appuser /app @@ -32,4 +57,4 @@ USER appuser EXPOSE 8000 # Команда запуска через Gunicorn -CMD ["gunicorn", "--bind", "0.0.0.0:8000", "etpgrf_site.wsgi"] +CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--chdir", "/app/etpgrf_site", "etpgrf_site.wsgi"] diff --git a/config/nginx/etpgrf--internal-nginx.conf b/config/nginx/etpgrf--internal-nginx.conf new file mode 100644 index 0000000..aaef23b --- /dev/null +++ b/config/nginx/etpgrf--internal-nginx.conf @@ -0,0 +1,53 @@ +user nginx; +worker_processes auto; +pid /var/run/nginx.pid; +include /etc/nginx/modules-enabled/*.conf; + +events { + worker_connections 768; +} + +http { + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + types_hash_max_size 2048; + + include /etc/nginx/mime.types; + default_type application/octet-stream; + + ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE + ssl_prefer_server_ciphers on; + + access_log /var/log/nginx/access.log; + error_log /var/log/nginx/error.log; + + gzip on; + gzip_disable "msie6"; + + # upstream для Gunicorn + upstream app_server { + server web:8000; + } + + server { + listen 80; + server_name localhost; + + location / { + proxy_pass http://app_server; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Host $host; + proxy_redirect off; + } + + location /static/ { + alias /app/public/static_collected/; + } + + location /media/ { + alias /app/public/media/; + } + } +} diff --git a/docker-compose.yml b/docker-compose.yml index 6416e65..39bbb4a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,12 +3,26 @@ version: '3.8' services: web: build: . - # Путь к manage.py - command: python etpgrf_site/manage.py runserver 0.0.0.0:8000 + # Команда запуска (Gunicorn) уже в Dockerfile + volumes: - - .:/app - ports: - - "8000:8000" + # Монтируем папку с базой данных + - ./data:/app/data + # Монтируем статику в именованный том, чтобы Nginx мог её читать + - static_volume:/app/public/static_collected + env_file: - # Подключаем файл .env с переменными окружения (секретами) - .env + + nginx: + image: nginx:1.25-alpine + volumes: + - ./config/nginx/etpgrf--internal-nginx.conf:/etc/nginx/nginx.conf:ro + - static_volume:/app/public/static_collected + ports: + - "8000:80" # Слушаем 8000 снаружи, проксируем на 80 внутри + depends_on: + - web + +volumes: + static_volume: diff --git a/frontend-assembly/package.json b/frontend-assembly/package.json index 62eca93..2a52a8b 100644 --- a/frontend-assembly/package.json +++ b/frontend-assembly/package.json @@ -1,10 +1,12 @@ { - "name": "tmp-frontend", + "name": "frontend-assembly", "version": "1.0.0", - "description": "", + "description": "CodeMirror build for ETPGRF", "main": "index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "build": "esbuild src/editor.js --bundle --format=esm --outfile=dist/editor.js --minify", + "dev": "esbuild src/editor.js --bundle --format=esm --outfile=../public/static/codemirror/editor.js --minify", + "watch": "esbuild src/editor.js --bundle --format=esm --outfile=../public/static/codemirror/editor.js --watch" }, "keywords": [], "author": "", diff --git a/pyproject.toml b/pyproject.toml index 2aa881b..de93cd2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,9 +12,9 @@ django = "^6.0" gunicorn = "^23.0.0" python-dotenv = "^1.2.1" etpgrf = "^0.1.3" -# lxml = "^5.1" # etpgrf подтянет как зависимость -# beautifulsoup4 = "^4.12" # etpgrf подтянет как зависимость -# regex = "^2023.12" # и это тоже +# lxml = "^5.1" # etpgrf подтянет как зависимость +# regex = "^2023.12" # etpgrf подтянет как зависимость +# beautifulsoup4 = "^4.10.0" # etpgrf подтянет как зависимость [build-system] requires = ["poetry-core"]