SSD Nodes Learn Hosting plans →
Guide Matt ConnorDi Matt Connor · Aggiornato 2026-08-27

dsh web: perché http://127.0.0.1:3080 non risponde

dsh mostra http://127.0.0.1:3080 perché la Web UI ascolta solo su localhost. Usa un tunnel SSH per accedervi senza esporre la porta 3080.

Cosa significa dsh web: http://127.0.0.1:3080

Quando avvii il profilo web di DeepSeek Harness su un VPS, stampa due righe e poi resta in attesa:

dsh web: http://127.0.0.1:3080
Ready.

127.0.0.1 è l'indirizzo di loopback. È l'indirizzo che una macchina usa per comunicare con se stessa. Un socket associato a 127.0.0.1 accetta connessioni dai processi presenti sulla stessa macchina e da nessun'altra origine. Quella riga indica quindi due cose: dove è in ascolto la Web UI e chi può raggiungerla. Solo la macchina su cui è in esecuzione dsh può accedervi.

Per questo l'URL non produce alcun risultato quando lo incolli nel browser del laptop. Il 127.0.0.1 del laptop è il laptop stesso. Harness è in ascolto sul 127.0.0.1 del VPS, che è un'altra macchina con uno stack di loopback distinto. Non c'è alcun guasto. Devi trasferire la connessione da una macchina all'altra.

Il README ufficiale lo indica chiaramente: "The command starts the Web UI, served at http://127.0.0.1:3080 by default." L'indirizzo di bind proviene dal plugin host del webserver, @deepseek-ai/dsh-host-webserver, la cui chiave host è documentata come "Listen host; the two supported values are loopback and all-interfaces". Se non lo modifichi, viene usato loopback. Se non hai familiarità con le porte, come funzionano le porte su Linux descrive il modello basato su indirizzo e porta su cui si fonda tutto questo.

Perché la Web UI è in ascolto solo su localhost

dsh è un agent harness, cioè il programma che avvolge il modello: gestisce il ciclo di esecuzione, le chiamate agli strumenti e i permessi con cui vengono eseguite. La scheda del browser è un'interfaccia di controllo per un processo che esegue comandi shell, legge e scrive file nella directory workspace scelta e utilizza la chiave API del modello. Chiunque possa caricare quella pagina può eseguire tutte queste operazioni con l'utente che esegue dsh. Inoltre, l'accesso non avviene soltanto tramite la rete: un plugin installato viene eseguito nello stesso processo e con gli stessi permessi. Per questo verificare un plugin dsh prima di installarlo richiede la stessa attenzione della scelta di ciò su cui il server deve restare in ascolto.

La porta 3080, quindi, non espone una dashboard in sola lettura. Il caricamento della pagina consente di eseguire comandi sul server.

Aprendo la Web UI si accede direttamente all'elenco delle sessioni. Non viene richiesto alcun login, perché la developer preview non include account utente né autenticazione remota. Su loopback questo comportamento è coerente: il controllo degli accessi è affidato al sistema operativo e soltanto i processi locali possono connettersi. Se si associa lo stesso server a 0.0.0.0 su un VPS con un indirizzo IP pubblico, la stessa pagina risponde all'intera Internet, senza alcun componente davanti. Gli scanner automatici analizzano continuamente le porte non comuni, quindi una porta 3080 pubblicata va considerata individuata.

Non aprire la porta 3080 nel firewall e non impostare host del webserver su 0.0.0.0 in un VPS pubblico. Questa combinazione consente a chiunque si connetta per primo di eseguire comandi sul server.

Lo stesso principio si applica a qualsiasi agent runtime installato su un server. Per questo eseguire in sicurezza un coding agent su un VPS parte dalla stessa regola: la porta di controllo dell'agent resta privata e un componente attendibile gestisce l'accesso.

Come apro l’interfaccia Web di dsh dal mio laptop?

Esistono tre modalità corrette e tutte mantengono l’harness in ascolto sull’interfaccia di loopback.

  • Un tunnel SSH. Nessun nuovo servizio è in ascolto sull’interfaccia pubblica e disponi già delle credenziali. È la modalità da usare.
  • Una rete overlay privata, così l’interfaccia è raggiungibile dai tuoi dispositivi e invisibile a chiunque altro.
  • Un reverse proxy che termina TLS (transport layer security) e richiede una password prima di inoltrare qualsiasi richiesta.

La differenza consiste nel modo in cui il browser raggiunge l’interfaccia di loopback. Nessuna di queste modalità deve prevedere lo spostamento dell’harness fuori dall’interfaccia di loopback.

Accedervi con un tunnel SSH

Esegui questo comando sul laptop, non sul VPS:

ssh -N -L 3080:127.0.0.1:3080 you@your-vps

