dsh web: perché compare http://127.0.0.1:3080
dsh stampa http://127.0.0.1:3080 perché la Web UI ascolta solo su localhost. Usa un tunnel SSH sicuro e scopri perché esporre la porta 3080 è rischioso.
Che 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 della stessa macchina e da nessun'altra. Questa riga indica quindi due cose: dove è in ascolto l'interfaccia Web e quali host possono raggiungerla. Può raggiungerla soltanto la macchina su cui è in esecuzione dsh.
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 diverso. Non c'è alcun guasto. Devi inoltrare la connessione.
Il README ufficiale indica chiaramente il comportamento predefinito: "Il comando avvia l'interfaccia Web, pubblicata per impostazione predefinita su http://127.0.0.1:3080." L'indirizzo di bind proviene dal plugin host del webserver, @deepseek-ai/dsh-host-webserver, la cui chiave host è documentata come "Host in ascolto; i due valori supportati sono loopback e tutte le interfacce". Se non lo modifichi, viene usato loopback. Se non conosci ancora bene le porte, come funzionano le porte in Linux descrive il modello basato su indirizzo e porta da cui dipende tutto questo.
Perché l'interfaccia Web resta in ascolto solo su localhost
dsh è un agent harness. La scheda del browser è una superficie di controllo per un processo che esegue comandi shell, legge e scrive file nella directory di lavoro scelta e utilizza la chiave API del modello. Chiunque possa caricare quella pagina può eseguire tutte queste operazioni con l'account che esegue dsh.
La porta 3080 non espone quindi 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. In ascolto sul loopback, questo comportamento è coerente: il controllo degli accessi è affidato al sistema operativo e solo i processi locali possono connettersi. Se si configura lo stesso server in ascolto su 0.0.0.0 su un VPS con un indirizzo IP pubblico, la stessa pagina risponde all'intera Internet senza alcun livello di protezione davanti. Gli scanner automatici analizzano continuamente anche le porte non comuni, quindi una porta 3080 pubblicata va considerata individuata.
Non aprire la porta 3080 nel firewall e non impostarehostdel webserver su0.0.0.0in un VPS pubblico. Questa combinazione consente a chiunque si connetta per primo di eseguire comandi sul server.
Lo stesso principio vale per ogni runtime di agent che installi su un server. Per questo eseguire in sicurezza un agent di coding su un VPS parte dalla stessa regola: la porta di controllo dell'agent resta privata e un componente di cui ti fidi gestisce l'accesso.
Come apro l'interfaccia Web di dsh dal mio laptop?
Esistono tre modalità corrette e tutte mantengono il servizio in ascolto sull'interfaccia di loopback.
- Un tunnel SSH. Nulla di nuovo viene messo in ascolto sull'interfaccia pubblica e disponi già delle credenziali. È la modalità consigliata.
- Una rete overlay privata, in modo che l'interfaccia sia raggiungibile dai tuoi dispositivi e invisibile a chiunque altro.
- Un reverse proxy con terminazione TLS (transport layer security) che richiede una password prima di inoltrare qualsiasi richiesta.
La differenza riguarda il percorso seguito dal browser per raggiungere l'interfaccia di loopback. In nessuno dei tre casi il servizio deve essere spostato fuori dall'interfaccia di loopback.
Raggiungerlo con un tunnel SSH
Esegui questo comando sul laptop, non sul VPS:
ssh -N -L 3080:127.0.0.1:3080 you@your-vpsLascialo 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 indica la porta da aprire sul laptop. Il secondo e il terzo indicano rispettivamente 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 vi è già arrivato. 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 funziona.
-N indica a SSH di non eseguire un comando remoto, quindi viene creato un inoltro senza aprire una shell. Per eseguire il tunnel in background e ottenere errori espliciti invece di errori silenziosi:
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 quando non è stato possibile configurare l'inoltro. Si ottiene quindi una sessione funzionante ma un tunnel inattivo, senza alcun avviso. ServerAliveInterval=30 invia un keepalive ogni 30 secondi, così il tunnel continua a funzionare anche dopo i timeout NAT (network address translation) dei router di bar e hotel.
Cosa dovresti vedere
Sul VPS, verifica quale processo è effettivamente in ascolto:
ss -ltnp | grep 3080Un risultato corretto indica 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 l'indirizzo di ascolto prima di procedere. Se ss stampa il socket ma lascia vuoto il campo users:, eseguilo con sudo, perché altrimenti il nome del processo associato a un socket appartenente a un altro utente non viene mostrato.
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: 3080Il problema riguarda il laptop, non il server. Un processo locale sta già usando la porta 3080, spesso un tunnel precedente che è stato lasciato attivo. Scegli invece una porta locale libera:
ssh -N -L 3081:127.0.0.1:3080 you@your-vpsÈ cambiato soltanto il primo campo, quindi ora devi aprire http://127.0.0.1:3081, mentre il servizio di harness continua a essere in ascolto sulla porta 3080. I due numeri non devono necessariamente 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'estremità remota. È possibile che dsh sia terminato oppure che sia in ascolto su un'altra porta. Verifica con ss -ltnp | grep 3080 sul server.
C'è un altro problema che spesso viene trascurato. Un processo npx @deepseek-ai/dsh web 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 per l'utente. È lo stesso problema descritto in mantenere in esecuzione un agente di coding su un VPS. Mentre lavori sulla parte SSH, conviene prima rafforzare la sicurezza di SSH sul VPS, perché il tunnel rende il tuo accesso SSH l'unico punto di accesso all'agente.
Raggiungilo tramite una rete overlay privata
Una rete overlay assegna al tuo VPS e al tuo laptop indirizzi su una rete privata a cui accedono soltanto i tuoi dispositivi. Tailscale è la scelta più comune e il suo comando serve è adatto esattamente a questo caso: tailscaled viene eseguito sul VPS e si connette direttamente 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 statusL'interfaccia è quindi raggiungibile tramite il nome del tuo computer nella tailnet, usando 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 usando off:
tailscale serve --https=443 offUsa serve, mai funnel. Funnel pubblica la stessa destinazione su Internet, riportandoti a un runtime dell'agente non autenticato su una porta aperta. 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 espone realmente una porta a Internet. L'autenticazione è quindi l'unico elemento che separa uno sconosciuto dall'esecuzione di comandi sul server. Sceglila quando più persone devono usare l'interfaccia e un tunnel per ciascun utente non è pratico.
L'harness resta su 127.0.0.1:3080. nginx viene eseguito sullo stesso host, quindi può raggiungere il loopback, e ascolta 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 e ricarica la configurazione:
sudo apt install -y apache2-utils
sudo htpasswd -c /etc/nginx/dsh.htpasswd you
sudo nginx -t && sudo systemctl reload nginxnginx -t dovrebbe stampare syntax is ok seguito da test is successful. Se il file non è valido, il reload fallisce e lascia attiva la configurazione corrente. Leggi quindi l'errore invece di riavviare il servizio alla cieca.
Tre di quelle direttive del proxy sono necessarie. 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. In caso contrario, una lunga esecuzione dell'agent viene interrotta a metà della risposta e l'interfaccia sembra 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 come scegliere tra nginx, Caddy e Traefik descrive come ottenere lo stesso risultato con certificati automatici.
Tieni chiusa la porta 3080 nel firewall indipendentemente dal proxy scelto. L'unico percorso di accesso deve passare dal proxy autenticato. Nozioni di base sul firewall ufw descrive le regole. L'autenticazione di base tramite TLS è un livello minimo di protezione, non un modello di sicurezza completo: chiunque possieda quella password dispone di una shell sul server. Quando possibile, preferisci il tunnel.
Come si cambia la porta su cui è in ascolto il web di dsh?
--port appartiene all'applicazione web, non al launcher. La documentazione della CLI riporta direttamente questo esempio:
dsh --profile web --port 8080dsh web è un alias di --profile web, quindi dsh web --port 8080 esegue 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 il primo token che il launcher non riconosce: da quel punto iniziano gli argomenti dell'applicazione. Inserire --port dopo il profilo, mai prima.
Leggere l'URL stampato dal comando invece di dedurlo, 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-vpsPer rendere permanente la modifica, impostare la porta nella configurazione del profilo invece che nella riga di comando. I profili web e headless vengono inizializzati automaticamente al primo utilizzo a partire dai template forniti, in ~/.dsh. Per vedere la configurazione effettiva dopo la composizione di tutti i livelli:
dsh --dump-configIl plugin webserver espone esattamente due chiavi, host e port. Impostare port su 0 chiede al sistema operativo di assegnare una porta libera, come indicato nella documentazione: "zero requests an OS-assigned port". Questo evita sempre i conflitti, ma non è adatto 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:3080Individua il processo che utilizza l'indirizzo prima di modificare qualsiasi cosa:
sudo ss -ltnp | grep 3080Il campo users:(("node",pid=1042,fd=21)) identifica il processo e il relativo PID. Di solito si tratta di un'istanza precedente di dsh che pensavi fosse terminata, ma che è ancora attiva in una sessione tmux scollegata. Arrestala con kill 1042 oppure avvia la nuova istanza su un'altra porta. Tieni presente che 127.0.0.1:3080 e 0.0.0.0:3080 entrano anch'essi in conflitto, perché il bind 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, viene aggiornato rapidamente e sono previste modifiche che possono interrompere la compatibilità.
npx @deepseek-ai/dsh web risolve ogni volta la versione pubblicata più recente. Un server che non viene toccato per una settimana può avviare una CLI diversa al successivo avvio, con flag differenti. Blocca la versione, in modo che un riavvio non diventi un aggiornamento:
npx @deepseek-ai/dsh@0.1.0-rc.7 webAd agosto 2026, il pacchetto pubblicato è la versione 0.1.0-rc.7. Verifica quale versione installerebbe un semplice npx prima di accettarla:
npm view @deepseek-ai/dsh versionNelle versioni preview, 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 supportati invece di procedere per tentativi:
dsh --profile web --helpPer l'installazione, la configurazione del workspace e la chiave del modello, consulta installare DeepSeek Harness su un VPS. Per una procedura più breve dedicata soltanto alla fase di accesso, accedere alla Web UI di dsh su un VPS illustra il tunnel senza la parte relativa al ragionamento.
FAQ
Perché non riesco ad aprire http://127.0.0.1:3080 nel browser del mio laptop?
Perché 127.0.0.1 indica il computer sul quale stai digitando. L'interfaccia Web di DeepSeek Harness è associata all'indirizzo di loopback della VPS, quindi solo 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, perciò punta al 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, mentre 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, tieni 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 scollegala con Ctrl-b d, oppure eseguilo come servizio systemd dell'utente con il lingering abilitato. Il tunnel e il harness sono indipendenti: puoi interrompere e ricreare il tunnel SSH tutte le volte che vuoi senza modificare il harness in esecuzione, purché il 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, cosa che può accadere facilmente 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 vada a buon fine. Senza questi header la pagina viene caricata, ma non riceve mai aggiornamenti.