Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/moqtail/moqtail/llms.txt

Use this file to discover all available pages before exploring further.

The MOQtail relay server is a high-performance Rust application that forwards MOQT messages between publishers and subscribers. It supports WebTransport and provides configurable caching, logging, and connection management.

Prerequisites

Before deploying the relay server, ensure you have:
  • Rust (1.70 or later) - Install Rust
  • SSL/TLS Certificates - Required for WebTransport
  • Linux/Unix environment - Recommended for production

Quick Start

1

Clone the repository

git clone https://github.com/moqtail/moqtail.git
cd moqtail
2

Generate certificates

For development, use mkcert to generate self-signed certificates:
# Install mkcert
brew install mkcert  # macOS
# or follow https://github.com/FiloSottile/mkcert#installation

# Install local CA
mkcert -install

# Generate certificates (run from apps/relay/cert)
cd apps/relay/cert
mkcert -key-file key.pem -cert-file cert.pem localhost 127.0.0.1 ::1
For production deployments, use certificates from a trusted Certificate Authority (CA) like Let’s Encrypt.
3

Run the relay server

cargo run --bin relay -- --port 4433 --cert-file cert/cert.pem --key-file cert/key.pem

Configuration Options

The relay server supports extensive configuration through command-line arguments:

Network Configuration

/// Port to bind
#[arg(long, default_value_t = 4433)]
pub port: u16,

/// Host to bind
#[arg(long, default_value = "localhost")]
pub host: String,
cargo run --bin relay -- \
  --port 4433 \
  --host localhost \
  --cert-file apps/relay/cert/cert.pem \
  --key-file apps/relay/cert/key.pem

Certificate Configuration

/// Certificate PEM file
#[arg(long, default_value = "apps/relay/cert/cert.pem")]
pub cert_file: String,

/// Private key PEM file
#[arg(long, default_value = "apps/relay/cert/key.pem")]
pub key_file: String,
Certificates are loaded using the wtransport Identity API:
let identity = Identity::load_pemfiles(&self.cert_file, &self.key_file).await?;

let config = ServerConfig::builder()
  .with_bind_default(self.port)
  .with_identity(identity)
  .keep_alive_interval(Some(Duration::from_secs(self.keep_alive_interval)))
  .max_idle_timeout(Some(Duration::from_secs(self.max_idle_timeout)))
  .unwrap()
  .build();

Connection Management

# Keep-alive and timeout settings
cargo run --bin relay -- \
  --max-idle-timeout 7 \
  --keep-alive-interval 3
Parameters:
  • --max-idle-timeout: Maximum idle time (seconds) before closing inactive connections
  • --keep-alive-interval: Interval (seconds) for sending keep-alive packets

Cache Configuration

The relay implements a sophisticated caching system for subgroups and fetches:
/// Number of cached subgroups/fetches per track
#[arg(long, default_value_t = 1000)]
pub cache_size: u16,

/// Cache expiration type (ttl or tti)
#[arg(long, value_enum, default_value = "ttl")]
pub cache_expiration_type: CacheExpirationType,

/// Cache expiration duration in minutes
#[arg(long, default_value_t = 30)]
pub cache_expiration_minutes: u64,
# Entries expire after fixed duration from creation
cargo run --bin relay -- \
  --cache-size 1000 \
  --cache-expiration-type ttl \
  --cache-expiration-minutes 30

Logging Configuration

#[arg(long, default_value = "/tmp")]
pub log_folder: String,

/// Enable object logging
#[arg(long, default_value_t = false)]
pub enable_object_logging: bool,

/// Enable token logging
#[arg(long, default_value_t = false)]
pub enable_token_logging: bool,

/// Token log file path
#[arg(long, default_value = "/tmp/tokens.csv")]
pub token_log_path: String,
cargo run --bin relay -- \
  --log-folder ./logs \
  --enable-object-logging \
  --enable-token-logging \
  --token-log-path ./logs/tokens.csv
The relay uses tracing for structured logging with daily log rotation:
fn init_logging(log_dir: &str) {
  let env_filter = EnvFilter::builder()
    .with_default_directive(LevelFilter::INFO.into())
    .from_env_lossy();

  std::fs::create_dir_all(log_dir).expect("Failed to create log directory");

  let file_appender = tracing_appender::rolling::daily(log_dir, "relay.log");
  let (non_blocking, _guard) = tracing_appender::non_blocking(file_appender);

  tracing_subscriber::fmt()
    .with_target(true)
    .with_level(true)
    .with_env_filter(env_filter)
    .with_writer(non_blocking.and(std::io::stdout))
    .init();
}

Advanced Configuration

# Initial maximum request ID
cargo run --bin relay -- \
  --initial-max-request-id 2305843009213693951
Parameter:
  • --initial-max-request-id: Starting maximum request ID (default: u64::MAX / 8)

Production Deployment

Building for Production

# Build optimized binary
cargo build --release --bin relay

# Binary location
./target/release/relay

Systemd Service

Create a systemd service file /etc/systemd/system/moqtail-relay.service:
[Unit]
Description=MOQtail Relay Server
After=network.target

