วิธีการป้องกัน“ การเขียนล้มเหลว: ท่อแตก” ในการเชื่อมต่อ SSH


283

ฉันจะทำอย่างไรเพื่อกำหนดค่า SSH บนทั้งไคลเอนต์และเซิร์ฟเวอร์เพื่อป้องกันWrite Failed: broken pipeข้อผิดพลาด? มันมักจะเกิดขึ้นหากคุณนอนหลับคอมพิวเตอร์ไคลเอนต์ของคุณและดำเนินการในภายหลัง


8
ไม่มีอะไรจริงๆ. เซสชั่นถูกขัดจังหวะและความปลอดภัยของเซสชั่นถูกทำลาย หากคุณไม่ใส่คอมพ์ในโหมดสลีปคุณสามารถกำหนดเวลาชีวิตให้กับลูกค้าเพื่อยิงหัวใจที่ยังมีชีวิตไปยังเซิร์ฟเวอร์ แต่ถ้าระบบเข้าสู่โหมดสลีปแล้วไม่มีอะไรที่สามารถทำได้
darkdragn

3
ในกรณีนี้ฉันกำลังมองหาบางอย่างที่จะช่วยให้ฉันเริ่มต้นการเชื่อมต่อ ssh ที่ใช้งานscreenไม่ได้อีกครั้ง (ตามรหัสออก) และเรียกคืนโดยใช้
โซริน

4
คุณเป็นคนผิด: ฉันมีเครื่องไคลเอนต์บนเดสก์ท็อปสองเครื่องเชื่อมต่อกับเซิร์ฟเวอร์ SAME หนึ่งคืออูบุนตู 12.10, Quantal ซึ่งไคลเอ็นต์ SSH ทำงานได้ดีและเชื่อมต่อเป็นเวลาหลายชั่วโมง อีกอันคือ Ubuntu 14.10, Utopic, แยกออกจากกันและติดตั้งใหม่ หลังจากนั้นสองสามนาทีมันบล็อกตัวเองด้วยข้อความนี้ ฟังก์ชั่นที่เหลือของเครือข่ายในเครื่องจะไม่ถูกขัดจังหวะ ไม่ใช่ปัญหาเครือข่ายหรือปัญหาเซิร์ฟเวอร์ แต่เป็นปัญหาเฉพาะของซอฟต์แวร์ SSH CLIENT ซึ่งสามารถแก้ไขได้ตรงข้ามกับสิ่งที่ "darkdragan" กล้าที่จะพูดว่า "ไม่มีอะไรสามารถทำได้"
David L

2
และอย่างที่ฉันพูดไป: ผู้คนพูดมากเกินไปเมื่อพวกเขาพูดว่า "ไม่มีอะไรที่จะทำได้" เช่นเดียวกับ @darkdragn ฉันอ่านคำตอบของ Aram Kocharyan และฉันใช้มัน: 20 นาทีที่แล้ว ... ฉันรู้ว่าใน Quantal Ubuntu รุ่นเก่า 12.10 ฉันได้ใช้คำสั่งนั้นในไฟล์นั้น [ฉันเพิ่งตรวจสอบ] เมื่อสองปีก่อนและนั่นก็คือ เหตุผลของความมั่นคงที่นั่น ฉันทำที่นี่และในช่วง 20 นาทีที่ผ่านมาการเชื่อมต่อมีเสถียรภาพตั้งแต่นั้นมา ดังนั้นโปรดผู้คน: อย่าอดใจตัวเองเมื่อกล้าคิดว่า "ไม่สามารถทำอะไรได้" และงดเว้นมากยิ่งขึ้นเมื่อพยายามฝากข้อความนั้นกับคนอื่น ๆ
David L

11
@DavidL คุณควรอ่านคำถามให้ดีขึ้นก่อนที่จะคุยโว ปัญหาของคุณไม่เหมือนกับ OP ของผู้ที่กล่าวอย่างชัดเจนว่าทำให้คอมพิวเตอร์เข้าสู่โหมดสลีป ซึ่งโดยวิธีเดียวที่อยู่คำตอบเดียว ("mosh") และมันถูกโพสต์ 2 ปีหลังจากคำถาม อย่างไรก็ตามคำตอบอื่น ๆ จะทำสิ่งที่ดีที่สุดถัดไปซึ่งเป็นการเสนอวิธีแก้ปัญหากรณีที่สามารถแก้ไขได้ง่ายขึ้นเช่นเดียวกับคุณ ทำใจให้สบายไม่ต้องเน้นให้คุยโวไม่ได้ทำดีใด ๆ ที่นี่ ...
MSB

