Jellyfin is a free, open source media server that streams your movies, TV shows, music and photos to web browsers, phones, TVs and desktop apps, with no accounts or subscriptions tied to a third party. In this tutorial you will install Jellyfin on Ubuntu 24.04 from the official Jellyfin repository, prepare a media directory with the right permissions, complete the setup wizard safely and publish the server over HTTPS through Nginx and Let's Encrypt.

Prerequisites

To follow this guide you need:

  • A server running Ubuntu 24.04 LTS (x86_64 or arm64), for example a CubePath VPS, with at least 2 GB of RAM. Plan for 4 GB or more if clients will need transcoding.
  • A non-root user with sudo privileges.
  • Enough disk space for your media library.
  • A domain or subdomain (this guide uses your_domain) with a DNS A record pointing to your_server_ip. This is needed for HTTPS in Step 5.

Step 1 - Adding the Jellyfin repository

Ubuntu does not ship Jellyfin in its own archive, so you will add the official repository. It also provides jellyfin-ffmpeg, a build of FFmpeg patched for Jellyfin's transcoding needs.

Install the tools needed to download and store the signing key:

sudo apt update
sudo apt install -y curl gnupg

Download the Jellyfin signing key into /etc/apt/keyrings:

sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://repo.jellyfin.org/jellyfin_team.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/jellyfin.gpg

Create the repository definition in the deb822 format used by Ubuntu 24.04:

sudo nano /etc/apt/sources.list.d/jellyfin.sources

Add the following content. If your server is arm64, replace amd64 with arm64 (you can check with dpkg --print-architecture):

Types: deb
URIs: https://repo.jellyfin.org/ubuntu
Suites: noble
Components: main
Architectures: amd64
Signed-By: /etc/apt/keyrings/jellyfin.gpg

Refresh the package index and confirm that the jellyfin package now comes from the new repository:

sudo apt update
apt policy jellyfin
jellyfin:
  Installed: (none)
  Candidate: 10.x.x+ubu2404
  Version table:
     10.x.x+ubu2404 500
        500 https://repo.jellyfin.org/ubuntu noble/main amd64 Packages

Step 2 - Installing Jellyfin

Install the jellyfin metapackage. It pulls in the server, the web client and jellyfin-ffmpeg:

sudo apt install -y jellyfin

The package creates a jellyfin system user and a systemd service. Make sure it is enabled and running:

sudo systemctl enable --now jellyfin
systemctl status jellyfin --no-pager
● jellyfin.service - Jellyfin Media Server
     Loaded: loaded (/usr/lib/systemd/system/jellyfin.service; enabled; preset: enabled)
     Active: active (running) since ...

Jellyfin listens on port 8096. Query its health endpoint locally:

curl http://localhost:8096/health
Healthy

The main locations to remember are /etc/jellyfin (configuration), /var/lib/jellyfin (database and metadata) and /var/log/jellyfin (logs).

Step 3 - Preparing the media directories

Jellyfin runs as the jellyfin user, so it needs read access to your media. A clean approach is to keep your own user as the owner of the files and give the jellyfin group read access.

Create a directory tree for your libraries:

sudo mkdir -p /srv/media/{movies,shows,music}

Give ownership to your user and the jellyfin group, grant the group read access, and set the setgid bit on directories so new files inherit the group:

sudo chown -R "$USER":jellyfin /srv/media
sudo chmod -R u=rwX,g=rX,o= /srv/media
sudo find /srv/media -type d -exec chmod g+s {} +

Check that the jellyfin user can list the directories:

sudo -u jellyfin ls -la /srv/media
drwxr-s--- 2 your_user jellyfin 4096 ... movies
drwxr-s--- 2 your_user jellyfin 4096 ... music
drwxr-s--- 2 your_user jellyfin 4096 ... shows

Jellyfin identifies titles by their folder and file names, so follow its naming conventions when you upload media:

/srv/media/movies/Blade Runner (1982)/Blade Runner (1982).mkv
/srv/media/shows/The Expanse (2015)/Season 01/The Expanse S01E01.mkv
/srv/media/music/Artist Name/Album Name/01 - Track Name.flac

You can copy files from your computer with rsync or scp, for example rsync -avP ./Movies/ your_user@your_server_ip:/srv/media/movies/.

Step 4 - Running the setup wizard through an SSH tunnel

The first visitor to a new Jellyfin server can create the administrator account, so do not expose port 8096 to the internet before finishing the wizard. Instead, open an SSH tunnel from your local computer:

ssh -L 8096:localhost:8096 your_user@your_server_ip

