Variables de entorno
Nunca versionar secretos
Los archivos .env no se suben al repositorio. Solo se versionan los .env.example con valores de ejemplo. En producción los valores se cargan en Environment de Dokploy.
ganadero-api
Resumen para Dokploy
| Tipo | Variables |
|---|---|
| Obligatorias | DATABASE_URL, JWT_ACCESS_SECRET, WEB_ORIGIN |
| Opcionales (tienen valor por defecto) | WEB_URL, MAIL_DRIVER (console), MAIL_FROM, SMTP_HOST, SMTP_PORT, SMTP_SECURE, SMTP_USER, SMTP_PASSWORD, TRUST_PROXY_HOPS (1), LOG_LEVEL, PORT, JWT_ACCESS_TTL_SECONDS, REFRESH_TTL_DAYS, COOKIE_SAMESITE, AUTH_RATE_LIMIT_MAX, AUTH_RATE_LIMIT_WINDOW_SECONDS, INVITATIONS_PER_HOUR, INVITATIONS_PER_DAY, INVITATIONS_NEW_ORG_LIMIT, SESSION_CACHE_TTL_SECONDS, COSTING_WORKER_CONCURRENCY, ENGINE_WORKERS, ENGINE_TIMEOUT_SECONDS, SWAGGER_ENABLED, IMAGE_TAG |
| Solo en la opción avanzada de dos roles | DATABASE_MIGRATION_URL |
| Ya no se usan en producción | POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DB, APP_DB_PASSWORD |
Base de datos y arranque
| Variable | Descripción |
|---|---|
NODE_ENV, PORT, LOG_LEVEL | Entorno, puerto (3000 por defecto) y nivel de log. |
DATABASE_URL | Única conexión en producción, compartida por migrate y la API: la del usuario que creó la base en Dokploy, postgres://<usuario>:<clave>@<nombre-interno-del-postgres>:5432/<base>. No requiere SQL manual: migrate crea el rol sin privilegios ganadero_app y la API ejecuta cada transacción como ese rol (ver Despliegue con Dokploy). Caracteres especiales del usuario o la clave codificados (@ → %40, : → %3A, / → %2F). Obligatoria. |
DATABASE_MIGRATION_URL | Opcional: solo en desarrollo y en la opción avanzada de dos roles. Conexión del dueño de la base para migrate mientras la API usa ganadero_app. Vacía o ausente: migrate usa DATABASE_URL. |
DATABASE_SEED_URL | Solo en desarrollo: superusuario local para pnpm db:seed. Nunca en producción. |
IMAGE_TAG | Etiqueta de la imagen. La API no publica ningún puerto en el host: Traefik la alcanza por la red dokploy-network. |
Sesión y seguridad
| Variable | Descripción |
|---|---|
JWT_ACCESS_SECRET | Secreto de los tokens de acceso (mínimo 32 caracteres). Obligatoria. Genere uno propio: openssl rand -base64 48. |
JWT_ACCESS_TTL_SECONDS | Vigencia del token de acceso (900 s por defecto). |
REFRESH_TTL_DAYS | Vigencia del token de refresco (30 días por defecto). |
COOKIE_SECURE, COOKIE_SAMESITE | Atributos de la cookie de sesión. En producción COOKIE_SECURE es siempre true. |
WEB_ORIGIN | Origen permitido del frontend (CORS con credenciales). Obligatoria. |
AUTH_RATE_LIMIT_MAX, AUTH_RATE_LIMIT_WINDOW_SECONDS | Límite de peticiones a /auth/* por IP (10 por 60 s por defecto). |
TRUST_PROXY_HOPS | Cuántos proxies hay delante de la API (0 en local; 1 detrás de Traefik, valor por defecto del Compose de producción). |
SESSION_CACHE_TTL_SECONDS | Segundos (0 a 30, por defecto 30) del caché en memoria con que se contrasta el token con los permisos vigentes. 0 desactiva el caché. Con varias réplicas, un cambio de rol puede tardar hasta este valor en verse en las otras réplicas. |
SWAGGER_ENABLED | Habilita la documentación OpenAPI (/docs). Se recomienda desactivarla en producción. |
Correo (invitaciones y restablecimiento de contraseña)
| Variable | Descripción |
|---|---|
MAIL_DRIVER | console (valor por defecto) o smtp. Con console la API arranca igual y registra el aviso correos deshabilitados (MAIL_DRIVER=console): en desarrollo el mensaje se ve en el log, pero en producción nunca se registra el cuerpo, así que nadie recibe el enlace. Para enviar correos de verdad use smtp. |
MAIL_FROM | Remitente, p. ej. Software Ganadero <no-reply@tudominio.com>. Obligatoria con smtp. |
SMTP_HOST, SMTP_PORT | Servidor SMTP (SMTP_HOST obligatoria con smtp; puerto típico 587). |
SMTP_USER, SMTP_PASSWORD | Credenciales; deben definirse juntas. |
SMTP_SECURE | TLS implícito. Por defecto solo en el puerto 465 (el 587 usa STARTTLS). |
WEB_URL | Base de los enlaces de los correos. Por defecto, WEB_ORIGIN. Puede incluir un subpath. |
Cuotas de invitaciones (anti-relay)
Por organización; superarlas responde 429. Revocar o reinvitar no devuelve cupo.
| Variable | Defecto | Efecto |
|---|---|---|
INVITATIONS_PER_HOUR | 20 | Ventana deslizante de 1 hora. |
INVITATIONS_PER_DAY | 100 | Ventana deslizante de 24 horas. |
INVITATIONS_NEW_ORG_LIMIT | 5 | Tope total mientras la organización tenga menos de 24 horas. |
ganadero-web
La imagen es la misma para todos los entornos; estas variables se inyectan al arrancar el contenedor.
| Variable | Descripción |
|---|---|
API_URL | URL base de la API (obligatoria en producción), p. ej. https://api.midominio.com/api. Confirme con su enrutamiento si lleva o no un prefijo (la API publica sus rutas en la raíz). |
MANUALES_URL | URL de este manual (opcional). Si se define, la aplicación descarga las plantillas desde <MANUALES_URL>/plantillas/. |
CSP_MODO | enforce (por defecto) o report-only. |
CSP_REPORT_URI | Colector de informes CSP (vacío = sin informes). |
CSP_CONNECT_SRC_EXTRA | Orígenes adicionales permitidos para conexiones, separados por espacio. |
manual-ganadero
| Variable | Descripción |
|---|---|
MANUAL_AUTH_ENABLED | true protege el manual con HTTP Basic Auth de nginx. |
MANUAL_AUTH_USER, MANUAL_AUTH_PASSWORD | Credenciales de ese acceso, obligatorias si está activo (si faltan, el contenedor no arranca; el usuario no puede contener :). Definirlas solo en el entorno de despliegue. |
Seguridad
La validación ocurre en nginx, del lado del servidor: la clave se guarda como hash en /etc/nginx/.htpasswd y nunca se envía al navegador. Basic Auth transmite las credenciales en cada petición, así que el dominio debe servirse siempre por HTTPS (Traefik en Dokploy lo gestiona con Let's Encrypt).