1 19/04/2026 11 min

http-server è un server statico minimale scritto per Node.js, utile quando devi servire file HTML, CSS, JS o asset senza tirare in mezzo Apache, Nginx o un framework più pesante. È la scelta giusta per test locali, demo, anteprime di build statiche e ambienti interni dove conta la rapidità più della logica applicativa.

Il punto non è “sostituire” un web server completo, ma avere uno strumento affidabile, leggibile e veloce da mettere in piedi. Se il requisito è servire una directory con un comportamento prevedibile, poche dipendenze e una CLI lineare, http-server fa esattamente questo. Se invece ti servono rewrite, reverse proxy, TLS complesso, caching avanzato o regole di accesso, stai già in un altro scenario.

Quando ha senso usarlo

La situazione tipica è questa: hai una cartella con un sito statico generato da un builder, vuoi aprirla in rete locale, oppure devi esporla temporaneamente su una macchina di test. In questi casi installare e configurare un web server completo è spesso inutile. Con Node.js e NPM puoi avere un servizio pronto in pochi minuti e senza toccare la stack di sistema.

È anche comodo per verificare rapidamente una build prima di pubblicarla: se il sito funziona con http-server, sai che il problema non è il contenuto statico in sé ma eventualmente il reverse proxy, il CDN, il path di deploy o la configurazione del server finale.

Prerequisiti reali: Node.js e NPM

Serve una installazione funzionante di Node.js con NPM. Nella pratica conviene verificare subito che i binari siano presenti e che la versione sia coerente con il tuo ambiente. Su sistemi recenti basta questo:

node -v
npm -v

Se uno dei due comandi non risponde, non partire a installare pacchetti a caso: prima risolvi la base. In ambienti Linux server, soprattutto se il software deve restare installato, è preferibile una distribuzione coerente tramite repository ufficiali, NodeSource o un gestore versioni come nvm. La scelta dipende da chi amministra la macchina e da quanto vuoi separare il runtime di Node dal resto del sistema.

Se lavori su una macchina condivisa o con più versioni di Node, nvm riduce i conflitti. Se invece vuoi un servizio stabile e gestito come pacchetto di sistema, meglio installare una versione definita e documentata, evitando aggiornamenti impliciti che cambiano comportamento da un giorno all’altro.

Installazione di http-server con NPM

L’installazione globale è la via più semplice se vuoi avere il comando disponibile ovunque sull’host:

npm install -g http-server

Dopo l’installazione, verifica che il binario sia nel PATH e che il comando risponda:

http-server -v
which http-server

Su Windows il principio è lo stesso, ma il path del binario dipende dall’installazione di Node e dal profilo utente. Se il comando non viene trovato, controlla il percorso dei binari NPM globali con:

npm bin -g

In alcuni ambienti conviene evitare il globale e usare npx o un’installazione locale nel progetto. È utile quando vuoi rendere il comportamento ripetibile tra macchine diverse o tenere bloccata la versione dello strumento.

npx http-server

Questa modalità riduce l’effetto “sulla mia macchina funziona” perché lega l’esecuzione al package risolto in quel contesto. Se però il server deve essere usato spesso da operatori diversi, l’installazione globale resta più pratica.

Avvio base: servire una directory

Il caso minimo è servire la directory corrente. Vai nella cartella del sito e lancia il server:

cd /var/www/site-statico
http-server

Per default il servizio ascolta su una porta locale e stampa in console l’indirizzo di accesso. Aprendo il browser vedrai la root della directory servita. Se nella cartella c’è un index.html, verrà usato come pagina iniziale.

Se vuoi essere esplicito sulla porta, soprattutto in ambienti con più servizi, specifica il parametro:

http-server -p 8080

Per una macchina in rete locale, l’ascolto su tutte le interfacce è spesso più comodo. In quel caso controlla che la porta sia raggiungibile dal client previsto e che firewall o security group non la blocchino. Il punto pratico è semplice: il server può essere attivo, ma il traffico non arriva comunque se la porta resta chiusa a livello di rete.

Opzioni utili da conoscere subito

Le opzioni più usate non sono molte, ma cambiano parecchio l’esperienza operativa. Le prime da memorizzare sono porta, binding, cache e directory di partenza.

http-server /var/www/site-statico -p 8080 -a 0.0.0.0 -c-1

