Le variabili d’ambiente non arrivano al container
Quando le variabili d’ambiente non funzionano in un container, la causa è solitamente una di cinque: build time e runtime, bundling del frontend, virgolette, riavvio o scope errato. Verificale in quest’ordine.
Imposti la variabile. La dashboard la mostra. L’applicazione dice che è undefined. Le variabili d’ambiente che non funzionano in un container sono uno dei problemi di configurazione più comuni nell’hosting delle applicazioni e quasi sempre la causa è una di cinque.
Sono elencate nell’ordine che consente di trovare il problema più rapidamente.
1. Build time e runtime sono due mondi diversi
Questa causa genera più problemi delle altre quattro messe insieme ed è quella che risulta meno intuitiva.
Le variabili impostate sul servizio esistono quando il container viene eseguito. Tutto ciò che fa il Dockerfile avviene prima, in un ambiente separato. Un’istruzione RUN non può vedere una variabile di runtime, perché in quel momento il runtime non esiste ancora.
# This is empty during build. Always.
RUN echo $DATABASE_URL
# This is available at runtime, because it is the running process reading it
CMD ["node", "server.js"]
Se hai davvero bisogno di un valore durante la build, devi passarlo come build argument — un meccanismo diverso, con proprietà di sicurezza diverse:
ARG BUILD_VERSION
RUN echo "Building $BUILD_VERSION"
Non passare mai un segreto in questo modo. I build argument vengono registrati nella cronologia dei layer dell’immagine. Chiunque possa eseguire il pull dell’immagine può leggerli.
2. Le variabili del frontend vengono incorporate, non lette
Se in produzione il frontend restituisce undefined, questa è quasi certamente la causa.
Un browser non ha un ambiente. Quando scrivi import.meta.env.VITE_API_URL o process.env.NEXT_PUBLIC_API_URL, il bundler sostituisce il valore letterale al build time. Nel browser non viene effettuata alcuna ricerca: il valore è stato incorporato in fase di compilazione.
Tre conseguenze spesso sorprendenti:
- Cambiare la variabile non serve a nulla finché non esegui una nuova build. Il vecchio valore si trova già nel file JavaScript.
- Il prefisso è obbligatorio. Vite espone solo
VITE_, mentre Next.js espone soloNEXT_PUBLIC_. Una variabile senza prefisso viene esclusa deliberatamente. - Qualsiasi valore esposto in questo modo è pubblico. Si trova in un file che distribuisci a chiunque. Non mettere mai un segreto dietro
NEXT_PUBLIC_, indipendentemente da ciò che suggerisce il nome.
Questo spiega anche perché un’immagine prebuilt non può essere configurata in questo modo a posteriori. Se l’immagine è stata buildata altrove con i valori già incorporati, impostare le variabili sul servizio non cambia nulla: le stringhe sono già nel bundle.
3. Le virgolette
I valori contenenti caratteri speciali vengono alterati in modi che producono errori confusi anziché errori evidenti.
# The shell eats everything after #
dockup env set DB_PASS=p@ss#word my-project/my-api
# Quote it
dockup env set 'DB_PASS=p@ss#word' my-project/my-api
I caratteri che causano questo problema sono: # (commento), $ (espansione), gli spazi (suddivisione degli argomenti), ! (history expansion nella bash interattiva) e le nuove righe, che compaiono in un unico caso comune: le chiavi private.
I valori multi-linea sono il caso più problematico. Una chiave PEM incollata in un campo a riga singola arriva senza le nuove righe e produce un errore di parsing che non dice nulla sulle nuove righe. Codificala in Base64 e decodificala nell’applicazione:
dockup env set "PRIVATE_KEY_B64=$(base64 -i key.pem)" my-project/my-api
4. Non hai riavviato
Le variabili d’ambiente vengono lette da un processo quando viene avviato. Modificarle ha effetto sul processo successivo, non su quello attualmente in esecuzione.
La maggior parte delle piattaforme gestisce il problema eseguendo automaticamente un nuovo deployment quando cambia la configurazione, ma non tutte lo fanno; inoltre, una modifica parziale — imposti tre variabili, esegui il redeploy, poi ne imposti una quarta — lascia indietro una variabile.
dockup env list my-project/my-api --json # what is configured
dockup restart my-project/my-api # make the process re-read it
La verifica decisiva consiste nel leggere la variabile dall’interno del container in esecuzione, non dalla dashboard.
dockup exec "printenv | sort" my-project/my-api
Se compare in quell’output e l’app continua a indicarla come undefined, il problema è nel codice. Se non compare, il problema è nella configurazione. Un solo comando divide lo spazio delle possibili cause a metà.
5. Scope errato
Le variabili hanno solitamente uno scope — un servizio, un ambiente o un progetto. Una variabile impostata in produzione non è visibile in un ambiente di preview. Allo stesso modo, una variabile impostata su un altro servizio dello stesso progetto non è visibile.
Questa è la causa più comune quando qualcosa funziona in un contesto ma non in un altro, a parità di codice.
L’ordine della diagnosi
# 1. Is it actually in the container's environment?
dockup exec "printenv | sort" my-project/my-api
# 2. Is it configured on the service you think it is?
dockup env list my-project/my-api --json
# 3. Is the running process older than the change?
dockup status my-project/my-api --json
Inizia sempre dal passaggio 1. Trasforma un problema ambiguo in uno di due problemi ben definiti.
I segreti in particolare
Indipendentemente dalla piattaforma, vale la pena adottare due abitudini.
Contrassegna i segreti come segreti. Su Dockup, una variabile contrassegnata come segreta viene mascherata negli elenchi e nelle risposte API: dockup env list mostra ******** anziché il valore. È più importante di quanto possa sembrare, perché il modo più comune in cui una credenziale viene esposta non è un attacco, ma uno screenshot, un ticket di supporto o una riga di log.
Tienili fuori dai build argument e dai bundle del frontend. Entrambi sono leggibili da chiunque ottenga l’artefatto. La regola pratica è: se finisce in un file che distribuisci, non è più un segreto.
Domande frequenti
Perché la mia variabile d’ambiente è undefined al build time? Perché build e runtime sono ambienti separati. Le variabili di runtime non esistono mentre l’immagine viene buildata. Usa un build argument se hai davvero bisogno di un valore durante la build — ma mai un segreto.
Perché il mio frontend non vede la variabile?
I bundler sostituiscono il valore al build time ed espongono solo i nomi con prefisso: VITE_, NEXT_PUBLIC_. Cambiare la variabile richiede una nuova build e qualsiasi valore esposto in questo modo è leggibile pubblicamente.
Devo riavviare dopo aver modificato una variabile?
Sì. Un processo in esecuzione ha già letto il proprio ambiente. La maggior parte delle piattaforme esegue automaticamente un nuovo deployment quando cambia la configurazione; verifica con printenv dall’interno del container invece di affidarti alla dashboard.
Come posso passare un valore multi-linea, come una chiave privata? Codificalo in Base64, imposta la stringa codificata e decodificala nell’applicazione. I campi per le variabili d’ambiente su una sola riga rimuovono le nuove righe e producono errori di parsing che non le menzionano.