[Service]
Type=simple
User=moqtail
Group=moqtail
WorkingDirectory=/opt/moqtail
ExecStart=/opt/moqtail/target/release/relay \
  --port 443 \
  --host 0.0.0.0 \
  --cert-file /etc/ssl/moqtail/cert.pem \
  --key-file /etc/ssl/moqtail/key.pem \
  --log-folder /var/log/moqtail \
  --cache-size 5000 \
  --max-idle-timeout 30 \
  --keep-alive-interval 5 \
  --enable-token-logging \
  --token-log-path /var/log/moqtail/tokens.csv
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
Enable and start the service:
sudo systemctl daemon-reload
sudo systemctl enable moqtail-relay
sudo systemctl start moqtail-relay
sudo systemctl status moqtail-relay

Docker Deployment

Create a Dockerfile in the relay directory:
FROM rust:1.70 as builder

WORKDIR /app
COPY . .

# Build the relay
RUN cargo build --release --bin relay

FROM debian:bookworm-slim

RUN apt-get update && apt-get install -y \
  ca-certificates \
  && rm -rf /var/lib/apt/lists/*

WORKDIR /app

COPY --from=builder /app/target/release/relay /app/relay

EXPOSE 4433

ENTRYPOINT ["/app/relay"]
CMD ["--port", "4433", "--host", "0.0.0.0", "--cert-file", "/certs/cert.pem", "--key-file", "/certs/key.pem"]
Build and run:
docker build -t moqtail-relay .
docker run -d \
  -p 4433:4433/udp \
  -v /path/to/certs:/certs \
  -v /path/to/logs:/var/log/moqtail \
  --name moqtail-relay \
  moqtail-relay

Environment Variables

Control logging level via environment variable:
# Set log level
export RUST_LOG=info

# More verbose logging
export RUST_LOG=debug,relay=trace

# Run with custom log level
RUST_LOG=info cargo run --bin relay

Monitoring

Server Startup

When the relay starts successfully, you’ll see:
info!(
  "{} is running at https://{}:{}",
  env!("MOQTAIL_VERSION"),
  self.app_config.host,
  self.app_config.port
);
Example output:
moqtail/0.12.0+a1b2c3d is running at https://localhost:4433

Log Files

The relay generates daily rotating logs:
# View relay logs
tail -f /var/log/moqtail/relay.log

# View token logs (if enabled)
tail -f /var/log/moqtail/tokens.csv

Health Checks

Monitor server health by checking:
  1. Process status: systemctl status moqtail-relay
  2. Port binding: ss -tulpn | grep 4433
  3. Log output: Check for errors in relay.log

Troubleshooting

Error:
Failed to load identity from PEM files
Solution:
  • Verify certificate files exist and have correct permissions
  • Check certificate format (must be PEM)
  • Ensure paths are correct (absolute or relative to working directory)
ls -la apps/relay/cert/
chmod 600 apps/relay/cert/key.pem
chmod 644 apps/relay/cert/cert.pem
Error:
Failed to create server endpoint: Address already in use
Solution:
  • Check if another process is using the port:
lsof -i :4433
# or
ss -tulpn | grep 4433
  • Choose a different port:
cargo run --bin relay -- --port 8443
Error:
Failed to create log directory
Solution:
  • Create the directory manually:
sudo mkdir -p /var/log/moqtail
sudo chown moqtail:moqtail /var/log/moqtail
  • Or use a writable location:
cargo run --bin relay -- --log-folder ./logs
Possible causes:
  • Firewall blocking UDP traffic on port 4433
  • Certificate not trusted by client browser
  • Server bound to localhost instead of 0.0.0.0
Solution:
# Allow UDP traffic
sudo ufw allow 4433/udp

# Bind to all interfaces
cargo run --bin relay -- --host 0.0.0.0

Complete Configuration Reference

#[derive(Parser, Debug)]
pub struct Cli {
  #[arg(long, default_value_t = 4433)]
  pub port: u16,
  
  #[arg(long, default_value = "localhost")]
  pub host: String,
  
  #[arg(long, default_value = "apps/relay/cert/cert.pem")]
  pub cert_file: String,
  
  #[arg(long, default_value = "apps/relay/cert/key.pem")]
  pub key_file: String,
  
  #[arg(long, default_value_t = 1000)]
  pub cache_size: u16,
  
  #[arg(long, default_value_t = 7)]
  pub max_idle_timeout: u64,
  
  #[arg(long, default_value_t = 3)]
  pub keep_alive_interval: u64,
  
  #[arg(long, default_value = "/tmp")]
  pub log_folder: String,
  
  #[arg(long, value_enum, default_value = "ttl")]
  pub cache_expiration_type: CacheExpirationType,
  
  #[arg(long, default_value_t = 30)]
  pub cache_expiration_minutes: u64,
  
  #[arg(long, default_value_t = false)]
  pub enable_object_logging: bool,
  
  #[arg(long, default_value_t = false)]
  pub enable_token_logging: bool,
  
  #[arg(long, default_value = "/tmp/tokens.csv")]
  pub token_log_path: String,
  
  #[arg(long, default_value_t = u64::MAX / 8)]
  pub initial_max_request_id: u64,
}

Next Steps

WebTransport Setup

Configure WebTransport for browser clients

Client Integration

Connect clients to your relay server