In questo esempio il server serve una directory specifica, ascolta su tutte le interfacce e disabilita la cache lato client. Quest’ultimo punto è utile in test e debug, perché evita di inseguire file vecchi nel browser dopo una modifica.

Altre opzioni da usare con criterio:

  • -p: porta di ascolto.
  • -a: indirizzo di bind, ad esempio 127.0.0.1 per uso locale o 0.0.0.0 per esporre il servizio in rete.
  • -c: controllo della cache; valori bassi o negativi sono utili in debug.
  • -o: apre il browser automaticamente, utile in ambienti desktop.
  • -d: attiva il logging dettagliato, comodo quando devi capire richieste e risposte.
  • -g: abilita gzip se supportato dal flusso previsto.

Occhio a non confondere “semplicità” con “assenza di disciplina”. Se il server deve stare acceso più di qualche ora, annota porta, directory, utente di esecuzione e motivo dell’uso. Sono dettagli banali, ma fanno la differenza quando devi riprendere mano al servizio dopo giorni o quando un collega deve verificarlo al posto tuo.

Test rapido con una pagina statica

Per capire subito se tutto è corretto, crea un file minimale e servilo. È un test banale, ma elimina molte ambiguità: path errato, permessi, porta occupata, file mancante, browser che mostra una cache vecchia.

mkdir -p /tmp/http-server-demo
cat > /tmp/http-server-demo/index.html <<'EOF'
<!doctype html>
<html lang="it">
<head>
  <meta charset="utf-8">
  <title>Demo</title>
</head>
<body>
  <h1>Funziona</h1>
</body>
</html>
EOF
cd /tmp/http-server-demo
http-server -p 8080

Dal client verifica con un semplice curl:

curl -I http://127.0.0.1:8080/

L’esito atteso è un HTTP/1.1 200 OK o comunque una risposta coerente con il file presente. Se ottieni 404, la directory servita non è quella che pensi. Se ottieni ECONNREFUSED, la porta non è in ascolto o il processo non è partito. Se il comando risponde ma il browser no, il problema è quasi sempre di rete o di binding sull’interfaccia sbagliata.

Uso in rete locale e attenzione al binding

Molti problemi nascono da un dettaglio: il server ascolta solo su 127.0.0.1 e quindi è visibile solo dalla stessa macchina. Se vuoi aprirlo dalla LAN, imposta il bind su 0.0.0.0 oppure sull’IP specifico dell’host.

http-server -a 0.0.0.0 -p 8080

Dopo l’avvio, controlla la porta in ascolto con:

ss -ltnp | grep 8080

Se il servizio risulta in ascolto ma non è raggiungibile da un altro host, il candidato successivo è il firewall locale o la policy di rete. In questo caso non serve toccare http-server: devi aprire la porta nel punto giusto e solo per il tempo necessario. È una regola pratica che evita di lasciare esposizioni inutili su macchine usate per test.

Esecuzione come servizio con systemd

Se il server deve restare attivo su una macchina Linux, conviene trattarlo come un servizio gestito da systemd. In questo modo hai restart, log centralizzati, controllo dello stato e avvio automatico al boot.

Un esempio minimale di unit file potrebbe essere questo:

[Unit]
Description=http-server static site
After=network.target

[Service]
Type=simple
User=www-data
WorkingDirectory=/var/www/site-statico
ExecStart=/usr/bin/http-server -a 0.0.0.0 -p 8080
Restart=on-failure
RestartSec=2

[Install]
WantedBy=multi-user.target

Salva il file, ad esempio in /etc/systemd/system/http-server-site.service, poi ricarica systemd e avvia il servizio:

systemctl daemon-reload
systemctl enable --now http-server-site.service
systemctl status http-server-site.service

Qui la parte importante non è la sintassi in sé, ma il contesto. L’utente di esecuzione deve avere permessi di lettura sulla directory servita. Se il contenuto viene aggiornato da un deploy, assicurati che i permessi e l’ownership restino coerenti. Un servizio statico che parte ma non legge i file giusti è un classico falso positivo.

Log, diagnosi e problemi frequenti

Quando qualcosa non torna, il primo controllo è sempre lo stato del processo e l’output standard. Con systemd puoi vedere subito gli eventi recenti:

journalctl -u http-server-site.service -n 50 --no-pager