คำตอบ:


266

ฉันได้ลองใน/etc/ssh/ssh_configLinux และ Mac แล้ว:

Host *
ServerAliveInterval 120

นี่คือความถี่ที่ควรจะส่งข้อความ keepalive ไปยังเซิร์ฟเวอร์ในไม่กี่วินาที หากไม่ได้ผลจงฝึกลิงให้กดทุกสองนาทีในขณะที่คุณทำงาน

คุณสามารถตั้งค่าได้ทั้งServerAliveIntervalใน/etc/ssh/ssh_configเครื่องไคลเอนต์หรือClientAliveIntervalใน/etc/ssh/sshd_configเครื่องเซิร์ฟเวอร์ ลองลดช่วงเวลาถ้าคุณยังพบข้อผิดพลาดอยู่

การกำหนดค่าสำหรับผู้ใช้คนเดียวสามารถตั้งค่าในไฟล์ได้~/.ssh/configทั้งบนเซิร์ฟเวอร์และฝั่งไคลเอ็นต์ chmod 644 ~/.ssh/configตรวจสอบให้แน่ใจไฟล์มีสิทธิ์ที่ถูกต้อง


4
ฉันไม่ได้ใช้ Mac แต่ Ubuntu 12.04 และไฟล์สำหรับระบบปฏิบัติการนี้ก็ดูเหมือนว่าจะเป็น ~ / .ssh / config
H2ONaCl

5
OS X 10.8.4 ให้ข้อผิดพลาดBad configuration option: ClientAliveInterval
ohho

3
ฉันพบBad configuration optionข้อผิดพลาดเดียวกันนี้ใน OSX 10.8.4
Nick Heiner

10
โดยทั่วไปคุณใส่คำสั่งทั้งสองนี้ไว้ในส่วนต่าง ๆ ของระบบ เฉพาะ ServerAliveInterval ในฝั่งไคลเอ็นต์ OSX ... และเฉพาะ ClientAliveInterval ในไฟล์ sshd config ...
ftrotter

2
ลิงของฉันพูดกับฉัน: "ทำไมคุณไม่พิมพ์ตัวเอง" ด้านบน [ENTER] "
สิงหาคม

85

เซสชัน SSH อาจแตกเนื่องจากเหตุผลมากมายและอาจหลีกเลี่ยงไม่ได้

screenยูทิลิตี้ที่มีประโยชน์ที่สามารถนำมาใช้เพื่อลดปัญหาที่เกิดจากนี้จะเรียกว่า หน้าจอเป็นเครื่องมือที่ทรงพลังที่ช่วยให้คุณควบคุมเทอร์มินัลหลายตัวซึ่งจะมีชีวิตอยู่อย่างอิสระจากเซสชัน ssh ตัวอย่างเช่นหากคุณทำงานscreenในเซสชัน ssh คุณจะเห็นเทอร์มินัลใหม่เปิดอยู่และคุณสามารถใช้งานนั้นเพื่อรันงาน ให้บอกว่าเซสชั่น ssh ของคุณตายในกระบวนการ การทำงานscreen -dจากนั้นscreen -rจะเปิดเซสชันล่าสุดอีกครั้งและคุณจะสามารถดำเนินการต่อจากที่นั่นได้ ตรวจสอบให้แน่ใจว่าคุณอ่านเอกสารบางอย่างก่อนที่จะใช้


5
นี่อาจเป็นคำตอบที่ดีที่สุดฉันไม่แน่ใจว่าทำไมมันถึงไม่โหวต "การแก้ไข" อื่น ๆ จะมีประโยชน์ในกรณีพิเศษที่คุณจะสนใจเกี่ยวกับการรักษาการเชื่อมต่อ SSH แต่ในกรณีการใช้งานส่วนใหญ่ฉันคิดว่าข้อกังวลที่แท้จริงคือกระบวนการที่ตั้งใจจะทำงานต่อไป .
Paul McMurdie

16
ฉันจะเพิ่มTmuxเป็นทางเลือกในหน้าจอ ฉันพบว่ามันอเนกประสงค์และมีเสถียรภาพมากกว่าหน้าจอ
fridaymeetssunday

