Transformation of the Emby video showcase website based on Cloudflare: From public network publishing to optimized access experience

1 From Media Servers to Film and Television Showcase Sites

For those who have amassed a large collection of movies and TV shows, the thought of sharing their collection with others is probably more or less understandable—of course, "sharing" here simply means looking at the posters, the size of the collection, and which movies are included, not actually providing online streaming services. After all, streaming not only continuously consumes the limited upload bandwidth of home broadband (domestic operators now have very strict restrictions on home broadband upload traffic; even a slightly large amount of data can trigger speed limits or even account blocking), but also, publicly offering movie and TV shows for streaming is a rather sensitive topic and not suitable for long-term operation as a personal hobby project.

Therefore, for collectors like myself, the needs are actually quite simple:Turn your film and television collection into a publicly accessible showcase. It allows others to see what movies and TV series they have collected, and the approximate size of their collection, just like browsing a Douban movie list.

From a technical standpoint, achieving this goal doesn't seem difficult. Popular media management systems like Emby, Jellyfin, and Plex offer mature web interfaces that can automatically retrieve posters, actor information, plot summaries, and various media metadata. Superficially, simply publishing one of these systems on the public internet seems to solve the problem.

However, in practice, it becomes clear that things are not so simple. While these systems do offer web interfaces, their design goal is essentially to provide media management and playback services for home users. In other words, they are first and foremost "media servers," and only secondarily "web applications."

However, when we try to turn them directly into a film and television showcase site for internet visitors, all sorts of problems arise.

For example:

  • Visitors who simply want to browse the posters still need to go through the full login process;
  • Resource loading delays that are barely noticeable in a local area network environment will be significantly amplified in a public network environment, especially when there are a large number of poster images and front-end static resources, resulting in a noticeable decline in the overall access experience.
  • The login page often experiences a noticeable delay upon initial loading, especially when accessed from the public internet. For ordinary visitors, a wait of ten or more seconds can easily lead them to mistakenly believe that the website has stopped working.

The reason for this is not that these systems are poorly designed, but rather that they were primarily designed for home media management from the outset. When the usage scenario changes from "internal home use" to "public network visitor browsing," some previously insignificant problems are quickly magnified.

In other words, for a film and television showcase website, being accessible to the public internet and being suitable for public access are two completely different things. If you want to transform an existing media management system into a film and television showcase website that is truly suitable for public access, simply completing the public internet launch is far from enough. You also need to make targeted adjustments and optimizations to multiple aspects such as access methods, authentication processes, and user experience.

This article will use Emby as an example to record how I solved these problems step by step and finally transformed it into a movie and TV show site suitable for public network access.

2. Preliminary Preparations: Deploying Emby using Cloudflare Tunnel

Before addressing issues like login and access experience, we first need to solve a fundamental problem:How can I make my home Emby accessible via the internet? For most home theater enthusiasts, Emby is usually deployed within a home network, running on a NAS, mini PC, or home server. In this case, all access requests come from the local area network, thus ensuring stable operation.

If the goal is to transform it into a publicly accessible video streaming site, the first problem to solve is how to enable internet users to access the Emby service at home.

The most direct solution is naturally a public IP address combined with port forwarding. If your home broadband has a public IP address (whether IPv4 or IPv6), theoretically, you only need to configure the corresponding port forwarding rules on your router to publish Emby from your internal network to the public network. This solution was very common in early personal website hosting and home server scenarios; it was simple and straightforward to configure and required almost no additional cost. However, today, it is gradually becoming less suitable as the default choice for home environments.

The first challenge is the acquisition and long-term availability of public IP addresses. With IPv4 address resources becoming increasingly scarce, more and more operators are adopting CGNAT (Carrier-Grade NAT) solutions, meaning many home broadband connections no longer have truly public IPv4 addresses. Even if a public IPv4 address can be obtained now, it may not be stable in the long term. While IPv6 fundamentally solves the address exhaustion problem, it also has limitations for publicly accessible websites. Visitors must also have a usable IPv6 network environment to access the site. This means that whether a website can be accessed smoothly depends not only on the server but also on the visitor's network conditions, thus raising the overall barrier to entry.

