เชลล์กราฟิกแบบเนทีฟสำหรับ SSH
(probablymarcus.com)- หากเซิร์ฟเวอร์และอุปกรณ์เอดจ์ให้บริการ เชลล์กราฟิกบนเบราว์เซอร์ แทนการเปิดให้ใช้แค่เทอร์มินัล ก็จะช่วยให้ใช้งานแอประยะไกลจากอุปกรณ์อื่นได้เป็นธรรมชาติมากขึ้น
- เชลล์นี้มีหน้าจอโฮมของแอปและ API สำหรับค้นหา URL ระหว่างแอป ทำให้สร้างโฟลว์ที่ส่งต่อไฟล์หรือทรัพยากรไปยังแอปที่เหมาะสมได้
- แอปให้บริการ UI ผ่าน HTTP server ขนาดเล็ก แต่ไม่ใช่เว็บเซิร์ฟเวอร์สาธารณะทั่วไป โดยทำงานเป็นเซิร์ฟเวอร์ส่วนตัวที่ตั้งอยู่บนสมมติฐานว่ามีการเข้าถึงผ่าน SSH หรือในเครื่องเป็นหลัก
- การเข้ารหัสไม่ต้องให้แต่ละแอป implement เอง แต่ปล่อยให้เลเยอร์ SSH จัดการได้ ทำให้เซิร์ฟเวอร์ของแต่ละแอปคงโครงสร้างที่เรียบง่ายและมี dependency น้อย
- Lewis สร้าง Outer Loop เป็นเบราว์เซอร์ SSH เพื่อแนวคิดนี้ และเปิดซอร์ส Outer Shell โดยคำนึงถึงทั้งแอป HTML และแอปเนทีฟ outerframe
เชลล์กราฟิกที่ทำงานบน SSH
- เว็บเบราว์เซอร์เป็นตัวอย่างที่วางรูปแบบไว้ดีแล้วสำหรับโฟลว์ที่อุปกรณ์หนึ่งซึ่งเป็น เซิร์ฟเวอร์ มอบประสบการณ์ให้กับอีกอุปกรณ์หนึ่งซึ่งเป็น ไคลเอนต์
- หากนำแนวทางเดียวกันไปใช้กับเซิร์ฟเวอร์และอุปกรณ์เอดจ์ ก็จะสามารถใช้ แอปกราฟิก ในสภาพแวดล้อมระยะไกลแทนแอปแบบเทอร์มินัลได้
- เชลล์ให้ หน้าจอโฮม ของแอปต่างๆ และแต่ละแอปจะเสิร์ฟส่วนติดต่อผู้ใช้แบบเว็บผ่าน HTTP server ขนาดเล็ก
- Shell API ช่วยให้แอปค้นหา URL ของกันและกันได้ สร้างการเชื่อมโยงระหว่างแอป
- ตัวอย่างเช่น หากแอปลงทะเบียนตัวเองเป็น text editor แอปอื่นก็สามารถเปิดไฟล์ข้อความด้วยแอป editor นั้นได้ด้วยการดับเบิลคลิกไฟล์ข้อความ
- แอปอาจเป็นเว็บแอปบน HTML แบบเดิม หรือเป็นแอปเนทีฟ outerframe ก็ได้
วิธี implement และโครงการที่เปิดเผยแล้ว
- โดยทั่วไป HTTP server ของแอปจะทำงานเป็น เซิร์ฟเวอร์ส่วนตัว ที่อุปกรณ์อื่นในเครือข่ายเข้าถึงไม่ได้
- ผู้ใช้จะใช้งานผ่าน SSH หรือใช้งานในเครื่อง
- ต่างจากเครื่องมือเซิร์ฟเวอร์บนเว็บที่มีอยู่ส่วนใหญ่ ตรงที่ใช้ ไฟล์ Unix domain socket เป็นหลัก แทนพอร์ต localhost
- ไฟล์ Unix domain socket คล้ายกับพอร์ต แต่มีตัวตนอยู่ในไฟล์ซิสเต็มและมีสิทธิ์ผู้ใช้ที่ระบุชัดเจน
- แต่ละ HTTP server ไม่จำเป็นต้องจัดการการเข้ารหัสเอง
- การเข้ารหัสถูกจัดการที่ เลเยอร์ SSH
- ด้วยเหตุนี้ เซิร์ฟเวอร์ของแต่ละแอปจึงเรียบง่ายมากและไม่ต้องมี dependency
- Outer Loop ถูกสร้างขึ้นเป็น เบราว์เซอร์ SSH สำหรับเชลล์กราฟิกลักษณะนี้
- มีการเปิดเผยโอเพนซอร์ส Outer Shell
- เอกสารที่เกี่ยวข้องมีให้ 3 ส่วน
- Outer Loop: วิธีการทำงานของเบราว์เซอร์
- Outer Shell: Outer Shell API และวิธีเพิ่มแอป
- Outerframe: วิธีการทำงานของแอปเนทีฟ
- ฟีเจอร์อย่างการเชื่อมต่อ Unix socket ในเบราว์เซอร์เคยถูกมองว่าเป็นฟีเจอร์เฉพาะทางมาก แต่เมื่อรวมกับความสามารถอย่างการรับรู้ SSH และ sudo ก็ทำให้เกิดความเป็นไปได้ใหม่ทางเทคนิค
- แม้จะมีเว็บแอปแบบเซิร์ฟเวอร์เดี่ยวๆ อย่าง Jupyter และ Tensorboard เกิดขึ้นแล้ว แต่แต่ละตัวใช้โปรโตคอลความปลอดภัยแบบเฉพาะกิจ ทำให้ยังไม่มีแนวทางร่วมที่ลงตัวในการส่งต่อสิ่งเหล่านี้ให้ “ถูกต้อง”
- เมื่อ AI ช่วยเขียนโค้ดได้ การที่แต่ละแอปมีโค้ดเบสแยกตามแพลตฟอร์มเป้าหมายจึงเป็นเรื่องที่ใช้งานได้จริง และมีการเสนอให้เป็นสถาปัตยกรรมเว็บที่เป็นธรรมชาติ โดยใช้ HTML สำหรับงานอ่านและแอปเบาๆ และใช้ แอปเนทีฟ ที่ปรับให้เข้ากับแพลตฟอร์มสำหรับแอปเพื่อการทำงาน
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
ค่อนข้างน่าหงุดหงิดที่มีปฏิกิริยาจำนวนมากที่ลดทอนคุณค่าของไอเดียนี้ ผู้อ่าน HN จำนวนมากดูเหมือนยังติดอยู่กับ แนวคิดว่า TUI เหนือกว่า และไม่ค่อยสนใจ GUI
ประเด็นสำคัญมีสองอย่าง TUI ไม่ได้เหนือกว่า GUI โดยเนื้อแท้ และ SSH ในฐานะเลเยอร์ขนส่งควรรองรับไม่ใช่แค่การส่งต่อ pty หรือเลเยอร์แสดงผลแบบ TUI เท่านั้น แต่รวมถึง เลเยอร์แสดงผลแบบ GUI ด้วย
อันที่จริงสองอย่างนี้เคยเกิดขึ้นแล้วบน UNIX เมื่อ 30 ปีก่อน และก็มีทางออกอย่างโปรโตคอล X กับ
ssh -Xด้วย แต่ X ไม่ได้ชนะ และอนาคตที่เราเชื่อมต่อเข้าเครื่องระยะไกลด้วยssh -Xแล้วรันgnome-control-centerเพื่อให้หน้าต่างตั้งค่าเด้งขึ้นมาและใช้ตั้งค่าคอมพิวเตอร์ระยะไกลได้ ก็ไม่เคยมาถึง ถ้าคิดว่าทำได้ก็ลองเองได้เลย ประสบการณ์นั้นย่ำแย่มากถึงอย่างนั้น ความต้องการแบบนี้ก็ยังคงมีอยู่ และแอปอย่าง Jupyter Notebook ก็เริ่มถูกพัฒนาในรูปแบบเว็บเซิร์ฟเวอร์ รูปแบบเอกสารของเว็บ การจัดสไตล์ และภาษาสคริปต์ฝั่งไคลเอนต์ แม้จะมีข้อเสียสารพัด แต่ก็ใช้งานเป็นเลเยอร์แสดงผลของแอปเชิงโต้ตอบได้ และเพราะเดิมทีเริ่มจากเอกสารระยะไกล จึงมีความโปร่งใสบนเครือข่ายฝังอยู่ในตัว
เมื่อดูแอป Electron ก็ควรยอมรับว่า สแต็ก HTML/CSS/JS ครองตำแหน่งสำคัญแม้แต่ในแอปเดสก์ท็อป และการนำมันมาใช้เป็นเลเยอร์แสดงผลของแอประยะไกลผ่าน SSH จึงเป็นเรื่องธรรมชาติ โปรเจกต์นี้ก็ดูเหมือนอยู่ในกระแสนั้น
แอป Electron ก็เหมือน X ตรงที่แยก display server กับ client ออกจากกัน โดยเรียกว่า “renderer process” และ “main process” ตามลำดับ และสื่อสารกันผ่าน IPC ในทางทฤษฎี ถ้ามีวิธีขนส่ง IPC ที่เหมาะสม ก็น่าจะรัน main process กับ renderer process บนคนละเครื่องได้ ซึ่งดูไม่ต่างจากไอเดียนี้มากนัก
ssh -Xทำงานได้ดีขึ้นอยู่กับ toolkit ที่ใช้ รวมถึงระยะทาง/latency เช่น Gtk ไม่ค่อยดีเพราะ pipeline การเรนเดอร์เมื่อระยะทางและ latency มากพอ ก็ต้องคิดว่าจะนำเสนอให้ผู้ใช้อย่างไร เพราะไม่ว่าสื่อกลางจะเป็นอะไร ข้อจำกัดทางฟิสิกส์ก็หลีกเลี่ยงไม่ได้ เครื่องมือใดก็ตามที่สัญญาว่าจะให้การเข้าถึงกราฟิกจากระยะไกลต้องออกแบบโดยคำนึงถึง latency ส่วนที่ vim ทำงานได้ดีแม้มี latency ก็เพราะโดยพื้นฐานแล้วมันส่งคำสั่งแบบเข้าคิว
waypipeดังนั้นอนาคตนั้นยังไม่ตายssh -Xเปิดgnome-control-centerของเครื่องระยะไกลเพื่อปรับแต่งเซิร์ฟเวอร์ไม่มาถึง การ ตั้งค่าเซิร์ฟเวอร์ด้วย GUI เป็นวิธีที่น่ารังเกียจ และหวังว่าจะเหลืออยู่แค่ในโลก Windowsนี่ดูเหมือนเป็นวิธีแก้ที่กำลังมองหาปัญหา ซึ่งเคยมีมาเยอะแล้วในอดีต ข้อความอ้างอิงด้านล่างดูเข้ากับความพยายามนี้ดี
“คนที่ไม่เข้าใจ Unix ถูกลิขิตให้ต้องคิดค้นมันขึ้นมาใหม่อย่างห่วยแตก” ~Henry Spencer
เครื่องเกือบทุกเครื่องที่มุ่งเป้าไปยังนักพัฒนามี SSH server ติดตั้งอยู่และเข้าถึงได้
ทำไมเทอร์มินัล SSH ต้องดูเหมือนขยะตัวอักษรล้วนสไตล์ยุค 1960? ทำไม TUI ต้องเป็นสิ่งที่ดีที่สุดที่ส่งผ่าน SSH ได้? ทำไมดูหนัง 4K ในเทอร์มินัลหรือท่องเว็บด้วย pinch zoom ไม่ได้?
ไอเดียอย่างการดูไดเรกทอรี Linux ผ่าน SSH ด้วยคอมโพเนนต์ UI แบบเนทีฟก็ดูดี
แต่บางส่วนก็ดูเหมือนเป็นปัญหาที่แก้ได้ด้วยวิธีอื่นอยู่แล้ว เช่นการเมานต์
sshfsนึกถึงบทความเก่าเกี่ยวกับเทอร์โมสตัทแบบตั้งโปรแกรมได้ เนื้อหาคือมันทรงพลังจนปรับแต่งได้ลึกมาก แต่สำหรับคนส่วนใหญ่แล้วใช้งานแย่มาก ใจความประมาณว่า “ผู้คนไม่ได้อยากเรียนรู้ระบบลึกลับของคุณ แต่ต้องการประโยชน์ที่ระบบนั้นสัญญาไว้” UI ที่ดีควรรู้วิธีลดช่องว่างนั้นให้น้อยที่สุด
ไอเดียในการแยก frontend กับ backend ของแอปกราฟิกออกจากกันนั้นดี แต่ยากจะเรียกว่าใหม่ อาจมีอะไรที่ผมพลาดไปก็ได้
ดูเหมือนจะไม่รู้จัก
X11Forwarding yesหรือhtml5 web appฟีเจอร์อย่างการให้เบราว์เซอร์เชื่อมต่อกับ Unix socket ถูกปัดตกมาโดยตลอด ด้วยเหตุผลว่าเป็นฟีเจอร์เฉพาะกลุ่มมาก
นั่นเป็นปัญหาความปลอดภัยจึงไม่ได้ถูกนำไปใช้ อย่างน้อยก็สำหรับ Unix socket แบบดิบ ๆ ส่วนพอร์ตอื่นที่จำกัดไว้เป็น WebSocket หรือ HTTP นั้นทำได้
ไม่สามารถอนุญาตให้เบราว์เซอร์เชื่อมต่อกับ socket ใด ๆ ก็ได้ เพราะ socket จำนวนมากไม่ได้ต้องการการเชื่อมต่อจากเบราว์เซอร์อย่างชัดเจน หรือไม่ได้ตระหนักด้วยซ้ำว่าเบราว์เซอร์สามารถเชื่อมต่อได้
ดังนั้นจึงต้องเพิ่ม allowlist บางอย่าง และเมื่อเป็นแบบนั้นก็ซับซ้อนเกินไปสำหรับฟีเจอร์เฉพาะกลุ่มแบบนี้
เลยคิดว่าแก่นของปัญหาคือ ความเป็นเฉพาะกลุ่ม
สำหรับข้อมูลเพิ่มเติม Outer Loop ได้เพิ่ม allowlist แล้ว: https://outerloop.sh/unix-domain-sockets/
กำลังพยายามทำความเข้าใจว่า Outer Shell ทำงานอย่างไร ในเว็บไซต์อธิบายแรงจูงใจไว้แบบนี้
แอปอย่าง Jupyter หรือ TensorBoard ถ้ากำลังรันอยู่บนเซิร์ฟเวอร์ระยะไกล โดยปกติจะไม่ปรากฏในเว็บเบราว์เซอร์มาตรฐาน เพราะการปล่อยให้ทั้งอินเทอร์เน็ตเข้าถึงแอปเหล่านี้ได้อันตรายมาก แทนที่จะทำแบบนั้น มันจะรันบนพอร์ตโลคัลของเซิร์ฟเวอร์ และคอมพิวเตอร์ของฉันก็เข้าถึงตรงนั้นโดยตรงไม่ได้
ตามวิธีดั้งเดิม ถ้าจะเข้าถึงตรงนี้ต้องเปิดเทอร์มินัลใหม่แล้วรันคำสั่งอย่าง
ssh -L 24601:localhost:8889 mrcslws@lambda4.mycompany.com &,ssh -L 24602:localhost:6006 mrcslws@lambda4.mycompany.com &แบบนี้ถูกไหม? ปกติเราจะใช้ SSH forwarding แบบนี้เฉพาะตอนทำโปรโตไทป์เท่านั้น และตอน deploy ก็สร้างเว็บไซต์อย่าง
myjupyternotebook.comแล้วใส่การยืนยันตัวตนเพื่อไม่ให้คนอื่นเข้าถึงไม่ใช่หรือ HTTP basic auth ก็ไม่ได้เป็นเรื่องใหญ่ขนาดนั้นถ้าอยากให้จุดที่เปิดเผยต่อสาธารณะไม่ใช่ HTTP แต่เป็น SSH ก็มีทางเลือกอื่นอย่างวางไว้หลัง VPN หรือ tunnel
Outer Loop ดูเจ๋งมาก แต่ยังไม่ค่อยเข้าใจว่าจำเป็นตรงไหน รู้สึกเหมือนกำลังพลาดอะไรไป เลยอยากให้ช่วยอธิบายว่าทำไมถึงสร้างมันขึ้นมา
ผมใกล้กับการใช้งานอย่างการทดลอง deep learning, การปรับแต่ง GPU kernel, การพัฒนาหุ่นยนต์มากกว่า หุ่นยนต์ก็เป็นแค่เซิร์ฟเวอร์ที่เคลื่อนที่ได้ และในกรณีแบบนี้เรากำลังใช้ คอมพิวเตอร์ระยะไกล อย่างชัดเจน
สำหรับคนกลุ่มนี้ ผมว่าเครื่องมือนี้น่าจะรู้สึกเป็นธรรมชาติกว่า flow ที่คุณเสนอมา แต่อาจเป็นไปได้ว่าผมกำลังเอาความคิดตัวเองไปทาบทับคนอื่น
สำหรับผม มันรู้สึกเหมือนเป็นหนึ่งในสิ่งพื้นฐานที่ควรมีอยู่ได้ คล้ายกับ ระบบปฏิบัติการแบบกราฟิกที่ให้ความสำคัญกับการใช้งานระยะไกลเป็นอันดับแรก
ssh -D 4711 -q -C -N user@hostแบบนี้
localhost:4711จะกลายเป็น SOCKS5 proxy ที่ตั้งค่าในเบราว์เซอร์ได้แน่นอนว่า WireGuard VPN ดีกว่า เหตุผลสำคัญคือ SSH multiplex บน TCP connection เดียว ดังนั้นถ้า packet หนึ่งหายไป ทราฟฟิก forwarding ทั้งหมดจะเจอ head-of-line blocking จนกว่าจะส่งซ้ำเสร็จ
ดูเหมือนผู้เขียนจะไม่เคยได้ยินชื่อ Cockpit
สิ่งที่บอกว่า “ไม่มี” หรือ “ใหม่” นั้นอยู่ใน Cockpit มานานกว่า 10 ปีแล้ว ทั้งการเชื่อมต่อเว็บเซิร์ฟเวอร์แบบ socket-based, การแยก backend-frontend ของแอปเซิร์ฟเวอร์, ไปจนถึงแนวคิด server console ที่รวมการเข้าถึง shell ไว้ด้วย
ถ้าถามว่า “ไม่แปลกเหรอที่สิ่งนี้ยังไม่มี?” ผมคงตอบว่าไม่ เพราะมันมีมานานแล้ว
ด้วยความจริงใจ
ตำรวจแนวทางปฏิบัติ HN :-)
https://news.ycombinator.com/newsguidelines.html
เป็นบทความที่ยอดเยี่ยม จะ bookmark ไว้สำหรับงานวิจัยของผม
ฟีเจอร์ “clickity clackity” ในเทอร์มินัลของผม [0] ผูกอยู่กับเครื่อง local ดังนั้นทันทีที่เข้าใช้งานระยะไกล ความเป็นกราฟิกก็หายไป
เรื่องนี้กำลังค่อย ๆ เปลี่ยนไปด้วย offline replay [1] โดยให้ native GUI กับ TUI ทำงานร่วมกันเพื่อเปิดทางให้ฟีเจอร์อย่างการ rewind แต่หนทางยังอีกไกล และเป็นเรื่องดีที่ได้เห็นคนอื่นทดลองอย่างจริงจัง เทอร์มินัลเป็นพื้นที่ที่ถูกปล่อยทิ้งไว้อย่างมาก
[0] https://terminal.click
[1] https://terminal.click/posts/2026/06/tui-stability/#:~:text=...
คนที่คุ้นเคยกับเทอร์มินัลมักลืมไปว่า SSH เป็นมิตรน้อยแค่ไหน สำหรับคนที่ไม่ได้เรียนมันในมหาวิทยาลัย
ถ้าสิ่งนี้ช่วยลดกำแพงการเริ่มต้นให้ทีมเล็ก ๆ ที่ดูแล VPS โดยไม่ต้องจ้างคนดูแลแพลตฟอร์มได้ ก็ถือว่าสำเร็จแล้ว แต่ก็สงสัยว่าจะจัดการ key กับ jump host อย่างไร
ยอดเยี่ยม เห็นได้ชัดว่ากำลังไปในทิศทางที่ถูกต้อง
ชั้นแยกส่วน ระหว่าง frontend กับ backend ควรถูกตัดที่ “ชิ้น” ที่เล็กที่สุดเท่าที่ทำได้
คนจำนวนมากที่ประชดอยู่ตรงนี้ ถ้าได้ “รู้สึก” ถึง latency และ overhead ที่เพิ่มขึ้นด้วยตัวเองก็คงเข้าใจ ยังไม่ได้ใส่ความคิดมากพอในการแบ่งข้อมูลอย่างระมัดระวังให้เหมาะกับ use case แต่ละแบบ
ยิ่งไปกว่านั้น ผมคิดว่าแอป
topในเดโมที่บอกว่า “ขยับการตั้งค่าบ่อย ๆ เพื่อสร้างโหลด” ควรทำการ render ทางฝั่ง client แบบ JIT ให้มากกว่านี้ ถ้าทำแบบนั้น ข้อมูลที่วิ่งไปมาระหว่าง Pi กับ client ก็น่าจะลดเหลือประมาณ delta ที่บีบอัดแล้ว ของ output จากpsไม่ควรทำแบบนี้ มีเหตุผลด้านความปลอดภัยที่ดีและมีมานาน รวมถึงเหตุผลด้าน การแยก web control plane มากมาย ที่ไม่อนุญาตให้เบราว์เซอร์มีสิทธิ์ socket ทั่วไป
อุปมาที่ใกล้ที่สุดในเชิงกลไกคือเหตุผลที่รถ ATV 3 ล้อเป็นไอเดียที่แย่
โดยค่าเริ่มต้น socket ต้องถูกบล็อก และจะเปิดได้ก็ต่อเมื่อฝั่งเซิร์ฟเวอร์เพิ่มเข้า allowlist อย่างชัดเจนแล้วเท่านั้น
ต้องมีการรับรู้ sudo อย่างแท้จริง เพื่อไม่ให้แตะ socket ของ root ได้ถ้าไม่มีรหัสผ่าน sudo เหตุผลที่ฟีเจอร์นี้สำคัญคือ มิฉะนั้นจะเกิดแรงจูงใจให้คนรัน backend ที่เป็น root ผ่าน socket ที่ผู้ใช้เข้าถึงได้
รายละเอียดอยู่ที่นี่: https://outerloop.sh/security/