ErsatzTV 26.11.6
Overview
ErsatzTV is a free, self-hosted server (Zlib licence) that turns the films, shows, music videos and other media you own into live, scheduled TV channels. You build channels and schedules in its web interface. ErsatzTV then plays them out around the clock as an IPTV playlist (M3U) with a programme guide (XMLTV), and as an emulated HDHomeRun tuner, so Plex, Jellyfin, Emby, VLC, TiviMate and other IPTV players can watch them like broadcast TV. Media can come from local folders or from Plex, Jellyfin and Emby servers you connect.
This guide covers launching and verifying ErsatzTV 26.11.6 on Ubuntu 24.04 from SecureAnyCloud on Amazon EC2. It is one software version of the SecureAnyCloud Hardened SRS Streaming Media Server & Media Servers AMIs listing on AWS Marketplace, which you select when you subscribe and launch. The other media and streaming products in the listing are described on the listing's guide hub.
What you get:
- ErsatzTV 26.11.6, the upstream self-contained Linux release (the .NET 10.0.14 runtime is inside it), checked against a pinned SHA-256, in
/opt/ersatztv - The ErsatzTV "Next" streaming engine (ersatztv-channel 0.2.4), rebuilt by SecureAnyCloud from the same upstream source with newer patch releases of its TLS and networking libraries
- FFmpeg 8.1.3 (the upstream static GPL build, no non-free codecs) as the transcoder, at
/usr/local/bin/ffmpegand/usr/local/bin/ffprobe - ErsatzTV listening only behind nginx serving HTTPS on port 443 with a certificate created on your instance; port 80 redirects to HTTPS
- A per-instance administrator login and a per-instance secret IPTV address, both created on first boot
ersatztv-set-hostname(serve ErsatzTV under your own DNS name),ersatztv-iptv-url(show or replace the IPTV address) andersatztv-selftest(an end-to-end check)
Default user: ubuntu. Architecture: x86_64. Root volume: 16 GiB gp3.
Security posture
- No open default. Upstream, ErsatzTV has no accounts of its own, so anyone who can reach its port controls it. On this image, nginx puts a sign-in in front of every page, the REST API, and the standard IPTV and HDHomeRun addresses. The only login is the administrator account
admin. Your instance generates its 32-character password at first boot, and nginx stores it only as a bcrypt hash. - A secret address for players that cannot sign in. Many IPTV players cannot send a user name and password. For them, the playlist, guide, streams and HDHomeRun endpoints are also served under
https://<host>/tv-<token>/, where the token is 128 random bits created on your instance. Nothing else is reachable under it, and any other path under/tv-answers 404. nginx never writes the address to its access or error log, andsudo ersatztv-iptv-url --rotatereplaces it. - The REST API needs two secrets.
/api/requires the administrator login and ErsatzTV's own API key, which ErsatzTV generates on your instance's first start. - Per-instance secrets. The administrator password, the IPTV token, ErsatzTV's database, API key and data-protection keys, and the TLS key are all created on your instance. The image ships without a database, so no two instances share a secret or a session.
- Fails closed. ErsatzTV listens on ports 8409 and 8410 on every address, because upstream has no option to bind loopback only. A firewall table (
inet ersatztv_guard, nftables) drops every packet to those ports that does not come from the instance itself.ersatztv.servicewill not start without the table, and nginx will not start until first boot has created the login and the certificate. - HTTPS from first boot. nginx serves TLS 1.2 and 1.3 with a self-signed certificate created on your instance and refuses TLS 1.1. It marks cookies
Secureand sendsStrict-Transport-Security. - The host name comes from configuration, never from a request. First boot reads the instance's public DNS name (or, failing that, its public or private IPv4 address) from EC2 instance metadata (IMDSv2) and pins nginx to it. nginx closes the connection for requests to any other host name, and redirects requests to the instance's IP addresses to the pinned name. nginx hands ErsatzTV only the configured name,
httpsand the real peer address. It drops client forwarding headers and the sign-in header, refuses ErsatzTV's/internalpaths, and refuses cross-site state changes and WebSocket upgrades. - The app cannot read instance metadata. systemd
IPAddressDenyblocks ErsatzTV, the first-boot unit and nginx from the instance metadata service (169.254.169.254, fd00:ec2::254). Only the small unit that looks up the host name at first boot may use it. - Sandboxed. ErsatzTV runs as the unprivileged
ersatztvuser with a read-only system, no access to home directories, no new privileges, no devices and no capabilities. It can write only to/var/lib/ersatztv. - Dependencies. At build time the .NET runtime, all 132 NuGet packages (including transitive ones) and the bundled JavaScript libraries were checked against the OSV vulnerability database with no advisory found. ErsatzTV 26.11.6 includes the upstream fix for GHSA-qrh2-626h-76m2. Notes are in
/opt/ersatztv/SECURITY-NOTES.txt. - No outbound calls of its own. ErsatzTV sends no telemetry and has no auto-update. Its home page shows release notes fetched from GitHub, and it contacts the Plex, Jellyfin or Emby servers you connect.
- Hardened SSH and system. SSH allows keys only, no root login and no X11 forwarding. The AMI requires IMDSv2. SSH host keys and the machine ID are generated fresh on every instance. Only Ubuntu's own package archives are configured.
Prerequisites
- An AWS account and permission to launch EC2 instances
- An EC2 key pair in the Region you launch in
- Your media (video files, or a Plex, Jellyfin or Emby server ErsatzTV can reach)
Recommended instance type: m5.large. ErsatzTV itself is light, and transcoding is the main load. FFmpeg starts on demand for each channel being watched, and a 1080p H.264 stream transcoded on the CPU uses most of a vCPU. For several simultaneous channels, choose a larger instance, for example m5.xlarge or a compute-optimized c5 type.
Keep media on a separate EBS volume (Step 8) rather than the 16 GiB root volume.
Connecting to your instance
Version Operating system SSH user
ErsatzTV 26.11.6 on Ubuntu 24.04 Ubuntu 24.04 LTS ubuntu
Launch the instance
Option A: AWS Marketplace console
- Open the SecureAnyCloud Hardened SRS Streaming Media Server & Media Servers AMIs listing on AWS Marketplace and choose View purchase options, then Subscribe. One subscription covers every version in the listing.
- Once the subscription is active, choose Launch your software.
- Choose One-click launch from AWS Marketplace (or Launch from EC2 Console for the full launch wizard). In Version, choose ErsatzTV 26.11.6 on Ubuntu 24.04, then choose your Region.
- Pick an instance type (
m5.largerecommended; the software charge is $0.04 per vCPU per hour) and your key pair. - Security group: the listing's default group opens SSH (22), HTTP (80) and HTTPS (443). Restrict SSH to your own IP address, and restrict 80 and 443 to the networks your viewers and media servers use. Do not open 8409 or 8410.
- Choose your VPC and subnet, leave the metadata defaults (the image already requires IMDSv2), then choose Launch.
Option B: AWS CLI
Run the command below on your own workstation. Replace the AMI ID with the one shown for your Region on the Marketplace launch page, and replace the VPC, subnet, key pair and CIDRs with your own:
SG=$(aws ec2 create-security-group --group-name ersatztv \
--description "ErsatzTV live channels" --vpc-id vpc-0123456789abcdef0 \
--query GroupId --output text)
aws ec2 authorize-security-group-ingress --group-id "$SG" --protocol tcp --port 22 --cidr <your-mgmt-cidr>
aws ec2 authorize-security-group-ingress --group-id "$SG" --protocol tcp --port 443 --cidr <your-viewer-cidr>
aws ec2 authorize-security-group-ingress --group-id "$SG" --protocol tcp --port 80 --cidr <your-viewer-cidr>
aws ec2 run-instances \
--image-id ami-0123456789abcdef0 \
--instance-type m5.large \
--key-name my-key-pair \
--security-group-ids "$SG" \
--subnet-id subnet-0123456789abcdef0 \
--block-device-mappings 'DeviceName=/dev/sdf,Ebs={VolumeSize=500,VolumeType=gp3}' \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=ersatztv}]'The block device mapping adds an empty 500 GiB volume for your media (Step 8). Leave it out if your media lives on a Plex, Jellyfin or Emby server. You do not need --metadata-options, because the AMI already requires IMDSv2. Associate an Elastic IP if you want the address to survive a stop and start.
Connect and find your login
Connect as ubuntu with the key pair you chose:
ssh -i ~/.ssh/my-key-pair.pem ubuntu@<public-ip>First boot takes about a minute after the instance starts. It sets the name ErsatzTV is served on (the instance's public DNS name when it has one) and creates the TLS certificate. It lets ErsatzTV create its database and keys, creates the administrator login and the IPTV token, and writes /var/lib/sac/data/ersatztv-credentials.txt (mode 0600, root).
The entries in that file are listed below. The secret values are not shown here.
sudo grep -E '^(ERSATZTV_URL|ADMIN_USERNAME)=' /var/lib/sac/data/ersatztv-credentials.txt
sudo grep -oE '^[A-Z_]+=' /var/lib/sac/data/ersatztv-credentials.txt
sudo stat -c '%a %U:%G %n' /var/lib/sac/data/ersatztv-credentials.txtERSATZTV_URL=https://ec2-44-203-152-239.compute-1.amazonaws.com/ ADMIN_USERNAME=admin ERSATZTV_URL= ADMIN_USERNAME= ADMIN_PASSWORD= <set-at-first-boot>= IPTV_GUIDE_URL= 600 root:root /var/lib/sac/data/ersatztv-credentials.txtValue What it is for
ERSATZTV_URL The address of this instance's ErsatzTV web interface
ADMIN_USERNAME The administrator's user name (admin)
ADMIN_PASSWORD Administrator password, generated on this instance
IPTV_PLAYLIST_URL The M3U playlist under the secret IPTV address, for players that cannot sign in
IPTV_GUIDE_URL The XMLTV programme guide under the same address
To read the password and the IPTV addresses, run sudo cat /var/lib/sac/data/ersatztv-credentials.txt in your own session. Store them in your password manager.
Confirm ErsatzTV is running
Confirm that the first-boot units have finished and that the firewall table, ErsatzTV and nginx are active. The listening sockets are sshd and nginx on 22, 80 and 443, plus ErsatzTV's own 8409 (web interface and API) and 8410 (streaming). ErsatzTV binds every address, which is why the firewall table exists:
systemctl is-active ersatztv-firewall.service ersatztv-host.service ersatztv-firstboot.service ersatztv.service nginx.service
sudo ss -Htlnp | awk '{print $4, $6}' | sed -E 's/,pid=[0-9]+,fd=[0-9]+//g' | sort -u cat /opt/ersatztv/VERSIONactive active active active active *:8409 users:(("ErsatzTV")) *:8410 users:(("ErsatzTV")) 0.0.0.0:22 users:(("sshd"),("systemd")) 0.0.0.0:443 users:(("nginx"),("nginx"),("nginx")) 0.0.0.0:80 users:(("nginx"),("nginx"),("nginx")) 127.0.0.53%lo:53 users:(("systemd-resolve")) 127.0.0.54:53 users:(("systemd-resolve")) [::]:22 users:(("sshd"),("systemd")) [::]:443 users:(("nginx"),("nginx"),("nginx")) [::]:80 users:(("nginx"),("nginx"),("nginx")) ersatztv_version=26.11.6 ersatztv_source=https://github.com/ErsatzTV/legacy/tree/v26.11.6 (release asset https://github.com/ErsatzTV/ErsatzTV/releases/download/v26.11.6/ErsatzTV-Legacy-v26.11.6-linux-x64.tar.gz) ersatztv_sha256=7920583c23c1b7cf492f4337a63447efe6f92b7936373f1a25bf1187541d3120 dotnet_runtime=10.0.14 (self-contained, inside the release) ersatztv_channel=ersatztv-channel 0.2.4 sac rebuild sha256 99bd3cdb9b936277e192fb41caaee5765c1e38d10241d44c4f3a7a75f6eb93ee (upstream binary sha256 48f201e597f408e00c5ad225b67eb1109cdc4297c7604747d903218fde69517e) ffmpeg=n8.1.3-34-ga35157abb9-20261106 (/opt/ffmpeg, BtbN autobuild-2026-11-06-12-50)The firewall table accepts loopback traffic and drops everything else sent to 8409 and 8410, so only nginx reaches ErsatzTV:
sudo nft list table inet ersatztv_guardtable inet ersatztv_guard { chain input { type filter hook input priority filter; policy accept; iif "lo" accept tcp dport { 8409, 8410 } drop } }Prove the login and the web defaults
Run the commands below to confirm the defaults. The web interface, the playlist and the REST API refuse a signed-out request. The health check answers, plain HTTP redirects to HTTPS, an unknown Host header gets no answer, and TLS 1.1 is not offered.
The last command is the image's own round-trip check. It signs in with this instance's administrator password and shows that a wrong password and an anonymous request are refused. It calls the REST API with and without its key, fetches the playlist under the secret IPTV address, and shows that a wrong token is refused:
H=$(sed -n 's/^set \$etv_host "\(.*\)";$/\1/p' /etc/nginx/ersatztv-hostvar.conf) C=(--connect-to ::127.0.0.1:) curl -sk "${C[@]}" -o /dev/null -w 'web UI, signed out -> %{http_code}\n' "https://$H/" curl -sk "${C[@]}" -o /dev/null -w 'health -> %{http_code}\n' "https://$H/healthz" curl -sk "${C[@]}" -o /dev/null -w 'playlist, signed out -> %{http_code}\n' "https://$H/iptv/channels.m3u" curl -sk "${C[@]}" -o /dev/null -w 'REST API, signed out -> %{http_code}\n' "https://$H/api/version" curl -s "${C[@]}" -o /dev/null -w 'http -> %{http_code}\n' "http://$H/" curl -sk -o /dev/null -w 'unknown Host -> %{http_code}\n' -H 'Host: evil.example' https://127.0.0.1/ || true curl -sk "${C[@]}" -o /dev/null -w 'TLS 1.1 -> %{http_code}\n' --tlsv1.1 --tls-max 1.1 "https://$H/" || true
sudo ersatztv-selftestweb UI, signed out -> 401 health -> 200 playlist, signed out -> 401 REST API, signed out -> 401 http -> 301 unknown Host -> 000 TLS 1.1 -> 000 round-trip OK: admin signed in over https://ec2-44-203-152-239.compute-1.amazonaws.com/ (anonymous 401, wrong password 401), REST API refused without its key (401) and answered the version with it, IPTV token playlist served 1 channel(s) with tokenised stream URLs (wrong token 404)--connect-to ::127.0.0.1: sends each request to this instance while keeping the real host name in the request, exactly as a browser would. A result of 000 means the server closed the connection without an answer.
Sign in to ErsatzTV
Browse to ERSATZTV_URL (https://<public-dns-name>/). The certificate is self-signed, so your browser warns once. Accept it for this host, or install your own certificate (Step 10).
When the browser asks for a user name and password, enter ADMIN_USERNAME and ADMIN_PASSWORD.
ErsatzTV opens on its home page, which runs a set of health checks and shows the release notes. On this image, two checks show a warning. Both are expected:
- FFmpeg Version says the FFmpeg build is not a current "ErsatzTV-ffmpeg" build. The image ships the upstream FFmpeg 8.1.3, which contains security fixes that ErsatzTV's own 8.1.2 package does not have. ErsatzTV works with it, and the warning is informational.
- Hardware Acceleration says channel 1 does not use NVENC, VAAPI or QSV. General-purpose EC2 instances have no GPU, so transcoding runs on the CPU (see Maintenance for GPU instances).
Channels and FFmpeg
Channels lists your channels. On first start, ErsatzTV creates channel 1 (named ErsatzTV) in MPEG-TS mode with the default 1920x1080 x264 aac FFmpeg profile.
Use Add Channel to create your own channels. Use the pencil to edit one (number, name, logo, streaming mode, FFmpeg profile). Use the play button to preview a channel in the browser once it has a schedule.
Settings, then FFmpeg, already points at the image's FFmpeg and FFprobe (/usr/local/bin/ffmpeg and /usr/local/bin/ffprobe). Leave those paths as they are. FFmpeg Profiles sets resolution, video and audio codecs and bitrates per channel. Lower resolutions cost less CPU.
The FFmpeg on the image, and its build options:
/usr/local/bin/ffmpeg -hide_banner -version | head -1 /usr/local/bin/ffmpeg -hide_banner -buildconf | grep -E -- '--enable-(gpl|version3|nonfree|libfdk)' | sed 's/^ *//'ffmpeg version n8.1.3-34-ga35157abb9-20261106 Copyright (c) 2000-2026 the FFmpeg developers --enable-gpl --enable-version3It is a GPL build with no non-free components (no --enable-nonfree, no libfdk-aac).
Use the REST API
ErsatzTV's REST API needs the administrator login and the API key that ErsatzTV generated on this instance. Choose API at the top of the page for its documentation.
This example reads both secrets into shell variables and hands them to curl through file descriptors, so neither appears on a command line, in your shell history or in the output:
H=$(sed -n 's/^set \$etv_host "\(.*\)";$/\1/p' /etc/nginx/ersatztv-hostvar.conf)
P=$(sudo grep '^ADMIN_PASSWORD=' /var/lib/sac/data/ersatztv-credentials.txt | cut -d= -f2-)
K=$(sudo python3 -I -c 'import json; print(json.load(open("/var/lib/ersatztv/config/api-secrets.json"))["ApiKey"])')
curl -sk --connect-to ::127.0.0.1: --netrc-file <(printf 'machine %s login admin password %s\n' "$H" "$P") \
-H @<(printf 'X-Etv-Api-Key: %s\n' "$K") "https://$H/api/version"; echo
curl -sk --connect-to ::127.0.0.1: --netrc-file <(printf 'machine %s login admin password %s\n' "$H" "$P") \
-H @<(printf 'X-Etv-Api-Key: %s\n' "$K") "https://$H/api/channels" | python3 -I -m json.tool | head -20 unset P K{"apiVersion":3,"appVersion":"v26.11.6-linux-x64"} [ { "id": 1, "number": "1", "name": "ErsatzTV", "ffmpegProfile": "1920x1080 x264 aac", "streamingMode": "MPEG-TS" } ]From your workstation, drop --connect-to ::127.0.0.1: and use your instance's name. Keep -k until you install a trusted certificate (Step 10).
Add your media
ErsatzTV can read media from local folders on the instance, or from Plex, Jellyfin and Emby servers (Media Sources).
For local media, attach an EBS volume (the CLI example in Step 1 adds one as /dev/sdf), create a file system on it, and mount it, for example at /srv/media. ErsatzTV runs as the ersatztv user and must be able to read the files. It cannot see anything under /home, so keep media out of home directories:
lsblk
sudo mkfs.ext4 -L media /dev/nvme1n1
sudo mkdir -p /srv/media echo 'LABEL=media /srv/media ext4 defaults,nofail 0 2' | sudo tee -a /etc/fstab
sudo mount /srv/media
sudo mkdir -p /srv/media/movies /srv/media/shows
sudo chown -R ubuntu:ersatztv /srv/media
sudo chmod -R g+rX /srv/mediaCheck the device name with lsblk first, because Nitro instances name EBS volumes /dev/nvme1n1 and so on. Then copy your files from your workstation with scp or rsync into /srv/media/movies and /srv/media/shows.
In ErsatzTV, open Media Sources, then Local. Each built-in library (Movies, Shows, Music Videos, Other Videos, Songs, Images, Remote Streams) holds one kind of media. Choose the pencil next to a library, add your folder (for example /srv/media/movies to Movies), and save. ErsatzTV scans the folder and fetches artwork and metadata.
Then build a channel. Create a Collection (or use a whole show) and add it to a Schedule under Scheduling. Assign the schedule to a channel to generate its playout.
Watch your channels
IPTV players that can send a user name and password use https://<your-name>/iptv/channels.m3u for the playlist and https://<your-name>/iptv/xmltv.xml for the guide, with the administrator login.
Players that cannot sign in use the secret IPTV address from IPTV_PLAYLIST_URL and IPTV_GUIDE_URL. The command below masks the token. Run it without the sed to see the token:
sudo ersatztv-iptv-url | sed -E 's#/tv-[0-9a-f]{32}/#/tv-<token>/#'IPTV playlist: https://ec2-44-203-152-239.compute-1.amazonaws.com/tv-<token>/iptv/channels.m3u IPTV guide: https://ec2-44-203-152-239.compute-1.amazonaws.com/tv-<token>/iptv/xmltv.xmlThe stream addresses inside that playlist carry the same token. Treat the address like a password: anyone who has it can watch your channels, but nothing else is reachable through it. To replace it, run sudo ersatztv-iptv-url --rotate. The old addresses stop working at once, so update your players.
Jellyfin and Emby: add an M3U tuner with the playlist address and an XMLTV guide provider with the guide address.
HDHomeRun clients (such as Plex's Live TV & DVR) that let you enter a tuner by address can use https://<your-name>/tv-<token>. ErsatzTV's HDHomeRun discovery, lineup and stream addresses are all served under the token. If a client accepts only a bare host name, use the M3U playlist and XMLTV guide instead.
Media servers and TV apps usually refuse a self-signed certificate. Serve ErsatzTV under your own DNS name with a trusted certificate (Step 10) before you connect them.
Serve ErsatzTV under your own DNS name
Point a DNS record (for example tv.example.com) at the instance's public or Elastic IP address, then tell the image to serve that name. The command creates a new self-signed certificate for the name, pins nginx and the cross-site guard to it, updates the addresses in the credentials file, and keeps the name across reboots:
sudo ersatztv-set-hostname tv.example.comFor a trusted certificate, obtain one for that name, for example with certbot's certonly mode using its own temporary web server, or from your organization's CA. Copy the certificate chain and key over /etc/ssl/ersatztv/ersatztv.crt and /etc/ssl/ersatztv/ersatztv.key (key mode 0600, root), then run sudo systemctl reload nginx.
Check the security controls
Run the commands below to review the security controls. ErsatzTV, its first-boot unit and nginx carry IPAddressDeny for the metadata addresses, and first boot recorded that it could not reach the metadata service from inside its own unit. ErsatzTV runs sandboxed as ersatztv and requires the firewall table. SSH runs with the SecureAnyCloud pins:
systemctl show -p IPAddressDeny ersatztv.service ersatztv-firstboot.service nginx.service
systemctl show -p User -p ProtectSystem -p ProtectHome -p NoNewPrivileges -p Requires ersatztv.service
sudo grep -o 'IMDS-REFUSED-IN-FIRSTBOOT.*' /var/log/sac/sac-firstboot.log
sudo sshd -T | grep -E '^(permitrootlogin|passwordauthentication|x11forwarding) 'IPAddressDeny=fd00:ec2::254/128 168.63.129.16/32 169.254.169.254/32 IPAddressDeny=fd00:ec2::254/128 168.63.129.16/32 169.254.169.254/32 IPAddressDeny=fd00:ec2::254/128 168.63.129.16/32 169.254.169.254/32 User=ersatztv ProtectHome=yes ProtectSystem=strict NoNewPrivileges=yes Requires=ersatztv-firewall.service system.slice -.mount sysinit.target IMDS-REFUSED-IN-FIRSTBOOT (http 000; IPAddressDeny in effect) permitrootlogin no passwordauthentication no x11forwarding noMaintenance
- Change the administrator password: run
sudo htpasswd -B -C 12 /etc/nginx/ersatztv.htpasswd admin(it prompts for the new password), then remove the old password from the credentials file (sudo nano /var/lib/sac/data/ersatztv-credentials.txt) once you have stored the new one. nginx reads the change on the next request. - Operating system updates: unattended security upgrades are on. Reboot when
/var/run/reboot-requiredexists; the firewall table, ErsatzTV and nginx start again by themselves. - ErsatzTV updates: ErsatzTV has no auto-update. To move to a newer release, launch the newer version of this image when the listing offers it and copy
/var/lib/ersatztvacross with ErsatzTV stopped. - Backups: ErsatzTV keeps its database, keys, artwork cache and settings in
/var/lib/ersatztv(on the root volume). Take an EBS snapshot, or stop ErsatzTV (sudo systemctl stop ersatztv) and copy the directory. Snapshot your media volume separately. - GPU transcoding: on a GPU instance, install the NVIDIA driver and add a systemd drop-in for
ersatztv.servicewithPrivateDevices=falseso ErsatzTV can use the GPU, then pick an NVENC FFmpeg profile. - Ubuntu's nftables service: if you enable
nftables.service, its/etc/nftables.confstarts withflush ruleset, which removes the ErsatzTV table. Runsudo systemctl restart ersatztv-firewallafterwards, or add the table to that file. - Logs:
sudo journalctl -u ersatztvfor ErsatzTV (also Support, then Logs, in the web interface),/var/log/nginx/for web requests (the secret IPTV address is never written to the access or error log),/var/log/sac/sac-firstboot.logfor first boot.
Troubleshooting
- The web page does not load right after launch: first boot is still running.
sudo journalctl -u ersatztv-host.service -u ersatztv-firstboot.service -fshows its progress. - Browser shows "connection closed": nginx answers only the configured name and redirects the instance's own IP addresses to it. Use
ERSATZTV_URL, or runsudo ersatztv-set-hostname <name>for a new name. - The browser keeps asking for a password: use
ADMIN_USERNAMEandADMIN_PASSWORDfrom the credentials file exactly; the user name isadmin. - A player gets 401 or 404: 401 means it is using
/iptv/...without a login; give it the secret IPTV address fromsudo ersatztv-iptv-urlinstead. 404 under/tv-means the token is wrong or out of date (for example after a--rotate). - ErsatzTV does not start:
systemctl status ersatztv-firewallmust be active; ErsatzTV refuses to start without its firewall table. - New media does not appear: check the folder is readable by the
ersatztvuser (sudo -u ersatztv ls /srv/media/movies) and is outside/home, then rescan the library from Media Sources. - The end-to-end check:
sudo ersatztv-selftestsigns in, calls the API, fetches the playlist under the secret address and printsround-trip OKwhen everything works.
Licensing
ErsatzTV is licensed under the zlib licence (Zlib); the text is on the instance in /opt/ersatztv/LICENSE. The ErsatzTV "Next" streaming engine (ersatztv-channel) is MIT-licensed (/opt/ersatztv/LICENSE.ersatztv-channel). FFmpeg is licensed under the GNU General Public License (this build enables GPL and version 3 components and no non-free code); its licence is in /opt/ffmpeg/LICENSE.txt and /opt/ffmpeg/SOURCE.txt says where to obtain its complete corresponding source. /opt/ersatztv/SOURCE.txt points to the ErsatzTV source at github.com/ErsatzTV/legacy. SecureAnyCloud is not affiliated with, endorsed by or sponsored by the ErsatzTV project or its authors, or by Plex, Jellyfin, Emby or HDHomeRun.
Support
SecureAnyCloud provides 24/7 technical support for this image by email and live chat: deployment, first login, HTTPS and DNS setup, IPTV and media server connections, upgrades and troubleshooting. Contact sales@secureanycloud.com.
Deploy on AWS
Launch ErsatzTV 26.11.6 on Ubuntu 24.04 on AWS with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com