dsh web por SSH só imprime a URL e não abre o navegador: por que acontece e como abrir o Web UI

terminal mostrando dsh web rodando por SSH com apenas a URL impressa
Resposta rápida

Rodou o dsh web por SSH e apareceu só uma URL no terminal, sem navegador nenhum? É de propósito. Quando SSH_CONNECTION ou SSH_TTY chega não vazio, o dsh não faz o handoff pro navegador e apenas imprime a URL do host, porque quem manda no endereço encaminhado é o cliente SSH. O caminho previsto é encaminhar a porta na mão com ssh -L 3080:127.0.0.1:3080 user@host e abrir http://127.0.0.1:3080 no navegador local. E não adianta tentar --host 0.0.0.0: o comando recusa por segurança

Você entra no servidor por SSH, roda o Web UI achando que uma aba vai pular na sua cara, e o terminal te devolve uma URL solitária piscando ali

Nada abre, nada acontece, e vem aquele pensamento clássico: quebrou?

Não quebrou 🙂

O DeepSeek Harness é mantido pela DeepSeek AI no repositório oficial deepseek-ai/deepseek-harness e está em developer preview, ou seja, mudanças que quebram compatibilidade são esperadas e fazem parte do combinado

Mas esse comportamento específico por SSH não é um bug de preview, é decisão de projeto: em sessão remota o dsh entrega a URL e deixa a abertura do navegador com quem realmente é dono do endereço, que é a tua máquina local

Bora destrinchar cada sintoma que aparece nesse caminho

Formação Claude Code
Formação Recomendada

Formação Claude Code

Domine Claude Code do absoluto zero até o avançado

  • 120 aulas
  • 4 projetos
  • 9h 45min

Sintoma: o terminal imprime a URL e nada abre

Em um launch local, o runner Web de produção serve o endereço padrão http://127.0.0.1:3080 e abre essa URL canônica no navegador só depois que a árvore do Loader assenta

Antes desse handoff local, o dsh ainda avisa o que vai fazer, com a mensagem:

dsh web: opening the default browser; pass --no-open to disable

Até aí, tudo lindo na tua máquina

A causa em sessão remota: uma variável SSH_CONNECTION ou SSH_TTY herdada e não vazia suprime o handoff do navegador

O motivo é bem pé no chão: quem é dono do endereço encaminhado local é o cliente SSH (ou o editor que abriu a conexão), não o processo que está rodando lá no host

E se liga no detalhe que salva: a URL do host continua sendo impressa mesmo assim

A solução: pega essa URL e usa ela através de um túnel, que é exatamente o que a seção abaixo mostra

Como prevenir: sempre que a sessão for remota, já assuma encaminhamento manual de porta como parte do fluxo, e não como plano B

Como abrir o Web UI do DeepSeek Harness numa máquina remota

O caminho previsto tem quatro passos e não precisa de plugin nenhum

  1. Suba o servidor no host remoto

O pacote npm oficial é @deepseek-ai/dsh, e é ele que expõe o comando dsh

Pra subir o Web UI sem instalar nada, vai de npx:

npx @deepseek-ai/dsh web

O erro comum deste passo: chamar dsh direto achando que o comando já existe na máquina remota, quando o binário vem do pacote @deepseek-ai/dsh

  1. Anote a URL impressa no terminal

Ela é a referência do que está no ar naquele host, com a porta que o servidor realmente subiu

O erro comum deste passo: bater o olho e assumir a porta de cabeça, principalmente se você mexeu nas flags de rede

  1. No terminal da SUA máquina, monte o túnel
ssh -L 3080:127.0.0.1:3080 user@host

O erro comum deste passo: rodar esse comando no host remoto, dentro da sessão que já está aberta

O -L é encaminhamento LOCAL, ele nasce no teu computador

  1. Abra o endereço encaminhado no navegador local
http://127.0.0.1:3080

O erro comum deste passo, e esse é o campeão: tentar abrir o IP do servidor direto no navegador, tipo http://ip-do-servidor:3080, em vez do endereço encaminhado

Com o túnel de pé, o 127.0.0.1 da tua máquina é a ponta do fio que chega no host remoto, beleza?