Leave that session open and browse to http://localhost:8096 on your computer. The wizard asks you to:

  1. Choose the display language.
  2. Create the administrator user with a strong password.
  3. Add media libraries. Pick a content type (Movies, Shows, Music) and add the matching folder, such as /srv/media/movies.
  4. Choose the metadata language and country.
  5. Keep Allow remote connections to this Jellyfin server enabled, since the reverse proxy will connect to it.

After the wizard, sign in and open Dashboard > Libraries. Jellyfin scans each library when it is added; the scan progress appears in the dashboard, and your titles show up on the home screen when it finishes.

Step 5 - Publishing Jellyfin over HTTPS with Nginx

Nginx will terminate TLS and forward requests to Jellyfin on localhost:8096, so port 8096 never has to be opened in the firewall.

Install Nginx and Certbot:

sudo apt install -y nginx certbot python3-certbot-nginx

Allow SSH and web traffic through UFW and enable the firewall:

sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable

Create a server block for Jellyfin:

sudo nano /etc/nginx/sites-available/jellyfin

Add the following, replacing your_domain with your domain:

server {
    listen 80;
    listen [::]:80;
    server_name your_domain;

    client_max_body_size 20M;

    location / {
        proxy_pass http://127.0.0.1:8096;
        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 X-Forwarded-Host $http_host;

        # WebSocket support for live updates and remote control
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        # Stream media without buffering it in Nginx
        proxy_buffering off;
    }
}

Enable the site, test the configuration and reload Nginx:

sudo ln -s /etc/nginx/sites-available/jellyfin /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Request a Let's Encrypt certificate. Certbot edits the server block to add the 443 listener and an HTTP to HTTPS redirect:

sudo certbot --nginx -d your_domain

Finally, tell Jellyfin to trust the proxy so it logs the real client IP addresses. In the web interface go to Dashboard > Networking, add 127.0.0.1 to Known proxies and save. Restart the service to apply it:

sudo systemctl restart jellyfin

Open https://your_domain in your browser. You should see the Jellyfin sign-in page with a valid certificate.

Step 6 - Adding users and connecting clients

Create one account per person instead of sharing the administrator login. Go to Dashboard > Users, click +, set a username and password, and choose which libraries the user can access. On the same page you can limit the remote streaming bitrate per user, which is useful when your server's upload bandwidth is limited.

Official clients are available for Android, Android TV, iOS, and desktop (Jellyfin Media Player), and there are community clients for Roku, Kodi and others. In any of them, enter https://your_domain as the server address and sign in with the user you created.

Step 7 - Enabling hardware transcoding (optional)

When a client cannot play a file's codec or bitrate directly, Jellyfin transcodes it. On a CPU-only VPS this works, but it is expensive: keep media in widely supported formats (H.264 video with AAC audio) so most clients use direct play. If your server has an Intel GPU (common on dedicated servers), you can offload transcoding to it with VA-API.

Check that a render device exists:

ls -l /dev/dri
crw-rw---- 1 root video  226,   0 ... card0
crw-rw---- 1 root render 226, 128 ... renderD128

Add the jellyfin user to the render group and restart the service:

sudo usermod -aG render jellyfin
sudo systemctl restart jellyfin

Confirm that the VA-API driver bundled with jellyfin-ffmpeg can open the device as the jellyfin user:

sudo -u jellyfin /usr/lib/jellyfin-ffmpeg/vainfo --display drm --device /dev/dri/renderD128

The output should list supported profiles such as VAProfileH264Main : VAEntrypointEncSlice. Then go to Dashboard > Playback > Transcoding, select Intel QuickSync (QSV) or Video Acceleration API (VAAPI) as hardware acceleration, set the device to /dev/dri/renderD128, tick the codecs your GPU can decode and save.

Troubleshooting

A library stays empty after the scan. The jellyfin user usually cannot read the files. Test with sudo -u jellyfin ls /srv/media/movies. If it fails, repeat the permission commands from Step 3, because files uploaded later may have kept a different group. Also check that the names follow the conventions shown above.

502 Bad Gateway from Nginx. Jellyfin is not running or not listening on 8096. Check systemctl status jellyfin and the logs with sudo journalctl -u jellyfin -n 50.

Playback buffers or stops on remote clients. Open Dashboard > Activity or the active session info to see whether the stream is being transcoded. If it is, lower the user's maximum streaming bitrate or convert the file to H.264/AAC ahead of time. The FFmpeg logs for each transcode are in /var/log/jellyfin.

Conclusion

You now have Jellyfin running on Ubuntu 24.04 from the official repository, serving organized libraries over HTTPS through Nginx, with per-user accounts for your clients. As next steps, consider mounting a separate block storage volume under /srv/media for larger libraries, installing plugins such as Open Subtitles from Dashboard > Plugins > Catalog, and backing up /etc/jellyfin and /var/lib/jellyfin so you can restore users and metadata.