
Build a persistent Oryx media server locally, verify it, and publish its web interface without router port forwarding
Oryx is an open-source, all-in-one video platform for live streaming, WebRTC, recording, transcoding, virtual live events, and related media workflows. In this guide, we install Oryx as a single Docker container, preserve its state on the host, verify the browser interface, and cover routine container operations and common startup problems. Once the local service works, we connect its HTTP endpoint to Localtonet as a separate remote-access step. The HTTP tunnel exposes the web service only, so RTMP, WebRTC media, and SRT require their own protocol-appropriate configurations.
๐ What's in this guide
What we are building
Oryx, formerly called SRS Stack, is an open-source video solution built with components including Go, React, SRS, FFmpeg, WebRTC, and Redis. It combines a browser-based management experience with media ingestion, playback, recording, forwarding, transcoding, and virtual-live capabilities. Its supported streaming protocols include RTMP, WebRTC, HLS, HTTP-FLV, and SRT.
The documented Docker deployment runs these components together in one container. Docker publishes selected container ports on the host, while a bind-mounted /data directory keeps Oryx configuration and generated data outside the container. After startup, the documented local management endpoint is http://localhost.
Remote access is intentionally a second phase of this guide. We first make Oryx work on the host itself. We then configure a Localtonet HTTP tunnel whose local target is the published HTTP port. The Localtonet client establishes an outbound connection to one of our relay servers, so this workflow does not require an inbound router port-forwarding rule, a public IP address, VPN setup, or an inbound firewall change.
ossrs/oryx:5 image and publishes the web and media ports required by the documented feature set.
/data directory is mounted to a host directory. This prevents configuration and media data from disappearing merely because the container restarts or is replaced.
How traffic reaches Oryx
In the supplied Docker command, requests sent to host TCP port 80 are forwarded to container TCP port 2022. That is why opening http://localhost reaches Oryx even though its internal HTTP listener is on port 2022. The same principle applies to the other published ports.
| Host port | Container port | Transport | Purpose |
|---|---|---|---|
80 |
2022 |
TCP | Oryx HTTP interface and HTTP-based services |
443 |
2443 |
TCP | Oryx HTTPS service |
1935 |
1935 |
TCP | RTMP stream publishing |
8000 |
8000 |
UDP | WebRTC media traffic such as RTP packets |
10080 |
10080 |
UDP | SRT stream publishing |
The Localtonet portion of this guide publishes the service listening on host TCP port 80. RTMP uses raw TCP, while the documented WebRTC media and SRT listeners use UDP. Those protocols do not travel through the same HTTP tunnel. If a deployment requires remote RTMP or UDP transport, evaluate and configure a matching Localtonet TCP or UDP tunnel separately.
Prerequisites and deployment decisions
Prepare a host on which Docker is installed and the Docker service is running. Oryx documentation strongly recommends Docker and advises choosing Ubuntu 20 for the documented environment because other systems may encounter issues. The project also documents other installation paths, including Helm, an Ubuntu archive, cloud marketplace options, and an aaPanel plugin, but this tutorial is deliberately scoped to the single-container Docker workflow.
You also need permission to create a persistent directory and bind to the selected host ports. On many systems, ports below 1024, including 80 and 443, can require elevated privileges or Docker daemon access. Existing web servers, reverse proxies, or other containers may already occupy those ports.
Before installation, decide where Oryx data should live. The official command uses $HOME/data, which resolves to a data directory under the current user's home directory. You may replace it with a different suitable host directory, but it must remain mapped to /data inside the container.
What Oryx stores under /data
The persistent data tree can include configuration, Redis data, recordings, uploads, virtual-live files, transcription data, cache files, ACME challenge material, and other application state. Documented directories include config, dvr, record, redis, signals, upload, vlive, transcript, nginx-cache, and srs-s3-bucket.
The config directory contains Oryx configuration and SSL-related files, while the redis directory contains Redis data such as publishing secrets and recording configuration. Recording and uploaded media can consume substantial disk capacity, so choose a filesystem with enough room for the intended workload and monitor its usage over time.
Oryx explicitly warns that /data should be mounted to a host location. Without that mount, application data remains in the container's writable layer and can be lost when the container is removed or replaced. A restart policy does not replace persistent storage.
Check for port conflicts before starting
The default command claims host ports 80, 443, 1935, 8000/udp, and 10080/udp. If another process already uses one of them, Docker will normally fail to publish that port and the Oryx container may not start successfully.
Oryx explicitly permits publishing the HTTP listener on host port 2022 instead of port 80, using -p 2022:2022. It similarly permits host port 2443 for the container's HTTPS listener. If you select alternate host ports, remember that local verification and the Localtonet target must use those host-side values.
Install Oryx with Docker

