How to run icey-server in production. Pick the deployment method that fits your infrastructure.
:::tabs
::tab{title="Docker Compose"}
version: "3.8"
services:
icey:
image: 0state/icey-server:0.1.1
network_mode: host
environment:
ICEY_MODE: stream
ICEY_SOURCE: /app/media/video.mp4
ICEY_LOOP: 1
volumes:
- ./media:/app/media:ro
- ./recordings:/app/recordings
restart: unless-stopped:::note
network_mode: host is the simplest path. It avoids port mapping and NAT complications. If you need bridge networking, you must publish ports 4500 and 3478 and set ICEY_TURN_EXTERNAL_IP to the host's public IP.
:::
:::note
The published Docker image is environment-driven (ICEY_MODE, ICEY_SOURCE, ICEY_LOOP, ICEY_TURN_EXTERNAL_IP). For config-file-driven bring-up, use a native icey-server install or the repo-backed nilstate/icey-cli source path.
:::
::
::tab{title="systemd"}
Create /etc/systemd/system/icey-server.service:
[Unit]
Description=icey-server media runtime
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/bin/icey-server \
--config /etc/icey-server/config.json
Restart=on-failure
RestartSec=5
User=icey
Group=icey
WorkingDirectory=/var/lib/icey-server
[Install]
WantedBy=multi-user.targetsudo systemctl daemon-reload
sudo systemctl enable --now icey-server
sudo journalctl -u icey-server -f::
::tab{title="Kubernetes"}
Minimal deployment. Adjust resource limits and storage for your workload.
apiVersion: apps/v1
kind: Deployment
metadata:
name: icey-server
spec:
replicas: 1
selector:
matchLabels:
app: icey-server
template:
metadata:
labels:
app: icey-server
spec:
containers:
- name: icey-server
image: 0state/icey-server:0.1.1
ports:
- containerPort: 4500
name: http
- containerPort: 3478
name: turn
protocol: UDP
env:
- name: ICEY_MODE
value: relay
livenessProbe:
httpGet:
path: /api/health
port: 4500
periodSeconds: 10
readinessProbe:
httpGet:
path: /api/ready
port: 4500
periodSeconds: 5:::warning
WebRTC and TURN require UDP. If your cluster uses a network policy that blocks UDP, TURN relay will not work. You may need hostNetwork: true or a UDP-capable load balancer.
:::
::
:::
If you are deploying for the first time, validate each layer before adding the next.
:::steps
-
Stream mode, local file, no TURN
icey-server --source ./demo.mp4 --no-turn
This validates HTTP serving, Symple signalling, and the server-to-browser media path. If the browser cannot see the server peer, you have a signalling problem. If video does not play, you have a media path problem. Neither involves TURN.
-
Record mode
icey-server --mode record --record-dir ./recordings --no-turn
This validates the browser-to-server media path. Grant camera access in the browser, click Call, and check that MP4 files appear in the recording directory.
-
Relay mode
icey-server --mode relay --no-turn
This validates the full bidirectional path. First browser becomes the source, second browser becomes the viewer.
-
Enable TURN
Remove
--no-turn. Set--turn-external-ipto your public IP. Test from a browser outside your local network.If relay fails under NAT, check the TURN deployment guide before touching the media code.
:::
Before starting the server in any environment:
- OpenSSL is installed and discoverable by the binary
- FFmpeg is installed and discoverable by the binary
--web-rootpoints at the actual builtdist/directory (or the Docker image includes it)--record-diris writable if you use record mode--sourcepoints to a real file, device, or reachable RTSP URL if you use stream mode- TURN port (3478) is reachable from outside if you expect relay through NATs
| Service | Port | Protocol | Required |
|---|---|---|---|
| HTTP / WebSocket | 4500 | TCP | Always |
| TURN relay | 3478 | UDP + TCP | Unless --no-turn |
If you are behind a firewall, both ports must be reachable from the browser. TURN uses UDP by default with TCP fallback.
See the TLS guide for HTTPS and WSS termination options.