Secondly, even if the public IP address issue can be resolved, directly exposing the home network to the internet will still incur additional maintenance costs. For example, port opening and routing configuration need to be maintained independently, the service will face constant scanning and probing from the public internet, HTTPS certificates need to be applied for and managed separately, and the real public IP address will be directly exposed to the external network. For a film and television exhibition site that primarily serves a display function, these additional investments seem somewhat counterproductive.

Furthermore, there is another often overlooked but very real factor: in recent years, domestic operators have generally become more cautious about running web services via home broadband. Although specific strategies vary across different regions and operators, providing website services via home broadband in the long term inherently involves a degree of uncertainty. For a video streaming website that aims for long-term stable operation, this is clearly not an ideal prerequisite.

For the reasons mentioned above, for individuals building publicly accessible film and television showcase sites, we prefer a publishing method that is neither reliant on public IPv4 nor affected by the availability of IPv6. In this context, I ultimately chose a solution more suitable for a home setting:Cloudflare Tunnel. Its key difference is not that it "adds an extra layer of proxy", but that the access model has changed - it no longer relies on the inbound port, but instead the home server actively establishes a persistent connection channel to the outside, and Cloudflare is responsible for forwarding external access requests.


For a brief configuration guide of Cloudflare Tunnel, please refer to the following article:Using tunnel technology, even home broadband without a public IP address can quickly build a website using Cloudflare for free (recommended).For those who wish to learn more, please refer to the article:Cloudflare Tutorial (Part 9): Introduction to Common Zero Trust Features and Usage in Multiple Scenarios.


For a home environment, the biggest change brought about by this approach is that public network access no longer depends on the availability of a public IP address. In other words, as long as the home server can access the internet normally, it can reliably provide services. At the same time, issues such as port exposure and public network scanning disappear, and the home network no longer needs to specifically adjust routing and open ports for public network access. For a video website primarily focused on display, this means that the deployment and maintenance of the entire system becomes much simpler.

In addition, Cloudflare Tunnel also solves the problem of applying for and renewing HTTPS certificates. And since all access traffic passes through the Cloudflare network, there is a foundation for subsequent improvements such as caching optimization, access acceleration, and modifications to the access process.

Therefore, in this project, the role of Cloudflare Tunnel is not simply to publish Emby to the public network. It actually serves as the unified entry point for the entire video showcase site, and many subsequent user experience optimizations are built upon this foundation.

After public network access was completed, the real problems began to emerge:How can we transform a media system designed for logged-in users into a video display site suitable for "browsing only, no operation"?

3. Optimized public network access experience

3.1 Create a new independent display instance (optional but recommended)

When using Emby as a public online video showcase site, an easily overlooked but actually crucial question is: should we directly use the existing production media library to provide access to the outside world?

From an implementation perspective, this is undoubtedly the simplest solution, as a usable display entry point can be quickly obtained by directly utilizing existing media servers. However, from a system architecture perspective, this approach essentially runs the "daily usage environment" and the "public network display environment" in the same instance. Although both use the same media library, their goals are completely different: one is for personal management and playback, while the other is for public browsing and display.

This coupling usually doesn't cause obvious problems in the short term, but with long-term exposure to the public network, it will gradually introduce some hidden risks. For example, any configuration adjustment may affect the display effect, routine maintenance operations may interfere with external access, and the display site itself cannot evolve independently in a stable and controllable environment.

Therefore, in more robust practice, a clearer approach is to deploy a separate Emby instance for presentation (Docker deployment is generally recommended), logically or physically separating it from the media server used daily. This presentation instance can share media files or only synchronize a portion of the media content. Its core purpose is not to expand functionality, but to clearly define the boundary between "daily use" and "external presentation."


