Run a media server on a storage VPS?
A storage VPS holds terabytes cheaply, but can it stream them? Do the bandwidth arithmetic first, then split the library from the application.
Can a storage VPS run a media server?
A storage VPS can run a media server, and for direct play it often runs one well. The wall is transcoding: a plan sold on disk capacity carries enough CPU to read files and push them out, and nowhere near enough to re-encode a high bitrate file while someone watches it. Sending bytes untouched is cheap work. Rewriting every frame is not.
Three limits decide the answer for your library, and they arrive in a fixed order.
- CPU. It stops you the moment a client cannot play a file exactly as it is stored.
- Disk. It rarely stops playback. It makes library scans crawl and it makes the web interface feel slow while the video itself looks fine.
- The network port. This is the real ceiling, and it is the one you can work out on paper before you spend anything.
Work through them in that order. The last one is arithmetic, so it gives you an answer instead of an opinion.
What a storage VPS actually gives you
On a storage VPS the disk is the product. You are buying terabytes at a price per terabyte that no compute plan matches, and the CPU, memory and network attached to those terabytes are sized to keep files safe and readable. Cheap terabytes are a good reason to buy one. They are not a reason to expect a transcoding server.
Two numbers on the plan page decide most of what follows: the port speed and the monthly traffic allowance. Read the current page for the exact plan you are about to buy. Do not carry a figure over from a review, a forum post or another provider, because these two vary more between plans than anything else on the page. What a storage VPS trades away next to a regular VPS covers the rest of that trade, and reading a cheap VPS offer carefully covers the wording that hides the limits.
Limit one: why transcoding is the CPU wall
A media server hands a file to a player in one of three ways.
- Direct play. The server sends the file as stored and the client decodes it. The server reads from disk and writes to a socket, so a single vCPU feeds several streams.
- Direct stream, also called remux. The container is rewritten and the video is copied frame for frame. The cost is small.
- Transcode. Every frame is decoded and encoded again at a new codec or bitrate. The cost is large, and it is paid again for every stream.
You do not choose which one happens. The client chooses, and it forces a transcode when any of these is true.
- It cannot decode the codec. HEVC (high efficiency video coding) in an older browser is the usual case.
- The subtitle track is an image rather than text, such as PGS from a Blu-ray rip, so the subtitles have to be painted into the picture and the video re-encoded around them.
- It asks for a bitrate cap below the file's bitrate, which a phone on mobile data does by default.
- The container is one it will not open.
Measure your own box rather than trusting a CPU model name. Take the heaviest file in your library and encode two minutes of it.
ffmpeg -hide_banner -y -i /path/to/movie.mkv -map 0:v:0 -c:v libx264 -preset veryfast -b:v 4M -t 120 -f null -The last line of output ends with a speed= field. speed=1.0x means the box produces one second of video per second of real time, which is one stream with no margin. Playback is not steady work: every seek throws away what the encoder has produced and starts it again, so a box that measures under roughly 2x rebuffers in normal use. Two concurrent transcodes need about twice the figure. A 4K source is harder than the ratio suggests, because the decode side alone scales with pixel count before the encoder starts.
Then check whether any hardware help exists.
ls -l /dev/driOn most VPS plans this prints ls: cannot access '/dev/dri': No such file or directory, because no GPU is passed through to the guest. Without that device node, VAAPI (video acceleration API) and Intel Quick Sync have nothing to open, so every transcode lands on the CPU. Hardware transcoding on a box with an NVIDIA GPU is a different machine at a different price, so treat it as a separate decision rather than an upgrade path for this plan.
The way past this limit is to make transcoding unnecessary. Store H.264 in MP4 or MKV, keep subtitles as text so they travel beside the video instead of being burned into it, and put a client app on every screen that decodes what you store. CPU load then falls close to zero and the whole question moves to the port. If the library does not exist yet, the step by step Jellyfin install on a VPS is where to start.
Limit two: what shared or spinning disk really costs
Playing a file is sequential reading at the file's bitrate. A 25 Mbps remux is about 3.1 MB/s. One slow spinning disk does forty times that in sequential reads, so playback is not where the disk hurts.
The disk hurts on small random work, and a media server does plenty of it. The first library scan opens every file and reads its header. Trickplay generation builds the preview thumbnails you see when dragging the seek bar, and it decodes frames spread through the whole file. That is seeking, not streaming. The library database is SQLite, at /var/lib/jellyfin/data/library.db on the Debian and Ubuntu packages, and every update ends in an fsync that waits for the storage to confirm the write.
On a volume shared with other tenants those fsyncs queue behind other people's work. The symptom is specific and easy to misread: a movie plays perfectly while the web interface takes seconds to paint a page. That is not the network and not the CPU. That is the database waiting on the disk.
Measure both patterns, inside the directory you will actually keep media in.
sudo apt install -y fio
fio --name=seq --rw=read --bs=1M --size=2G --ioengine=libaio --direct=1 --runtime=60 --time_based --group_reporting
fio --name=rand --rw=randread --bs=4k --size=1G --iodepth=32 --ioengine=libaio --direct=1 --runtime=60 --time_based --group_reportingThe sequential number tells you how many streams the disk can feed at once. The random number tells you how long a scan of ten thousand files will take. If fio answers OS does not support direct IO, drop --direct=1 and read the result knowing the page cache is now in the way. Delete the seq.0.0 and rand.0.0 files it leaves behind. What disk speed to expect from a storage VPS gives the shape of the numbers, and a repeatable way to benchmark a VPS keeps your runs comparable between boxes.
One setting matters more than the rest: the transcode temporary directory must not sit on the storage volume. A transcode writes HLS (HTTP live streaming) segments continuously while the viewer watches, and on slow or remote storage those writes fall behind and the player stalls while the CPU still has headroom. Point it at local disk in the playback settings.
Limit three: the port, and the arithmetic that settles it
The data behind this chart
[
{
"label": "1080p web rip (H.264)",
"bitrate_mbps": 5,
"gb_per_hour": 2.25,
"streams_per_gigabit": 200
},
{
"label": "1080p Blu-ray remux",
"bitrate_mbps": 25,
"gb_per_hour": 11.25,
"streams_per_gigabit": 40
},
{
"label": "4K HDR remux",
"bitrate_mbps": 60,
"gb_per_hour": 27,
"streams_per_gigabit": 16
},
{
"label": "Transcoded 1080p output",
"bitrate_mbps": 4,
"gb_per_hour": 1.8,
"streams_per_gigabit": 250
}
]Those are typical published bitrates for each kind of file, not measurements of any provider's plan. The rule is one line: concurrent streams multiplied by bitrate must stay under the port speed. A 1080p web rip at 5 Mbps gives 200 streams on a gigabit port on paper. A Blu-ray remux at 25 Mbps gives 40. A 4K HDR remux at 60 Mbps gives 16, which is one household with two televisions using most of a gigabit.
The paper figure is optimistic for two reasons. Protocol overhead and a shared uplink take a slice you never see. The larger effect is buffering: a direct play client does not trickle bytes at the file's bitrate, it pulls ahead as fast as the link allows and then goes quiet, so one person starting a film can saturate the port for several seconds. Plan for well under half the paper figure.
The traffic allowance is a separate limit, and it is the one a household hits first. A port speed caps how many people watch at once. An allowance caps how much they watch all month.
The data behind this chart
[
{
"label": "One stream, 1080p at 5 Mbps, 2 h a day",
"hours_per_month": 60,
"gb_per_month": 135
},
{
"label": "Two streams, 1080p at 5 Mbps, 3 h a day",
"hours_per_month": 180,
"gb_per_month": 405
},
{
"label": "Two streams, 1080p at 5 Mbps, 6 h a day",
"hours_per_month": 360,
"gb_per_month": 810
},
{
"label": "Two streams, remux at 25 Mbps, 6 h a day",
"hours_per_month": 360,
"gb_per_month": 4050
}
]Two people watching a normal evening at 1080p come to 810 GB a month, across 360 stream hours. Keep the viewing identical and switch the library to Blu-ray remuxes, and the same 360 hours cost 4050 GB, close to 4 TB. The bitrate you store is the traffic bill you pay, and it is the one term in this arithmetic you fully control.
Read the plan page for the allowance, then read what happens when you pass it. Some plans slow the port, some charge for the excess. Check separately whether inbound traffic counts, because filling a library is one large upload and plans differ on whether they meter it.
The split: library on the storage box, application on the fast box
The setup that works is not one machine. Media files live on the storage VPS. The media server application, its database, its metadata images and its transcode directory live on a small fast VPS with local NVMe. The application mounts the library over the private network, and every file that can be direct played is sent out untouched.
Mount it with an automount unit rather than a boot time mount.
10.0.0.10:/srv/media /mnt/media nfs4 rw,hard,noatime,rsize=1048576,wsize=1048576,noauto,x-systemd.automount 0 0noauto,x-systemd.automount mounts the share on first access instead of at boot, so a storage box that is briefly unreachable delays one directory listing rather than hanging the boot. Check it with findmnt /mnt/media, then confirm the service account can read through it with sudo -u jellyfin ls /mnt/media. A permission denied there while root lists the same path fine is a user ID mismatch: NFS compares numeric IDs, so the jellyfin user needs the same UID on both machines, and the default root_squash export option maps root to nobody.
Keep the database on local disk. SQLite depends on file locking that a network filesystem does not reliably provide, and the failure is not a clean error message. You get database is locked under concurrent access, and database disk image is malformed after the wrong kind of crash, by which point the library is a restore job. The database is small, so local disk costs you nothing here.
Keep the download directory and the library on the same filesystem. An import that can use a hardlink is instant and takes no extra space. An import across two filesystems is a full copy, which over a network mount drags the file across the link twice for no reason. In practice that means running the arr stack in Docker Compose on the storage box beside the files, with only the media server reading across the mount.
The split has one real cost: the extra hop. A stream is read across the private link and then sent out of the application box's port, so the bytes cross the network twice, and the second crossing is the metered one. When both machines sit in the same location on a private network, the first hop is usually fast and usually free. When they do not, you pay for the traffic twice and you feel the latency on every seek. Confirm that both machines can be placed in the same location before buying either one. Pairing a storage VPS with your main VPS works through the mount and the network side in detail.
The four measurements to run before you commit
- Encode two minutes of your heaviest file with the
ffmpegcommand above and readspeed=. Under 2x means transcoding that file is off the table. - Run both fio jobs in the media directory. The sequential result feeds streams. The random result decides scan time.
- Run
iperf3 -son one box andiperf3 -c 10.0.0.10 -Ron the other, then download one real file to a device on the network you actually watch from. The second test includes everything the first one leaves out. - Install
vnstat, leave it for a normal week, then runvnstat -m. That is your real monthly traffic rather than an estimate.
When the honest answer is a NAS at home
If everyone who watches lives in the same house, the server belongs in the house. A local network gives a gigabit or more with no meter and no monthly bill, a 4K remux plays with no bitrate arithmetic at all, and the running cost is electricity. A VPS earns its place when you watch from outside the house, when you share with people in other homes, when your home upload cannot carry even one stream, or when you would rather not keep a machine running at home. Check that upload first: a remux at 25 Mbps needs more upstream capacity than many home connections have.
When the answer is the NAS, the storage VPS still has a job worth paying for. An offsite copy of the library is exactly what cheap terabytes are for, and using a VPS as an offsite backup target uses a fraction of the traffic that streaming does, because a backup sends each file once instead of once per viewing. Size it from an honest estimate of how much storage you need rather than by rounding up, and test the plan against a storage VPS checklist before committing to a year.
One point that is not about hardware: renting the server makes the content your responsibility under the provider's terms. Serve what you have the right to serve.
FAQ
Can a storage VPS transcode 4K to 1080p?
Usually not in real time. Software encoding from a 4K source means decoding roughly four times the pixels of a 1080p file before the encoder starts, and the vCPU share on a capacity plan is not sized for that. Test it instead of guessing: run ffmpeg -hide_banner -y -i /path/to/movie.mkv -map 0:v:0 -c:v libx264 -preset veryfast -b:v 4M -t 120 -f null - and read the speed= field on the last line. Under 1.0x the stream cannot keep up at all, and under about 2x it rebuffers whenever a viewer seeks. Run ls -l /dev/dri as well. If it answers No such file or directory there is no GPU in the guest, so hardware encoding is not an option on that plan.
How many streams fit on a gigabit port?
Divide the port speed by the bitrate of the files you serve. At 5 Mbps for a 1080p web rip that is 200 streams on paper, and at 60 Mbps for a 4K HDR remux it is 16. Plan for well under those figures. The port is shared and protocol overhead is real. A direct play client also buffers ahead at whatever speed the link allows instead of pacing itself at the file's bitrate, so a single viewer starting a film can take the whole port for a few seconds.
Where should the media server database live in a split setup?
On local disk on the machine running the application, never on the network mount. SQLite relies on file locking that a network filesystem does not always deliver, so a database on an NFS share produces database is locked errors under load and database disk image is malformed after a bad crash. On the Debian and Ubuntu packages the file is /var/lib/jellyfin/data/library.db. Keep the metadata images and the transcode directory local as well, and let only the media files come across the mount.
Does transcoding use less bandwidth than direct play?
Yes, and that is the trade. Direct play sends the file at its stored bitrate, so a 25 Mbps remux costs 25 Mbps of outbound traffic per viewer. Transcoding the same film down to 4 Mbps is why 250 of those streams fit on a gigabit port. You pay for the saving in CPU, once per stream, which is the exact resource a storage plan is short of. Storing files at a bitrate your clients accept directly gives you the same bandwidth saving for free.
Should I use a NAS at home instead of a storage VPS?
If every viewer is in the house, yes. A local network has no traffic meter and no monthly bill, so bitrate stops being a constraint at all. A VPS wins when you watch from outside the house, or when you share with other households. Home upload decides it in most cases: many connections cannot push a 25 Mbps remux upstream even once. The two also work together, with the NAS serving the house and the storage VPS holding the offsite copy.