The following process follows the project's documented Docker quick start. Run the command on the machine that will host the media server. Shell syntax shown here is suitable for a Linux-style shell in which $HOME refers to the current user's home directory.
Confirm Docker is available
Verify that the Docker client can communicate with the Docker service. If this fails, install or start Docker according to the operating system's supported procedure before continuing.
Create the persistent host directory
Create $HOME/data so the location is deliberate and easy to inspect or back up. The Docker volume option will map this directory to /data inside Oryx.
Run the official Oryx container
Start a detached container named oryx, apply the always-restart policy, mount persistent storage, and publish the documented HTTP, HTTPS, RTMP, WebRTC UDP, and SRT UDP ports.
Wait for application startup
The image must initialize multiple components. Check the container state and logs rather than assuming that creation alone means the browser service is ready.
docker --version
mkdir -p "$HOME/data"
docker run --restart always -d -it --name oryx \
-v "$HOME/data:/data" \
-p 80:2022 \
-p 443:2443 \
-p 1935:1935 \
-p 8000:8000/udp \
-p 10080:10080/udp \
ossrs/oryx:5
Docker prints the new container identifier when creation succeeds. The --restart always option instructs Docker to restart the container according to that policy. The -d option runs it in the background, and --name oryx gives routine commands a stable container name.
The image reference ossrs/oryx:5 is the image used by the documented quick start. Oryx also publishes versioned releases. Pinning a tested version can make controlled production upgrades easier, but version selection should follow the project's current release notes and your own validation process. Do not assume that changing an image tag alone is risk-free for an existing data directory.
Use alternate HTTP and HTTPS host ports
If ports 80 or 443 are unavailable, the project documents host ports 2022 and 2443 as alternatives. The following variation leaves the media ports unchanged:
docker run --restart always -d -it --name oryx \
-v "$HOME/data:/data" \
-p 2022:2022 \
-p 2443:2443 \
-p 1935:1935 \
-p 8000:8000/udp \
-p 10080:10080/udp \
ossrs/oryx:5
With this mapping, use http://localhost:2022 for local HTTP access. When creating the Localtonet tunnel later, enter host port 2022 rather than 80. A port mapping always has the form host-port:container-port, and Localtonet connects to the host-side listener.
Both commands create a container named oryx and claim the same RTMP and UDP ports. Choose the mapping appropriate for your host and run only that command. If a failed attempt already created the named container, inspect and remove that stopped container before retrying.
Verify Oryx before enabling remote access