If you have a large collection of film and television resources, manually creating all media libraries and rescanning them after creating a new display instance will take a lot of time (scanning just one "Western films" library, including scraping time, takes at least 1-2 days). Actually, there are techniques for quickly migrating media library data; for details, please refer to the article:Emby Series High-End: Quickly migrate media library data between new and old Emby servers.


Meanwhile, from a security perspective, this demonstration example needs to be exposed to the public network environment, and the use of default or weak password combinations for administrator accounts should be avoided as much as possible to reduce the risk of being scanned or subjected to credential stuffing attacks.

However, it should be noted that this step is not mandatory. This section is more accurately positioned as a recommended architectural isolation strategy, rather than a prerequisite.

Only after completing this selection process can we move on to the real issue of optimizing the access experience, which is how to allow visitors to enter the system itself at the lowest cost.

3.2 Guest Accounts: Lowering the Barrier to Access

When using Emby as a public video showcase site, the first problem to solve is not performance, but the access barrier itself: by default, Emby's access model is still designed around "user login". Any access must first complete account authentication (enter username/password) before entering the media library page.

However, in the context of a film and television showcase website, most visitors' behavior is very clear: they open links to browse film and television resource posters, rather than entering a complete media system. Therefore, retaining the complete login process essentially interrupts the act of "viewing content" with unnecessary steps.

To solve this problem, I created an account named "Guest/empty password" and used it as the default access point (only displaying the Guest account and hiding other accounts, including the administrator account):

image.png

The Guest account itself is also strictly limited in its permissions, with only read-only browsing capabilities enabled. It does not include playback or administrative permissions, ensuring that it is used solely as a display entry point. It's important to emphasize that using Guest here does not "cancel the login process," but rather simplifies the authentication process to the extreme: after entering the site, users only need to click the Guest login entry once to directly access the poster browsing interface, without needing to enter an account or password or perform any additional operations.


To display only the Guest account on the login screen, you need to configure the settings to hide it in other accounts:

image.png

Meanwhile, the prompt at the bottom of the interface, "Click 'guest' to log in," is set in "Settings" - "General" under "Login Disclaimer."
image.png


After the adjustment, the access path changed from the original: manually entering "username/password" to log in → entering the system → browsing content to: clicking "Guest" to log in → entering the poster wall → browsing content. Although the authentication step still exists in essence, for visitors, this step has changed from a "login process that requires understanding and entering information" to a lightweight operation of "entering with a single click." In actual experience, this difference is crucial because it directly determines whether visitors will drop off at the very first step.

Therefore, from the perspective of the overall system transformation, the Guest account is not a functional optimization, but rather the first step in transforming Emby from a "user-oriented media system" to a "browser-oriented display system".

3.3 Cloudflare Caching: Optimizing Resource Loading

After lowering the access barrier by using Guest accounts, visitors can now access Emby relatively smoothly.

However, new problems soon arise. For Emby, deployed on a home network, each public network access actually requires traversing the internet to reach the home server before returning the result. Although the latency of a single request may not be very high, Emby's web pages themselves load a large number of resources, including front-end static files, poster images, and various metadata interfaces.

In a local area network environment, these requests have almost no noticeable delay; however, when placed in a public network environment, a large number of requests are stacked together, and the page response speed will decrease significantly.

Since the entire system has been connected to Cloudflare via Cloudflare Tunnel, the most natural optimization approach is to leverage Cloudflare's edge caching capabilities to cache content with low change frequency on Cloudflare nodes as much as possible, instead of sending it back to the home server every time.

