เรียกใช้งานคำสั่งรีโมตปลดการเชื่อมต่อ ssh อย่างสมบูรณ์


48

ฉันมี 2 เครื่องคอมพิวเตอร์และlocalpcremoteserver

ฉันต้องการที่จะดำเนินการคำสั่งบางอย่างเกี่ยวกับlocalpc remoteserverสิ่งหนึ่งที่ต้องทำคือเริ่มสคริปต์สำรองที่ทำงานหลายชั่วโมง ฉันต้องการคำสั่งlocalpcให้ "ดับไฟ" จากนั้นทำงานโดยอิสระอย่างremoteserverเต็มที่เหมือนlocalpcไม่เคยมีมาตั้งแต่แรก

นี่คือสิ่งที่ฉันทำไปแล้ว:

remoteserver ภายในมีสคริปต์:

/root/backup.sh

localpc มีกำหนดการทำงานนี้:

ssh root@remoteserver 'nohup /root/backup.sh' &

ฉันกำลังทำสิ่งนี้อย่างถูกวิธีหรือไม่? มีวิธีที่ดีกว่าในการทำเช่นนี้? ฉันจะพบปัญหาใด ๆ ในการทำเช่นนี้หรือไม่?


stackoverflow.com/questions/19996089/…และstackoverflow.com/questions/29142/…ให้แนวทางที่เป็นประโยชน์จำนวนมากสำหรับปัญหานี้ที่ไม่ได้ใช้หน้าจอ / tmux ฯลฯ ...
Paul

คำตอบ:


47

คุณควรใช้screenกับรีโมตโฮสต์เพื่อให้มีคำสั่งที่แยกออกจริง:

ssh root@remoteserver screen -d -m ./script

ฉันชอบความคิดนี้ เมื่อสคริปต์เสร็จสิ้นหน้าจอจะยังคงทำงานต่อไป ... และฉันจะต้องเชื่อมต่อใหม่อีกครั้งในครั้งต่อไปที่ฉันต้องการเรียกใช้ใช่ไหม
LVLAaron

@AaronJAnderson: ไม่ได้รับว่าคำสั่งไม่ใช่เชลล์เมื่อมันสิ้นสุดลงเช่นกันหน้าจอนั้นจะสิ้นสุดเซสชัน
enzotib

52

ปิด แต่ไม่ตรง

เป็นอิสระจากสถานีใด ๆ

ssh root@remoteserver '/root/backup.sh </dev/null >/var/log/root-backup.log 2>&1 &'

คุณต้องปิดไฟล์ descriptors ทั้งหมดที่เชื่อมต่อกับซ็อกเก็ต ssh เนื่องจากเซสชัน ssh จะไม่ปิดตราบใดที่รีโมตบางกระบวนการเปิดซ็อกเก็ต หากคุณไม่สนใจเอาต์พุตของสคริปต์ (น่าจะเป็นเพราะสคริปต์ดูแลการเขียนไปยังไฟล์บันทึก) ให้เปลี่ยนเส้นทางไปที่/dev/null(แต่โปรดทราบว่าสิ่งนี้จะซ่อนข้อผิดพลาดเช่นไม่สามารถเริ่มสคริปต์)

การใช้nohupไม่มีผลประโยชน์ที่นี่ nohupจัดเรียงโปรแกรมที่รันไม่ให้รับสัญญาณ HUP หากเทอร์มินัลการควบคุมของโปรแกรมหายไป แต่ที่นี่ไม่มีเทอร์มินัลในตอนแรกดังนั้นจึงไม่มีอะไรจะส่ง SIGHUP ไปยังกระบวนการออกจากสีน้ำเงิน นอกจากนี้จะnohupเปลี่ยนเส้นทางเอาต์พุตมาตรฐานและข้อผิดพลาดมาตรฐาน (แต่ไม่ใช่อินพุตมาตรฐาน) ไปยังไฟล์ แต่เฉพาะในกรณีที่พวกเขาเชื่อมต่อกับเทอร์มินัล

