VPS पर dsh को systemd service के रूप में कैसे चलाएं
VPS पर dsh को headless मोड में चलाने के लिए systemd unit file सेटअप करें। यह गाइड समर्पित user बनाने, Restart रूल्स, journalctl लॉग्स और SSH टनल कॉन्फ़िगर करने की प्रक्रिया बताती है।
VPS पर dsh को headless मोड में चलाना
VPS पर dsh को headless मोड में चलाने के लिए एक systemd unit file और उसे चलाने के लिए एक समर्पित user की आवश्यकता होती है। dsh, DeepSeek Harness के लिए कमांड लाइन लॉन्चर है। यह DeepSeek का एजेंट रनटाइम है, जिसे अगस्त 2026 में developer preview के तहत MIT लाइसेंस के साथ जारी किया गया था। quickstart आपको npx @deepseek-ai/dsh web टाइप करने के लिए कहता है, जो सही है, लेकिन आपके SSH (secure shell) सेशन को बंद करते ही यह बंद हो जाता है।
एक unit file एक साथ चार समस्याओं का समाधान करती है। reboot के बाद सर्विस अपने आप फिर से शुरू हो जाती है। इसका आउटपुट आपकी स्क्रीन पर स्क्रॉल होने के बजाय journal में चला जाता है। यह root के बजाय एक सामान्य अकाउंट के रूप में चलती है। और यह वही वर्ज़न चलाती है जिसे आपने चुना है, जो यहाँ सामान्य से अधिक महत्वपूर्ण है, क्योंकि upstream ने इसे बड़े अक्षरों में स्पष्ट किया है:
DeepSeek Harness वर्तमान में developer preview में है और इसमें तेजी से बदलाव हो रहे हैं। इसमें ऐसे बदलाव होंगे जो पुरानी compatibility को तोड़ देंगे।
यह गाइड मानती है कि dsh आपके सिस्टम पर पहले से ही मैन्युअल रूप से काम कर रहा है। यदि ऐसा नहीं है, तो VPS पर DeepSeek Harness इंस्टॉल करने से शुरुआत करें और जब npx @deepseek-ai/dsh web एक पेज सर्व करने लगे, तब वापस आएँ।
सबसे पहले 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 file लिखने से पहले सुनिश्चित करें कि यह चल रहा है
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 करने का प्रयास करती है जिसे कोई अन्य process पहले से ही उपयोग कर रही है, तो वह Error: listen EADDRINUSE: address already in use 127.0.0.1:3080 के साथ fail हो जाएगी।
0.1.0-rc.7, 18 August 2026 को प्रकाशित version था। 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 सटीक वर्ज़न प्रिंट करता है, जो कि छह सप्ताह बाद आपके काम आएगा जब व्यवहार बदल जाएगा और आपको याद नहीं रहेगा कि आपने क्या इंस्टॉल किया था।
एक उपयोगकर्ता जो केवल सर्विस का स्वामी हो
यह एजेंट 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 कर लेती हैं। वह पहला boot files लिखता है और bundles fetch कर सकता है, इसलिए इसे मैन्युअल रूप से करें जहाँ आप इसे देख सकें।
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 पर निर्भर करता है। यदि आप इसे गलत करते हैं, तो पहली बार चलने पर यह cache directories को आपके home directory में डाल देगा, जिसका स्वामी dsh होगा, और बाद में service अपनी state नहीं ढूँढ पाएगी। जब curl check up return करे, तो Ctrl+C दबाकर इसे रोक दें।
Unit file
Write /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 एक bare command name के लिए एक निश्चित path list में खोज करता है, लेकिन वह list आपके shell का PATH नहीं है, इसलिए absolute path का उपयोग करने से अनिश्चितता खत्म हो जाती है।
WorkingDirectory= वह स्थान है जहाँ relative paths resolve होते हैं, और यहीं से वह tool call शुरू होता है जो बिना किसी argument के ls को चलाता है। इसे उस workspace पर point करें जिसे आप agent को देते हैं। यदि directory मौजूद नहीं है या service user उसमें प्रवेश नहीं कर सकता है, तो dsh के चलने से पहले ही service status=200/CHDIR के साथ fail हो जाएगी।
ProtectHome=true प्रक्रिया से /home और /root को छिपा देता है। यह यहाँ सुरक्षित है क्योंकि service जिस भी चीज़ को access करती है, वह /var/lib/dsh के अंतर्गत ही रहती है। यदि आप workspace को /home के अंतर्गत किसी path पर point करते हैं, तो agent यह report करेगा कि directory मौजूद नहीं है; यह तब तक भ्रमित करने वाला लगता है जब तक आपको यह line याद न रहे। ProtectSystem=full, /usr, /boot और /etc को read-only बना देता है, जिन्हें service को कभी भी write करने की आवश्यकता नहीं होती।
आगे बढ़ना आकर्षक है लेकिन आमतौर पर गलत होता है। ProtectSystem=strict kernel pseudo-filesystems को छोड़कर पूरे filesystem को read-only बना देता है, इसलिए पहली बार जब कोई tool file write करने की कोशिश करता है तो वह EROFS: read-only file system के साथ fail हो जाता है। यदि आप उस स्तर की सुरक्षा चाहते हैं, तो उसी edit में ReadWritePaths=/var/lib/dsh जोड़ें।
यहाँ Type= का कौन सा प्रकार उपयोग करें
Type=exec, क्योंकि dsh foreground में रहता है और कभी fork नहीं करता। default के मुकाबले इसका लाभ यह है कि आपको वास्तविक error message मिलता है। Type=simple के साथ, systemd fork होते ही start को सफल मान लेता है, इससे पहले कि उसे पता चले कि binary मौजूद भी है या नहीं, इसलिए systemctl start dsh बिना किसी त्रुटि के return हो जाता है और विफलता केवल journal में दिखाई देती है। Type=exec के साथ, systemd execve() के सफल होने का इंतज़ार करता है, इसलिए ExecStart= में कोई typo होने पर वह command तुरंत विफल हो जाती है, जिसे आप वहीं देख सकते हैं।
बाकी दो गलत विकल्प hang हो जाते हैं। Type=forking systemd को parent process के exit होने का इंतज़ार करने के लिए कहता है, और dsh कभी exit नहीं होता, इसलिए start तब तक block रहता है जब तक TimeoutStartSec समाप्त (default रूप से 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=on-failure गैर-शून्य (non-zero) एग्जिट या घातक सिग्नल मिलने पर रीस्टार्ट होता है, और क्लीन एग्जिट के बाद यूनिट को वैसे ही छोड़ देता है। प्रीव्यू बिल्ड के लिए आपको यही व्यवहार चाहिए होता है। यदि dsh कभी 0 के साथ एग्जिट होता है क्योंकि उसने ऐसी कॉन्फ़िगरेशन पढ़ी जो उसे पसंद नहीं आई, तो यूनिट रुक जाती है और रुकी ही रहती है, और systemctl status dsh में inactive (dead) दिखाई देता है जहाँ आप इसे देख सकते हैं। Restart=always उसी घटना को एक रीस्टार्ट लूप में बदल देता है जो दूर से देखने पर सही (healthy) लगता है।
रेट लिमिट वह हिस्सा है जिसे लोग छोड़ देते हैं। systemd का डिफ़ॉल्ट मान दस सेकंड के भीतर पाँच स्टार्ट है, और RestartSec=5s के साथ आप दस सेकंड की विंडो में पाँच स्टार्ट तक कभी नहीं पहुँचते, इसलिए जो यूनिट स्टार्टअप पर क्रैश होती है वह हमेशा रीस्टार्ट होती रहती है और केवल जर्नल को ही इसका पता चलता है। StartLimitIntervalSec=300 के साथ StartLimitBurst=5 का मतलब है कि पाँच मिनट में पाँच विफलताएँ पर्याप्त हैं: systemd प्रयास छोड़ देता है और यूनिट को failed में पार्क कर देता है, और Start request repeated too quickly. लॉग करता है। कारण ठीक करने के बाद sudo systemctl reset-failed dsh के साथ उस स्थिति को साफ़ करें। दोनों सेटिंग्स [Unit] में होनी चाहिए, न कि [Service] में, और गलत सेक्शन में होने पर 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: लाइन दिखनी चाहिए। इसके बाद पुष्टि करें कि यह किस port पर listen कर रहा है:
sudo ss -lntp | grep 3080आपको 127.0.0.1:3080 दिखना चाहिए। यदि आपको 0.0.0.0:3080 दिखाई देता है, तो इसका मतलब है कि किसी ने bind address को बदल दिया है और आपका agent public internet पर expose हो गया है। उस output में process का नाम node है, न कि dsh, क्योंकि dsh binary एक Node script है, इसलिए pgrep -x dsh को कुछ नहीं मिलेगा। इसके बजाय systemctl show -p MainPID dsh का उपयोग करें।
इसके बाद एक बार server को reboot करें। जो service reboot के बाद भी चालू नहीं रहती, वह अभी पूरी तरह से तैयार नहीं है।
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 वेब 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 किया जाना चाहिए। वेब API (application programming interface) agent को संचालित करता है, और agent shell commands चलाता है। इसलिए, जो कोई भी इस port तक पहुँच प्राप्त कर लेगा, उसे आपके VPS पर shell का access मिल जाएगा। maintainers का कहना है कि remote authentication न होने के कारण ही bind को loopback तक सीमित रखा गया है। इसके बजाय अपनी मशीन से 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 यह सूचित करेगा:
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 करें। अपनी मशीन पर ~/.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 को सुरक्षित करने के बाकी नियम यहाँ सामान्य से अधिक सख्ती से लागू होते हैं।
API 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 इस file को exec time पर root के रूप में पढ़ता है, और systemctl show इसकी सामग्री को print नहीं करता है।
इसे चलाने की लागत
Inference DeepSeek के API पर होता है, आपके VPS पर नहीं। आपका सर्वर Node process, इसके द्वारा serve किए जाने वाले UI, और agent द्वारा चलाए जाने वाले हर command के लिए संसाधन खर्च करता है। पहले दो स्थिर और कम होते हैं। तीसरा इस unit file में किसी भी सीमा से बंधा नहीं है।
किसी और के आंकड़ों पर भरोसा करने के बजाय अपने सर्वर पर स्वयं आधारभूत खपत मापें:
systemctl show dsh -p MemoryCurrent
systemd-cgtop -1 --depth 2MemoryCurrent बाइट्स में होता है। इसे तब देखें जब agent काम कर रहा हो, न कि जब वह idle हो।
Tool calls इस service के 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 की निगरानी के लिए आप जो भी tool उपयोग करते हैं, उसमें 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 उस प्रक्रिया का नाम बताता है।
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 को तोड़ने वाले बदलावों के बारे में दी गई चेतावनी ही 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 एक foreground process है जो आपके login session के अधीन होती है, इसलिए session समाप्त होने पर यह बंद हो जाती है। इसके विपरीत, एक systemd unit init system के अधीन होती है, इसीलिए disconnect करने के बाद भी यह चलती रहती है और reboot के बाद फिर से start हो जाती है। 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 setup करते समय npm view @deepseek-ai/dsh version जो भी report करे, उसे npm install -g @deepseek-ai/dsh@<that version> के साथ install करें और कहीं सुरक्षित record कर लें। 18 August 2026 को 0.1.0-rc.7 current था। मुख्य बात version number नहीं है, बल्कि यह है कि बिना version के npx start time पर package को resolve करता है, जिससे unattended restart आपको चुपचाप एक ऐसे build पर ले जा सकता है जिसका config format अलग हो।