VPS पर dsh को systemd service के रूप में कैसे चलाएं
VPS पर dsh को headless मोड में चलाने के लिए systemd unit file सेटअप करें। यह गाइड समर्पित user, version pinning, Restart rules और SSH tunnel के माध्यम से UI एक्सेस करना सिखाती है।
VPS पर dsh को headless मोड में चलाना
VPS पर dsh को headless मोड में चलाने के लिए एक systemd unit file और उसे चलाने के लिए एक समर्पित user की आवश्यकता होती है। dsh, DeepSeek Harness के लिए command line launcher है। यह DeepSeek का agent runtime है, जिसे अगस्त 2026 में developer preview के रूप में MIT licence के तहत जारी किया गया था। Harness मॉडल के बजाय मॉडल के चारों ओर का प्रोग्राम होता है, इसलिए आप systemd के अंतर्गत loop, tools और permissions को डाल रहे हैं, न कि DeepSeek के inference को। Quickstart आपको npx @deepseek-ai/dsh web टाइप करने के लिए कहता है, जो सही है, लेकिन आपके द्वारा SSH (secure shell) session बंद करते ही यह बंद हो जाता है।
एक unit file एक साथ चार समस्याओं का समाधान करती है। reboot के बाद service अपने आप चालू हो जाती है। इसका output आपके सामने scroll होने के बजाय journal में चला जाता है। यह root के बजाय एक सामान्य account के रूप में चलती है। और यह वही version चलाती है जिसे आपने चुना है, जो यहाँ सामान्य से अधिक महत्वपूर्ण है, क्योंकि upstream ने इसे बड़े अक्षरों में लिखा है:
DeepSeek Harness वर्तमान में developer preview में है और इसमें तेजी से बदलाव हो रहे हैं। इसमें संगतता तोड़ने वाले (compatibility-breaking) बदलाव होंगे।
यह guide मानती है कि dsh आपके लिए पहले से ही manually काम कर रहा है। यदि ऐसा नहीं है, तो VPS पर DeepSeek Harness इंस्टॉल करने से शुरुआत करें और जब npx @deepseek-ai/dsh web एक page serve करने लगे, तब वापस आएँ।
Node पहले इंस्टॉल करें, क्योंकि npm आपको चेतावनी नहीं देगा
node -vUbuntu 24.04 का अपना पैकेज Node 18 (अगस्त 2026 तक 18.19.1) है, जो इस वर्ष प्रकाशित किसी पैकेज के लिए काफी पुराना है। @deepseek-ai/dsh में कोई engines फ़ील्ड प्रकाशित नहीं होती है, इसलिए जब आपका Node बहुत पुराना होता है तो npm कोई EBADENGINE चेतावनी नहीं देता है। इसके बजाय, विफलता रन-टाइम पर एक सिंटैक्स त्रुटि या किसी इन-बिल्ट फ़ंक्शन की कमी के रूप में सामने आती है, जिसे ढूँढना बहुत अधिक कठिन होता है। NodeSource से वर्तमान लॉन्ग टर्म सपोर्ट (LTS) रिलीज़ इंस्टॉल करें:
curl -fsSL https://deb.nodesource.com/setup_22.x -o /tmp/nodesource_setup.sh
less /tmp/nodesource_setup.sh
sudo -E bash /tmp/nodesource_setup.sh
sudo apt install -y nodejs
node -vnode -v को अब एक v22 वर्शन प्रिंट करना चाहिए। less लाइन इसलिए है क्योंकि रिमोट स्क्रिप्ट को सीधे bash में पाइप करने से ऐसा कोड रन होता है जिसे आपने कभी पढ़ा नहीं है।
Unit लिखने से पहले यह सुनिश्चित करें कि वह चल रहा है
npx @deepseek-ai/dsh@0.1.0-rc.7 webइसे चलते रहने दें। एक दूसरे SSH session से:
curl -fsS http://127.0.0.1:3080/ -o /dev/null && echo upup का अर्थ है कि web profile loopback पर listen कर रहा है, जो कि इसका default bind स्थान है। curl: (7) Failed to connect to 127.0.0.1 port 3080: Connection refused का अर्थ है कि ऐसा नहीं है, और पहला terminal आपको इसका कारण बता रहा है। आगे बढ़ने से पहले Ctrl+C के साथ manual run को रोकें: यदि कोई unit ऐसे port को bind करने का प्रयास करता है जिसे पहले से ही किसी अन्य प्रक्रिया ने ले रखा है, तो वह Error: listen EADDRINUSE: address already in use 127.0.0.1:3080 के साथ fail हो जाएगा।
0.1.0-rc.7, 18 August 2026 को प्रकाशित संस्करण था। npm view @deepseek-ai/dsh version के साथ जाँचें कि वर्तमान में क्या उपलब्ध है, और फिर जिसे आप चलाना चाहते हैं उसे pin करें।
पिन किए गए वर्ज़न को ग्लोबली इंस्टॉल करें
npx यूनिट फाइल के अंदर इस्तेमाल करने के लिए गलत टूल है। यह प्रोसेस शुरू होने पर पैकेज वर्ज़न को रिज़ॉल्व करता है, इसलिए तीन महीने बाद रीस्टार्ट करने पर आपकी तरफ से कोई बदलाव किए बिना ही प्रीव्यू-स्टेज एजेंट का कोई अलग बिल्ड चल सकता है। इसे बूट के समय npm रजिस्ट्री तक पहुँच की भी आवश्यकता होती है, जिससे रजिस्ट्री धीमी होने पर एक सही काम करने वाली मशीन भी फेल यूनिट बन सकती है। एक बार इंस्टॉल करें, उस वर्ज़न पर जिसे आपने नोट किया है:
sudo npm install -g @deepseek-ai/dsh@0.1.0-rc.7
command -v dsh
npm ls -g --depth=0 @deepseek-ai/dshcommand -v dsh तब /usr/bin/dsh प्रिंट करता है जब npm, NodeSource से आया हो, और /usr/local/bin/dsh तब जब यह Ubuntu के अपने पैकेज से आया हो। यूनिट फाइल में उसी पाथ का उपयोग करें जो इसने प्रिंट किया है। npm ls -g सटीक वर्ज़न प्रिंट करता है, जो छह सप्ताह बाद तब काम आता है जब व्यवहार बदल जाता है और आपको याद नहीं रहता कि आपने क्या इंस्टॉल किया था। यदि इंस्टॉलेशन फेल हो जाता है, या command -v dsh बाद में कुछ भी प्रिंट नहीं करता है, या आपको मिलने वाला वर्ज़न वह नहीं है जो आपने मांगा था, तो यूनिट फाइल लिखने से पहले सामान्य dsh इंस्टॉलेशन और वर्ज़न संबंधी त्रुटियों को हल करें।
एक ऐसा user जो केवल service का स्वामी हो और कुछ नहीं
Agent shell commands चलाता है। यही उसका काम है। इसे root के रूप में चलाने का अर्थ है कि हर tool call एक root tool call बन जाती है, इसलिए इसे बिना login shell वाला अपना एक अलग account दें।
sudo useradd --system --create-home --home-dir /var/lib/dsh --shell /usr/sbin/nologin dsh
sudo install -d -o dsh -g dsh -m 750 /var/lib/dsh/harness /var/lib/dsh/workspace
id dsh/var/lib/dsh/harness बदलकर DSH_HOME हो जाता है, जो वह directory है जहाँ dsh profiles रखता है। एक profile plugin bundles का एक named stack होता है, जिसके ऊपर आपकी अपनी patch layer होती है, और web तथा headless profiles पहली बार boot करने पर shipped templates से खुद को build करते हैं। बाद में आप उस stack में जो कुछ भी जोड़ते हैं, वह इस user के रूप में चलता है और उसे agent की अपनी file और shell access प्राप्त होती है, इसलिए install करने से पहले plugin की जाँच करना उसी काम का हिस्सा है जो account बनाना है। वह पहला boot files लिखता है और bundles fetch कर सकता है, इसलिए इसे manually करें जहाँ आप इसे देख सकें।
sudo -u dsh env HOME=/var/lib/dsh DSH_HOME=/var/lib/dsh/harness /usr/bin/dsh --profile webHOME को स्पष्ट रूप से set करें, बजाय इसके कि sudo इसके साथ क्या करता है उस पर भरोसा करें, क्योंकि non-login command के लिए sudo, HOME को rewrite करेगा या नहीं, यह /etc/sudoers में set_home setting पर निर्भर करता है। यदि आप इसे गलत करते हैं, तो पहली run cache directories को आपके home directory में डाल देगी, जिनका स्वामी dsh होगा, और बाद में service अपनी state नहीं ढूँढ पाएगी। जैसे ही curl check up return करे, इसे Ctrl+C के साथ रोक दें।
यूनिट फाइल
/etc/systemd/system/dsh.service लिखें:
[Unit]
Description=DeepSeek Harness (dsh) web profile
Documentation=https://github.com/deepseek-ai/deepseek-harness
After=network-online.target
Wants=network-online.target
StartLimitIntervalSec=300
StartLimitBurst=5
[Service]
Type=exec
User=dsh
Group=dsh
WorkingDirectory=/var/lib/dsh/workspace
Environment=HOME=/var/lib/dsh
Environment=DSH_HOME=/var/lib/dsh/harness
ExecStart=/usr/bin/dsh --profile web
Restart=on-failure
RestartSec=5s
TimeoutStopSec=30s
SyslogIdentifier=dsh
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
ProtectHome=true
[Install]
WantedBy=multi-user.targetExecStart= में वह एब्सोल्यूट पाथ (absolute path) डालें जो आपको command -v dsh से मिला है। systemd एक साधारण कमांड नाम के लिए निश्चित पाथ की सूची में खोज करता है, लेकिन वह सूची आपके शेल के PATH जैसी नहीं होती, इसलिए एब्सोल्यूट पाथ का उपयोग करने से अनिश्चितता खत्म हो जाती है।
WorkingDirectory= वह स्थान है जहाँ रिलेटिव पाथ (relative paths) रिजॉल्व होते हैं, और यहीं से वह टूल कॉल शुरू होता है जो बिना किसी आर्ग्युमेंट के ls चलाता है। इसे उस वर्कस्पेस पर पॉइंट करें जिसे आप एजेंट को देते हैं। यदि वह डायरेक्टरी मौजूद नहीं है या सर्विस यूजर उसमें प्रवेश नहीं कर सकता, तो dsh के चलने से पहले ही सर्विस status=200/CHDIR के साथ फेल हो जाएगी।
ProtectHome=true प्रोसेस से /home और /root को छिपा देता है। यह यहाँ सुरक्षित है क्योंकि सर्विस जिस भी चीज का उपयोग करती है, वह /var/lib/dsh के अंतर्गत ही रहती है। यदि आप वर्कस्पेस को /home के अंतर्गत किसी पाथ पर पॉइंट करेंगे, तो एजेंट रिपोर्ट करेगा कि डायरेक्टरी मौजूद नहीं है, जो तब तक भ्रमित करने वाला लगेगा जब तक आपको यह लाइन याद न आ जाए। ProtectSystem=full, /usr, /boot और /etc को रीड-ओनली बना देता है, जिन्हें सर्विस को कभी भी राइट करने की आवश्यकता नहीं होती।
आगे बढ़ना आकर्षक लग सकता है लेकिन आमतौर पर यह गलत होता है। ProtectSystem=strict कर्नल स्यूडो-फाइलसिस्टम (kernel pseudo-filesystems) को छोड़कर पूरे फाइलसिस्टम को रीड-ओनली बना देता है, इसलिए पहली बार जब कोई टूल फाइल राइट करने की कोशिश करेगा तो वह EROFS: read-only file system के साथ फेल हो जाएगा। यदि आप उस स्तर की सुरक्षा चाहते हैं, तो उसी एडिट में ReadWritePaths=/var/lib/dsh जोड़ें।
यहाँ कौन सा Type= उपयोग करना चाहिए
Type=exec, क्योंकि dsh foreground में रहता है और कभी fork नहीं होता। डिफ़ॉल्ट की तुलना में इसका लाभ यह है कि आपको एक वास्तविक error message मिलता है। Type=simple के साथ, systemd fork होते ही start को सफल मान लेता है, इससे पहले कि उसे पता चले कि binary मौजूद भी है या नहीं, इसलिए systemctl start dsh बिना किसी त्रुटि के return हो जाता है और विफलता केवल journal में दिखाई देती है। Type=exec के साथ, systemd execve() के सफल होने का इंतज़ार करता है, इसलिए ExecStart= में कोई typo होने पर वह command तुरंत fail हो जाती है, जिसे आप वहीं देख सकते हैं।
दोनों गलत विकल्प hang हो जाते हैं। Type=forking systemd को parent process के exit होने का इंतज़ार करने के लिए कहता है, और dsh कभी exit नहीं होता, इसलिए start तब तक block रहता है जब तक TimeoutStartSec समाप्त न हो जाए (डिफ़ॉल्ट रूप से 90 seconds) और फिर Job for dsh.service failed because a timeout was exceeded. रिपोर्ट करता है। Type=notify, sd_notify पर READY=1 संदेश का इंतज़ार करता है, और जो Node process इसे कभी नहीं भेजती, वह भी इसी तरह अटक जाती है। systemd service types की पूर्ण तुलना बाकी जानकारी प्रदान करती है, जिसमें यह भी शामिल है कि notify को कब कॉन्फ़िगर करना सार्थक होता है।
Restart rules जो स्पष्ट रूप से विफल होते हैं
Restart=on-failure non-zero exit या fatal signal मिलने पर restart करता है, और clean exit के बाद unit को वैसे ही छोड़ देता है। preview build के लिए आपको यही व्यवहार चाहिए। यदि dsh कभी 0 exit code देता है क्योंकि उसने ऐसी config पढ़ी जो उसे पसंद नहीं आई, तो unit रुक जाती है और रुकी ही रहती है, और systemctl status dsh में inactive (dead) दिखाई देता है जहाँ आप इसे देख सकते हैं। Restart=always उसी घटना को एक restart loop में बदल देता है जो दूर से देखने पर सही (healthy) लगता है।
Rate limit वह हिस्सा है जिसे लोग छोड़ देते हैं। systemd की default settings दस सेकंड के भीतर पाँच starts हैं, और RestartSec=5s के साथ आप दस सेकंड की अवधि में पाँच starts तक कभी नहीं पहुँचते, इसलिए जो unit startup पर ही crash हो जाती है वह हमेशा restart होती रहती है और केवल journal को ही इसका पता होता है। StartLimitIntervalSec=300 के साथ StartLimitBurst=5 का मतलब है कि पाँच मिनट में पाँच विफलताएँ ही काफी हैं: systemd प्रयास छोड़ देता है और unit को failed में park कर देता है, और Start request repeated too quickly. log करता है। एक बार जब आप कारण ठीक कर लें, तो sudo systemctl reset-failed dsh के साथ उस state को clear करें। दोनों settings [Unit] में होनी चाहिए, न कि [Service] में, और गलत section में होने पर systemd उन्हें चुपचाप अनदेखा कर देता है।
इसे start करें, फिर इसकी जाँच करें
sudo systemctl daemon-reload
sudo systemctl enable --now dsh
systemctl status dshenable --now दो काम करता है। enable वह कमांड है जो reboot के बाद service को वापस लाता है, और --now इसे वर्तमान boot में start करता है। केवल systemctl start का उपयोग करने पर अगले reboot के बाद service बंद हो जाएगी, और kernel updates के कारण reboot करना आवश्यक होता है।
systemctl status dsh को Active: active (running), एक Main PID, और एक Memory: लाइन दिखानी चाहिए। इसके बाद पुष्टि करें कि यह कहाँ listen कर रहा है:
sudo ss -lntp | grep 3080आपको 127.0.0.1:3080 की आवश्यकता है। यदि आपको 0.0.0.0:3080 दिखाई देता है, तो किसी चीज़ ने bind address को बदल दिया है और आपका agent public internet पर है। उस output में process का नाम node है, न कि dsh, क्योंकि dsh binary एक Node script है, इसलिए pgrep -x dsh को कुछ नहीं मिलता। इसके बजाय systemctl show -p MainPID dsh का उपयोग करें।
फिर एक बार reboot करें। जो service कभी reboot के बाद भी चालू नहीं रही, वह अभी तक एक पूर्ण service नहीं है।
sudo rebootReconnect करें और systemctl is-active dsh चलाएँ। यह active print करता है।
journalctl के साथ लॉग पढ़ना
dsh जो कुछ भी stdout और stderr पर लिखता है, वह unit नाम के अंतर्गत journal में दर्ज हो जाता है।
journalctl -u dsh -f
journalctl -u dsh -n 200 --no-pager
journalctl -u dsh --since "10 min ago" -p err-f नई लाइनों को फॉलो करता है, -n अंतिम N लाइनें दिखाता है, और -p err प्राथमिकता के आधार पर फिल्टर करता है। unit में SyslogIdentifier=dsh का उपयोग इसलिए किया जाता है ताकि उन लाइनों को dsh के रूप में टैग किया जा सके न कि node के रूप में, जो तब महत्वपूर्ण होता है जब आप पहली बार ऐसा journal आउटपुट पढ़ते हैं जो unit द्वारा फिल्टर नहीं किया गया है।
यह सुनिश्चित करें कि आपको आवश्यकता पड़ने से पहले ही journal रीबूट के बाद भी सुरक्षित रहता है:
journalctl -u dsh -b -1यदि यह Specifying boot ID or boot offset has no effect, no persistent journal was found प्रिंट करता है, तो इसका मतलब है कि journal /run में स्थित है और हर रीबूट पर डिलीट हो जाता है। निर्देशिका (directory) बनाएँ और daemon को रीस्टार्ट करें:
sudo mkdir -p /var/log/journal
sudo systemctl restart systemd-journaldSSH tunnel के माध्यम से UI तक पहुँचें, न कि public port के जरिए
dsh अपना web UI (user interface) 127.0.0.1:3080 पर serve करता है और इसे कहीं और serve करने से मना कर देता है। यदि आप --host 0.0.0.0 का अनुरोध करते हैं, तो यह इस error के साथ रुक जाता है:
error: --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यह कोई ऐसी सीमा नहीं है जिसे bypass किया जाना चाहिए। web API (application programming interface) ही agent को संचालित करती है, और agent shell commands चलाता है। इसलिए, जो भी इस port तक पहुँच सकता है, वह आपके VPS पर shell access पा सकता है। maintainers का कहना है कि remote authentication न होने के कारण ही इसे loopback पर bind किया गया है। startup output में 127.0.0.1:3080 लाइन का वास्तविक अर्थ क्या है इसे बदलने की कोशिश करने से पहले पढ़ना उपयोगी है। इसके बजाय अपनी machine से port forward करें:
ssh -N -L 3080:127.0.0.1:3080 you@203.0.113.10-L 3080:127.0.0.1:3080 आपके laptop पर port 3080 खोलता है और वहाँ आने वाले किसी भी traffic को VPS पर resolve होने वाले 127.0.0.1:3080 पर भेज देता है। -N का अर्थ है कि कोई remote command न चलाएँ, ताकि session केवल tunnel को खुला रखे। इसे चलते रहने दें और अपने browser में http://127.0.0.1:3080/ खोलें। यहीं पर आप Settings के अंतर्गत Models में DeepSeek API key दर्ज करते हैं, और यहीं आप workspace directory चुनते हैं। workspace को /var/lib/dsh/workspace पर point करें, जो वह directory है जिसका मालिक service user है, अन्यथा agent के file tools EACCES: permission denied error के साथ fail हो जाएंगे।
यदि आपके laptop पर port 3080 व्यस्त है, तो ssh यह error देता है:
bind [127.0.0.1]:3080: Address already in use
channel_setup_fwd_listener_tcpip: cannot listen to port: 3080ssh -N -L 3081:127.0.0.1:3080 you@203.0.113.10 के साथ एक अलग local port चुनें, और फिर http://127.0.0.1:3081/ पर browse करें। अपनी machine पर ~/.ssh/config में typing बचाएं:
Host dsh-vps
HostName 203.0.113.10
User you
LocalForward 3080 127.0.0.1:3080उसके बाद, ssh -N dsh-vps ही पूरी command है। यह tunnel अब आपके agent का एकमात्र द्वार है, इसलिए SSH daemon ही इसकी सुरक्षा कर रहा है: केवल keys का उपयोग करें, password authentication न रखें, और अपने VPS पर SSH को सुरक्षित करने के बाकी नियम यहाँ सामान्य से अधिक सख्ती से लागू होते हैं। यदि वह VPS अपने आप में एक छोटे private network में विकसित हो जाता है, जिसके पीछे database या staging box है, तो उन addresses को subnet router के साथ अपने tailnet पर advertise करना आपको प्रति service एक forward करने से बचाता है, हालाँकि dsh का loopback bind होने के कारण UI अभी भी tunnel के माध्यम से ही आता है।
key को unit file में नहीं रखा जाना चाहिए। Environment= values को systemctl show dsh -p Environment द्वारा print किया जाता है, जिसे box पर कोई भी user चला सकता है। यदि आपके द्वारा install किया गया कोई plugin environment में key मांगता है, तो उसे root के स्वामित्व वाली mode 600 वाली /etc/dsh.env file में रखें और EnvironmentFile=/etc/dsh.env के साथ reference दें। systemd exec time पर उस file को root के रूप में पढ़ता है, और systemctl show इसकी सामग्री को print नहीं करता है। disk पर प्रत्येक setting वास्तव में किस file में जाती है, और जब आप dsh को DeepSeek API के बजाय local Ollama endpoint पर point करते हैं तो आपकी box से क्या बाहर जाता है, यह dsh की keys, models और endpoints को configure करने का विषय है।
इसे चलाने की लागत
Inference DeepSeek के API पर होता है, आपके VPS पर नहीं। आपका सर्वर Node process, इसके द्वारा serve किए जाने वाले UI, और agent द्वारा चलाए जाने वाले हर command का खर्च उठाता है। पहले दो स्थिर और छोटे हैं। तीसरा इस unit file में किसी भी चीज़ द्वारा सीमित नहीं है।
किसी और के आंकड़ों पर भरोसा करने के बजाय अपने सर्वर पर स्वयं आधारभूत लागत मापें:
systemctl show dsh -p MemoryCurrent
systemd-cgtop -1 --depth 2MemoryCurrent bytes में है। इसे तब देखें जब agent काम कर रहा हो, न कि जब वह idle हो।
Tool calls सेवा के child processes होते हैं, इसलिए वे एक ही control group में आते हैं और उन्हीं सीमाओं के अंतर्गत गिने जाते हैं। जो agent workspace के भीतर npm install या test suite चलाता है, वह harness से कहीं अधिक memory का उपयोग कर सकता है। 1 GB VPS पर यहीं समस्या आती है: kernel एक process चुनता है और उसे kill कर देता है, और journalctl -k | grep -i "out of memory" में Out of memory: Killed process लाइन दिखाई देती है जो उस process का नाम बताती है जिसे उसने चुना है। वह process अक्सर वह नहीं होता जिसने समस्या पैदा की है।
इसका समाधान वह सीमा है जिसे आप जानबूझकर सेट करते हैं। [Service] section में MemoryMax= और CPUQuota= नुकसान को unit के भीतर ही रखते हैं, ताकि पूरा सर्वर lock होने के बजाय केवल अनियंत्रित build process ही kill हो। systemd के साथ memory और CPU को सीमित करना में संख्याओं और failure व्यवहार के बारे में बताया गया है। Disk का उपयोग भी बढ़ता है, जो DSH_HOME के अंतर्गत session history और agent द्वारा workspace में लिखी गई किसी भी चीज़ के कारण होता है, इसलिए disk की निगरानी के लिए आप जो भी उपयोग करते हैं उसमें du -sh /var/lib/dsh को शामिल करें।
यदि आप एक ऐसा interactive agent चाहते हैं जिससे आप जुड़ सकें और अलग हो सकें, तो service इसके लिए सही विकल्प नहीं है, और persistent tmux session में agent चलाना बेहतर काम करता है। जब आप चाहते हैं कि dsh हमेशा चालू रहे और tunnel के माध्यम से सुलभ हो, तभी इसे unit के रूप में चलाएं।
विफलता के प्रकार और वे संदेश जो आपको दिखाई देंगे
status=203/EXEC. systemd फ़ाइल को रन नहीं कर सका, और लॉग Failed to locate executable /usr/local/bin/dsh: No such file or directory में हैं। ExecStart= में दिया गया पाथ उस पाथ से मेल नहीं खाता जो command -v dsh ने प्रिंट किया था। यह वह विफलता है जिसे Type=exec छिपाने के बजाय systemctl start समय पर रिपोर्ट करता है।
status=217/USER. User= में दिया गया अकाउंट मौजूद नहीं है। id dsh के साथ इसकी पुष्टि करें।
status=200/CHDIR. WorkingDirectory= गायब है, या सर्विस यूजर उसमें प्रवेश नहीं कर सकता। sudo -u dsh ls /var/lib/dsh/workspace इसे सीधे पुनरुत्पादित (reproduce) करता है।
Error: listen EADDRINUSE: address already in use 127.0.0.1:3080. किसी अन्य चीज़ ने पोर्ट को पहले ही होल्ड कर रखा है, आमतौर पर यह किसी दूसरे टर्मिनल में खुला रह गया npx रन होता है। sudo ss -lntp | grep 3080 उस प्रक्रिया (process) का नाम बताता है।
EACCES: permission denied और उसके बाद एक पाथ। /var/lib/dsh के अंतर्गत ओनरशिप गलत है, आमतौर पर ऐसा इसलिए होता है क्योंकि पहला रन root के रूप में या गलत HOME के साथ हुआ था। sudo chown -R dsh:dsh /var/lib/dsh इसे ठीक कर देता है।
Start request repeated too quickly. यूनिट स्टार्ट रेट लिमिट तक पहुँच गई और उसने प्रयास करना छोड़ दिया। वास्तविक त्रुटि इसके ऊपर की लाइनों में है। दोबारा प्रयास करने से पहले sudo systemctl reset-failed dsh चलाएँ।
यूनिट active (running) है लेकिन ब्राउज़र में कुछ नहीं दिख रहा है। VPS पर चेक चलाएँ: यदि curl -fsS http://127.0.0.1:3080/ -o /dev/null && echo up वहाँ up प्रिंट करता है, तो सर्विस सही ढंग से काम कर रही है और समस्या पोर्ट फॉरवर्ड में है।
सोच-समझकर अपग्रेड करना
Pinning का अर्थ है कि अपग्रेड एक ऐसी प्रक्रिया है जिसे आप स्वयं नियंत्रित करते हैं, न कि वह जो अपने आप हो जाए। सबसे पहले release notes पढ़ें, क्योंकि upstream द्वारा compatibility-breaking बदलावों के बारे में दी गई चेतावनी ही pinning का मुख्य कारण है। state directory का बैकअप लें, और फिर version बदलें:
sudo systemctl stop dsh
sudo tar czf /root/dsh-home-$(date +%F).tgz -C /var/lib/dsh harness
sudo npm install -g @deepseek-ai/dsh@0.1.0-rc.7
sudo systemctl start dsh
journalctl -u dsh -n 50 --no-pagerRollback करने की प्रक्रिया पुराने version के साथ npm install -g जैसी ही है, साथ ही उस tarball को restore करना भी आवश्यक है, जो केवल तभी काम करेगा यदि आपने उसे पहले लिया हो। एक preview-stage agent runtime वास्तव में वह software है जहाँ अपग्रेड आपके द्वारा उपयोग किए जा रहे config format को बदल सकता है।
FAQ
SSH session बंद करने पर dsh क्यों रुक जाता है?
क्योंकि npx @deepseek-ai/dsh web आपके लॉगिन session के स्वामित्व वाली एक foreground process है, इसलिए session समाप्त होने पर इसे बंद कर दिया जाता है। इसके विपरीत, एक systemd unit init system के स्वामित्व में होती है, यही कारण है कि disconnect करने के बाद भी यह चलती रहती है और reboot के बाद फिर से शुरू हो जाती है। sudo systemctl enable --now dsh उन दो चरणों का युग्म है जो आपको दोनों सुविधाएँ देता है: reboot के लिए enable, और इस boot के लिए --now।
क्या मुझे dsh के लिए Type=simple या Type=exec का उपयोग करना चाहिए?
Type=exec। dsh foreground में चलता है और कभी fork नहीं होता, इसलिए दोनों काम करते हैं, लेकिन Type=exec यह सुनिश्चित करता है कि start को सफल मानने से पहले systemd execve() के सफल होने का इंतज़ार करे। यदि ExecStart= में path गलत है, तो systemctl start विफल हो जाएगा और आपको status=203/EXEC दिखाई देगा। Type=simple के साथ वही गलती सफलता का संकेत देगी और journal में छिप जाएगी। Type=forking और Type=notify दोनों यहाँ गलत हैं, और दोनों तब तक hang रहेंगे जब तक कि 90 seconds बाद TimeoutStartSec समाप्त न हो जाए।
मैं अपने laptop से dsh web UI कैसे खोलूँ?
SSH के माध्यम से port forward करें: ssh -N -L 3080:127.0.0.1:3080 you@your-vps, फिर अपने browser में http://127.0.0.1:3080/ खोलें। service को public address पर bind करने का प्रयास न करें। dsh --host 0.0.0.0 को error: --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 के साथ अस्वीकार कर देता है, क्योंकि web API agent को shell commands चलाने के लिए बाध्य कर सकता है और इसके आगे कोई remote authentication नहीं होता है।
क्या मैं permissions को सरल रखने के लिए dsh को root के रूप में चला सकता हूँ?
नहीं। यह harness commands चलाने और files लिखने के लिए है, इसलिए service के पास जो भी privileges होंगी, वही agent के पास भी होंगी। useradd --system --shell /usr/sbin/nologin dsh के साथ एक system account बनाएँ, /var/lib/dsh का स्वामित्व उसे दें, और unit में NoNewPrivileges=true जोड़ें। यदि बाद में आपको EACCES: permission denied का सामना करना पड़ता है, तो इसका सामान्य कारण root के रूप में पहले किया गया run है, जिसने root-owned files छोड़ दी हैं, और sudo chown -R dsh:dsh /var/lib/dsh इसे ठीक कर देता है।
मुझे unit में dsh का कौन सा version pin करना चाहिए?
service set up करते समय npm view @deepseek-ai/dsh version जो भी रिपोर्ट करे, उसे npm install -g @deepseek-ai/dsh@<that version> के साथ install करें और कहीं सुरक्षित दर्ज कर लें। 18 August 2026 को 0.1.0-rc.7 current था। मुद्दा version number का नहीं है, बल्कि यह है कि बिना version के npx start time पर package को resolve करता है, इसलिए एक unattended restart आपको चुपचाप ऐसे build पर ले जा सकता है जिसका config format अलग हो।