Почему DeepSeek Harness выводит http://127.0.0.1:3080
DeepSeek Harness по умолчанию привязывает веб-интерфейс к адресу 127.0.0.1. Это означает, что доступ к панели возможен только через SSH-туннель. Публикация порта 3080 небезопасна.
Что означает dsh web: http://127.0.0.1:3080
Когда вы запускаете веб-профиль DeepSeek Harness на VPS, он выводит две строки и переходит в режим ожидания:
dsh web: http://127.0.0.1:3080
Ready.127.0.0.1 — это адрес обратной петли (loopback). Этот адрес машина использует для связи с самой собой. Сокет, привязанный к 127.0.0.1, принимает соединения только от процессов на этой же машине и ниоткуда больше. Таким образом, эта строка сообщает вам две вещи одновременно: где прослушивается веб-интерфейс и кому разрешено к нему обращаться. Только той машине, на которой запущен dsh.
Именно поэтому URL не работает, когда вы вставляете его в браузер на своем ноутбуке. 127.0.0.1 вашего ноутбука — это сам ноутбук. Harness прослушивает 127.0.0.1 на VPS, а это другая машина с другим стеком loopback. Ничего не сломано. Вам нужно перенаправить соединение.
В официальном README значение по умолчанию указано прямо: "Команда запускает веб-интерфейс, который по умолчанию доступен по адресу http://127.0.0.1:3080". Адрес привязки берется из плагина веб-сервера @deepseek-ai/dsh-host-webserver, чей ключ host описан как "Хост для прослушивания; поддерживаются два значения: loopback и all-interfaces". Loopback используется по умолчанию, если вы не измените это значение. Если работа с портами для вас в новинку, в статье как работают порты в Linux описана модель «адрес плюс порт», на которой всё это базируется.
Почему веб-интерфейс привязывается только к localhost
dsh — это среда выполнения агента. Вкладка браузера служит панелью управления для процесса, который выполняет shell-команды, читает и записывает файлы в выбранной рабочей директории, а также расходует ваш API-ключ модели. Любой, кто может открыть эту страницу, получает все эти возможности от имени пользователя, под которым запущен dsh.
Таким образом, порт 3080 — это не просто панель мониторинга для чтения. Загрузка этой страницы дает возможность выполнения команд на сервере.
При открытии веб-интерфейса вы сразу попадаете в список сессий. Запроса на вход нет, так как в developer preview не реализованы учетные записи пользователей и удаленная аутентификация. При работе через loopback это безопасно: операционная система выступает в роли контроля доступа, и доступ получают только локальные процессы. Если привязать этот же сервер к 0.0.0.0 на VPS с публичным IP, та же самая страница станет доступна всему интернету без какой-либо защиты. Автоматизированные сканеры постоянно проверяют редкие порты, поэтому считайте, что опубликованный порт 3080 будет обнаружен немедленно.
Не открывайте порт 3080 в вашем брандмауэре и не устанавливайте для веб-сервераhostзначение0.0.0.0на публичном VPS. Такая комбинация передает права на выполнение команд на вашем сервере любому, кто подключится первым.
Те же рассуждения применимы к любой среде выполнения агентов, которую вы размещаете на сервере. Именно поэтому руководство по безопасному запуску агента для программирования на VPS начинается с того же правила: управляющий порт агента должен оставаться приватным, а доступ к нему должен осуществляться через доверенный промежуточный узел.
Как открыть веб-интерфейс dsh с моего ноутбука?
Существует три надежных способа, и каждый из них оставляет harness привязанным к loopback.
- SSH-туннель. Никакие новые службы не прослушивают публичный интерфейс, а учетные данные у вас уже есть. Это рекомендуемый вариант.
- Частная оверлейная сеть, благодаря которой интерфейс доступен с ваших устройств и невидим для всех остальных.
- Reverse proxy, который выполняет TLS (transport layer security) termination и запрашивает пароль перед пересылкой любого запроса.
Разница между ними заключается в способе доставки трафика из вашего браузера на loopback. Ни один из этих методов не требует переноса harness с loopback.
Доступ через SSH-туннель
Выполните эту команду на своем ноутбуке, а не на VPS:
ssh -N -L 3080:127.0.0.1:3080 you@your-vpsОставьте процесс запущенным, затем откройте http://127.0.0.1:3080 в локальном браузере. Веб-интерфейс загрузится.
Аргумент -L содержит три поля, разделенных двоеточиями. Первое — порт, который будет открыт на вашем ноутбуке. Второе и третье — адрес и порт, на которые перенаправляется каждое соединение. Важная деталь: 127.0.0.1 в среднем поле разрешается SSH-сервером на VPS уже после того, как трафик туда поступил. Это означает loopback-интерфейс VPS, а не вашего компьютера. Именно этот адрес выводит dsh, поэтому туннель работает, а прямое подключение из браузера — нет.
-N указывает SSH не выполнять удаленную команду, поэтому вы получаете только перенаправление портов без интерактивной оболочки. Для фонового туннеля, который сообщает об ошибках, а не молчит:
ssh -N -f -o ExitOnForwardFailure=yes -o ServerAliveInterval=30 -L 3080:127.0.0.1:3080 you@your-vps-f переводит процесс в фоновый режим после аутентификации. ExitOnForwardFailure=yes важнее, чем кажется: без этого флага SSH успешно установит соединение, даже если перенаправление настроить не удалось. В результате вы получите рабочую сессию и неработающий туннель без каких-либо предупреждений. ServerAliveInterval=30 отправляет keepalive-пакеты каждые 30 секунд, чтобы простаивающий туннель не разрывался из-за таймаутов NAT (network address translation) в сетях кафе или отелей.
Что вы должны увидеть
На VPS проверьте, какой именно адрес прослушивается:
ss -ltnp | grep 3080Корректный результат указывает на loopback-адрес:
LISTEN 0 511 127.0.0.1:3080 0.0.0.0:* users:(("node",pid=1042,fd=21))Если в столбце локального адреса указано 0.0.0.0:3080, значит, веб-интерфейс доступен на всех интерфейсах, включая публичный. Остановите его и исправьте привязку (bind), прежде чем продолжать. Если ss показывает сокет, но поле users: пустое, запустите команду с sudo, так как в противном случае имя процесса для сокета, принадлежащего другому пользователю, будет скрыто.
Если туннель не запускается
SSH выводит следующее сообщение и завершает работу:
bind [127.0.0.1]:3080: Address already in use
channel_setup_fwd_listener_tcpip: cannot listen to port: 3080Проблема на стороне вашего ноутбука, а не сервера. Какой-то локальный процесс уже занял порт 3080, часто это забытый ранее запущенный туннель. Выберите другой свободный локальный порт:
ssh -N -L 3081:127.0.0.1:3080 you@your-vpsИзменилось только первое поле, поэтому теперь переходите по адресу http://127.0.0.1:3081, в то время как сервис продолжает слушать порт 3080. Эти два числа не обязаны совпадать.
Если туннель поднялся, но браузер сообщает об отказе в соединении или пустом ответе, значит, трафик дошел до VPS, но на той стороне ничего не обнаружено. Либо процесс dsh завершился, либо он привязался к другому порту. Проверьте это с помощью ss -ltnp | grep 3080 на сервере.
Есть еще один нюанс. Фоновый процесс npx @deepseek-ai/dsh web завершается при закрытии оболочки, поэтому туннель остановится, как только вы выйдете из системы. Запускайте его внутри tmux или как пользовательский systemd-сервис — это та же задача, что описана в поддержании работы агента на VPS. Пока вы занимаетесь настройкой SSH, стоит сначала выполнить укрепление безопасности SSH на VPS, так как туннель делает ваш SSH-логин единственной точкой входа к агенту.
Доступ через частную оверлейную сеть
Оверлейная сеть предоставляет вашему VPS и ноутбуку адреса в частной сети, к которой подключаются только ваши устройства. Tailscale является популярным выбором, и его команда serve идеально подходит для этого случая: tailscaled запускается на VPS и подключается к localhost:3080, поэтому обвязка остается на loopback, и вам не нужно менять настройки dsh.
tailscale serve --bg localhost:3080
tailscale serve statusИнтерфейс становится доступен по имени вашей машины внутри tailnet по протоколу HTTPS, при этом порты на публичном интерфейсе остаются закрытыми. Для этого в вашем tailnet должны быть включены HTTPS-сертификаты, иначе serve не сможет предоставить сертификат. Чтобы отключить доступ, повторите команду с off:
tailscale serve --https=443 offИспользуйте serve, никогда не используйте funnel. Funnel публикует ту же цель в публичный интернет, что возвращает вас к неаутентифицированной среде выполнения агента на открытом порту. Эти две команды выглядят почти одинаково, но выполняют противоположные действия, поэтому ознакомьтесь с разницей между Tailscale Serve и Funnel перед вводом любой из них. В Tailscale как частная сеть описана настройка самой сети.
Доступ через обратный прокси с проверкой пароля
Это вариант, который действительно открывает порт в интернет, поэтому аутентификация — единственное препятствие между посторонним лицом и выполнением команд на вашем сервере. Выбирайте его, когда доступ к интерфейсу нужен нескольким пользователям, а создание отдельного туннеля для каждого нецелесообразно.
Harness остается на 127.0.0.1:3080. nginx работает на том же узле, поэтому он может обращаться к loopback и слушает порт 443 с использованием сертификата и файла паролей.
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;
}
}Создайте файл паролей и перезагрузите конфигурацию:
sudo apt install -y apache2-utils
sudo htpasswd -c /etc/nginx/dsh.htpasswd you
sudo nginx -t && sudo systemctl reload nginxnginx -t должен вывести syntax is ok, а затем test is successful. Перезагрузка с поврежденным файлом завершится ошибкой и сохранит текущую конфигурацию, поэтому читайте текст ошибки, а не перезапускайте сервис вслепую.
Три из этих строк прокси-сервера не являются декоративными. Заголовки Upgrade и Connection пропускают рукопожатие WebSocket, без них страница загружается, но не обновляется. proxy_read_timeout 3600s заменяет стандартное значение в 60 секунд, которое иначе прервет выполнение долгого агента в середине ответа и оставит интерфейс в «зависшем» состоянии. proxy_buffering off отправляет вывод модели в браузер по мере поступления, вместо того чтобы удерживать его до завершения ответа. Построчный разбор конфигурации обратного прокси nginx объясняет остальное, а выбор между nginx, Caddy и Traefik описывает реализацию того же решения с автоматическими сертификатами.
Держите порт 3080 закрытым в брандмауэре независимо от того, какой прокси вы выберете, чтобы единственный путь внутрь проходил через аутентифицированный прокси. Основы работы с брандмауэром ufw описывает правила настройки. Базовая аутентификация поверх TLS — это минимальный уровень, а не законченная модель безопасности: тот, кто владеет этим паролем, владеет оболочкой (shell) на вашем сервере. По возможности отдавайте предпочтение туннелям.
Как изменить порт, на котором прослушивает запросы dsh web?
--port относится к веб-приложению, а не к лаунчеру. В документации CLI приведен прямой пример:
dsh --profile web --port 8080dsh web является псевдонимом --profile web, поэтому dsh web --port 8080 — это та же самая команда. Лаунчер анализирует только свои собственные флаги, а всё, что идет после них, передает загружаемому профилю. Поэтому флаги лаунчера должны стоять первыми, а первый токен, который лаунчер не распознает, начинает аргументы приложения. Размещайте --port после профиля, но никогда не перед ним.
Считывайте URL, который выводит команда, вместо того чтобы предполагать его, так как эта строка сообщает адрес, к которому сервер фактически привязался. Затем обновите последнее поле вашего туннеля, чтобы оно соответствовало:
ssh -N -L 3080:127.0.0.1:8080 you@your-vpsДля постоянного изменения порт указывается в конфигурации профиля, а не в командной строке. Профили web и headless автоматически инициализируются при первом использовании из поставляемых шаблонов, расположенных в ~/.dsh. Чтобы увидеть, что именно действует после объединения всех уровней конфигурации:
dsh --dump-configПлагин веб-сервера предоставляет ровно два ключа: host и port. Установка port в значение 0 запрашивает у операционной системы свободный порт; это задокументировано как «ноль запрашивает порт, назначенный ОС». Это гарантирует отсутствие конфликтов, но плохо подходит для туннеля, так как номер порта меняется при каждом перезапуске.
Почему dsh завершается с ошибкой address already in use?
Это происходит потому, что другой процесс уже занял этот адрес и порт, поэтому ядро отклоняет повторный вызов bind. Node сообщает об этом следующим образом:
Error: listen EADDRINUSE: address already in use 127.0.0.1:3080Прежде чем вносить изменения, найдите процесс, удерживающий порт:
sudo ss -ltnp | grep 3080Поле users:(("node",pid=1042,fd=21)) указывает имя процесса и его PID. Чаще всего причиной является предыдущий экземпляр dsh, который, как вы полагали, был остановлен, но всё ещё работает в отсоединённом окне tmux. Остановите этот процесс с помощью kill 1042 или запустите новый экземпляр на другом порту. Учтите, что 127.0.0.1:3080 и 0.0.0.0:3080 также конфликтуют друг с другом, так как привязка ко всем интерфейсам уже включает в себя loopback.
Закрепите версию, так как это предварительная версия для разработчиков
В README прямо сказано: DeepSeek Harness находится на стадии предварительной версии для разработчиков и быстро развивается, поэтому возможны изменения, нарушающие обратную совместимость.
npx @deepseek-ai/dsh web при каждом запуске обращается к самой новой опубликованной версии. Сервер, к которому вы не обращались неделю, при следующем запуске может запустить другой CLI с другими флагами. Закрепите версию, чтобы перезапуск не приводил к обновлению:
npx @deepseek-ai/dsh@0.1.0-rc.7 webПо состоянию на август 2026 года опубликованный пакет имеет версию 0.1.0-rc.7. Проверьте, что именно загрузит обычный npx, прежде чем подтверждать действие:
npm view @deepseek-ai/dsh versionВ предварительных выпусках флаги перемещаются между загрузчиком и веб-приложением. Если --port перестает вести себя так, как описано в этом руководстве, запросите у самого приложения список его флагов, вместо того чтобы угадывать:
dsh --profile web --helpИнформацию об установке, настройке рабочей области и ключе модели см. в разделе установка DeepSeek Harness на VPS. Более краткое руководство, посвященное только этапу доступа, подключение к веб-интерфейсу dsh на VPS, описывает создание туннеля без пояснений логики работы.
FAQ
Почему я не могу открыть http://127.0.0.1:3080 в браузере на своем ноутбуке?
Потому что 127.0.0.1 означает машину, за которой вы работаете. Веб-интерфейс DeepSeek Harness привязан к loopback-адресу VPS, поэтому к нему могут подключаться только процессы внутри самого VPS. У вашего ноутбука собственный loopback, и на нем никто не слушает порт 3080. Перенаправьте порт через SSH с помощью ssh -N -L 3080:127.0.0.1:3080 you@your-vps, а затем откройте http://127.0.0.1:3080 локально. Среднее поле аргумента -L разрешается на стороне сервера, именно поэтому оно указывает на harness.
Безопасно ли привязывать веб-интерфейс dsh к 0.0.0.0 на публичном VPS?
Нет. Веб-интерфейс — это панель управления агентом, который выполняет shell-команды и редактирует файлы от имени пользователя, запустившего dsh, а предварительная версия для разработчиков не имеет экрана авторизации. Привязка ко всем интерфейсам на публичном IP означает, что любой, кто обратится к порту 3080, получит возможность выполнять команды на вашем сервере. Оставьте привязку на 127.0.0.1, держите порт 3080 закрытым в файрволе и используйте SSH-туннель, частную оверлейную сеть или reverse proxy с обязательной аутентификацией.
Как оставить веб-интерфейс dsh запущенным после закрытия SSH-сессии?
Процесс npx @deepseek-ai/dsh web, запущенный в foreground, является дочерним для вашей оболочки входа, поэтому он завершается при выходе из нее. Запустите его внутри сессии tmux и отсоединитесь с помощью Ctrl-b d, либо запустите его как systemd user service с включенным lingering. Туннель и harness независимы: вы можете разрывать и восстанавливать SSH-туннель сколько угодно раз, не затрагивая работающий harness, если у последнего есть родительский процесс, который продолжает работать после завершения вашей сессии.
Почему веб-интерфейс dsh зависает во время долгого выполнения агента при работе через nginx?
Потому что значение proxy_read_timeout по умолчанию в nginx составляет 60 секунд, поэтому он закрывает соединение, если в течение минуты не передаются данные, что часто случается при длительных шагах агента. Установите proxy_read_timeout 3600s; в блоке location. Добавьте proxy_buffering off;, чтобы вывод передавался в браузер по мере поступления, и передайте заголовки Upgrade и Connection с помощью proxy_http_version 1.1;, чтобы рукопожатие WebSocket завершилось успешно. Без этих заголовков страница загружается, но обновления не приходят.