🔍 Verificare la sicurezza della connessione
Ogni utente vede, in fondo alla barra laterale di LibreFolio, quanto è sicuro il dialogo tra il suo browser e il server: Connessione: sicura, Connessione: rete locale o Connessione: non sicura. La guida per l'utente, Sicurezza della connessione, gli spiega i tre livelli. Questa pagina è per chi gestisce il server: come verificare che la tua installazione dia ai suoi utenti Connessione: sicura, e come correggerla quando non lo fa.
L'obiettivo è un indirizzo HTTPS, da Tailscale Serve o Funnel
(Esposizione sicura) o da un reverse proxy con un certificato
(Dietro un reverse proxy), e un cookie di sessione marcato Secure.
✅ Lista di controllo
Percorrila una volta che il tuo indirizzo HTTPS funziona, e di nuovo dopo ogni modifica al proxy o a
.env. Ti servono un account amministratore e, per gli ultimi due controlli, un telefono con i dati
mobili.
- Apri l'indirizzo HTTPS e accedi. L'indicatore mostra 🟢 Connessione: sicura, e i suoi dettagli dicono che la connessione è cifrata con HTTPS.
- Cerca la riga del cookie. Con l'accesso da amministratore, i dettagli mostrano solo quel motivo e il link Come connettersi in sicurezza. Una riga in più, sul cookie di sessione, significa che LibreFolio non sa dell'HTTPS: vedi Dietro un reverse proxy.
- Chiedi al server. In una nuova scheda, apri
https://<your address>/api/v1/system/connection: la risposta contiene"cookie_secure":true(Il punto di vista del server). - Guarda il cookie. Negli strumenti per sviluppatori del browser, il cookie
sessionè marcatoSecure(Il cookie di sessione). - Da fuori, apri l'indirizzo HTTPS. Sul telefono, con il Wi-Fi spento, la pagina si carica e, una volta fatto l'accesso, l'indicatore mostra 🟢 Connessione: sicura. Tieni Tailscale spento sul telefono per un indirizzo Funnel o di reverse proxy; accendilo per un indirizzo Tailscale Serve, che solo la tua tailnet può aprire.
- Da fuori, prova l'HTTP in chiaro. Sullo stesso telefono,
http://<your public IP or name>:6040, o la tuaPORT, non si carica. Se compare la pagina di accesso, l'HTTP in chiaro è aperto a internet: non accedere lì, perché la password viaggerebbe in chiaro, e chiudi la porta (Quando un controllo fallisce). Chi accede da quell'indirizzo vede 🔴 Connessione: non sicura, o 🏠 Connessione: rete locale con un motivo Incerta quando il server non vede da dove arrivano i visitatori (Limiti).
Tutti i controlli superati? Chiedi ai tuoi utenti di usare l'indirizzo HTTPS su ogni dispositivo e di aggiornare i loro vecchi preferiti (Come connettersi in sicurezza).
📶 Ancora nessun indirizzo HTTPS?
Con il Livello 1 o 2 di Esposizione sicura, gli utenti raggiungono
LibreFolio con l'HTTP in chiaro. Controlla il livello che ottiene ogni indirizzo
(Cosa mostra l'indicatore) e che l'HTTP in chiaro non si carichi da fuori
(controllo 6). I controlli sul cookie non si applicano: con l'HTTP in chiaro il cookie di
sessione non è Secure, e "cookie_secure":false è atteso.
🚦 Cosa mostra l'indicatore
Il browser giudica l'indirizzo che ha aperto; il server riferisce poi da dove vede arrivare la richiesta, e può confermare quel verdetto o renderlo incerto, ma mai renderlo sicuro. Ecco cosa vedono i tuoi utenti, secondo il modo in cui raggiungono LibreFolio:
| Come gli utenti raggiungono LibreFolio | Esempio | Livello |
|---|---|---|
| Tailscale Serve o Funnel, o un reverse proxy con un certificato | https://librefolio.your-tailnet.ts.net |
🟢 sicura: HTTPS |
| Sul server stesso | http://localhost:6040 |
🟢 sicura: localhost |
| IP Tailscale o nome MagicDNS completo, HTTP in chiaro (Livello 1) | http://100.a.b.c:6040 |
🟢 sicura: VPN (Tailscale) |
| Nome MagicDNS breve, HTTP in chiaro: un nome senza punto conta come locale | http://your-server:6040 |
🏠 rete locale |
| Indirizzo locale, anche attraverso un subnet router (Livello 2) | http://192.168.1.100:6040 |
🏠 rete locale |
| Una porta aperta sul router, HTTP in chiaro | http://myhome.duckdns.org:6040 |
🔴 non sicura |
Quando il server non vede gli indirizzi dei tuoi visitatori, l'ultima riga mostra invece 🏠 rete locale con un motivo Incerta (Limiti). La guida per l'utente dà le regole esatte sotto ogni livello: intervalli di indirizzi, nomi e casi Incerta (Sicurezza della connessione).
🔎 Il punto di vista del server
L'indicatore chiede al server come vede la connessione, una volta per ogni caricamento della
pagina: GET /api/v1/system/connection. Puoi leggere la stessa risposta: con l'accesso fatto, apri
questo indirizzo in una nuova scheda dello stesso browser, con il tuo indirizzo LibreFolio al posto
di quello dell'esempio:
Il browser mostra una risposta di una riga, per esempio:
Va bene qualsiasi account, non solo un amministratore. Una risposta come {"detail":"Not authenticated"}
significa che a quell'indirizzo non c'è una sessione: le sessioni appartengono a un indirizzo,
quindi accedere su http://192.168.1.100:6040 non ti fa accedere all'indirizzo HTTPS. E siccome
l'indicatore chiede una sola volta per caricamento della pagina, ricarica LibreFolio dopo una
modifica per vedere il suo nuovo verdetto.
cookie_secure dice se un cookie di sessione impostato su questa richiesta sarebbe Secure,
secondo SESSION_COOKIE_SECURE. Sull'indirizzo HTTPS deve essere true: false
è ciò che mostra la riga per l'amministratore sul cookie (Dietro un reverse proxy).
Con l'HTTP in chiaro, false è atteso.
client_class è da dove il server vede arrivare la richiesta. Legge l'ultimo valore di
X-Forwarded-For, quello aggiunto dal proxy più vicino, quando è un indirizzo IP, e altrimenti
l'indirizzo della connessione stessa. Dal server esce solo la classe: l'indirizzo non viene mai
restituito né registrato nei log.
client_class |
La richiesta arriva da |
|---|---|
loopback |
Il server stesso: 127.0.0.0/8 o ::1 |
vpn |
Tailscale o Headscale: 100.64.0.0/10 o fd7a:115c:a1e0::/48 |
lan |
Una rete locale: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16, fe80::/10 o fc00::/7 |
public |
Qualsiasi altro indirizzo: internet |
unknown |
Nessun indirizzo, o uno che non si riesce a leggere |
La classe conta solo con l'HTTP in chiaro, e non sul server stesso (localhost):
- con un indirizzo pubblico nel browser,
publicounknownconferma Connessione: non sicura, mentreloopback,vpnolanla trasformano in Connessione: rete locale, come incerta; - con un indirizzo locale o di Tailscale nel browser,
publicrende il verdetto incerto, e qualsiasi altra classe lo lascia com'è.
Sull'indirizzo HTTPS la classe non cambia niente, ma ti dice se il server riesce a vedere gli
indirizzi dei tuoi visitatori: dal telefono con i dati mobili, con Tailscale spento, public
significa che ci riesce, e lan o loopback che non ci riesce (Limiti).
🍪 Il cookie di sessione
Il cookie che tiene un utente connesso si chiama session. LibreFolio lo imposta all'accesso,
sempre HttpOnly, così gli script della pagina non possono leggerlo, e SameSite=Lax. Se è anche
Secure, cioè inviato solo con HTTPS, dipende da SESSION_COOKIE_SECURE in .env:
auto, il predefinito:Securequando la richiesta è HTTPS, vista direttamente o perché il primo valore diX-Forwarded-Protoinviato da un reverse proxy èhttps;always: sempreSecure;never: maiSecure.
Maiuscole e spazi intorno al valore non contano; qualsiasi altro valore ferma LibreFolio all'avvio.
Quando always o never sono la scelta giusta: Configurazione.
L'attributo si decide all'accesso: il cookie che un browser ha già tiene l'attributo che ha avuto allora. Dopo aver corretto il proxy o l'opzione, esci e accedi di nuovo.
Per vedere l'attributo nel browser:
- Accedi all'indirizzo HTTPS.
- Apri gli strumenti per sviluppatori:
F12, oppure clic destro sulla pagina e Ispeziona. Safari li mostra solo dopo aver attivato le sue funzioni per sviluppatori nelle impostazioni. - Apri i cookie del tuo indirizzo LibreFolio: Application → Cookies in Chrome ed Edge, Storage → Cookies in Firefox e Safari (i nomi seguono la lingua del browser).
- Nella riga
session, Secure è spuntato (truein Firefox), e così HttpOnly; SameSite indicaLax.
La console non può mostrarlo: document.cookie esclude i cookie HttpOnly.
🧰 Dietro un reverse proxy
Un reverse proxy riceve la connessione HTTPS e la passa a LibreFolio in HTTP in chiaro, quindi LibreFolio sa dell'HTTPS, e del visitatore, solo dalle intestazioni del proxy:
X-Forwarded-Proto: httpsdice che il browser usa HTTPS: conSESSION_COOKIE_SECURE=auto, il predefinito, LibreFolio marca allora il cookie di sessioneSecure;X-Forwarded-Forporta l'indirizzo del visitatore, che permette all'indicatore di vedere da dove si connettono gli utenti.
Tailscale Serve e Funnel, Caddy e Traefik le inviano entrambe da soli. Nginx ha bisogno di entrambe
le righe nel blocco location che passa le richieste a LibreFolio:
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
Se il browser usa HTTPS ma il cookie di sessione non è marcato Secure, perché il proxy non invia
X-Forwarded-Proto o perché SESSION_COOKIE_SECURE è never, gli amministratori vedono una riga
in più nei dettagli dell'indicatore. Il livello resta Connessione: sicura, perché la connessione
è cifrata; solo al cookie manca Secure:
Il browser usa HTTPS, ma il cookie di sessione non è marcato Secure. Fai mandare X-Forwarded-Proto al reverse proxy (Nginx:
proxy_set_header X-Forwarded-Proto $scheme;), oppure riporta SESSION_COOKIE_SECURE ad auto se è never.
Una volta corretto il proxy, ricarica LibreFolio: la riga scompare. Poi esci e accedi di nuovo,
così che il browser riceva un cookie Secure.
⚙️ Imposta invece SESSION_COOKIE_SECURE
Inviare l'intestazione è la correzione migliore. Se raggiungi LibreFolio sempre e solo in HTTPS,
puoi invece aggiungere questa riga a .env:
Poi riavvia LibreFolio: con Docker, esegui docker compose up -d (un semplice
docker compose restart mantiene il vecchio ambiente); con un'installazione sull'host, riavvia
./dev.py server, che legge anch'esso .env. Poi esci e accedi di nuovo.
Usa never solo per il raro proxy che dichiara HTTPS mentre il browser è in HTTP in chiaro. Vedi
Configurazione per ogni opzione.
🛠️ Quando un controllo fallisce
| Cosa vedi | Perché | Cosa fare |
|---|---|---|
| L'indirizzo HTTPS non mostra Connessione: sicura | La pagina non è in HTTPS: la barra degli indirizzi mostra http:// |
Apri l'indirizzo https://, e fai reindirizzare http:// lì dal proxy |
La riga sul cookie di sessione, o "cookie_secure":false sull'indirizzo HTTPS |
Il proxy non invia X-Forwarded-Proto: https, o SESSION_COOKIE_SECURE è never |
Correggi il proxy (Dietro un reverse proxy) o riporta l'opzione ad auto, poi ricarica |
"cookie_secure":true, ma il cookie session non è Secure |
Il cookie è stato impostato prima della correzione | Esci e accedi di nuovo |
{"detail":"Not authenticated"} |
Nessuna sessione a questo indirizzo | Accedi a questo indirizzo, nello stesso browser |
| Ogni accesso finisce di nuovo sulla pagina di accesso | Il cookie è Secure, ma il browser usa l'HTTP in chiaro: SESSION_COOKIE_SECURE=always, o un proxy che invia X-Forwarded-Proto: https a un browser in HTTP in chiaro |
Usa l'indirizzo HTTPS, o correggi il proxy: vedi Configurazione |
| Da fuori, l'indirizzo HTTPS non si carica | Un indirizzo Tailscale Serve è privato; un nuovo Funnel ha bisogno di approvazione e di qualche minuto | Accendi Tailscale sul telefono, o usa Funnel; approva il Funnel e aspetta (Esposizione sicura) |
Da fuori, http://…:6040 in chiaro si carica |
La porta di LibreFolio è aperta a internet: un port forward sul router, o un server con un indirizzo pubblico | Chiudila: rimuovi il port forward, o blocca la porta nel firewall del server. Tailscale non ha bisogno di porte aperte, e un reverse proxy solo della sua |
client_class indica lan o loopback dai dati mobili, o l'HTTP in chiaro da internet mostra Connessione: rete locale, Incerta |
Il server non vede da dove arrivano i visitatori | Vedi Limiti; con Nginx, aggiungi la riga X-Forwarded-For |
| Un indirizzo Tailscale mostra Connessione: rete locale | Un nome MagicDNS breve non ha punti, quindi conta come locale | Usa l'IP Tailscale, il nome completo .ts.net o, meglio, l'indirizzo HTTPS |
⚠️ Limiti
L'indicatore è un consiglio, non un controllo: non blocca niente. Due limiti contano quando verifichi un'installazione.
Non sempre vede dove sono i visitatori. Con Docker Desktop esposto direttamente, o dietro un
proxy che non passa l'indirizzo del visitatore in X-Forwarded-For, il server vede ogni visitatore
come locale: lan, o loopback per un proxy sulla stessa macchina. L'HTTP in chiaro da internet
mostra allora Connessione: rete locale, come incerta, invece di Connessione: non sicura.
Docker Engine su Linux mantiene l'indirizzo del visitatore. Gli indirizzi HTTPS non ne risentono:
mostrano Connessione: sicura in ogni caso.
Non controlla i certificati. Un certificato autofirmato che un utente ha accettato nel browser mostra Connessione: sicura: il traffico è cifrato, ma nessuno garantisce che il server sia davvero il tuo.
Non c'è nessun elenco di proxy fidati da configurare. X-Forwarded-For alimenta solo l'indicatore,
quindi un valore falsificato inganna solo l'indicatore di chi l'ha inviato; X-Forwarded-Proto può
solo attivare Secure, quindi un https falsificato rompe solo l'accesso di chi l'ha inviato.
🔗 Correlati
- 🔐 Sicurezza della connessione — La guida per l'utente: i tre livelli e cosa fare per ciascuno
- 🌐 Esposizione sicura — Tailscale, da una VPN privata a un indirizzo HTTPS pubblico
- 🐳 Docker avanzato — File Compose, variabili d'ambiente, reverse proxy
- 📝 Configurazione —
SESSION_COOKIE_SECUREe ogni altra opzione di.env