ErsatzTV 26.11.6 on AWS User Guide
Overview
This guide covers launching and verifying ErsatzTV 26.11.6 on Ubuntu 24.04 from cloudimg on Amazon EC2. It is one version of the cloudimg Hardened SRS Streaming Media Server & Media Servers AMIs listing on AWS Marketplace; you pick it as the software version when you subscribe and launch. The other media and streaming products in the listing are described on the listing's guide hub.
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.
What is on the image:
- 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-channel0.2.4), rebuilt by cloudimg 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. ErsatzTV has no accounts of its own: upstream, 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
admin, whose 32-character password is generated on your instance at first boot and stored by nginx only as a bcrypt hash. - A secret address for players that cannot sign in. Many IPTV players cannot send a user name and password, so 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 (any other path under/tv-answers 404), nginx never writes it 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 (upstream has no option to bind loopback only), so 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 it, 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 (TLS 1.1 is refused), 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 (else its public or private IPv4 address) from EC2 instance metadata (IMDSv2) and pins nginx to it. Requests for any other host name get their connection closed; requests to the instance's IP addresses are redirected to that name. nginx hands ErsatzTV the configured name,
httpsand the real peer address only, 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. ErsatzTV, the first-boot unit and nginx are blocked from the instance metadata service (169.254.169.254, fd00:ec2::254) by systemd
IPAddressDeny; 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; transcoding is the 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, so choose a larger instance (for example m5.xlarge or a compute-optimised c5 type) for several simultaneous channels. 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 |
Step 1: Launch the instance
Option A: AWS Marketplace console
- Open the cloudimg 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 this on your own workstation. Replace the AMI ID with the one shown for your Region on the Marketplace launch page, and 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: the AMI already makes IMDSv2 required. Associate an Elastic IP if you want the address to survive a stop and start.
Step 2: 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 as (the instance's public DNS name when it has one), creates the TLS certificate, lets ErsatzTV create its database and keys, creates the administrator login and the IPTV token, and writes /var/lib/cloudimg/ersatztv-credentials.txt (mode 0600, root). These are the entries in that file (the secret values are not shown here):
sudo grep -E '^(ERSATZTV_URL|ADMIN_USERNAME)=' /var/lib/cloudimg/ersatztv-credentials.txt
sudo grep -oE '^[A-Z_]+=' /var/lib/cloudimg/ersatztv-credentials.txt
sudo stat -c '%a %U:%G %n' /var/lib/cloudimg/ersatztv-credentials.txt
ERSATZTV_URL=https://ec2-44-203-152-239.compute-1.amazonaws.com/
ADMIN_USERNAME=admin
ERSATZTV_URL=
ADMIN_USERNAME=
ADMIN_PASSWORD=
IPTV_PLAYLIST_URL=
IPTV_GUIDE_URL=
600 root:root /var/lib/cloudimg/ersatztv-credentials.txt
| Value | 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/cloudimg/ersatztv-credentials.txt in your own session and store them in your password manager.
Step 3: Confirm ErsatzTV is running
The first-boot units have finished, the firewall table, ErsatzTV and nginx are active, and 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 below 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/VERSION
active
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 cloudimg 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_guard
table inet ersatztv_guard {
chain input {
type filter hook input priority filter; policy accept;
iif "lo" accept
tcp dport { 8409, 8410 } drop
}
}
Step 4: Prove the login and the web 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, proves a wrong password and an anonymous request are refused, calls the REST API with and without its key, and fetches the playlist under the secret IPTV address (and proves 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-selftest
web 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 send it. 000 means the server closed the connection without an answer.
Step 5: 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). The browser then 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, and 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; 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).

Step 6: Channels and FFmpeg
Channels lists your channels. ErsatzTV creates channel 1 (named ErsatzTV) on first start, in MPEG-TS mode with the default 1920x1080 x264 aac FFmpeg profile. Use Add Channel for your own channels, the pencil to edit one (number, name, logo, streaming mode, FFmpeg profile), and the play button to preview it in the browser once it has a schedule.

Settings, then FFmpeg, is already pointed 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-version3
It is a GPL build with no non-free components (no --enable-nonfree, no libfdk-aac).
Step 7: Use the REST API
ErsatzTV's REST API (choose API at the top of the page for its documentation) needs the administrator login and the API key ErsatzTV generated on this instance. This example reads both 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/cloudimg/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).
Step 8: 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), put a file system on it and mount it, for example at /srv/media. ErsatzTV runs as the ersatztv user and needs 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/media
Check the device name with lsblk first (Nitro instances name EBS volumes /dev/nvme1n1 and so on), then copy your files up 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 one, add your folder (for example /srv/media/movies to Movies), and save. ErsatzTV scans it and fetches artwork and metadata. Then build a channel: create a Collection (or use a whole show), add it to a Schedule under Scheduling, and assign the schedule to a channel to generate its playout.

Step 9: 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. Show it (the token is masked here; run the command without the sed to see it):
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.xml
The stream addresses inside that playlist carry the same token. Treat the address like a password: anyone who has it can watch your channels (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, so serve ErsatzTV under your own DNS name with a trusted certificate (Step 10) before connecting them.
Step 10: 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. It 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.com
For a trusted certificate, obtain one for that name (for example with certbot's certonly mode using its own temporary web server, or from your organisation's CA), copy the certificate chain and key over /etc/ssl/ersatztv/ersatztv.crt and /etc/ssl/ersatztv/ersatztv.key (key mode 0600, root), and run sudo systemctl reload nginx.
Step 11: Check the security controls
ErsatzTV, its first-boot unit and nginx carry IPAddressDeny for the metadata addresses, 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, and SSH runs with the cloudimg 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/cloudimg-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 no
Maintenance
- 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/cloudimg/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/cloudimg-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. cloudimg is not affiliated with, endorsed by or sponsored by the ErsatzTV project or its authors, or by Plex, Jellyfin, Emby or HDHomeRun.
Support
cloudimg 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 support@cloudimg.co.uk.