Lascialo in esecuzione, quindi apri http://127.0.0.1:3080 nel browser locale. L'interfaccia Web viene caricata.

L'argomento -L contiene tre campi separati da due punti. Il primo è la porta da aprire sul laptop. Il secondo e il terzo sono l'indirizzo e la porta a cui inoltrare ogni connessione. Il dettaglio importante è il seguente: 127.0.0.1 nel campo centrale viene risolto dal server SSH sul VPS, dopo che il traffico è già arrivato al VPS. Indica il loopback del VPS, non quello del laptop. È esattamente l'indirizzo mostrato da dsh; per questo il tunnel funziona quando una connessione diretta dal browser non riesce.

-N indica a SSH di non eseguire un comando remoto, quindi viene creato un inoltro senza aprire una shell. Per un tunnel in background che segnala gli errori invece di ignorarli:

ssh -N -f -o ExitOnForwardFailure=yes -o ServerAliveInterval=30 -L 3080:127.0.0.1:3080 you@your-vps

-f lo sposta in background dopo l'autenticazione. ExitOnForwardFailure=yes è più importante di quanto sembri: senza questa opzione, SSH si connette correttamente anche se non è riuscito a configurare l'inoltro. Si ottiene così una sessione attiva ma un tunnel non funzionante, senza alcun avviso. ServerAliveInterval=30 invia un keepalive ogni 30 secondi, così un tunnel inattivo può superare i timeout del NAT (network address translation) sui router di bar e hotel.

Cosa dovresti vedere

Sul VPS, verifica quale processo è effettivamente in ascolto:

ss -ltnp | grep 3080

Un risultato corretto mostra l'indirizzo di loopback:

LISTEN 0  511  127.0.0.1:3080  0.0.0.0:*  users:(("node",pid=1042,fd=21))

Se la colonna dell'indirizzo locale contiene invece 0.0.0.0:3080, l'interfaccia Web è disponibile su tutte le interfacce, inclusa quella pubblica. Arresta il servizio e correggi il bind prima di procedere. Se ss stampa il socket ma lascia vuoto il campo users:, eseguilo con sudo, perché altrimenti il nome del processo che possiede un socket appartenente a un altro utente resta nascosto.

Quando il tunnel non si avvia

SSH stampa questo messaggio e termina:

bind [127.0.0.1]:3080: Address already in use
channel_setup_fwd_listener_tcpip: cannot listen to port: 3080

Il problema riguarda il laptop, non il server. Un processo locale sta già utilizzando la porta 3080, spesso un tunnel precedente che non è stato chiuso. Scegli invece una porta locale libera:

ssh -N -L 3081:127.0.0.1:3080 you@your-vps

È cambiato solo il primo campo, quindi ora devi aprire http://127.0.0.1:3081 nel browser, mentre l'harness continua ad ascoltare sulla porta 3080. I due numeri non devono coincidere.

Se il tunnel si avvia ma il browser segnala una connessione rifiutata o una risposta vuota, il traffico ha raggiunto il VPS ma non ha trovato nulla all'altra estremità. È possibile che dsh sia terminato oppure che sia in ascolto su una porta diversa. Verifica con ss -ltnp | grep 3080 sul server.

C'è un altro problema frequente. Un npx @deepseek-ai/dsh web eseguito in primo piano termina quando la shell viene chiusa, quindi l'harness si arresta non appena esegui il logout. Avvialo all'interno di tmux oppure tramite un servizio systemd dell'utente. È lo stesso problema risolto in mantenere un agente di coding in esecuzione su un VPS. Mentre configuri la parte SSH, conviene prima mettere in sicurezza SSH sul VPS, perché il tunnel rende il tuo accesso SSH l'unico punto di ingresso all'agente.

Accedere tramite una rete overlay privata

Una rete overlay assegna al VPS e al laptop indirizzi su una rete privata a cui possono accedere soltanto i tuoi dispositivi. Tailscale è la scelta più comune e il comando serve è esattamente adatto a questo caso: tailscaled viene eseguito sul VPS e si connette a localhost:3080, quindi l’harness resta in ascolto su loopback e non devi modificare la configurazione di dsh.

tailscale serve --bg localhost:3080
tailscale serve status

L’interfaccia è quindi raggiungibile all’indirizzo del computer nella tua tailnet, tramite HTTPS, senza aprire porte sull’interfaccia pubblica. Devi prima abilitare i certificati HTTPS per la tailnet; in caso contrario serve non ha alcun certificato da presentare. Per disattivarlo, ripeti il comando con off:

tailscale serve --https=443 off

Usa serve, mai funnel. Funnel pubblica la stessa destinazione su Internet, riportandoti a un runtime dell’agente non autenticato su una porta esposta. I due comandi sono quasi identici, ma hanno effetti opposti. Leggi la differenza tra Tailscale Serve e Funnel prima di eseguire uno dei due. Tailscale come rete privata descrive la configurazione della rete.