Local verification separates Oryx or Docker problems from tunnel configuration problems. Do not create a public route until the browser endpoint responds on the host and you understand which host port is active.
Check the container state
docker ps --filter name=oryx
Confirm that the named container appears and is running. The port listing should reflect the mappings selected during installation. If the container is absent from the running list, inspect all containers and then read its logs:
docker ps -a --filter name=oryx
docker logs oryx
A container can exist but exit during application startup. Typical categories to investigate include a host-port collision, inability to access the mounted directory, insufficient disk space, or an image startup error. Use the actual Docker error and Oryx logs as the basis for diagnosis rather than repeatedly recreating the container.
Open the browser interface
For the default mapping, open:
http://localhost
For the alternate HTTP mapping, open:
http://localhost:2022
A successful response confirms that Docker is forwarding the selected host TCP port to Oryx's internal HTTP listener. Complete any setup or sign-in flow shown by the installed Oryx version. The exact browser screens can change between releases, so this guide does not invent button names or assume a fixed first-run interface.
If you are testing from another computer on the same LAN, replace localhost with the Oryx host's private IP address and retain the correct host port. This test also confirms that Oryx is reachable beyond the loopback interface. Whether a LAN test is permitted depends on the host firewall and network policy.
Distinguish web verification from media verification
Loading the management interface proves the HTTP listener works. It does not by itself prove that RTMP publishing, WebRTC media, SRT publishing, recording, or restreaming is correctly configured. Those workflows have additional protocol, authentication, encoder, browser, certificate, and network requirements.
In particular, Oryx warns that browser-based WebRTC WHIP should not use localhost or 127.0.0.1. The project calls for a private IP, public IP, or domain and points users toward HTTPS setup. This requirement is separate from merely opening the Oryx management interface over HTTP.
Configuration, persistence, and routine operations
Set the management password deliberately
Oryx documents the MGMT_PASSWORD environment variable for setting the management administrator password. It also saves that value in /data/config/.env. Because the entire /data tree is persistent, treat the host data directory as sensitive application state and restrict access to authorized administrators.
If you provide the password when creating a container, do not paste a real secret into shared documentation, screenshots, issue reports, or shell transcripts. A command-line environment value can also remain in shell history or be visible through container inspection to users with Docker-level access. Choose a secret-handling process appropriate for the host and deployment environment.
Oryx also documents REACT_APP_LOCALE for the user-interface language, with supported values en and zh and a default of en. Additional variables may exist, but they should be taken from the documentation for the installed version rather than guessed.
Users who can inspect or control Docker containers may be able to view configuration, modify mounts, replace the image, or access persisted Oryx data. Limit Docker permissions and filesystem access to trusted administrators.
Start, stop, restart, and inspect Oryx
The fixed container name makes common maintenance operations straightforward:
docker stop oryx
docker start oryx
docker restart oryx
docker logs oryx
docker logs --tail 100 oryx
Stopping the container makes the local service unavailable. A Localtonet tunnel may still be configured, but it cannot deliver a functioning Oryx response while the target is down. Starting or restarting the container should not erase mounted data because the application's /data directory points to the host.
Understand removal and recreation
Updating a container normally involves preserving the host data directory, removing or replacing the old container, and creating a new one from the selected image. Before any update, back up the persistent directory and read the release notes for version-specific migration requirements. The evidence available for this guide does not establish a universal, risk-free upgrade sequence across every Oryx release, so we do not claim one.
Removing the container is not equivalent to deleting $HOME/data. The bind-mounted files remain on the host unless an administrator explicitly deletes them. That separation is useful for recovery, but only if the path is correct, writable, and included in a tested backup process.
Back up data with application awareness
The persistent directory can contain configuration, Redis state, recordings, uploads, cached content, and credentials. A simple filesystem copy taken while services are actively writing may not provide application-consistent recovery. For an important deployment, determine an appropriate quiescing or backup procedure for the installed Oryx version and test restoration on a separate host.
Capacity planning also matters. DVR recordings, uploaded source videos, generated virtual-live assets, and caches can grow independently. Monitor both available space and inode usage. If the filesystem fills, Oryx may be unable to record, update state, or write logs and temporary data even if the container itself continues running.
Access the Oryx web interface remotely with Localtonet