2
เพียงแค่ปล่อยไว้ที่นี่เพื่ออ้างอิงในอนาคตคุณสามารถเรียกใช้screen -d -rเพื่อกู้คืนเซสชันล่าสุดของคุณได้อย่างสะดวก
doplumi

2
screen -drหรือเพียงแค่ หรือscreen -xขึ้นอยู่กับสิ่งที่คุณวางแผนจะทำ ประเด็นคือเราควรรู้ว่าสวิตช์ทั้งหมดทำอะไรเพื่อให้สามารถใช้สวิตช์ที่เหมาะสมและไม่เพียงทำตามคำแนะนำของผู้ใช้อินเทอร์เน็ต มีบทสรุปขนาดกะทัดรัดที่ดีอยู่ที่นี่: ss64.com/bash/screen.html
flith

นี่ไม่ใช่คำตอบของปัญหา
3728501

46

การกำหนดค่าไคลเอนต์

ลองสร้างไฟล์:

~/.ssh/config

เพิ่มเนื้อหา:

Host *
  ServerAliveInterval 30
  ServerAliveCountMax 5

ตอนนี้ไปที่เซิร์ฟเวอร์ของคุณและดูว่าปัญหาของคุณได้รับการแก้ไขแล้วหรือไม่ ตัวเลือก ClientAliveInterval มีประโยชน์เฉพาะเมื่อกำหนดค่าเซิร์ฟเวอร์ ssh (aka sshd) แต่จะไม่เปลี่ยนแปลงสิ่งใด ๆ ในฝั่งไคลเอ็นต์ ssh ดังนั้นอย่าใช้ในไฟล์การกำหนดค่าด้านบน

นี่จะส่งสัญญาณสวัสดีคุณอยู่ที่นั่นไปยังเซิร์ฟเวอร์หากไม่ได้รับแพ็กเก็ตใน 30 วินาทีก่อนหน้า (ตามที่ระบุข้างต้น) อย่างไรก็ตามหากจำนวนของสัญญาณสวัสดี - คุณอยู่ที่นั่นติดต่อกันถึง ServerAliveCountMax ดังนั้น ssh จะตัดการเชื่อมต่อจากเซิร์ฟเวอร์ ค่านี้เป็นค่าเริ่มต้นที่ 3 (ดังนั้น 3 * 30 = 90 วินาทีโดยไม่มีกิจกรรมของเซิร์ฟเวอร์) เพิ่มขึ้นถ้ามันเหมาะสมกับความต้องการของคุณ มีตัวเลือกปรับแต่งมากมายให้กับไฟล์. ssh / config และคุณสามารถอ่านได้:

ใช้ไฟล์กำหนดค่า SSH

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับตัวเลือกอื่น ๆ คุณอาจไม่ต้องการใช้สิ่งนี้กับเซิร์ฟเวอร์ทุกเครื่องที่คุณเชื่อมต่อกับตัวอย่างนี้ หรือ จำกัด ให้เฉพาะเซิร์ฟเวอร์โดยการแทนที่บรรทัดHost *ด้วยHost <IP>(แทนที่ด้วยที่อยู่ IP ดูที่ ssh_config man page)

การกำหนดค่าเซิร์ฟเวอร์

ในทำนองเดียวกันคุณสามารถบอกเซิร์ฟเวอร์ให้สุภาพกับลูกค้าของคุณ /etc/ssh/sshd_configแฟ้มการกำหนดค่าที่ได้คือ

ClientAliveInterval 20
ClientAliveCountMax 5

คุณสามารถปิดใช้งานโดยการตั้งค่าClientAliveIntervalไป0หรือปรับแต่งClientAliveIntervalและClientAliveCountMaxการตั้งค่าการใช้งานของลูกค้า SSH สูงสุดโดยไม่ตอบสนองต่อฟิวส์ ข้อดีอย่างหนึ่งของการตั้งค่านี้ผ่าน TCPKeepAlive ก็คือสัญญาณจะถูกส่งผ่านแชนเนลที่เข้ารหัสดังนั้นจึงมีโอกาสน้อยที่จะถูกปลอมแปลงได้


มันไม่ทำงาน ฉันกำลังเผชิญกับข้อผิดพลาดเดียวกันอีกครั้ง
user997704

