راهاندازی Jellyfin روی VPS: آموزش کامل نصب با Docker
با استفاده از Docker و یک فایل compose، سرور Jellyfin خود را روی VPS اجرا کنید. این راهنما مشکلات مجوز فایل و چالشهای transcoding در سرورهای بدون GPU را بررسی میکند.
آنچه در حال ساخت آن هستید
یک سرور رسانهای Jellyfin روی یک VPS: شامل یک کانتینر، سه volume و یک دیسک block-storage برای نگهداری فیلمها و سریالهای شما که از هر مرورگر یا اپلیکیشن Jellyfin قابل دسترسی است. نصب این سرویس با یک فایل compose پانزدهخطی انجام میشود. هر مشکلی که پس از آن رخ دهد، ناشی از دو مورد است: مجوزهای دسترسی فایل که کانتینر قادر به خواندن آنها نیست، و درخواست از یک VPS بدون GPU برای transcoding ویدیو که توانایی انجام آن را ندارد. این راهنما بخش عمدهای از حجم خود را به این دو مورد اختصاص داده است، زیرا اکثر درخواستهای پشتیبانی مربوط به همین مسائل هستند.
نرمافزار Jellyfin رایگان و کاملاً متنباز است؛ بدون نیاز به حساب کاربری، بدون قابلیتهای پولی و بدون تلهمتری. به همین دلیل است که نام آن در تقریباً تمام فهرستهای مواردی که ارزش self-hosting در سال 2026 را دارند دیده میشود. این نرمافزار رسانههایی که مالک آنها هستید را پخش میکند. Jellyfin هیچ محتوایی ارائه نمیدهد و این راهنما نیز درباره نحوه تهیه محتوا نیست.
واقعیت transcoding، پیش از اجاره هر چیزی
این بخش را ابتدا بخوانید، زیرا تصمیم شما برای خرید را تغییر میدهد. یک مدیا سرور هنگام فشردن دکمه پخش، یکی از دو کار زیر را انجام میدهد. Direct play فایل را همانطور که هست استریم میکند: VPS بایتها را از دیسک میخواند و روی شبکه میفرستد، که تقریباً هیچ فشاری به CPU وارد نمیکند. Transcoding ویدیو را بهصورت آنی (on the fly) دوباره کدگذاری میکند، رزولوشن یا کدک را تغییر میدهد یا زیرنویس را روی تصویر میچسباند (burn-in)؛ این کار تماماً پردازش CPU است.
یک VPS معمولی فاقد GPU است. بنابراین هر transcoding ویدیویی با libx264/libx265 روی CPU اجرا میشود و انکود نرمافزاری بسیار سنگین است. یک transcoding تکی 1080p H.264 میتواند چندین vCPU اشتراکی را کاملاً درگیر کند؛ transcoding ویدیوهای 4K یا HEVC معمولاً نمیتواند با سرعت پخش زنده (real-time) همگام شود، بنابراین پخش ویدیو متوقف شده و مدام با بافرینگ مواجه میشوید. transcoding سختافزاری، همان قابلیتی که این کار را در سیستمهای خانگی با iGPU اینتل یا کارتهای Nvidia ارزان میکند، در VPS در دسترس شما نیست مگر اینکه ارائهدهنده، نمونههای GPU-based اجاره دهد.
بنابراین استراتژی کلی در VPS این است: از transcoding اجتناب کنید. کتابخانه خود را با کدکهایی نگه دارید که کلاینتهای شما بهصورت بومی (natively) پخش میکنند؛ ویدیوی H.264، صدای AAC یا AC3 در کانتینر MP4 یا MKV. همچنین از اپلیکیشنهای کلاینتی استفاده کنید که از قابلیت direct-play پشتیبانی میکنند: اپلیکیشنهای بومی Jellyfin برای Android TV، iOS و Roku، بهعلاوه Infuse، Kodi و Jellyfin Media Player دسکتاپ. اگر این کار را انجام دهید، VPS هرگز مجبور نخواهد بود در حین پخش، ffmpeg transcoding اجرا کند و یک سرور معمولی با 2 vCPU میتواند همزمان برای چندین نفر استریم کند. اگر قصد transcoding دارید، به سروری بسیار بزرگتر و گرانتر نیاز خواهید داشت و حتی در آن صورت هم 4K گزینه مطمئنی نیست.
محاسبات پهنای باند را هم انجام دهید، چون این مورد غافلگیری بعدی است. در حالت direct play، فایل با نرخ بیت (bitrate) اصلی خود ارسال میشود. یک فایل 1080p فشرده حدود 8-12 Mbps، یک نسخه Blu-ray remux 1080p حدود 20-30 Mbps و یک فایل 4K HDR حدود 40-80 Mbps پهنای باند نیاز دارد. سه نفر که همزمان فایلهای 10 Mbps را direct-play میکنند، به 30 Mbps آپلود مداوم از VPS شما نیاز دارند. دو عدد را در طرح خود چک کنید: سرعت پورت (آیا میتواند 30 Mbps آپلود را پشتیبانی کند؟) و محدودیت انتقال ماهانه. یک فیلم دو ساعته 10 Mbps حدود 9 GB ترافیک خروجی دارد، بنابراین سقف 1 TB در ماه برای حدود صد فیلم در ماه کافی است (سه یا چهار فیلم در روز)؛ اما تماشای 4K که چهار تا هشت برابر نرخ بیت بیشتری دارد، این سقف را بسیار سریعتر پر میکند. هر سرویس دیگری که ترافیک خروجی از همان سرور ایجاد میکند را نیز در این بودجه لحاظ کنید، از جمله یک relay خودمیزبان RustDesk که هر زمان دو کلاینت نتوانند مستقیماً به هم متصل شوند، تمام ترافیک نشست دسکتاپ از راه دور را عبور میدهد.
پیشنیازها
- یک سرور مجازی Ubuntu 24.04 KVM تازه با دسترسی root یا sudo، به همراه Docker و افزونه Compose نصبشده.
- یک فضای ذخیرهسازی Block Storage برای رسانهها، با ظرفیت متناسب با کتابخانه شما (به بخش تعیین اندازه در ادامه مراجعه کنید). دیسک روت کوچکی که همراه VPS ارائه میشود، محل مناسبی برای ذخیره فیلمها نیست.
- یک نام دامنه اگر قصد دسترسی عمومی HTTPS دارید، یا یک WireGuard VPN روی همان VPS اگر ترجیح میدهید کل سیستم خصوصی باقی بماند.
- رسانههایی که از نظر قانونی مجاز به استریم آنها هستید؛ شامل فایلهای ریپشده توسط خودتان، ضبطهای شخصی یا فایلهایی که مالکیت آنها را دارید.
ابتدا حافظه جانبی (Block Storage) را Mount کنید
ابتدا Volume را در پنل مدیریت ارائهدهندهٔ خود متصل (Attach) کنید، سپس آن را شناسایی و Mount نمایید. نام دستگاه را از طریق 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 Mount کنید، زیرا ممکن است حروف اختصاصیافته به دستگاهها پس از reboot تغییر کنند و در نتیجه دیسک اشتباهی را فرمت یا Mount کنید. یک خط به فایل /etc/fstab اضافه کنید:
UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx /mnt/media ext4 defaults,nofail 0 2sudo mount -a
df -h /mnt/mediaگزینه nofail اهمیت حیاتی دارد؛ بدون آن، اگر Volume جدا شود، سرور بوت نمیشود و به محیط emergency shell میرود. بزرگترین اشتباه در این مرحله، اجرای دستور mkfs.ext4 روی Volumeای است که از قبل حاوی داده است، زیرا تمام اطلاعات را پاک میکند. فقط Volumeهای جدید را فرمت کنید؛ اگر دیسک از قبل حاوی اطلاعات شماست، مستقیماً به مرحله اضافه کردن خط در fstab بروید.
ساختار فایلهای رسانهای را مطابق انتظار Jellyfin تنظیم کنید
Jellyfin متادادهها را بر اساس نام پوشهها و فایلها تطبیق میدهد. اگر ساختار را اشتباه بچینید، فیلمها بهصورت فایلهای بدون عنوان و پوستر نمایش داده میشوند یا یک قسمت سریال به اشتباه با مجموعه دیگری تطبیق میخورد. چهار قرارداد اصلی تقریباً تمام کار را انجام میدهند: هر فیلم باید در پوشه اختصاصی خود با نامی مطابق با آن قرار گیرد که با Name (Year) نامگذاری شده است (Jellyfin سال را اختیاری میداند، اما وجود آن تطبیق را بسیار مطمئنتر میکند)؛ پوشههای فصل باید با نام Season 01 باشند، نه S01؛ فایلهای قسمتها از الگوی S01E01 استفاده میکنند؛ و قسمتهای ویژه (Specials) باید در 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) در نام فیلمها صرفاً جنبه تزئینی ندارد، بلکه بازسازیها (remakes) را متمایز میکند تا موتور تطبیق، عنوان صحیح را پیدا کند. پوشههای 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 در لاگ، خالی نمایش داده میشوند. هر پوشهٔ رسانهای که قابل خواندن نباشد، در لاگ ثبت و نادیده گرفته میشود؛ بنابراین دستهای از فایلها که با کاربر root کپی شدهاند، بدون هیچ هشداری از کتابخانه ناپدید میشوند. به همین دلیل است که ما از chown به صورت بازگشتی (recursive) استفاده میکنیم و بیت execute را روی تمام دایرکتوریها تنظیم میکنیم، به جای اینکه فقط یک پوشه را اصلاح کنیم.
فایل docker-compose
services:
jellyfin:
image: jellyfin/jellyfin:12
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خط به خط: jellyfin/jellyfin:12 نسخه فعلی سری 12.x را دنبال میکند (12.2 تا تاریخ 2026-10-10). user: "1000:1000" شناسه uid/gid که فرآیند Jellyfin با آن اجرا میشود را تعیین میکند. این گزینه مالکیت یا حالت هیچ فایلی را تغییر نمیدهد، زیرا Docker شناسه uid/gid میزبان را روی دایرکتوریهای mount شده حفظ میکند؛ به همین دلیل است که chown در بالا باید با آن مطابقت داشته باشد. /config کل سرور، حسابها، کتابخانهها، متادیتا و وضعیت تماشا را در خود نگه میدارد، بنابراین باید قابل نوشتن باشد و همان بخشی است که باید از آن نسخه پشتیبان تهیه کنید. /cache فضای کاری موقت و دورریختنی است. mount رسانه به صورت :ro (فقط خواندنی) و با هدف مشخص انجام شده است: Jellyfin بهطور پیشفرض تصاویر و متادیتا را در /config ذخیره میکند، بنابراین هرگز نیازی به نوشتن در کتابخانه شما ندارد و حالت فقط خواندنی از فایلهای شما در برابر حذف تصادفی یا پلاگینهای مخرب محافظت میکند. پورت بهطور عمدی به 127.0.0.1 محدود شده است، زیرا ورود به وب Jellyfin از نوع HTTP ساده است و ما هرگز 8096 را در اینترنت عمومی منتشر نمیکنیم. JELLYFIN_PublishedServerUrl آدرسی است که سرور برای کشف خودکار محلی (local autodiscovery) و پخش UDP در شبکه LAN اعلام میکند، بنابراین کلاینتهای موجود در اینترنت هرگز آن را نمیبینند و صرفاً از 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 (مسیر داخل کانتینر، نه مسیر میزبان) هدایت کنید، سپس همین کار را برای Shows در /media/Shows تکرار کنید. پس از پایان، Jellyfin شروع به اسکن میکند. نتیجهٔ موفقیتآمیز این است که برای یک کتابخانه کوچک، پوسترها و عناوین ظرف یک یا دو دقیقه بارگذاری شوند. کتابخانهها را میتوانید بعداً از طریق Dashboard → Libraries اضافه یا ویرایش کنید و با استفاده از Scan All Libraries، اسکن مجدد را اجبار کنید. این پوسترها همان چیزی هستند که باعث میشوند یک فرانتاند جایگزین ارزش بررسی داشته باشد، چرا که Halcyon همان کتابخانه را به شکل یک فروشگاه ویدیوی دهه نودی قابلگشتوگذار بازسازی میکند که از آثار هنری دریافتشده توسط Jellyfin استفاده میکند.
اگر به هر نوع transcoding وابسته هستید، به Dashboard → Playback → Transcoding بروید و مسیر موقت transcode را روی /cache/transcodes تنظیم کنید تا بار پردازشی روی volume کش قرار بگیرد و باعث پر شدن /config نشود. شتابدهنده سختافزاری (hardware acceleration) را روی None باقی بگذارید، زیرا GPU برای شتابدهی وجود ندارد.
دسترسی از راه دور: reverse proxy با TLS، یا نگهداری در VPN
دو روش امن برای دسترسی به Jellyfin از خارج از شبکه وجود دارد و یک روش ناامن که باید از آن اجتناب کرد. روش ناامن، باز کردن مستقیم پورت 8096 روی اینترنت است: اطلاعات ورود بهصورت متن ساده (cleartext) منتقل میشوند و پورت مذکور ظرف چند ساعت مورد حمله brute-force قرار میگیرد.
گزینه A، استفاده از reverse proxy با TLS. سرویس Jellyfin را روی یک زیردامنه پشت Traefik با TLS خودکار برای برنامههای Docker یا پشت nginx با گواهی Let's Encrypt صادر شده توسط Certbot قرار دهید. Jellyfin برای بهروزرسانیهای لحظهای از WebSockets استفاده میکند، بنابراین proxy باید هدرهای upgrade را فوروارد کند. Traefik این کار را بهصورت خودکار انجام میدهد؛ اما در nginx باید این هدرها بهصراحت تعریف شوند و برای اینکه عملیات upgrade با موفقیت انجام شود، باید از 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 تنظیم کنید تا پیش از کاربران، از قطعی سرویس مطلع شوید. اعلانهای آن را به سمت یک سرور ntfy خودمیزبان هدایت کنید تا در صورت شکست بررسی، بهجای ایمیلی که ممکن است صبح روز بعد بخوانید، یک push notification روی گوشی دریافت کنید. قرار دادن یک صفحه ورود روی اینترنت عمومی، فرصت مناسبی برای بررسی امنیتی سایر بخشهای سرور است تا صرفاً به این اطمینان که فقط پورت 443 پاسخگو است، اکتفا نکنید: دستور sudo ss -tlnp تمام پورتهای در حال گوش دادن و پردازشهای مربوط به آنها را فهرست میکند. اگر کدهای شخصی خود را نیز روی سرور مستقر میکنید، open-kritt مخازن و وابستگیهای آنها را برای یافتن آسیبپذیریها اسکن میکند؛ این ابزار سورسکد را بررسی میکند، نه پورتهای در حال گوش دادن.
گزینه B، خصوصی نگه داشتن در VPN. پورت 8096 را بههیچوجه روی اینترنت عمومی باز نکنید؛ فقط از طریق تونل WireGuard که روی همان سرور خاتمه مییابد به Jellyfin دسترسی پیدا کنید. برای یک محیط خانگی، این سادهترین انتخاب امن است؛ بدون نیاز به گواهی، بدون مواجهه با اینترنت عمومی و بدون سطح حمله برای brute-force. اتصال localhost در فایل compose بهتنهایی در اینجا کافی نیست، زیرا پورتی که روی 127.0.0.1 منتشر شده باشد، فقط از داخل خود VPS قابل دسترسی است، نه از طریق همتایان VPN. آن را روی آدرس تونل سرور منتشر کنید (برای مثال "10.8.0.1:8096:8096"، با استفاده از IP سرور WireGuard خودتان) یا localhost را حفظ کرده و یک proxy که روی آدرس تونل گوش میدهد جلوی آن قرار دهید و سپس از طریق VPN متصل شوید. برای راهاندازی خود تونل، به راهنمای راهاندازی WireGuard VPN برای یک VPS خصوصی مراجعه کنید.
تخمین فضای ذخیرهسازی و پشتیبانگیری
بودجهبندی را بر اساس کیفیت انجام دهید، نه تعداد فایلها. فیلمهای 1080p فشردهشده بین 4 تا 15 گیگابایت، نسخههای remux 1080p بین 20 تا 40 گیگابایت، یک فصل سریال 1080p بین 15 تا 40 گیگابایت و هر محتوای 4K بین 40 تا 100 گیگابایت برای هر فیلم فضا اشغال میکنند. یک آرشیو شامل چند صد فیلم و تعدادی سریال به یک volume با ظرفیت 2 تا 4 ترابایت نیاز دارد؛ هزینهٔ اختصاص فضای اضافه در همان ابتدا، بسیار کمتر از مهاجرت دادهها در آینده است.
/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 باید جداگانه پشتیبان بگیرید یا بپذیرید که در صورت از دست رفتن، دوباره قابل جایگزینی (re-rip) هستند؛ اکثر کاربران با توجه به حجم بالای این دادهها، گزینه دوم را انتخاب میکنند. ارتقاها docker compose pull && docker compose up -d هستند؛ تگ :12 در بالا در محدودهٔ نسخه 12.x باقی میماند، بنابراین انتقال به نسخه اصلی بعدی یک تغییر تگ آگاهانه است. پیش از انجام این کار، یادداشتهای انتشار Jellyfin را مطالعه کنید، زیرا مهاجرت طرحواره (schema) کتابخانه در نسخههای اصلی رخ میدهد. Jellyfin با انتشار نسخه 12.0 (سپتامبر 2026) پیشوند "10." را از شماره نسخههای خود حذف کرد: 12.0 همان چیزی است که قرار بود 10.12 باشد؛ نسخه 11.x وجود ندارد و 10.11.x آخرین سری در طرح شمارهگذاری قدیمی بود. اگر فایل compose قدیمی شما همچنان از jellyfin/jellyfin:10 استفاده میکند، روی نسخه 10.11 متوقف شده است (این تگ آخرین بار در تاریخ 2026-06-06 به 10.11.11 بهروزرسانی شد) و هرگز نسخه 12.x را دریافت نخواهد کرد. انتقال به :12 چیزی فراتر از یک تغییر تگ ساده است: نسخه 12.0 طرحواره پایگاه داده را تغییر میدهد و در اولین اجرا دادهها را بازنویسی میکند. بنابراین ابتدا سرور را متوقف کرده و از دایرکتوری وضعیت پشتیبان بگیرید، زیرا آن نسخه پشتیبان تنها راه بازگشت است. ارتقا به 12.0 مستقیماً از نسخه 10.10.7 یا هر نسخه 10.11.x امکانپذیر است و پس از آن نیاز به اسکن کامل کتابخانه دارد که بهطور محسوسی طولانیتر از حالت معمول است. یک تگ ثابت (pinned tag) به همراه یک دایرکتوری وضعیت پشتیبانگیریشده، تمام چیزی است که برای هر کانتینر همیشه روشن نیاز دارید؛ این همان الگویی است که در حفظ حافظه و زمانبندیهای یک 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 در حال transcoding نرمافزاری با سرعتی کمتر از زمان واقعی است و عقب میماند. علت: کدک یا کانتینر پشتیبانینشده، رندر شدن زیرنویس روی تصویر (burn-in)، یا tone-mapping برای HDR. راهحل: از کلاینتی استفاده کنید که از پخش مستقیم پشتیبانی میکند، منابع را با فرمت H.264/AAC نگه دارید، از زیرنویسهای متنی (SRT) به جای زیرنویسهای تصویری (PGS/VOBSUB) استفاده کنید (چون اکثر کلاینتهای Jellyfin نمیتوانند دومی را مستقیماً رندر کنند و مجبور به 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." کلاینت منبع را رد کرده و transcoding جایگزین نیز برای شروع شکست خورده است. علت: دستور ffmpeg خراب، فایل غیرقابل خواندن، یا مسدود بودن تبدیل ویدیو در پروفایل کاربر. راهحل: خط مربوط به ffmpeg را در Dashboard → Logs بخوانید، مطمئن شوید فایل اصلاً پخش میشود، اگر به transcoding وابسته هستید مجوزهای پخش کاربر را بررسی کنید، و برای اطمینان از اینکه مشکل از محدودیتهای کدک مرورگر نیست، از کلاینت دیگری استفاده کنید.
فیلمها پوستر ندارند یا پوستر اشتباه نمایش داده میشود. متادیتا مطابقت نداشته است. علت: نام پوشه یا فایل با عنوانی که در دیتابیس متادیتا ثبت شده مطابقت ندارد، فیلم بازسازیشده یا عنوانی رایج است که سال ساخت برای تشخیص نسخهها در آن ذکر نشده، پوشه فصل به جای Season 01 با نام S01 نامگذاری شده، یا قسمتها در قالب S01E01 نیستند. راهحل: نامگذاری را به الگوی بالا تغییر دهید، سپس Refresh metadata → Replace all را بزنید، یا از گزینه Identify روی یک آیتم خاص استفاده کنید تا ورودی صحیح TMDB/TVDB را به آن اختصاص دهید.
FAQ
آیا یک VPS میتواند بدون GPU ویدیو را Transcode کند؟
بله، اما فقط با استفاده از CPU و این کار هزینهبر است. یک Transcode نرمافزاری 1080p میتواند چندین vCPU را کاملاً درگیر کند و معمولاً پردازش 4K یا HEVC نمیتواند با سرعت پخش زنده (Real-time) همگام شود، در نتیجه پخش با وقفه (Buffer) مواجه میشود. بهترین راهکار، پرهیز از Transcoding است: کتابخانه خود را با فرمت H.264/AAC نگه دارید و از کلاینتهایی استفاده کنید که از قابلیت Direct-play پشتیبانی میکنند تا VPS فقط نقش انتقالدهنده بایتها را داشته باشد. تنها در صورتی یک نمونه (Instance) دارای GPU اجاره کنید که واقعاً به Transcoding لحظهای نیاز دارید.
چرا کتابخانه Jellyfin من پس از اسکن خالی است؟
تقریباً همیشه مشکل از مجوزها (Permissions) است. تصویر رسمی jellyfin/jellyfin با هر user: که تعیین کردهاید (یا root) اجرا میشود؛ اگر فایلها توسط آن uid قابل خواندن نباشند، لاگهای اسکن Access to the path ... is denied را ثبت کرده و از آنها عبور میکند. مالکیت فایلها را با chown -R 1000:1000 /mnt/media اصلاح کنید، به دایرکتوریها بیت اجرایی (755) بدهید، دوباره اسکن کنید و دایرکتوری والد را نیز بررسی کنید؛ زیرا اگر uid کانتینر نتواند از /mnt/media عبور کند، هرگز به پوشههای کتابخانه نمیرسد و همه چیز خالی نمایش داده میشود. دومین دلیل رایج، ساختار پوشهبندی است که با انتظارات Jellyfin مطابقت ندارد.
چگونه به صورت امن و از راه دور به Jellyfin دسترسی داشته باشم؟
دو گزینه مناسب وجود دارد. آن را پشت یک Reverse Proxy با TLS روی یک زیردامنه قرار دهید تا ورود و استریم رمزنگاری شوند و fail2ban را اضافه کنید؛ هرگز پورت 8096 را به صورت خام در معرض اینترنت قرار ندهید، زیرا رمز عبور شما را به صورت متن ساده (Cleartext) ارسال میکند. یا آن را کاملاً خصوصی نگه دارید و فقط از طریق VPN به آن دسترسی پیدا کنید که سادهترین انتخاب امن برای مصارف خانگی است. آدرس عمومی را مستقیماً به اپلیکیشنها بدهید، زیرا قابلیت Autodiscovery یک پخش شبکه محلی (Broadcast) است و به کلاینتهایی که از طریق اینترنت متصل میشوند، نمیرسد.
یک VPS برای Jellyfin به چه مقدار دیسک و پهنای باند نیاز دارد؟
میزان دیسک به کیفیت بستگی دارد: برای هر فیلم 1080p فشرده 4-15 گیگابایت، برای هر Remux حدود 20-40 گیگابایت و برای 4K حدود 40-100 گیگابایت در نظر بگیرید، بنابراین اکثر کتابخانهها به یک Block Volume با ظرفیت 2-4 ترابایت نیاز دارند. پهنای باند توسط نرخ بیت (Bitrate) در حالت Direct-play تعیین میشود که برای هر استریم 1080p حدود 8-12 مگابیت بر ثانیه است و برای 4K بسیار بیشتر؛ بنابراین اطمینان حاصل کنید که سرعت پورت شما پاسخگوی تعداد بینندگان همزمان است و سقف انتقال ماهانه را نیز زیر نظر داشته باشید. اگر قصد Transcoding دارید، ظرفیت CPU بیشتری در نظر بگیرید؛ اما اگر قصد استفاده از Direct-play دارید، پهنای باند را نسبت به تعداد هستهها در اولویت قرار دهید.
آیا اجرای Jellyfin روی یک VPS قانونی است؟
Jellyfin خود یک نرمافزار آزاد و متنباز است و اجرای آن کاملاً قانونی است. آنچه اهمیت دارد محتواست: فقط رسانههایی را استریم کنید که مالک آنها هستید یا مجوز نگهداری آنها را دارید؛ مانند ریپهای دیسک شخصی، ضبطها یا فایلهایی که حق استفاده از آنها را دارید. Jellyfin هیچ رسانهای را به همراه ندارد و راهی برای دریافت آن فراهم نمیکند؛ این نرمافزار صرفاً یک پخشکننده برای کتابخانهای است که از قبل در اختیار دارید.