Ant Media Server Community 3.1.0 on AWS User Guide
Overview
This guide covers launching and using the Ant Media Server Community 3.1.0 on Ubuntu 24.04 AMI from cloudimg on Amazon EC2. It is one version of the cloudimg media servers listing on AWS Marketplace; you pick it as the software version when you subscribe and launch.
Ant Media Server is a self hosted live streaming engine. The Community Edition takes live video in over RTMP (OBS, vMix, Wirecast, ffmpeg, hardware encoders) and over WebRTC from a browser, pulls IP cameras and other stream sources, and plays everything back as HLS in any browser or player. It records live streams to MP4, serves recordings and uploaded files as video on demand, and is managed from a web panel and a REST API. WebRTC playback, adaptive bitrate and DASH are Enterprise Edition features and are not part of this image.
Upstream Ant Media Server listens for its panel on plain HTTP port 5080 on every interface, lets the first visitor to a fresh server create the administrator, and accepts a publish to any stream name. The cloudimg image turns that around:
- HTTPS from the first boot. nginx serves the panel, the REST API, WebRTC signalling and HLS on port 443 with a certificate generated on your instance's first boot. Port 80 redirects to HTTPS. Ant Media Server's own HTTP port listens on
127.0.0.1only. - No open first run signup. The administrator is created on first boot, over the loopback interface, before nginx starts. Its password is unique to your instance and written to
/root/ant-media-server-credentials.txt. The first admin endpoint is closed afterwards. - Secrets unique to your instance. The cluster communication key, subscriber authentication key, JWT keys, hash token secret and time token secrets of every bundled application, and the server JWT key, are generated on first boot. None is baked into the image, and Ant Media Server refuses to start until first boot has written them.
- REST API limited to the instance itself. The application REST API only answers requests from the instance. nginx passes the real client address to Ant Media Server, so a request from anywhere else is refused, even one carrying a forged
X-Forwarded-Forheader. The panel's own REST calls need a signed in session. - Publishing only to streams you create. A publish to a stream id that does not exist yet is refused, so nobody can use your server to relay their own streams.
- Hardened defaults. Ant Media Server runs as its own unprivileged user in a systemd sandbox; Ant Media Server and nginx are blocked from the instance metadata service, so a stream source, IP camera or webhook URL cannot reach your instance's credentials; cross site requests and cross site WebSocket connections are refused; vendor heartbeat telemetry is off; the AMI requires IMDSv2.
- Fully patched Ubuntu 24.04 LTS at build time, with unattended security upgrades switched on.
What is on the image: Ant Media Server Community Edition 3.1.0 (the official release, unmodified, Apache License 2.0), OpenJDK 21, nginx, Ubuntu 24.04 LTS, cloud-init and the AWS Systems Manager agent.
Default user: ubuntu · Architecture: x86_64 · Recommended instance type: m5.large
Prerequisites
- An AWS account subscribed to the listing, an EC2 key pair and a VPC subnet with a route to the internet.
- A security group that allows:
- TCP 22 (SSH) from your own networks only
- TCP 443 (panel, REST API, WebRTC signalling and HLS playback) from your administrators and viewers, usually anywhere
- TCP 80 (redirects to HTTPS) from the same sources as 443
- TCP 1935 (RTMP ingest) from your broadcasters' networks
- UDP 50001 to 60000 (WebRTC media for browser publishing) from your broadcasters' networks
Ant Media Server's own HTTP port (5080) stays on loopback and never needs opening. Live transcoding is not part of the Community Edition, so CPU is mostly spent on packaging: an m5.large handles several 720p streams comfortably. Outbound bandwidth is the main sizing question for HLS viewers.
Step 1: Launch the instance
In the AWS Marketplace listing choose Continue to Subscribe, then Continue to Configuration, pick Ant Media Server Community 3.1.0 on Ubuntu 24.04 as the software version and your Region, then Launch through EC2. Choose m5.large, your key pair and a security group as above.
With the AWS CLI (replace the values in angle brackets):
aws ec2 run-instances --region <region> --image-id <ami-id-from-the-listing> \
--instance-type m5.large --key-name <your-key-pair> \
--security-group-ids <your-security-group> --subnet-id <your-subnet> \
--metadata-options HttpTokens=required,HttpEndpoint=enabled \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=ant-media-server}]'
Step 2: Connect to your instance
| Version | SSH user |
|---|---|
| Ant Media Server Community 3.1.0 on Ubuntu 24.04 | ubuntu |
ssh -i <your-key.pem> ubuntu@<public-ip>
Step 3: Check the services
First boot generates the certificate and the secrets, starts Ant Media Server, creates the administrator over loopback and only then starts nginx. This takes about a minute after the instance is reachable:
systemctl is-active antmedia nginx ant-media-server-firstboot ant-media-server-admin
sudo test -f /var/lib/cloudimg/ant-media-server-firstboot.done && echo FIRSTBOOT_DONE
All four units are active and the first boot marker is present:
active
active
active
active
FIRSTBOOT_DONE
nginx (80 and 443) and the RTMP listener (1935) are the only services on public addresses; Ant Media Server's HTTP and shutdown ports are on loopback:
sudo ss -lntp | awk 'NR>1 {print $4, $6}' | sed -E 's/pid=[0-9]+,fd=[0-9]+/.../g' | sort
0.0.0.0:1935 users:(("java",...))
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:5080 users:(("java",...))
127.0.0.1:9999 users:(("java",...))
127.0.0.53%lo:53 users:(("systemd-resolve",...))
127.0.0.54:53 users:(("systemd-resolve",...))
[::]:22 users:(("sshd",...),("systemd",...))
WebRTC media ports in the 50001 to 60000 UDP range are opened per session while a browser is publishing, so none is listed while the server is idle.
Step 4: Get your URL and password
sudo cat /root/ant-media-server-credentials.txt
The file is readable by root only:
# Ant Media Server Community 3.1.0 - generated on first boot (ant-media-server-admin.service)
# This admin password is unique to this instance; no admin account was baked into the image. Keep this file secret.
AMS_URL=https://ec2-<public-ip-dashed>.<region>.compute.amazonaws.com/
AMS_ADMIN_USER=admin@cloudimg.local
AMS_ADMIN_PASSWORD=<AMS_ADMIN_PASSWORD>
AMS_RTMP_URL=rtmp://ec2-<public-ip-dashed>.<region>.compute.amazonaws.com/LiveApp
AMS_URLis the management panel. Sign in withAMS_ADMIN_USER(an e-mail style user name) andAMS_ADMIN_PASSWORD.AMS_RTMP_URLis the RTMP server address for your encoder; the stream key is the stream id you create in Step 7.
The URLs use the instance's public DNS name from EC2 instance metadata. The certificate also names the public and private IP addresses, so https://<public-ip>/ works too. To use your own DNS name, see Step 11. When you need to share the file, for example in a support request, print it with the password masked:
sudo sed -E 's/^(AMS_ADMIN_PASSWORD=).*/\1********/' /root/ant-media-server-credentials.txt | grep -E '^AMS_'
Step 5: Check the server from the command line
Port 80 redirects to HTTPS, the health check is open for load balancers, and the panel answers over HTTPS:
H=$(sudo grep '^AMS_URL=' /root/ant-media-server-credentials.txt | sed -E 's#^AMS_URL=https://([^/]+)/.*#\1#')
curl -s -o /dev/null -w 'http:// -> %{http_code} %{redirect_url}\n' --resolve "$H:80:127.0.0.1" "http://$H/"
curl -sk -o /dev/null -w 'healthz -> HTTP %{http_code}\n' --resolve "$H:443:127.0.0.1" "https://$H/healthz"
curl -sk -o /dev/null -w 'panel -> HTTP %{http_code}\n' --resolve "$H:443:127.0.0.1" "https://$H/"
http:// -> 301 https://ec2-<public-ip-dashed>.<region>.compute.amazonaws.com/
healthz -> HTTP 200
panel -> HTTP 200
The image includes a sign in check. It signs in through nginx exactly as the panel does, confirms that a blank password and the guess admin are rejected, that the first admin endpoint is closed, and that the application REST API refuses a client that is not the instance itself. The password travels on standard input only:
sudo ant-media-server-cred-roundtrip.sh
OK per-instance admin authenticates via nginx (panel md5 path); blank + 'admin' rejected; users/initial 403; app REST 403 to a remote client with forged XFF
Step 6: Sign in to the management panel
Open AMS_URL in your browser. The certificate is self signed, so your browser asks you to confirm it the first time (or install your own, Step 11). Sign in with the user name and password from Step 4. The Classic panel is the default; the New UI switch opens the beta of the new panel:

The Dashboard shows CPU, disk, system memory and Java heap use, the number of live streams and the applications on the server. The image ships with the three standard applications: LiveApp, WebRTCApp and live:

To add more panel users, open Settings, then Users.
Step 7: Create a stream
Because publishing to an unknown stream id is refused, create the stream first. In the panel open LiveApp, choose New Live Stream, give it a name and note the Stream Id it shows. Or create it with the REST API from the instance itself, where the API answers without a session:
curl -s -H 'Content-Type: application/json' \
-d '{"streamId":"my-first-stream","name":"My first stream"}' \
http://127.0.0.1:5080/LiveApp/rest/v2/broadcasts/create | jq -r '"\(.streamId) \(.status)"'
my-first-stream created
The stream is listed with status created until an encoder connects, then broadcasting:
curl -s http://127.0.0.1:5080/LiveApp/rest/v2/broadcasts/list/0/10 | jq -r '.[] | "\(.streamId) \(.status)"'
my-first-stream created
Step 8: Publish from your encoder
The encoder runs on your machine. In OBS Studio open Settings, Stream, choose Custom and enter:
Server : rtmp://<your-host>/LiveApp (the AMS_RTMP_URL value)
Stream Key : my-first-stream (the stream id from Step 7)
vMix, Wirecast and hardware encoders take the same two values. With ffmpeg, for example to send a test pattern:
ffmpeg -re -f lavfi -i testsrc2=size=1280x720:rate=30 -f lavfi -i sine=frequency=440 \
-c:v libx264 -preset veryfast -tune zerolatency -g 60 -b:v 2000k -c:a aac -b:a 128k \
-f flv rtmp://<your-host>/LiveApp/my-first-stream
A publish to a stream id you have not created is refused: the encoder reports a connection or I/O error. Once connected, the stream shows Broadcasting in the panel:

To publish from a browser over WebRTC instead, create the stream, then open https://<your-host>/LiveApp/index.html, allow the camera, enter the stream id and select Start Publishing. WebRTC media uses the UDP 50001 to 60000 range from Prerequisites.
Step 9: Watch the stream
Every live stream is packaged as HLS under the application:
HLS playlist : https://<your-host>/LiveApp/streams/my-first-stream.m3u8
Web player : https://<your-host>/LiveApp/play.html?id=my-first-stream&playOrder=hls
The playlist plays in Safari, VLC, ffplay and any HLS capable player. The web player page plays it in any browser and can be embedded in your own site with an <iframe>:

Each application's Settings tab controls HLS segment length and list size, MP4 recording, VoD and the security options. On this image Accept Undefined Streams is off and the REST API IP filter allows only the instance itself:

Remove the test stream when you are done:
curl -s -X DELETE http://127.0.0.1:5080/LiveApp/rest/v2/broadcasts/my-first-stream | jq -r .success
true
Step 10: Use the REST API from elsewhere
The application REST API answers only the instance itself. Run automation on the instance, reach it through an SSH tunnel (ssh -i <your-key.pem> -L 5080:127.0.0.1:5080 ubuntu@<public-ip>, then call http://127.0.0.1:5080/LiveApp/rest/v2/... on your machine), or allow your automation host's address in the application's Settings, under REST API Security, with a CIDR such as 203.0.113.10/32. Prefer the tunnel or a narrow CIDR over opening the filter: the REST API can create stream sources, change settings and delete content.
Step 11: Use your own DNS name and certificate
Point a DNS record at the instance (an Elastic IP keeps the address stable), then tell the instance its name. This regenerates the self signed certificate for that name, updates the allowed origins and the credentials file, and reloads nginx:
sudo ams-set-hostname media.your-domain.example
To use a certificate from a public CA instead, replace /etc/ssl/ant-media/ams.crt (full chain) and /etc/ssl/ant-media/ams.key (mode 0600) and run sudo systemctl reload nginx.
Browsers may only open WebRTC WebSockets and send state changing requests from the instance's own names. If you embed the WebRTC publisher in another site, list that site's origin (for example https://www.your-domain.example) in /etc/cloudimg/ams-allowed-origins and run sudo ams-set-hostname again with your host name.
Step 12: Security checks
The application REST API answers the instance itself and refuses every other address, including a request carrying a forged X-Forwarded-For header:
H=$(sudo grep '^AMS_URL=' /root/ant-media-server-credentials.txt | sed -E 's#^AMS_URL=https://([^/]+)/.*#\1#')
TOKEN=$(curl -s -X PUT http://169.254.169.254/latest/api/token -H 'X-aws-ec2-metadata-token-ttl-seconds: 60')
PRIV=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/local-ipv4)
curl -sk -o /dev/null -w 'REST API from this instance -> HTTP %{http_code}\n' --resolve "$H:443:127.0.0.1" "https://$H/LiveApp/rest/v2/broadcasts/list/0/10"
curl -sk -o /dev/null -w 'REST API from another address -> HTTP %{http_code}\n' --resolve "$H:443:$PRIV" "https://$H/LiveApp/rest/v2/broadcasts/list/0/10"
curl -sk -o /dev/null -w 'same, with a forged X-Forwarded-For -> HTTP %{http_code}\n' --resolve "$H:443:$PRIV" -H 'X-Forwarded-For: 127.0.0.1' "https://$H/LiveApp/rest/v2/broadcasts/list/0/10"
REST API from this instance -> HTTP 200
REST API from another address -> HTTP 403
same, with a forged X-Forwarded-For -> HTTP 403
No placeholder secret is left: every key in the server and application configuration is this instance's own. The HTTP connector is on loopback, vendor heartbeat telemetry is off, undefined streams are refused and the upstream JMX keystore is gone:
if sudo grep -q CLOUDIMG_SET_ON_FIRSTBOOT /usr/local/antmedia/conf/red5.properties /usr/local/antmedia/webapps/*/WEB-INF/red5-web.properties; then
echo "a placeholder secret is still present"; exit 1
else
echo "no placeholder secret: every key is this instance's own"
fi
sudo grep -hE '^(http.host|server.heartbeatEnabled)=' /usr/local/antmedia/conf/red5.properties
sudo grep -hE '^(acceptOnlyStreamsInDataStore|remoteAllowedCIDR)=' /usr/local/antmedia/webapps/LiveApp/WEB-INF/red5-web.properties
ls /usr/local/antmedia/conf/keystore.jmx 2>/dev/null || echo "no shipped JMX keystore"
no placeholder secret: every key is this instance's own
server.heartbeatEnabled=false
http.host=127.0.0.1
acceptOnlyStreamsInDataStore=true
remoteAllowedCIDR=127.0.0.1
no shipped JMX keystore
Ant Media Server and nginx are blocked from the instance metadata service, so nothing Ant Media Server fetches (stream sources, IP cameras, playlists, webhooks) can reach your instance's credentials:
systemctl show antmedia nginx -p IPAddressDeny --value
169.254.169.254/32 fd00:ec2::254/128 168.63.129.16/32
169.254.169.254/32 fd00:ec2::254/128 168.63.129.16/32
Maintenance
- Configuration: server settings in
/usr/local/antmedia/conf/red5.properties, application settings in/usr/local/antmedia/webapps/<app>/WEB-INF/red5-web.properties. Settings you save in the panel are written to these files. Apply hand edits withsudo systemctl restart antmedia. Keephttp.host=127.0.0.1: nginx publishes the panel on 443. - Changing the admin password: sign in, open the user menu at the top right and change it there, then update
/root/ant-media-server-credentials.txt. First boot runs only once, so it never overwrites your changes. - Telemetry: heartbeat telemetry is off. Upstream Ant Media Server also reports the admin e-mail address and an instance id to antmedia.io when the first admin is created and when someone signs in to the panel; the image uses the neutral address
admin@cloudimg.localfor that reason. Block outbound access to antmedia.io in your security group or network firewall if you prefer; streaming is not affected. - Logs: Ant Media Server in
/var/log/antmedia/, nginx (with the real client addresses) in/var/log/nginx/. - Backups: the datastores (
/usr/local/antmedia/*.db), the configuration files above and any recordings in/usr/local/antmedia/webapps/<app>/streams/. For large recording volumes, attach and mount a separate EBS volume there. - Security updates: unattended security upgrades are on. Reboot when a new kernel is installed. Ant Media Server upgrades come from the upstream release; review the release notes before upgrading.
Support
cloudimg provides 24/7/365 expert technical support for this image. Contact support@cloudimg.co.uk. Ant Media Server Community Edition is developed by Ant Media and licensed under the Apache License 2.0; the licence text is in /usr/share/doc/ant-media-server/ and the source is at github.com/ant-media/Ant-Media-Server. This image is provided by cloudimg and is not affiliated with or endorsed by Ant Media.