دلیل نمایش http://127.0.0.1:3080 در dsh چیست؟
اگر dsh آدرس http://127.0.0.1:3080 را نمایش میدهد به این معناست که رابط وب فقط روی localhost فعال است. برای دسترسی امن از راه دور، از SSH tunnel استفاده کنید.
معنای 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 متصل (bind) شده باشد، فقط اتصالات را از پردازشهای موجود روی همان ماشین میپذیرد و نه از هیچ جای دیگر. بنابراین آن خط دو نکته را همزمان به شما میگوید: رابط کاربری وب در کجا گوش میدهد (listening) و چه کسی اجازه دسترسی به آن را دارد. فقط ماشینی که dsh روی آن در حال اجراست.
به همین دلیل است که وقتی URL را در مرورگر لپتاپ خود کپی میکنید، هیچ اتفاقی نمیافتد. 127.0.0.1 لپتاپ شما، خودِ لپتاپ شماست. اما Harness روی 127.0.0.1 سرور VPS گوش میدهد که ماشینی متفاوت با پشتهٔ loopback متفاوت است. هیچ مشکلی وجود ندارد. شما باید اتصال را به آن سمت منتقل کنید.
فایل README رسمی، مقدار پیشفرض را بهصراحت بیان میکند: «این دستور رابط کاربری وب را اجرا میکند که بهصورت پیشفرض روی http://127.0.0.1:3080 سرویسدهی میشود.» آدرس bind از پلاگین میزبان وبسرور یعنی @deepseek-ai/dsh-host-webserver میآید که کلید host آن در مستندات به این صورت تعریف شده است: «میزبان گوشدهنده (Listen host)؛ دو مقدار پشتیبانیشده عبارتند از loopback و all-interfaces». تا زمانی که آن را تغییر ندهید، مقدار پیشفرض همان loopback است. اگر مفهوم پورتها برای شما جدید است، نحوه عملکرد پورتها در لینوکس مدل آدرس-بهعلاوه-پورت را که پایه و اساس این موضوع است، پوشش میدهد.
چرا رابط کاربری وب فقط روی localhost متصل میشود
dsh یک ابزار واسط (agent harness) است که در واقع برنامهای است که مدل را در بر میگیرد: این برنامه مدیریت حلقه اجرا، فراخوانی ابزارها و مجوزهایی که این فراخوانیها تحت آنها اجرا میشوند را بر عهده دارد. زبانه مرورگر، یک سطح کنترل برای فرآیندی است که دستورات shell را اجرا میکند، فایلها را در دایرکتوری کاری انتخابی شما میخواند و مینویسد، و از کلید API مدل شما استفاده میکند. هر کسی که بتواند آن صفحه را بارگذاری کند، میتواند تمام این کارها را به عنوان کاربری که dsh را اجرا میکند، انجام دهد. شبکه تنها راه دسترسی به این سطح از دسترسی نیست: پلاگینی که نصب میکنید در همان فرآیند و با همان مجوزها اجرا میشود؛ به همین دلیل است که بررسی دقیق پلاگین dsh پیش از نصب به همان اندازه اهمیت دارد که تصمیمگیری درباره اینکه سرور روی چه پورتی گوش دهد.
بنابراین پورت 3080 یک داشبورد فقطخواندنی نیست. بارگذاری آن صفحه به معنای اجرای دستورات روی سرور است.
رابط کاربری وب را باز میکنید و مستقیماً وارد لیست نشستها میشوید. هیچ صفحه ورود به سیستمی وجود ندارد، زیرا نسخه پیشنمایش توسعهدهنده فاقد حساب کاربری و احراز هویت از راه دور است. در حالت loopback این موضوع منطقی است: سیستمعامل کنترل دسترسی را بر عهده دارد و فقط فرآیندهای محلی اجازه عبور دارند. اگر همین سرور را روی 0.0.0.0 در یک VPS با IP عمومی متصل کنید، همان صفحه به کل اینترنت پاسخ میدهد، بدون اینکه هیچ محافظی جلوی آن باشد. اسکنرهای خودکار بهطور مداوم پورتهای غیرمعمول را بررسی میکنند، بنابراین فرض کنید که پورت 3080 در صورت عمومی شدن، بلافاصله پیدا خواهد شد.
پورت 3080 را در فایروال خود باز نکنید و وبسرورhostرا روی0.0.0.0در یک VPS عمومی تنظیم نکنید. این ترکیب باعث میشود که اجرای دستورات روی سرور شما به اولین کسی که متصل شود، واگذار گردد.
همین استدلال برای هر محیط اجرای عاملی (agent runtime) که روی سرور قرار میدهید صدق میکند، و به همین دلیل است که اجرای ایمن یک عامل برنامهنویسی روی VPS با همان قانون شروع میشود: پورت کنترل عامل باید خصوصی باقی بماند و دسترسی به آن باید از طریق ابزاری که به آن اعتماد دارید انجام شود.
چگونه رابط کاربری وب dsh را از لپتاپ خود باز کنم؟
سه روش مطمئن وجود دارد و در هر کدام از آنها، harness همچنان به loopback محدود باقی میماند.
- یک تونل SSH. هیچ سرویس جدیدی روی رابط عمومی (public interface) گوش نمیدهد و شما از قبل اعتبارنامههای لازم را دارید. این روشی است که باید استفاده کنید.
- یک شبکه overlay خصوصی، تا رابط کاربری از دستگاههای خودتان قابل دسترسی باشد و برای دیگران نامرئی بماند.
- یک reverse proxy که TLS (امنیت لایه انتقال) را خاتمه میدهد و پیش از ارسال هر درخواستی، درخواست رمز عبور میکند.
تفاوت این روشها در نحوه هدایت مرورگر شما به loopback است. در هیچکدام از این روشها نباید harness را از روی loopback منتقل کنید.
دسترسی به آن از طریق SSH tunnel
این دستور را روی لپتاپ خود اجرا کنید، نه روی 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 و پس از رسیدن ترافیک شما به آنجا، ترجمه (resolve) میشود. این یعنی loopback مربوط به VPS، نه لپتاپ شما. این دقیقاً همان آدرسی است که dsh چاپ میکند و به همین دلیل است که وقتی اتصال مستقیم مرورگر کار نمیکند، این tunnel کار میکند.
-N به SSH میگوید که هیچ دستور از راه دوری را اجرا نکند، بنابراین شما فقط یک forwarder دریافت میکنید و نه یک shell. برای یک tunnel در پسزمینه که به جای سکوت، در صورت شکست با صدای بلند خطا میدهد:
ssh -N -f -o ExitOnForwardFailure=yes -o ServerAliveInterval=30 -L 3080:127.0.0.1:3080 you@your-vps-f پس از احراز هویت، آن را به پسزمینه میفرستد. ExitOnForwardFailure=yes اهمیت بیشتری از آنچه به نظر میرسد دارد: بدون آن، SSH حتی زمانی که forward نتواند تنظیم شود با موفقیت متصل میشود، بنابراین شما یک session فعال خواهید داشت اما tunnel بدون هیچ هشداری از کار افتاده است. ServerAliveInterval=30 هر 30 ثانیه یک keepalive ارسال میکند تا یک tunnel غیرفعال، از timeoutهای NAT (ترجمه آدرس شبکه) در روترهای کافهها و هتلها جان سالم به در ببرد.
آنچه باید ببینید
روی 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 را نشان میدهد، رابط کاربری وب روی تمام رابطها (interfaceها) از جمله رابط عمومی در دسترس است. قبل از انجام هر کار دیگری، آن را متوقف کرده و bind را اصلاح کنید. اگر ss سوکت را چاپ میکند اما فیلد users: را خالی میگذارد، آن را با sudo اجرا کنید، زیرا در غیر این صورت نام پردازش برای سوکتی که متعلق به کاربر دیگری است، مخفی میماند.
وقتی tunnel از شروع امتناع میکند
SSH این را چاپ کرده و خارج میشود:
bind [127.0.0.1]:3080: Address already in use
channel_setup_fwd_listener_tcpip: cannot listen to port: 3080این مشکل مربوط به لپتاپ شماست، نه سرور. چیزی در سیستم محلی شما از قبل پورت 3080 را اشغال کرده است، که اغلب یک tunnel قدیمی است که فراموش کردهاید. به جای آن یک پورت محلی آزاد انتخاب کنید:
ssh -N -L 3081:127.0.0.1:3080 you@your-vpsفقط فیلد اول تغییر کرد، بنابراین اکنون به http://127.0.0.1:3081 میروید در حالی که harness همچنان روی 3080 گوش میدهد. این دو عدد هرگز نیازی ندارند که با هم مطابقت داشته باشند.
اگر tunnel بالا میآید اما مرورگر گزارش میدهد که اتصال رد شده یا پاسخ خالی است، ترافیک به VPS رسیده اما در مقصد چیزی پیدا نکرده است. یا dsh خارج شده است، یا پورت دیگری را bind کرده است. با ss -ltnp | grep 3080 روی سرور بررسی کنید.
یک نکته دیگر که کاربران را در اینجا دچار مشکل میکند: یک npx @deepseek-ai/dsh web در پیشزمینه با بسته شدن shell از بین میرود، بنابراین به محض اینکه log out کنید، harness متوقف میشود. آن را داخل tmux یا تحت یک systemd user service شروع کنید، که همان مشکلی است که در نگه داشتن یک coding agent در حال اجرا روی VPS حل شده است. در حالی که روی بخش SSH کار میکنید، ایمنسازی SSH روی VPS ارزش انجام دادن دارد، زیرا tunnel باعث میشود ورود SSH شما تنها درِ ورودی به agent باشد.
دسترسی از طریق یک شبکه overlay خصوصی
یک شبکه overlay به VPS و لپتاپ شما آدرسهایی در یک شبکه خصوصی میدهد که فقط دستگاههای شما به آن متصل میشوند. Tailscale انتخاب رایجی است و دستور serve آن دقیقاً برای این مورد مناسب است: tailscaled روی VPS اجرا شده و به localhost:3080 متصل میشود، بنابراین harness روی loopback باقی میماند و شما هیچ تغییری در نحوه پیکربندی dsh ایجاد نمیکنید.
tailscale serve --bg localhost:3080
tailscale serve statusدر این حالت، رابط کاربری از طریق نام دستگاه شما در tailnet و با پروتکل HTTPS قابل دسترسی است، بدون اینکه پورتی روی اینترفیس عمومی باز باشد. این کار مستلزم فعال بودن گواهیهای HTTPS برای tailnet شماست، در غیر این صورت serve گواهی معتبری برای ارائه نخواهد داشت. برای غیرفعال کردن آن، دستور را با off تکرار کنید:
tailscale serve --https=443 offاز serve استفاده کنید، هرگز از funnel استفاده نکنید. Funnel همان مقصد را در اینترنت عمومی منتشر میکند که شما را دوباره به وضعیت یک agent runtime احراز هویتنشده روی یک پورت باز برمیگرداند. این دو دستور تقریباً یکسان به نظر میرسند اما عملکردهای متضادی دارند، بنابراین پیش از تایپ هر کدام، تفاوت بین Tailscale Serve و Funnel را مطالعه کنید. Tailscale به عنوان یک شبکه خصوصی به نحوه راهاندازی آن میپردازد.
دسترسی از طریق یک reverse proxy با احراز هویت رمز عبور
این گزینهای است که در واقع یک پورت را روی اینترنت منتشر میکند، بنابراین احراز هویت تنها مانع بین یک غریبه و اجرای دستورات روی سرور شماست. زمانی این روش را انتخاب کنید که چندین نفر به رابط کاربری نیاز دارند و ایجاد تونل برای هر کدام غیرعملی است.
برنامه اصلی روی 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;
}
}فایل رمز عبور را ایجاد کرده و تنظیمات را reload کنید:
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 را چاپ کند. reload کردن با یک فایل خراب، با شکست مواجه میشود و پیکربندی در حال اجرا را دستنخورده باقی میگذارد؛ بنابراین بهجای restart کورکورانه، خطا را بخوانید.
سه مورد از آن خطوط proxy صرفاً برای تزئین نیستند. هدرهای Upgrade و Connection اجازه میدهند handshake مربوط به WebSocket انجام شود و بدون آنها، صفحه بارگذاری میشود اما هرگز بهروزرسانی نمیشود. proxy_read_timeout 3600s جایگزین پیشفرض 60 ثانیهای میشود که در غیر این صورت، اجرای طولانیمدت agent را در میانه پاسخ قطع کرده و رابط کاربری را منجمد نشان میدهد. proxy_buffering off خروجی مدل را بهمحض رسیدن به مرورگر میفرستد، بهجای آنکه آن را تا تکمیل پاسخ نگه دارد. پیکربندی nginx reverse proxy، خط به خط بقیه موارد را توضیح میدهد و انتخاب بین nginx، Caddy و Traefik انجام همین کار با گواهیهای خودکار را پوشش میدهد.
صرفنظر از اینکه کدام proxy را انتخاب میکنید، پورت 3080 را در فایروال بسته نگه دارید تا تنها مسیر ورود، از طریق مسیر احراز هویتشده باشد. اصول فایروال ufw قوانین مربوطه را پوشش میدهد. احراز هویت پایه (Basic authentication) روی TLS یک حداقل است، نه یک مدل امنیتی کامل: هر کسی که آن رمز عبور را داشته باشد، به یک shell روی سرور شما دسترسی دارد. هر زمان که میتوانید، استفاده از تونل را در اولویت قرار دهید.
چگونه میتوانم پورتی که dsh web روی آن گوش میدهد را تغییر دهم؟
--port متعلق به اپلیکیشن وب است، نه لانچر. مستندات CLI این مثال را مستقیماً ارائه میدهد:
dsh --profile web --port 8080dsh web یک نام مستعار برای --profile web است، بنابراین dsh web --port 8080 همان دستور است. لانچر فقط پرچمهای (flags) مربوط به خود را تجزیه میکند و هر چیزی که پس از آنها بیاید را به پروفایل در حال اجرا تحویل میدهد. بنابراین پرچمهای لانچر باید در ابتدا قرار بگیرند و اولین توکنی که لانچر تشخیص نمیدهد، شروع آرگومانهای اپلیکیشن است. --port را بعد از پروفایل قرار دهید، هرگز قبل از آن نگذارید.
به جای فرض کردن، URL چاپ شده توسط دستور را بخوانید، زیرا آن خط آدرسی که سرور واقعاً به آن متصل شده است را گزارش میکند. سپس آخرین فیلد تونل خود را مطابق با آن بهروزرسانی کنید:
ssh -N -L 3080:127.0.0.1:8080 you@your-vpsبرای تغییر دائمی، پورت به جای خط فرمان، در پیکربندی پروفایل قرار دارد. پروفایلهای web و headless در اولین استفاده از قالبهای پیشفرض، در مسیر ~/.dsh بهطور خودکار مقداردهی اولیه میشوند. همان دایرکتوری جایی است که کلید API و تنظیمات endpoint مدل شما در آن قرار دارند، بنابراین پیکربندی کلیدها، مدلها و endpointهای 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 جداشده (detached) در حال اجراست. آن را با kill 1042 متوقف کنید یا نمونه جدید را روی پورت دیگری اجرا نمایید. توجه داشته باشید که 127.0.0.1:3080 و 0.0.0.0:3080 نیز با یکدیگر تداخل دارند، زیرا bind کردن روی تمامی اینترفیسها، شامل loopback نیز میشود.
نسخه را ثابت کنید، زیرا این یک پیشنمایش توسعهدهنده است
فایل README در این مورد صریح است: DeepSeek Harness در مرحله پیشنمایش توسعهدهنده قرار دارد و بهسرعت در حال تغییر است، بنابراین تغییرات ناسازگار با نسخههای قبلی رخ خواهد داد. اگر این سرعتِ تغییر دلیلی است که باعث تردید شما شده، مقایسه dsh با Claude Code و Omnigent آن را در برابر دو ابزار مشابه در مراحل مختلفِ توسعه بررسی میکند.
npx @deepseek-ai/dsh web هر بار که آن را اجرا میکنید، به جدیدترین نسخه منتشرشده متصل میشود. سروری که یک هفته به آن دست نزدهاید، ممکن است در اجرای بعدی، CLI متفاوتی را با فلگهای متفاوت بالا بیاورد. نسخه را ثابت (Pin) کنید تا راهاندازی مجدد به معنای ارتقا نباشد:
npx @deepseek-ai/dsh@0.1.0-rc.7 webتا آگوست 2026، بسته منتشرشده نسخه 0.1.0-rc.7 است. بررسی کنید که یک npx ساده قبل از پذیرش، چه نسخهای را دریافت میکند:
npm view @deepseek-ai/dsh versionاگر نصب نسخه ثابتشده با خطا مواجه شد، یا npx پس از ثابت کردن نسخه جدید همچنان نسخه قدیمی را اجرا میکند، خطاهای نصب و نسخه نحوه پاکسازی کش npx و بررسی اینکه کدام npm توسط Node شما استفاده میشود را توضیح میدهد.
فلگها در نسخههای پیشنمایش بین لانچر و اپلیکیشن وب جابهجا میشوند. اگر --port دیگر مطابق آنچه در این راهنما توضیح داده شده عمل نمیکند، بهجای حدس زدن، از خود اپلیکیشن لیست فلگهایش را بخواهید:
dsh --profile web --helpبرای خودِ نصب، تنظیمات محیط کاری (workspace) و کلید مدل، به نصب DeepSeek Harness روی VPS مراجعه کنید. برای یک راهنمای کوتاهتر فقط در مورد مرحله دسترسی، دسترسی به رابط وب dsh روی VPS تونلزنی را بدون توضیحات اضافه پوشش میدهد.
FAQ
چرا نمیتوانم http://127.0.0.1:3080 را در مرورگر لپتاپ خود باز کنم؟
زیرا 127.0.0.1 به معنای ماشینی است که پشت آن نشستهاید. رابط کاربری وب DeepSeek Harness به آدرس loopback در VPS متصل (bind) شده است، بنابراین فقط پردازشهای روی همان 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، یک شبکه خصوصی (overlay network) یا یک reverse proxy که نیاز به رمز عبور دارد، استفاده کنید.
چگونه رابط کاربری وب dsh را پس از بستن نشست SSH فعال نگه دارم؟
یک npx @deepseek-ai/dsh web که در پیشزمینه اجرا میشود، فرزند shell ورود شماست و با خروج از آن shell، کشته میشود. آن را درون یک نشست tmux اجرا کرده و با Ctrl-b d جدا (detach) شوید، یا آن را بهعنوان یک سرویس کاربری systemd با فعالسازی lingering اجرا کنید. تونل و harness مستقل از یکدیگر هستند: شما میتوانید تونل SSH را هر چند بار که بخواهید قطع و وصل کنید بدون اینکه harness در حال اجرا متوقف شود، به شرطی که harness والد پایداری داشته باشد که پس از خروج شما از سیستم همچنان فعال بماند.
چرا رابط کاربری وب dsh هنگام اجرای طولانیمدت عامل (agent) پشت nginx متوقف (freeze) میشود؟
زیرا مقدار پیشفرض proxy_read_timeout در nginx برابر با 60 ثانیه است؛ بنابراین اگر اتصالی به مدت یک دقیقه دادهای ارسال نکند، nginx آن را میبندد، اتفاقی که در مراحل طولانی اجرای عامل بهراحتی رخ میدهد. مقدار proxy_read_timeout 3600s; را در بلوک location تنظیم کنید. proxy_buffering off; را اضافه کنید تا خروجی بهمحض تولید، به مرورگر ارسال شود و هدرهای Upgrade و Connection را با proxy_http_version 1.1; ارسال کنید تا handshake مربوط به WebSocket با موفقیت انجام شود. بدون این هدرها، صفحه بارگذاری میشود اما هرگز بهروزرسانی دریافت نمیکند.