SSD Nodes Learn Hosting plans →
คู่มือ Matt Connorโดย Matt Connor · อัปเดตเมื่อ 2026-08-26

วิธีติดตั้ง Jellyfin บน VPS ด้วย Docker ให้ใช้งานได้จริง

เรียนรู้วิธีติดตั้ง Jellyfin บน VPS ผ่าน Docker พร้อมตั้งค่า block storage และจัดการสิทธิ์ไฟล์ให้ถูกต้อง ป้องกันปัญหา transcoding หนักเกิน CPU และวิธีเข้าถึงสื่ออย่างปลอดภัย

สิ่งที่คุณกำลังสร้าง

การติดตั้ง Jellyfin media server บน VPS: ประกอบด้วยหนึ่งคอนเทนเนอร์, สามโวลุ่ม และดิสก์ block-storage สำหรับเก็บภาพยนตร์และรายการทีวีของคุณ ซึ่งสามารถเข้าถึงได้จากเบราว์เซอร์หรือแอป Jellyfin ใดๆ การติดตั้งนี้ใช้ไฟล์ compose เพียง 15 บรรทัด ปัญหาที่อาจเกิดขึ้นหลังจากนั้นมักมาจากสองสาเหตุหลัก คือสิทธิ์การเข้าถึงไฟล์ (file permissions) ที่คอนเทนเนอร์ไม่สามารถอ่านได้ และการสั่งให้ VPS ที่ไม่มี GPU ทำการแปลงรหัสวิดีโอ (transcoding) ซึ่งเกินขีดความสามารถของระบบ คู่มือนี้จะเน้นเนื้อหาส่วนใหญ่ไปที่สองประเด็นนี้ เนื่องจากเป็นจุดที่มักเกิดปัญหาและต้องมีการสนับสนุนทางเทคนิคบ่อยที่สุด

Jellyfin เป็นซอฟต์แวร์ฟรีและโอเพนซอร์สเต็มรูปแบบ โดยไม่มีการบังคับสร้างบัญชี ไม่มีฟีเจอร์ที่ต้องจ่ายเงินเพื่อปลดล็อก และไม่มีการเก็บข้อมูลการใช้งาน (telemetry) ซึ่งเป็นเหตุผลที่ทำให้มันติดอันดับในเกือบทุกรายการของ สิ่งที่ควรทำ self-hosting ในปี 2026 มันทำหน้าที่เล่นสื่อที่คุณเป็นเจ้าของเท่านั้น ตัวซอฟต์แวร์ไม่ได้มาพร้อมกับเนื้อหาใดๆ และคู่มือนี้ไม่ได้มีเนื้อหาเกี่ยวกับการจัดหาเนื้อหาเหล่านั้น

ความเป็นจริงของการแปลงรหัส (transcoding) ก่อนที่คุณจะเช่าบริการใดๆ

โปรดอ่านส่วนนี้ก่อน เพราะมันจะเปลี่ยนสิ่งที่คุณควรเลือกซื้อ Media server จะทำงานอย่างใดอย่างหนึ่งเมื่อคุณกดเล่นไฟล์ Direct play คือการสตรีมไฟล์ตามสภาพเดิม: VPS จะอ่านไบต์จากดิสก์แล้วส่งผ่านเครือข่าย ซึ่งแทบไม่ใช้ CPU เลย ส่วน Transcoding คือการแปลงรหัสวิดีโอแบบทันที (on the fly) ไม่ว่าจะเป็นการเปลี่ยนความละเอียด เปลี่ยน codec หรือการฝังคำบรรยายลงในวิดีโอ ซึ่งเป็นงานที่ใช้ CPU สูงมาก

VPS ทั่วไปไม่มี GPU ดังนั้นการแปลงรหัสทุกครั้งจะทำงานบน CPU ด้วย libx264/libx265 และการเข้ารหัสด้วยซอฟต์แวร์นั้นสิ้นเปลืองทรัพยากรมาก การแปลงรหัสวิดีโอ 1080p H.264 เพียงรายการเดียวอาจทำให้ vCPU แบบแชร์หลายตัวทำงานเต็มขีดจำกัด ส่วนการแปลงรหัส 4K หรือ HEVC มักจะไม่สามารถทำได้ทันเวลาแบบ real-time ส่งผลให้การเล่นวิดีโอสะดุดและบัฟเฟอร์ตลอดเวลา การแปลงรหัสด้วยฮาร์ดแวร์ (Hardware transcoding) ซึ่งเป็นสิ่งที่ทำให้การทำ Media server ที่บ้านด้วย Intel iGPU หรือการ์ดจอ Nvidia มีราคาถูกนั้น ไม่สามารถใช้งานได้บน VPS เว้นแต่ผู้ให้บริการของคุณจะมีบริการ GPU instance ให้เช่า

