Installation

Install C21 Live Control and C21 Live Encoder on one host

Run C21 Live Control and C21 Live Encoder on a single host — port layout, install order, the move of Control to port 9443, licenses, certificate, firewall and the impact of updates.

When to use this layout

A single host runs both C21 Live Control (a Docker compose stack) and C21 Live Encoder (the encoding engine and its Apache front end, installed on the host). Live Control manages the Encoder on its own host through the Devices section, and can manage other Encoders on other hosts as well.

This layout suits deployments with few hosts available, such as a cloud VM that has to provide both the control plane and the first encoding capacity. When you have more than one host, the standard layout — Control and each Encoder on their own hosts — is simpler to operate: follow Install C21 Live Control and Install C21 Live Encoder instead.

Updating Live Control interrupts the local Encoder. Every Live Control update restarts the Docker service, and the Encoder service is stopped and started with it. Live streams on the Encoder of the same host drop for about one to two minutes and then recover on their own. Plan every Live Control update in a maintenance window — see Updates on a shared host.

How the two products share the host

Both products serve HTTPS on port 443 by default, so one of them has to move. Everything else coexists without changes.

PortLive ControlLive EncoderOn a shared host
443/tcpHTTPS — operator UI and REST APIHTTPS — Encoder API and outputsConflict. Live Control moves to 9443.
80/tcp—HTTPUnchanged.
9080/tcpHTTP (redirects to HTTPS)—Unchanged.
3100/tcpMCP server—Unchanged.
8484/tcp—Delivery of outputsUnchanged.

Live Control is the product that moves, not the Encoder, because:

  • Live Control reaches every registered Encoder at https://<encoder-ip>/ — the Device form takes an IP, not a port.
  • Players, CDNs and origins that pull the Encoder's local output fetch it from port 443.

Both products also share the host fingerprint: the license for both is bound to the same value.

Before you start

  • A host that meets the prerequisites of both products — see Prepare the host, Install C21 Live Control and Install C21 Live Encoder. Size CPU and RAM for the Encoder workload plus the Control stack, which is capped at 4 cores and 3 GiB of RAM.
  • Ubuntu 24.04 LTS (required by the Encoder) with a fixed IP address.
  • The platform certificate and its private key for the host, issued by Cires21 for the host's IP (full chain: leaf and intermediate). The self-signed certificate the installers generate is not enough: Live Control must be able to validate the Encoder's certificate to register it.
  • The same target version for both products, and 6.12.0 or later on every Encoder this Control manages — local and remote. From 6.12.0 on, Live Control delivers logos and blackout files to the Encoder before each order. Earlier Encoders download them from Live Control on port 443, which on this host answers as the Encoder, so logo overlays and blackouts fail on them.
  • A maintenance window — the Encoder installer updates the SSH server and drops SSH sessions for one to two minutes.
Run both installers detached from the SSH session (for example with nohup) so that the SSH restart does not abort the install, and read the log to follow progress.

Steps

1. Prepare the host

Apply Prepare the host — DNS, NTP, swap and the OS update policy. For the firewall, follow step 8 below instead of the ufw section of that page: on a shared host the Control ports are published by Docker and need a different rule set.

2. Install Live Control first

Live Control goes first because its installer requires port 443 to be free. Once it is moved to 9443 in the next step, port 443 is free for the Encoder.

sudo nohup bash -c "curl -fsSL https://get.cires21.com/livecontrol \
  | bash -s -- --version <X.Y.Z> --yes; echo INSTALL_EXIT=\$?" > /tmp/lc-install.log 2>&1 &
tail -f /tmp/lc-install.log      # Wait for INSTALL_EXIT=0

Keep the access details and the initial credentials that the installer prints at the end of the log.

From this point the operator UI and the MCP server are reachable from any address that can reach the host, and admin still has its initial password. On a host exposed to the Internet, apply the Control part of the firewall (step 8) right after step 3, before you go on.

3. Move Live Control HTTPS to port 9443

Create a compose override in the Live Control installation directory (/opt/livecontrol by default). The installer only regenerates docker-compose.yml, so this file survives updates.

