/static/codemoomoo2.png

7. Remote Access (SSH, Cockpit, VNC)

การเข้าถึงระบบจากระยะไกล (Remote Access) เป็นทักษะพื้นฐานที่จำเป็นสำหรับผู้ดูแลระบบ (System Administrator) และนักพัฒนา (Developer) ในยุคที่เซิร์ฟเวอร์ส่วนใหญ่อยู่บน Cloud หรือ Data Center บทความนี้นำเสนอแนวคิด สถาปัตยกรรม การตั้งค่า และเทคนิคขั้นสูงของเครื่องมือ Remote Access ยอดนิยมในโลก Linux ได้แก่ SSH, Cockpit และ VNC พร้อมตัวอย่างการใช้งานจริงและแนวทางด้านความปลอดภัย (Security Best Practices)


7.1 แนวคิด Remote Access

Remote Access หมายถึง การเข้าถึงและควบคุมคอมพิวเตอร์หรือระบบจากตำแหน่งที่อยู่ห่างไกลผ่านเครือข่าย (Network) โดยไม่จำเป็นต้องอยู่หน้าเครื่องจริง ๆ ซึ่งเป็นองค์ประกอบสำคัญของการบริหารจัดการระบบสมัยใหม่ ทั้งในงาน DevOps, Cloud Computing และ Edge Computing

7.1.1 Remote Shell vs Remote Desktop

การเข้าถึงระยะไกลแบ่งออกเป็นสองรูปแบบหลักตามลักษณะ Interface ที่ผู้ใช้ปฏิสัมพันธ์ด้วย:

flowchart LR
    User[("👤 ผู้ใช้
(User)")] --> Choice{ต้องการอะไร?
What is needed?} Choice -->|Text เท่านั้น
Text only| Shell["Remote Shell
(SSH, Mosh)"] Choice -->|กราฟิก
Graphics| Desktop["Remote Desktop
(VNC, RDP, SPICE)"] Choice -->|จัดการระบบผ่านเว็บ
Web management| Web["Web-based
(Cockpit, Webmin)"] Shell --> LowBW["แบนด์วิดธ์ต่ำ
Low Bandwidth
~ KB/s"] Desktop --> HighBW["แบนด์วิดธ์สูง
High Bandwidth
~ MB/s"] Web --> MidBW["แบนด์วิดธ์ปานกลาง
Medium Bandwidth"]

7.1.2 Protocol: SSH, Telnet, RDP, VNC, SPICE, X11 Forwarding

Protocol ที่ใช้สำหรับ Remote Access มีหลากหลาย แต่ละแบบมีจุดแข็ง-จุดอ่อนและ Use Case ที่ต่างกัน

Protocol ประเภท Encryption Default Port จุดเด่น Use Case
SSH Shell ใช่ (AES, ChaCha20) 22/tcp ปลอดภัย, มาตรฐาน Unix/Linux Server admin, file transfer
Telnet Shell ไม่ใช่ (cleartext) 23/tcp เก่าแก่, เบามาก Legacy device, lab เท่านั้น
Mosh Shell ใช่ (UDP-based) 60000-61000/udp ทนต่อเครือข่ายไม่เสถียร มือถือ, Wi-Fi เปลี่ยนบ่อย
RDP Desktop ใช่ (TLS) 3389/tcp Native ใน Windows Remote Windows
VNC Desktop ขึ้นกับ implementation 5900-5999/tcp ข้ามแพลตฟอร์ม Remote Linux GUI
SPICE Desktop ใช่ (TLS) 5900+/tcp ประสิทธิภาพสูง, multimedia KVM/QEMU VM
X11 Forwarding App ผ่าน SSH tunnel ผ่าน 22/tcp ส่งเฉพาะหน้าต่างแอป รันโปรแกรม GUI ทีละตัว

⚠️ Telnet ส่งข้อมูลทุกอย่าง (รวม username/password) เป็น cleartext ห้ามใช้บน Public Network เด็ดขาด ปัจจุบันถูกแทนที่ด้วย SSH โดยสมบูรณ์

7.1.3 ความสำคัญของการเข้ารหัสและ Authentication

ในการเข้าถึงระยะไกล มีองค์ประกอบสามประการที่ต้องคำนึงถึงเสมอ ตามหลัก CIA Triad:

  1. Confidentiality (ความลับ) ข้อมูลที่ส่งระหว่าง Client กับ Server ต้องไม่ถูกดักฟัง (Eavesdropping) แม้แต่ผู้ที่ควบคุมเส้นทางเครือข่ายระหว่างทาง — แก้ไขด้วย Encryption
  2. Integrity (ความถูกต้อง) ข้อมูลต้องไม่ถูกแก้ไขระหว่างทาง (Man-in-the-Middle Attack) — แก้ไขด้วย MAC (Message Authentication Code) หรือ HMAC
  3. Authentication (การพิสูจน์ตัวตน) ทั้งผู้ใช้และเซิร์ฟเวอร์ต้องพิสูจน์ตัวตนซึ่งกันและกัน — แก้ไขด้วย Public Key Cryptography, Password, MFA

ความแข็งแรงของการเข้ารหัสสามารถวัดได้จากจำนวน Operations ที่ผู้โจมตีต้องใช้ใน Brute-force Attack ซึ่งสำหรับ key ขนาด n บิต จะมีค่าเท่ากับ:

W = 2n

โดยที่ W คือจำนวน Operations เฉลี่ยที่ต้องใช้ในการเดา Key สำเร็จ และ n คือขนาดของ Key (เป็นบิต) — ตัวอย่างเช่น AES-256 ต้องใช้ 2256 Operations ซึ่งเป็นไปไม่ได้ในทางปฏิบัติแม้ใช้ supercomputer ที่เร็วที่สุดในโลก


7.2 SSH (Secure Shell)

SSH (Secure Shell) เป็น Protocol และโปรแกรมที่ออกแบบมาแทนที่ Telnet, rlogin, rsh ที่ไม่ปลอดภัย โดย Tatu Ylönen สร้างขึ้นในปี 1995 ปัจจุบันมาตรฐานที่ใช้คือ SSH-2 (RFC 4251-4254) และ implementation ที่นิยมที่สุดคือ OpenSSH

7.2.1 สถาปัตยกรรม Client-Server

SSH ทำงานในรูปแบบ Client-Server Architecture ดังนี้:

flowchart TB
    subgraph Client["💻 SSH Client (ฝั่งผู้ใช้)"]
        SC[ssh command]
        CK[("Client Keys
~/.ssh/id_ed25519")] KH[("Known Hosts
~/.ssh/known_hosts")] end subgraph Network["🌐 Network (Internet/LAN)"] Pkt["Encrypted Packets
(AES, ChaCha20)
Port 22/tcp"] end subgraph Server["🖥️ SSH Server (ฝั่งเซิร์ฟเวอร์)"] SD[sshd Daemon] HK[("Host Keys
/etc/ssh/ssh_host_*")] AK[("authorized_keys
~/.ssh/authorized_keys")] Cfg[("sshd_config
/etc/ssh/sshd_config")] end SC --> Pkt --> SD SD --> Pkt --> SC CK -.อ่าน.-> SC KH -.ตรวจสอบ.-> SC HK -.อ่าน.-> SD AK -.ตรวจสอบ.-> SD Cfg -.อ่าน.-> SD

7.2.2 Handshake และการเข้ารหัส (Symmetric + Asymmetric + Hashing)

การเชื่อมต่อ SSH ใช้การเข้ารหัสสามแบบรวมกันเพื่อความปลอดภัย:

  1. Asymmetric Cryptography (Public-Key) ใช้ในขั้นตอน Handshake และ Authentication เช่น RSA, Ed25519, ECDSA — ช้าแต่ไม่ต้องแชร์ secret
  2. Symmetric Cryptography ใช้เข้ารหัสข้อมูลในระหว่าง session เช่น AES-256-GCM, ChaCha20-Poly1305 — เร็วกว่ามาก
  3. Hashing/MAC ใช้ตรวจสอบ Integrity เช่น HMAC-SHA-256, HMAC-SHA-512

ขั้นตอน Handshake (แบบสรุป) มีดังนี้:

sequenceDiagram
    participant C as 💻 Client
    participant S as 🖥️ Server
    C->>S: 1. TCP SYN → port 22
    S->>C: 2. SSH Version String (SSH-2.0-OpenSSH_9.x)
    C->>S: 3. SSH Version String
    Note over C,S: 4. Algorithm Negotiation
(KEX, Cipher, MAC) C->>S: 5. KEXINIT (รายการ algorithms) S->>C: 6. KEXINIT (เลือก algorithms ร่วม) Note over C,S: 7. Key Exchange
(ECDH/Curve25519) C->>S: 8. Public Key (ephemeral) S->>C: 9. Public Key + Host Key + Signature Note over C,S: 10. คำนวณ Shared Secret K C->>S: 11. NEWKEYS (เปลี่ยนเป็น symmetric) S->>C: 12. NEWKEYS Note over C,S: 🔒 ช่องสัญญาณเข้ารหัสพร้อม C->>S: 13. User Authentication S->>C: 14. Auth Success → Open Shell/Channel

หลักการ Diffie-Hellman Key Exchange ที่ใช้ใน SSH สามารถอธิบายด้วยสมการได้ว่า ทั้งสองฝ่ายตกลงเลขสาธารณะ p (จำนวนเฉพาะ) และ g (generator) จากนั้น Client เลือก secret a และ Server เลือก secret b แล้วต่างคำนวณ:

A = ga mod p , B = gb mod p

จากนั้นแลกเปลี่ยน A และ B และคำนวณ Shared Secret K:

K = Ba mod p = Ab mod p = gab mod p

โดยที่ K คือ Shared Secret ที่ทั้งสองฝ่ายได้ค่าเดียวกันโดยไม่เคยส่ง a หรือ b ผ่านเครือข่าย — ผู้ดักฟังจะเห็นเพียง p,g,A,B แต่ไม่สามารถคำนวณ K ได้ในเวลาที่สมเหตุสมผล (Discrete Logarithm Problem) ปัจจุบัน SSH นิยมใช้ Elliptic Curve Diffie-Hellman (ECDH) บน Curve25519 แทนเพื่อความเร็วและความปลอดภัยที่สูงขึ้น

7.2.3 การเชื่อมต่อพื้นฐาน

# การเชื่อมต่อแบบพื้นฐาน — รูปแบบ user@host
ssh moo@server.rmutsv.ac.th

# ระบุพอร์ตที่ไม่ใช่ default 22 ด้วย -p
ssh -p 2222 moo@10.0.0.50

# ระบุ identity file (private key) ที่จะใช้
ssh -i ~/.ssh/id_ed25519_lab moo@10.0.0.50

# เปิด verbose mode สำหรับ debug การเชื่อมต่อ (-v, -vv, -vvv)
ssh -vvv moo@10.0.0.50

# รันคำสั่งเดียวบนเซิร์ฟเวอร์แล้วปิดทันที (ไม่ได้ shell)
ssh moo@10.0.0.50 'uptime && df -h'

# ใช้ ssh เป็น "pipe" — รันคำสั่งบน remote แล้วเอาผลกลับมา process ฝั่ง local
ssh moo@10.0.0.50 'cat /var/log/syslog' | grep ERROR | wc -l

ตัวอย่างผลลัพธ์ที่จะเห็นเมื่อเชื่อมต่อสำเร็จ:

$ ssh moo@10.0.0.50
The authenticity of host '10.0.0.50 (10.0.0.50)' can't be established.
ED25519 key fingerprint is SHA256:abc123def456...xyz
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.0.0.50' (ED25519) to the list of known hosts.
moo@10.0.0.50's password: ********
Welcome to Ubuntu 24.04 LTS (GNU/Linux 6.8.0-generic x86_64)
moo@server:~$

7.2.4 Known Hosts และ Host Key Verification

เมื่อเชื่อมต่อ SSH ครั้งแรก Client จะบันทึก Host Key (กุญแจสาธารณะของ Server) ลงในไฟล์ ~/.ssh/known_hosts ครั้งต่อไป Client จะตรวจสอบว่า Host Key ตรงกับครั้งก่อนหรือไม่ — กลไกนี้ป้องกัน Man-in-the-Middle Attack

# ดูเนื้อหาไฟล์ known_hosts
cat ~/.ssh/known_hosts

# ตัวอย่าง entry หนึ่งบรรทัด:
# 10.0.0.50 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO...

# ลบ entry ของ host เดียว (เช่น เปลี่ยนเซิร์ฟเวอร์แล้วได้ key ใหม่)
ssh-keygen -R 10.0.0.50

# ตรวจสอบ fingerprint ของ host key (รันบนเซิร์ฟเวอร์)
ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub

# ตรวจสอบ fingerprint ของ host จากระยะไกล (ก่อนเชื่อมต่อจริง)
ssh-keyscan -t ed25519 server.rmutsv.ac.th | ssh-keygen -lf -

💡 Best Practice: เมื่อเห็นข้อความ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! ห้าม กด yes ทันที ให้ตรวจสอบกับผู้ดูแลระบบเสมอว่ามีการเปลี่ยน host key จริงหรือไม่ มิฉะนั้นอาจตกเป็นเหยื่อ MitM Attack


7.3 SSH Authentication

SSH รองรับการพิสูจน์ตัวตน (Authentication) หลายแบบ ซึ่งสามารถใช้ผสมกัน (Multi-method) ได้ตามนโยบายความปลอดภัย

7.3.1 Password Authentication

วิธีที่ง่ายที่สุดคือใช้ Username/Password ของระบบ (ตรงกับใน /etc/passwd และ /etc/shadow) แต่มีข้อเสียคือ:

# ปิด Password Auth ใน sshd_config (แนะนำสำหรับ production)
sudo sed -i 's/^#*PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo systemctl reload sshd

7.3.2 Public Key Authentication

วิธีที่ปลอดภัยและสะดวกที่สุดคือ Public Key Authentication ซึ่งใช้คู่กุญแจ (Key Pair):

หลักการคือ Server ส่ง Challenge ที่เข้ารหัสด้วย Public Key ของผู้ใช้ Client ต้องใช้ Private Key ในการ decrypt และตอบกลับ ถ้าตอบถูก แสดงว่าเป็นเจ้าของ key จริง

sequenceDiagram
    participant C as 💻 Client
(มี Private Key) participant S as 🖥️ Server
(มี authorized_keys) C->>S: 1. ขอ Login เป็น user "moo" S->>S: 2. อ่าน ~moo/.ssh/authorized_keys S->>C: 3. ส่ง Challenge (random data)
encrypted ด้วย Public Key C->>C: 4. Decrypt Challenge ด้วย Private Key C->>S: 5. ส่ง Hash ของ Challenge กลับ S->>S: 6. ตรวจสอบ Hash S->>C: 7. ✅ Auth Success → เปิด Shell

7.3.3 การสร้าง Key ด้วย ssh-keygen (RSA, Ed25519, ECDSA)

# สร้าง Ed25519 key (แนะนำ — เร็ว, ปลอดภัย, key สั้น)
ssh-keygen -t ed25519 -C "moo@rmutsv-laptop" -f ~/.ssh/id_ed25519

# สร้าง RSA 4096-bit (compatibility กับระบบเก่า)
ssh-keygen -t rsa -b 4096 -C "moo@rmutsv-laptop" -f ~/.ssh/id_rsa

# สร้าง ECDSA (ทางเลือก — แต่นิยมน้อยกว่า Ed25519)
ssh-keygen -t ecdsa -b 521 -C "moo@rmutsv-laptop"

# ดู public key ที่สร้าง
cat ~/.ssh/id_ed25519.pub
# ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO... moo@rmutsv-laptop

# ดู fingerprint ของ key
ssh-keygen -lf ~/.ssh/id_ed25519.pub
# 256 SHA256:abc123... moo@rmutsv-laptop (ED25519)

# เปลี่ยน passphrase ของ private key เดิม
ssh-keygen -p -f ~/.ssh/id_ed25519

ตารางเปรียบเทียบประเภทของ Key:

ประเภท ขนาดที่แนะนำ ความเร็ว ขนาด Public Key สถานะปัจจุบัน
Ed25519 256-bit (fixed) ⚡⚡⚡ เร็วที่สุด สั้น (~80 chars) ✅ แนะนำ
RSA ≥ 3072-bit ⚡ ช้าที่สุด ยาวมาก (~700+ chars) ⚠️ ใช้ได้ ต้อง ≥ 3072
ECDSA 256/384/521-bit ⚡⚡ เร็ว ปานกลาง ⚠️ ใช้ได้ แต่นิยมน้อย
DSA 1024-bit ช้า ปานกลาง ❌ ห้ามใช้ (deprecated)

7.3.4 ssh-copy-id และ authorized_keys

# วิธีง่ายที่สุด: ใช้ ssh-copy-id ส่ง public key ไปยัง server
ssh-copy-id -i ~/.ssh/id_ed25519.pub moo@10.0.0.50

# วิธี manual (ถ้าไม่มี ssh-copy-id เช่น บน Windows)
cat ~/.ssh/id_ed25519.pub | ssh moo@10.0.0.50 \
    'mkdir -p ~/.ssh && chmod 700 ~/.ssh && \
     cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys'

# ทดสอบเชื่อมต่อ — ไม่ควรถาม password อีกแล้ว
ssh moo@10.0.0.50

# ตรวจสอบเนื้อหา authorized_keys บนเซิร์ฟเวอร์
ssh moo@10.0.0.50 'cat ~/.ssh/authorized_keys'

โครงสร้างของ authorized_keys แต่ละบรรทัดมีรูปแบบ:

[options] keytype base64-encoded-key comment

ตัวอย่างพร้อม options เพื่อจำกัดสิทธิ์ของ key:

# จำกัดให้ key นี้รันได้เฉพาะคำสั่ง backup เท่านั้น (ห้าม shell)
command="/usr/local/bin/backup.sh",no-port-forwarding,no-pty,no-X11-forwarding ssh-ed25519 AAAA... backup-job

# จำกัด IP ที่อนุญาตให้ใช้ key นี้
from="10.0.0.0/24,192.168.1.5" ssh-ed25519 AAAA... office-only

# key สำหรับ Git deploy (อ่านอย่างเดียว ไม่ต้องการ shell)
command="git-shell",no-pty,no-X11-forwarding ssh-rsa AAAA... deploy-key

7.3.5 ssh-agent และ ssh-add

ssh-agent เป็นโปรแกรมที่จดจำ Private Key (หลังถอด passphrase แล้ว) ไว้ในหน่วยความจำ ทำให้ผู้ใช้ไม่ต้องพิมพ์ passphrase ทุกครั้ง

# เริ่ม ssh-agent ใน shell ปัจจุบัน (ส่วนใหญ่ desktop env เริ่มให้อยู่แล้ว)
eval "$(ssh-agent -s)"

# เพิ่ม key เข้า agent (ถาม passphrase ครั้งเดียว)
ssh-add ~/.ssh/id_ed25519

# เพิ่ม key พร้อมหมดอายุใน 1 ชั่วโมง (ปลอดภัยกว่า)
ssh-add -t 3600 ~/.ssh/id_ed25519

# ดู keys ที่อยู่ใน agent ขณะนี้
ssh-add -l

# ลบ key ออกจาก agent
ssh-add -d ~/.ssh/id_ed25519

# ลบทุก keys ออกจาก agent
ssh-add -D

Agent Forwarding ทำให้สามารถใช้ key จากเครื่อง local ผ่านเซิร์ฟเวอร์กลางได้ (เช่น hop ไปอีกเครื่อง):

# เปิด agent forwarding ด้วย -A
ssh -A moo@bastion.rmutsv.ac.th
# เมื่อเข้าไปแล้ว สามารถ ssh ต่อไปยังเครื่องอื่นโดยใช้ key เดิมได้
moo@bastion:~$ ssh moo@internal-server

⚠️ Agent Forwarding มีความเสี่ยง — ถ้าเซิร์ฟเวอร์กลางถูกแฮ็ก ผู้โจมตีสามารถใช้ key ของคุณได้ ควรใช้ ProxyJump (-J) แทนเป็นทางเลือกที่ปลอดภัยกว่า

7.3.6 Passphrase และ Key Management

Passphrase คือรหัสผ่านที่ใช้เข้ารหัส Private Key อีกชั้น — แม้ Private Key รั่วไหล ผู้โจมตีก็ยังต้องเดา passphrase อีก

แนวทางจัดการ Key อย่างปลอดภัย:

  1. ใช้ passphrase ที่แข็งแรงเสมอ — อย่างน้อย 16 ตัวอักษร mix อักษร-ตัวเลข-สัญลักษณ์
  2. ใช้ ssh-agent เพื่อไม่ต้องพิมพ์ passphrase ทุกครั้ง
  3. แยก key ตาม role/environment เช่น id_ed25519_personal, id_ed25519_work, id_ed25519_lab
  4. กำหนดสิทธิ์ไฟล์ให้ถูกต้อง: ~/.ssh = 700, private key = 600, public key = 644
  5. เปลี่ยน key เป็นระยะ (key rotation) อย่างน้อยปีละครั้งสำหรับ production
  6. เก็บ backup ของ key ใน password manager ที่เข้ารหัส (เช่น Bitwarden, 1Password)
  7. ใช้ Hardware Token เช่น YubiKey, Nitrokey สำหรับ key สำคัญ
# ตรวจสอบและแก้ไข permission อัตโนมัติ
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519 ~/.ssh/authorized_keys ~/.ssh/config
chmod 644 ~/.ssh/id_ed25519.pub ~/.ssh/known_hosts

7.4 การตั้งค่า SSH

การตั้งค่า SSH แบ่งเป็นสองฝั่ง: Client config สำหรับผู้ใช้ที่เชื่อมต่อออก และ Server config สำหรับเครื่องที่รับการเชื่อมต่อ

7.4.1 Client config (~/.ssh/config)

ไฟล์ ~/.ssh/config ช่วยให้กำหนด alias และ option ของแต่ละ host ทำให้พิมพ์คำสั่งสั้นลงและจำง่ายขึ้น

# ~/.ssh/config — ตัวอย่าง config ที่ใช้งานจริง

# === Default settings สำหรับทุก host ===
Host *
    ServerAliveInterval 60
    ServerAliveCountMax 3
    Compression yes
    HashKnownHosts yes
    AddKeysToAgent yes
    IdentitiesOnly yes

# === เซิร์ฟเวอร์มหาวิทยาลัย ===
Host rmutsv-server
    HostName 202.xx.xx.xx
    User moo
    Port 2222
    IdentityFile ~/.ssh/id_ed25519_rmutsv

# === เซิร์ฟเวอร์ใน Lab (เข้าผ่าน bastion) ===
Host lab-bastion
    HostName bastion.lab.rmutsv.ac.th
    User moo
    IdentityFile ~/.ssh/id_ed25519_lab

Host lab-*
    User student
    IdentityFile ~/.ssh/id_ed25519_lab
    ProxyJump lab-bastion

Host lab-web
    HostName 10.10.0.10

Host lab-db
    HostName 10.10.0.20

# === GitHub (สำหรับ git over SSH) ===
Host github.com
    User git
    IdentityFile ~/.ssh/id_ed25519_github
    IdentitiesOnly yes

# === Wildcard pattern ===
Host *.rmutsv.ac.th
    User moo
    ForwardAgent no

ผลลัพธ์: แทนที่จะพิมพ์ ssh -i ~/.ssh/id_ed25519_rmutsv -p 2222 moo@202.xx.xx.xx ก็พิมพ์เพียง ssh rmutsv-server ได้ทันที และ ssh lab-web จะ ProxyJump ผ่าน bastion ให้อัตโนมัติ

7.4.2 Server config (/etc/ssh/sshd_config)

ตัวอย่าง sshd_config ที่ปลอดภัยและพร้อมใช้งานจริง:

# /etc/ssh/sshd_config — Production-ready hardened config

# === Network ===
Port 2222                          # เปลี่ยนจาก 22 เพื่อลด noise จาก bot
AddressFamily inet                 # ใช้ IPv4 เท่านั้น (หรือ any สำหรับ dual-stack)
ListenAddress 0.0.0.0
Protocol 2                         # ห้าม SSH-1 เด็ดขาด

# === Host Keys ===
HostKey /etc/ssh/ssh_host_ed25519_key
HostKey /etc/ssh/ssh_host_rsa_key

# === Authentication ===
LoginGraceTime 30
PermitRootLogin no                 # ห้าม login เป็น root โดยตรง
StrictModes yes
MaxAuthTries 3
MaxSessions 5

PubkeyAuthentication yes
PasswordAuthentication no          # ปิด password auth (ใช้ key เท่านั้น)
PermitEmptyPasswords no
ChallengeResponseAuthentication no
KbdInteractiveAuthentication no
UsePAM yes

# === User/Group restrictions ===
AllowUsers moo admin deploy
# AllowGroups ssh-users
DenyUsers root guest

# === Forwarding (เปิดเฉพาะที่จำเป็น) ===
AllowTcpForwarding yes
AllowAgentForwarding no            # ปิดเป็น default — เปิดต่อเมื่อจำเป็น
X11Forwarding no
PermitTunnel no
GatewayPorts no

# === Misc ===
ClientAliveInterval 300
ClientAliveCountMax 2
PrintMotd no
PrintLastLog yes
TCPKeepAlive yes
UseDNS no                          # speed up login
Banner /etc/issue.net

# === Crypto Hardening (ตัด weak algorithms) ===
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com
HostKeyAlgorithms ssh-ed25519,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-256

# === Subsystems ===
Subsystem sftp /usr/lib/openssh/sftp-server

หลังแก้ไข ต้องตรวจสอบ syntax และ reload service:

# ตรวจสอบ syntax ของ config (ห้าม restart ก่อนตรวจ!)
sudo sshd -t

# ถ้าไม่มี error ค่อย reload
sudo systemctl reload sshd

# ถ้า reload ไม่ได้ผล (เช่นเปลี่ยน port) ใช้ restart
sudo systemctl restart sshd

# ตรวจสอบสถานะ
sudo systemctl status sshd

# ดู log ล่าสุด
sudo journalctl -u sshd -n 50 --no-pager

⚠️ คำเตือน: ก่อน restart sshd ให้เปิด session ที่สองทิ้งไว้เสมอ! ถ้า config ผิด session ปัจจุบันจะยังอยู่ แต่ session ใหม่จะเข้าไม่ได้ — ต้องใช้ session ที่สองในการแก้

7.4.3 Hardening: Port Change, PermitRootLogin no, AllowUsers

แนวทาง Hardening พื้นฐานที่ควรทำกับทุก SSH Server:

  1. เปลี่ยน Port จาก 22 เป็น port อื่น (เช่น 2222, 22022) — ลด noise ของ automated scan ลง 95%+
  2. ห้าม Root Login ใช้ PermitRootLogin no แล้ว sudo แทน
  3. ปิด Password Auth ใช้ key เท่านั้น
  4. จำกัด User ด้วย AllowUsers หรือ AllowGroups
  5. จำกัด IP ด้วย Firewall (ufw, firewalld, iptables) ให้รับเฉพาะจาก subnet ที่ไว้ใจ
  6. Update sshd อย่างสม่ำเสมอ เพื่อรับ security patch

ตัวอย่างการตั้ง firewall เพื่อจำกัด SSH:

# ufw (Ubuntu/Debian)
sudo ufw allow from 10.0.0.0/24 to any port 2222 proto tcp
sudo ufw deny 2222/tcp

# firewalld (Fedora/RHEL)
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.0.0.0/24" port port="2222" protocol="tcp" accept'
sudo firewall-cmd --reload

# nftables
sudo nft add rule inet filter input tcp dport 2222 ip saddr 10.0.0.0/24 accept
sudo nft add rule inet filter input tcp dport 2222 drop

7.4.4 Fail2Ban / CrowdSec สำหรับป้องกัน Brute Force

Fail2Ban เป็นโปรแกรมที่อ่าน log และ ban IP ที่พยายาม login ผิดเกินจำนวนครั้งที่กำหนด

# ติดตั้ง
sudo apt install fail2ban -y       # Debian/Ubuntu
sudo dnf install fail2ban -y       # Fedora/RHEL

# สร้างไฟล์ jail.local (ห้ามแก้ jail.conf โดยตรง)
sudo tee /etc/fail2ban/jail.local <<'EOF'
[DEFAULT]
bantime  = 1h
findtime = 10m
maxretry = 5
backend  = systemd

[sshd]
enabled = true
port    = 2222
logpath = %(sshd_log)s
EOF

# เริ่มและ enable
sudo systemctl enable --now fail2ban

# ดู IP ที่ถูก ban
sudo fail2ban-client status sshd

# unban IP เฉพาะ (กรณีตัวเองโดน)
sudo fail2ban-client set sshd unbanip 1.2.3.4

CrowdSec เป็นทางเลือกใหม่ที่ทันสมัยกว่า — มี community blocklist แชร์กันทั่วโลก

7.4.5 sshd log และ auditing

# ดู log ของ sshd แบบ real-time
sudo journalctl -u sshd -f

# ดู login ที่สำเร็จในวันนี้
sudo journalctl -u sshd --since today | grep "Accepted"

# ดู login ที่ล้มเหลว
sudo journalctl -u sshd --since "1 hour ago" | grep -E "Failed|Invalid"

# คำสั่ง last — ดูประวัติ login ทั้งหมด
last -a | head -20

# lastb — ดู login ที่ล้มเหลว (ต้อง root)
sudo lastb -a | head -20

# ดู IP ที่พยายาม brute-force มากที่สุด
sudo journalctl -u sshd --since "1 day ago" \
    | grep "Failed password" \
    | grep -oE 'from [0-9.]+' \
    | sort | uniq -c | sort -rn | head -10

7.5 SSH ขั้นสูง

SSH ไม่ได้เป็นเพียงแค่ Remote Shell — แต่ยังเป็นเครื่องมือ Tunneling ที่ทรงพลังที่สุดตัวหนึ่ง สามารถใช้สร้างช่องทางเข้ารหัสสำหรับ Protocol อื่น ๆ ได้

7.5.1 Local Port Forwarding (-L)

Local Port Forwarding เปิดพอร์ตบนเครื่อง Client แล้วส่ง traffic ผ่าน SSH ไปยังเป้าหมายฝั่ง Server หรือเครื่องที่ Server เห็นได้ — ใช้สำหรับ เข้าถึงบริการที่อยู่หลัง firewall

รูปแบบ: ssh -L [bind_addr:]local_port:target_host:target_port user@ssh_server

flowchart LR
    subgraph Local["🏠 เครื่อง Local (ของเรา)"]
        Browser[("Browser/App
localhost:8080")] end subgraph SSHC["🔒 SSH Tunnel (Encrypted)"] Tunnel["ssh -L 8080:db:5432
user@bastion"] end subgraph Remote["🌐 Remote Network (ที่ทำงาน)"] Bastion["Bastion
(SSH Server)"] DB[("Database Server
db:5432")] end Browser -->|1. connect| Tunnel Tunnel -->|2. encrypted| Bastion Bastion -->|"3. plaintext
(internal)"| DB
# ตัวอย่าง: เข้าถึง PostgreSQL บน internal server ผ่าน bastion
# - เปิด port 5432 บน localhost
# - ผ่าน SSH ไปที่ bastion.example.com
# - แล้ว forward ไปที่ db.internal:5432
ssh -L 5432:db.internal:5432 moo@bastion.example.com

# จากนั้นเชื่อมต่อ DB ได้เลยที่ localhost:5432
psql -h localhost -p 5432 -U appuser mydb

# Forward หลายพอร์ตในคราวเดียว
ssh -L 5432:db:5432 -L 6379:redis:6379 -L 9200:elasticsearch:9200 \
    moo@bastion.example.com

# Background mode (-f) + ไม่ execute remote command (-N)
ssh -fN -L 5432:db:5432 moo@bastion.example.com

7.5.2 Remote Port Forwarding (-R)

Remote Port Forwarding เปิดพอร์ตบนเครื่อง Server แล้วส่ง traffic กลับมายังเครื่อง Client — ใช้สำหรับ expose บริการบนเครื่อง local ให้คนภายนอกเข้าถึงได้

รูปแบบ: ssh -R [bind_addr:]remote_port:target_host:target_port user@ssh_server

# ตัวอย่าง: เปิด web dev server บน localhost:3000 ของเรา
# ให้คนเข้าถึงได้ที่ public-server:8080
ssh -R 8080:localhost:3000 moo@public-server.com

# ถ้าต้องการให้ bind 0.0.0.0 ของ remote (ไม่ใช่แค่ localhost)
# ต้องตั้ง GatewayPorts yes ใน sshd_config ของ remote ก่อน
ssh -R 0.0.0.0:8080:localhost:3000 moo@public-server.com

💡 ทางเลือกสมัยใหม่สำหรับงานนี้: ใช้ ngrok, cloudflared, localtunnel, frp หรือ rathole ที่ออกแบบมาเฉพาะ

7.5.3 Dynamic Port Forwarding / SOCKS Proxy (-D)

Dynamic Port Forwarding เปลี่ยน SSH ให้กลายเป็น SOCKS5 Proxy สามารถใช้ proxy traffic ของแอปต่าง ๆ ผ่าน SSH ได้ทั้งหมด

# เปิด SOCKS5 proxy ที่ localhost:1080 ผ่าน SSH
ssh -D 1080 moo@bastion.example.com

# ใช้ curl ผ่าน SOCKS proxy
curl --socks5 localhost:1080 https://internal-app.company.com

# ตั้ง Firefox/Chrome ให้ใช้ proxy 127.0.0.1:1080 (SOCKS5)
# จะสามารถเปิดเว็บภายในได้ทั้งหมด

# Background mode
ssh -fND 1080 moo@bastion.example.com

7.5.4 Jump Host / ProxyJump (-J)

ProxyJump ทำให้สามารถ SSH ทะลุผ่านเครื่องกลาง (Bastion / Jump Host) ไปยังเครื่องปลายทางได้ในคำสั่งเดียว — ปลอดภัยกว่า Agent Forwarding

# Hop เดียว: local → bastion → target
ssh -J moo@bastion.example.com student@10.10.0.20

# Multiple hops: local → bastion1 → bastion2 → target
ssh -J moo@bastion1,moo@bastion2 student@10.10.0.20

# กำหนดใน ~/.ssh/config (สะดวกกว่า)
# Host lab-target
#     HostName 10.10.0.20
#     User student
#     ProxyJump moo@bastion.example.com
ssh lab-target

7.5.5 SSH Tunnel สำหรับ Database

ตัวอย่างการใช้ SSH Tunnel เข้าถึง MySQL/PostgreSQL บน server ที่ไม่เปิด port ออกเน็ต:

# === MySQL ===
# Terminal 1: เปิด tunnel
ssh -fN -L 3307:localhost:3306 moo@db.rmutsv.ac.th

# Terminal 2: เชื่อมต่อ MySQL ผ่าน tunnel
mysql -h 127.0.0.1 -P 3307 -u dbuser -p mydatabase

# === PostgreSQL ===
# Tunnel
ssh -fN -L 5433:localhost:5432 moo@db.rmutsv.ac.th

# เชื่อมต่อ
psql "host=127.0.0.1 port=5433 user=dbuser dbname=mydb sslmode=disable"

# === MongoDB ===
ssh -fN -L 27018:localhost:27017 moo@db.rmutsv.ac.th
mongosh mongodb://127.0.0.1:27018/mydb

# ปิด tunnel ที่รันแบบ background
pkill -f "ssh -fN -L"
# หรือ
ps aux | grep "ssh -fN" | awk '{print $2}' | xargs kill

7.5.6 X11 Forwarding (-X, -Y)

X11 Forwarding ทำให้สามารถรันโปรแกรม GUI บน server แล้วแสดงผลที่หน้าจอของ client ได้ — เหมาะสำหรับงาน lab หรือใช้ tool GUI เฉพาะตัวที่ติดตั้งบนเซิร์ฟเวอร์

# -X: Untrusted X11 forwarding (ปลอดภัยกว่า)
ssh -X moo@server

# -Y: Trusted X11 forwarding (เร็วกว่า แต่ปลอดภัยน้อยลง)
ssh -Y moo@server

# ทดสอบ
moo@server:~$ xclock          # นาฬิกาควรขึ้นบนหน้าจอ local
moo@server:~$ wireshark       # ตัวอย่าง GUI app

# ฝั่ง server ต้องเปิดใน sshd_config:
# X11Forwarding yes
# X11DisplayOffset 10
# X11UseLocalhost yes

7.5.7 SSH Multiplexing (ControlMaster, ControlPath)

Multiplexing ทำให้ SSH หลาย session ใช้ TCP connection เดียวกัน — เร็วขึ้นมากเพราะไม่ต้อง handshake ใหม่ทุกครั้ง

# ~/.ssh/config
Host *
    ControlMaster auto
    ControlPath ~/.ssh/sockets/%r@%h:%p
    ControlPersist 10m
# สร้างโฟลเดอร์ sockets ก่อน
mkdir -p ~/.ssh/sockets

# ครั้งแรก: เชื่อมต่อปกติ — สร้าง master connection
ssh moo@server         # ใช้เวลา ~2 วินาที (handshake ครบ)

# ครั้งต่อ ๆ ไป: ใช้ master connection เดิม
ssh moo@server         # ใช้เวลา < 0.1 วินาที!
scp file.txt moo@server:~/   # เร็วเพราะไม่ต้อง handshake ใหม่

# ดู master connection ที่เปิดอยู่
ls -la ~/.ssh/sockets/

# ปิด master connection
ssh -O exit moo@server

7.5.8 sshuttle (VPN ผ่าน SSH)

sshuttle เป็นเครื่องมือที่ทำ "VPN-like" tunnel ผ่าน SSH โดยไม่ต้องตั้ง VPN จริง — เหมาะสำหรับเข้าถึง subnet ภายในองค์กรชั่วคราว

# ติดตั้ง
sudo apt install sshuttle -y      # Debian/Ubuntu
sudo dnf install sshuttle -y      # Fedora

# เปิด tunnel ทั้ง subnet 10.10.0.0/24 ผ่าน server
sudo sshuttle -r moo@bastion.example.com 10.10.0.0/24

# Tunnel ทุก traffic (เป็น VPN เต็ม)
sudo sshuttle -r moo@bastion.example.com 0/0

# Exclude DNS หรือ subnet บางอัน
sudo sshuttle -r moo@bastion.example.com 10.10.0.0/24 -x 10.10.0.50

# ใช้ DNS ของ remote ด้วย
sudo sshuttle --dns -r moo@bastion.example.com 10.10.0.0/24

💡 sshuttle ไม่ใช่ VPN จริง ไม่ส่ง UDP, ICMP — ถ้าต้องการ full VPN ใช้ WireGuard หรือ OpenVPN แทน


7.6 การถ่ายโอนไฟล์ผ่าน SSH

SSH ไม่ได้ใช้แค่ Remote Shell — แต่ยังเป็นช่องทางถ่ายโอนไฟล์ที่ปลอดภัยที่สุดวิธีหนึ่ง

7.6.1 scp (Secure Copy)

scp เป็นคำสั่งคัดลอกไฟล์ผ่าน SSH ที่ใช้ syntax คล้าย cp ปกติ

# Local → Remote: คัดลอกไฟล์ขึ้น server
scp /home/moo/report.pdf moo@server:/home/moo/

# Remote → Local: ดึงไฟล์ลงมา
scp moo@server:/var/log/syslog ./

# คัดลอกทั้งโฟลเดอร์ (recursive)
scp -r ./project moo@server:/home/moo/

# ระบุ port ที่ไม่ใช่ default
scp -P 2222 file.txt moo@server:~/

# ระบุ identity file
scp -i ~/.ssh/id_ed25519_lab file.txt moo@server:~/

# คงสิทธิ์ไฟล์ + timestamp + verbose
scp -pv file.txt moo@server:~/

# Server-to-Server: คัดลอกระหว่างสอง remote โดย client เป็นตัวกลาง
scp moo@server1:/data/file.txt moo@server2:/backup/

# ใช้ option -3 ให้ traffic ผ่าน client (กรณี server-to-server โดยตรงไม่ได้)
scp -3 moo@server1:/data/file.txt moo@server2:/backup/

⚠️ scp กำลังถูก deprecate ใน OpenSSH รุ่นใหม่ — แนะนำให้ใช้ sftp หรือ rsync แทน

7.6.2 sftp (SSH File Transfer Protocol)

sftp เป็น protocol ระดับสูงกว่า scp ที่รองรับ resume, listing, permission management

# เริ่ม interactive session
sftp moo@server

# คำสั่งภายใน sftp (interactive mode)
sftp> pwd                     # show remote pwd
sftp> lpwd                    # show local pwd
sftp> ls                      # list remote
sftp> lls                     # list local
sftp> cd /var/log             # cd remote
sftp> lcd /tmp                # cd local
sftp> get syslog              # download
sftp> put report.pdf          # upload
sftp> get -r /etc/nginx       # download recursive
sftp> mkdir backup            # create remote dir
sftp> rm oldfile              # delete remote file
sftp> chmod 644 file          # change permission
sftp> bye                     # exit

# Batch mode: รัน script จากไฟล์
cat > batch.txt <<EOF
cd /var/log
get -r nginx
bye
EOF
sftp -b batch.txt moo@server

7.6.3 rsync over SSH

rsync เป็นเครื่องมือ sync ที่ฉลาดกว่า — คัดลอกเฉพาะส่วนที่เปลี่ยน (delta transfer) เหมาะสำหรับ backup และ sync โฟลเดอร์ใหญ่

# === Options พื้นฐาน ===
# -a : archive mode (= -rlptgoD: recursive, links, perms, times, group, owner, devices)
# -v : verbose
# -z : compress
# -P : show progress + resume partial
# --delete : ลบไฟล์ฝั่งปลายทางที่ไม่มีในต้นทาง

# Local → Remote
rsync -avzP /home/moo/project/ moo@server:/home/moo/project/

# Remote → Local
rsync -avzP moo@server:/var/www/site/ ./site_backup/

# ⚠️ ข้อสำคัญ: ตามด้วย / หรือไม่ตาม / ความหมายต่างกัน!
# rsync -av /src/  /dst/   → คัดลอกเนื้อหาภายใน src ไปไว้ใน dst
# rsync -av /src   /dst/   → คัดลอก folder src ทั้งก้อนไปไว้ใน dst (กลายเป็น dst/src)

# Mirror (ทำให้ปลายทางเหมือนต้นทางทุกอย่าง)
rsync -avz --delete /src/ moo@server:/dst/

# Exclude บาง pattern
rsync -avz --exclude='*.log' --exclude='node_modules/' \
      ./project/ moo@server:/home/moo/project/

# ใช้ exclude file
cat > .rsyncignore <<EOF
*.log
*.tmp
node_modules/
__pycache__/
.venv/
.git/
EOF
rsync -avz --exclude-from=.rsyncignore ./project/ moo@server:/home/moo/project/

# ระบุ SSH option (port, identity)
rsync -avz -e "ssh -p 2222 -i ~/.ssh/id_ed25519_lab" \
      ./project/ moo@server:/home/moo/project/

# Dry run (--dry-run / -n) ทดสอบก่อนรันจริง
rsync -avzn --delete /src/ moo@server:/dst/

# Bandwidth limit (KB/s)
rsync -avz --bwlimit=1024 /src/ moo@server:/dst/

ตัวอย่าง backup script ที่ใช้ในงานจริง:

#!/usr/bin/env bash
# backup.sh — สำรองข้อมูลรายวัน

set -euo pipefail

REMOTE_USER="moo"
REMOTE_HOST="backup.rmutsv.ac.th"
REMOTE_PATH="/srv/backup/$(hostname)"
LOCAL_PATH="/home/moo/important_data"
LOG_FILE="/var/log/backup-$(date +%F).log"

# Sync ด้วย rsync — log ทั้งหมด, ใช้ port 2222
rsync -avzP --delete \
      --exclude-from="$HOME/.rsyncignore" \
      -e "ssh -p 2222 -i $HOME/.ssh/id_ed25519_backup" \
      "$LOCAL_PATH/" \
      "${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_PATH}/" \
      2>&1 | tee "$LOG_FILE"

echo "Backup completed at $(date)" | tee -a "$LOG_FILE"

7.6.4 sshfs (Mount Remote Filesystem)

sshfs ใช้ FUSE mount โฟลเดอร์ remote ให้เป็นเหมือนโฟลเดอร์ใน filesystem ของเรา — ใช้งานเหมือนไฟล์ local ทุกประการ

# ติดตั้ง
sudo apt install sshfs -y          # Debian/Ubuntu
sudo dnf install fuse-sshfs -y     # Fedora

# Mount: remote /home/moo → local ~/server
mkdir -p ~/server
sshfs moo@server.rmutsv.ac.th:/home/moo ~/server

# พร้อม option ที่ใช้บ่อย
sshfs -o reconnect,ServerAliveInterval=15,ServerAliveCountMax=3,allow_other \
      moo@server:/home/moo ~/server

# ใช้งานได้เหมือนโฟลเดอร์ local
ls ~/server
nano ~/server/script.sh
cp ~/Downloads/file.zip ~/server/

# Unmount
fusermount -u ~/server
# หรือบน macOS
umount ~/server

ตารางเปรียบเทียบเครื่องมือถ่ายโอนไฟล์:

เครื่องมือ การใช้งาน Resume Delta Mount เหมาะกับ
scp One-shot copy ไฟล์เดียว, เล็ก
sftp Interactive/Batch จัดการไฟล์หลายชนิด
rsync Sync/Backup Backup, mirror, ใหญ่ ๆ
sshfs Filesystem mount ใช้งานต่อเนื่องเหมือนโฟลเดอร์ local

7.7 Cockpit

Cockpit เป็น Web-based Server Management Tool ที่ Red Hat พัฒนา — ออกแบบให้เป็น "เครื่องมือเสริม sshd" ไม่ใช่แทน SSH ทำให้ผู้ดูแลระบบจัดการเซิร์ฟเวอร์ผ่านเบราว์เซอร์ได้สะดวกขึ้น โดยเฉพาะสำหรับงานที่ต้องการ visualization

7.7.1 แนวคิด Web-based Server Management

ข้อดีของ Web-based Management เทียบกับ CLI ล้วน:

แต่ก็มีข้อเสีย:

flowchart TB
    subgraph Browser["🌐 Browser (Client)"]
        UI["Cockpit Web UI
https://server:9090"] end subgraph Server["🖥️ Server"] CWS["cockpit-ws
(Web Server, port 9090)"] CB["cockpit-bridge
(per-user session)"] subgraph Modules["Cockpit Modules"] M1[System] M2[Logs] M3[Storage] M4[Network] M5[Services] M6[Containers] M7[VMs] end SYS[(Linux Kernel
systemd, NetworkManager,
firewalld, podman, libvirt)] end UI <-->|HTTPS + WebSocket| CWS CWS --> CB CB --> M1 & M2 & M3 & M4 & M5 & M6 & M7 M1 & M2 & M3 & M4 & M5 & M6 & M7 --> SYS

7.7.2 การติดตั้ง Cockpit และ Enable Service

# === Debian/Ubuntu ===
sudo apt update
sudo apt install -y cockpit
# (ทางเลือก) ติดตั้ง module เพิ่ม
sudo apt install -y cockpit-podman cockpit-machines cockpit-networkmanager cockpit-storaged

# === Fedora/RHEL/Rocky/AlmaLinux ===
sudo dnf install -y cockpit
sudo dnf install -y cockpit-podman cockpit-machines cockpit-networkmanager

# === Arch Linux ===
sudo pacman -S cockpit
sudo pacman -S cockpit-podman cockpit-machines cockpit-networkmanager cockpit-storaged

# === openSUSE ===
sudo zypper install cockpit cockpit-machines cockpit-networkmanager

# Enable + Start ผ่าน systemd socket (เปิดบริการตอนมี request เท่านั้น)
sudo systemctl enable --now cockpit.socket

# ตรวจสอบสถานะ
sudo systemctl status cockpit.socket

# เปิด firewall port 9090
sudo firewall-cmd --permanent --add-service=cockpit
sudo firewall-cmd --reload
# หรือ ufw
sudo ufw allow 9090/tcp

หลังจากนั้นเปิดเบราว์เซอร์ไปที่ https://server-ip:9090 แล้ว login ด้วยบัญชี Linux ของระบบ

7.7.3 Dashboard และ Module หลัก

หน้า Dashboard หลักของ Cockpit ประกอบด้วย module ดังนี้:

  1. Overview สรุประบบ — Hostname, OS, CPU, RAM, Uptime, Performance graphs
  2. Logs ดู journalctl ผ่านเว็บ — filter ตาม service, severity, time
  3. Storage จัดการ disk, partition, LVM, RAID, NFS, iSCSI พร้อม graph IOPS
  4. Networking จัดการ interface, bridge, bond, VLAN, firewall (รวม firewalld)
  5. Accounts สร้าง/ลบ user, ตั้ง password, จัดการ SSH key
  6. Services จัดการ systemd unit — start/stop/enable/disable, ดู logs
  7. Software Updates ตรวจหาและติดตั้ง package update
  8. Terminal Web-based shell (ทำงานผ่าน WebSocket) — เผื่อกรณีต้องใช้ CLI
  9. Containers (Podman) จัดการ container แบบ rootless ผ่าน Podman
  10. Virtual Machines (libvirt) สร้างและจัดการ VM ผ่าน libvirt/KVM
  11. Diagnostic Reports สร้าง sosreport สำหรับ support
  12. Kernel Dump ตั้งค่า kdump

7.7.4 การเพิ่ม Multiple Host / Cluster Management

Cockpit รองรับการจัดการหลายเซิร์ฟเวอร์จากหน้าเดียว — เครื่องที่เป็น "primary" จะ SSH ไปยังเครื่องอื่น

# ติดตั้ง dashboard module เพิ่ม (เฉพาะบน primary)
sudo apt install -y cockpit-dashboard      # Debian/Ubuntu
sudo dnf install -y cockpit-dashboard      # Fedora/RHEL

# ติดตั้ง Cockpit บนทุกเครื่อง (server1, server2, server3)
# จากนั้นเปิด primary แล้วคลิก "Add new host" ใน dashboard
# กรอก hostname/IP ของเครื่องอื่น + login credentials
# Cockpit จะ SSH ไปจัดการเครื่องนั้น ๆ ให้

7.7.5 Security (TLS, Firewall)

โดย default Cockpit ใช้ self-signed certificate — ในการใช้งานจริงควรใช้ certificate ของจริง

# === ใช้ Let's Encrypt cert ===
# ตรวจสอบ path ของ cert ปัจจุบัน
sudo ls /etc/cockpit/ws-certs.d/

# วาง cert + key ที่ได้จาก Let's Encrypt
sudo cat /etc/letsencrypt/live/server.example.com/fullchain.pem \
         /etc/letsencrypt/live/server.example.com/privkey.pem \
         | sudo tee /etc/cockpit/ws-certs.d/0-server.cert
sudo chmod 600 /etc/cockpit/ws-certs.d/0-server.cert

# Restart Cockpit
sudo systemctl restart cockpit

# === Hardening: จำกัด IP ที่เข้าถึงได้ ===
# /etc/systemd/system/cockpit.socket.d/listen.conf
sudo mkdir -p /etc/systemd/system/cockpit.socket.d
sudo tee /etc/systemd/system/cockpit.socket.d/listen.conf <<EOF
[Socket]
ListenStream=
ListenStream=10.0.0.10:9090
EOF
sudo systemctl daemon-reload
sudo systemctl restart cockpit.socket

# === ปิด root login ใน Cockpit ===
# /etc/cockpit/disallowed-users
echo "root" | sudo tee /etc/cockpit/disallowed-users

💡 Best Practice: ไม่เปิด Cockpit ออก Public Internet เด็ดขาด — ให้เข้าผ่าน VPN หรือ SSH Tunnel เท่านั้น เช่น ssh -L 9090:localhost:9090 server แล้วเปิด https://localhost:9090


7.8 VNC (Virtual Network Computing)

VNC เป็น Remote Desktop Protocol แบบ cross-platform ที่ใช้ RFB (Remote Frame Buffer) Protocol ออกแบบโดย Olivetti & Oracle Research Lab ในปี 1998 (ปัจจุบันเป็น open standard)

7.8.1 แนวคิด Frame Buffer Sharing (RFB Protocol)

VNC ทำงานโดยส่ง Frame Buffer (พิกเซลของหน้าจอ) จาก Server ไปยัง Client ผ่านเครือข่าย และส่ง keyboard/mouse event กลับ

หลักการสำคัญของ RFB:

ปริมาณข้อมูลที่ต้องส่ง (Bandwidth) สามารถประมาณได้จาก:

B = W×H×D×F×R C

โดยที่ B คือ Bandwidth (bits/sec), W = ความกว้างหน้าจอ (pixels), H = ความสูง (pixels), D = bit depth (เช่น 24 bits/pixel), F = frame rate (fps), R = อัตราส่วนพื้นที่ที่เปลี่ยน (0–1), C = compression ratio (เช่น 5–10 สำหรับ Tight encoding)

ตัวอย่าง: 1920×1080×24×30×0.1 / 8 ≈ 18.7 MB/s ต่อ frame เปลี่ยน 10% — แสดงว่า VNC กิน bandwidth สูงพอสมควร

7.8.2 VNC Server: TigerVNC, TightVNC, x11vnc, RealVNC, Xrdp

VNC Server ลักษณะ License จุดเด่น
TigerVNC Standalone X server GPL นิยมที่สุดบน Linux, รองรับ multi-user
TightVNC Standalone GPL บีบอัดดี, ข้ามแพลตฟอร์ม
x11vnc Attach to existing X GPL แชร์ session ที่ใช้อยู่
RealVNC Standalone Commercial + free tier UI สวย, มี cloud relay
TurboVNC Optimized for 3D GPL เน้นงาน CAD, OpenGL
Xrdp RDP-to-X bridge Apache 2.0 ใช้ RDP client (Windows) ได้

7.8.3 VNC Client: Remmina, RealVNC Viewer, TigerVNC Viewer

7.8.4 การตั้งค่าและสร้าง VNC Session

ตัวอย่างการติดตั้ง TigerVNC พร้อม XFCE เป็น desktop environment:

# === ติดตั้ง TigerVNC + XFCE ===
sudo apt install -y tigervnc-standalone-server xfce4 xfce4-goodies

# === ตั้ง password VNC (เก็บใน ~/.vnc/passwd) ===
vncpasswd
# Password: ********
# Verify:   ********
# Would you like to enter a view-only password (y/n)? n

# === สร้าง startup script ===
mkdir -p ~/.vnc
cat > ~/.vnc/xstartup <<'EOF'
#!/bin/bash
unset SESSION_MANAGER
unset DBUS_SESSION_BUS_ADDRESS
xrdb $HOME/.Xresources
startxfce4 &
EOF
chmod +x ~/.vnc/xstartup

# === เริ่ม VNC server บน display :1 (port 5901) ===
vncserver :1 -geometry 1920x1080 -depth 24 -localhost no

# === ดู VNC session ที่รันอยู่ ===
vncserver -list

# === หยุด session ===
vncserver -kill :1

7.8.5 systemd service สำหรับ VNC

สำหรับการใช้งานในระยะยาว ควรตั้ง VNC เป็น systemd service:

# /etc/systemd/system/vncserver@.service
sudo tee /etc/systemd/system/vncserver@.service <<'EOF'
[Unit]
Description=Remote desktop service (VNC) for user %i
After=syslog.target network.target

[Service]
Type=simple
User=%i
Group=%i
WorkingDirectory=/home/%i
PIDFile=/home/%i/.vnc/%H:%i.pid
ExecStartPre=-/usr/bin/vncserver -kill :%i > /dev/null 2>&1
ExecStart=/usr/bin/vncserver :%i -geometry 1920x1080 -depth 24 -fg -localhost yes
ExecStop=/usr/bin/vncserver -kill :%i

[Install]
WantedBy=multi-user.target
EOF

# enable + start สำหรับ user moo บน display :1
sudo systemctl daemon-reload
sudo systemctl enable --now vncserver@moo:1.service

# ดูสถานะ
sudo systemctl status vncserver@moo:1.service

7.8.6 Security: VNC over SSH Tunnel

⚠️ VNC Protocol โดย default ไม่ปลอดภัย — password authentication ใช้แค่ challenge-response แบบอ่อน, frame buffer ส่งเป็น plaintext! ห้ามเปิด VNC port (5900-5999) ออก Public Internet

วิธีที่ถูกต้องคือเปิด VNC ให้ฟังเฉพาะ localhost แล้วใช้ SSH Tunnel:

# === ฝั่ง Server ===
# เริ่ม VNC ที่ฟังเฉพาะ localhost (-localhost yes)
vncserver :1 -geometry 1920x1080 -depth 24 -localhost yes
# port 5901 จะฟังเฉพาะ 127.0.0.1

# === ฝั่ง Client ===
# สร้าง SSH tunnel: local 5901 → remote 5901
ssh -L 5901:localhost:5901 moo@server.example.com

# จากนั้นเปิด VNC viewer แล้วเชื่อมต่อ localhost:5901
remmina -c vnc://localhost:5901
# หรือ
vncviewer localhost:5901

# === One-liner: tunnel + launch viewer ===
ssh -fNL 5901:localhost:5901 moo@server.example.com && \
    vncviewer localhost:5901

ใช้ noVNC ผ่าน HTTPS Reverse Proxy (Nginx) สำหรับเข้าถึงผ่านเบราว์เซอร์:

# ติดตั้ง noVNC + websockify
sudo apt install -y novnc websockify

# Run websockify เป็น proxy ระหว่าง WebSocket → VNC
websockify --web=/usr/share/novnc/ 6080 localhost:5901

# จากนั้นเข้าผ่าน https://server:6080/vnc.html
# (ควรอยู่หลัง Nginx + Let's Encrypt + Auth)

7.9 ทางเลือกอื่น

นอกจาก SSH, Cockpit, VNC ยังมีเครื่องมือ Remote Access อื่น ๆ ที่เหมาะกับ Use Case แตกต่างกัน

7.9.1 RDP ด้วย xrdp / FreeRDP

RDP (Remote Desktop Protocol) เป็น protocol ของ Microsoft แต่บน Linux มี implementation ฟรีคือ xrdp (server) และ FreeRDP (client) — ข้อดีคือ RDP ปลอดภัยกว่า VNC โดย default และมี client ในทุกระบบปฏิบัติการ

# === ฝั่ง Server: ติดตั้ง xrdp ===
sudo apt install -y xrdp xfce4

# ตั้งให้ใช้ XFCE
echo xfce4-session > ~/.xsession

# Add user xrdp เข้ากลุ่ม ssl-cert (สำหรับ TLS)
sudo adduser xrdp ssl-cert

# Enable + Start
sudo systemctl enable --now xrdp

# เปิด firewall (port 3389)
sudo ufw allow 3389/tcp

# === ฝั่ง Client: ใช้ FreeRDP หรือ Remmina ===
# FreeRDP CLI
xfreerdp /v:server.example.com /u:moo /p:password /size:1920x1080 /dynamic-resolution

# Remmina GUI
remmina -c rdp://moo@server.example.com

7.9.2 NoMachine

NoMachine เป็น proprietary remote desktop ที่ใช้ NX protocol — มีประสิทธิภาพดีกว่า VNC มาก เหมาะกับงาน multimedia, แต่เป็น closed-source (มี free tier สำหรับ personal use)

7.9.3 Apache Guacamole (Web-based Remote)

Apache Guacamole เป็น clientless remote desktop gateway — เปิดผ่านเบราว์เซอร์ได้เลย รองรับ SSH, RDP, VNC, Telnet, Kubernetes — เหมาะสำหรับองค์กรที่อยากให้ user เข้าถึงเครื่องต่าง ๆ จากเบราว์เซอร์โดยไม่ต้องติดตั้ง client

# วิธีง่ายที่สุด: ใช้ Docker
docker run -d --name guacd guacamole/guacd
docker run -d --name guacamole \
    --link guacd:guacd \
    -e POSTGRES_HOSTNAME=postgres \
    -e POSTGRES_DATABASE=guacamole_db \
    -e POSTGRES_USER=guacamole \
    -e POSTGRES_PASSWORD=secret \
    -p 8080:8080 \
    guacamole/guacamole

# เข้าผ่าน http://server:8080/guacamole/
# default user/pass: guacadmin/guacadmin (เปลี่ยนทันที!)

7.9.4 MeshCentral, RustDesk

ตารางเปรียบเทียบเครื่องมือ Remote Access:

เครื่องมือ Type License NAT Traversal Self-hosted UX
SSH Shell BSD ❌ (ใช้ tunnel) CLI
Cockpit Web Mgmt LGPL Web
VNC Desktop GPL GUI
xrdp Desktop Apache GUI
NoMachine Desktop Proprietary บางส่วน GUI
Guacamole Gateway Apache Web
MeshCentral RMM Apache Web
RustDesk Desktop AGPL GUI
TeamViewer Desktop Proprietary GUI
AnyDesk Desktop Proprietary GUI

7.10 Security Best Practices

ระบบ Remote Access เป็น attack surface อันดับต้น ๆ ของเซิร์ฟเวอร์ที่เปิดสู่อินเทอร์เน็ต — การ harden ให้แน่นหนาเป็นเรื่องจำเป็น

7.10.1 Firewall: ufw, firewalld, nftables

# === ufw (Ubuntu/Debian) — Easy interface ===
# Default policy
sudo ufw default deny incoming
sudo ufw default allow outgoing

# Allow SSH จาก subnet เดียว
sudo ufw allow from 10.0.0.0/24 to any port 2222 proto tcp

# Rate limit SSH (ป้องกัน brute force)
sudo ufw limit 2222/tcp

# Enable
sudo ufw enable

# ดูสถานะ
sudo ufw status numbered

# === firewalld (Fedora/RHEL) — Zone-based ===
# ดู zone
sudo firewall-cmd --get-active-zones

# Add SSH service ใน zone public
sudo firewall-cmd --permanent --zone=public --add-port=2222/tcp

# Rich rule: allow จาก subnet เดียว
sudo firewall-cmd --permanent --zone=public --add-rich-rule='
    rule family="ipv4" source address="10.0.0.0/24" 
    port port="2222" protocol="tcp" accept'

# Reload
sudo firewall-cmd --reload

# === nftables (modern Linux) ===
sudo tee /etc/nftables.conf <<'EOF'
table inet filter {
    chain input {
        type filter hook input priority 0; policy drop;
        ct state established,related accept
        iif lo accept
        # ICMP
        ip protocol icmp accept
        ip6 nexthdr ipv6-icmp accept
        # SSH (rate limited)
        tcp dport 2222 ip saddr 10.0.0.0/24 limit rate 5/minute accept
        # Cockpit
        tcp dport 9090 ip saddr 10.0.0.0/24 accept
    }
    chain forward { type filter hook forward priority 0; policy drop; }
    chain output  { type filter hook output  priority 0; policy accept; }
}
EOF
sudo systemctl enable --now nftables

7.10.2 Port Knocking

Port Knocking ซ่อนพอร์ต SSH โดยให้ผู้ใช้ "เคาะ" พอร์ตชุดหนึ่งก่อน firewall จึงเปิด SSH port ให้ — ไม่ใช่ security ที่แข็งแรงในตัวเอง แต่ลด noise จาก scan ได้ดี

# ติดตั้ง knockd
sudo apt install -y knockd

# /etc/knockd.conf
sudo tee /etc/knockd.conf <<'EOF'
[options]
    UseSyslog

[openSSH]
    sequence    = 7000,8000,9000
    seq_timeout = 5
    command     = /sbin/iptables -I INPUT -s %IP% -p tcp --dport 2222 -j ACCEPT
    tcpflags    = syn

[closeSSH]
    sequence    = 9000,8000,7000
    seq_timeout = 5
    command     = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 2222 -j ACCEPT
    tcpflags    = syn
EOF

sudo systemctl enable --now knockd

# ฝั่ง Client: เคาะ port แล้ว SSH
knock server.example.com 7000 8000 9000
ssh -p 2222 moo@server.example.com

7.10.3 2FA/MFA สำหรับ SSH (Google Authenticator, YubiKey)

Multi-Factor Authentication เพิ่มชั้นที่สอง — แม้ key/password รั่ว ผู้โจมตีก็ยังต้องมี factor ที่สอง (TOTP, hardware key)

# === Google Authenticator (TOTP) ===
sudo apt install -y libpam-google-authenticator

# รันในนาม user (ไม่ใช่ sudo!) เพื่อสร้าง secret
google-authenticator -t -d -f -r 3 -R 30 -W
# จะได้ QR code → scan ด้วย Google Authenticator app บนมือถือ
# จด emergency scratch codes ไว้ในที่ปลอดภัย

# แก้ /etc/pam.d/sshd — เพิ่มบรรทัดบนสุด
sudo sed -i '1i auth required pam_google_authenticator.so' /etc/pam.d/sshd

# แก้ /etc/ssh/sshd_config
sudo tee -a /etc/ssh/sshd_config <<EOF
ChallengeResponseAuthentication yes
KbdInteractiveAuthentication yes
UsePAM yes
AuthenticationMethods publickey,keyboard-interactive
EOF

sudo systemctl restart sshd

💡 YubiKey ใช้งานคล้ายกัน — Setup ผ่าน pam_yubico หรือใช้ FIDO2 ผ่าน OpenSSH 8.2+ (ssh-keygen -t ed25519-sk)

7.10.4 Audit Log (auditd)

# ติดตั้ง auditd
sudo apt install -y auditd

# ดู rule ปัจจุบัน
sudo auditctl -l

# Watch SSH config
sudo auditctl -w /etc/ssh/sshd_config -p wa -k sshd_config

# Watch authorized_keys ของทุก user
sudo auditctl -w /root/.ssh/ -p wa -k root_ssh
sudo auditctl -w /home/ -p wa -k home_ssh

# ทำให้ rule persistent
sudo tee -a /etc/audit/rules.d/audit.rules <<EOF
-w /etc/ssh/sshd_config -p wa -k sshd_config
-w /root/.ssh/ -p wa -k root_ssh
EOF
sudo systemctl restart auditd

# ค้นหา event
sudo ausearch -k sshd_config -i | tail -20
sudo ausearch -m USER_LOGIN -i | tail -20

7.10.5 Principle of Least Privilege

หลักการสำคัญที่สุดคือ ให้สิทธิ์เฉพาะที่จำเป็น:

  1. ไม่มี root SSH ทุก user ต้อง login เป็นบัญชีตัวเอง แล้ว sudo ตามต้องการ
  2. Sudo Granular ใน /etc/sudoers.d/ กำหนดเฉพาะคำสั่งที่อนุญาต ไม่ใช้ ALL=(ALL) NOPASSWD: ALL พร่ำเพรื่อ
  3. Restricted Shell สำหรับ deploy ใช้ git-shell หรือ rssh สำหรับ user ที่ต้องการแค่ deploy
  4. One key per purpose key สำหรับ admin, deploy, backup ควรแยกกัน
  5. Time-limited Access ใช้ certificate-based SSH (ssh-keygen -s) ที่หมดอายุได้
  6. Bastion/Jump Host ทุกการ access ต้องผ่าน host เดียวที่ตรวจสอบได้
  7. Network Segmentation Production server ไม่ควรเปิด SSH ออกเน็ตโดยตรง — ต้องผ่าน VPN หรือ Bastion เท่านั้น
  8. Regular Audit review authorized_keys, sudoers, login log ทุก 1-3 เดือน

ตัวอย่าง sudoers granular:

# /etc/sudoers.d/deploy
# ให้ user deploy รัน restart service ได้เฉพาะที่ระบุ — ไม่ต้อง password
deploy ALL=(root) NOPASSWD: /bin/systemctl restart myapp
deploy ALL=(root) NOPASSWD: /bin/systemctl status myapp
deploy ALL=(root) NOPASSWD: /bin/journalctl -u myapp *

7.10.6 Checklist สรุปการ Hardening

ก่อนนำ SSH server ออก production ควรเช็คทุกข้อต่อไปนี้:

  1. ✅ เปลี่ยน Port จาก 22 เป็นพอร์ตอื่น
  2. PermitRootLogin no
  3. PasswordAuthentication no (key-only)
  4. ✅ ใช้ Ed25519 key (หรือ RSA ≥ 3072-bit)
  5. ✅ Private key ทุกตัวมี passphrase
  6. ✅ จำกัด user ด้วย AllowUsers หรือ AllowGroups
  7. ✅ ตั้ง MaxAuthTries 3
  8. ✅ ตัด weak Cipher/KEX/MAC ใน sshd_config
  9. ✅ Firewall จำกัด IP ที่เข้าได้
  10. ✅ Fail2Ban หรือ CrowdSec ป้องกัน brute force
  11. ✅ 2FA/MFA สำหรับ user ที่มีสิทธิ์สูง
  12. ✅ Audit Log + Log Rotation
  13. ✅ ติดตั้ง security patch สม่ำเสมอ (unattended-upgrades)
  14. ✅ ทดสอบด้วย ssh-audit หรือ nmap --script ssh-*
# ทดสอบ SSH config ของตัวเองด้วย ssh-audit
pip install ssh-audit
ssh-audit server.example.com

# หรือใช้ nmap script
nmap -p 2222 --script ssh2-enum-algos,ssh-auth-methods server.example.com

📚 สรุป (Summary)

บทความนี้ได้นำเสนอครอบคลุม 3 เครื่องมือหลัก สำหรับการ Remote Access บนระบบ Linux:

หลักการสำคัญที่ผู้ดูแลระบบทุกคนต้องจำ:

🔐 "Encryption + Authentication + Least Privilege + Audit" — สี่เสาหลักของระบบ Remote Access ที่ปลอดภัย ไม่ว่าจะเลือกเครื่องมือใด หลักการนี้ใช้ได้เสมอ


🔗 อ้างอิงและเอกสารเพิ่มเติม