กลยุทธ์ทั้งหมดบน VPS จึงสรุปได้ว่า: หลีกเลี่ยงการแปลงรหัส ให้เก็บคลังสื่อของคุณในรูปแบบ codec ที่ไคลเอนต์เล่นได้โดยตรง (native) เช่น วิดีโอ H.264, เสียง AAC หรือ AC3 ในคอนเทนเนอร์ MP4 หรือ MKV และเลือกใช้แอปไคลเอนต์ที่รองรับ Direct play เช่น แอป Jellyfin บน Android TV, iOS และ Roku รวมถึง Infuse, Kodi และ Jellyfin Media Player บนเดสก์ท็อป หากทำเช่นนี้ VPS จะไม่ต้องเรียกใช้ ffmpeg เลย และเครื่องที่มีสเปกเพียง 2 vCPU ก็สามารถสตรีมให้หลายคนพร้อมกันได้ หากคุณวางแผนจะแปลงรหัส คุณจำเป็นต้องใช้เครื่องที่ใหญ่ขึ้นและมีราคาแพงกว่ามาก และถึงอย่างนั้น 4K ก็ยังเป็นตัวเลือกที่มีความเสี่ยงสูง

คำนวณ bandwidth ด้วย เพราะนี่เป็นข้อจำกัดอีกอย่างที่มักไม่คาดคิด การ direct play จะส่งไฟล์ด้วย bitrate ของไฟล์นั้นเอง ไฟล์ 1080p ที่บีบอัดแล้วใช้ 8-12 Mbps ส่วนไฟล์ 1080p Blu-ray remux ใช้ 20-30 Mbps และไฟล์ 4K HDR ใช้ 40-80 Mbps หากมี 3 คน direct play ไฟล์ที่ใช้ 10 Mbps แต่ละไฟล์ VPS ของคุณต้องส่งข้อมูลขาออกอย่างต่อเนื่อง 30 Mbps

ตรวจสอบตัวเลข 2 รายการในแพ็กเกจของคุณ: ความเร็วพอร์ต (รองรับการส่งข้อมูลขาออก 30 Mbps หรือไม่) และโควตา transfer รายเดือน ภาพยนตร์ความยาว 2 ชั่วโมงที่ใช้ 10 Mbps จะมีข้อมูลขาออกประมาณ 9 GB ดังนั้นโควตา 1 TB/month แบบคิดตามปริมาณการใช้งานจะรองรับภาพยนตร์ลักษณะนี้ได้มากกว่า 100 เรื่องต่อเดือนเล็กน้อย หรือประมาณ 3-4 เรื่องต่อวัน หากคนในบ้านรับชม 4K ซึ่งใช้ bitrate สูงกว่า 4-8 เท่า โควตาจะลดลงเร็วกว่ามาก

ให้นับ traffic อื่นที่ส่งออกจากเครื่องเดียวกันรวมอยู่ในงบประมาณเดียวกันด้วย รวมถึง relay RustDesk ที่ self-host ซึ่งจะส่งข้อมูลของ remote desktop session ทั้งหมดเมื่อ peer 2 ฝั่งไม่สามารถเชื่อมต่อกันโดยตรงได้

ข้อกำหนดเบื้องต้น

  • VPS ประเภท KVM ที่ใช้ Ubuntu 24.04 แบบติดตั้งใหม่ พร้อมสิทธิ์ root หรือ sudo และติดตั้ง Docker รวมถึงปลั๊กอิน Compose เรียบร้อยแล้ว
  • พื้นที่จัดเก็บข้อมูลแบบ block-storage สำหรับสื่อบันเทิง โดยกำหนดขนาดให้เหมาะสมกับคลังข้อมูลของคุณ (ดูรายละเอียดการคำนวณขนาดด้านล่าง) ดิสก์หลักขนาดเล็กที่มาพร้อมกับ VPS ไม่ใช่ที่สำหรับเก็บไฟล์ภาพยนตร์ของคุณ
  • ชื่อโดเมนหากคุณต้องการเข้าถึงผ่าน HTTPS แบบสาธารณะ หรือใช้ WireGuard VPN บน VPS เดียวกัน หากคุณต้องการเก็บทุกอย่างไว้เป็นส่วนตัว
  • สื่อบันเทิงที่คุณมีสิทธิ์ในการสตรีมอย่างถูกต้องตามกฎหมาย เช่น ไฟล์ที่คุณคัดลอกเอง, ไฟล์ที่คุณบันทึกเอง หรือไฟล์ที่คุณเป็นเจ้าของ

เมาท์ block storage ก่อน

เชื่อมต่อ volume ในแผงควบคุมของผู้ให้บริการ จากนั้นค้นหาและเมาท์อุปกรณ์ดังกล่าว ตรวจสอบชื่ออุปกรณ์จาก lsblk ซึ่งมักจะมีรูปแบบเป็น /dev/sdb หรือ /dev/vdb โดยต้องไม่ใช่ดิสก์ที่เป็น root