Com o Web UI encaminhado funcionando, o fluxo de trabalho fica bem confortável: você gera no host remoto e ainda pode revisar o código do DeepSeek antes de abrir o PR, sem precisar expor nada pra rede

–no-open: quando desligar a abertura do navegador de propósito

Aí bate a dúvida honesta: se por SSH já não abre nada, pra que existe a flag?

A causa da confusão: a supressão em sessão SSH é automática, ela acontece por causa das variáveis de ambiente herdadas

Já a --no-open é a forma EXPLÍCITA de rodar o servidor Web sem abrir navegador:

dsh web --no-open

Isso é ouro em script, em container e em serviço que sobe sozinho, onde abrir navegador não faz o menor sentido

Como prevenir a confusão: trate --no-open como intenção declarada ("eu não quero navegador aqui"), e não como conserto do comportamento em SSH

São duas coisas diferentes que chegam no mesmo lugar

Sintoma: a flag –port ou –host é recusada ou ignorada

Clássico: você escreve a flag antes do subcomando e o comando não obedece

A causa: --port, --host e a repetível --trusted-host pertencem ao aplicativo web, então elas precisam vir DEPOIS do subcomando web

A solução é só posição:

dsh web --port 3180
Flag Pra que serve Posição
--no-open roda o servidor Web sem abrir navegador depois de web
--port define a porta do aplicativo web depois de web
--host define o host do aplicativo web depois de web
--trusted-host adiciona autoridade aceita, é repetível depois de web

Como prevenir: memoriza a regra preguiçosa e infalível: tudo que é de rede vem depois de web

E tome cuidado com o efeito colateral: se você mudou a porta, o túnel tem que apontar pra ela também

ssh -L 3180:127.0.0.1:3180 user@host

Já vi gente jurar que o Web UI estava fora do ar quando o túnel só estava mirando na porta velha 😀

Sintoma: erro ao tentar expor o Web UI com –host 0.0.0.0

A tentação é grande, eu sei: se o problema é acesso remoto, é só escutar em tudo e pronto

Só que o comando sai com erro de uso

A causa: o dsh web recusa --host 0.0.0.0 de propósito, por segurança, com esta mensagem:

--host 0.0.0.0 is intentionally not supported yet for safety: it would expose remote code execution to the network; use 127.0.0.1 instead

Leia de novo a parte do meio: expor execução remota de código pra rede

Não é frescura da CLI, é a ferramenta te impedindo de deixar um executor de código aberto pro mundo

A solução: mantenha 127.0.0.1 e resolva o acesso remoto pelo túnel SSH

Como prevenir: para de tratar túnel como gambiarra

Ele é o caminho previsto pra esse cenário, não o desvio

Sintoma: a página abre, mas sessões e modelos não aparecem (403 no /api)

Esse aqui engana bonito: a casca da página carrega, o layout está lá, e o conteúdo fica vazio

A causa: existe uma cerca de browser-trust no /api, e a comparação do cabeçalho Host é LITERAL

Host que não está na lista faz toda chamada /api retornar 403, e o resultado é justamente esse: página carrega, sessões e modelos ficam ausentes

A solução: adicionar a autoridade aceita com --trusted-host, que é repetível e vem depois do subcomando web

Como prevenir: confira exatamente qual host e qual porta você digitou no navegador

Comparação literal não perdoa detalhe, então vale olhar caractere por caractere antes de sair xingando a ferramenta

Sintoma: settings, credentials e descoberta de modelos dão 403 mesmo com o host confiável

Agora um caso mais sutil: chat funciona, sessões funcionam, modelos aparecem, e mesmo assim algumas telas quebram

A causa: um conjunto de métodos sensíveis da API fica preso ao loopback independentemente de trustedHosts

São eles: settings., credentials. e llm.discoverModels

De origem remota, essas chamadas retornam 403, enquanto chat, sessões e modelos seguem funcionando normalmente

A solução: faça essas operações a partir do loopback, ou seja, pelo endereço encaminhado do túnel na própria máquina, em vez de tentar servir o host pra fora

Como prevenir: separa mentalmente as duas coisas

Uma é acesso remoto pra usar o Web UI, outra é operação sensível (credencial, configuração, descoberta de modelo)

A segunda mora no loopback e é bom que seja assim mesmo

