Skip to content

Configuration reference ​

Every setting Quikcast accepts, in the order you will meet them in a real file. Each entry tells you what the setting does, its type, its default, the values it accepts, and whether a SIGHUP reload applies it or it needs a restart.

New to Quikcast? Start with the quickstart for a working local setup, then come back here when you need to know exactly what a line does. A copy-ready file with every option commented lives at config/quikcast.reference.toml in the repository; config/quikcast.example.toml is the short starting point.

How to read this page ​

Each setting is introduced like this:

Type integer · Default 4096 · Range 1–65,536 · Applies restart

FieldMeaning
TypeThe TOML type: string, integer, boolean, array of strings, table, or array of tables.
DefaultThe value used when the key is omitted. "none" means the feature is off or the key is required.
Range / ValuesWhat is accepted. Anything else stops startup with a diagnostic that names the key.
Appliesreload means kill -HUP applies it to new work without dropping connections. restart means the process must be restarted.

Rules that apply to the whole file ​

  • Unknown keys are rejected. A typo such as listner_limit stops startup instead of being ignored.
  • Root keys come first. listen, admin_listen and log_filter must appear before the first [table] header, or TOML assigns them to that table.
  • Paths are relative to the config file. A *_file value such as secrets/radio-source resolves beside the configuration file, not the working directory. Absolute paths stay absolute. ~ and $VARIABLES are not expanded.
  • Size limit. The configuration file itself may be at most 128 KiB.
  • A failed reload changes nothing. If SIGHUP finds any error, the running configuration stays active and the error is logged.

TIP

Validate any change before applying it:

sh
quikcast --config quikcast.toml --check

--check runs the complete startup validation, including reading every secret, list, certificate and database, and then exits without binding a port. Exit code 0 means the file is good.

Secret values ​

Secrets are never defaults, so you must supply them. Where a setting offers both an inline value and a _file form, prefer the file.

KindLengthCharactersUsed by
Mount / HLS password16–512 bytesany bytes; a password may contain :secret, secret_file on mounts, [sources], [hls]
Usernames1–64 bytesASCII graphic, no whitespace, no :every username
Management token32–512 bytesASCII graphic, no whitespace[management]
Upstream relay password1–512 bytesASCII graphic, no whitespace[[relays]]
Signed-URL key32–4,096 bytesany byteslistener_auth
UI passwordat least 15 characters, at most 512 bytesUTF-8[ui]

A secret file contains only the secret. One trailing newline is removed; nothing else is trimmed. Do not wrap the value in quotes or write password=.... Files are read at startup and on SIGHUP, so editing a file takes effect only after a successful reload or restart.

Generate a good value with:

sh
openssl rand -hex 32 > secrets/radio-source

Root settings ​

These keys sit at the top of the file, above every table.

listen ​

Type string (host:port) · Default "127.0.0.1:8000" · Applies restart

The address of the public listener. Players, encoders, HLS clients and the operator console all connect here.

The default only accepts connections from the same machine, which is right for local testing or when a reverse proxy runs beside Quikcast. To accept outside connections, bind a public address such as "0.0.0.0:8000". Inside Docker you must use 0.0.0.0, otherwise the published port has nothing to reach.

toml
listen = "0.0.0.0:8000"

Use port 0 only in automated tests; the operating system then picks a free port.

admin_listen ​

Type string (host:port) · Default "127.0.0.1:9090" · Applies restart

The address of the private listener. It serves /health/live, /health/ready, /metrics and the native /api management routes.

This address must be a loopback address (127.0.0.1 or ::1). Quikcast refuses to start with a public admin address, because these routes can disconnect listeners and drain the server. Reach it from outside through an SSH tunnel or an internal-only proxy, never by publishing the port.

log_filter ​

Type string · Default "quikcast=info" · Applies restart

A tracing filter that decides how much is logged. Examples: "quikcast=debug" for connection-level detail, "quikcast=warn" for problems only.

The QUIKCAST_LOG environment variable overrides this value when set. Logs go to standard output through a bounded, non-blocking writer, so the output must be a terminal or a pipe that something is reading. Redirecting straight to a regular file is rejected. Logging currently requires a Unix system.

[tls] ​

Serve HTTPS directly from Quikcast. Omit the table to serve plain HTTP, which is the right choice when a proxy such as Traefik, nginx or Cloudflare already terminates TLS.

