Media & Entertainment AWS

ErsatzTV on AWS User Guide

ErsatzTV on AWS

This image delivers ErsatzTV 26.6.0, the open source self-hosted IPTV server, fully installed, secured and reverse-proxied with nginx. ErsatzTV turns your own local media - movies, shows and music videos you supply - into live, always-on television channels that play on a schedule you define, then streams those channels over HLS and MPEG-TS. It emulates an HDHomeRun network tuner and publishes an M3U playlist and an XMLTV electronic programme guide, so Plex, Jellyfin, Emby and other IPTV clients can add it as a live-TV source and browse a proper channel guide.

ErsatzTV is a self-contained .NET application running under systemd as a dedicated unprivileged ersatztv service account, with all state (its SQLite database, configuration and transcode scratch) under /var/lib/ersatztv. Media transcoding uses a clean, redistributable GPL FFmpeg 7.x build baked into the image, with the H.264 (libx264) and AAC encoders ErsatzTV needs.

You supply the media. This image ships ErsatzTV on its own, with no media of any kind. You add your own content and you are responsible for holding the rights to stream it. Use ErsatzTV only with media you are lawfully entitled to use.

The ErsatzTV web admin dashboard, served through the nginx reverse proxy on port 80

Secure by default

ErsatzTV has no built-in authentication on its management interface, and its internal web server binds all interfaces. A bare deployment therefore leaves an unauthenticated admin UI reachable on the network - anyone who can reach it gets full control of your channels and libraries. This image never ships in that state:

  • ErsatzTV listens only on the loopback interface (management port 8409, streaming port 8410), enforced by a host firewall (nftables) that drops any off-loopback access to those ports.
  • An nginx reverse proxy on port 80 is the only public door. The admin UI and REST API are protected by HTTP Basic Auth.
  • A unique administrator password is generated on each instance's first boot, bcrypt-hashed for nginx, with the plaintext written only to a root-only file. No shared or default password ships in the image, and nginx is not started until that password is in place - so there is never a window where an unauthenticated admin UI is exposed.
  • The IPTV client endpoints stay open without a password (the tuner, the M3U playlist and the XMLTV guide), so Plex, Jellyfin and Emby keep working, while the admin interface stays protected.
  • An unauthenticated /healthz endpoint is provided for load-balancer probes.

Because the endpoints split this way, open only ports 22 and 80 (and optionally 443 for TLS) in your security group. Never expose 8409 or 8410.

Connecting to your instance

SSH in as the default login user for your OS variant:

OS variant SSH login user
Ubuntu 24.04 ubuntu
ssh ubuntu@<public-ip>

Retrieve the generated administrator password (readable only by root):

sudo cat /root/ersatztv-credentials.txt

You will see the per-instance credentials and the endpoint URLs, for example:

ERSATZTV_URL=http://203.0.113.10/
ERSATZTV_USERNAME=admin
ERSATZTV_PASSWORD=xxxxxxxxxxxxxxxxxxxxxxxx

Open ERSATZTV_URL in a browser and sign in as admin with that password to reach the ErsatzTV web admin UI.

Verifying the deployment

Confirm the services are active:

systemctl is-active ersatztv.service nginx.service ersatztv-firewall.service

All three report active. Confirm the unauthenticated health endpoint answers:

curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/healthz

This returns 200. The admin UI, by contrast, is refused without the password:

curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/

This returns 401 - proof the admin interface is gated.

The IPTV endpoints (tuner, M3U and XMLTV)

ErsatzTV publishes an HDHomeRun tuner plus an M3U playlist and an XMLTV guide. These are served without a password so your players can consume them. Fetch the playlist:

curl -s http://127.0.0.1/iptv/channels.m3u | head -3

Out of the box ErsatzTV publishes a single built-in channel until you create your own:

#EXTM3U url-tvg="http://127.0.0.1/iptv/xmltv.xml" x-tvg-url="http://127.0.0.1/iptv/xmltv.xml"
#EXTINF:0 tvg-id="C1.145.ersatztv.org" channel-number="1" tvg-chno="1" tvg-name="ErsatzTV" group-title="ErsatzTV", ErsatzTV
http://127.0.0.1/iptv/channel/1.ts

The matching guide data is at the XMLTV endpoint:

curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/iptv/xmltv.xml

This returns 200. From your own network, point your IPTV client at the same host using the instance's address:

  • HDHomeRun tuner / device: http://<public-ip>/
  • M3U playlist: http://<public-ip>/iptv/channels.m3u
  • XMLTV guide: http://<public-ip>/iptv/xmltv.xml

Adding your media and building a channel

  1. In the ErsatzTV UI, open Media Sources -> Local and add a library that points at a folder of your own media (copy or mount your content onto the instance first, for example under /srv/media, and make sure the ersatztv user can read it). ErsatzTV scans the folder and imports the items.
  2. Open Channels and choose Add Channel. Give the channel a number and a name and pick the FFmpeg profile (a default 1920x1080 x264 aac profile ships with the image).

The Channels view, where you build and organise your live TV channels

Building a channel: give it a number and name, then schedule your own media

  1. Use Lists (collections) and Scheduling to decide what plays on the channel and in what order, then build the channel's playout.
  2. Your new channel now appears in the M3U playlist and XMLTV guide automatically, ready for your IPTV clients.

The image ships a clean, redistributable GPL FFmpeg 7.x build; the default transcode profile streams H.264 video with AAC audio.

The FFmpeg transcode profile used to stream channels

Connecting Plex, Jellyfin or Emby

In your media server's Live TV / DVR setup, add an HDHomeRun tuner and point it at http://<public-ip>/, then supply the XMLTV guide URL http://<public-ip>/iptv/xmltv.xml. Plex, Jellyfin and Emby all consume ErsatzTV this way - your ErsatzTV channels then appear in the client's live TV guide alongside any other tuners.

Enabling HTTPS (recommended for production)

The image serves the admin UI and IPTV surface over HTTP on port 80. For production, terminate TLS in front of ErsatzTV. Two common options:

  • AWS load balancer / CloudFront - put an Application Load Balancer or CloudFront distribution in front of the instance and attach an ACM certificate; forward to the instance on port 80.
  • Let's Encrypt on the instance - point a DNS name at the instance, open port 443 in the security group, then:
sudo apt-get update && sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d your-domain.example.com

certbot obtains a certificate and reconfigures nginx to serve the admin UI and IPTV endpoints over HTTPS.

Service management

ErsatzTV and its reverse proxy are ordinary systemd services:

systemctl status ersatztv.service
sudo systemctl restart nginx.service

Configuration and data live under /var/lib/ersatztv (SQLite database, config and transcode scratch); the nginx site is at /etc/nginx/sites-available/cloudimg-ersatztv. The loopback firewall guard is ersatztv-firewall.service.

Support

cloudimg provides 24/7 technical support for this product by email and live chat at support@cloudimg.co.uk. We can help with deployment, connecting media libraries, building channels and schedules, ffmpeg transcoding, TLS termination and integrating Plex, Jellyfin and Emby.