Configuración
Todo se configura en dos sitios, y conviene saber cuál es cuál.
Todo se configura en dos sitios, y conviene saber cuál es cuál:
- El
.envdel backend — lo que el sistema necesita para arrancar: base de datos, secretos, claves de servicios externos. Se toca con un editor y exige reiniciar. - El panel — lo que cambia el día a día: nombre de la tienda, datos fiscales, formas de pago, proveedor de IA. No exige reiniciar nada.
La regla es sencilla: si es un secreto, va en el .env. Todo lo demás,
en el panel. Hay una excepción: las claves de las pasarelas de pago también se
pueden poner en Ajustes → Pagos, y entonces se guardan en la base de datos
cifradas (tabla pcc_pasarela) y mandan sobre las del .env. Ninguna clave
viaja al navegador, salvo las públicas que las pasarelas están hechas para
enseñar.
Con Docker, el backend lee el .env entero que está junto a
docker-compose.yml, así que todas las variables de esta página funcionan igual
dentro y fuera de Docker. Allí algunas salen de otras: CORS_TIENDA y
STOREFRONT_URL salen de TIENDA_URL, CORS_PANEL de PANEL_URL y
PCC_BACKEND_URL de BACKEND_URL, y esas mandan sobre el mismo nombre escrito
en el .env.
La lista completa de variables, generada del código, está en referencia/variables-entorno.md. Aquí está lo que hace falta entender para decidir.
Lo mínimo para arrancar
Solo una variable es obligatoria:
DATABASE_URL=postgres://usuario:contraseña@localhost:5432/mi_tiendaSin nada más, el sistema arranca y funciona. Todo lo demás enciende cosas.
Los secretos
JWT_SECRET=
COOKIE_SECRET=
PCC_CLAVE_CIFRADO= # opcional; si está vacía, se usa JWT_SECRETLas sesiones no dependen de ellos: son fichas aleatorias guardadas en la base de
datos, no fichas firmadas. Lo que sí depende de ellos es el cifrado.
PCC_CLAVE_CIFRADO —o JWT_SECRET si está vacía— es la clave que cifra las
claves de pasarela guardadas desde el panel, las claves y códigos digitales que
vendes y las cuentas de cobro de los vendedores, y además firma los enlaces de
descarga privados y las licencias. Ese es el riesgo real de dejar los valores de
ejemplo: quien los conozca puede descifrar lo que guarda tu base. Cámbialos
antes de publicar.
Sin JWT_SECRET ni PCC_CLAVE_CIFRADO no se guarda ni se lee nada delicado:
claves de pasarela, claves y códigos digitales, cuentas de cobro, enlaces de
descarga y firmas de licencia se niegan con un error que dice qué variable falta
(HTTP 503). No hay ninguna clave de reserva escrita en el código. En la
práctica: pon siempre una de las dos (Docker lo hace por ti). Un
PCC_CLAVE_CIFRADO= vacío cuenta como no puesto, y se usa JWT_SECRET.
En Docker puedes dejarlos vacíos: el contenedor genera unos la primera vez y los
guarda en el volumen datos. Dos consecuencias:
- Con varias réplicas del backend, ponlos a mano con el mismo valor en todas: con secretos distintos, una réplica no puede descifrar lo que guardó otra.
- Si pierdes el volumen
datos, se generan secretos nuevos y todo lo cifrado se vuelve ilegible. Haz copia de él, o pon túPCC_CLAVE_CIFRADOy guárdala en lugar seguro.
Si cambias PCC_CLAVE_CIFRADO (o JWT_SECRET cuando hace de clave), lo que ya
estaba cifrado deja de poder leerse.
CORS: quién puede hablar con la tienda
CORS_TIENDA=https://mitienda.com # el escaparate
CORS_PANEL=https://panel.mitienda.com # el panelSon listas separadas por comas. Si falta una dirección, el navegador la
bloquea y el error no dice que sea culpa de esto: dice «CORS», y se pierde
media tarde buscando en el sitio equivocado. Cuando montes un tema nuevo en otro
puerto, acuérdate de añadirlo a CORS_TIENDA. En Docker los dos salen de
TIENDA_URL y PANEL_URL.
Lo que enciende cada cosa
Todo lo que sigue es opcional. Sin la variable, la funcionalidad simplemente no está — no falla, no avisa, no estorba.
Correo
SMTP_HOST=
SMTP_PORT=587
SMTP_USER=
SMTP_PASS=
SMTP_FROM=
CONTACT_TO= # buzón al que se avisa de cada mensaje del formulario (también llega a Panel → Soporte)Sin esto no salen ni confirmaciones de pedido ni recuperación de contraseña. Los avisos no se pierden: se quedan en la cola, el arranque lo dice, y se mandan en cuanto pongas el servidor de correo.
Que el correo salga no basta para que llegue: el dominio desde el que escribes tiene que autorizarlo, y eso vive en su DNS. Para verlo:
pcc correo # el dominio de SMTP_FROM
pcc correo mitienda.com # o el que le digasMira MX, SPF, DKIM y DMARC y dice qué falta. No necesita base de datos, así que sirve también cuando la tienda no arranca. Sin DKIM no puedes demostrar que un correo salió de ti —SPF se rompe en cuanto alguien reenvía el mensaje—, y Gmail y Yahoo lo exigen a quien manda volumen.
Inteligencia artificial
ANTHROPIC_API_KEY=
OPENAI_API_KEY=
GOOGLE_API_KEY=
MISTRAL_API_KEY=
OPENROUTER_API_KEY=
VOYAGE_API_KEY= # solo para búsqueda por significado
COHERE_API_KEY=
OLLAMA_URL=http://localhost:11434 # en tu máquina, sin costePones la clave que quieras usar, no todas. El proveedor se elige después en el panel, en la sección IA.
La clave es tuya y el gasto también: el sistema viene con los frenos puestos (tope diario y límite por visitante), pero quien paga las llamadas eres tú. Cómo funciona y qué cuesta: la IA.
Sin ninguna clave la tienda funciona igual — buscador por palabras, fichas, avisos. Lo que necesita clave es lo que escribe o razona.
Envíos
Las zonas, las tarifas y las clases de envío no van en el .env: se hacen en
el panel, en Envíos. Cómo, en configurar los envíos.
No hay integración con Sendcloud que calcule portes o haga etiquetas. Lo
único que existe es la ruta que recibe sus avisos de cambio de estado de un
paquete, POST /hooks/sendcloud:
SENDCLOUD_WEBHOOK_SECRET= # la firma de sus avisos
# o, si no está, se usa SENDCLOUD_SECRET_KEYComprueba la firma y apunta el aviso en el registro del servidor; no cambia el pedido. Sin ninguno de los dos secretos, contesta 503 a todo lo que llegue: una ruta abierta sin firma sería una puerta para que cualquiera escriba en tu registro.
Si tu .env trae SENDCLOUD_PUBLIC_KEY, SENDCLOUD_FROM_*,
SENDCLOUD_DEFAULT_WEIGHT_KG o SENDCLOUD_FALLBACK_EUR, puedes borrarlas:
nadie las lee. Rellenarlas no enciende nada.
Temas y extensiones
THEMES_DIR= # dónde están los temas. Por defecto: themes/
PLUGINS_DIR= # dónde están los plugins. Por defecto: plugins/ en la raíz del repositorio; /plugins en Docker
PLUGINS_DISABLED=uno,otro # apagar uno sin desinstalarlo
LICENSE_PUBLIC_KEY= # comprobar licencias de plugins de pagoLICENSE_PUBLIC_KEY es pública a propósito: solo sirve para verificar
firmas, nunca para crearlas.
Enlaces a la tienda
STOREFRONT_URL=https://mitienda.com
STOREFRONT_RUTA_PRODUCTO=producto # /producto/<handle>De aquí salen los enlaces que la IA y los correos mandan al cliente. Si tu tema
usa otra ruta —/p/, /articulo/— cámbiala aquí o los enlaces darán 404.
El escaparate se configura aparte
El tema no lee el .env del backend: es otra aplicación, muchas veces en otro
servidor. Necesita dos datos suyos:
COMMERCE_URL=https://api.mitienda.com # dirección del backend
COMMERCE_KEY=pk_... # clave publicable del canal de ventaCuando el panel arranca un tema, le pasa exactamente estos dos. Cada stack los
expone al navegador a su manera: Next quiere NEXT_PUBLIC_, Vite quiere
VITE_. El tema de fábrica dulce-obrador, hecho con Vite, los llama
VITE_PCC_BACKEND_URL y VITE_PCC_PUBLISHABLE_KEY. Mira el .env.example del
tema.
La clave publicable decide qué productos ve ese escaparate: va atada a un canal de venta.
El backend crea una en su primer arranque (preparar, que en Docker corre en
cada arranque y la escribe en datos/clave-publicable.txt). No hay pantalla en
el panel para crear más: el panel lee la primera clave publicable activa y se la
da a todos los temas que arranca.
Lo que se configura en el panel
Sin tocar ficheros ni reiniciar:
| Dónde | Qué |
|---|---|
| Ajustes | Nombre y marca de la tienda; en Facturación, los datos fiscales de las facturas; en Pagos, las formas de pago y las claves de las pasarelas |
| IA | Proveedor y modelo, tope de gasto diario, qué se puede escribir solo |
| Temas | Qué tema está activo y su contenido de ejemplo |
| Extensiones | Plugins instalados y sus ajustes |
| Equipo | Quién entra al panel |
Los datos fiscales viven en la tienda, no en el código: cambiar un NIF no
debería exigir reconstruir nada. Lo guardado en Ajustes → Facturación manda
sobre las variables COMPANY_*, que son solo el respaldo mientras no se haya
guardado nada. Si tiras de ese respaldo, el prefijo de factura es
INVOICE_PREFIX tanto para el panel como para el backend (los antiguos
COMPANY_INVOICE_PREFIX y NEXT_PUBLIC_INVOICE_PREFIX se siguen leyendo).