Deployment guide

go2rtc 1.9.15

Overview

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). It 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 and plays your streams, and a REST API gives scripts and home-automation systems the same control.

This guide covers launching and verifying go2rtc 1.9.15 on Ubuntu 24.04 from SecureAnyCloud on Amazon EC2. It is one version of the SecureAnyCloud Hardened SRS Streaming Media Server & Media Servers AMIs listing on AWS Marketplace. You choose it as the software version when you subscribe and launch. The listing's guide hub describes the other media and streaming products in the listing.

What you get:

  • go2rtc 1.9.15, compiled by SecureAnyCloud from the upstream v1.9.15 source archive (commit 7c05066c) 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:1984 only, 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
  • A test-pattern stream called demo, so you can see the pipeline working before you add a camera
  • go2rtc-selftest (an end-to-end check), go2rtc-set-hostname, go2rtc-rotate-credentials and go2rtc-config-editing
  • Default user ubuntu, x86_64 architecture and an 8 GiB gp3 root volume

Security posture

  • Sign-in on every request. Upstream go2rtc leaves its web UI and API open to anyone who can reach port 1984, and it skips authentication 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) gets 401.
  • Per-instance secrets, no defaults. First boot generates the web and 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 POST and PATCH to /api/config. The Config page still shows the file. Edit /etc/go2rtc/go2rtc.yaml over SSH, or turn API editing on with sudo go2rtc-config-editing enable (Step 9).
  • No command-running sources. go2rtc can start a shell command as a stream source (echo: and exec: sources) or evaluate an expression (expr:). This image does not load the echo and expr modules. It lets exec run ffmpeg and nothing else (ffmpeg: sources run through it), and go2rtc refuses exec: 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/sac.yaml (Step 9).
  • Another website cannot use your sign-in. Browsers remember the HTTP sign-in and send it on their own, even when another site or a link in an email starts the request. Every /api and /onvif request must therefore come from go2rtc's own pages. It must carry a Referer or Origin naming this instance, and it is refused (403) if another site or something outside the browser started it. go2rtc's own pages always send one, so the dashboard and the players work as normal. A GET request never makes go2rtc open a URL. A link whose src= names a camera address instead of one of your streams is refused. Add new sources with the dashboard's Add button (a PUT) or in the configuration file.
  • Fails closed. go2rtc starts only after first boot has written the credentials and the address to advertise for media. nginx starts 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. The certificate 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. go2rtc is served under your own name (Step 8) or the instance's public DNS name from EC2 instance metadata (IMDSv2). nginx closes the connection for requests to any other host name.
  • Client address from the connection. nginx replaces X-Forwarded-For and X-Real-IP with the real peer address and drops Forwarded and X-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. systemd IPAddressDeny blocks go2rtc, every ffmpeg it starts, its first-boot unit and nginx from the instance metadata service (169.254.169.254, fd00:ec2::254). 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 the service, and it serves nothing.
  • Sandboxed. go2rtc runs as the unprivileged go2rtc user with no capabilities, a read-only system (ProtectSystem=strict, no writable path) and no core dumps.
  • Dependencies. govulncheck reports no vulnerability reachable from go2rtc 1.9.15. This build also raises golang.org/x/net from 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. The version reads 1.9.15+SecureAnyCloud (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, with 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. ffmpeg and its codec libraries come from Ubuntu's community-maintained universe archive. Some universe packages this image needs (ffmpeg and its libraries) receive certain security fixes only through Ubuntu Pro (ESM). Attach the instance to Ubuntu Pro to receive 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. You can also start with just the built-in test pattern

Recommended instance type: m5.large. Passing a camera's H.264 stream through to viewers is light work. 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: go2rtc 1.9.15 on Ubuntu 24.04
  • Operating system: Ubuntu 24.04 LTS
  • SSH user: ubuntu
1

Launch the instance

Option A: AWS Marketplace console

  • Open the SecureAnyCloud Hardened SRS Streaming Media Server & Media Servers AMIs listing on AWS Marketplace. Choose View purchase options, then Subscribe. One subscription covers every version in the listing.
  • When 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.large is recommended; the software charge is $0.04 per vCPU per hour) and your key pair.
  • Configure the 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, because 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 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.

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 under (the public DNS name when there is one), and creates the TLS certificate and the sign-in. It then writes /root/go2rtc-credentials.txt (mode 0600, root).

The file contains the entries below. 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= <set-at-first-boot>= GO2RTC_RTSP_PASSWORD= <set-at-first-boot>= GO2RTC_WEBRTC_ADDRESS= 600 root:root /root/go2rtc-credentials.txt 640 root:go2rtc /etc/go2rtc/secrets.yaml
  • 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 that RTSP clients need once you open RTSP to your network (Step 7)
  • GO2RTC_CERT_SHA256: the fingerprint of this instance's certificate, to check against the browser warning
  • 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.

3

Confirm go2rtc is running

The commands below confirm the following:

  • The network-configuration unit has run and first boot has finished.
  • go2rtc and nginx are active.
  • go2rtc listens on 127.0.0.1:1984 (UI and API), on 127.0.0.1:8554 (RTSP) and on UDP 8555 on the instance's own address.
  • Only sshd and nginx listen on TCP beyond loopback.
