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

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
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
- 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
- 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
- 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
- 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.
Formações
Formação Vibe Coding
Do Prompt ao Produto: Crie Software Real com IA
- 474 aulas
- 20 projetos
- 39h 27min
Blog | Mais populares
Como rodar o DeepSeek Harness com npx e abrir o Web UI no navegador
Aprenda a rodar o DeepSeek Harness npx e abrir o Web UI em http://127.0.0.1:3080 automaticamente no navegador, direto do terminal com Node.js instalado.
DeepSeek V4 Pro: o que é e quando compensa usar em vez do V4 Flash?
DeepSeek V4 Pro tem 1,6 tri de parâmetros e janela de 1 milhão de tokens. Entenda o preço, o desempenho e quando vale mais a pena que o V4 Flash.
Como rodar o DeepSeek V4 no Ollama: o passo a passo e o que checar antes de tentar
Rodar o DeepSeek V4 no Ollama hoje é via tag cloud: veja como fazer login, baixar a tag e usar via CLI ou API local, e quando vale ir de GGUF offline.