Raggiungerlo tramite un reverse proxy che verifica una password

Questa è l’opzione che pubblica effettivamente una porta su Internet, quindi l’autenticazione è l’unica barriera tra uno sconosciuto e l’esecuzione di comandi sul server. Sceglila quando più persone devono usare l’interfaccia e un tunnel per ciascun utente non è pratico.

Il harness resta su 127.0.0.1:3080. nginx è in esecuzione sullo stesso server, quindi può raggiungere il loopback, e resta in ascolto sulla porta 443 con un certificato e un file delle password.

server {
    listen 443 ssl;
    server_name dsh.example.com;

    ssl_certificate     /etc/letsencrypt/live/dsh.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/dsh.example.com/privkey.pem;

    auth_basic           "dsh";
    auth_basic_user_file /etc/nginx/dsh.htpasswd;

    location / {
        proxy_pass http://127.0.0.1:3080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_read_timeout 3600s;
        proxy_buffering off;
    }
}

Crea il file delle password ed esegui il reload:

sudo apt install -y apache2-utils
sudo htpasswd -c /etc/nginx/dsh.htpasswd you
sudo nginx -t && sudo systemctl reload nginx

nginx -t dovrebbe stampare syntax is ok seguito da test is successful. Un reload con un file non valido non va a buon fine e lascia attiva la configurazione in esecuzione, quindi leggi l’errore invece di riavviare alla cieca.

Tre di quelle direttive del proxy non sono decorative. Gli header Upgrade e Connection consentono l’handshake WebSocket; senza di essi la pagina viene caricata, ma non si aggiorna mai. proxy_read_timeout 3600s sostituisce il valore predefinito di 60 secondi, che altrimenti interrompe a metà una lunga esecuzione dell’agente e fa apparire l’interfaccia bloccata. proxy_buffering off invia l’output del modello al browser man mano che arriva, invece di trattenerlo fino al completamento della risposta. Una configurazione reverse proxy nginx, riga per riga spiega il resto, mentre scegliere tra nginx, Caddy e Traefik illustra come ottenere lo stesso risultato con certificati automatici.

Mantieni chiusa la porta 3080 nel firewall, indipendentemente dal proxy scelto, in modo che l’unico percorso di accesso passi da quello autenticato. Nozioni di base sul firewall ufw illustra le regole. L’autenticazione di base tramite TLS è il livello minimo, non un modello di sicurezza completo: chiunque possieda quella password dispone di una shell sul server. Quando possibile, preferisci il tunnel.

Come modificare la porta su cui è in ascolto il webserver di dsh?

--port appartiene all'applicazione web, non al launcher. La documentazione della CLI mostra direttamente questo esempio:

dsh --profile web --port 8080

dsh web è un alias di --profile web, quindi dsh web --port 8080 è lo stesso comando. Il launcher analizza soltanto i propri flag e passa tutto ciò che segue al profilo avviato. I flag del launcher devono quindi precedere gli altri argomenti; il primo token non riconosciuto dal launcher avvia gli argomenti dell'applicazione. Inserire --port dopo il profilo, mai prima.

Leggere l'URL stampato dal comando invece di presumerlo, perché quella riga indica l'indirizzo su cui il server è effettivamente in ascolto. Aggiornare quindi l'ultimo campo del tunnel in modo che corrisponda:

ssh -N -L 3080:127.0.0.1:8080 you@your-vps

Per una modifica permanente, la porta si trova nella configurazione del profilo, non nella riga di comando. I profili web e headless vengono inizializzati automaticamente al primo utilizzo a partire dai template forniti, nella directory ~/.dsh. Nella stessa directory si trovano le impostazioni per la chiave API e l'endpoint del modello; configurare chiavi, modelli ed endpoint di dsh è quindi la guida correlata da consultare mentre si modificano questi file. Per verificare quali impostazioni siano effettivamente applicate dopo la composizione di tutti i livelli:

dsh --dump-config

Il plugin webserver espone esattamente due chiavi, host e port. Impostare port su 0 richiede al sistema operativo una porta libera; la documentazione specifica che "zero requests an OS-assigned port". In questo modo si evitano i conflitti, ma la configurazione è poco adatta a un tunnel, perché il numero cambia a ogni riavvio.

Perché dsh restituisce l’errore «address already in use»?

Perché un altro processo utilizza già quell’indirizzo e quella porta. Il kernel rifiuta quindi il secondo bind. Node lo segnala in questo modo:

Error: listen EADDRINUSE: address already in use 127.0.0.1:3080

Individua il processo che occupa l’indirizzo prima di modificare qualsiasi configurazione:

sudo ss -ltnp | grep 3080

