From b43b888f53058c30bb3a09d9f5cdc7fd71abb992 Mon Sep 17 00:00:00 2001 From: adevopg Date: Sun, 12 Jul 2026 16:16:29 +0000 Subject: [PATCH] =?UTF-8?q?A=C3=B1ade=20README=20de=20despliegue=20y=20sop?= =?UTF-8?q?orte=20Docker?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - README.md: guía de instalación (venv, .env, migraciones, gunicorn) y notas de producción/seguridad - Dockerfile: imagen Python 3.14 con deps de sistema para mysqlclient/Pillow - docker-compose.yml: servicios web (Django+gunicorn) y db (MySQL 8.4) con las 4 BBDD - docker/entrypoint.sh: espera a MySQL, migra, collectstatic y arranca gunicorn - docker/mysql-init.sql: crea django_wow + bases acore_* - .dockerignore y gunicorn en requirements Co-Authored-By: Claude Opus 4.8 (1M context) --- .dockerignore | 15 ++++++ Dockerfile | 32 ++++++++++++ README.md | 115 ++++++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 44 ++++++++++++++++ docker/entrypoint.sh | 22 ++++++++ docker/mysql-init.sql | 14 +++++ requirements.txt | 1 + 7 files changed, 243 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 README.md create mode 100644 docker-compose.yml create mode 100755 docker/entrypoint.sh create mode 100644 docker/mysql-init.sql diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..11e1334 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,15 @@ +.git +.gitignore +.venv +venv +.env +*.pyc +__pycache__/ +**/__pycache__/ +staticfiles/ +db.sqlite3 +*.sqlite3 +.dockerignore +Dockerfile +docker-compose.yml +README.md diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..05bdadd --- /dev/null +++ b/Dockerfile @@ -0,0 +1,32 @@ +# Nova WoW - imagen del portal Django +FROM python:3.14-slim + +ENV PYTHONDONTWRITEBYTECODE=1 \ + PYTHONUNBUFFERED=1 + +# Dependencias de sistema para mysqlclient (compilación + runtime) y Pillow +RUN apt-get update && apt-get install -y --no-install-recommends \ + build-essential \ + pkg-config \ + default-libmysqlclient-dev \ + libgmp-dev libmpfr-dev libmpc-dev \ + libjpeg-dev zlib1g-dev \ + netcat-openbsd \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /app + +# Instalar dependencias Python primero (mejor cache) +COPY requirements.txt . +RUN pip install --upgrade pip && pip install --no-cache-dir -r requirements.txt + +# Copiar el código +COPY . . + +# Entrypoint +RUN chmod +x /app/docker/entrypoint.sh + +EXPOSE 8000 + +ENTRYPOINT ["/app/docker/entrypoint.sh"] +CMD ["gunicorn", "novawow.wsgi:application", "--bind", "0.0.0.0:8000", "--workers", "4"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..8165cd7 --- /dev/null +++ b/README.md @@ -0,0 +1,115 @@ +# Nova WoW + +Portal web (Django) para un servidor de World of Warcraft basado en AzerothCore. + +- **Python:** 3.14 +- **Framework:** Django 6.0 +- **Base de datos:** MySQL (4 bases: la del portal `django_wow` + las de AzerothCore `acore_auth`, `acore_characters`, `acore_world`) + +--- + +## 1. Requisitos + +- Python 3.14 y `venv` +- MySQL/MariaDB accesible +- Librerías de sistema para compilar algunas dependencias: + +```bash +sudo apt install python3.14-venv python3.14-dev build-essential pkg-config \ + default-libmysqlclient-dev libgmp-dev libmpfr-dev libmpc-dev libjpeg-dev zlib1g-dev +``` + +--- + +## 2. Puesta en marcha (desarrollo) + +```bash +git clone https://git.nightspire.gg/Inna/NovaWoW.git +cd NovaWoW + +# Entorno virtual +python3 -m venv .venv +source .venv/bin/activate +pip install --upgrade pip +pip install -r requirements.txt + +# Variables de entorno +cp .env.example .env +# edita .env con tus credenciales reales (ver sección 3) + +# Migraciones y arranque +python manage.py migrate +python manage.py createsuperuser # opcional +python manage.py runserver +``` + +La app queda en http://127.0.0.1:8000 + +--- + +## 3. Configuración (`.env`) + +Toda la configuración sensible se lee de variables de entorno mediante +[python-dotenv](https://pypi.org/project/python-dotenv/). Copia `.env.example` +a `.env` y rellena los valores. **El `.env` no se versiona.** + +| Variable | Descripción | +|---|---| +| `DJANGO_SECRET_KEY` | Clave secreta de Django. Genera una nueva (ver abajo). | +| `DJANGO_DEBUG` | `True` en desarrollo, `False` en producción. | +| `DB_USER` / `DB_PASSWORD` | Credenciales MySQL (compartidas por las 4 BBDD). | +| `DB_HOST` / `DB_PORT` | Host y puerto de MySQL. | +| `DB_NAME_DEFAULT` | BD del portal (por defecto `django_wow`). | +| `DB_NAME_AUTH` / `DB_NAME_CHARACTERS` / `DB_NAME_WORLD` | BBDD de AzerothCore. | +| `AC_SOAP_*` | Conexión SOAP a AzerothCore (crear cuentas, etc.). | +| `SUMUP_*` / `STRIPE_*` | Pasarelas de pago. | +| `EMAIL_HOST_USER` / `EMAIL_HOST_PASSWORD` | SMTP de Gmail (App Password). | + +Generar una `SECRET_KEY` nueva: + +```bash +python -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())" +``` + +--- + +## 4. Producción + +```bash +# Recopilar estáticos +python manage.py collectstatic --noinput + +# Servir con gunicorn (4 workers) +gunicorn novawow.wsgi:application --bind 0.0.0.0:8000 --workers 4 +``` + +Recomendaciones: + +- `DJANGO_DEBUG=False` y una `DJANGO_SECRET_KEY` propia y secreta. +- Poner **Nginx** delante como proxy inverso y para servir `staticfiles/`. +- Revisar `ALLOWED_HOSTS` y `CSRF_TRUSTED_ORIGINS` en `novawow/settings.py`. + +--- + +## 5. Docker + +Alternativamente, se puede levantar todo con Docker (web + MySQL): + +```bash +cp .env.example .env # ajusta los secretos (no las variables DB_*, las fija compose) +docker compose up --build +``` + +- La web queda en http://127.0.0.1:8000 +- El servicio `db` crea automáticamente las 4 bases de datos. +- El `entrypoint` espera a MySQL, aplica migraciones y recopila estáticos antes de arrancar gunicorn. + +Ver `docker-compose.yml` y `Dockerfile` para los detalles. + +--- + +## 6. Notas de seguridad + +- Los secretos que estuvieron hardcodeados en el historial de git deben **rotarse** + (contraseña MySQL/SOAP, App Password de Gmail, claves de Stripe/SumUp). +- Nunca subas el archivo `.env` al repositorio. diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..3074e8f --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,44 @@ +services: + db: + image: mysql:8.4 + restart: unless-stopped + environment: + MYSQL_ROOT_PASSWORD: rootpass + MYSQL_DATABASE: django_wow + MYSQL_USER: novawow + MYSQL_PASSWORD: novawow_pass + volumes: + - db_data:/var/lib/mysql + - ./docker/mysql-init.sql:/docker-entrypoint-initdb.d/init.sql:ro + healthcheck: + test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-prootpass"] + interval: 5s + timeout: 5s + retries: 20 + + web: + build: . + restart: unless-stopped + # Secretos de la app (Stripe, SumUp, SOAP, email, SECRET_KEY...) desde .env + env_file: + - path: .env + required: false + # Las variables de BD las fija compose para apuntar al servicio 'db' + environment: + DJANGO_DEBUG: "False" + DB_HOST: db + DB_PORT: "3306" + DB_USER: novawow + DB_PASSWORD: novawow_pass + DB_NAME_DEFAULT: django_wow + DB_NAME_AUTH: acore_auth + DB_NAME_CHARACTERS: acore_characters + DB_NAME_WORLD: acore_world + ports: + - "8000:8000" + depends_on: + db: + condition: service_healthy + +volumes: + db_data: diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh new file mode 100755 index 0000000..0571939 --- /dev/null +++ b/docker/entrypoint.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +set -e + +# Espera a que MySQL esté disponible +if [ -n "$DB_HOST" ]; then + echo "Esperando a MySQL en $DB_HOST:${DB_PORT:-3306}..." + until nc -z "$DB_HOST" "${DB_PORT:-3306}"; do + sleep 1 + done + echo "MySQL disponible." +fi + +# Migraciones (solo la base 'default' del portal) +echo "Aplicando migraciones..." +python manage.py migrate --noinput + +# Estáticos +echo "Recopilando archivos estáticos..." +python manage.py collectstatic --noinput + +# Ejecuta el comando indicado (gunicorn por defecto) +exec "$@" diff --git a/docker/mysql-init.sql b/docker/mysql-init.sql new file mode 100644 index 0000000..af15fde --- /dev/null +++ b/docker/mysql-init.sql @@ -0,0 +1,14 @@ +-- Crea las bases de datos que necesita el portal. +-- La del portal (django_wow) y las de AzerothCore. +-- Las de AzerothCore quedan vacías; en un entorno real las provee el core del juego. +CREATE DATABASE IF NOT EXISTS `django_wow` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; +CREATE DATABASE IF NOT EXISTS `acore_auth` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; +CREATE DATABASE IF NOT EXISTS `acore_characters` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; +CREATE DATABASE IF NOT EXISTS `acore_world` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- Concede permisos al usuario de la aplicación sobre las 4 bases +GRANT ALL PRIVILEGES ON `django_wow`.* TO 'novawow'@'%'; +GRANT ALL PRIVILEGES ON `acore_auth`.* TO 'novawow'@'%'; +GRANT ALL PRIVILEGES ON `acore_characters`.* TO 'novawow'@'%'; +GRANT ALL PRIVILEGES ON `acore_world`.* TO 'novawow'@'%'; +FLUSH PRIVILEGES; diff --git a/requirements.txt b/requirements.txt index 2f51b1d..99b9e7b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,3 +14,4 @@ stripe==15.3.0 typing_extensions==4.16.0 urllib3==2.7.0 python-dotenv==1.2.2 +gunicorn==26.0.0