วิธีแก้ปัญหา SSH Permission denied (publickey) เบื้องต้น
แก้ไขปัญหา SSH Permission denied (publickey) ด้วยการรันคำสั่ง ssh -v เพื่อวิเคราะห์สาเหตุที่แท้จริงจาก 5 กรณีที่เป็นไปได้ ช่วยให้คุณปลดล็อกการเข้าถึงเซิร์ฟเวอร์ได้อย่างถูกต้องและปลอดภัย
ความหมายที่แท้จริงของ Permission denied (publickey)
ข้อความ Permission denied (publickey) หมายความว่าไคลเอนต์ของคุณได้ส่ง public key ไปหนึ่งรายการหรือมากกว่านั้น แต่เซิร์ฟเวอร์ไม่ยอมรับเลยสักรายการ ระบบเครือข่ายทำงานปกติและ sshd ก็กำลังทำงานอยู่ การปฏิเสธเกิดขึ้นในขั้นตอนสุดท้ายของการยืนยันตัวตน วิธีแก้ไขไม่ใช่การเดา เพราะ ssh -v จะบอกคุณว่าปัญหาเกิดจากสาเหตุใดใน 5 สาเหตุที่เป็นไปได้
ข้อความในวงเล็บคือวิธีการที่เซิร์ฟเวอร์ยินยอมให้ใช้ในการยืนยันตัวตน หากมีเพียง Permission denied (publickey) แสดงว่าการล็อกอินด้วยรหัสผ่านถูกปิดใช้งานบนเซิร์ฟเวอร์นั้น จึงไม่มีรหัสผ่านให้ใช้สำรอง หากมี Permission denied (publickey,password) หมายความว่ามีการเปิดให้ใช้รหัสผ่านได้ แต่คุณไม่ผ่านการตรวจสอบด้วยวิธีนั้นเช่นกัน
ข้อความเดียวครอบคลุมความผิดพลาดที่แตกต่างกัน 5 ประการ และถูกออกแบบมาให้คลุมเครือโดยเจตนา หากเซิร์ฟเวอร์ตอบกลับว่า "ไม่มีผู้ใช้นี้" หรือ "ไม่ได้ติดตั้งคีย์นี้" จะเป็นการช่วยเหลือผู้ที่กำลังสแกนหาบัญชีผู้ใช้ที่ใช้งานได้ ดังนั้นอย่าเพิ่งสลับคีย์หรือแก้ไขไฟล์ config ให้รันคำสั่งเดียว อ่านผลลัพธ์ 3 บรรทัด แล้วสาเหตุที่เป็นไปได้ 5 ประการจะเหลือเพียงสาเหตุเดียว
เรียกใช้ ssh -v ก่อน แล้วอ่านสามบรรทัดนี้
ให้เรียกใช้คำสั่งที่ล้มเหลวซ้ำอีกครั้ง โดยเพิ่ม -v เข้าไป:
ssh -v deploy@203.0.113.10ตัวอย่างผลลัพธ์ที่ตัดทอนมาแต่เป็นสถานการณ์จริงจะมีลักษณะดังนี้:
OpenSSH_9.6p1 Ubuntu-3ubuntu13, OpenSSL 3.0.13 30 Jan 2024
debug1: Connecting to 203.0.113.10 [203.0.113.10] port 22.
debug1: Connection established.
debug1: Authenticating to 203.0.113.10:22 as 'deploy'
debug1: Authentications that can continue: publickey
debug1: Next authentication method: publickey
debug1: Will attempt key: /home/you/.ssh/id_ed25519 ED25519 SHA256:0eL/8sBw... agent
debug1: Offering public key: /home/you/.ssh/id_ed25519 ED25519 SHA256:0eL/8sBw... agent
debug1: Authentications that can continue: publickey
debug1: No more authentication methods to try.
deploy@203.0.113.10: Permission denied (publickey).ข้อมูลสามบรรทัดนี้มีทุกสิ่งที่คุณจำเป็นต้องทราบ
Authenticating to 203.0.113.10:22 as 'deploy' คือชื่อผู้ใช้ที่จะถูกนำไปใช้งานจริง ไม่ใช่ชื่อที่คุณตั้งใจจะใช้ แต่เป็นชื่อที่ ssh สรุปได้จากบรรทัดคำสั่ง จาก ~/.ssh/config หรือจากชื่อล็อกอินในเครื่องของคุณ
Authentications that can continue: publickey คือรายการวิธีการตรวจสอบสิทธิ์ที่เซิร์ฟเวอร์ยอมรับ ซึ่งจะถูกส่งมาก่อนที่จะมีการลองใช้คีย์ใดๆ หาก publickey ไม่ปรากฏอยู่ในรายการแรกนี้ แสดงว่าเซิร์ฟเวอร์ปิดการล็อกอินด้วย public key ไว้ ดังนั้นจึงไม่มีคีย์ใดที่สามารถใช้งานได้
Offering public key: ... คือบรรทัดที่แสดงคีย์แต่ละรายการที่ไคลเอนต์ของคุณส่งไปจริง โดยระบุชื่อไฟล์ที่คีย์นั้นถูกอ่านมาและค่า SHA256 fingerprint ของคีย์ หากไม่มีบรรทัด Offering แสดงว่าคีย์นั้นไม่เคยถูกส่งไปยังเซิร์ฟเวอร์
ตอนนี้ให้แยกปัญหาออกเป็นสองส่วน:
- ไม่มีบรรทัด
Offering public keyสำหรับคีย์ที่คุณคาดหวัง: ความผิดพลาดอยู่ที่เครื่องของคุณ เพราะเซิร์ฟเวอร์ไม่ได้รับคีย์ของคุณเลย - มีการเสนอคีย์ไปแล้วแต่
Authentications that can continue: publickeyยังคงปรากฏขึ้นมาอีก: เซิร์ฟเวอร์ได้รับคีย์นั้นแล้วแต่ปฏิเสธการใช้งาน ดังนั้นความผิดพลาดอยู่ที่ฝั่งเซิร์ฟเวอร์
สาเหตุต่างๆ ด้านล่างนี้เรียงลำดับตามความถี่ที่มักจะเป็นคำตอบของปัญหา
สาเหตุที่ 1: คุณกำลังเชื่อมต่อด้วยชื่อผู้ใช้ที่ไม่ถูกต้อง
สาเหตุที่พบบ่อยที่สุดกลับเป็นสาเหตุที่น่าเบื่อน้อยที่สุด sshd ซึ่งเป็น SSH (secure shell) server daemon จะไม่แจ้งให้คุณทราบหากบัญชีผู้ใช้งานไม่มีอยู่จริง มันจะดำเนินการแลกเปลี่ยนข้อมูลทั้งหมดสำหรับชื่อผู้ใช้ที่สมมติขึ้นมา และปฏิเสธการเชื่อมต่อในตอนท้ายด้วยข้อความเดียวกัน ทั้งนี้เพื่อป้องกันไม่ให้ผู้โจมตีทราบชื่อบัญชีที่ถูกต้อง การพิมพ์ชื่อผู้ใช้ผิดจึงดูเหมือนกับกุญแจที่ใช้งานไม่ได้ทุกประการ
ตรวจสอบบรรทัด Authenticating to ... as ก่อนดำเนินการอื่นใด หากบรรทัดดังกล่าวระบุชื่อผู้ใช้บนแล็ปท็อปของคุณแทนที่จะเป็นบัญชีบนเซิร์ฟเวอร์ แสดงว่าคุณไม่ได้ระบุชื่อผู้ใช้ในคำสั่ง
ssh -v deploy@203.0.113.10
ssh -v root@203.0.113.10บัญชีผู้ใช้เริ่มต้นขึ้นอยู่กับอิมเมจที่ผู้ให้บริการของคุณสร้างขึ้น ณ เดือนสิงหาคม 2026 อิมเมจ Ubuntu บนคลาวด์มักจะมาพร้อมกับบัญชี ubuntu, อิมเมจ Debian มาพร้อมกับ debian หรือ admin, Rocky Linux และ AlmaLinux มาพร้อมกับ rocky และ almalinux และผู้ให้บริการ VPS หลายรายจะติดตั้งกุญแจของคุณลงใน root โดยตรง แผงควบคุมของผู้ให้บริการของคุณจะบันทึกว่าได้สร้างบัญชีใดไว้ ซึ่งไม่มีคำสั่งใดที่รันจากภายนอกเซิร์ฟเวอร์จะสามารถตรวจสอบข้อมูลนี้ได้
บล็อก Host ใน ~/.ssh/config ยังสามารถกำหนดชื่อผู้ใช้ได้เช่นกัน และจะมีผลเหนือกว่าชื่อผู้ใช้ในเครื่องของคุณ:
Host vps-prod
HostName 203.0.113.10
User deployหากคุณสร้างบัญชีด้วยตนเองแล้วไม่สามารถล็อกอินเข้าใช้งานได้ เป็นไปได้ว่ากุญแจถูกติดตั้งไว้สำหรับผู้ใช้เริ่มต้นของอิมเมจและไม่ได้ถูกคัดลอกมา ขั้นตอนนี้เป็นส่วนหนึ่งของ สิบนาทีแรกบน VPS ใหม่ ซึ่งเป็นขั้นตอนที่ข้ามได้ง่าย
สาเหตุที่ 2: กุญแจที่คุณคิดว่ากำลังส่งอยู่ ไม่ใช่กุญแจที่ถูกส่งจริง
โดยค่าเริ่มต้น ssh จะเสนอเฉพาะกุญแจที่เก็บไว้ใน ssh-agent และชื่อไฟล์ชุดหนึ่งที่กำหนดไว้ใน ~/.ssh ได้แก่ id_ed25519, id_ecdsa, id_rsa รวมถึงกุญแจประเภท hardware และ DSA ของชื่อเหล่านั้น กุญแจที่บันทึกไว้เป็น ~/.ssh/vps-prod จะไม่ปรากฏให้ ssh เห็นจนกว่าคุณจะระบุชื่อไฟล์นั้น ซึ่งเป็นเหตุผลว่าทำไมผลลัพธ์แบบ verbose จึงไม่แสดงบรรทัด Offering public key สำหรับกุญแจดังกล่าว
ให้ระบุชื่อไฟล์และป้องกันไม่ให้กุญแจจาก agent เข้ามาแทนที่:
ssh -i ~/.ssh/vps-prod -o IdentitiesOnly=yes deploy@203.0.113.10การใช้ -i เพียงอย่างเดียวไม่เพียงพอเมื่อ agent มีกุญแจเก็บอยู่ เพราะ ssh จะเสนอชื่อกุญแจจาก agent ก่อนเสมอและเสนอไฟล์ที่ระบุไว้เป็นลำดับสุดท้าย เรื่องนี้มีความสำคัญเนื่องจากเซิร์ฟเวอร์จะนับจำนวนกุญแจที่ถูกปฏิเสธรวมกับค่า MaxAuthTries ซึ่งมีค่าเริ่มต้นเป็น 6 หาก agent เก็บกุญแจไว้ 7 ดอก จำนวนครั้งจะเต็มก่อนที่ระบบจะตรวจสอบถึงกุญแจที่ถูกต้องของคุณ และข้อความจะเปลี่ยนเป็น:
Received disconnect from 203.0.113.10 port 22:2: Too many authentication failuresIdentitiesOnly=yes จะจำกัดการพยายามเชื่อมต่อให้เหลือเพียงไฟล์ที่คุณระบุเท่านั้น ให้ตรวจสอบว่า agent เก็บกุญแจอะไรไว้บ้างด้วย ssh-add -l และล้างข้อมูลออกด้วย ssh-add -D หากพบว่ามีการสะสมกุญแจเก่าไว้เป็นเวลานาน จากนั้นให้บันทึกการตั้งค่าไว้เพื่อให้การเข้าสู่ระบบครั้งถัดไปไม่ต้องพึ่งพาการจำ flag อีก:
Host vps-prod
HostName 203.0.113.10
User deploy
IdentityFile ~/.ssh/vps-prod
IdentitiesOnly yesอีกหนึ่งกับดักที่ฝั่ง client คือ ssh จะปฏิเสธการใช้ private key ที่บัญชีผู้ใช้อื่นบนเครื่องของคุณสามารถอ่านได้ ระบบจะแสดงคำเตือนแล้วเพิกเฉยกุญแจนั้น ทำให้ไม่มีการส่งกุญแจไปและเซิร์ฟเวอร์จะไม่ได้รับกุญแจดังกล่าว:
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: UNPROTECTED PRIVATE KEY FILE! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0644 for '/home/you/.ssh/vps-prod' are too open.chmod 600 ~/.ssh/vps-prod จะช่วยแก้ไขปัญหานี้ การย้ายกุญแจผ่าน USB หรือ Windows share มักเป็นสาเหตุที่ทำให้สิทธิ์การเข้าถึง (mode) สูญหาย ข้อมูลเกี่ยวกับตำแหน่งที่เก็บกุญแจและวิธีการตั้งชื่อกุญแจครอบคลุมอยู่ใน พื้นฐานการจัดการ SSH key
สาเหตุที่ 3: public key ไม่ถูกเพิ่มเข้าไปใน authorized_keys
หาก ssh -v แสดงว่ามีการส่ง key ออกไปแล้วแต่เซิร์ฟเวอร์ยังคงปฏิเสธการเชื่อมต่อ คำถามถัดไปคือ key ดังกล่าวอยู่ในไฟล์ authorized_keys ของบัญชีผู้ใช้นั้นหรือไม่ ให้เปิดคอนโซลของผู้ให้บริการเพื่อตรวจสอบ เนื่องจากคุณไม่สามารถล็อกอินผ่าน SSH เข้าไปดูได้
sudo ls -l /home/deploy/.ssh/
sudo ssh-keygen -lf /home/deploy/.ssh/authorized_keysคำสั่ง ssh-keygen -lf บนไฟล์ authorized_keys จะแสดง fingerprint รายการละหนึ่งบรรทัด:
256 SHA256:0eL/8sBw... you@laptop (ED25519)
3072 SHA256:9Tq2yZk... old-laptop (RSA)ให้เปรียบเทียบค่าเหล่านั้นกับ fingerprint ในบรรทัด Offering public key ของคุณ หากไม่พบในรายการ แสดงว่า key ดังกล่าวไม่ได้ถูกติดตั้งในบัญชีนั้น ไม่ว่าคุณจะจำได้ว่าทำอะไรไปก็ตาม
มี 4 สาเหตุที่พบบ่อยซึ่งทำให้เกิดข้อผิดพลาด:
- คุณคัดลอก private key ไปวางแทนที่จะเป็นไฟล์
.pubโดยบรรทัดของ public key จะต้องขึ้นต้นด้วยssh-ed25519หรือssh-rsaส่วน private key จะขึ้นต้นด้วย-----BEGIN OPENSSH PRIVATE KEY----- - การคัดลอกมีการตัดบรรทัดโดยไม่ตั้งใจ แต่ละรายการจะต้องอยู่บนบรรทัดเดียวเท่านั้น หากมีการตัดบรรทัด ระบบจะอ่าน key เป็นหลายรายการที่เสียหายและไม่ตรงกับค่าใดเลย
- key ถูกเพิ่มเข้าไปใน
/root/.ssh/authorized_keysในขณะที่คุณล็อกอินด้วยชื่อdeployหรือในทางกลับกัน ไฟล์นี้แยกตามบัญชีผู้ใช้และไม่มีการใช้ร่วมกัน - ช่อง "add my key" ของผู้ให้บริการเขียน key ลงในผู้ใช้เริ่มต้นของ image เท่านั้น ทำให้บัญชีที่คุณสร้างขึ้นภายหลังมีไดเรกทอรี
.sshว่างเปล่า
วิธีที่ปลอดภัยในการเพิ่ม key จากคอนโซลในฐานะ root:
sudo install -d -m 700 -o deploy -g deploy /home/deploy/.ssh
sudo tee -a /home/deploy/.ssh/authorized_keys >/dev/null <<'EOF'
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIExampleKeyDataHere you@laptop
EOF
sudo chown deploy:deploy /home/deploy/.ssh/authorized_keys
sudo chmod 600 /home/deploy/.ssh/authorized_keysจากนั้นให้รัน sudo ssh-keygen -lf /home/deploy/.ssh/authorized_keys อีกครั้ง fingerprint ใหม่ควรจะปรากฏอยู่ในรายการ หากคุณมีเครื่องที่ยังสามารถล็อกอินด้วยรหัสผ่านได้ คำสั่ง ssh-copy-id -i ~/.ssh/vps-prod.pub deploy@203.0.113.10 จะทำงานแบบเดียวกันและตั้งค่าสิทธิ์การเข้าถึง (mode) ให้ถูกต้องโดยอัตโนมัติ
สาเหตุที่ 4: ทำไม sshd ถึงเพิกเฉยต่อ authorized_keys เมื่อสิทธิ์การเข้าถึงเปิดกว้างเกินไป
StrictModes yes คือค่าเริ่มต้นของ sshd ภายใต้การตั้งค่านี้ sshd จะปฏิเสธการอ่านไฟล์ authorized_keys หากไฟล์ดังกล่าว ไดเรกทอรี .ssh หรือไดเรกทอรี home ของบัญชีผู้ใช้ สามารถถูกเขียนโดยบุคคลอื่นที่ไม่ใช่เจ้าของได้ สาเหตุนั้นชัดเจนคือ หากกลุ่มหรือบุคคลภายนอกสามารถเขียนข้อมูลลงในไดเรกทอรี home ของคุณได้ บัญชีใดก็ตามที่มีสิทธิ์เข้าถึงนั้นจะสามารถแทนที่ไฟล์ authorized_keys และเข้ายึดการล็อกอินได้ sshd จึงถือว่าเส้นทางที่ไม่น่าเชื่อถือนี้เสมือนไม่มีกุญแจอยู่จริง
ฝั่งไคลเอนต์จะเห็นข้อความ Permission denied ทั่วไป แต่ log ของเซิร์ฟเวอร์จะบันทึกสาเหตุที่แท้จริงไว้ดังนี้:
Authentication refused: bad ownership or modes for directory /home/deploy/.sshหรือในกรณีที่ตัวไฟล์เองเป็นปัญหา:
Authentication refused: bad ownership or modes for file /home/deploy/.ssh/authorized_keysสิ่งที่ sshd จะยอมรับ:
- ไดเรกทอรี home: ต้องไม่เปิดสิทธิ์ให้กลุ่มหรือบุคคลภายนอกเขียนได้
755,750และ700ถือว่าผ่านทั้งหมด ส่วน775และ777จะไม่ผ่าน ~/.ssh: ต้องมีโหมด700~/.ssh/authorized_keys: ต้องมีโหมด600- ความเป็นเจ้าของ: ทั้งสามรายการต้องเป็นของบัญชีผู้ใช้ที่คุณใช้ล็อกอิน ไม่ใช่ของ root
ความเป็นเจ้าของมีความสำคัญพอๆ กับโหมดของไฟล์ ไฟล์ที่อยู่ภายใน /home/deploy/.ssh ซึ่งเป็นของ root จะไม่ผ่านการตรวจสอบเช่นกัน ซึ่งมักเกิดขึ้นเมื่อคุณสร้างไฟล์ด้วยคำสั่ง sudo nano แล้วลืมเปลี่ยนความเป็นเจ้าของกลับมา ให้แก้ไขทั้งสองอย่างพร้อมกันด้วยคำสั่งนี้:
sudo chown -R deploy:deploy /home/deploy/.ssh
sudo chmod 700 /home/deploy/.ssh
sudo chmod 600 /home/deploy/.ssh/authorized_keys
sudo chmod go-w /home/deploy
ls -ld /home/deploy /home/deploy/.sshคำสั่งสุดท้ายจะแสดงผลลัพธ์ที่คุณต้องการ คุณควรตั้งค่าไดเรกทอรี home ให้เป็น drwxr-xr-x หรือเข้มงวดกว่านั้น และตั้งค่า .ssh ให้เป็น drwx------ หากคุณยังไม่เข้าใจสตริงเหล่านี้ โปรดอ่าน วิธีอ่านสตริงสิทธิ์การเข้าถึง เช่น drwxr-xr-x ก่อนที่คุณจะเปลี่ยนโหมดบนเซิร์ฟเวอร์ที่ใช้งานจริง
บน Rocky Linux และ AlmaLinux ให้เพิ่ม SELinux (security-enhanced Linux) เข้าไปในรายการสิ่งที่ควรตรวจสอบด้วย ไดเรกทอรี .ssh ที่ถูกสร้างขึ้นด้วยวิธีที่ไม่ปกติอาจมี label ของไฟล์ที่ไม่ถูกต้อง ทำให้ sshd ถูกปฏิเสธสิทธิ์ในการอ่านแม้ว่าโหมดของไฟล์จะดูถูกต้องแล้วก็ตาม คำสั่ง sudo restorecon -Rv /home/deploy/.ssh จะช่วยคืนค่า label ให้ถูกต้อง และ sudo ausearch -m avc -ts recent จะแสดงให้เห็นว่า SELinux เป็นส่วนประกอบที่ปฏิเสธการเข้าถึงหรือไม่
สาเหตุที่ 5: sshd ถูกตั้งค่าให้ปฏิเสธการเชื่อมต่อของคุณ
การอ่าน /etc/ssh/sshd_config เพียงอย่างเดียวไม่เพียงพอสำหรับระบบ Ubuntu หรือ Debian ในปัจจุบัน ไฟล์ดังกล่าวเริ่มต้นด้วย Include /etc/ssh/sshd_config.d/*.conf และ OpenSSH จะยึดค่าแรกที่พบสำหรับทุกการตั้งค่า ดังนั้นไฟล์เสริมอย่าง 50-cloud-init.conf จึงถูกอ่านก่อนและมีผลเหนือกว่าสิ่งที่คุณแก้ไขในส่วนล่างของไฟล์หลัก นี่คือเหตุผลว่าทำไมการแก้ไขของคุณอาจดูถูกต้องแต่ไม่มีผลใดๆ เลย
ให้สอบถาม sshd เกี่ยวกับการตั้งค่าที่ใช้งานจริง:
sudo sshd -T | grep -Ei 'pubkeyauth|authorizedkeysfile|permitrootlogin|allowusers|allowgroups|denyusers'ผลลัพธ์ที่ปกติจะมีลักษณะดังนี้:
permitrootlogin prohibit-password
pubkeyauthentication yes
authorizedkeysfile .ssh/authorized_keys .ssh/authorized_keys2สิ่งที่ควรตรวจสอบในผลลัพธ์ของคุณ:
pubkeyauthentication no: จะไม่มีคีย์ใดได้รับการยอมรับเลย ค่านี้จะปรากฏในssh -vเป็นรายการAuthentications that can continue:แรกที่ไม่มีpublickeyอยู่ภายในauthorizedkeysfile: ชี้ไปยังตำแหน่งอื่น เช่น/etc/ssh/authorized_keys/%uไฟล์ในโฮมไดเรกทอรีของคุณจะถูกละเลยโดยสิ้นเชิง และกฎเรื่องโหมดจากสาเหตุที่ 4 จะนำไปใช้กับพาธใหม่แทนallowusersหรือallowgroups: หากมีการตั้งค่านี้ บัญชีผู้ใช้ที่ไม่อยู่ในรายการจะถูกปฏิเสธด้วยข้อผิดพลาดนี้โดยไม่มีคำอธิบายเพิ่มเติม ส่วนdenyusersและdenygroupsจะทำงานในลักษณะตรงกันข้ามpermitrootlogin no: ในขณะที่คุณพยายามล็อกอินในฐานะ root ค่าprohibit-passwordเป็นการตั้งค่าระดับกลางที่มีประโยชน์ คืออนุญาตให้ root ใช้คีย์ได้แต่ห้ามใช้รหัสผ่าน
บล็อก Match จะไม่ปรากฏใน sshd -T แบบปกติ เนื่องจากผลลัพธ์ขึ้นอยู่กับว่าใครเป็นผู้เชื่อมต่อ ให้ตรวจสอบการเชื่อมต่อเฉพาะเจาะจงแทน:
sudo sshd -T -C user=deploy,host=vps.example.com,addr=198.51.100.7มีการตั้งค่าอีกหนึ่งอย่างที่ส่งผลต่อคีย์รุ่นเก่า OpenSSH 8.8 ได้หยุดยอมรับลายเซ็น SHA-1 (ssh-rsa) โดยค่าเริ่มต้น ดังนั้นคีย์ RSA ที่เคยใช้งานได้มานานหลายปีอาจหยุดทำงานทันทีหลังจากการอัปเกรดเซิร์ฟเวอร์ ซึ่งฝั่งไคลเอนต์จะแจ้งเตือนไว้อย่างชัดเจน:
debug1: send_pubkey_test: no mutual signature algorithmวิธีแก้ไขที่ถูกต้องคือการสร้างคีย์ใหม่ด้วยคำสั่ง ssh-keygen -t ed25519 -C "deploy@vps-prod" แล้วติดตั้งไฟล์ .pub ตามที่แสดงไว้ข้างต้น การตั้งค่า PubkeyAcceptedAlgorithms +ssh-rsa บนเซิร์ฟเวอร์จะช่วยเปิดใช้งานลายเซ็นเก่าอีกครั้งเพื่อให้คุณเข้าใช้งานได้ในวันนี้ ดังนั้นให้ถือว่าวิธีนี้เป็นเพียงทางผ่านในการเข้าถึงเครื่อง ไม่ใช่วิธีการแก้ไขที่ถาวร การตั้งค่าฝั่งเซิร์ฟเวอร์ส่วนที่เหลือที่ควรตรวจสอบเพิ่มเติมสามารถดูได้ที่ การเพิ่มความปลอดภัยให้กับ SSH server บน VPS
วิธีพิสูจน์ว่า private key ตรงกับ public key ที่ติดตั้งไว้
ความไม่แน่นอนส่วนใหญ่ในข้อผิดพลาดนี้เกิดจากการไม่ทราบว่าไฟล์สองไฟล์เป็นคู่กันหรือไม่ คำสั่งเดียวที่ใช้ตรวจสอบได้คือ:
ssh-keygen -y -f ~/.ssh/vps-prodคำสั่งนี้จะแสดง public key ที่ได้มาจาก private key โดยตรง มันไม่ได้อ่านไฟล์ .pub ที่อยู่ข้างกัน จึงทำให้ทราบค่าที่แท้จริงของ private key แทนที่จะเป็นค่าที่ไฟล์ .pub เก่าระบุไว้ หากกุญแจมีการตั้ง passphrase ไว้ คำสั่งจะถามรหัสผ่าน ซึ่งเป็นการพิสูจน์ว่าคุณยังจำ passphrase นั้นได้
ssh-keygen -lf ~/.ssh/vps-prod.pub
ssh-add -lคำสั่งแรกจะแสดง fingerprint ของไฟล์ public key หนึ่งไฟล์ ส่วนคำสั่งที่สองจะแสดง fingerprint ที่อยู่ใน agent ของคุณ ตอนนี้ให้เปรียบเทียบค่าทั้ง 4 จุด: fingerprint ในบรรทัด Offering public key จาก ssh -v, fingerprint ของไฟล์ .pub ของคุณ, fingerprint ใน ssh-keygen -lf บนไฟล์ authorized_keys ของเซิร์ฟเวอร์ และ fingerprint ใน log ของเซิร์ฟเวอร์ จุดที่ค่าไม่ตรงกันคือจุดที่เกิดข้อผิดพลาดจากฝั่งคุณ
อ่าน log ของเซิร์ฟเวอร์ในขณะที่การล็อกอินล้มเหลว
ระบบจะจงใจไม่แจ้งข้อมูลที่เป็นประโยชน์แก่ฝั่งไคลเอนต์ แต่เซิร์ฟเวอร์จะบันทึกสาเหตุที่แท้จริงไว้ ให้เริ่มการติดตาม log บนเซสชันคอนโซล จากนั้นจึงรันคำสั่ง ssh ที่ล้มเหลวจากแล็ปท็อปของคุณ
sudo journalctl -u ssh -fUbuntu 24.04 ไม่ได้ติดตั้ง rsyslog มาให้โดยค่าเริ่มต้น ดังนั้น /var/log/auth.log อาจไม่มีอยู่บนระบบนั้น สำหรับ Rocky Linux และ AlmaLinux ยูนิตจะมีชื่อว่า sshd และบันทึกข้อมูลเดียวกันจะถูกเก็บไว้ใน /var/log/secure เช่นกัน
ตั้งค่า LogLevel VERBOSE ในไฟล์คอนฟิกูเรชันของ sshd แล้วโหลด service ใหม่ ทุกความพยายามในการเชื่อมต่อหลังจากนี้จะบันทึก fingerprint ที่เซิร์ฟเวอร์ได้รับจริง:
Failed publickey for deploy from 198.51.100.7 port 49812 ssh2: ED25519 SHA256:0eL/8sBw...บรรทัดดังกล่าวจะบอกคุณว่าความผิดพลาดเกิดขึ้นที่ฝั่งใด หากเป็น fingerprint ที่คุณรู้จัก แสดงว่ากุญแจของคุณส่งไปถึงแล้วแต่ถูกเซิร์ฟเวอร์ปฏิเสธ ให้ตรวจสอบสาเหตุที่ 3, 4 และ 5 หากเป็น fingerprint ที่คุณไม่รู้จัก แสดงว่าไคลเอนต์ของคุณส่งกุญแจที่คุณไม่ได้ตั้งใจจะใช้ไป ให้ย้อนกลับไปดูสาเหตุที่ 2
เมื่อ log ยังคงไม่ชัดเจน ให้รัน sshd ตัวที่สองบนพอร์ตอื่นในโหมด debug มันจะทำงานที่ foreground, รองรับการเชื่อมต่อหนึ่งรายการ, แสดงเหตุผลการทำงาน แล้วจึงปิดตัวลง:
sudo /usr/sbin/sshd -ddd -p 2222จากเซสชันคอนโซลบนเซิร์ฟเวอร์เดียวกัน ให้เชื่อมต่อไปยังพอร์ตนั้นผ่าน loopback address:
ssh -p 2222 -i ~/.ssh/vps-prod -o IdentitiesOnly=yes deploy@127.0.0.1การเชื่อมต่อผ่าน 127.0.0.1 จะช่วยตัดปัญหาเรื่อง firewall ออกไปจากการทดสอบ ผลลัพธ์จากโหมด debug จะระบุชื่อไฟล์ที่เปิด, fingerprint ที่นำมาเปรียบเทียบ และเหตุผลที่ปฏิเสธอย่างชัดเจน รวมถึงบรรทัดข้อความอย่างเช่น Authentication refused: bad ownership or modes for directory /home/deploy ให้กด Ctrl+C เมื่อคุณได้คำตอบแล้ว sshd ตัวหลักที่ทำงานบนพอร์ต 22 จะไม่ได้รับผลกระทบใดๆ ตลอดกระบวนการนี้
วิธีป้องกันการถูกล็อกออกจากระบบ
ทุกขั้นตอนที่มีการแก้ไขการตั้งค่าเซิร์ฟเวอร์ จำเป็นต้องมีช่องทางสำรองในการเข้าถึงที่ไม่ขึ้นอยู่กับ SSH ให้ดำเนินการตั้งค่านี้ในขณะที่ SSH ยังใช้งานได้ปกติ อย่ารอจนกว่าจะเกิดปัญหา
- เปิดคอนโซลของผู้ให้บริการผ่านทาง serial หรือ VNC (virtual network computing) และตรวจสอบให้แน่ใจว่าคุณสามารถล็อกอินผ่านช่องทางนั้นได้
- ตรวจสอบให้แน่ใจว่าคุณมีรหัสผ่านท้องถิ่นที่ใช้งานได้สำหรับบัญชีที่มีสิทธิ์ sudo หากคุณไม่มี ให้รีเซ็ตรหัสผ่าน root จากคอนโซลของผู้ให้บริการ ก่อน
- เปิดเซสชัน SSH ปัจจุบันของคุณทิ้งไว้ เซสชันที่เปิดอยู่จะยังคงทำงานต่อไปแม้เกิด
systemctl restart sshดังนั้นมันจึงเป็นช่องทางสำรองหากการตั้งค่าใหม่เกิดข้อผิดพลาด - ตรวจสอบไวยากรณ์ก่อนทำการรีสตาร์ท:
sudo sshd -tจะไม่แสดงผลลัพธ์ใดๆ หากไฟล์ถูกต้อง แต่จะแสดงชื่อไฟล์และหมายเลขบรรทัดที่ผิดพลาดหากมีข้อผิดพลาด - เปิดเทอร์มินัลที่สองและล็อกอินใหม่ก่อนที่จะปิดเทอร์มินัลแรก การตั้งค่าที่ผิดพลาดจะขัดขวางการล็อกอินใหม่แต่จะไม่ส่งผลต่อเซสชันที่เปิดอยู่ ดังนั้นเซสชันที่คุณใช้งานอยู่จะไม่สามารถบอกได้ว่าการเปลี่ยนแปลงนั้นสำเร็จหรือไม่
ทำการรีสตาร์ทด้วย sudo systemctl restart ssh บน Debian และ Ubuntu หรือ sudo systemctl restart sshd บน Rocky Linux และ AlmaLinux สำหรับ Ubuntu 24.04 นั้น sshd จะถูกเริ่มทำงานจาก socket unit ดังนั้นการเปลี่ยนแปลงใน Port หรือ ListenAddress จำเป็นต้องใช้ sudo systemctl restart ssh.socket ก่อนที่การตั้งค่าจะมีผล
FAQ
ทำไมฉันถึงได้รับข้อผิดพลาด Permission denied (publickey) ทั้งที่ key เดียวกันนี้ใช้งานได้บนเซิร์ฟเวอร์อื่น?
เพราะตัว key นั้นปกติ แต่มีบางอย่างในสภาพแวดล้อมที่ผิดปกติ ให้รันคำสั่ง ssh -v แล้วหาบรรทัด Offering public key หากไม่มี key ของคุณแสดงอยู่ แสดงว่า ssh ไม่ได้ส่ง key นั้นไป เนื่องจากไฟล์ไม่ได้อยู่ใน ~/.ssh ด้วยชื่อมาตรฐานและไม่ได้โหลดไว้ใน agent ให้เพิ่มด้วยคำสั่ง -i /path/to/key -o IdentitiesOnly=yes หาก key แสดงอยู่แต่เซิร์ฟเวอร์ยังปฏิเสธ แสดงว่า key นั้นไม่ได้อยู่ในไฟล์ authorized_keys ของบัญชีผู้ใช้นั้น, path ของไฟล์เปิดสิทธิ์ให้ group เขียนได้ หรือการตั้งค่า sshd บล็อกผู้ใช้รายนั้นไว้ ซึ่ง log ของเซิร์ฟเวอร์จะระบุสาเหตุที่แตกต่างกันเหล่านี้
ฉันจะดูได้อย่างไรว่า SSH กำลังส่ง key ไหนอยู่?
ssh -v host จะแสดงบรรทัด debug1: Offering public key: หนึ่งบรรทัดต่อหนึ่ง key โดยระบุไฟล์ต้นทางและ SHA256 fingerprint ของแต่ละ key ไว้ ssh-add -l จะแสดงรายการ fingerprint ที่ agent ถืออยู่ ssh-keygen -lf ~/.ssh/id_ed25519.pub จะแสดง fingerprint ของไฟล์ key ไฟล์เดียว และ ssh-keygen -y -f ~/.ssh/id_ed25519 จะแสดง public key ที่สร้างมาจาก private key นั้นจริงๆ เพื่อให้การล็อกอินสำเร็จ fingerprint จากบรรทัด Offering จะต้องปรากฏอยู่ในผลลัพธ์ของ ssh-keygen -lf ที่รันกับไฟล์ authorized_keys ของเซิร์ฟเวอร์ด้วย
ทำไม sshd ถึงเพิกเฉยต่อไฟล์ authorized_keys ของฉัน?
เพราะ StrictModes ถูกเปิดใช้งานเป็นค่าเริ่มต้น และไฟล์ดังกล่าว, ไดเรกทอรี .ssh หรือ home directory มีสิทธิ์ให้ group หรือผู้อื่นเขียนได้ หรือเป็นเจ้าของโดยบัญชีผู้ใช้ที่ไม่ถูกต้อง sshd จะไม่เชื่อถือ path ที่บุคคลอื่นสามารถแก้ไขได้ จึงทำงานเสมือนว่าไม่มี key อยู่ ให้ตั้งค่าสิทธิ์ home directory เป็น 755 หรือเข้มงวดกว่านั้น, ตั้งค่า .ssh เป็น 700, ตั้งค่า authorized_keys เป็น 600 และตรวจสอบให้แน่ใจว่าทั้งสามรายการมีบัญชีผู้ใช้ที่ล็อกอินเป็นเจ้าของ เมื่อใช้ LogLevel VERBOSE เซิร์ฟเวอร์จะบันทึก Authentication refused: bad ownership or modes for directory /home/deploy/.ssh ไว้
key ของฉันหยุดทำงานทันทีหลังจากอัปเกรดเซิร์ฟเวอร์ เกิดอะไรขึ้น?
หากเป็น RSA key สาเหตุที่เป็นไปได้มากที่สุดคือการเปลี่ยนแปลงเกี่ยวกับ SHA-1 โดย OpenSSH 8.8 ได้ปิดการใช้งานลายเซ็น ssh-rsa SHA-1 เป็นค่าเริ่มต้น ดังนั้น key ที่สามารถลงชื่อได้ด้วยวิธีนั้นเพียงอย่างเดียวจึงถูกปฏิเสธ ผลลัพธ์แบบละเอียดของ client จะแสดง debug1: send_pubkey_test: no mutual signature algorithm ให้สร้าง key สมัยใหม่ด้วย ssh-keygen -t ed25519 และติดตั้งไฟล์ .pub ของมัน หากต้องการเข้าถึงทันที การใช้ PubkeyAcceptedAlgorithms +ssh-rsa บนเซิร์ฟเวอร์จะเปิดใช้งานลายเซ็นแบบเก่าอีกครั้ง และคุณควรลบบรรทัดนั้นออกเมื่อ key ใหม่ใช้งานได้แล้ว
ฉันแก้ไข sshd_config แล้วตอนนี้ล็อกอินไม่ได้เลย ฉันจะกลับเข้าไปได้อย่างไร?
ให้ใช้ console ของผู้ให้บริการของคุณซึ่งไม่ได้ผ่าน SSH ให้ล็อกอินด้วยรหัสผ่านท้องถิ่นที่นั่น แล้วรัน sudo sshd -t เพื่อดูข้อผิดพลาดทางไวยากรณ์และหมายเลขบรรทัด จากนั้นยกเลิกการแก้ไขและรีสตาร์ทบริการ จากนั้นตรวจสอบ sudo sshd -T เพื่อยืนยันค่าที่กำลังทำงานอยู่ เนื่องจากไฟล์ใน /etc/ssh/sshd_config.d/ อาจกำลังเขียนทับการตั้งค่าหลัก หากคุณไม่มีรหัสผ่านท้องถิ่น ให้รีเซ็ตรหัสผ่าน root จาก console ก่อน แล้วจึงซ่อมแซมไฟล์ดังกล่าว