lsblk
sudo mkfs.ext4 /dev/sdb          # ONLY on a new, empty volume — this ERASES it
sudo mkdir -p /mnt/media
sudo blkid /dev/sdb              # copy the UUID shown for this device

ให้เมาท์โดยใช้ UUID แทนการใช้ /dev/sdb เนื่องจากลำดับตัวอักษรของอุปกรณ์อาจเปลี่ยนแปลงได้หลังการรีบูต ซึ่งอาจส่งผลให้คุณฟอร์แมตหรือเมาท์ดิสก์ผิดลูก ให้เพิ่มบรรทัดลงใน /etc/fstab ดังนี้:

UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx  /mnt/media  ext4  defaults,nofail  0  2
sudo mount -a
df -h /mnt/media

nofail มีความสำคัญมาก หากไม่มีค่านี้และ block volume ถูกถอดออก เซิร์ฟเวอร์จะไม่สามารถบูตได้และจะเข้าสู่ emergency shell ข้อผิดพลาดที่พบบ่อยที่สุดคือการรัน mkfs.ext4 บน volume ที่มีข้อมูลอยู่แล้ว ซึ่งจะทำให้ข้อมูลทั้งหมดถูกลบ ให้ฟอร์แมตเฉพาะ volume ใหม่เท่านั้น หากดิสก์มีข้อมูลของคุณอยู่แล้ว ให้ข้ามไปที่ขั้นตอนการเพิ่มบรรทัดใน fstab ได้เลย

จัดระเบียบสื่อให้ตรงตามที่ Jellyfin ต้องการ

Jellyfin ใช้ชื่อโฟลเดอร์และชื่อไฟล์ในการจับคู่ข้อมูลเมตา (metadata) หากจัดระเบียบไม่ถูกต้อง ภาพยนตร์จะปรากฏเป็นไฟล์ที่ไม่มีชื่อและไม่มีโปสเตอร์ หรือตอนของซีรีส์อาจถูกจับคู่ผิดเรื่อง โดยมีกฎ 3 ข้อที่ต้องปฏิบัติตาม: ภาพยนตร์แต่ละเรื่องต้องอยู่ในโฟลเดอร์ Name (Year) ของตนเองโดยมีชื่อไฟล์ที่ตรงกัน, โฟลเดอร์ซีซันต้องตั้งชื่อว่า Season 01 ไม่ใช่ S01, ไฟล์ตอนของซีรีส์ต้องใช้รูปแบบ S01E01 และตอนพิเศษต้องเก็บไว้ใน Season 00

/mnt/media
├── Movies
│   ├── Blade Runner (1982)
│   │   └── Blade Runner (1982).mkv
│   └── Arrival (2016)
│       └── Arrival (2016).mkv
└── Shows
    └── Severance (2022)
        ├── Season 01
        │   ├── Severance - S01E01.mkv
        │   └── Severance - S01E02.mkv
        └── Season 00
            └── Severance - The Lexington Letter.mkv

(Year) ในชื่อภาพยนตร์ไม่ใช่แค่การตกแต่ง แต่ช่วยแยกแยะภาพยนตร์ที่นำกลับมาสร้างใหม่ (remake) เพื่อให้ระบบจับคู่ข้อมูลได้ชื่อเรื่องที่ถูกต้อง ควรแยก Movies และ Shows ไว้เป็นโฟลเดอร์ระดับบนสุดแยกจากกัน เนื่องจากแต่ละโฟลเดอร์จะกลายเป็นไลบรารีใน Jellyfin ตามประเภทเนื้อหาที่กำหนด การนำมาปะปนกันจะทำให้ผู้ให้บริการข้อมูลเมตาสับสน ทั้งนี้ Jellyfin สามารถจัดทำดัชนีโฟลเดอร์รูปภาพที่สามได้เช่นกัน แต่ประสบการณ์การใช้งานจะจำกัดเมื่อเทียบกับเซิร์ฟเวอร์ที่ออกแบบมาเพื่อจัดการรูปภาพโดยเฉพาะ ดังนั้นหากอัลบั้มรูปภาพของคุณมีความสำคัญ ควรแยกไปใช้เซิร์ฟเวอร์เฉพาะทางอย่าง PhotoPrism หรือ Immich แล้วปล่อยให้เซิร์ฟเวอร์นี้จัดการเฉพาะภาพยนตร์และรายการโทรทัศน์เท่านั้น

สิทธิ์การเข้าถึง: สาเหตุอันดับหนึ่งที่ทำให้คลังข้อมูลว่างเปล่า

