Streaming & Messaging AWS

go2rtc on AWS User Guide

| Product: go2rtc 1.9.14 on Ubuntu 24.04 LTS on AWS

Overview

go2rtc is an ultra low latency camera streaming application and restreaming gateway. It connects to your cameras and video sources over the protocols they speak, RTSP, ONVIF, RTMP, HTTP and USB, and republishes each stream over whatever protocol the viewer needs: WebRTC for sub second latency in a browser, Media Source Extensions, HLS, MJPEG and RTSP. It is a single self contained Go binary with no database, driven by one readable configuration file, so a working streaming gateway is answering within minutes of launch.

The cloudimg image installs go2rtc 1.9.14 and puts it behind an nginx TLS reverse proxy that binds go2rtc to loopback. The appliance is secure by default. Upstream go2rtc ships with its web interface and API completely open, which is unsafe on any network, so this image closes that gap. go2rtc binds only to the local host, sits behind nginx on port 443, and its api.local_auth setting forces HTTP Basic authentication on every request, including the loopback requests the proxy makes. There is no default or shared login. On first boot go2rtc-firstboot.service generates a unique username and password, renders them into the configuration, writes the plaintext once to a root only file at /root/go2rtc-credentials.txt, and regenerates a per instance self signed TLS certificate. Nothing is baked into the image.

To show the pipeline working on first boot, the image ships a demonstration stream: a self contained ffmpeg test pattern that needs no camera hardware, transcoded to H.264 so it plays over WebRTC, MSE and HLS and yields JPEG snapshots the moment you sign in. This is demo data only, and Step 10 and Step 11 show you how to add your own cameras.

What is included:

  • go2rtc 1.9.14 single Go binary (/opt/go2rtc/go2rtc)
  • One readable configuration file (/etc/go2rtc/go2rtc.yaml), no database to maintain
  • go2rtc.service running as the unprivileged go2rtc user, with the web UI and API bound to loopback 127.0.0.1:1984
  • The RTSP restream server on TCP 8554 and WebRTC media on 8555 (with automatic public address discovery via STUN)
  • nginx.service reverse proxy terminating TLS on 443, with the whole UI and API behind HTTP Basic auth, a WebSocket upgrade for browser playback, an unauthenticated /healthz endpoint, and a 301 redirect from port 80
  • A self contained demonstration stream so the dashboard is populated on first boot (demo data only)
  • go2rtc-firstboot.service generating a per instance UI/API credential and TLS certificate on first boot
  • Ubuntu 24.04 LTS base, latest patches, unattended security upgrades enabled
  • 24/7 cloudimg support, 24h response SLA

Prerequisites

An active AWS account, an EC2 key pair in your target region, and a VPC with a subnet. Recommended instance type: m5.large (2 vCPU, 8 GB RAM). go2rtc is light; larger sizes only help when you transcode many simultaneous high resolution streams.

You also need a security group. go2rtc uses these ports:

Port Protocol Purpose
22 TCP SSH management
443 TCP HTTPS web UI and REST API (nginx TLS reverse proxy)
8554 TCP RTSP restream server (pull ingested streams back out over RTSP)
8555 TCP and UDP WebRTC media (low latency browser playback)

Open each port only to the client networks that need it. The go2rtc API on port 1984 is bound to loopback and is never exposed directly. RTSP port 554 is used outbound when go2rtc pulls from your cameras, so it is not a security group inbound rule.

Step 1: Launch the Instance from the AWS Marketplace

Find the cloudimg go2rtc listing on AWS Marketplace, choose Continue to Subscribe, then Continue to Configuration and Continue to Launch. Select the m5.large instance type, your VPC and subnet, your EC2 key pair, and a security group that opens the ports in the table above. Launch the instance and note its public IPv4 address once it is running.

Step 2: Launch the Instance from the AWS CLI

The following block launches an instance from the cloudimg go2rtc Marketplace AMI into an existing subnet and security group. Replace <ami-id> with the AMI ID shown on the Marketplace listing, <key-name> with your EC2 key pair name, <subnet-id> with your subnet ID, and <security-group-id> with a security group that opens ports 22, 443, 8554 and 8555 as described above.