Sintoma: o navegador não abriu nem em launch local

E quando você está na tua própria máquina, sem SSH nenhum no meio, e o navegador simplesmente não sobe?

A causa: falha no handoff do sistema operacional

O comportamento esperado nesse caso é bem educado: o dsh emite um diagnóstico em stderr com o motivo, mantém o servidor rodando e nomeia a URL pra uso manual

A solução: lê o stderr, pega a URL e abre na mão

O servidor não caiu, ele está ali de boa esperando você 🙂

Como prevenir: sempre olhe o stderr antes de concluir que o comando falhou

Muita gente mata o processo achando que deu ruim, quando o processo estava servindo o Web UI o tempo todo

Conclusão

O resumo da ópera é que rodar o dsh web por SSH e ver só uma URL no terminal é decisão de design, com segurança no centro dela

A supressão da abertura acontece porque quem manda no endereço encaminhado é o cliente SSH, o --host 0.0.0.0 é recusado de propósito pra não jogar execução remota de código na rede, e a cerca de browser-trust do /api compara host de forma literal

Vale lembrar também que o projeto segue em developer preview, com breaking changes esperados, e a versão mais recente publicada no npm ainda é uma release candidate, então revisitar o comportamento depois de atualizar é sabedoria pura

Próximo passo é direto: monta o túnel, testa o Web UI pelo endereço encaminhado e confere a lista de trusted hosts antes de culpar a ferramenta

Na maioria das vezes o problema é uma porta esquecida ou um host escrito diferente do que a cerca espera…

até o próximo post!

Perguntas frequentes

Preciso instalar o @deepseek-ai/dsh globalmente antes de rodar o dsh web?

Não. O pacote npm oficial é @deepseek-ai/dsh e dá pra subir o Web UI sem instalar nada, direto com npx @deepseek-ai/dsh web. É o jeito mais rápido de testar num host remoto sem sujar o ambiente.

Rodar o dsh web dentro do VS Code com Remote SSH também impede a abertura do navegador?

Sim. A supressão acontece sempre que existe uma variável SSH_CONNECTION ou SSH_TTY herdada e não vazia, e isso vale tanto pro cliente SSH quanto pro editor que abriu a conexão remota. Quem é dono do endereço encaminhado é essa ferramenta, então o dsh só imprime a URL do host mesmo assim.

Configurar –trusted-host resolve todo erro 403 no dsh web por SSH?

Não totalmente. Host não listado em –trusted-host já derruba qualquer chamada de /api com 403, mas mesmo com o host liberado, os métodos settings., credentials. e llm.discoverModels ficam presos ao loopback e retornam 403 se a origem for remota. Chat, sessões e modelos continuam funcionando normalmente nesse cenário.

O DeepSeek Harness é um projeto oficial da DeepSeek ou mantido pela comunidade?

É mantido pela própria DeepSeek AI, no repositório oficial deepseek-ai/deepseek-harness. Vale lembrar que o projeto está em developer preview, então mudanças que quebram compatibilidade são esperadas.

Existe uma versão estável do dsh disponível no npm hoje?

A versão mais recente publicada no npm ainda é uma release candidate, não uma versão estável. Combina com o status de developer preview do projeto, então é normal ainda não existir uma tag estável.

O que fazer se o dsh web tentar abrir o navegador em launch local e falhar mesmo assim?

Se o handoff do sistema operacional falhar, o dsh emite um diagnóstico em stderr explicando o motivo, mas o servidor continua rodando normalmente. A URL fica informada no terminal pra você abrir manualmente, sem precisar reiniciar nada.



Escrito por | Matheus Battisti

Matheus Battisti
Fundador da Hora de Codar

Programador apaixonado pelo mundo das tecnologias, sempre buscando em aprender e se aprofundar em linguagens, frameworks e o que mais for necessário para executar um bom trabalho. Agora tem uma nova missão que é de passar seu conhecimento adiante para formar novos programadores e especializar mais os que já são.

Subscribe
Notify of
guest

0 Comentários
Oldest
Newest Most Voted

Formações

Formação Vibe Coding

Formação Vibe Coding

Do Prompt ao Produto: Crie Software Real com IA

  • 474 aulas
  • 20 projetos
  • 39h 27min

Blog | Mais populares