Media server บน VPS เดิม (ไม่มี GPU) — ติดตั้ง + วัดจริง

เอกสาร / สรุปงาน · 2026-10-26 · /opt/data/docs/2026-10-26-media-server.md

ติดตั้งแล้ว

อย่างค่า
ซอฟต์แวร์Jellyfin 12.3.0 (docker, jellyfin/jellyfin:latest, 751 MB)
URLhttps://media.thisaan.com (Caddy → 127.0.0.1:8096)
storage/srv/media/{movies,shows} (เมาท์เข้า container แบบ read-only)
config/cache/opt/jellyfin/{config,cache} (ไม่หายเมื่อ container สร้างใหม่)
adminสร้างผ่าน API — รหัสอยู่ใน /root/jellyfin-admin.txt (โหมด 600) ไม่พิมพ์ในแชท
libraryMovies + Shows · สแกนแล้ว 3 รายการ (h264 1080p, h264 720p, hevc 10-bit 1080p)

ผลวัดจริง (ตัวเลขจากเครื่องนี้)

การทดสอบผล
Direct playHTTP 206 Partial Content · video/mp4 · 1 MB ใน 0.06 วิ = 16.6 MB/s
ffmpeg transcode เดี่ยว (1080p→720p 3 Mbps, 2 threads)17.5 วิ สำหรับคลิป 120 วิ = 6.9× realtime
3 สตรีมพร้อมกัน (ffmpeg ล้วน)49 วิ/สตรีม = 2.45× realtime ยังทัน
Jellyfin transcode จริง (HLS)TranscodeReasons = ContainerBitrateExceedsLimit · playlist 40 segment · ดึง 3 segment = 1.97 MB
CPU ระหว่าง Jellyfin transcode 1 สตรีม92% โดยเฉลี่ย (78.9 → 97.5%)

แปลว่าอะไร (สรุปที่ใช้ตัดสินใจได้)

สิ่งที่ทำได้ทันทีโดยไม่ต้องซื้ออะไร

  1. แปลงไฟล์ใหม่เป็น h264/AAC + +faststart (สคริปต์ ffmpeg ใช้ได้เลย) → direct play 100%
  2. ตั้ง bitrate เพดานต่อผู้ใช้ให้ต่ำ (เช่น 2 Mbps) เพื่อให้ transcode เบาลง
  3. ใช้ media.thisaan.com ผ่าน Caddy — มี TLS อยู่แล้ว ไม่ต้องเปิดพอร์ต 32400

ข้อจำกัดที่ยังอยู่

เครื่องมือแปลงไฟล์ให้ direct play (เขียนเสร็จ + ทดสอบแล้ว)

/opt/data/tools/media_optimize.py (รันบน host: python3 /opt/jellyfin/media_optimize.py /srv/media/movies)

ความสามารถรายละเอียด
ตรวจก่อนแปลงffprobe: h264? + aac? + moov อยู่หัวไฟล์ (faststart)?
แปลงlibx264 -crf 22 -pix_fmt yuv420p + aac 160k + +faststart
สำรองต้นฉบับย้ายไป /srv/media/.originals/<path> — ไม่ลบ
ตรวจหลังแปลงถ้าไม่ผ่าน h264/aac/faststart → ลบไฟล์ชั่วคราว ไม่แตะต้นฉบับ
โหมดดูเฉยๆ--dry

ผลทดสอบจริงบนไฟล์ทดสอบ 3 ไฟล์

```

OK Test 1080p H264.mp4 · h264/yuv420p aac faststart=True (ไม่ต้องแตะ)

CONV Test 1080p HEVC10.mp4 · hevc/yuv420p10le → h264/yuv420p faststart=True

CONV Test 720p H264.mp4 · h264 ไม่มี faststart → ใส่ faststart

{"already": 1, "converted": 2, "failed": 0}

```

หลังแปลง + Library/Refresh → Jellyfin รายงาน directplay=True ทั้ง 3 เรื่อง (ก่อนหน้านี้ HEVC จะถูกบังคับ transcode)

บทเรียนจากการเขียนรอบนี้

  1. #!/bin/sh บน Ubuntu = dash → read -d '' ใช้ไม่ได้ (Illegal option -d) ทำให้ loop ข้ามไฟล์

→ เขียนเป็น Python แทน shell เมื่อต้องวนไฟล์ที่มีช่องว่างในชื่อ

  1. รายงานขนาดไฟล์ก่อน/หลังต้องจับ os.path.getsize() ก่อน แปลง ไม่งั้นได้เลขเท่ากันทั้งสองฝั่ง