3
ลองใช้โดยตรงจากบรรทัดคำสั่งและลดขนาดลง: ssh -o ServerAliveInterval = 5 user @ host
Matt

พยายามเช่นกัน. ไม่ทำงาน. ฉันไม่รู้จริงๆว่าเกิดอะไรขึ้นกับระบบของฉัน
user997704

2
มันคือ ClientAliveCountMax ไม่ใช่ ClientAliveMaxCount
David G

@DavidG โปรดแก้ไขคำตอบด้วยการแก้ไขของคุณ
CivMeierFan

23

ฉันอัปเกรดเซิร์ฟเวอร์ Ubuntu จากระยะไกลเป็นชัดเจนและสูญเสียการเชื่อมต่อ ssh ในระหว่างการอัปเกรดด้วยข้อความ "เขียนล้มเหลว Brocken pipe" ClientAliveInterval และ ServerAliveInterval ไม่ได้ทำอะไรเลย การแก้ปัญหาคือการเปิดตัวเลือก TCPKeepAlive ในไคลเอนต์ ssh:

TCPKeepAlive yes

ใน

/etc/ssh/ssh_config

20

สำหรับลูกค้าให้แก้ไขไฟล์~/.ssh/config(หรือ/etc/ssh/ssh_config) ของคุณดังนี้:

Host *
  TCPKeepAlive yes
  ServerAliveInterval 120

TCPKeepAlive - ระบุว่าระบบควรส่งข้อความ TCP keepalive ไปอีกด้านหนึ่งหรือไม่ หากพวกเขาถูกส่งความตายของการเชื่อมต่อหรือความผิดพลาดของหนึ่งในเครื่องจะสังเกตเห็นได้อย่างถูกต้อง อย่างไรก็ตามนี่หมายความว่าการเชื่อมต่อจะตายหากเส้นทางหยุดชั่วคราวและบางคนพบว่ามันน่ารำคาญ (ค่าเริ่มต้นคือ 'ใช่')

ServerAliveInterval - ตั้งค่าช่วงเวลาหมดเวลาเป็นวินาทีหลังจากนั้นหากไม่ได้รับข้อมูลจากเซิร์ฟเวอร์ ssh (1) จะส่งข้อความผ่านแชนเนลที่เข้ารหัสเพื่อร้องขอการตอบสนองจากเซิร์ฟเวอร์ ค่าเริ่มต้นคือ 0 ระบุว่าข้อความเหล่านี้จะไม่ถูกส่งไปยังเซิร์ฟเวอร์


สำหรับเซิร์ฟเวอร์ให้แก้ไข/etc/ssh/sshd_configเป็น:

ClientAliveInterval 600
ClientAliveCountMax 0

หากคุณต้องการให้ไคลเอ็นต์ ssh ออก (หมดเวลา) โดยอัตโนมัติหลังจาก 10 นาที (600 วินาที)

ClientAliveCountMax - นี่เป็นการระบุจำนวนทั้งหมดของข้อความการตรวจสอบที่ส่งโดยเซิร์ฟเวอร์ ssh โดยไม่ได้รับการตอบสนองใด ๆ จากไคลเอ็นต์ ssh ค่าเริ่มต้นคือ 3

ClientAliveInterval - นี่เป็นการระบุการหมดเวลาเป็นวินาที หลังจาก x จำนวนวินาทีเซิร์ฟเวอร์ ssh จะส่งข้อความไปยังลูกค้าเพื่อขอการตอบสนอง Deafult เป็น 0 (เซิร์ฟเวอร์จะไม่ส่งข้อความถึงลูกค้าเพื่อตรวจสอบ)


ดูเพิ่มเติมที่: ตัวเลือกอะไรServerAliveIntervalและClientAliveIntervalใน sshd_config ทำอย่างแม่นยำ?


การตั้งค่า ServerAliveCountMax สูงกว่าค่าเริ่มต้นบนไคลเอนต์ควรช่วยให้การเชื่อมต่อสดสำหรับการเชื่อมต่อที่ช้า
jonnyjandles

17

ฉันรัก Mosh ฉันมักจะ ssh ลงในเซิร์ฟเวอร์ปิดแล็ปท็อปของฉันและไปที่ร้านกาแฟเปิดขึ้นและดำเนินการต่อราวกับว่าไม่มีอะไรเปลี่ยนแปลง

Mosh (เปลือกมือถือ)

