Skip to content
Murali Krishnan A
All writing

14 Sept 2026

Jellyfin from scratch, part 1: a media server on a $10 Lightsail box

The first of a five-part guide to running your own Jellyfin server and wiring a Telegram bot into it. This part covers what Jellyfin is, setting up an Ubuntu instance on Amazon Lightsail, installing Jellyfin, opening the right ports, and getting through the first-run wizard.

7 min read · jellyfin, selfhosted, telegram, beginners

This is part 1 of a five-part guide to running Jellyfin on your own server and connecting it to a Telegram bot. Later parts cover getting a real domain and HTTPS, setting up the Telegram side, the script that ties them together, and keeping all of it running after a reboot.

I keep my movie collection - my own recordings, my own rips of discs I own, a few things shot on my phone that are too big for anyone's cloud photo tier - on a tiny Ubuntu box that costs ten dollars a month and runs Jellyfin. This series is what I did to get there, written the way I wish someone had written it for me: one server, one bot token, one working setup by the end of part 4, and a way to keep it alive by the end of part 5.

What Jellyfin actually is

Jellyfin is a free, open-source media server. You point it at a folder of video files, it reads their names and matches them against a metadata provider to get posters, descriptions and episode numbers, and it serves the result as a proper app - on your phone, your TV, a browser, whatever - instead of a folder of files you have to guess the names of.

The part that matters for this series: Jellyfin has an HTTP API. Every button in its web interface is a request to that API, including "rescan this folder for new files," which is the one this whole series is really about. A Telegram bot that can call one URL is enough to make your media server notice a file the moment it arrives.

Setting up the Lightsail instance

Amazon Lightsail is AWS with the complexity sanded off: fixed monthly pricing, a plain "create instance" button, no VPC configuration to get right before anything works.

  1. In the Lightsail console, Create instance.
  2. Platform: Linux/Unix. Blueprint: OS Only → Ubuntu 24.04 LTS.
  3. Instance plan: the $10/month tier (2 GB RAM, 2 vCPUs, 60 GB SSD) is the realistic minimum. Jellyfin itself is light. What eats memory and CPU is transcoding - converting a file on the fly because the device asking for it can't play the format directly. More on that in a moment.
  4. Name it something you'll recognize later, and create it.

Once it's running, go to the Networking tab and attach a static IP. Free while attached to a running instance, and it means the address you configure everywhere else - DNS, the bot script, your own bookmarks - doesn't change the next time the instance restarts.

Opening the firewall

Lightsail has two firewalls, and missing this is the single most common reason "I installed it and can't reach it" happens.

The first is the box's own, ufw, which we'll leave alone for now. The second is Lightsail's own firewall, sitting in front of the instance entirely, on the same Networking tab as the static IP. By default it allows SSH (port 22) and nothing else. Add a rule for Custom → TCP → 8096, which is Jellyfin's default port. Firewalls at this layer block a port silently - no connection refused, just nothing, which is a uniquely confusing way for a beginner's first request to fail.

Installing Jellyfin

SSH into the instance - Lightsail gives you a browser-based terminal if you don't want to set up a key locally - and run the official install script:

curl https://repo.jellyfin.org/install-debuntu.sh | sudo bash

This adds Jellyfin's own apt repository and signing key, then installs three packages: jellyfin-server, jellyfin-web, and jellyfin-ffmpeg, which is a build of ffmpeg pinned to a version Jellyfin has actually tested transcoding against, rather than whatever your distro happens to ship.

Check it came up:

$ systemctl status jellyfin
● jellyfin.service - Jellyfin Media Server
     Active: active (running)

It's listening on port 8096 already, on all interfaces, no extra config needed. Open http://<your-static-ip>:8096 in a browser.

The first-run wizard

Five short screens, in order.

Jellyfin first-run wizard asking for a server name and preferred display language
Screen one: a server name and a language. The server name is cosmetic - it's what shows up in your app list, not a hostname.
  1. Language. Cosmetic, changes only.

  2. Create the admin user. This is your Jellyfin login, unrelated to your Ubuntu login on the box itself. Use a real password - it's about to be reachable from the internet.

    Jellyfin wizard screen for creating the admin username and password
    This account logs into the web UI and the dashboard. It has nothing to do with the ubuntu Linux user the bot script runs as in part 4.
  3. Add a media library. Choose a content type (Movies, Shows, Home Videos - whichever fits), give it a display name, and point it at a folder. I use /home/ubuntu/files/ott, because it's also the folder the bot in part 4 saves into - decide yours now and it saves a rename later.

    sudo mkdir -p /home/ubuntu/files/ott
    sudo chown ubuntu:ubuntu /home/ubuntu/files/ott
    The Add Media Library dialog with fields for content type, display name and folders
    Content type changes which metadata provider Jellyfin queries - Movies asks a different database than Home Videos does.
  4. Metadata language and country. Affects which posters and descriptions it fetches. Leave the defaults unless you know you want otherwise.

  5. Remote access. Leave "allow remote connections" on - that's the entire point of running this on a server instead of a laptop.

    Jellyfin wizard screen with a checkbox for allowing remote connections to the server
    Leave this checked. It only controls whether Jellyfin itself will answer non-local requests - the actual gatekeeping is the firewall rule from earlier.
Jellyfin wizard final screen reading You're Done, with a Finish button
Finish drops you at the login screen, then the dashboard - the same login screen the bot's API key gets created from in part 4.

Finish the wizard and you're looking at an empty library, because the folder is empty. Drop one file into /home/ubuntu/files/ott over scp and refresh the library from the dashboard (Dashboard → Libraries → ⋮ → Scan Library) to confirm the whole pipeline - folder, scan, metadata, playback - actually works before you build anything on top of it.

scp your-file.mp4 ubuntu@<your-static-ip>:/home/ubuntu/files/ott/

If it shows up with a poster within a minute or two of a manual scan, the server half of this series is done.

What people get wrong on day one

Next in the series

Part 2 replaces the IP address and plain HTTP with a real domain name and automatic HTTPS, using a two-line config file and a reverse proxy called Caddy.