In actual configuration, I mainly use Cloudflare's Cache Rules feature (for those unfamiliar with CF cache rule configuration, please refer to previous articles:Cloudflare Tutorial (Part 6): Introduction and Detailed Configuration Tutorial for CF Cache RulesAnd a caching rule was designed based on Emby's access characteristics (taking my showcase site's domain "movie.tangwudi.com" as an example):

(http.host eq "movie.tangwudi.com" and http.request.uri.path contains "/Images/") or (http.host eq "movie.tangwudi.com" and starts_with(http.request.uri.path, "/web/")) or (http.host eq "movie.tangwudi.com" and http.request.uri.path contains "/emby/Users/") or (http.host eq "movie.tangwudi.com" and http.request.uri.path contains "/emby/Items") or (http.host eq "movie.tangwudi.com" and http.request.uri.path contains "/emby/System/")

For requests that meet the above conditions, Cloudflare Cache will be enabled directly, and the edge caching time will be set to 1 month (up to 1 year).

These paths were chosen primarily because the content they correspond to changes relatively infrequently. Specifically:

  • /Images/ It mainly includes image resources such as movie posters, background images, and actor portraits;
  • /web/ The static files corresponding to the Emby Web frontend include JavaScript, CSS, and font files;
  • /emby/Users/ It contains user-related information and changes very little in the display scenario;
  • /emby/Items It primarily provides media library metadata, such as movie titles, descriptions, and ratings;
  • /emby/System/ This includes system configuration and basic status information.

For a video website primarily focused on display, the aforementioned content often remains largely unchanged for extended periods, making it ideal for Cloudflare caching. This allows many requests to be handled directly at the Cloudflare edge nodes, eliminating the need to route them back to the home server.

From the user's perspective, the most direct change is faster poster loading speed and smoother page switching; while from the server's perspective, it reduces the extra pressure on the home network and Emby instance caused by a large number of repeated requests.

Of course, it's important to note that caching isn't suitable for all APIs. For data involving real-time status, permission checks, or frequent changes, it's still advisable to access the origin server; otherwise, the displayed content may not match the actual state.

However, for browsing-oriented scenarios like film and television showcase websites, simply caching the aforementioned paths is enough to achieve a significant improvement in the user experience.

3.4 Worker Startup Page: Refactoring the Waiting Experience (Optional but Recommended)

Actually, after versions 3.1 to 3.3, the film and television resource display site was already running normally. However, for domestic users, there is still a problem that affects the user experience: the homepage loads relatively slowly.

This is not a problem with Emby itself, but rather the result of the entire access chain working together: the user's request needs to go through the Cloudflare network first, and then be forwarded to the home server via the Tunnel. When Emby Web is opened for the first time, it also needs to load front-end resources, initialize the page, and request various media library data.

Even after caching optimization, this process cannot be completely eliminated. Especially in the domestic network environment, it is not uncommon for the first access to experience a wait of several seconds or even more than ten seconds.

From a technical perspective, this type of problem is difficult to solve. It's not that a single interface is slow; rather, it's the result of the entire access chain and the system initialization process combined. Continuing to invest significant effort in optimization often yields limited benefits.

So I changed my approach: since waiting can't be completely eliminated, could we make it more acceptable? In fact, many large websites and applications, when faced with unavoidable loading processes, don't simply shorten the time, but rather use various methods to provide feedback to the user about the current status, letting them know the system is working normally: for example, installers display progress bars, games show loading screens, and streaming media has fixed startup cutscenes, like the familiar "ding-dong" intro to Netflix movies.

image.png

Essentially, they are not solving performance problems, but rather user experience problems.

Therefore, I added a Cloudflare Worker as the splash screen before Emby (for those unfamiliar with CF worker functionality, please refer to my previous article:Cloudflare Tutorial (Part 7): Introduction to CF Worker Feature and Practical Demonstration, Verification, and Research on Related Technical Principles of Implementing a "Budget APO for WordPress" Based on Workers to Accelerate Website AccessThe original entry point for directly accessing Emby was changed to a new access address:”movie.tangwudi.com/start” .

When a user visits this address, they will not immediately enter Emby. Instead, they will first see a simple startup page that simulates the startup process of a movie and television database.

Connecting to the film and television database... Establishing a secure connection... Verifying media services... Preparing access point... Entering the film and television database...

Simultaneously, the progress bar and dynamic animation effects allow users to perceive that the system is working. After a few seconds, the Worker automatically redirects to the actual Emby login page. It should be noted that this method does not make Emby faster; from a technical perspective, it offers almost no performance optimization. However, from a user experience perspective, the two methods provide completely different experiences.

The original situation was:

Click the link ↓ A long wait on the page with the Emby icon ↓ Suspecting the website is broken ↓ The login page appears ↓ Enter Emby

The current situation is:

Click the link ↓ See the startup page ↓ Know that the system is loading ↓ The login screen appears ↓ Enter Emby

The waiting time may not have changed significantly, but users' acceptance of the wait has increased considerably. This is the most interesting aspect of this optimization: it doesn't attempt to solve a difficult performance problem, but rather improves the user's perception of the entire system by redesigning the waiting process.

Of course, this step is not mandatory. Even without adding a Worker launcher, the optimizations already completed are sufficient to support a fully functional video showcase website.

However, if your main visitors are also domestic users and you care about the experience when visiting for the first time, then adding such a lightweight startup layer can often bring more significant improvement than continuing to tweak performance parameters.

I've also pasted the worker's JavaScript code here; those who are interested can take a look:

export default {
  async fetch(request) {
    const url = new URL(request.url);

    if (url.pathname !== "/start") {
      return fetch(request);
    }

    return new Response(`<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>正在连接影视资料库</title>

<style>
html,body{
    margin:0;
    width:100%;
    height:100%;
    background:#050505;
    color:#ffffff;
    overflow:hidden;
    font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;
}

.container{
    height:100%;
    display:flex;
    flex-direction:column;
    justify-content:center;
    align-items:center;
    text-align:center;
}

.logo{
    font-size:40px;
    letter-spacing:6px;
    margin-bottom:40px;
    opacity:.95;
}

.status{
    font-size:16px;
    opacity:.85;
    margin-bottom:22px;
    min-height:24px;
}

.progress-wrap{
    width:320px;
    max-width:80vw;
}

.progress{
    height:8px;
    border-radius:999px;
    background:#1f1f1f;
    overflow:hidden;
}

.bar{
    width:0%;
    height:100%;
    background:#ffffff;
    transition:width .5s ease;
}

.percent{
    margin-top:12px;
    font-size:13px;
    opacity:.65;
}

.footer{
    position:absolute;
    bottom:40px;
    font-size:12px;
    opacity:.3;
    letter-spacing:2px;
}

.fadeout{
    animation:fadeout .8s forwards;
}

@keyframes fadeout{
    from{opacity:1;}
    to{opacity:0;}
}
</style>
</head>

<body>

<div class="container">
    <div class="logo">MOVIE LIBRARY</div>

    <div class="status" id="status">
        正在连接影视资料库...
    </div>

    <div class="progress-wrap">
        <div class="progress">
            <div class="bar" id="bar"></div>
        </div>
        <div class="percent" id="percent">0%</div>
    </div>
</div>

<div class="footer">
    TANGWUDI MOVIE COLLECTION
</div>

<script>
const statusEl = document.getElementById("status");
const bar = document.getElementById("bar");
const percent = document.getElementById("percent");

const steps = [
    { text: "连接影视资料库...", progress: 18 },
    { text: "建立安全连接...", progress: 38 },
    { text: "验证媒体服务...", progress: 62 },
    { text: "准备访问入口...", progress: 85 },
    { text: "正在进入影视库...", progress: 100 }
];

const totalTime = 6000 + Math.random() * 2000;

let index = 0;

function nextStep() {
    if (index >= steps.length) {
        document.body.classList.add("fadeout");

        setTimeout(() => {
            location.href =
                "/web/index.html#!/startup/login.html?serverId=d2f780f97e4d4f39928b1b1f97d3ca7f";
        }, 800);

        return;
    }

    const step = steps[index];

    statusEl.textContent = step.text;
    bar.style.width = step.progress + "%";
    percent.textContent = step.progress + "%";

    index++;

    setTimeout(nextStep, totalTime / steps.length);
}

nextStep();
</script>

</body>
</html>`, {
      headers: {
        "content-type": "text/html;charset=UTF-8",
        "cache-control": "no-store"
      }
    });
  }
};

You can experience the final result by visiting the following link:”https://movie.tangwudi.com/start”"”

Note: I update this showcase site about once a year, and only the "Western Films", "Asian Films", and "Western Retro Films" sections. I'm too lazy to update the others; it's too much of a waste of time.

4. Afterword

Although the previous modifications have resulted in a basic framework for showcasing film and television resources based on Emby, meeting daily display needs in terms of public network publishing, access barriers, and loading experience, I do not believe this will be the final solution from a long-term development perspective.

The reason is actually quite simple: Emby is ultimately a media server. Even though many issues have been resolved through Guest accounts, Cloudflare caching, and Worker launchers, it's still essentially about adapting to a system originally designed for media management. In other words, all the previous optimizations are actually doing the same thing: making Emby as suitable as possible for use as a video showcase site.

However, from another perspective, a website truly designed for showcasing content shouldn't involve Emby at all. For a showcase site, what we really need are metadata such as film titles, release years, ratings, synopses, actor information, poster images, and category tags. This content already exists in Emby's database. Theoretically, as long as this data can be exported via API, along with resources like poster images, all the basic requirements for building an independent showcase site are already met.

Therefore, a more ideal architecture might be: Emby only manages the media library and maintains metadata, while the website itself is completely static. The website no longer depends on Emby at runtime, nor does it need to go back to the home server via Tunnel. All pages, data, and image resources are deployed directly to a static hosting platform, distributed by a CDN. This not only results in faster access speeds but also a much simpler overall architecture.

In fact, while working on this showcase site, I had already started considering this direction and spent a considerable amount of time searching for ready-made solutions online. Unfortunately, I found almost no mature static showcase projects in the Emby, Jellyfin, or Plex communities. Most discussions focused on the media server itself, rather than how to export the entire media library as a standalone static website. This also means that if I really want to continue in this direction, I will most likely have to develop it from scratch in the end.

However, after actually starting the analysis, I realized that this matter was not as simple as I had initially imagined. Taking my current collection of 20,000 movies as an example, just generating an index file containing movie information required careful consideration of data structure design. How to synchronize poster images, how to organize resources, how to incrementally update data, how to implement search functionality, and how to efficiently render tens of thousands of records in the browser—all of these required separate design.

Especially at the front-end presentation level, if you want to achieve a browsing experience similar to Netflix or Emby's poster wall, you must consider technologies such as virtual scrolling; otherwise, the browser can easily experience performance issues due to rendering too much content at once. Similarly, the search function cannot simply rely on backend interfaces, because static sites do not have traditional database query capabilities. This means that a local index needs to be built on the browser side to perform searches directly through JavaScript.

Individually, these problems aren't particularly complex, but when combined, they approach the scale of a small project. I even feel like I'm being forced to learn front-end frameworks. Therefore, this project remains in the planning stage and hasn't officially started.

However, at present, the solution introduced in this article is sufficient to meet the needs of most users for displaying film and television resources, while the static display site seems to be a gap that will be gradually filled in the next stage. If this system is indeed completed in the future, then Emby's role in the overall architecture may change—it will no longer be the website itself, but merely the data source behind the website.

As for when this problem will be solved, I can't say for sure right now. However, for personal projects, it's often not necessary to have a final form from the start. Getting it running first, making sure it solves the immediate problem, and then continuously adjusting and evolving it during actual use is often a more realistic approach.

At least until a static version is truly implemented, the solution described in this article is enough for me to showcase my film and television collection to more people.

📌 Content Structure Hints:
This content belongs to "Cloudflare Learning MapThis is part of the document; you can view the full content path here: Cloudflare Learning Map .
Share this article
All blog content is original; please indicate the source when reprinting! The blog's RSS address is:https://blog.tangwudi.com/feed, welcome to subscribe; if necessary, you can joinTelegram GroupDiscuss the problem together.
No Comments

Send Comment Edit Comment


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠(ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ°Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
Emoticons
Emoji
Little Dinosaur
flower!
Previous