systemctl is-active go2rtc-netconf.service go2rtc.service nginx.service ls /var/lib/sac/data/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/sac/data/go2rtc-firstboot.done go2rtc version 1.9.15+sac () 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"))
# sac 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. The image reads it again on every boot, so a stop and start that gives the instance a new public address keeps working.

4

Verify the security defaults

Run the commands below to check that the dashboard and the API:

  • refuse a request that is not signed in or has a wrong password, and accept the instance's sign-in
  • refuse a request that 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. -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.

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 the certificate 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. It is a colour-bar test pattern that ffmpeg generates on the instance, with 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 also 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 SecureAnyCloud built this image, a WebRTC player on a workstation in London pulled the test pattern from an instance in us-east-1 over the internet. It connected to the instance's public address on UDP 8555 and decoded every frame it received.

6

Add your cameras

Streams live in /etc/go2rtc/go2rtc.yaml, with one name per camera and one or more sources for each. Edit the file over SSH, then restart go2rtc. Typical sources look like this. 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. Because configuration editing through the API is off, it is not saved and disappears 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 types 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 that names this instance. The header tells nginx the request is not from another website:

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.

7

Configure 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.service reads 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)

Sometimes viewers should use an address other than the instance's own public address, for example an Elastic IP you move between instances, or a Network Load Balancer that passes UDP 8555 through. In that case, write the address to /etc/sac/go2rtc-public-ip and restart the two units:

echo 203.0.113.10 | sudo tee /etc/sac/go2rtc-public-ip
sudo systemctl restart go2rtc-netconf.service go2rtc.service

STUN. go2rtc itself uses no STUN server, because it already knows its address. Upstream's default asks Google's and Cloudflare's servers. 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/sac.yaml).

RTSP to your network. go2rtc's RTSP server restreams each stream as rtsp://<host>:8554/<name>, for VLC, recorders and NVRs. It 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/sac.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
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. The command creates a new self-signed certificate for the name and pins nginx (and the cross-site guard) to it. It also updates the URL in the credentials file and keeps the name across reboots:

sudo go2rtc-set-hostname cameras.example.com

To use a certificate that browsers trust without a warning, obtain one for that name. For example, use certbot's certonly mode with its own temporary web server, or your organisation's CA. Then 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.

9

Configuration files, credentials and opt-ins

go2rtc reads four files. A later file wins for every setting it contains.

  • /etc/go2rtc/go2rtc.yaml: your streams and settings (the file the Config page shows). You write it.
  • /run/go2rtc/network.yaml: the address advertised for WebRTC. go2rtc-netconf.service writes it on every boot.
  • /etc/go2rtc/sac.yaml: the security baseline: listeners, sign-in mode, modules and the command allow-list. You edit it only to change the security posture.
  • /etc/go2rtc/secrets.yaml: the per-instance credentials. First boot and go2rtc-rotate-credentials write it.

As a result, 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-credentials writes a new user name and password (and RTSP credentials) to the credentials file and restarts go2rtc. The old credentials stop working at once.
  • Configuration editing through the API: sudo go2rtc-config-editing enable lets the Config page and the add page save to go2rtc.yaml (and only that file). sudo go2rtc-config-editing disable turns it off again. While it is on, anyone with the sign-in can change your streams.
  • Command-running sources: to allow echo: sources, add echo to app: modules: in /etc/go2rtc/sac.yaml. To let exec: run other programs, add them to exec: allow_paths:. Then run sudo systemctl restart go2rtc. Anyone with the sign-in can then run those commands as the go2rtc user, so enable this only 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) that the go2rtc user can reach.

You can check the security controls behind these defaults 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/sac.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-required exists. 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: run sudo journalctl -u go2rtc for go2rtc (the dashboard's log page shows the same), and see /var/log/nginx/ for web requests (without query strings).
  • What the instance contacts: go2rtc contacts only the cameras and sources you configure. The image was 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.
  • What the browser loads: a few dashboard pages load helper scripts from the public cdn.jsdelivr.net CDN (the Config page's editor and 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 and any network ACL. Also check that sudo cat /run/go2rtc/network.yaml shows an address your viewers can reach (Step 7).
  • The browser keeps asking for the password: use GO2RTC_USER and GO2RTC_PASSWORD from the credentials file. After go2rtc-rotate-credentials, use the new values.
  • 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.
  • The browser shows "connection closed": nginx answers only the configured name and the instance's own addresses. Use GO2RTC_URL, or run sudo go2rtc-set-hostname <name> to set a new name.
  • The end-to-end check: sudo go2rtc-selftest checks the sign-in, the cross-site protection, the test pattern, the refused configuration editing and command sources, and the listening ports. It prints GO2RTC-SELFTEST OK when 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.

SecureAnyCloud is not affiliated with, endorsed by or sponsored by the go2rtc project or its author.

Support

SecureAnyCloud provides 24/7 technical support for this image by email and live chat. Support covers deployment, first sign-in, HTTPS and DNS setup, camera network configuration and troubleshooting. Contact sales@secureanycloud.com.

Deploy on AWS

Launch go2rtc 1.9.15 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

Deploy on AWS