Se il problema è una porta occupata, vedrai un errore di bind. In quel caso identifica il processo che già usa la porta e scegli una porta diversa oppure ferma il servizio corretto. Non sovrascrivere alla cieca: il conflitto di porta è spesso sintomo di una configurazione duplicata o di un vecchio processo dimenticato.

Se invece il browser mostra una pagina vuota o una directory listing inattesa, controlla due cose: presenza di index.html e path effettivo servito. Un comando utile è:

pwd
ls -la
find . -maxdepth 1 -type f | sort

In molti casi il bug non è nel server ma nella directory sbagliata. È un errore umano normale, soprattutto quando si lavora in più shell o si lancia il comando da un path diverso da quello previsto.

Un altro caso comune è la cache del browser: hai aggiornato il file ma continui a vedere la vecchia versione. Qui la soluzione non è riavviare il server, ma forzare il refresh o disabilitare temporaneamente la cache con l’opzione appropriata durante il test.

Integrazione con un reverse proxy

Quando il servizio deve stare dietro Nginx o Apache, http-server diventa un upstream locale. In questo scenario il suo compito resta quello di servire contenuti statici, mentre il proxy gestisce TLS, virtual host, compressione, header e routing pubblico.

La configurazione tipica è semplice: http-server ascolta su 127.0.0.1:8080 e il proxy inoltra il traffico. Questo approccio riduce l’esposizione diretta e ti permette di tenere il servizio non raggiungibile dall’esterno, che è una scelta più sensata su host condivisi o server di produzione.

Se il sito deve essere pubblico, il reverse proxy è quasi sempre la strada migliore. Se il sito è solo per test o staging, l’accesso diretto può bastare, ma resta una decisione da limitare nel tempo e nell’ambito di rete.

Un caso pratico: anteprima di una build frontend

Immagina una build generata da un frontend moderno, per esempio una cartella dist o build. Dopo il deploy della build, vuoi verificare che le route statiche, i bundle e gli asset siano raggiungibili. In questo caso puoi lanciare il server direttamente dentro la directory generata:

cd /srv/app/dist
http-server -p 9090 -c-1

Se la tua applicazione usa routing lato client, attenzione: il comportamento di fallback non è sempre identico a quello del server finale. http-server è ottimo per verificare asset e contenuto statico, ma non sostituisce un setup con rewrite specifici se la tua app si aspetta regole particolari per le route. Questo punto va tenuto presente per non confondere il test della build con il comportamento di produzione.

Per questo motivo, quando la build è complessa, la prova più utile è doppia: prima verifichi che i file siano serviti, poi confronti il comportamento con l’architettura reale che userai in produzione. Così eviti di promuovere una configurazione che funziona solo nel server temporaneo.

Buone pratiche operative

Se lo usi in modo professionale, tieni a mente poche regole che fanno risparmiare tempo:

  • Usa una porta esplicita, non quella di default, quando il contesto è condiviso.
  • Se serve accesso remoto, verifica firewall e bind prima di cambiare altro.
  • Disabilita la cache solo per il debug; non lasciare impostazioni da test in ambienti che restano attivi a lungo.
  • Se il servizio deve durare, gestiscilo con systemd o un supervisore equivalente.
  • Non esporre il servizio alla rete pubblica se non hai un motivo preciso.

La semplicità dello strumento non elimina la necessità di controllare il contesto. Un server statico “leggero” può comunque diventare un punto di accesso non voluto se lo lanci su una macchina sbagliata o con un bind troppo aperto. La disciplina operativa conta più della dimensione del software.

Conclusione operativa

http-server è utile perché abbassa il costo di verifica: installi, punti la directory, apri una porta e controlli il risultato. Per test locali, anteprime statiche e staging rapido è uno strumento pulito e prevedibile. Se invece devi gestire pubblicazione, TLS, regole di accesso o logica di routing più articolata, usalo come componente di appoggio e non come sostituto del web server finale.

Il vantaggio vero non è solo “avere un server”, ma avere una baseline semplice con cui isolare i problemi. Quando qualcosa non funziona, sai subito se il guasto è nei file, nella porta, nel bind, nella cache o nella rete. Ed è esattamente il tipo di riduzione della complessità che serve quando devi fare troubleshooting senza perdere tempo.