toml
[tls]
cert_file = "secrets/tls/fullchain.pem"
key_file = "secrets/tls/privkey.pem"

TLS applies to the public listener only. The admin listener always stays plain and loopback. Quikcast offers TLS 1.2 and 1.3 with ALPN http/1.1. A plain HTTP request sent to a TLS port is closed without a response, and the TLS handshake counts against header_timeout_ms and max_handshakes.

INFO

Enabling or disabling [tls] needs a restart. Renewing a certificate does not: replace the files and send SIGHUP. New connections use the new certificate, existing listeners are not interrupted, and a bad file leaves the old certificate in place.

cert_file ​

Type string (path) · Default none (required inside [tls]) · Max size 256 KiB · Applies reload

A PEM file containing the certificate chain, leaf certificate first, with one to eight certificates. A Let's Encrypt fullchain.pem is exactly the right file.

key_file ​

Type string (path) · Default none (required inside [tls]) · Max size 64 KiB · Applies reload

A PEM file with the matching private key (PKCS#8, PKCS#1 or SEC1). A key that does not match the certificate stops startup or the reload with an error.

[trusted_proxies] ​

Tells Quikcast which network peers are your own proxies, so it can report real listener addresses instead of the proxy's address. The real address feeds IP rules, country rules, listener statistics and logs. By default no proxy is trusted and Quikcast uses the connecting address as is.

toml
[trusted_proxies]
ips = ["127.0.0.1", "10.0.0.0/8"]
providers = ["cloudflare"]
proxy_protocol = false

WARNING

Only list infrastructure you control. Anyone you trust here can claim any client address, which weakens every IP and country rule.

ips ​

Type array of strings · Default [] · Max 64 entries · Applies reload

IP addresses or CIDR networks (IPv4 or IPv6) of your proxies. When a connection comes from one of these, Quikcast reads the X-Forwarded-For header and walks it right to left, stopping at the first address that is not itself trusted. Bare addresses mean a single host (/32 or /128). Hostnames and ports are rejected. Errors name the entry, for example trusted_proxies.ips[1].

providers ​

Type array of strings · Default [] · Values "cloudflare" · Applies reload

Adds the built-in list of Cloudflare's published address ranges. A connection that comes directly from Cloudflare may then supply the client address in CF-Connecting-IP. The ranges ship inside Quikcast and are never fetched at runtime; they are refreshed by upgrading Quikcast.

proxy_protocol ​

Type boolean · Default false · Applies reload (new connections)

Use this behind a layer-4 load balancer (HAProxy in TCP mode, nginx stream, a cloud network load balancer) that cannot add HTTP headers. When true, every public connection must begin with a PROXY protocol v1 or v2 header, sent before TLS and HTTP.

  • It needs ips or providers. Only peers that match them may send the header; a connection from anyone else is closed without a reply.
  • The client address in the header replaces the connecting address for all access rules and statistics.
  • A header marked LOCAL or UNKNOWN, which is what health checks send, keeps the connecting address.
  • A missing or malformed header closes the connection.
  • The admin listener never uses PROXY protocol.
toml
[trusted_proxies]
ips = ["10.0.0.0/8"]
proxy_protocol = true

WARNING

Turning this on means every public connection, including your own health checks and direct curl tests, has to arrive through the proxy.

[management] ​

Enables the native management API on the admin listener (/api/server, /api/stats, /api/mounts, /api/listeners, /api/history, and others).

The API is fail-closed: without this table every /api request is rejected. Mount and HLS passwords do not unlock it.

toml
[management]
token_file = "secrets/management-token"

Call it by sending the token as a Bearer credential to the admin address:

sh
curl -H "Authorization: Bearer $(cat secrets/management-token)" \
  http://127.0.0.1:9090/api/server

token_file ​

Type string (path) · Default none · Applies reload

Path to a file holding the token, 32–512 ASCII graphic characters. Set exactly one of token_file and token. Editing the file rotates the token after the next successful reload.

token ​

Type string · Default none · Applies reload

The token written directly in the config. It works, but keeps a secret in a file you may commit or share. Prefer token_file.

[ui] ​

The embedded operator console, served at /ui on both listeners. It is compiled into the binary, so there is nothing else to install. It is off by default.

toml
[ui]
enabled = true
mode = "private"
username = "admin"
password_file = "secrets/ui-password"

The console has one operator identity, separate from source, HLS and management credentials. Any change to the effective UI settings, including a password change, signs out existing sessions after the next reload.

enabled ​

Type boolean · Default false · Applies reload

When false, every /ui URL, including its assets, returns 404.

mode ​

Type string · Default "private" · Values "private", "public" · Applies reload

"private" shows a login form and, after sign-in, the full console. "public" shows only a small sanitized status page and offers no login or controls. /ui/status is readable without signing in in both modes.

username ​

Type string · Default "" · Range 1–64 ASCII graphic bytes · Applies reload

The operator login name. Required in private mode.

password_file ​

Type string (path) · Default none · Applies reload

Path to a file holding the password: at least 15 characters excluding surrounding whitespace, at most 512 bytes. Obvious values (a single repeated character, common passwords) are rejected. Required in private mode. The file is re-read on every reload.

Type boolean · Default true · Applies reload

Marks the session cookie Secure, so browsers only send it over HTTPS. Leave it on in production, including when a proxy terminates TLS. Set it to false only for throwaway testing over plain HTTP.

public_mounts ​

Type array of strings · Default [] · Applies reload

The mount names the public status page may show. Each entry must be a configured mount. Listing a mount is your explicit consent to publish its availability, codec, content type and listener count. Leave the list empty to disclose no mount at all. Listing a mount here does not give anyone access to play it.

[limits] ​

Capacity and timing controls that protect the server. Every value has a sensible default, so most stations never need this table. All of [limits] needs a restart.

toml
[limits]
max_listeners = 2000
listeners_per_mount = 2000

Startup checks that the memory you reserve fits retained_audio_budget. If it does not, you get retained audio budget cannot cover admission reservations; lower max_listeners or raise the budget.

SettingDefaultRange
ring_bytes4194304positive
ring_entries40961–65,536
join_bytes655360 to ring_bytes
max_connections120001–100,000
max_handshakes1281 to max_connections
max_listeners100001 to max_connections
listeners_per_mount100000 to max_listeners
retained_audio_budget1073741824enough for the reservation formula
relay_allocation_budget33554432at least 2 MiB per relay
header_timeout_ms50001–3,600,000
source_timeout_ms100001–3,600,000
write_timeout_ms100001–3,600,000
shutdown_timeout_ms100001–3,600,000
flac_initialization_bytes6553642–262,144
flac_frame_bytes104857616–4,194,304

ring_bytes ​

The most encoded audio kept in memory for each live stream, in bytes. It is the catch-up buffer new listeners join from, and the line a slow listener must stay inside: a listener who falls further behind than the ring is disconnected, so one slow client never holds back everyone else. Default 4 MiB.

ring_entries ​

The most separate chunks of audio the ring can hold at once. Whichever of ring_bytes and ring_entries fills first decides when the oldest audio is dropped. A chunk is a block of published data, not one second or one codec frame.

join_bytes ​

How much recent audio a new listener may start from, in bytes (not milliseconds). Codec rules still decide the exact safe starting point. 0 means "start at the live edge".

max_connections ​

The most simultaneous TCP connections on the public listener, counting encoders, players, the console and HLS downloads. The admin listener has its own fixed reserve of 32 connections, so a flood of public clients can never lock you out of health checks or management. Connections beyond the limit are refused, not queued.

max_handshakes ​

The most connections that may be waiting to send their request headers (or finish a TLS handshake) at one time. This is the main defence against slow-connection attacks. The admin listener has a separate reserve of 16.

max_listeners ​

The most simultaneous audio listeners across all mounts. HLS downloads are ordinary requests and do not count here. This value also sizes the memory reservation, even when individual mounts are capped lower.

listeners_per_mount ​

The default listener cap for each mount. 0 means no per-mount cap beyond max_listeners. A mount's own listener_limit replaces this value rather than being combined with it.

retained_audio_budget ​

The total memory, in bytes, Quikcast promises it can use for audio rings, parser buffers and listener references. Startup calculates what your mounts and max_listeners require and refuses to start if that exceeds the budget. Default 1 GiB. The exact formula is in Capacity and limits.

relay_allocation_budget ​

Memory set aside for relay workers, at least 2 MiB per configured relay (up to 16). Disabled relays still count. Default 32 MiB.

header_timeout_ms ​

How long a client may take to send its request headers before the connection is dropped. Also bounds the TLS handshake.

source_timeout_ms ​

How long an encoder may send nothing before it is disconnected. A healthy stream can run forever; this only catches stalls.

write_timeout_ms ​

How long a listener's socket may refuse data before the listener is disconnected as a slow consumer. A quiet stream with nothing to send is not a violation.

shutdown_timeout_ms ​

How long a graceful shutdown waits for connections to finish after you stop the server. Anything still running afterwards is aborted.

flac_initialization_bytes ​

The most data Quikcast accepts for the start of a native FLAC stream: the fLaC marker plus every metadata block, including cover art. Raise it if your encoder embeds large artwork.

flac_frame_bytes ​

The most bytes allowed for a single unfinished native FLAC frame. This is a size limit in bytes, not a sample or block-size setting.

[[mounts]] ​

A mount is one stream path, such as /radio.mp3, that an encoder feeds and listeners play. Every [[mounts]] header starts a new mount; the settings under it, and its sub-tables, belong to it.

Configure 1–64 mounts. Zero mounts is allowed only if you enable [hls] or [sources].

toml
[[mounts]]
path = "/radio.mp3"
username = "source"
secret_file = "secrets/radio-source"

Only one encoder can own a mount at a time. A second one is refused with 409 Source already connected; there is no takeover or priority. When the encoder disconnects, its listeners disconnect too, and players reconnect to the next encoder session.

path ​

Type string · Default none (required) · Applies restart to add or remove a mount

The URL path listeners use. It must start with /, be at most 2,048 bytes, and use only ASCII letters, digits and / . _ - ~. Names are case-sensitive, and nested names such as /stations/jazz are fine.

Not allowed: / alone, a trailing /, //, . or .. parts, spaces, Unicode, or any path under the reserved roots /api, /admin, /internal, /health, /metrics and /hls.

The extension does not choose the codec. /radio.mp3 can carry any supported format; the encoder's content type decides.

username ​

Type string · Default "source" · Applies reload

The username the encoder uses for HTTP Basic authentication (and for metadata updates).

secret_file ​

Type string (path) · Default none · Applies reload

Path to the encoder password file. Set exactly one of secret_file and secret. If you set neither, the mount inherits the whole global [sources] credential.

secret ​

Type string · Default none · Applies reload

The encoder password written directly in the config. Prefer secret_file.

fallback ​

Type string · Default none · Applies reload

Another configured mount to serve when this one has no source. The listener keeps its original URL; Quikcast attaches it internally, with no redirect. Chains may be up to eight mounts long including the first. Unknown targets, a mount pointing at itself, loops and chains that are too long stop startup. Compatible MP3 and AAC listeners return to the original mount automatically when its source comes back. See Fallback mounts.

toml
[[mounts]]
path = "/live.mp3"
fallback = "/automation.mp3"
secret_file = "secrets/live-source"

[[mounts]]
path = "/automation.mp3"
secret_file = "secrets/automation-source"

listener_limit ​

Type integer · Default inherit limits.listeners_per_mount · Range 0 to max_listeners · Applies restart

The most listeners this mount allows. 0 removes the per-mount cap (the global limits still apply). A listener served through fallback counts against the mount that actually serves it.

[mounts.listener_auth] ​

Protect this mount with signed, expiring URLs created by your own application. Omit the table, or use type = "none", to keep the mount public. Quikcast only verifies; it has no accounts or sessions. See Signed URLs for the exact signing recipe.

toml
[mounts.listener_auth]
type = "signed_url"
secret_file = "secrets/radio-signing-key"
max_ttl_seconds = 86400
clock_skew_seconds = 0
KeyDefaultRangeMeaning
type"none""none", "signed_url""none" leaves the mount public.
secret_filenone32–4,096 bytesHMAC key shared with your application. Required for signed_url.
max_ttl_seconds864001–604,800The furthest in the future a link may expire. Longer links are refused.
clock_skew_seconds00–60Extra time after expiry a link is still accepted, to tolerate clock drift.

[mounts.access] ​

Restrictions on who may listen. They are added to the global [access] rules: a listener must pass both. The fields are identical to [access] except that geoip_database is only allowed in the global table.

toml
[mounts.access]
countries_allow = ["GH", "NG"]
ip_deny_file = "lists/blocked.txt"

[mounts.source_access] ​

Restrictions on which IP addresses may connect an encoder to this mount. Credentials are still required. There is no global version, and no User-Agent or country rules here.

toml
[mounts.source_access]
ip_allow = ["203.0.113.10", "2001:db8::/48"]
KeyTypeMeaning
ip_allowarray of stringsOnly these IPs or CIDRs may connect. Empty means no restriction.
ip_allow_filepathA list file merged with ip_allow. It must contain at least one rule.
ip_denyarray of stringsThese IPs or CIDRs are always refused.
ip_deny_filepathA list file merged with ip_deny. An empty file is fine.

Up to 10,000 distinct rules per list, counting inline and file entries together. Changes apply on reload.

[access] ​

Global restrictions on who may listen, applied to every mount, in addition to each mount's own [mounts.access]. Omit it for open playback.

A listener is allowed only if it passes every category you configure: IP, User-Agent and country. A deny rule always wins over an allow rule in the same category. Everything here applies on reload.

toml
[access]
ip_deny_file = "lists/blocked.txt"
user_agent_deny = ["exact:bad-monitor"]
countries_allow = ["GH", "NG"]

ip_allow and ip_deny ​

Type array of strings · Default [] · Limit 10,000 distinct rules together with the file

IPv4 or IPv6 addresses or CIDR networks, for example "203.0.113.9" or "198.51.100.0/24". With a non-empty ip_allow, only matching listeners are admitted. ip_deny always refuses matches. Equivalent entries are merged; overlapping networks are kept as written. IPv4-mapped IPv6 addresses (::ffff:192.0.2.1) match their IPv4 form.

ip_allow_file and ip_deny_file ​

Type string (path) · Default none · Max size 1 MiB

A text file of rules, one IP or CIDR per line. Blank lines and lines starting with # are ignored, and a leading UTF-8 byte-order mark is tolerated. The file is merged with the inline list and re-read on every reload, so you can update a blocklist without restarting.

text
# blocked.txt
203.0.113.0/24
198.51.100.7
2001:db8:bad::/48

Errors name the file and line, such as ip_deny_file: lists/blocked.txt:2: invalid IP/CIDR "not-an-ip".

WARNING

An ip_allow_file with no rules is rejected, because an empty allow list would mean "allow everyone". An empty ip_deny_file is fine.

user_agent_allow and user_agent_deny ​

Type array of strings · Default [] · Limit 256 rules · Rule length 1–256 bytes

Match the player's User-Agent header. Each rule is mode:text, where the mode is one of:

ModeMatches when the User-Agent...
exact:equals the text exactly.
prefix:starts with the text.
substring:contains the text.

Matching is case-sensitive. A rule without a mode, or with an unknown mode such as regex:, stops startup.

toml
user_agent_allow = ["prefix:RadioPlayer/"]
user_agent_deny = ["substring:unsupported-build"]

INFO

User-Agent is chosen by the client and trivially faked. Use it for compatibility and convenience, not security.

countries_allow and countries_deny ​

Type array of strings · Default [] · Limit 249 codes

Two-letter ISO 3166-1 country codes (and XK for Kosovo). Lowercase is accepted and normalised. countries_deny refuses listeners in those countries; countries_allow, when non-empty, admits only those countries. Addresses whose country cannot be determined, such as local ones, pass a deny-only policy but fail an allow list.

geoip_database ​

Type string (path) · Default the built-in database · Max size 128 MiB

Country lookups use a database embedded in Quikcast, so country rules work with no setup. Set this to use your own MaxMind-format country database instead, for example "/etc/quikcast/GeoLite2-Country.mmdb". If you set it, it is opened and validated at startup even when no country rules are active, and re-opened on every reload. Quikcast never downloads or updates databases.

[sources] ​

Lets encoders connect to paths you did not list under [[mounts]]. The mount is created when the encoder connects and disappears when its last listener leaves. Nothing is saved to the config. Listed mounts always win over dynamic ones.

toml
[sources]
allow_dynamic_mounts = true
username = "source"
secret_file = "secrets/dynamic-source"

[sources.defaults]
name = "Quikcast Stream"
genre = "Various"
public = false

Even with allow_dynamic_mounts = false, setting credentials here makes every [[mounts]] that omits its own secret inherit them. A server with global credentials may have no [[mounts]] at all.

allow_dynamic_mounts ​

Type boolean · Default false · Applies reload

When true, a correctly authenticated encoder may create a new mount just by connecting to a free path. It requires the credentials below, and the retained-audio budget must have room for at least one more stream.

username and secret_file / secret ​

Type string · Default username "source" · Applies reload

The shared encoder credential for dynamic mounts and for configured mounts that have none of their own. Set exactly one of secret_file or secret.

[sources.defaults] ​

Descriptive station metadata used when an encoder sends none. An encoder's own ice-name, ice-description, ice-genre, ice-url and ice-public headers always win. These fields describe the station only; they cannot change limits, security or routing.

KeyTypeMeaning
namestringThe station name shown to players.
descriptionstringA short description.
genrestringThe genre.
urlstringThe station's website.
publicbooleanWhether the stream may be listed publicly.

[[relays]] ​

A relay pulls an existing internet stream and republishes it on one of your mounts. Use it to rebroadcast another station, build an edge server, or run a backup feed.

The target mount must exist under [[mounts]]. Once a mount has a relay, the relay owns it: an encoder cannot connect there, even while the relay is stopped. You can have up to 16 relays, one per mount. Relay settings apply on reload; changing any of them restarts that relay.

toml
[[mounts]]
path = "/remote.mp3"
secret_file = "secrets/remote-local"

[[relays]]
mount = "/remote.mp3"
upstreams = [
  { url = "https://primary.example/live" },
  { url = "https://backup.example/live" },
]

mount ​

Type string · Default none (required)

The local mount the relay feeds. It is the path your listeners use, not part of the upstream URL.

url, urls and upstreams ​

Type string, array of strings, or array of tables · Default none · Choose exactly one

Where to pull audio from. Use one of the three forms:

  • url = "https://origin.example/live" is a single upstream.
  • urls = ["https://a.example/live", "https://b.example/live"] lists 1–8 upstreams that share the relay's credentials.
  • upstreams = [{ url = "..." }, ...] lists 1–8 upstreams where each may have its own credentials.

All forms need absolute http:// or https:// URLs of at most 2,048 bytes. Queries are fine. Fragments, user:pass@ in the URL, whitespace and other schemes are rejected. Pointing a relay at this same server is rejected. Duplicates are rejected.

The upstream may be a plain stream (MP3, AAC, Ogg, FLAC), an old SHOUTcast server, or an audio-only HLS playlist: see Relay another station.

The first entry is the primary. If it fails, Quikcast tries the next entry immediately. After the last entry fails, it waits for the backoff delay and starts again at the primary. A working backup stays selected until it fails: there is no automatic return to the primary.

TIP

New configurations should prefer upstreams, since it can express everything url and urls can. The older forms still work.

toml
upstreams = [
  { url = "https://primary.example/live", username = "primary-user", secret_file = "secrets/primary-password" },
  { url = "https://backup.example/live" },
]

username and secret_file ​

Type string · Default none (anonymous) · Password 1–512 ASCII graphic bytes

Basic-auth credentials sent to the upstream. Set both or neither. There is no inline secret field for relays. With upstreams, these act as the default for entries that set neither of their own fields; an entry with its own username and secret_file overrides them.

enabled ​

Type boolean · Default true

Whether the relay starts with the server. false starts it stopped (the mount still stays reserved); you can start it later through the management API.

max_redirects ​

Type integer · Default 0 · Range 0–8

How many upstream redirects (301, 302, 303, 307, 308) to follow per attempt. 0 treats any redirect as a failure. Credentials are never sent to a different host than the one you configured: they are dropped at the first change of scheme, host or port.

hls_variant ​

Type string · Default "highest" · Values "highest", "lowest" · Applies reload (restarts the relay)

When a relay's upstream is an HLS master playlist offering several bitrates, this chooses which audio-only variant to follow. "highest" gives the best quality; "lowest" uses the least bandwidth. Variants that contain video are never chosen. It has no effect on non-HLS upstreams.

toml
[[relays]]
mount = "/hls-station.aac"
url = "https://stream.example/live/master.m3u8"
hls_variant = "lowest"
max_redirects = 3

Timeouts and retry ​

All values are milliseconds from 1 to 3,600,000 unless stated.

KeyDefaultMeaning
connect_timeout_ms10000One overall deadline for DNS, TCP connect and TLS.
header_timeout_ms5000How long the upstream may take to send response headers.
audio_timeout_ms10000How long without new audio before the attempt is abandoned. For HLS upstreams the limit is the longer of this and three segment lengths, and it also bounds each playlist or segment download.
initial_backoff_ms1000First wait after every upstream failed. Must not exceed max_backoff_ms.
max_backoff_ms60000Longest wait between retry cycles.
stable_connection_ms30000A connection that lasts this long resets the backoff.
jitter_percent20Random variation applied to waits, 0 to 50.

Outbound HTTPS is always verified against the bundled public certificate roots. There is no option to disable verification, add a private CA or use client certificates.

[hls] ​

A separate subsystem that serves HLS (.m3u8 playlists with segment files) to browsers and mobile players. Quikcast does not encode: your own tool, such as FFmpeg, pushes finished, correctly packaged segments to the private ingest API, and Quikcast stores and serves them from memory. HLS is not derived from your normal mounts.

Everything is held in memory and lost on restart. Passwords, CORS and signed-URL rules reload; capacity settings need a restart.

toml
[hls]
username = "hls"
secret_file = "secrets/hls-ingest"
cors_origin = "https://player.example.com"

See HLS ingest API for the ingest API and supported formats.

username ​

Type string · Default "hls"

The ingest username (Basic authentication).

secret_file / secret ​

Type string · Default none · Password 16–512 bytes

The ingest password. Set exactly one. It must differ from every mount password.

cors_origin ​

Type string · Default none (CORS off) · Max length 256 bytes

The website allowed to play your HLS from a browser. Use "*" or exactly one origin such as "https://player.example.com" (no path, no trailing slash, no list). Without it, browsers on other sites cannot fetch your playlists, although non-browser players are unaffected. Preflight requests allow Range, If-None-Match and If-Range.

Capacity settings ​

KeyDefaultRangeMeaning
max_streams161–64Most HLS streams.
renditions_per_stream81–16Most quality levels per stream.
max_renditions641–128Most quality levels overall.
max_segment_bytes2097152188–16,777,216Largest single uploaded segment. A safety ceiling, not a target size.
max_segments102416–4,096Segment slots per rendition.
max_uploads41–16Uploads accepted at the same time.
rendition_budget134217728up to allocation_budgetMemory reserved per rendition.
allocation_budget536870912up to 4 GiBTotal memory for HLS.

[hls.listener_auth."/hls/NAME"] ​

Protect one HLS stream with signed URLs. The key is the stream's public path, /hls/ followed by 1–64 letters, digits, _ or -. A stream with no entry is public; up to 64 entries are allowed. One signature covers the playlists and every segment of that stream. The fields are the same as [mounts.listener_auth].

toml
[hls.listener_auth."/hls/private"]
type = "signed_url"
secret_file = "secrets/hls-private-key"

Putting it together ​

A small station with HTTPS, a private console, a country allow list and a backup feed:

toml
listen = "0.0.0.0:8443"
admin_listen = "127.0.0.1:9090"

[tls]
cert_file = "secrets/tls/fullchain.pem"
key_file = "secrets/tls/privkey.pem"

[management]
token_file = "secrets/management-token"

[ui]
enabled = true
username = "admin"
password_file = "secrets/ui-password"

[access]
countries_allow = ["GH", "NG"]
ip_deny_file = "lists/blocked.txt"

[[mounts]]
path = "/radio.mp3"
fallback = "/backup.mp3"
secret_file = "secrets/radio-source"

[[mounts]]
path = "/backup.mp3"
secret_file = "secrets/backup-local"

[[relays]]
mount = "/backup.mp3"
upstreams = [{ url = "https://backup.example/live" }]

What can be reloaded ​

Send SIGHUP to apply changes without dropping connected listeners or encoders:

sh
kill -HUP "$(pidof quikcast)"
Applies on reloadNeeds a restart
[tls] certificate and key fileslisten, admin_listen, log_filter
[trusted_proxies] (all keys)Enabling or disabling [tls]
[management], [ui]Every [limits] setting
[access] and every list fileAdding or removing a [[mounts]] entry, and listener_limit
Mount credentials, fallback, listener_auth, access, source_accessHLS capacity settings
[sources] (credentials, dynamic mounts, defaults)
[[relays]] (a changed relay restarts)
[hls] credentials, cors_origin, listener_auth

A reload is all or nothing. Existing listeners and encoders stay connected, and rotated credentials affect new connections and updates. For the full behaviour, see Operations: reload, drain and troubleshooting.

Documentation for Quikcast.