Why dsh dey show http://127.0.0.1:3080
dsh dey print http://127.0.0.1:3080 because Web UI bind to localhost only. Use SSH tunnel reach am safely, and no publish port 3080 anyhow.
Wetin dsh web: http://127.0.0.1:3080 mean
When you start the DeepSeek Harness web profile for VPS, e go print two lines, then e go wait:
dsh web: http://127.0.0.1:3080
Ready.127.0.0.1 na loopback address. Na the address machine dey use to talk to itself. Socket wey bind to 127.0.0.1 go accept connection from process wey dey run for that same machine, and nowhere else. So that line dey tell you two things at once: where Web UI dey listen, and who fit reach am. Na only the machine wey dsh dey run on fit reach am.
Na why the URL no dey do anything when you paste am for browser wey dey your laptop. Your laptop own 127.0.0.1 na your laptop. The harness dey listen for VPS own 127.0.0.1, and na different machine with different loopback stack. Nothing spoil. You need carry the connection across.
The official README talk the default clearly: "The command starts the Web UI, served at http://127.0.0.1:3080 by default." The bind address come from webserver host plugin, @deepseek-ai/dsh-host-webserver. The plugin document host key as "Listen host; the two supported values are loopback and all-interfaces". Loopback na wetin you go get unless you change am. If ports never too clear for you, how ports dey work for Linux explain the address-plus-port model wey everything here dey depend on.
Why Web UI dey bind to localhost only
dsh na agent harness, wey be the program wey dey wrap the model: na e dey control the loop, tool calls, and permissions wey those calls dey use run. Browser tab na control surface for process wey dey run shell commands, read and write files for the workspace directory wey you choose, and spend your model API key. Anybody wey fit load that page fit do all those things as the user wey dey run dsh. Network no be the only way to reach those permissions: plugin wey you install dey run inside the same process with the same permissions. Na why you need vet dsh plugin before you install am with the same care wey you go use decide wetin server go listen on.
So port 3080 no be read-only dashboard. If you load that page, you get command execution for the server.
Open Web UI and e go take you straight to session list. No login prompt dey, because developer preview no ship with user accounts or remote authentication. For loopback, this arrangement make sense: operating system na the access control, and na only local processes fit pass. If you bind the same server to 0.0.0.0 for VPS wey get public IP, that same page go answer the whole internet, with nothing in front of am. Automated scanners dey scan uncommon ports continuously, so treat published 3080 as already found.
No open port 3080 for your firewall, and no set webserverhostto0.0.0.0for public VPS. That combination go give anybody wey connect first command execution for your server.
The same reasoning apply to every agent runtime wey you put for server. Na why to run coding agent safely on VPS dey start with the same rule: agent control port stay private, and something wey you trust go carry you reach am.
How I fit open dsh Web UI from my laptop?
Three correct ways dey, and every one of dem go leave the harness bound to loopback.
- SSH tunnel. Nothing new go listen for public interface, and you already get the credentials. Na this one you suppose use.
- Private overlay network, so UI fit dey reachable from your own devices and remain invisible to everybody else.
- Reverse proxy wey go terminate TLS (transport layer security) and demand password before e forward anything.
The difference na wetin carry your browser go loopback. None of dem suppose involve moving the harness comot from loopback.
Reach am with SSH tunnel
Run this for your laptop, no be for the VPS:
ssh -N -L 3080:127.0.0.1:3080 you@your-vpsMake e dey run, then open http://127.0.0.1:3080 for your local browser. The Web UI go load.
The -L argument get three fields wey colon separate. The first one na the port to open for your laptop. The second and third na the address and port wey SSH go forward each connection go. The important detail be say: 127.0.0.1 for the middle field na the SSH server for the VPS go resolve am, after your traffic don already reach there. E mean the VPS loopback, no be your own loopback. Na exactly the address wey dsh print, and na why the tunnel dey work when direct browser connection no dey work.
-N tell SSH make e no run remote command, so you go get forwarder and no shell. For background tunnel wey go show error clearly instead of failing quietly:
ssh -N -f -o ExitOnForwardFailure=yes -o ServerAliveInterval=30 -L 3080:127.0.0.1:3080 you@your-vps-f put am for background after authentication. ExitOnForwardFailure=yes important pass as e look: without am, SSH fit connect successfully even when e no fit set up the forward, so you go get working session but dead tunnel without warning. ServerAliveInterval=30 send keepalive every 30 seconds so idle tunnel fit survive NAT (network address translation) timeouts for café and hotel routers.
Wetin you suppose see
For the VPS, confirm wetin dey listen:
ss -ltnp | grep 3080Healthy result go show the loopback address:
LISTEN 0 511 127.0.0.1:3080 0.0.0.0:* users:(("node",pid=1042,fd=21))If the local address column show 0.0.0.0:3080 instead, the Web UI dey every interface, including the public one. Stop am and fix the bind before you do anything else. If ss print the socket but leave the users: field empty, run am with sudo, because e dey hide the process name for socket wey another user own.
When the tunnel refuse to start
SSH go print this and exit:
bind [127.0.0.1]:3080: Address already in use
channel_setup_fwd_listener_tcpip: cannot listen to port: 3080This one concern your laptop, no be the server. Something for your laptop don already hold port 3080, often na old tunnel wey you forget. Choose another local port wey free:
ssh -N -L 3081:127.0.0.1:3080 you@your-vpsNa only the first field change, so now you go browse to http://127.0.0.1:3081 while the harness still dey listen on 3080. The two numbers no need match.
If the tunnel start but browser report refused connection or empty reply, the traffic don cross go the VPS but e find nothing for the far end. Either dsh don exit, or e bind another port. Check with ss -ltnp | grep 3080 for the server.
One more thing dey catch people here. Foreground npx @deepseek-ai/dsh web go die when its shell close, so the harness go stop immediately you log out. Start am inside tmux or under a systemd user service. Na the same problem wey dem solve for keeping coding agent running for VPS. While you dey work on the SSH side, hardening SSH for your VPS worth doing first, because the tunnel make your SSH login the only door to the agent.
Reach am through private overlay network
Overlay network dey give your VPS and laptop addresses for private network wey na only your devices fit join. Tailscale na common choice, and e serve command fit this case exactly: tailscaled dey run for the VPS and connect to localhost:3080 by itself, so the harness remain for loopback and you no need change anything about how dem configure dsh.
tailscale serve --bg localhost:3080
tailscale serve statusYou fit reach the UI through your machine name inside your tailnet, over HTTPS, and no port go open for the public interface. This one need HTTPS certificates make dem enable am for your tailnet; otherwise serve no get certificate to present. To bring am down again, run the command again with off:
tailscale serve --https=443 offUse serve, never funnel. Funnel dey publish the same target to public internet, and this one go return you to unauthenticated agent runtime for open port. The two commands look almost the same but dem dey do opposite things, so read the difference between Tailscale Serve and Funnel before you type either one. Tailscale as private network explain the setup itself.
Reach am through reverse proxy wey dey check password
Na this option genuinely dey publish one port to internet, so na only authentication dey between stranger and command execution for your server. Choose am when several people need the UI and e no practical to give each person one tunnel.
The harness still dey for 127.0.0.1:3080. nginx dey run for the same box, so e fit reach loopback, and e dey listen for 443 with certificate and password file.
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;
}
}Create the password file and reload:
sudo apt install -y apache2-utils
sudo htpasswd -c /etc/nginx/dsh.htpasswd you
sudo nginx -t && sudo systemctl reload nginxnginx -t suppose print syntax is ok followed by test is successful. If file spoil, reload go fail and the running configuration go remain active, so read the error instead of restarting blindly.
Three of those proxy lines no be decoration. The Upgrade and Connection headers allow the WebSocket handshake pass, and without dem the page go load but e no go update again. proxy_read_timeout 3600s replaces the 60 second default. Without am, e fit cut long agent run halfway through response and make the UI look frozen. proxy_buffering off sends model output go browser as e dey arrive instead of holding am until response complete. nginx reverse proxy config, line by line explains the remaining parts, and how to choose between nginx, Caddy and Traefik explains how to do the same thing with automatic certificates.
Keep 3080 closed for firewall no matter which proxy you choose, so the only way enter na through the one wey require authentication. ufw firewall basics explains the rules. Basic authentication over TLS na minimum protection, no be complete security model: anybody wey get that password get shell access to your server. Prefer the tunnel whenever you fit.
How I fit change the port wey dsh web dey listen on?
--port belong to the web application, no be launcher. The CLI documentation give the example directly:
dsh --profile web --port 8080dsh web na alias of --profile web, so dsh web --port 8080 na the same command. The launcher dey parse only im own flags, then e hand everything after dem to the profile wey e boot. So launcher flags go first, and the first token wey launcher no recognise na where the application arguments start. Put --port after the profile, never before am.
Read the URL wey the command print instead of assuming am, because that line show the address wey server actually bind to. Then update the last field of your tunnel make e match:
ssh -N -L 3080:127.0.0.1:8080 you@your-vpsFor permanent change, the port dey inside the profile configuration instead of command line. The web and headless profiles auto-initialise the first time you use dem from shipped templates, under ~/.dsh. That same directory na where your API key and model endpoint settings dey, so how to configure dsh keys, models and endpoints na the companion read wey you need when you dey edit these files anyway. To see wetin actually dey active after all the layers don combine:
dsh --dump-configThe webserver plugin expose exactly two keys, host and port. If you set port to 0, e ask the operating system for free port, documented as "zero requests an OS-assigned port". This guarantee say conflict no go happen, but e no good for tunnel because the number go change every time you restart.
Why dsh dey fail with address already in use?
Na because another process don already hold that address and port, so kernel no go allow the second bind. Node dey report am like this:
Error: listen EADDRINUSE: address already in use 127.0.0.1:3080Find the process wey dey hold am before you change anything:
sudo ss -ltnp | grep 3080The users:(("node",pid=1042,fd=21)) field show the process and im PID. Usually, na an earlier dsh wey you think say don stop, but e still dey alive inside detached tmux window. Stop that one with kill 1042, or start the new instance for another port. Note say 127.0.0.1:3080 and 0.0.0.0:3080 still go collide with each other, because binding all interfaces already cover loopback.
Fixa version, porque na developer preview
README talk am clear: DeepSeek Harness dey developer preview and dem dey change am fast, so compatibility-breaking changes go happen. If na this speed dey make you hesitate, how dsh dey compare with Claude Code and Omnigent compare am with two harnesses wey dey different points for the same curve.
npx @deepseek-ai/dsh web dey resolve to the newest published version every time you run am. Server wey you never touch for one week fit start different CLI the next time e launch, with different flags. Fixa the version so restart no turn upgrade:
npx @deepseek-ai/dsh@0.1.0-rc.7 webAs of August 2026, the published package na version 0.1.0-rc.7. Check wetin bare npx go pull before you accept am:
npm view @deepseek-ai/dsh versionIf the pin no gree install, or npx still dey start the old build after you pin new one, the install and version errors wey this dey throw explain how to clear npx cache and check which npm your Node bundle get.
Flags dey move between the launcher and the web application across preview releases. If --port stop to behave the way this guide describe, ask the application for its own flag list instead make you guess:
dsh --profile web --helpFor the install, workspace setup, and model key, see how to install DeepSeek Harness for a VPS. For shorter walkthrough of only the access step, how to reach dsh Web UI for a VPS cover the tunnel without the reasoning.
FAQ
Why I no fit open http://127.0.0.1:3080 for my laptop browser?
Because 127.0.0.1 mean the machine wey you dey type from. The DeepSeek Harness Web UI dey bound to the VPS loopback address, so na only processes for the VPS fit connect to am. Your laptop get its own separate loopback, and nothing dey listen on port 3080 there. Forward the port through SSH with ssh -N -L 3080:127.0.0.1:3080 you@your-vps, then load http://127.0.0.1:3080 locally. The middle field for the -L argument dey resolve for the server side, and na wetin make am point to the harness.
E safe to bind dsh Web UI to 0.0.0.0 for public VPS?
No. The Web UI na the control surface for an agent wey dey run shell commands and edit files as the user wey dey run dsh, and the developer preview no get login screen at all. If you bind am to all interfaces for public IP, anybody wey reach port 3080 fit execute commands for your server. Keep the bind for 127.0.0.1, keep 3080 closed for firewall, and use SSH tunnel, private overlay network, or reverse proxy wey require password.
How I fit keep dsh Web UI running after I close my SSH session?
A foreground npx @deepseek-ai/dsh web na child process of your login shell, so e go die when that shell comot. Start am inside tmux session and detach with Ctrl-b d, or run am as systemd user service with lingering enabled. The tunnel and the harness dey independent: you fit drop and rebuild the SSH tunnel as many times as you like without touching the running harness, as long as the harness itself get parent wey go outlive your login.
Why dsh Web UI dey freeze halfway through long agent run behind nginx?
Because nginx default proxy_read_timeout na 60 seconds, so e dey close connection wey no produce data for one minute, and long agent step fit easily do that. Set proxy_read_timeout 3600s; inside the location block. Add proxy_buffering off; so output go stream to the browser as e dey arrive, and pass the Upgrade and Connection headers with proxy_http_version 1.1; so the WebSocket handshake go succeed. Without those headers, the page go load but e no go ever receive update.