กำลังแยกออกจากเทอร์มินัล

 aaron@localpc$ ssh root@remoteserver
 root@remoteserver# nohup /root/backup.sh </dev/null &
 nohup: appending output to `nohup.out'
 [1] 12345
 root@remoteserver# exit
 aaron@localpc$ 

ใช้nohupเพื่อแยกสคริปต์ออกจากเทอร์มินัลการควบคุมเพื่อไม่ให้ได้รับSIGHUPเมื่อเทอร์มินัลหายไป nohupเปลี่ยนเส้นทางเอาต์พุตมาตรฐานและข้อผิดพลาดมาตรฐานไปยังไฟล์ที่เรียกว่าnohup.outหากเชื่อมต่อกับเทอร์มินัล คุณต้องดูแลอินพุตมาตรฐานด้วยตัวเอง

การรักษาสถานีระยะไกล

หากคุณต้องการที่จะให้คำสั่งที่ทำงานอยู่ในสถานีระยะไกล แต่ไม่ได้มันติดอยู่กับเซสชั่น SSH รันใน Multiplexer ขั้วเช่นหน้าจอหรือTmux

ssh root@remoteserver 'screen -S backup -d -m /root/backup.sh'

คุณสามารถเชื่อมต่อกับเทอร์มินัลในภายหลังซึ่งสคริปต์กำลังทำงานอยู่โดยเรียกใช้screen -S backup -rdเป็นรูทบนเครื่องนั้น

อัตโนมัติคำสั่งระยะไกลหนึ่ง

เพื่อความปลอดภัยที่ดีขึ้นเล็กน้อยอย่าเปิดการเข้าสู่ระบบรากระยะไกลโดยตรงอย่างกว้างขวางเกินไป /root/.ssh/authorized_keysสร้างวัตถุประสงค์พิเศษคู่ที่สำคัญและให้คำสั่งบังคับใน เนื้อหาของไฟล์กุญแจสาธารณะคือAAAA…== wibble@example.com; เพิ่มรายการของตัวเลือกที่คั่นด้วยเครื่องหมายจุลภาครวมถึงcommand="…"ที่ระบุว่าคีย์สามารถใช้เพื่อดำเนินการคำสั่งเฉพาะนี้เท่านั้น ตรวจสอบให้แน่ใจว่าได้เก็บตัวเลือกและปุ่มทั้งหมดไว้ในหนึ่งบรรทัด

command="/root/backup.sh </dev/null >/dev/null 2>/dev/null &",no-port-forwarding,no-agent-forwarding,no-x11-forwarding,no-pty,no-user-rc AAAA…== wibble@example.com

ฉันได้ลองคำสั่งแรกที่คุณระบุไว้ มันไม่ได้พื้นหลังในกล่องที่ดำเนินการคำสั่ง เคอร์เซอร์อยู่ที่นั่นและรอให้เสร็จสมบูรณ์ ... อาจเป็นข้อผิดพลาดหรือไม่
LVLAaron

คุณอาจต้องเปลี่ยนเส้นทาง stdin เป็น / dev / null บนระบบรีโมต นั่นอาจเป็นสาเหตุที่ ssh ไม่ออก
KeithB

ฉันจะเพิ่ม-fตัวเลือกในการรับ ssh 'พื้นหลัง' (เช่นยุติการเชื่อมต่อปิด) ในด้านท้องถิ่น &นี้จะทำงานร่วมกับ nohupเป็นตัวเลือกในกรณีนี้ แต่คุณอาจลองใช้setsidแทน
Alexios

@KeithB การเปลี่ยนเส้นทาง stdin เป็นส่วนหนึ่งของมัน แต่ฉันยังต้องเปลี่ยนเส้นทาง stdout และ stderr: nohup จะไม่ทำที่นี่เพราะพวกเขาไม่ใช่อาคารและในความเป็นจริง nohup ไม่มีประโยชน์ที่นี่
Gilles 'SO- หยุดความชั่วร้าย'

1
@erikbwork โปรดทราบว่าฉันไม่มีเงื่อนงำเกี่ยวกับสิ่งเหล่านั้น แต่ทำตามการสนทนาและความคิดเห็น: Gilles ไม่ได้ใช้ตัวเลือก -t ในคำสั่งของเขาดังนั้นจึงไม่มีเทอร์มินัลหลอกที่สร้างขึ้นทั้งที่ลูกค้าหรือเซิร์ฟเวอร์ ด้าน ดังนั้นจะไม่มีการส่ง HUP
Binarus

12

สูตรมาตรฐานสำหรับการเรียกใช้คำสั่งระยะไกลจากการเข้าสู่ระบบระยะไกลเช่น SSH มีดังต่อไปนี้:

nohup command </dev/null >command.log 2>&1 &

ถ้าcommandเป็นสคริปต์เปลือกที่ดูแลการเข้าสู่ระบบไปยังแฟ้มตัวเองแล้วคุณอาจจะเปลี่ยนไปcommand.log /dev/nullเมื่อคุณเริ่มต้นสิ่งนี้ออกจากระบบทันที

คุณต้องการทุกอย่างในบรรทัดนั้น

nohup แจ้งให้เชลล์ไม่รบกวนกระบวนการหากเซสชันการล็อกอินถูกตัดการเชื่อมต่อ

</dev/null บอกว่าจะไม่รออินพุต

>command.log บอกให้ส่งข้อความใด ๆ ไปยังไฟล์บันทึกที่มีชื่อนี้

2>&1บอกให้ส่งข้อความ stderr ใด ๆ ไปยังไฟล์บันทึกเดียวกัน ในบางกรณีจะเป็นการดีกว่าถ้ามีสองไฟล์ไฟล์ที่สองเพื่อรวบรวมข้อความแสดงข้อผิดพลาดและไฟล์แรกที่รวบรวมข้อความกิจกรรมปกติ ที่สามารถทำให้ง่ายต่อการตรวจสอบว่าทุกอย่างทำงานอย่างถูกต้อง

& บอกให้แยกกระบวนการนี้และเรียกใช้ในพื้นหลังเป็นกระบวนการภูต


10

เธรดนี้มีประโยชน์มาก แต่โซลูชันของฉันต้องแตกต่างกันเล็กน้อย

ฉันไม่ชอบวิธีแก้ปัญหาหน้าจอเพราะมันทำให้กระบวนการหน้าจอทำงานซึ่งฉันไม่ต้องการ การเปลี่ยนเส้นทางและไม่มีปุ่มใช้เช่นนี้:

ssh root@remoteserver '/root/backup.sh </dev/null >/var/log/root-backup.log 2>&1 &'

ไม่ทำงานสำหรับฉันเมื่อใช้กับคำสั่ง ssh

ฉันสร้างสคริปต์ตัวตัดบนเครื่องระยะไกลซึ่งเรียกใช้สคริปต์จริง สคริปต์ wrapper ตั้งค่าการเปลี่ยนเส้นทางและ nohup บางสิ่งเช่นนี้

backupwrapper.sh:
nohup backup.sh > /dev/null 2>&1 &

จากนั้นในเครื่องไคลเอนต์ของฉันฉันเรียกใช้ (สังเกตเห็นการเปลี่ยนเส้นทาง):

# ssh remotemachine "backupwrapper.sh"
#

คำสั่ง ssh ส่งคืนทันทีการเชื่อมต่อถูกยกเลิกและสคริปต์จะยังคงทำงานอยู่


6

ดังที่นิลส์บอกว่าเป็นความเสี่ยงด้านความปลอดภัยที่จะอนุญาตให้รูทเข้าสู่ระบบผ่านทาง ssh และฉันแนะนำไม่ให้ทำงานที่สำคัญบนเครื่องโดยไม่มีบันทึก หากมีสิ่งใดผิดพลาดคุณจะต้องมีข้อความแก้ไขปัญหาบางอย่าง มีคำตอบอื่น ๆ ที่แสดงวิธีการทำเช่นนั้น แต่นี่คือวิธีที่ฉันแนะนำให้ทำสิ่งที่คุณขอให้สำเร็จ มันทั้งหมดสร้างขึ้นในดวลจุดโทษ (1) ไม่จำเป็นต้องใช้หน้าจอ GNU (แม้ว่าฉันคิดว่านั่นเป็นทางออกที่ฉลาด) >&- 2>&- <&- &ผนวกสายนี้กับคำสั่งของคุณ: >&-หมายถึงปิด stdout 2>&-หมายถึง stderr ปิด <&-หมายถึงปิด stdin &หมายถึงทำงานในพื้นหลังเช่น

$ ssh myhost 'sleep 30 >&- 2>&- <&- &'
# ssh returns right away, and your sleep job is running remotely
$

0

remoteserverคุณควรพื้นหลังคำสั่งระยะไกลบน วิธีที่คุณทำมันจะพื้นหลัง localpcSSH-คำสั่งบน

นอกเหนือจากนั้นมันเป็นความคิดที่ดีที่จะอนุญาตให้รูท ssh

ดังนั้นการตั้งค่าบนremoteserver: บรรทัด sudoers ที่จะทำงาน/root/backup.shในฐานะผู้ใช้backupรูท

คุณสามารถสร้างผู้ใช้ที่ไม่มีรหัสผ่าน "ดี"

วางคำสั่งsudo /root/backup.sh &เป็นคำสั่งลงใน~backup/.ssh/authorized_keys- พร้อมกับกุญแจสาธารณะจากlocalpc(ใครก็ตามที่เรียกสคริปต์นั้น)


-1
#screen -d -m -S BACKUP ssh root@remoteserver /root/backup.sh

2
ไม่เป็นประโยชน์มาก: ถ้าการเชื่อมต่อ SSH ตาย stdout และ stderr ของสคริปต์จะถูกปิดซึ่งอาจทำให้เกิดปัญหา หน้าจอควรทำงานบนเครื่องระยะไกล (เช่นเดียวกับคำตอบของ enzotib )
Gilles 'SO- หยุดความชั่วร้าย'
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.