🎥 Hunt to find the cheapest way to host videos
📌 TL;DR Findings 🚀
- FFmpeg is hard amazingly powerful 🎉
- Cloud providers might be charging a fortune for peanuts (possibly) 🥜
- NSA Cloudflare should seriously consider launching a video site 🌐
🔍 How This Came to Be
A client approached me with a seemingly simple request — set up a video solution. Why, you may ask? They were using YouTube previously and were having difficulties:
- YouTube was putting ads and a clunky UI in their embeds 📺
- The embeds were forcing users to bounce off from the blog and onto YouTube 🔄
- Some of their videos were taken down due to copyright claims since they were using clips from other sources ⚖️
The task was to move onto something else which doesn't interfere with these issues.
📝 The Requirements
- YouTube-like quality and speed switching ⚡
- Some kind of CDN so the videos load quickly 🚀
- Universal device compatibility 📱💻
🔍 The Initial Research Phase
I was new to this. I have built websites, hosted static pages, deployed microservices, but video hosting was something new. After some digging, I uncovered the magic formula:
- Create an HLS stream (for quality switching) 🎞️
- Store the HLS (obviously) 💾
- Use a CDN (to serve the HLS) 🌐
- Implement an embeddable video player (to embed the HLS) 📽️
💰 Let's Do the Math First
My client uploads 5 videos a day, which are around 5 minutes each, and each get at least 10,000 views monthly.
Using some ChatGPT calculation, a 5-minute video has these sizes:
- 4K (2160p): 750 MB 📏
- 1080p: 300 MB 📏
- 720p: 187.5 MB 📏
- 480p: 93.75 MB 📏
Let's ignore 4K for now, and round off the sum of others to 512MB (0.5GB)
Storage needed for a single video: 0.5GB 📦
Assuming that most of the streams are going to be in 1080p, total bandwidth for 10,000 views? 300MB * 10,000 / 1024 ≈ 2,929.69GB (Rounding off to 3TB)
Bandwidth needed for a single video: 3TB 📊
A 5-minute video has to be transcoded into 3 streams, 2 HD and 1 non-HD. Pricing is usually X for HD videos and 0.5X for non-HD videos.
Transcoding required for a single video: 5 minutes (into 3 streams) ⏳
So if my client wants to store 5 videos a day with each getting 10,000 views, they would need roughly:
- Transcoding: 5 * 110 = 9 hours and 10 minutes ⏰
- Storage: 0.5GB * 5 * 22 = 55GB every month 📁
- Bandwidth: 3TB * 5 * 22 = 330TB 📈
For ease of calculation, let's round off:
- Transcoding to 10 hours ⏱️
- Storage to 50GB 📦
- Bandwidth to 300TB 🌐
🔧 So... How Do You Create HLS?
There are services that do this for you. AWS, Azure, GCP, etc., all have some sort of services that do this. Since the client was already using AWS for their websites, I decided to use AWS. Now I just need to put together a proposal and send out a quotation. Let's calculate.
💵 AWS Calculations 😎
At first glance, AWS seemed to have it all for me nicely packaged as a bundle:
- MediaConvert for transcoding 🎬
- S3 for storage 📦
- CloudFront for CDN ☁️
Perfect! Let me quickly calculate the costs now.
We have 10 hours of video to be transcoded every month.
HLS conversion: $22.5 💲
- 1080p: $9 💵
- 720p: $9 💵
- 480p: $4.5 💵
S3 storage (monthly): $1.15 (50GB × $0.023 per GB) 💾
CloudFront: $19,050 💸
- First 10 TB: $870.40 (10,240 GB × $0.085 per GB) 💰
- Next 40 TB: $3,276.80 (40,960 GB × $0.080 per GB) 💰
- Next 100 TB: $6,144.00 (102,400 GB × $0.060 per GB) 💰
- Next 150 TB: $6,144.00 (153,600 GB × $0.040 per GB) 💰
- Remaining 30 TB: $900.00 (30,720 GB × $0.030 per GB) 💰
Total bill? $19,000 per month! 😱 (which might compound each month as the videos grow)
📞 The Client's Reality Check ☎️
"This might not be worth it since YouTube has been kind of free this whole time. Is there a cheaper option?" 🤔
I mean, I can't compete with YouTube's prices, but let's try.
🕵️ The Quest for Alternatives
With the client's blessing to explore non-AWS options, I embarked on a new journey.
🎬 Vimeo
Vimeo specializes in video hosting, so I thought they might have their pricing figured out better. Vimeo wants $9 a month for 100GB of storage but limits you to 2TB of bandwidth and has no clear indication of the pricing for more bandwidth. Reading through forums, I found out their pricing to be similarly high as AWS. SKIP
🐰 Bunny CDN
These guys have a Stream feature which does exactly what I want it to. Let's recalculate:
- HLS conversion: $0 (it's free!) 🎉
- Storage (monthly): $0.5 (50 GB × $0.01 per GB) 💲
- Stream cost (volume tier) : $1500 (300 * 5$ per TB) 📊
Total bill? $1500 monthly (Would compound each month) 💵
We've cut costs by 92%! 🎉
I could have submitted the quote to the client and likely secured the project. However, I decided to delve deeper and explore other options. One key reason for avoiding a dedicated server was concurrency. Typically, a dedicated server has a port speed of 1Gbps and includes 20TB of bandwidth (Hetzner), allowing for 200 concurrent streams. Additionally, with extra bandwidth costing $1 per TB, we'd be facing a $280 bandwidth cost without any CDN benefits. During traffic spikes, I didn't want to deal with a P0 call in the middle of the night without knowing how to resolve it. We needed a service that was (almost) hands-off.
🛠️ DIY: The Final Frontier
Time to roll up our sleeves and do it ourselves!
🔧 The DIY Breakdown
- Transcoding: Python script + FFmpeg magic 🧙♂️
- Cost: $7 per month server with any cloud server (I like Hetzner). Can bump it up to $20-30 if I want faster transcodes. 💻
- Storage: Cloudflare R2 at $15.0 / TB 💾
- (We passed on Backblaze at $6 / TB for reasons you'll see) 🚫
- CDN: Cloudflare R2 with free egress! 🌟
- The catch: $0.36 / million class-B requests 💸
Cloudflare offers free egress? WAIT, WHAT. Let's calculate the cost of the "catch".
Since Cloudflare wants money for each file request, we need to open up the calculator and see how many requests would be made. A 5-minute video has 100 segments (5 * 60 seconds / 3 seconds). Each 10,000 views would consume 1 million requests. 110 videos would consume 110 million requests. Total cost? $39.6 💵
I have assumed that we will use 3-second segments; we could also use 6-second segments, and the cost would go down by half. Would users experience any delay? Probably not, since a 6-second segment is 3.75MB and would load in <1 second on most internet devices. Anyway, I digress. What's the total bill now?
Total bill? $40 monthly (Would compound each month) 💲
So we are now saving 97% over the cheapest option (Bunny) in the market, and 99.46% over AWS. 🎉
Could we have used Cloudflare CDN and stored the files on our own server and let Cloudflare cache it? Well, it might goes against their T&C, plus I don't want to deal with servers as much as possible. 🚫
📊 Graphs to show? 🏆
Storage Cost Comparison (1TB/month)
Pricing sources (as of August 2024):
- AWS S3: $0.023 per GB
- Bunny.net: $0.01 per GB
- Backblaze B2: $0.006 per GB
- Cloudflare R2: $0.015 per GB
Transcoding Cost Comparison (60 minutes)
Pricing details:
- AWS MediaConvert: $7.65 for 4K, 1080p, 720p, 480p combined
- Bunny: Free transcoding
- Coconut.co: $4.05 for 4K, 1080p, 720p, 480p combined
- DIY (Hetzner): $0.15 estimated cost for server time
Note: Prices are for transcoding 5 minutes of video to 4k, 1080p, 720p, and 480p resolutions.
Streaming Cost Comparison (1TB / 6000 streams at 5mbps)
Pricing details:
- AWS CloudFront: $0.085 per GB for the first 10 TB/month
- Bunny CDN Standard: $30 per TB
- Bunny CDN Volume: $5 per TB
- Cloudflare R2: Free egress, $0.36 per million Class B operations.
- Total segments for 6000 streams of 5 minutes = 6,00,000
Note: Prices are for streaming 1TB of data across 6000 streams. Cloudflare costs vary based on segment length due to the number of requests.
✨ The Moral of the Story 🏆
- FFmpeg is your new best friend 🤝
- Cloud giants might not always be the answer ☁️
- DIY can lead to massive savings 💰
- Cloudflare R2 is a game-changer 🌟
For self hosters.
- It is not necessary to use cloudflare r2, you can also use minio if you are hosting this in-house.
- AWS can also be replaced with minio. minio supports webhook notifications to trigger transcoding pipelines.
Room for improvement?
- This project is missing ability to add subtitles, thumbnails and multi-audio streams.
- The autoscaling of transcoding servers is missing.
- You can substitute self hosted transcoding with AWS mediaconvert or coconut for a complete serverless experience
- Postgres can be replaced with sqlite if running small instance
- Self hosting transcoding might not be as efficient as cloud providers'. I have heard from sources that their transcoding is better (better compression without losing on quality).
🚀 So what now?
- This project is now open source for all. Feel free to self host or contribute or just raise bugs. Code Available here. 📂
- If you have any comments or feedback, do tweet or mail me 📧