aws ec2 run-instances \
  --image-id <ami-id> \
  --instance-type m5.large \
  --key-name <key-name> \
  --subnet-id <subnet-id> \
  --security-group-ids <security-group-id> \
  --block-device-mappings '[{"DeviceName":"/dev/sda1","Ebs":{"VolumeSize":16,"VolumeType":"gp3"}}]' \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=go2rtc-01}]'

The command prints a JSON document on success. Note the instance ID, then retrieve its public address once it is running with aws ec2 describe-instances --instance-ids <instance-id> --query "Reservations[].Instances[].PublicIpAddress" --output text.

Step 3: Connect via SSH

Connect over SSH with the key pair you selected and the public IPv4 address from Step 2. The SSH login user depends on the operating system of the AMI variant you launched:

AMI variant SSH login user
go2rtc 1.9.14 on Ubuntu 24.04 ubuntu
ssh <login-user>@<public-ip>

go2rtc.service, nginx.service and go2rtc-firstboot.service all start automatically on first boot, so the credentials file is always in place when you log in for the first time.

Step 4: Verify the Service

sudo systemctl is-active go2rtc nginx go2rtc-firstboot
sudo test -f /var/lib/cloudimg/go2rtc-firstboot.done && echo FIRSTBOOT_DONE
sudo ss -tlnp | grep -E ':443 |:1984 |:8554 |:8555 ' | sed 's/users:.*/users:.../'

The services are active, nginx is bound to the public port 443, go2rtc's API is bound to loopback 127.0.0.1:1984 only, and the RTSP and WebRTC ports are listening:

active
active
active
FIRSTBOOT_DONE
LISTEN 0      4096       127.0.0.1:1984      0.0.0.0:*    users:...
LISTEN 0      511          0.0.0.0:443       0.0.0.0:*    users:...
LISTEN 0      4096               *:8554            *:*    users:...
LISTEN 0      4096               *:8555            *:*    users:...

go2rtc, nginx and the firstboot service all active, with nginx bound to public port 443, the go2rtc API bound to loopback 127.0.0.1:1984 only, and the RTSP 8554 and WebRTC 8555 ports listening

Step 5: Get Your UI Credentials

go2rtc has no default login. On first boot a unique username and password are generated, rendered into the configuration and written to a root only note, so there is no usable credential baked into the image. The following block confirms the note exists with 0600 root:root permissions and shows the URL, username and host without printing the password:

sudo stat -c '%a %U:%G %n' /root/go2rtc-credentials.txt
sudo grep -E '^(GO2RTC_URL|go2rtc.username|go2rtc.host)=' /root/go2rtc-credentials.txt

The note is root only and carries the per instance URL, username and host:

600 root:root /root/go2rtc-credentials.txt
GO2RTC_URL=https://<public-ip>/
go2rtc.username=admin_<random>
go2rtc.host=<public-ip>

To read the password itself, run sudo cat /root/go2rtc-credentials.txt on the instance. Keep this file readable only by root.

The per instance credentials note is mode 0600 root only, and go2rtc binds the API to loopback with local_auth true so Basic auth is forced on every request

Step 6: Verify the Auth Round-Trip

The /healthz endpoint is public for liveness checks, but the web UI and the entire API require the per instance credential, even over loopback. Prove it end to end over TLS without ever printing your password:

UN=$(sudo grep '^go2rtc.username=' /root/go2rtc-credentials.txt | cut -d= -f2-)
PW=$(sudo grep '^go2rtc.password=' /root/go2rtc-credentials.txt | cut -d= -f2-)
curl -sk -o /dev/null -w 'GET /healthz            -> HTTP %{http_code}\n' https://127.0.0.1/healthz
curl -sk -o /dev/null -w 'GET /api (no creds)     -> HTTP %{http_code}\n' https://127.0.0.1/api
curl -sk -o /dev/null -w 'GET /api (per-instance) -> HTTP %{http_code}\n' -u "$UN:$PW" https://127.0.0.1/api

The health endpoint answers 200, the API is refused without credentials, and the per instance credential signs you in:

GET /healthz            -> HTTP 200
GET /api (no creds)     -> HTTP 401
GET /api (per-instance) -> HTTP 200

Step 7: Open the Stream Dashboard

Open the web UI in a browser at https://<public-ip>/ and sign in with the username and password from Step 5. Your browser shows a certificate warning the first time because the certificate is self signed and unique to this instance; accept it, or add a real certificate in Step 16. The dashboard lists every configured stream, its online state, and one click links to view it, copy its protocol URLs, or inspect it:

The go2rtc web dashboard signed in, listing the demo stream with its online state, the WebRTC, MSE, HLS and MJPEG mode toggles, and stream, links and delete actions

Step 8: Watch the Live Stream

Click stream next to the demo stream to open the player. go2rtc negotiates the lowest latency protocol the browser supports, WebRTC first, then Media Source Extensions, so the demonstration test pattern plays live in the browser. WebRTC playback uses port 8555, so make sure your security group allows TCP and UDP 8555 from your client network:

The go2rtc live viewer playing the demonstration test pattern stream in the browser over WebRTC, with the RTC indicator showing the active low latency protocol

Step 9: Copy the Stream Links

Click links next to a stream to see every way to consume it: WebRTC and MSE for browsers, HLS for Apple devices, MJPEG and a frame.jpeg snapshot, an stream.mp4 recording URL, and the raw rtsp:// restream address with a ready to paste ffplay command. This is how you embed a stream in your own page or wire it into another tool:

The go2rtc stream links page listing every protocol URL for the demo stream: WebRTC and MSE via stream.html, HLS, MJPEG, a frame.jpeg snapshot, an MP4 recording URL, and the raw RTSP restream address with an ffplay command

Step 10: Add a Camera in the Web UI

Click add in the top navigation to open the add source page. go2rtc can ingest a wide range of cameras and platforms: RTSP and ONVIF network cameras, USB and V4L2 devices, and integrations such as Apple HomeKit, Google Nest, Ring, Tuya and Home Assistant. Pick your source type and follow the prompts, and go2rtc writes the new stream into /etc/go2rtc/go2rtc.yaml for you:

The go2rtc add source page listing the supported camera and platform integrations including RTSP, ONVIF, FFmpeg devices, USB, Apple HomeKit and Google Nest

Step 11: Add a Camera in the Config File

You can also edit the configuration directly. Each entry under streams is a name mapped to one or more sources. Add your camera's RTSP URL (most IP cameras expose one) alongside the demo stream:

streams:
  demo: "ffmpeg:virtual?video&size=1280x720#video=h264"
  front_door: rtsp://<camera-username>:<camera-password>@<camera-ip>:554/stream1

After editing /etc/go2rtc/go2rtc.yaml, apply the change and reload the dashboard in your browser:

sudo systemctl restart go2rtc.service

go2rtc connects to the camera on demand when a viewer opens the stream, and republishes it over WebRTC, MSE, HLS, MJPEG and RTSP without you touching the camera again.

Step 12: Server Components

Component Path
go2rtc binary /opt/go2rtc/go2rtc
Configuration /etc/go2rtc/go2rtc.yaml
Configuration template (for firstboot) /etc/go2rtc/go2rtc.yaml.template
Systemd unit /etc/systemd/system/go2rtc.service
Firstboot script /usr/local/sbin/go2rtc-firstboot.sh
nginx TLS reverse proxy /etc/nginx/sites-available/cloudimg-go2rtc
Self signed TLS certificate /etc/nginx/tls/go2rtc.crt
Per instance credentials note /root/go2rtc-credentials.txt (mode 0600)
Sentinel /var/lib/cloudimg/go2rtc-firstboot.done
/opt/go2rtc/go2rtc --version
sudo ls /opt/go2rtc/go2rtc /etc/go2rtc/go2rtc.yaml /etc/systemd/system/go2rtc.service
UN=$(sudo grep '^go2rtc.username=' /root/go2rtc-credentials.txt | cut -d= -f2-)
PW=$(sudo grep '^go2rtc.password=' /root/go2rtc-credentials.txt | cut -d= -f2-)
curl -sk -u "$UN:$PW" https://127.0.0.1/api/streams | jq 'keys'