นี่คือความเข้าใจผิดที่ทำให้หลายคนเสียเวลาไปทั้งเย็น ภาพลักษณ์ jellyfin/jellyfin อย่างเป็นทางการ ไม่ รองรับตัวแปรสภาพแวดล้อม PUID/PGID เนื่องจากตัวแปรดังกล่าวเป็นของอิมเมจจาก LinuxServer.io (lscr.io/linuxserver/jellyfin) สำหรับอิมเมจอย่างเป็นทางการ คุณสามารถควบคุมผู้ใช้งานได้ด้วยคีย์ user: ในไฟล์ compose และหากคุณละเว้นคีย์นี้ คอนเทนเนอร์จะทำงานในฐานะ root ไม่ว่าคุณจะใช้วิธีใด กฎยังคงเหมือนเดิมคือ uid/gid ที่คอนเทนเนอร์ใช้ทำงานต้องสามารถอ่านและเข้าถึงทุกไดเรกทอรีสื่อได้

เราจะรันด้วย uid/gid 1000 ซึ่งเป็นผู้ใช้งานที่ไม่ใช่ root คนแรกบน Ubuntu รุ่นมาตรฐาน ให้ตรวจสอบค่าของคุณและตั้งค่าความเป็นเจ้าของดังนี้:

id                                  # confirm your user is uid=1000 gid=1000
sudo chown -R 1000:1000 /mnt/media
sudo find /mnt/media -type d -exec chmod 755 {} \;
sudo find /mnt/media -type f -exec chmod 644 {} \;
mkdir -p ~/jellyfin/config ~/jellyfin/cache
sudo chown -R 1000:1000 ~/jellyfin

ไดเรกทอรีจำเป็นต้องมีบิต execute (คือ x ใน 755) ไม่ใช่แค่สิทธิ์การอ่าน หากไม่มีบิตนี้ คอนเทนเนอร์จะไม่สามารถเข้าไปในโฟลเดอร์ได้แม้ว่าจะแสดงรายชื่อไฟล์ได้ก็ตาม กับดักที่ทำให้คลังข้อมูลว่างเปล่าทั้งคลังคือไดเรกทอรีแม่: หาก uid ของคอนเทนเนอร์ไม่สามารถเข้าถึงจุด mount ได้ มันก็จะไม่สามารถไปถึง /media/Movies หรือ /media/Shows ได้เลย และคลังข้อมูลทั้งหมดจะว่างเปล่าทันทีพร้อมกับข้อความ Access to the path ... is denied ใน log โฟลเดอร์สื่อใดก็ตามที่อ่านไม่ได้จะถูกบันทึกไว้และข้ามไป ดังนั้นไฟล์จำนวนมากที่คัดลอกเข้ามาในฐานะ root จะหายไปจากคลังข้อมูลโดยไม่มีการแจ้งเตือน นี่คือเหตุผลที่เราต้องใช้ chown แบบ recursive และตั้งค่าบิต execute บนทุกไดเรกทอรี แทนที่จะแก้ไขเพียงโฟลเดอร์เดียว

ไฟล์ docker-compose

services:
  jellyfin:
    image: jellyfin/jellyfin:10
    container_name: jellyfin
    user: "1000:1000"
    restart: unless-stopped
    ports:
      - "127.0.0.1:8096:8096"
    volumes:
      - ./config:/config
      - ./cache:/cache
      - /mnt/media:/media:ro
    environment:
      - JELLYFIN_PublishedServerUrl=https://jellyfin.example.com

อธิบายทีละบรรทัด: user: "1000:1000" คือส่วนที่กำหนดสิทธิ์ของไฟล์จริง โดยให้สอดคล้องกับความเป็นเจ้าของที่ระบุไว้ด้านบน /config เป็นที่เก็บข้อมูลทั้งหมดของเซิร์ฟเวอร์ รวมถึงบัญชีผู้ใช้, ไลบรารี, ข้อมูลเมตา และสถานะการรับชม ดังนั้นจึงต้องเป็นตำแหน่งที่เขียนข้อมูลได้และเป็นส่วนที่คุณต้องสำรองข้อมูล /cache เป็นพื้นที่ทำงานชั่วคราว ส่วนการ mount ข้อมูลสื่อคือ :ro ซึ่งตั้งค่าเป็นแบบอ่านอย่างเดียว (read-only) โดยเจตนา เนื่องจาก Jellyfin มีค่าเริ่มต้นในการจัดเก็บภาพปกและข้อมูลเมตาไว้ที่ /config จึงไม่จำเป็นต้องเขียนข้อมูลลงในไลบรารีของคุณ และการตั้งค่าแบบอ่านอย่างเดียวจะช่วยป้องกันไฟล์ของคุณจากการถูกลบโดยไม่ตั้งใจหรือจากปลั๊กอินที่มีปัญหา พอร์ตถูกผูกไว้กับ 127.0.0.1 อย่างตั้งใจ เนื่องจากหน้าล็อกอินเว็บของ Jellyfin เป็น HTTP ธรรมดา เราจึงไม่เปิดพอร์ต 8096 สู่สาธารณะ JELLYFIN_PublishedServerUrl คือที่อยู่ที่เซิร์ฟเวอร์ประกาศใช้สำหรับการค้นหาอัตโนมัติภายในเครือข่าย (LAN UDP broadcast) ดังนั้นไคลเอนต์ที่อยู่ผ่านอินเทอร์เน็ตจะไม่เห็นที่อยู่นี้และจะใช้ URL ที่คุณพิมพ์ลงในแอปโดยตรง ให้ตั้งค่าเป็นที่อยู่ที่ต้องการให้ไคลเอนต์รับทราบ และคาดหวังว่าจะต้องกรอก URL นั้นด้วยตนเองบนอุปกรณ์ระยะไกล

