3. Despliegue del ERP¶
3.1. Clonar repositorio¶
cd /opt
git clone <URL_REPO> tienda
cd /opt/tienda
# Crear usuario de sistema dedicado
useradd -r -d /opt/tienda -s /bin/bash tienda
chown -R tienda:tienda /opt/tienda
3.2. Instalar dependencias¶
Dependencias clave verificadas:
| Paquete | Propósito |
|---|---|
Django==5.1.4 |
Framework |
channels==4.3.2, daphne==4.2.1 |
WebSocket / ASGI |
psycopg2-binary==2.9.9 |
Driver Postgres |
WeasyPrint==66.0 |
Generación PDF |
Pillow>=10.4.0 |
Imágenes |
celery[redis]==5.4.0, django-celery-beat==2.7.0 |
Tareas async + cron |
djangorestframework==3.15.2 |
API REST (tienda externa, opcional) |
lxml==5.3.0 |
Parser XML rápido |
signxml==4.0.4 |
Firma XAdES-BES |
cryptography>=43 |
Manejo de claves/cert |
qrcode==7.4.2 |
QR timbre fiscal |
requests==2.33.1 |
HTTP cliente DGII |
pytesseract>=0.3.13, pdfplumber>=0.11.0 |
OCR factura proveedor |
Verificar:
python -c "import signxml, lxml, cryptography, qrcode; print('OK firma')"
python -c "import pdfplumber, pytesseract; print('OK OCR')"
3.3. Variables de entorno¶
Crear /opt/tienda/.env con permisos restrictivos:
Contenido (estructura — reemplazar valores reales):
# Django
DJANGO_SETTINGS_MODULE=tienda.settings
DJANGO_SECRET_KEY=<48+ caracteres random>
DJANGO_ENV=production
DJANGO_DEBUG=0
DJANGO_ALLOWED_HOSTS=erp.tuempresa.com.do,www.erp.tuempresa.com.do,127.0.0.1
DJANGO_CSRF_TRUSTED_ORIGINS=https://erp.tuempresa.com.do
# Cookies/Headers seguros
DJANGO_SECURE_SSL_REDIRECT=1
DJANGO_HSTS_SECONDS=31536000
DJANGO_CSRF_COOKIE_SECURE=1
DJANGO_SESSION_COOKIE_SECURE=1
# Base de datos
DB_ENGINE=django.db.backends.postgresql
DB_NAME=tienda_db
DB_USER=tienda
DB_PASSWORD=<password fuerte>
DB_HOST=127.0.0.1
DB_PORT=5432
# Redis / Celery
REDIS_URL=redis://:<password_redis>@127.0.0.1:6379/0
CELERY_BROKER_URL=redis://:<password_redis>@127.0.0.1:6379/1
CELERY_RESULT_BACKEND=redis://:<password_redis>@127.0.0.1:6379/2
# DGII e-CF
DGII_PUBLIC_BASE_URL=https://erp.tuempresa.com.do
DGII_SOFTWARE_NAME=Artistica Garcia
DGII_SOFTWARE_VERSION_PUBLIC=2.0
DGII_AMBIENTE_DEFAULT=CERT
DGII_CERTIFICADO_P12=/opt/tienda/secrets/ccpsd_RNC.p12
DGII_CERTIFICADO_PASSWORD=<password p12>
DGII_RNC_EMISOR=130768021
DGII_CADENA_CCPSD=/opt/tienda/secrets/CCPSD_cadena.crt
# Endpoints DGII
DGII_API_BASE_CERT=https://ecf.dgii.gov.do/CerteCF
DGII_API_BASE_PROD=https://ecf.dgii.gov.do/eCF
# Seguridad bearer/mTLS
ECF_BEARER_REQUIRED=1
ECF_MTLS_REQUIRED=0
ECF_VALIDATE_XSD_BEFORE_SEND=1
# API tienda virtual (opcional)
INTERNAL_API_TOKEN=<token random 48+ chars>
Buena práctica: gestionar .env con git-crypt, sops o Ansible Vault. NUNCA versionarlo plano.
3.4. Migraciones, collectstatic, superusuario¶
sudo -u tienda bash -c 'cd /opt/tienda && set -a && . .env && set +a && source .venv/bin/activate && \
python manage.py migrate && \
python manage.py collectstatic --noinput && \
python manage.py createsuperuser'
El comando
set -a; . .env; set +aes obligatorio al corrermanage.pydesde SSH directo. Sin él, Django usa los defaults (SQLite) y la migración se aplica al archivo equivocado.
3.5. Gunicorn (HTTP) + Daphne (WebSocket) con systemd¶
/etc/systemd/system/tienda.service (Gunicorn → puerto 8000):
[Unit]
Description=Tienda ERP (Gunicorn HTTP)
After=network.target postgresql.service redis-server.service
[Service]
User=tienda
Group=tienda
WorkingDirectory=/opt/tienda
EnvironmentFile=/opt/tienda/.env
ExecStart=/opt/tienda/.venv/bin/gunicorn tienda.wsgi:application \
--bind 127.0.0.1:8000 \
--workers 4 \
--threads 2 \
--timeout 60 \
--access-logfile /opt/tienda/logs/gunicorn-access.log \
--error-logfile /opt/tienda/logs/gunicorn-error.log
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
/etc/systemd/system/tienda-daphne.service (WebSocket → puerto 8002):
[Unit]
Description=Tienda ERP (Daphne WebSocket)
After=network.target redis-server.service
[Service]
User=tienda
Group=tienda
WorkingDirectory=/opt/tienda
EnvironmentFile=/opt/tienda/.env
ExecStart=/opt/tienda/.venv/bin/daphne -b 127.0.0.1 -p 8002 tienda.asgi:application
Restart=on-failure
[Install]
WantedBy=multi-user.target
Activar:
systemctl daemon-reload
systemctl enable --now tienda.service tienda-daphne.service
systemctl status tienda tienda-daphne
Validar: curl -I https://erp.tuempresa.com.do/ debe devolver 200/302 desde Gunicorn.