go2rtc reports version 1.9.14, the component paths exist, and the API lists the configured streams:

go2rtc version 1.9.14 (b5948cf) linux/amd64
/etc/go2rtc/go2rtc.yaml
/etc/systemd/system/go2rtc.service
/opt/go2rtc/go2rtc
[
  "demo"
]

Step 13: Managing the Service

sudo systemctl restart go2rtc.service
sudo journalctl -u go2rtc.service --no-pager -n 20

go2rtc restarts in well under a second because it is a single binary with no database. The service is hardened with NoNewPrivileges, ProtectSystem=full, ProtectHome and PrivateTmp, and is only granted write access to its own configuration directory so the web UI can persist streams you add.

Step 14: Configuration

go2rtc is configured entirely through /etc/go2rtc/go2rtc.yaml. The key sections set by this image:

Section Meaning Image default
api.listen Web UI and API bind address 127.0.0.1:1984 (loopback)
api.local_auth Force Basic auth on every request true
api.username / api.password Per instance credential (generated at first boot) unique per instance
rtsp.listen RTSP restream server :8554
webrtc.listen WebRTC media :8555
webrtc.candidates Public address discovery stun:8555
streams Named streams and their sources the demo stream

After editing the file, apply changes by restarting the go2rtc service. nginx is the sole public listener and terminates TLS; go2rtc never binds a public port for its UI.

Step 15: Change the UI Password

The credential is generated per instance at first boot. To set your own, edit api.username and api.password in the configuration and restart go2rtc (replace <new-password>):

sudo sed -i 's/^  password:.*/  password: "<new-password>"/' /etc/go2rtc/go2rtc.yaml
sudo systemctl restart go2rtc.service

Update /root/go2rtc-credentials.txt to match so your note stays accurate, and keep that file readable only by root.

Step 16: Add a Real TLS Certificate (Optional)

The image ships a per instance self signed certificate so the UI is encrypted out of the box. For production, point a DNS record at the instance and install a certificate from Let's Encrypt so browsers trust it without a warning:

sudo apt-get install -y certbot
sudo certbot certonly --standalone -d <your-domain>
sudo sed -i 's#/etc/nginx/tls/go2rtc.crt#/etc/letsencrypt/live/<your-domain>/fullchain.pem#; s#/etc/nginx/tls/go2rtc.key#/etc/letsencrypt/live/<your-domain>/privkey.pem#' /etc/nginx/sites-available/cloudimg-go2rtc
sudo systemctl reload nginx

certbot obtains the certificate and sets up automatic renewal, so your credentials and streams travel over a trusted TLS connection.

Step 17: Security Recommendations

  • Restrict the security group so ports 443, 22 and the streaming ports only reach trusted networks. Do not expose an unauthenticated camera gateway to the public internet.
  • Keep the API on loopback: the image binds go2rtc to 127.0.0.1 behind nginx. Do not expose port 1984 directly.
  • Change the credential (Step 15) and keep the note /root/go2rtc-credentials.txt readable only by root.
  • Use a real certificate (Step 16) so the per instance credential and your camera streams travel over trusted TLS.
  • Secure your cameras too: give each camera its own account, and restrict which networks can reach the RTSP and WebRTC ports.
  • Patch the OS regularly with sudo apt-get update && sudo apt-get upgrade; unattended security upgrades are already enabled.

Step 18: Support and Licensing

go2rtc is MIT licensed — no per CPU or per user fee. cloudimg provides commercial support separately.

  • Email: support@cloudimg.co.uk
  • Website: www.cloudimg.co.uk
  • Support hours: 24/7, 24h response SLA

Support

cloudimg provides 24/7/365 expert technical support for this image. Guaranteed response within 24 hours, one hour average for critical issues. Contact support@cloudimg.co.uk.

For general go2rtc questions consult the project documentation at https://github.com/AlexxIT/go2rtc. go2rtc is a trademark of its respective owner; use here is nominative and does not imply affiliation or endorsement.