Il campo users:(("node",pid=1042,fd=21)) identifica il processo e il relativo PID. Di solito si tratta di una precedente istanza di dsh che pensavi fosse stata arrestata, ma che è ancora attiva in una finestra tmux scollegata. Arrestala con kill 1042 oppure avvia la nuova istanza su un’altra porta. Tieni presente che anche 127.0.0.1:3080 e 0.0.0.0:3080 sono in conflitto, perché il binding su tutte le interfacce include già il loopback.

Blocca la versione, perché si tratta di una developer preview

Il README lo dichiara chiaramente: DeepSeek Harness è in developer preview e viene aggiornato rapidamente; sono previste modifiche incompatibili. Se è questa velocità a farti esitare, come dsh si confronta con Claude Code e Omnigent mette a confronto due harness in fasi diverse della stessa evoluzione.

npx @deepseek-ai/dsh web risolve ogni volta la versione pubblicata più recente quando lo esegui. Un server che non hai toccato per una settimana può avviare una CLI diversa al successivo avvio, con flag differenti. Blocca la versione, così un riavvio non diventa un aggiornamento:

npx @deepseek-ai/dsh@0.1.0-rc.7 web

Ad agosto 2026 il pacchetto pubblicato è la versione 0.1.0-rc.7. Controlla quale versione installerebbe un semplice npx prima di confermare:

npm view @deepseek-ai/dsh version

Se il pin rifiuta l'installazione oppure npx continua ad avviare la build precedente dopo che hai bloccato una nuova versione, gli errori di installazione e versione che possono verificarsi spiega come svuotare la cache di npx e verificare quale npm è incluso nel tuo Node.

Nelle release di anteprima i flag vengono spostati tra il launcher e l'applicazione Web. Se --port smette di comportarsi come descritto in questa guida, chiedi all'applicazione l'elenco dei flag disponibili invece di procedere per tentativi:

dsh --profile web --help

Per l'installazione, la configurazione del workspace e la chiave del modello, consulta installare DeepSeek Harness su un VPS. Per una procedura più breve limitata all'accesso, raggiungere la Web UI di dsh su un VPS descrive il tunnel senza la parte relativa al ragionamento.

FAQ

Perché non riesco ad aprire http://127.0.0.1:3080 nel browser del laptop?

Perché 127.0.0.1 indica il computer su cui stai digitando. L'interfaccia Web di DeepSeek Harness è associata all'indirizzo di loopback della VPS, quindi soltanto i processi eseguiti sulla VPS possono connettersi. Il laptop ha un loopback separato e su quella macchina nessun processo è in ascolto sulla porta 3080. Inoltra la porta tramite SSH con ssh -N -L 3080:127.0.0.1:3080 you@your-vps, quindi apri localmente http://127.0.0.1:3080. Il campo centrale dell'argomento -L viene risolto sul server, ed è questo che lo indirizza verso l'harness.

È sicuro associare l'interfaccia Web di dsh a 0.0.0.0 su una VPS pubblica?

No. L'interfaccia Web è la superficie di controllo di un agente che esegue comandi shell e modifica file con l'utente che esegue dsh; inoltre, l'anteprima per sviluppatori non presenta alcuna schermata di accesso. L'associazione a tutte le interfacce su un IP pubblico consente a chiunque raggiunga la porta 3080 di eseguire comandi sul server. Mantieni l'associazione su 127.0.0.1, mantieni chiusa la porta 3080 nel firewall e usa un tunnel SSH, una rete overlay privata oppure un reverse proxy che richieda una password.

Come posso mantenere in esecuzione l'interfaccia Web di dsh dopo aver chiuso la sessione SSH?

Un npx @deepseek-ai/dsh web in primo piano è un processo figlio della shell di login, quindi viene terminato quando la shell esce. Avvialo all'interno di una sessione tmux e scollegalo con Ctrl-b d, oppure eseguilo come servizio systemd dell'utente con il lingering abilitato. Il tunnel e l'harness sono indipendenti: puoi interrompere e ricreare il tunnel SSH tutte le volte che vuoi senza modificare l'harness in esecuzione, purché l'harness abbia un processo padre che resti attivo oltre la sessione di login.

Perché l'interfaccia Web di dsh si blocca durante un'esecuzione lunga dell'agente dietro nginx?

Perché il valore predefinito di proxy_read_timeout in nginx è 60 secondi. nginx chiude quindi una connessione che non produce dati per un minuto, condizione comune durante un passaggio lungo dell'agente. Imposta proxy_read_timeout 3600s; nel blocco location. Aggiungi proxy_buffering off; per inviare l'output al browser man mano che arriva e inoltra gli header Upgrade e Connection con proxy_http_version 1.1;, in modo che l'handshake WebSocket abbia esito positivo. Senza questi header la pagina viene caricata, ma non riceve mai aggiornamenti.