go2rtc 1.9.15 on AWS User Guide
Overview
This guide covers launching and verifying go2rtc 1.9.15 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.
go2rtc is an open-source camera streaming gateway (MIT licence). It connects to your cameras over the protocols they speak (RTSP, ONVIF, RTMP, HTTP and many vendor protocols) and serves each stream to a browser over WebRTC (sub-second delay), MSE, HLS or MJPEG, converting between them as needed, with ffmpeg for transcoding and snapshots. A web dashboard lists your streams and plays them; a REST API gives the same control to scripts and home-automation systems.
What is on the image:
- go2rtc 1.9.15, compiled by cloudimg from the upstream
v1.9.15source archive (commit7c05066c) with Go 1.27.3; see Security posture for the one raised library and the two changed source lines - ffmpeg from Ubuntu 24.04, for transcoding, JPEG snapshots and the built-in test pattern
- The web UI and API on
127.0.0.1:1984only, behind nginx serving HTTPS on port 443 with a certificate created on your instance; port 80 redirects to HTTPS - WebRTC media on one UDP port, 8555, with the instance's public address advertised on every boot
- A per-instance sign-in (user name and password) created on first boot and required on every request, and a test-pattern stream called
demoso you can see the pipeline working before you add a camera go2rtc-selftest(an end-to-end check),go2rtc-set-hostname,go2rtc-rotate-credentialsandgo2rtc-config-editing
Default user: ubuntu · Architecture: x86_64 · Root volume: 8 GiB gp3
Security posture
- Signed in, on every request. Upstream go2rtc ships with its web UI and API open to anyone who can reach port 1984, and with authentication skipped for local callers, which would include nginx. This image sets a per-instance user name and password and
local_auth, so go2rtc asks for them on every request, including those nginx forwards. go2rtc refuses to start without well-formed credentials. A missing, wrong or default password (admin:admin, empty) gets401. - Per-instance secrets, no defaults. First boot generates the web/API sign-in and a separate RTSP sign-in on your instance and writes them to root-only files. The image ships with no credential and no TLS key. The values never appear on a command line or in a log.
- Configuration editing through the web UI and API is off. go2rtc's API can rewrite its own configuration file. Here the file is read-only to go2rtc and nginx refuses
POSTandPATCHto/api/config; the Config page still shows the file. You edit/etc/go2rtc/go2rtc.yamlover SSH, or turn API editing on withsudo go2rtc-config-editing enable(Step 9). - No command-running sources. go2rtc can start a shell command as a stream source (
echo:andexec:sources) or evaluate an expression (expr:). This image does not load theechoandexprmodules, and letsexecrun ffmpeg and nothing else (ffmpeg:sources run through it). go2rtc also refusesexec:sources added through the API. HomeKit, Home Assistant, WebTorrent and the ngrok and pinggy tunnels are not loaded either. Turning any of these on is a deliberate edit of/etc/go2rtc/cloudimg.yaml(Step 9). - Another web site cannot use your sign-in. Browsers remember the HTTP sign-in and send it on their own, even when another site or a link from an email starts the request. Every
/apiand/onvifrequest must therefore come from go2rtc's own pages: it must carry aRefererorOriginnaming this instance, and is refused (403) if it was started by another site or from outside the browser. go2rtc's own pages always send one, so the dashboard and the players work as normal. AGETrequest never makes go2rtc open a URL: a link whosesrc=names a camera address instead of one of your streams is refused, and new sources are added with the dashboard's Add button (aPUT) or in the configuration file. - Fails closed. go2rtc starts only after first boot has written the credentials and the address to advertise for media, and nginx only after first boot has finished. If first boot cannot finish, nothing is served.
- HTTPS from first boot. nginx serves TLS 1.2 and 1.3 with a self-signed end-entity certificate created on your instance (it cannot act as a certificate authority). The sign-in and every stream travel only over HTTPS.
- The host name comes from configuration, never from a request. The name go2rtc is served as is your own (Step 8) or the instance's public DNS name from EC2 instance metadata (IMDSv2). Requests for any other host name get their connection closed.
- Client address from the connection. nginx replaces
X-Forwarded-ForandX-Real-IPwith the real peer address and dropsForwardedandX-Forwarded-Host. The access log records no query strings (a stream source can carry a camera password) and no user names. - Exactly these ports: 22, 80 and 443 TCP and 8555 UDP. go2rtc's API (1984) and its RTSP server (8554) listen on loopback only; its RTMP, SRTP/HomeKit and WebRTC-over-TCP listeners are off.
- go2rtc cannot read instance metadata. go2rtc, every ffmpeg it starts, its first-boot unit and nginx are blocked from the instance metadata service (169.254.169.254, fd00:ec2::254) by systemd
IPAddressDeny, so no stream source, whatever URL it names, can reach the instance's credentials. Only the small unit that looks up the instance's address at boot may use it, and it serves nothing. - Sandboxed. go2rtc runs as the unprivileged
go2rtcuser with no capabilities, a read-only system (ProtectSystem=strict, no writable path) and no core dumps. - Dependencies.
govulncheckreports no vulnerability reachable from go2rtc 1.9.15; this build also raisesgolang.org/x/netfrom 0.61.0 to 0.62.0 so that binary scanners do not flag two advisories in a package go2rtc does not use. Multicast DNS is switched off in the WebRTC stack (one source line), so a session never opens UDP 5353, and the version reads1.9.15+cloudimg(one source line). The build record is in/usr/share/doc/go2rtc/BUILD-PROVENANCE.txt. - No outbound calls from the server. go2rtc uses no STUN server; it advertises the address it reads from instance metadata. See Maintenance for what your browser loads.
- 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.
- Ubuntu Pro note. ffmpeg and its codec libraries come from Ubuntu's community-maintained
universearchive. Some universe packages this image needs (ffmpeg and its libraries) receive certain security fixes only through Ubuntu Pro (ESM). Attaching the instance to Ubuntu Pro delivers them.
Prerequisites
- An AWS account and permission to launch EC2 instances
- An EC2 key pair in the Region you launch in
- A camera or video source reachable from the instance (for example over a VPN or in the same VPC), or just the built-in test pattern to start with
Recommended instance type: m5.large. Passing a camera's H.264 stream through to viewers is light; transcoding with ffmpeg (for example H.265 to H.264, or snapshots) is CPU-bound, so size up for many transcoded streams.
Connecting to your instance
| Version | Operating system | SSH user |
|---|---|---|
| go2rtc 1.9.15 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 go2rtc 1.9.15 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/tcp), HTTP (80/tcp), HTTPS (443/tcp) and WebRTC media (8555/udp). Keep 8555/udp open to your viewers: without it, browsers fall back to the slower MSE player over HTTPS. Restrict SSH, and ideally 443, to your own networks.
- Choose your VPC and a subnet that can reach your cameras (with a public IP or Elastic IP if viewers connect over the internet), 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 go2rtc \
--description "go2rtc camera streaming" --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 80 --cidr <your-viewer-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 udp --port 8555 --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 \
--associate-public-ip-address \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=go2rtc}]'
You do not need --metadata-options: the AMI already makes IMDSv2 required.
Step 2: Connect and find your sign-in
Connect as ubuntu with the key pair you chose:
ssh -i ~/.ssh/my-key-pair.pem ubuntu@<public-ip>
First boot takes a few seconds after the instance starts. It reads the instance's public address, sets the name go2rtc is served as (the public DNS name when it has one), creates the TLS certificate and the sign-in, and writes /root/go2rtc-credentials.txt (mode 0600, root). These are the entries in that file (the user names and passwords are not shown here):
sudo grep -E '^GO2RTC_(URL|CERT_SHA256|WEBRTC_ADDRESS)=' /root/go2rtc-credentials.txt
sudo grep -oE '^[A-Z0-9_]+=' /root/go2rtc-credentials.txt
sudo stat -c '%a %U:%G %n' /root/go2rtc-credentials.txt /etc/go2rtc/secrets.yaml
GO2RTC_URL=https://ec2-54-234-251-189.compute-1.amazonaws.com/
GO2RTC_CERT_SHA256=13:F5:C2:36:68:3C:16:EC:80:B2:AE:9C:4E:82:C9:F1:A6:C7:3E:1F:E2:02:AB:05:10:8E:8F:14:3F:DD:22:0F
GO2RTC_WEBRTC_ADDRESS=54.234.251.189
GO2RTC_URL=
GO2RTC_USER=
GO2RTC_PASSWORD=
GO2RTC_RTSP_USER=
GO2RTC_RTSP_PASSWORD=
GO2RTC_CERT_SHA256=
GO2RTC_WEBRTC_ADDRESS=
600 root:root /root/go2rtc-credentials.txt
640 root:go2rtc /etc/go2rtc/secrets.yaml
| Value | What it is for |
|---|---|
GO2RTC_URL |
The address of this instance's go2rtc dashboard |
GO2RTC_USER, GO2RTC_PASSWORD |
The sign-in for the dashboard and the API (keep the password secret) |
GO2RTC_RTSP_USER, GO2RTC_RTSP_PASSWORD |
The sign-in RTSP clients will need once you open RTSP to your network (Step 7) |
GO2RTC_CERT_SHA256 |
The fingerprint of this instance's certificate, to check the browser warning against |
GO2RTC_WEBRTC_ADDRESS |
The address advertised for WebRTC media (UDP 8555) |
To read the passwords, run sudo cat /root/go2rtc-credentials.txt in your own session and store them in your password manager.
Step 3: Confirm go2rtc is running
The network-configuration unit has run, first boot has finished, go2rtc and nginx are active, go2rtc listens on 127.0.0.1:1984 (UI and API) and 127.0.0.1:8554 (RTSP) and on UDP 8555 on the instance's own address, and only sshd and nginx listen on TCP beyond loopback:
systemctl is-active go2rtc-netconf.service go2rtc.service nginx.service
ls /var/lib/cloudimg/go2rtc-firstboot.done
go2rtc -version
sudo ss -Htlnp | awk '{print $4, $6}' | sed -E 's/,pid=[0-9]+,fd=[0-9]+//g' | sort -u
sudo ss -Hulnp | grep -F '"go2rtc"' | awk '{print $4, $6}' | sed -E 's/,pid=[0-9]+,fd=[0-9]+//g' | sort -u
sudo cat /run/go2rtc/network.yaml
sudo sed -n '/^tag commit/p;/^binary sha256/p;/^govulncheck/p' /usr/share/doc/go2rtc/BUILD-PROVENANCE.txt
active
active
active
/var/lib/cloudimg/go2rtc-firstboot.done
go2rtc version 1.9.15+cloudimg () linux/amd64
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.1:1984 users:(("go2rtc"))
127.0.0.1:8554 users:(("go2rtc"))
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"))
172.31.93.107:8555 users:(("go2rtc"))
# cloudimg go2rtc-netconf (every boot): the address WebRTC peers send media to (instance metadata public-ipv4)
webrtc:
candidates:
- 54.234.251.189:8555
tag commit 7c05066c90ab6ad1fccb506d5f0408aa31ebe60f
binary sha256 2924d26e33771d5f47e3722a4bbed768e4f793b7d276d13028d26591d33edc2c (reproducible)
govulncheck v1.9.0 -mode=binary: No vulnerabilities found.
The candidates entry is the public address go2rtc tells browsers to send WebRTC media to. It is read again on every boot, so a stop and start that gives the instance a new public address keeps working.
Step 4: Prove the defaults
The dashboard and the API refuse a request that is not signed in or has a wrong password, accept the instance's sign-in, refuse it when the request comes from another site or from a link opened outside the browser, refuse configuration editing and command sources, redirect plain HTTP and drop an unknown Host. The commands read the sign-in from the credentials file without printing it; the last one is the image's own end-to-end check:
H=$(sed -n 's/^set \$g2_host "\(.*\)";$/\1/p' /etc/nginx/go2rtc-host.conf)
C=(--connect-to ::127.0.0.1: --cacert /etc/nginx/tls/go2rtc.crt)
O=(-H "Origin: https://$H")
auth() { sudo awk -F= -v w="${1:-}" '/^GO2RTC_USER=/{u=$2} /^GO2RTC_PASSWORD=/{p=$2} END{printf "user = \"%s:%s%s\"\n", u, p, w}' /root/go2rtc-credentials.txt; }
curl -s "${C[@]}" -o /dev/null -w 'web UI, not signed in -> %{http_code}\n' "https://$H/"
curl -s "${C[@]}" -K <(auth) -o /dev/null -w 'web UI, instance sign-in -> %{http_code}\n' "https://$H/"
curl -s "${C[@]}" -K <(auth x) "${O[@]}" -o /dev/null -w 'API, wrong password -> %{http_code}\n' "https://$H/api"
curl -s "${C[@]}" -K <(auth) "${O[@]}" -o /dev/null -w 'API, instance sign-in -> %{http_code}\n' "https://$H/api"
curl -s "${C[@]}" -K <(auth) -H 'Sec-Fetch-Site: none' -o /dev/null -w 'API, link opened from outside the browser -> %{http_code}\n' "https://$H/api"
curl -s "${C[@]}" -K <(auth) -H 'Sec-Fetch-Site: cross-site' -H 'Origin: https://evil.example' -o /dev/null -w 'API, another web site -> %{http_code}\n' "https://$H/api"
curl -s "${C[@]}" -K <(auth) "${O[@]}" -o /dev/null -w 'config editing through the API -> %{http_code}\n' -X POST --data-binary 'streams: {}' "https://$H/api/config"
curl -s "${C[@]}" -K <(auth) "${O[@]}" -w ' <- exec: source through the API: %{http_code}\n' -X PUT "https://$H/api/streams?name=x&src=exec:id"
curl -s --connect-to ::127.0.0.1: -o /dev/null -w 'http -> %{http_code} %{redirect_url}\n' "http://$H/"
curl -sk -o /dev/null -w 'unknown Host -> %{http_code}\n' -H 'Host: evil.example' https://127.0.0.1/ || true
sudo go2rtc-selftest | tail -3
web UI, not signed in -> 401
web UI, instance sign-in -> 200
API, wrong password -> 401
API, instance sign-in -> 200
API, link opened from outside the browser -> 403
API, another web site -> 403
config editing through the API -> 403
streams: source from insecure producer
<- exec: source through the API: 400
http -> 301 https://ec2-54-234-251-189.compute-1.amazonaws.com/
unknown Host -> 000
selftest: ok go2rtc UDP listener(s) on port 8555 only
selftest: ok go2rtc-netconf.service ran this boot
selftest: GO2RTC-SELFTEST OK
--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. -K <(auth) hands the sign-in to curl through a file descriptor, so it never appears on a command line. 000 means the server closed the connection without an answer.
Step 5: Open the dashboard and watch the test pattern
Browse to GO2RTC_URL (https://<public-dns-name>/). The certificate is self-signed, so your browser warns once; compare the fingerprint it shows with GO2RTC_CERT_SHA256 and accept it for this host, or install your own certificate (Step 8). Your browser then asks for the user name and password (GO2RTC_USER, GO2RTC_PASSWORD).
The dashboard lists your streams. The image comes with one, demo: a colour-bar test pattern that ffmpeg generates on the instance (no camera and no network source), encoded to H.264 so it plays over every protocol:

Choose stream next to demo to open the player. go2rtc picks the best protocol the browser supports (WebRTC first, then MSE), and the test pattern plays with well under a second of delay:

The same stream is available as a snapshot and over the other protocols:
H=$(sed -n 's/^set \$g2_host "\(.*\)";$/\1/p' /etc/nginx/go2rtc-host.conf)
C=(--connect-to ::127.0.0.1: --cacert /etc/nginx/tls/go2rtc.crt)
O=(-H "Origin: https://$H")
auth() { sudo awk -F= '/^GO2RTC_USER=/{u=$2} /^GO2RTC_PASSWORD=/{p=$2} END{printf "user = \"%s:%s\"\n", u, p}' /root/go2rtc-credentials.txt; }
curl -s "${C[@]}" -K <(auth) "${O[@]}" "https://$H/api/streams" | jq -c '.demo.producers'
curl -s "${C[@]}" -K <(auth) "${O[@]}" -o /run/go2rtc-guide.jpg -w 'snapshot -> %{http_code} %{content_type} %{size_download} bytes\n' "https://$H/api/frame.jpeg?src=demo"
ffprobe -v error -show_entries stream=codec_name,width,height -of csv=p=0 /run/go2rtc-guide.jpg; rm -f /run/go2rtc-guide.jpg
[{"url":"ffmpeg:virtual?video&size=1280x720#video=h264"}]
snapshot -> 200 image/jpeg 20785 bytes
mjpeg,1280,720
When cloudimg built this image, a WebRTC player on a workstation in London, pulling the test pattern from an instance in us-east-1 over the internet, connected to the instance's public address on UDP 8555 and decoded every frame it received.
Step 6: Add your cameras
Streams live in /etc/go2rtc/go2rtc.yaml, one name per camera with one or more sources. Edit the file over SSH, then restart go2rtc. Typical sources (use your camera's address and its own credentials):
streams:
front_door: rtsp://user:password@192.0.2.10:554/stream1
garage: onvif://user:password@192.0.2.11
lobby_h264: ffmpeg:rtsp://user:password@192.0.2.12/live#video=h264
sudo nano /etc/go2rtc/go2rtc.yaml
sudo systemctl restart go2rtc
The dashboard's add page can also add a source (it uses a PUT request): the stream works straight away, but because configuration editing through the API is off, it is not saved and goes away at the next restart. Copy it into go2rtc.yaml to keep it, or turn API editing on (Step 9).
The instance must be able to reach your cameras: put it in a VPC connected to the camera network (VPN, AWS Site-to-Site VPN or Direct Connect), or have each camera, or a recorder on site, push to the instance. Never expose a camera's own RTSP port to the internet.

The add page lists every source type go2rtc knows; the ones whose modules this image does not load (ALSA, Apple HomeKit, Home Assistant, V4L2, WebTorrent) answer with an error.
To use the API from a script or another system (not a browser), sign in and send an Origin header naming this instance, which tells nginx the request is not from another web site:
curl --cacert go2rtc.crt -u "$GO2RTC_USER:$GO2RTC_PASSWORD" -H "Origin: https://<your-host>" \
"https://<your-host>/api/frame.jpeg?src=front_door" -o snapshot.jpg
A GET whose src= is a camera address rather than a stream name is refused (403): add the camera as a stream first, then refer to it by name. The add page's ONVIF probe uses such a request, so add ONVIF cameras by typing their onvif:// address into the add box or the configuration file.
Step 7: Networking: the media port, the advertised address and RTSP
WebRTC media does not travel over the web connection: browsers send it to the address go2rtc advertises, on UDP 8555. Two things must be true:
- The security group allows 8555/udp from your viewers. Without it the player falls back to MSE over HTTPS, which works but adds a second or more of delay.
- The advertised address is reachable. On every boot,
go2rtc-netconf.servicereads the instance's public IPv4 address from instance metadata and writes it to/run/go2rtc/network.yaml. An instance with no public address advertises its private address, so WebRTC then works only inside the VPC or over a VPN.
sudo journalctl -u go2rtc-netconf.service -b --no-pager -o cat | grep 'go2rtc-netconf:' | tail -2
go2rtc-netconf: WebRTC media address 54.234.251.189:8555/udp (instance metadata public-ipv4)
go2rtc-netconf: served as https://ec2-54-234-251-189.compute-1.amazonaws.com/ (instance metadata)
If the address viewers should use is not the instance's own public address (an Elastic IP you move between instances, or a Network Load Balancer passing UDP 8555 through), write it to /etc/cloudimg/go2rtc-public-ip and restart the two units:
echo 203.0.113.10 | sudo tee /etc/cloudimg/go2rtc-public-ip
sudo systemctl restart go2rtc-netconf.service go2rtc.service
STUN. go2rtc itself uses no STUN server (upstream's default asks Google's and Cloudflare's), because it already knows its address. The browser player built into go2rtc still asks stun.cloudflare.com and stun.l.google.com for the viewer's own address; that request comes from the viewer's browser, not from the instance. To change it, serve your own copy of go2rtc's web pages (api: static_dir: in /etc/go2rtc/cloudimg.yaml).
RTSP to your network. go2rtc's RTSP server (restreaming each stream as rtsp://<host>:8554/<name>, for VLC, recorders and NVRs) listens on loopback only, because RTSP has no encryption and upstream go2rtc runs it with no sign-in: anyone who reached the port could watch every camera and even push a stream into one. To use it, set listen: ":8554" under rtsp: in /etc/go2rtc/cloudimg.yaml, restart go2rtc, and open TCP 8554 in the security group to your own clients only. RTSP clients must then sign in with GO2RTC_RTSP_USER and GO2RTC_RTSP_PASSWORD. For clients elsewhere, an SSH tunnel is safer:
ssh -i ~/.ssh/my-key-pair.pem -L 8554:127.0.0.1:8554 ubuntu@<public-ip>
vlc rtsp://127.0.0.1:8554/demo
Step 8: Serve go2rtc under your own DNS name
Point a DNS record (for example cameras.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 URL in the credentials file and keeps the name across reboots:
sudo go2rtc-set-hostname cameras.example.com
For a certificate that browsers trust without a warning, 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/nginx/tls/go2rtc.crt and /etc/nginx/tls/go2rtc.key (key mode 0600, root), and run sudo systemctl reload nginx.
Step 9: Configuration files, credentials and opt-ins
go2rtc reads four files, a later file winning for every setting it contains:
| File | What it holds | Who writes it |
|---|---|---|
/etc/go2rtc/go2rtc.yaml |
Your streams and settings (the file the Config page shows) | You |
/run/go2rtc/network.yaml |
The address advertised for WebRTC | go2rtc-netconf.service, every boot |
/etc/go2rtc/cloudimg.yaml |
The security baseline: listeners, sign-in mode, modules, the command allow-list | You, only to change the security posture |
/etc/go2rtc/secrets.yaml |
The per-instance credentials | First boot, go2rtc-rotate-credentials |
So nothing in go2rtc.yaml, and nothing written through the API, can turn the sign-in off, open a listener or enable a command source.

- New credentials:
sudo go2rtc-rotate-credentialswrites a new user name and password (and RTSP credentials) to the credentials file and restarts go2rtc; the old ones stop working at once. - Configuration editing through the API:
sudo go2rtc-config-editing enablelets the Config page and the add page save togo2rtc.yaml(and only that file);sudo go2rtc-config-editing disableturns it off again. Anyone with the sign-in can then change your streams. - Command-running sources: to allow
echo:sources, addechotoapp: modules:in/etc/go2rtc/cloudimg.yaml; to letexec:run other programs, add them toexec: allow_paths:. Thensudo systemctl restart go2rtc. Anyone with the sign-in could then run those commands as thego2rtcuser, so only do this if you need it. - Treat the sign-in as an administrator password. Whoever has it can add stream sources, which makes go2rtc and ffmpeg open the URLs (and local files) the
go2rtcuser can reach.
The security controls behind these defaults can be checked at any time:
systemctl show -p IPAddressDeny go2rtc.service nginx.service go2rtc-firstboot.service
systemctl show -p User -p CapabilityBoundingSet -p ProtectSystem -p NoNewPrivileges go2rtc.service
sudo grep -E '^ (modules|listen|local_auth|allow_paths|ice_servers):' /etc/go2rtc/cloudimg.yaml
sudo go2rtc-config-editing status
openssl x509 -in /etc/nginx/tls/go2rtc.crt -noout -ext basicConstraints,keyUsage,extendedKeyUsage
sudo sshd -T | grep -E '^(permitrootlogin|passwordauthentication|x11forwarding) '
IPAddressDeny=168.63.129.16/32 fd00:ec2::254/128 169.254.169.254/32
IPAddressDeny=168.63.129.16/32 fd00:ec2::254/128 169.254.169.254/32
IPAddressDeny=168.63.129.16/32 fd00:ec2::254/128 169.254.169.254/32
CapabilityBoundingSet=
User=go2rtc
ProtectSystem=strict
NoNewPrivileges=yes
modules: [api, ws, http, rtsp, webrtc, mp4, hls, mjpeg, onvif, rtmp, exec, ffmpeg, mpegts, bubble, doorbird, dvrip, eseecloud, flussonic, gopro, isapi, ivideon, kasa, multitrans, nest, ring, roborock, tapo, tuya, wyze, xiaomi, yandex]
listen: "127.0.0.1:1984"
local_auth: true
allow_paths: [ffmpeg]
listen: "127.0.0.1:8554"
listen: ""
listen: ""
listen: ":8555/udp"
ice_servers: []
configuration editing through the API: OFF
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication
permitrootlogin no
passwordauthentication no
x11forwarding no
Maintenance
- Operating system updates: unattended security upgrades are on. Reboot when
/var/run/reboot-requiredexists; go2rtc and nginx start again by themselves. - go2rtc updates: go2rtc is a single binary at
/usr/local/bin/go2rtc. To move to a newer release, launch the newer version of this image when the listing offers it, and copy/etc/go2rtc/go2rtc.yaml(your streams) across. - Backups: go2rtc records nothing; your configuration is
/etc/go2rtc/go2rtc.yaml. - Logs:
sudo journalctl -u go2rtcfor go2rtc (the dashboard's log page shows the same),/var/log/nginx/for web requests (without query strings). - What the instance contacts: go2rtc contacts only the cameras and sources you configure. Measured on a new instance for ten minutes from just after its first boot, while the test pattern played, every outbound connection came from the operating system: the instance metadata service, the AWS Systems Manager agent and the time service. go2rtc and nginx made none. In the browser, a few dashboard pages load helper scripts from the public
cdn.jsdelivr.netCDN (the Config page's editor, the hls, links and net pages), the player asks the STUN servers above, and the stream page loads go2rtc's icon from go2rtc.org.
Troubleshooting
- The player shows MSE instead of WebRTC, or the video starts slowly: UDP 8555 is not reachable. Check the security group, any network ACL, and that
sudo cat /run/go2rtc/network.yamlshows the address your viewers can reach (Step 7). - The browser keeps asking for the password: use
GO2RTC_USERandGO2RTC_PASSWORDfrom the credentials file (aftergo2rtc-rotate-credentials, the new ones). - An API call from a script answers 403: send
-H "Origin: https://<your-host>"(Step 6), and refer to streams by name, not by camera URL. - A stream added in the dashboard is gone after a restart: configuration editing through the API is off; add the stream to
/etc/go2rtc/go2rtc.yaml(Step 6) or turn editing on (Step 9). - A camera does not play: check it from the instance with
ffprobe -rtsp_transport tcp rtsp://<camera>/...; the instance must be able to reach the camera's address. - Browser shows "connection closed": nginx answers only the configured name and the instance's own addresses. Use
GO2RTC_URL, or runsudo go2rtc-set-hostname <name>for a new name. - The end-to-end check:
sudo go2rtc-selftestchecks the sign-in, the cross-site protection, the test pattern, the refused configuration editing and command sources, and the listening ports, and printsGO2RTC-SELFTEST OKwhen everything works.
Licensing
go2rtc is licensed under the MIT licence; the licence text is on the instance in /usr/share/doc/go2rtc/LICENSE, and the source of this release is at github.com/AlexxIT/go2rtc/tree/v1.9.15. ffmpeg is from Ubuntu's archive under its own licences. cloudimg is not affiliated with, endorsed by or sponsored by the go2rtc project or its author.
Support
cloudimg provides 24/7 technical support for this image by email and live chat: deployment, first sign-in, HTTPS and DNS setup, camera network configuration and troubleshooting. Contact support@cloudimg.co.uk.