แอปพลิเคชั่นเทอร์มินัลระยะไกลที่อนุญาตให้โรมมิ่งรองรับการเชื่อมต่อเป็นระยะและให้เสียงสะท้อนในตัวเครื่องและการแก้ไขการกดแป้นของผู้ใช้

Mosh แทน SSH มันแข็งแกร่งและตอบสนองได้ดียิ่งขึ้นโดยเฉพาะผ่าน Wi-Fi, เซลลูล่าร์และลิงค์ทางไกล

Mosh เป็นซอฟต์แวร์ฟรีสำหรับ GNU / Linux, FreeBSD, Solaris, Mac OS X และ Android


6

สำหรับฉันฉันได้รับWrite failed: Broken pipeแม้ในขณะที่ฉันกำลังพิมพ์เป็นกลุ่มหรือที่พรอมต์เชลล์ ฉันไม่สามารถท่องอินเทอร์เน็ตในพื้นที่ได้ทั้งสักครู่ (ฉันกำลังเชื่อมต่อระยะไกลกับ Ubuntu โดยใช้ Terminal)

คนอื่น ๆ ในเครือข่ายของฉันสตรีมวิดีโอจำนวนมากจาก Netflix และที่อื่น ๆ ฉันไม่สามารถพิสูจน์ได้ แต่ฉันสงสัยว่าเป็นปัญหาของ ISP หรือเราเตอร์ ตัวอย่างเช่น Verizon และ Netflix กำลังชี้นิ้วมือกันเพื่อปัญหาเครือข่ายของลูกค้า

หากคุณมีการเชื่อมต่อผ่านสายโทรศัพท์และกำลังสตรีมมิ่งวิดีโอหรือเพลงด้วยการเชื่อมต่อ SSH หรือ telnet พร้อมกันในบางจุดคุณจะได้รับข้อความแสดงข้อผิดพลาด การอัพเกรดแพ็คเกจ ISP ของฉันดูเหมือนจะทำให้การเชื่อมต่อที่ใช้งานไม่บ่อย



3

ฉันมีสคริปต์บนเซิร์ฟเวอร์ระยะไกลที่ไม่เคยดูเหมือนจะล้มเหลวโดยไม่คำนึงถึงไคลเอ็นต์หรือเซิร์ฟเวอร์การกำหนดค่า SSH

#!/bin/bash
while true; do date; sleep 10; done;

บันทึกลงในไฟล์ dummy.sh และเรียกใช้อย่างรวดเร็วก่อนที่จะย่อขนาดหน้าต่างหรือย้ายออกจากไฟล์ มันจะทำการพิมพ์การประทับเวลาปัจจุบันบนเซิร์ฟเวอร์และทำให้การเชื่อมต่อของคุณยังคงอยู่ตราบใดที่การเชื่อมต่อไม่ได้ลดลงด้วยเหตุผลอื่นใด เมื่อคุณกลับไปที่เทอร์มินัลเพียงกด CTRL + C และทำงานต่อไป


9
หรือเพียงแค่ออกtopวิ่ง
Eben Geer

1

คุณสามารถเพิ่ม args เหล่านี้ทุกครั้งที่คุณเรียกใช้ ssh: -o ServerAliveInterval=15 -o ServerAliveCountMax=3

คุณไม่จำเป็นต้องแก้ไขไฟล์ / etc / ssh / * config หากคุณทำเช่นนี้

คุณสามารถสร้างนามแฝงทุบตีหรือฟังก์ชั่นหรือสคริปต์เพื่อให้ง่าย

เช่นฟังก์ชันทุบตีเหล่านี้คุณสามารถเพิ่มลงใน. bashrc ของคุณ do_ssh จะถูกใช้ด้วยตนเองเพื่อเปิด keepalives do_ssh_pty ถูกใช้ภายในสคริปต์เพื่อตั้งค่า pty และหลีกเลี่ยงพร้อมต์

do_ssh() {
    ssh -o ServerAliveInterval=15 -o ServerAliveCountMax=3 $*
}

do_ssh_pty() {
    ssh -tt -o "BatchMode=yes" -o "StrictHostKeyChecking=no" -o ServerAliveInterval=15 -o ServerAliveCountMax=3 $*
}

ตอนนี้do_ssh user@hostสามารถใช้งานได้do_ssh user@host <args> <command>และจะมีการใช้งาน keepalives

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.