เริ่มการทำงานจากไดเรกทอรีที่เก็บไฟล์ compose:

docker compose up -d
docker logs -f jellyfin

การใช้งานครั้งแรก: วิซาร์ดการตั้งค่าและไลบรารีของคุณ

เนื่องจากพอร์ตถูกผูกไว้กับ localhost ให้เข้าถึงวิซาร์ดผ่าน SSH tunnel จากแล็ปท็อปของคุณแทนการเปิดช่องโหว่บนไฟร์วอลล์:

ssh -L 8096:127.0.0.1:8096 you@your-vps-ip

จากนั้นให้เปิดเบราว์เซอร์ไปที่ http://localhost:8096 วิซาร์ดจะนำคุณไปสู่การเลือกภาษา จากนั้นให้สร้าง บัญชีผู้ดูแลระบบด้วยรหัสผ่านที่คาดเดายาก บัญชีนี้คือเซิร์ฟเวอร์ของคุณ ดังนั้นห้ามใช้รหัสผ่านที่ใช้แล้วทิ้ง เพิ่มไลบรารีแรกของคุณ: เลือกประเภทเนื้อหาเป็น Movies แล้วระบุตำแหน่งไปที่ /media/Movies (ระบุ path ภายใน คอนเทนเนอร์ ไม่ใช่ path บนโฮสต์) และทำซ้ำขั้นตอนเดิมสำหรับ Shows ที่ /media/Shows เมื่อเสร็จสิ้น Jellyfin จะเริ่มทำการสแกน ผลลัพธ์ที่ถูกต้องคือโปสเตอร์และชื่อเรื่องจะปรากฏขึ้นภายในหนึ่งหรือสองนาทีสำหรับไลบรารีขนาดเล็ก คุณสามารถเพิ่มหรือแก้ไขไลบรารีในภายหลังได้ที่ Dashboard → Libraries และบังคับให้สแกนใหม่ด้วย Scan All Libraries

หากคุณจำเป็นต้องใช้การแปลงรหัส (transcoding) ให้เปิดไปที่ Dashboard → Playback → Transcoding และตั้งค่า path ชั่วคราวสำหรับการแปลงรหัสไปที่ /cache/transcodes เพื่อให้ข้อมูลที่เปลี่ยนแปลงไปลงที่โวลุ่มแคชแทนที่จะทำให้ /config เต็ม ให้คงค่าการเร่งความเร็วฮาร์ดแวร์ไว้ที่ None เนื่องจากไม่มี GPU สำหรับใช้ในการเร่งความเร็ว

การเข้าถึงจากระยะไกล: ใช้ TLS reverse proxy หรือเก็บไว้ใน VPN

คุณมีวิธีที่ปลอดภัย 2 วิธีในการเข้าถึง Jellyfin จากภายนอก และมี 1 วิธีที่ไม่ปลอดภัยซึ่งควรหลีกเลี่ยง วิธีที่ไม่ปลอดภัยคือการเปิดพอร์ต 8096 ออกสู่สาธารณะโดยตรง เนื่องจากข้อมูลการเข้าสู่ระบบจะถูกส่งเป็นข้อความธรรมดา (cleartext) และพอร์ตจะถูกโจมตีแบบ brute-force ภายในเวลาไม่กี่ชั่วโมง

ทางเลือก A, ใช้ TLS reverse proxy ให้วาง Jellyfin ไว้บน subdomain หลัง Traefik พร้อม TLS อัตโนมัติสำหรับแอป Docker ของคุณ หรือหลัง nginx ที่ใช้ ใบรับรอง Let's Encrypt ที่ออกโดย Certbot โดย Jellyfin ใช้ WebSockets สำหรับการอัปเดตแบบเรียลไทม์ ดังนั้น proxy ต้องส่งต่อ upgrade headers ไปด้วย Traefik จะจัดการส่วนนี้โดยอัตโนมัติ แต่สำหรับ nginx คุณต้องระบุค่าเหล่านี้ให้ชัดเจน และต้องใช้ HTTP/1.1 ไปยัง upstream มิฉะนั้นการอัปเกรดจะไม่เกิดขึ้น:

location / {
    proxy_pass http://127.0.0.1:8096;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

ตั้งค่า JELLYFIN_PublishedServerUrl ให้เป็นที่อยู่ https:// เพื่อให้ระบบ autodiscovery ภายในเครือข่ายแจ้ง URL ที่ถูกต้อง แอปภายนอกจะใช้ที่อยู่ที่คุณระบุ และควรเพิ่ม fail2ban เพื่อชะลอการพยายาม brute-force หน้าเข้าสู่ระบบ เมื่อเซิร์ฟเวอร์เปิดใช้งานสู่สาธารณะแล้ว ให้ตั้งค่า Uptime Kuma ให้ตรวจสอบ URL ดังกล่าว เพื่อให้คุณทราบถึงสถานะ downtime ก่อนที่ผู้ใช้งานของคุณจะพบปัญหา

ทางเลือก B, เก็บไว้เป็นส่วนตัวบน VPN ห้ามเปิดพอร์ต 8096 ออกสู่สาธารณะโดยเด็ดขาด ให้เข้าถึง Jellyfin ผ่าน WireGuard tunnel ที่เชื่อมต่อกับเครื่องเดียวกันเท่านั้น สำหรับการใช้งานในครัวเรือน นี่เป็นทางเลือกที่ปลอดภัยและง่ายที่สุด ไม่ต้องใช้ใบรับรอง ไม่มีการเปิดเผยข้อมูลสู่สาธารณะ และไม่มีช่องทางให้ถูกโจมตีแบบ brute-force ให้ผูก (bind) container เข้ากับที่อยู่ของ tunnel หรือ localhost แล้วเชื่อมต่อผ่าน VPN ดูรายละเอียดเพิ่มเติมได้ที่ การตั้งค่า WireGuard VPN สำหรับ VPS ส่วนตัว เพื่อสร้าง tunnel ดังกล่าว

การกำหนดขนาดพื้นที่จัดเก็บและการสำรองข้อมูล

ให้จัดสรรงบประมาณตามคุณภาพ ไม่ใช่ตามจำนวนไฟล์ ภาพยนตร์ความละเอียด 1080p แบบบีบอัดจะมีขนาด 4-15 GB ต่อเรื่อง ส่วน 1080p remux จะอยู่ที่ 20-40 GB สำหรับซีรีส์ความละเอียด 1080p หนึ่งซีซันจะมีขนาด 15-40 GB และเนื้อหาความละเอียด 4K ทุกรูปแบบจะมีขนาด 40-100 GB ต่อเรื่อง คลังสื่อที่มีภาพยนตร์หลายร้อยเรื่องรวมกับรายการทีวีจำนวนหนึ่งควรใช้พื้นที่จัดเก็บขนาด 2-4 TB การจัดสรรพื้นที่ block volume ให้เกินความจำเป็นไว้ตั้งแต่ต้นนั้นประหยัดค่าใช้จ่ายกว่าการย้ายข้อมูลในภายหลัง

/config คือสถานะทั้งหมดของเซิร์ฟเวอร์ ดังนั้นจึงเป็นสิ่งเดียวที่คุณต้องสำรองข้อมูล ให้ทำ snapshot หรือหยุดการทำงานแล้วใช้ tar เพื่อสำรองข้อมูล จากนั้นเก็บสำเนาไว้ภายนอกเครื่อง:

docker compose down
sudo tar czf jellyfin-config-$(date +%F).tgz -C ~/jellyfin config
docker compose up -d

/cache และโฟลเดอร์ transcode เป็นข้อมูลที่ทิ้งได้ ส่วนสื่อใน /mnt/media ให้สำรองข้อมูลแยกต่างหากหรือยอมรับว่าสามารถ rip ใหม่ได้ ซึ่งคนส่วนใหญ่มักเลือกวิธีหลังเนื่องจากขนาดไฟล์ที่ใหญ่ การอัปเกรดเป็น docker compose pull && docker compose up -d โดยแท็ก :10 ด้านบนจะคงอยู่ในเวอร์ชันหลัก 10.x ดังนั้นการย้ายไปยังเวอร์ชันหลักถัดไปจึงเป็นการแก้ไขแท็กโดยเจตนา โปรดอ่านบันทึกการปล่อยเวอร์ชันของ Jellyfin ก่อนดำเนินการ เนื่องจากอาจมีการย้าย schema ของคลังข้อมูลในเวอร์ชันหลัก การใช้แท็กที่ระบุเวอร์ชันชัดเจนควบคู่กับการสำรองไดเรกทอรีสถานะคือสูตรสำเร็จสำหรับ container ที่ทำงานตลอดเวลา และเป็นรูปแบบเดียวกันกับที่ใช้ใน การรักษาหน่วยความจำและตารางเวลาของ agent ที่โฮสต์เองให้คงอยู่หลังการรีบูต

รูปแบบความล้มเหลวและข้อความที่คุณจะพบ

คลังข้อมูลว่างเปล่าหลังจากการสแกน บันทึกที่ Dashboard → Logs (หรือ ~/jellyfin/config/log/log_*.log) แสดงข้อความดังนี้:

System.UnauthorizedAccessException: Access to the path '/media/Movies' is denied.

uid ของคอนเทนเนอร์ไม่สามารถอ่านพาธดังกล่าวได้ สาเหตุ: สื่อข้อมูลถูกครอบครองโดย root หรือ uid อื่นที่ไม่ใช่ค่า user: ของคุณ, ไดเรกทอรีไม่มี execute bit หรือตัว mount หลักไม่สามารถเข้าถึงได้โดย uid นั้น วิธีแก้ไข: chown -R 1000:1000 /mnt/media, ไดเรกทอรี 755, ไฟล์ 644 จากนั้นทำการสแกนใหม่อีกครั้ง

การเล่นไฟล์ทำให้ CPU ทำงานหนักและเกิดการบัฟเฟอร์ docker stats jellyfin แสดงการใช้งาน CPU ใกล้ 100% คูณด้วยจำนวนคอร์ของคุณ และ Dashboard → Playback แสดงรายการเซสชันเป็น Transcode ด้วยความเร็วต่ำกว่า 1.0x ไคลเอนต์ไม่ได้ทำการ direct-play ทำให้ VPS ต้องทำการ CPU-transcoding ซึ่งช้ากว่าเวลาจริงและไม่สามารถเล่นได้ทัน สาเหตุ: codec หรือคอนเทนเนอร์ไม่รองรับ, การฝังคำบรรยาย (burn-in), หรือการทำ HDR tone-mapping วิธีแก้ไข: เปลี่ยนไปใช้ไคลเอนต์ที่รองรับ direct-play, เก็บไฟล์ต้นฉบับในรูปแบบ H.264/AAC, ใช้คำบรรยายแบบ text (SRT) แทนคำบรรยายแบบ image (PGS/VOBSUB) ซึ่งบังคับให้ต้องทำการ burn-in และหลีกเลี่ยงการเล่น 4K HDR บนเครื่องที่ใช้ CPU เพียงอย่างเดียว

"No compatible streams are available." ข้อความเต็มมักจะเป็น "This client isn't compatible with the media and the server isn't sending a compatible media format." ไคลเอนต์ปฏิเสธไฟล์ต้นฉบับและระบบสำรองการแปลงไฟล์ (fallback transcode) ก็ไม่สามารถเริ่มทำงานได้ สาเหตุ: คำสั่ง ffmpeg ผิดพลาด, ไฟล์ไม่สามารถอ่านได้, หรือโปรไฟล์ของผู้ใช้บล็อกการแปลงวิดีโอ วิธีแก้ไข: อ่านบรรทัดคำสั่ง ffmpeg ใน Dashboard → Logs, ตรวจสอบว่าไฟล์สามารถเล่นได้จริง, ตรวจสอบสิทธิ์การเล่นของผู้ใช้หากคุณจำเป็นต้องใช้การ transcoding และลองใช้ไคลเอนต์ตัวที่สองเพื่อตัดปัญหาเรื่องความเข้ากันได้ของ codec ในเบราว์เซอร์

ภาพยนตร์ไม่มีโปสเตอร์หรือแสดงโปสเตอร์ผิด ข้อมูลเมตาไม่ตรงกัน สาเหตุ: ภาพยนตร์ไม่ได้อยู่ในโฟลเดอร์ Name (Year) ของตัวเอง, โฟลเดอร์ซีซันตั้งชื่อว่า S01 แทนที่จะเป็น Season 01, ตอนของซีรีส์ไม่ได้อยู่ในรูปแบบ S01E01 หรือไม่มีการระบุปี วิธีแก้ไข: เปลี่ยนชื่อให้เป็นไปตามรูปแบบข้างต้น จากนั้นเลือก Refresh metadata → Replace all หรือใช้ฟังก์ชัน Identify กับรายการนั้นๆ เพื่อระบุข้อมูล TMDB/TVDB ที่ถูกต้อง

FAQ

VPS สามารถแปลงรหัสวิดีโอ (transcode) โดยไม่มี GPU ได้หรือไม่?

ได้ แต่ต้องใช้ CPU เพียงอย่างเดียวซึ่งสิ้นเปลืองทรัพยากรมาก การแปลงรหัสซอฟต์แวร์ระดับ 1080p เพียงรายการเดียวอาจทำให้ vCPU หลายคอร์ทำงานเต็มประสิทธิภาพ และสำหรับ 4K หรือ HEVC มักจะไม่สามารถประมวลผลได้ทันเวลาจริง ทำให้การเล่นวิดีโอเกิดการบัฟเฟอร์ วิธีที่ดีที่สุดคือหลีกเลี่ยงการแปลงรหัส โดยจัดเก็บคลังสื่อของคุณในรูปแบบ H.264/AAC และใช้แอปพลิเคชันฝั่งไคลเอนต์ที่รองรับการเล่นโดยตรง (direct-play) เพื่อให้ VPS ทำหน้าที่เพียงส่งข้อมูลเท่านั้น ควรเช่าอินสแตนซ์ที่มี GPU เฉพาะในกรณีที่คุณจำเป็นต้องแปลงรหัสแบบเรียลไทม์จริงๆ เท่านั้น

ทำไมคลังสื่อ Jellyfin ของฉันถึงว่างเปล่าหลังจากสแกน?

สาเหตุเกือบทั้งหมดมาจากสิทธิ์การเข้าถึงไฟล์ (permissions) อิมเมจ jellyfin/jellyfin อย่างเป็นทางการจะทำงานภายใต้ user: ที่คุณกำหนด (หรือ root) หากไฟล์เหล่านั้นไม่สามารถอ่านได้โดย uid ดังกล่าว บันทึกการสแกนจะแจ้ง Access to the path ... is denied และข้ามไฟล์เหล่านั้นไป ให้แก้ไขความเป็นเจ้าของไฟล์ด้วย chown -R 1000:1000 /mnt/media และกำหนดสิทธิ์ execute bit ให้กับไดเรกทอรี (755) แล้วทำการสแกนใหม่ นอกจากนี้ให้ตรวจสอบไดเรกทอรีหลักด้วย เพราะหาก uid ของคอนเทนเนอร์ไม่สามารถเข้าถึง /mnt/media ได้ ก็จะไม่สามารถเข้าถึงโฟลเดอร์คลังสื่อได้เลยและผลลัพธ์จะว่างเปล่า สาเหตุที่พบบ่อยเป็นอันดับสองคือโครงสร้างโฟลเดอร์ไม่ตรงกับที่ Jellyfin คาดหวัง

ฉันจะเข้าถึง Jellyfin จากระยะไกลได้อย่างปลอดภัยได้อย่างไร?

มีสองทางเลือกที่ดี ทางเลือกแรกคือวางไว้หลัง TLS reverse proxy บนโดเมนย่อยเพื่อให้การล็อกอินและการสตรีมถูกเข้ารหัส และเพิ่ม fail2ban ห้ามเปิดพอร์ต 8096 โดยตรงเด็ดขาดเพราะจะส่งรหัสผ่านของคุณเป็นข้อความธรรมดา ทางเลือกที่สองคือเก็บไว้เป็นส่วนตัวทั้งหมดและเข้าถึงผ่าน VPN เท่านั้น ซึ่งเป็นทางเลือกที่ปลอดภัยและง่ายที่สุดสำหรับใช้งานในบ้าน ให้ระบุที่อยู่สาธารณะให้กับแอปโดยตรง เนื่องจากฟีเจอร์ autodiscovery เป็นการกระจายสัญญาณภายในเครือข่ายท้องถิ่น จึงไม่สามารถเข้าถึงไคลเอนต์ที่เชื่อมต่อผ่านอินเทอร์เน็ตได้

Jellyfin บน VPS ต้องการพื้นที่ดิสก์และแบนด์วิดท์เท่าใด?

พื้นที่ดิสก์ขึ้นอยู่กับคุณภาพ: ให้เผื่อไว้ 4-15 GB ต่อภาพยนตร์ 1080p แบบบีบอัด, 20-40 GB ต่อไฟล์ remux และ 40-100 GB สำหรับ 4K ดังนั้นคลังสื่อส่วนใหญ่จึงต้องการ block volume ขนาด 2-4 TB ส่วนแบนด์วิดท์จะถูกกำหนดโดยอัตราการส่งข้อมูล (bitrate) ของการเล่นโดยตรง ซึ่งอยู่ที่ 8-12 Mbps ต่อการสตรีม 1080p หนึ่งรายการ และมากกว่านั้นมากสำหรับ 4K ดังนั้นควรตรวจสอบว่าความเร็วพอร์ตของคุณรองรับจำนวนผู้ชมพร้อมกันได้ และคอยตรวจสอบขีดจำกัดการถ่ายโอนข้อมูลรายเดือน หากคุณวางแผนจะแปลงรหัส ให้เพิ่มประสิทธิภาพ CPU แต่หากวางแผนจะเล่นโดยตรง ให้ความสำคัญกับแบนด์วิดท์มากกว่าจำนวนคอร์

การรัน Jellyfin บน VPS ถูกกฎหมายหรือไม่?

Jellyfin เป็นซอฟต์แวร์โอเพนซอร์สฟรีและการใช้งานนั้นถูกกฎหมายโดยสมบูรณ์ สิ่งที่สำคัญคือเนื้อหา: ให้สตรีมเฉพาะสื่อที่คุณเป็นเจ้าของหรือได้รับอนุญาตให้ถือครอง เช่น ไฟล์ที่ริปจากแผ่นของคุณเอง, การบันทึกรายการ หรือไฟล์ที่คุณมีสิทธิ์ครอบครอง Jellyfin ไม่ได้มาพร้อมกับสื่อใดๆ และไม่มีช่องทางในการจัดหาสื่อเหล่านั้น มันเป็นเพียงโปรแกรมเล่นสำหรับคลังสื่อที่คุณมีอยู่แล้วเท่านั้น