sudo tee /opt/livecontrol/docker-compose.override.yml >/dev/null <<'EOF'
# Shared Control + Encoder host: the Encoder serves HTTPS on 443.
services:
  livecontrol:
    ports: !override
      - "9080:80"
      - "9443:443"
EOF
sudo systemctl restart livecontrol   # Recreates the containers with the new ports

livecontrol restart is not enough here: it restarts the containers without applying the new port mapping. The !override tag requires Docker Compose 2.24.4 or later — check it with docker compose version. Verify that Live Control answers on 9443 and that 443 is free:

curl -sk -o /dev/null -w "%{http_code}\n" https://127.0.0.1:9443/   # 200
sudo ss -ltnp | grep ':443 '                                         # No output

From now on the operator UI is at https://<host>:9443/.

4. Install Live Encoder

sudo nohup bash -c "curl -fsSL https://get.cires21.com/liveencoder \
  | bash -s -- --version <X.Y.Z> --yes; echo INSTALL_EXIT=\$?" > /tmp/le-install.log 2>&1 &
tail -f /tmp/le-install.log      # Wait for INSTALL_EXIT=0; SSH drops for 1–2 minutes during the run

On a cloud VM without capture cards or GPU, add --skip-drivers to the installer flags. Live Control keeps running during the Encoder install.

5. Install the licenses

Both products report the same fingerprint:

sudo livecontrol license info
sudo liveencoder license info

Send that single value to your Cires21 representative with the product slots your contract covers. Cires21 returns one license file per product; install each with its own CLI:

sudo livecontrol license install /path/to/control-license.txt
sudo livecontrol restart
sudo livecontrol license verify

sudo liveencoder license install /path/to/encoder-license.txt
sudo liveencoder restart
sudo liveencoder license verify

See Licenses for the slots of each product.

6. Install the certificate in both products

Both products present the same certificate: the Encoder through its Apache front end on 443, Live Control on 9443.

# Live Encoder
sudo install -m 644 <host>.crt /etc/ssl/certs/cert.pem
sudo install -m 600 <host>.key /etc/ssl/private/private-key.pem
sudo apache2ctl configtest && sudo systemctl reload apache2

# Live Control
sudo livecontrol ssl import <host>.crt <host>.key

Check that Live Control validates the Encoder's certificate. Live Control reaches the Encoder through the host's IP, as it would reach a remote Encoder:

sudo docker exec livecontrol curl -s -o /dev/null -w "%{ssl_verify_result}\n" https://<host-ip>/   # 0

Any value other than 0 means the certificate chain or the IP in the certificate does not match, and registering the Encoder in step 9 will fail.

7. First login and admin password rotation

Open https://<host>:9443/ and sign in as admin with the initial password printed by the installer. The UI asks you to rotate the password before anything else. Until the password is rotated, the REST API and the MCP server reject every request made with the admin account.

livecontrol security password reset does not replace this step: it sets a new password but leaves the account pending rotation.

Bundled MCP server. The MCP server that ships with Live Control signs in with the admin account, using the password stored in the installation directory (/opt/livecontrol by default). After the rotation, replace the admin password in that directory's .env and .credentials files with the new one, then recreate the MCP service with cd /opt/livecontrol && sudo docker compose up -d livecontrol-mcp.

8. Configure the firewall

The two products need two different rule sets, because their ports reach the host through different paths:

ProductHow its ports are exposedWhere to filter
Live EncoderDirectly on the host: 80, 443, 8484 and the ingest ports of your Channels (SRT, RTMP, UDP…).The host firewall (ufw or the INPUT chain), as usual.
Live ControlPublished by Docker: 9443, 9080, 3100.The DOCKER-USER chain. Docker-published ports skip the INPUT chain, so ufw rules do not apply to them.

Without a DOCKER-USER rule set, the Control ports — the MCP server included — are open to any address that can reach the host.

Encoder. Keep the policy of your deployment: allow the ingest ports your sources use, and restrict 80 / 443 / 8484 to the clients that pull the Encoder output and to any other Live Control that manages this Encoder. If you restrict 443, re-run the certificate check of step 6 afterwards to confirm that the local Live Control still reaches the Encoder.

With a default-deny policy, also allow the Encoder's own multicast traffic. The Encoder sends it to itself, and it arrives on the WAN interface with the host IP as source; if the firewall drops it, running Live streams stop:

sudo ufw allow in on <wan-interface> from <host-ip> to 224.0.0.0/4 proto udp comment 'Encoder internal multicast'

The local Live Control runs in a container, so its requests reach the Encoder from the Docker network of Live Control, not from the host IP. Allow that subnet on 443 — Live Control does not use the Encoder's 80 or 8484:

sudo docker network inspect livecontrol_network -f '{{(index .IPAM.Config 0).Subnet}}'   # For example 172.18.0.0/16
sudo ufw allow from <control-docker-subnet> to any port 443 proto tcp comment 'Encoder HTTPS from local Control'

Control. The script below allows the listed sources and drops everything else that enters on the WAN interface. Replies to connections started from the host, and traffic between containers, are not affected.

#!/usr/bin/env bash
# /usr/local/sbin/c21-docker-user-fw.sh
set -euo pipefail
WAN_IF="<wan-interface>"                         # For example eth0
ALLOW_SRC="<office-ip>/32 <vpn-subnet>"          # Sources allowed to reach 9443, 9080 and 3100

for ipt in iptables ip6tables; do                # Docker also publishes on IPv6
  $ipt -N DOCKER-USER 2>/dev/null || true
  $ipt -F DOCKER-USER
  $ipt -A DOCKER-USER -i "$WAN_IF" -m conntrack --ctstate RELATED,ESTABLISHED -j RETURN
done
for src in $ALLOW_SRC; do
  case "$src" in *:*) ipt=ip6tables ;; *) ipt=iptables ;; esac
  $ipt -A DOCKER-USER -i "$WAN_IF" -s "$src" -j RETURN
done
for ipt in iptables ip6tables; do
  $ipt -A DOCKER-USER -i "$WAN_IF" -j DROP
  $ipt -A DOCKER-USER -j RETURN
done

iptables rules live only in memory and are lost when the host reboots, so apply the script from a systemd unit bound to Docker: it runs every time Docker starts, including after a reboot and after a Live Control update.

# /etc/systemd/system/c21-docker-user-fw.service
[Unit]
Description=DOCKER-USER rules for C21 Live Control
After=docker.service
PartOf=docker.service

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/local/sbin/c21-docker-user-fw.sh

[Install]
WantedBy=docker.service
sudo chmod 755 /usr/local/sbin/c21-docker-user-fw.sh
sudo systemctl daemon-reload
sudo systemctl enable --now c21-docker-user-fw.service
sudo iptables -S DOCKER-USER

From an address outside the allowlist, ports 9443, 9080 and 3100 must now be closed.

9. Register the Encoder in Live Control

In the Live Control UI open Devices → Add device and register the Encoder of this host as you would register any other one — see Install C21 Live Encoder, step 4:

  • Server IP — the IP of the host, the same one the certificate is issued for. No port: Live Control reaches the Encoder on 443.
  • Register username / Register password — the Encoder's admin credentials (sudo liveencoder credentials show / credentials reset).

The Device row must show registration_status: registered. Other Encoders, on other hosts, are registered in the same way.

10. Verify

curl -sk -o /dev/null -w "%{http_code}\n" https://127.0.0.1:9443/   # Live Control UI: 200
sudo livecontrol status                                             # Live Control services healthy
sudo liveencoder status                                             # Encoder service running
sudo iptables -S DOCKER-USER                                        # Control firewall in place

Then run a test Live stream on the local Encoder and check that its output is served from https://<host>/.

Updates on a shared host

Update both products in the same maintenance window, with the operation stopped:

UpdateEffect on the shared host
Live ControlThe update reconfigures and restarts the Docker service. The Encoder service depends on Docker, so it is stopped and started with it: local Live streams drop for one to two minutes and recover on their own. The port override and the DOCKER-USER rules are kept.
Live EncoderLive Control is not affected. SSH sessions can drop while the SSH server is updated.

Follow the order recommended in Updates — Encoder first, then Live Control — and after the Live Control update check:

curl -sk -o /dev/null -w "%{http_code}\n" https://127.0.0.1:9443/   # Live Control still on 9443
sudo liveencoder status                                             # Encoder back up
sudo iptables -S DOCKER-USER                                        # Firewall rules still in place
Copyright © 2026