Once http://localhost or http://localhost:2022 works, we can expose that HTTP service through Localtonet. The Localtonet client should run on the Oryx host or on another device that can reach the selected host IP and port.
Our client establishes an outbound connection to a Localtonet relay server. The resulting HTTP tunnel provides a public HTTPS address for the local HTTP target. No inbound router port-forwarding rule or public IP address is required. The tunnel remains available only while the selected client device is connected and the tunnel is running.
Use the following documented workflow. Dashboard choices such as available relay servers can vary, so select a current value displayed in your account rather than copying a hardcoded region from an article.
Install and run the Localtonet client
Install our client for the operating system on the device that can reach Oryx. Keep the client running so it can establish the outbound relay connection.
Authenticate or select the client device
Use the device-specific authentication token associated with the client that will run the tunnel. Never publish, guess, or reuse another device's private token.
Select an available relay server
Choose a server or region currently offered in the Localtonet dashboard. Availability can vary, so use the live product choices instead of relying on a hardcoded server code.
Create an HTTP tunnel to Oryx
Select an HTTP tunnel and set its local target to Oryx's reachable host address and host-side HTTP port. Use 127.0.0.1 with port 80 when both clients run directly on the same host with the default mapping. Use port 2022 if that is the mapping you selected. If the Localtonet client runs elsewhere, enter an Oryx host address reachable from that device rather than its own loopback address.
Start the tunnel
Creating a tunnel does not start it. Press Start and wait until the selected device is connected and the tunnel is running.
Open and test the assigned public URL
Open the public HTTPS address assigned to the HTTP tunnel. Test it from a network other than the Oryx host's LAN, sign in through the application's normal authentication flow, and confirm that expected browser requests work.
HTTP tunnels can use a generated random subdomain, a selected subdomain where supported, or a custom domain. These process types serve the same content at a public HTTPS address. Custom-domain DNS requirements can change and should be checked against the current Localtonet documentation before changing DNS records.
The tunnel target must be the host-side endpoint, not the container's isolated address. With -p 80:2022, target port 80. With -p 2022:2022, target port 2022. Do not enter container port 2022 merely because it appears on the right side of the default mapping.
127.0.0.1 always means the device or network namespace making the connection. It is correct when the Localtonet client runs directly on the Oryx Docker host. If the client runs on another computer, use the Oryx host's reachable private IP. If the client itself runs in a container, container networking requires separate planning and is outside the evidenced workflow in this guide.
What the HTTP tunnel does and does not cover
| Oryx traffic | Protocol | Covered by this HTTP tunnel? | Remote-access consideration |
|---|---|---|---|
| Browser interface | HTTP | Yes | Targets the published Oryx HTTP host port |
| HTTP API or HTTP-based delivery | HTTP | Potentially | Depends on Oryx authentication, routes, generated URLs, and application configuration |
| RTMP publishing | TCP | No | Requires a separate raw TCP configuration if remote access is needed |
| WebRTC media | UDP on documented media port | No | Requires separate UDP and WebRTC-aware configuration, including suitable addressing and HTTPS |
| SRT publishing | UDP | No | Requires a separate UDP configuration if remote access is needed |
Browser pages can reference additional endpoints or advertise media addresses based on Oryx configuration. Consequently, successful loading of the console through the public URL does not guarantee that every player, publisher, callback, or WebRTC negotiation path is remotely usable. Validate the exact Oryx feature being deployed and expose only the additional protocol listeners it genuinely requires.
Security guidance for a remotely accessible media server
A public URL changes the threat model. A service previously reachable only from the host or LAN can receive requests from the internet while its tunnel is running. Localtonet removes the need for inbound router configuration, but it does not remove the application's responsibility for authentication, authorization, safe configuration, updates, and data protection.
Protect the Oryx administrator account
Set a strong, unique management password and do not share administrator credentials with viewers or stream publishers. Oryx includes authentication and protects its console and proxied SRS HTTP API. It also generates and stores stream tokens in Redis and verifies publishing tokens for RTMP, SRT, and WHIP/WebRTC workflows.
Application authentication should remain enabled even when the public URL is difficult to guess. A URL is an address, not an authorization boundary. Review Oryx's authentication behavior after upgrades and test both authorized and unauthorized requests.
Expose only the protocols you need
The official Docker quick start publishes all documented service ports. For an internet-facing production deployment, review whether every published host port is actually required. Docker port publishing can make a listener available on host interfaces independently of Localtonet, depending on Docker and firewall configuration.
If the goal is only remote browser administration through an HTTP tunnel, do not assume that RTMP and UDP listeners also need public network access. Any change to the official port set should be tested against the Oryx features you use. This guide does not claim that every feature works when unrelated ports are omitted.
Keep credentials and persistent data private
Protect $HOME/data because it may contain administrator settings, publishing secrets, Redis state, certificates, recorded media, and uploaded content. Include it in a controlled backup policy, restrict filesystem permissions, and avoid placing it inside a broadly synchronized or publicly shared directory.
Authentication tokens for Localtonet are device-specific. Do not include them in Docker commands, screenshots, support posts, source repositories, or article examples. If a token is exposed, replace it through the appropriate account workflow rather than continuing to use it.
Stop public access when it is not required
Stop the Localtonet tunnel when remote Oryx access is no longer needed. Delete obsolete tunnel configurations and remove access that no longer has an operational owner. Stopping the tunnel affects the public route but does not stop the local Oryx container. Conversely, stopping Oryx makes the target unavailable but does not necessarily remove the tunnel configuration.
After starting the tunnel, use a separate network to confirm exactly what is public. Verify the sign-in boundary, test that unauthenticated users cannot reach protected functions, and make sure no additional Docker-published ports have been unintentionally exposed through a router, cloud firewall, or host configuration.
Troubleshooting Oryx and Localtonet
The container name is already in use
Docker requires container names to be unique. Inspect the existing object:
docker ps -a --filter name=oryx
docker logs oryx
If it is the intended deployment, start or troubleshoot it rather than creating a duplicate. If it is a failed disposable attempt and its important data is safely stored in the bind mount, remove the stopped container before rerunning the chosen installation command:
docker rm oryx
Do not remove a container casually if you are uncertain where its data resides. Confirm the volume mapping first, especially if the initial command did not mount /data correctly.
Docker reports that a port is already allocated
Another process or container is using one of the requested ports. Identify whether the conflict is on TCP 80, TCP 443, TCP 1935, UDP 8000, or UDP 10080. Stop or reconfigure the conflicting service only if doing so is operationally safe.
For conflicts on the web ports, use the documented alternate mapping 2022:2022 and, if needed, 2443:2443. Update the browser URL and Localtonet target to match the host-side port.
The container starts and then exits
Run docker ps -a and docker logs oryx. Check whether the mounted host directory exists, whether Docker can access it, whether the disk is full, and whether the image initialized correctly. The release evidence for Oryx also shows that specific versions can contain startup fixes, so consult the release notes before choosing or changing a pinned image.
Localhost does not open Oryx
Confirm that the container is running and that the expected port mapping appears in Docker's output. Match the URL to the mapping:
-p 80:2022means browse tohttp://localhost.-p 2022:2022means browse tohttp://localhost:2022.
If the browser is on another device, localhost points to that other device, not the Oryx host. Use the host's reachable private address and verify applicable host firewall rules.
The Localtonet public URL returns an error
Recheck the layers in order:
- Confirm that the Oryx container is running.
- Open the Oryx HTTP endpoint locally on the host.
- Confirm that the Localtonet client device is connected.
- Verify that the HTTP tunnel targets the correct reachable IP address.
- Verify that it uses the host port, either
80or2022in this guide. - Confirm that the tunnel has been started, not merely created.
If the Localtonet client runs on a different machine, test the target URL from that machine before expecting the tunnel to work. A LAN firewall or incorrect private address can prevent the client from reaching Oryx even though Oryx works locally on its own host.
The console works remotely, but streaming does not
This is expected when the streaming path uses a protocol outside HTTP. RTMP publishing uses TCP port 1935. WebRTC media uses the documented UDP port 8000. SRT uses UDP port 10080. An HTTP tunnel to port 80 does not carry those connections.
Determine which protocol the publisher and player actually use, then evaluate a separate Localtonet tunnel of the matching family. WebRTC can also require suitable public addressing, HTTPS, browser permissions, and negotiation behavior. Do not treat it as a simple replacement of an HTTP port.
WebRTC WHIP fails when using localhost
Oryx specifically warns against using localhost or 127.0.0.1 for browser-based WebRTC WHIP. Use an appropriate private IP, public IP, or domain and configure HTTPS according to Oryx's supported process. A working Localtonet HTTP console URL does not automatically complete the separate WebRTC media and addressing setup.
Settings or recordings disappear after recreation
Confirm that the container was created with -v "$HOME/data:/data" and that the expected files exist in that host directory. A common cause is using a different account, changing $HOME, mistyping the source path, or recreating the container with another mount location.
Stop making changes until the previous data directory is located. Repeatedly starting fresh containers can make recovery more confusing. Once recovered, document the absolute host path and include it in backup and monitoring procedures.
Frequently asked questions
Which Docker image does the Oryx quick start use?
The documented quick start uses ossrs/oryx:5. Oryx also publishes versioned release images. If you pin a release for production, review its release notes and test it with a backup or disposable copy of your deployment data before updating an existing installation.
Why is the /data volume required?
Oryx stores configuration and operational data under /data. The documented bind mount maps that path to $HOME/data on the host so the information survives container replacement. Without the mount, removing the container can remove the data stored in its writable layer.
Can I use port 2022 instead of port 80?
Yes. Oryx documents -p 2022:2022 as an alternative. Open http://localhost:2022 locally and configure the Localtonet HTTP tunnel to target host port 2022.
Does the Localtonet HTTP tunnel expose RTMP, WebRTC, and SRT too?
No. The HTTP tunnel in this guide targets Oryx's HTTP listener. RTMP is raw TCP, while the documented WebRTC media and SRT listeners use UDP. Each non-HTTP service requires separate protocol-appropriate planning and, when needed, a separate matching tunnel.
Does Localtonet require router port forwarding?
No. Our client makes an outbound connection to a Localtonet relay server. This allows the configured local service to receive traffic through its assigned public address without an inbound router port-forwarding rule, a public IP address, VPN setup, or an inbound firewall change.
Must the Localtonet client run on the same machine as Oryx?
No. It can run on another device that can reach the Oryx host and port. If it runs on the same host, 127.0.0.1 is an appropriate target for the published HTTP port. If it runs elsewhere, use an Oryx host address reachable from that client device.
Is creating a Localtonet tunnel enough to make it available?
No. After creating the configuration, press Start. The selected Localtonet client must also be connected. The public route remains available only while that client is connected and the tunnel is running.
Is the public tunnel URL a replacement for Oryx authentication?
No. Keep Oryx authentication enabled, use a strong management password, protect publishing credentials, and apply least privilege. A public URL provides connectivity, not permission to use the application.
Connect your verified Oryx HTTP service with Localtonet
Start Oryx locally, confirm its browser interface on port 80 or 2022, then create an HTTP tunnel to that exact host endpoint. Keep application authentication enabled and add separate protocol-specific tunnels only when your streaming workflow requires them.
Get Started Free โ