Skip to content

Configuration Index

This page lists the default configuration shipped with SyncTV. Effective values combine config files, environment variables, CLI overrides, path resolution, and timezone fallback.

See Full Configuration Example for YAML templates. Run synctv config show --output yaml to inspect the effective configuration for the current binary with secrets redacted.

OAuth2 provider instances are Runtime Settings. Remote media provider instances are persisted through the management API/CLI and are not static config-file fields.

Most fields can keep their defaults. Production launch should prioritize secrets, database, entrypoints, security boundaries, and backups.

Setting When to change it Common mistake After change Production guidance
jwt.secret Any production deployment Keeping change-me-in-production or committing it Restart required; old tokens may become invalid Inject through Secret Manager or secret file
security.opaque_server_setup_secret Local password/OPAQUE login Regenerating it on every deployment Restart required; casual changes can break password records Generate once and back it up
security.credential_encryption_key Storing encrypted provider credentials Not 64 hex chars, or losing the key Restart required; losing it breaks encrypted credential reads Use openssl rand -hex 32 and back it up
security.email_outbox_encryption_key Every production deployment Different replicas use different keys Restart required; queued email depends on this key Generate once and back it up with the database
database.url / split fields Production PostgreSQL Pointing at local dev DB or oversizing the pool Restart required PostgreSQL must be persistent and backed up
redis.url / split fields Production, OAuth2, multi-replica, rate limits, L2 cache Different replicas use different Redis or key prefixes collide Restart required Recommended in production, required for multi-replica mode
server.cors_allowed_origins Web frontend and API use different origins Using * or adding a path Restart required Use exact origins such as https://app.example.com
server.trusted_proxies A reverse proxy or Ingress sits in front Trusting the whole internet Restart required Trust only proxy networks you control
management.* CLI or operations control plane is needed Exposing TCP management publicly without a token Restart required Prefer Unix socket; TCP must be authenticated
metrics.* Prometheus or alerting is used Exposing /metrics publicly Restart required Use auth and network isolation
webauthn.* Passkeys are enabled rp_origin does not match the real origin Restart required Use only production HTTPS origins
email.* Email verification, password reset, email MFA, notifications TLS/port/from address mismatch Restart required Verify with synctv settings test-email
cluster.* / cluster.secret Multi-replica cluster Cluster enabled without Redis or cluster secret Restart required All replicas share PostgreSQL, Redis, and secrets
livestream.* RTMP/FLV/HLS livestreaming HLS storage model differs between replicas Restart required Use shared filesystem or S3 for high traffic
proxy_slice_cache.* Proxy Range slice cache is needed Expecting full-file cache Restart required Mount enough storage; only Range slices are cached

Run these checks after changing configuration:

终端窗口
synctv config validate
synctv config show --output yaml
curl -fsS http://localhost:8081/health/ready

Production Compose uses .env.postgres, .env.redis, and .env.synctv; it does not require a hand-written full YAML file. Before launch, confirm:

Goal Compose/env focus Config field
Initial administrator SYNCTV_BOOTSTRAP_ROOT_PASSWORD bootstrap.root_password
Token signing SYNCTV_JWT_SECRET jwt.secret
OPAQUE password login SYNCTV_SECURITY_OPAQUE_SERVER_SETUP_SECRET security.opaque_server_setup_secret
Provider credential encryption SYNCTV_SECURITY_CREDENTIAL_ENCRYPTION_KEY security.credential_encryption_key
Email queue encryption SYNCTV_SECURITY_EMAIL_OUTBOX_ENCRYPTION_KEY security.email_outbox_encryption_key
Web frontend CORS SYNCTV_SERVER_CORS_ALLOWED_ORIGINS='["https://app.example.com"]' server.cors_allowed_origins
PostgreSQL .env.postgres and Compose volume database.*
Redis .env.redis, Compose Redis service, and key prefix redis.*
Runtime files Compose /data volume data_dir

Use the field index below for bare-metal, Kubernetes, secret files, or custom YAML.

Field Type Default Details
server object see below Server Listener and Runtime Paths
time object see below Server Listener and Runtime Paths
public_ids object see below Public IDs
security object see below Security and Secrets
data_dir string path platform-specific Server Listener and Runtime Paths
metrics object see below Metrics Monitoring
management object see below Server Listener and Runtime Paths
database object see below Database and Redis
redis object see below Database and Redis
jwt object see below Security and Secrets
logging object see below Server Listener and Runtime Paths
livestream object see below Livestream Configuration
chat object see below chat field table on this page
webauthn object see below WebAuthn and Passkeys
email object see below Email and OAuth2
media_providers object see below Media Providers
webrtc object see below WebRTC Configuration
connection_limits object see below Rate Limits and Connection Limits
bootstrap object see below Bootstrap Root User
cluster object see below Cluster Configuration
password_complexity object see below Security and Secrets
buffer_sizes object see below Internal Buffers
cache object see below Business Cache
proxy_slice_cache object see below Proxy Slice Cache
messaging_rate_limits object see below Rate Limits and Connection Limits
request_rate_limits object see below Rate Limits and Connection Limits
request_rate_limits object see below Rate Limits and Connection Limits
Field Type / values Default Meaning
server.host IP/listen address 0.0.0.0 Main API listen address
server.port port 8080 HTTP REST and public gRPC listen port
server.enable_reflection boolean false Enable public gRPC reflection
server.trusted_proxies string array [] Trusted reverse proxy IPs/CIDRs
server.cors_allowed_origins string array [] Frontend origins allowed by startup CORS
server.advertise_host string "" Address other nodes use to reach this node
server.shutdown_drain_timeout_seconds seconds 30 Graceful shutdown drain timeout
server.grpc_max_message_size_bytes bytes 16777216 Maximum gRPC message size
server.grpc_compression_enabled boolean true Allow gRPC gzip compression negotiation
Field Type / values Default Meaning
health.enabled boolean true Enable the dedicated health listener
health.host IP/listen address 127.0.0.1 Health listener address
health.port port 8081 Health listener port for liveness and readiness endpoints
Field Type / values Default Meaning
time.timezone IANA timezone "" Timezone for human-readable formatting and local datetime parsing
public_ids.sqids object or null null Enable sqids public IDs when configured
public_ids.sqids.alphabet string or null null sqids alphabet
public_ids.sqids.min_length integer 12 Minimum sqids length
security.credential_encryption_key 64-character hex secret "" Provider credential encryption key
security.totp_encryption_key 64-character hex secret "" Dedicated TOTP encryption key; required
security.email_outbox_encryption_key 64-character hex secret "" Dedicated email outbox encryption key; required in production
security.opaque_server_setup_secret secret string "" Stable OPAQUE server setup secret
security.proxy_signing_key at least 32 characters "" Dedicated media proxy URL signing key; required
security.media_swarm_signing_key at least 32 characters "" Dedicated WebRTC media swarm announcement signing key; required
security.provider_session_encryption_key at least 32 characters "" Dedicated provider login session key; required
security.login_discovery_key at least 32 characters "" Login discovery enumeration-protection key; required
security.webauthn_enumeration_key at least 32 characters "" WebAuthn enumeration-protection key; required
security.ssrf.enabled boolean false Enable global SSRF protection for server-side outbound requests
security.ssrf.allow_private_network_targets boolean false Allow server-side outbound requests to private/loopback/link-local/reserved/metadata targets
security.ssrf.allowed_hosts string array [] Additional hostnames allowed by the global SSRF policy
security.ssrf.allowed_ip_ranges IP/CIDR string array [] Additional IPs or CIDR ranges allowed by the global SSRF policy
Field Type / values Default Meaning
metrics.enabled boolean false Start the dedicated metrics listener
metrics.host IP/listen address 0.0.0.0 Metrics listen address
metrics.port port 9090 Metrics listen port
metrics.tls.enabled boolean false Enable TLS on the metrics listener
metrics.tls.cert_path file path "" Metrics TLS certificate
metrics.tls.key_path file path "" Metrics TLS private key
metrics.auth.mode bearer_token, basic, or kubernetes bearer_token Metrics authentication mode
metrics.auth.bearer_token secret string "" Bearer token for bearer-token mode
metrics.auth.basic_username string "" Basic-auth username
metrics.auth.basic_password secret string "" Basic-auth password
metrics.auth.kubernetes.audience string "" Kubernetes TokenReview audience
metrics.auth.kubernetes.authentication_cache_ttl_seconds seconds 60 TokenReview result cache TTL
metrics.auth.kubernetes.authorization_cache_ttl_seconds seconds 60 SubjectAccessReview result cache TTL
Field Type / values Default Meaning
management.enabled boolean true Enable the management endpoint
management.transport unix or tcp unix on Unix, tcp elsewhere Management endpoint transport
management.port port 50052 TCP management port
management.unix_socket_path file path platform-specific Unix socket path
management.auth_token secret string "" TCP management bearer token
management.enable_reflection boolean false Management gRPC reflection
Field Type / values Default Meaning
database.url PostgreSQL URL postgresql://synctv:synctv@localhost:5432/synctv Complete database connection URL
database.host string "" Database host for split configuration
database.port port 0 Database port for split configuration
database.username string "" Database username
database.password secret string "" Database password
database.name string "" Database name
database.max_connections integer 20 Maximum pool connections
database.min_connections integer 5 Minimum idle pool connections
database.connect_timeout_seconds seconds 10 Connection timeout
database.idle_timeout_seconds seconds 600 Idle connection timeout
database.max_lifetime_seconds seconds 1800 Maximum connection lifetime
Field Type / values Default Meaning
redis.url Redis URL "" Complete Redis connection URL
redis.host string "" Redis host for split configuration
redis.port port 0 Redis port for split configuration
redis.username string "" Redis username
redis.password secret string "" Redis password
redis.database integer 0 Redis database index
redis.connect_timeout_seconds seconds 5 Redis connection timeout
redis.response_timeout_seconds seconds 5 Redis command response timeout
redis.pipeline_buffer_size integer 512 Redis connection manager pipeline buffer size
redis.key_prefix string synctv: Redis key prefix
redis.deployment_mode standalone or sentinel standalone Redis deployment mode
redis.sentinel_master_name string or null null Sentinel master name
redis.sentinel_addresses string array [] Sentinel node addresses

Top-level logging receives logs from the database, Redis, caches, proxies, realtime, outbox, migrations, startup, third-party dependencies, and all remaining targets. <component> is one of server, health, metrics, management, cluster, livestream, or webrtc; each component has an independent output.

Field Type / values Default Meaning
jwt.secret secret string change-me-in-production Token signing secret
jwt.access_token_duration_hours hours 1 Access-token lifetime
jwt.refresh_token_duration_days days 30 Refresh-token lifetime
jwt.guest_token_duration_hours hours 4 Guest-token lifetime
jwt.clock_skew_leeway_secs seconds 60 Token timestamp skew allowance
logging.level error, warn, info, debug, or trace info Global log level
logging.format text or json text Global log format
logging.output stdout, stderr, or a file object stdout Global log output
logging.output.path file path "" Global log file path; relative paths resolve under data_dir
logging.output.rotation.strategy daily, hourly, or never daily Global log file rotation period
logging.output.rotation.max_files positive integer 30 Global log files retained
logging.color auto, always, or never auto Global color output
<component>.logging.level error, warn, info, debug, or trace info (warn for metrics/cluster) Component log level
<component>.logging.format text or json text Component log format
<component>.logging.output stdout, stderr, or a file object stdout Independent component output
<component>.logging.output.path file path "" Component log file path; relative paths resolve under data_dir
<component>.logging.output.rotation.strategy daily, hourly, or never daily File rotation period
<component>.logging.output.rotation.max_files positive integer 30 Files retained per component
<component>.logging.color auto, always, or never auto Component color output
Field Type / values Default Meaning
livestream.rtmp_port port 1935 RTMP ingest port
livestream.public_rtmp_host string "" Public RTMP host returned to publishers
livestream.public_webrtc_base_url HTTP(S) origin or empty "" Public WHIP origin in publish-key responses; empty returns a relative URL
livestream.gop_cache_size integer 2 Number of GOPs cached per stream
livestream.stream_timeout_seconds seconds 300 Pull-stream idle timeout
livestream.cleanup_check_interval_seconds seconds 60 Cleanup check interval
livestream.pull_max_retries integer 10 Maximum pull-stream retries
livestream.pull_initial_backoff_ms milliseconds 1000 Initial pull retry backoff
livestream.pull_max_backoff_ms milliseconds 30000 Maximum pull retry backoff
livestream.max_flv_tag_size_bytes bytes 10485760 Maximum accepted FLV tag size
livestream.gop_cache_max_memory_mb MB 100 GOP cache memory limit
livestream.hls_storage.type memory, file, shared_file, or s3 memory HLS segment storage backend
livestream.hls_storage.memory_max_mb MB 0 HLS storage limit for memory; 0 uses the built-in default
livestream.hls_storage.path path "" HLS file path for the file / shared_file backend
livestream.hls_storage.endpoint string "" S3-compatible endpoint for the s3 backend; required when s3 is enabled
livestream.hls_storage.access_key_id secret string "" Access key ID for the s3 backend; required when s3 is enabled
livestream.hls_storage.secret_access_key secret string "" Secret access key for the s3 backend; required when s3 is enabled
livestream.hls_storage.bucket string "" Bucket for the s3 backend; required when s3 is enabled
livestream.hls_storage.region string or null null Region for the s3 backend
livestream.hls_storage.base_path string hls/ Object key prefix inside the bucket
livestream.flv_max_connection_duration_seconds seconds 86400 Maximum HTTP-FLV connection duration
livestream.flv_write_timeout_seconds seconds 30 HTTP-FLV write timeout
livestream.webrtc.enabled boolean true Enable WHIP/WHEP livestream sessions
livestream.webrtc.ice_servers ICE server list [] STUN/TURN servers used by livestream PeerConnections
livestream.webrtc.ice_gathering_timeout_seconds seconds 10 Time allowed to gather local ICE candidates
livestream.webrtc.max_sdp_bytes bytes 262144 Limit for WHIP/WHEP SDP requests and upstream WHEP SDP responses
livestream.webrtc.max_sessions integer 1000 Total WHIP/WHEP session limit on one node
livestream.webrtc.max_session_duration_seconds seconds 86400 Maximum lifetime of one WHIP/WHEP session
Field Type / values Default Meaning
file_storage.default_backend backend name disabled Fallback backend used by product features
file_storage.chat_attachments_backend backend name or empty "" Backend for chat attachments; empty inherits default_backend
file_storage.user_avatars_backend backend name or empty "" Backend for user avatars; empty inherits default_backend
file_storage.media_covers_backend backend name or empty "" Backend for media covers; empty inherits default_backend
file_storage.room_covers_backend backend name or empty "" Backend for room covers; empty inherits default_backend
file_storage.playlist_covers_backend backend name or empty "" Backend for playlist covers; empty inherits default_backend
file_storage.upload_token_secret at least 32 characters "" Dedicated signing key for file upload/read tokens; required
file_storage.unreferenced_object_retention_seconds seconds 86400 Grace period before uploaded objects with no active product reference are cleaned; 0 disables orphan cleanup
file_storage.backends.<name>.type disabled, database, or s3 disabled Registered backend implementation type
file_storage.backends.<name>.compression none, lz4, or zstd zstd Compression algorithm used by type: "database" backends for persisted file_blob_parts segments
file_storage.backends.<name>.compression_min_size_bytes bytes 4096 Minimum original payload size before compression is attempted
file_storage.backends.<name>.compression_min_savings_percent 0 to 100 10 Minimum saved percentage required before compressed bytes are stored
file_storage.backends.<name>.<s3-field> S3 config default S3 fields S3-compatible settings for backends with type: "s3"; public_base_url is required for readable file URLs after upload or ownership proof validation

Upload sessions use a server-provided part plan: clients first request FileUploadPlan with empty parts, hash every planned part with SHA-256, then submit FileUploadManifestPart[]. SyncTV computes content_manifest_sha256 from the canonical manifest and uses it for instant-upload object lookup and unfinished resumable-session lookup. Database backends persist fixed file_blob_parts segments and serve HTTP Range requests directly from those segments, decompressing only the parts that overlap the requested byte range. S3 backends use native multipart uploads with presigned part URLs, sign x-amz-checksum-sha256 into each part URL, and validate object identity from the recorded part manifest at completion without reading GB-scale objects back from S3. Duplicate objects return upload_required=false with an ownership proof challenge; readable URLs are signed after proof validation and business-reference persistence.

Disable file storage:

file_storage:
default_backend: "disabled"
backends: {}

Store file bytes in PostgreSQL:

file_storage:
default_backend: "database"
chat_attachments_backend: "database"
user_avatars_backend: "database"
media_covers_backend: "database"
room_covers_backend: "database"
playlist_covers_backend: "database"
upload_token_secret_file: "/run/secrets/file_upload_token_secret"
backends:
database:
type: "database"
compression: "zstd"

Use S3-compatible object storage:

file_storage:
default_backend: "s3_public"
chat_attachments_backend: "s3_public"
user_avatars_backend: "s3_public"
media_covers_backend: "s3_public"
room_covers_backend: "s3_public"
playlist_covers_backend: "s3_public"
upload_token_secret_file: "/run/secrets/file_upload_token_secret"
backends:
s3_public:
type: "s3"
endpoint: "https://s3.example.com"
access_key_id_file: "/run/secrets/file_storage_s3_access_key_id"
secret_access_key_file: "/run/secrets/file_storage_s3_secret_access_key"
bucket: "synctv-files"
region: "auto"
base_path: "files/"
public_base_url: "https://cdn.example.com/files"
upload_expires_seconds: 900
Field Type / values Default Meaning
webauthn.enabled boolean false Enable passkey endpoints
webauthn.rp_id domain "" WebAuthn relying-party ID
webauthn.rp_origin origin "" Primary WebAuthn origin
webauthn.rp_name string SyncTV Authenticator display name
webauthn.allowed_origins origin array [] Additional accepted origins
webauthn.apple_app_ids Apple application identifier array [] Web Credentials associations for native Apple apps
webauthn.android_apps Android app association array [] Package names and signing-certificate SHA-256 fingerprints
webauthn.allow_subdomains boolean false Allow subdomains of configured origins
webauthn.allow_any_port boolean false Ignore origin ports
webauthn.timeout_seconds seconds 300 Challenge timeout
Field Type / values Default Meaning
media_providers.alist.request_timeout_seconds seconds 30 Local Alist provider request timeout
media_providers.alist.connect_timeout_seconds seconds 10 Local Alist provider connection timeout
media_providers.bilibili.request_timeout_seconds seconds 30 Local Bilibili provider request timeout
media_providers.bilibili.connect_timeout_seconds seconds 10 Local Bilibili provider connection timeout
media_providers.emby.request_timeout_seconds seconds 30 Local Emby/Jellyfin provider request timeout
media_providers.emby.connect_timeout_seconds seconds 10 Local Emby/Jellyfin provider connection timeout
webrtc.mode signaling_only or peer_to_peer peer_to_peer WebRTC operating mode
webrtc.enable_builtin_stun boolean false Enable built-in STUN
webrtc.stun_port port 3478 STUN port
webrtc.stun_host IP/listen address 0.0.0.0 STUN listen address
webrtc.stun_external_addr string "" STUN external address announced to clients
webrtc.filter_private_ice_candidates boolean false Filter private ICE candidates
Field Type / values Default Meaning
connection_limits.max_per_user integer 20 Maximum connections per user
connection_limits.max_per_room integer 2000 Maximum connections per room
connection_limits.max_total integer 100000 Maximum service-wide connections
connection_limits.idle_timeout_seconds seconds 300 Idle connection timeout
connection_limits.max_duration_seconds seconds 86400 Maximum connection lifetime
connection_limits.ws_message_rate_limit_per_second per-second count 50 WebSocket message rate per connection
bootstrap.create_root_user boolean false Create the initial root user automatically
bootstrap.root_username string root Initial root username
bootstrap.root_password secret string "" Initial root password
cluster.enabled boolean false Enable cluster mode
cluster.host IP/listen address 0.0.0.0 Dedicated internal gRPC listen address
cluster.port port 50051 Dedicated internal gRPC listen port
cluster.advertise_host hostname or IP "" Internal address advertised to peers; empty uses server.advertise_host
cluster.advertise_port port or 0 0 Internal port advertised to peers; 0 uses cluster.port
cluster.secret secret string "" Authentication secret for internal cluster gRPC
cluster.secret_file file path or empty "" File containing the internal cluster request authentication secret
cluster.critical_channel_capacity integer 10000 High-priority cluster event queue capacity
cluster.publish_channel_capacity integer 100000 Normal cluster publish queue capacity
cluster.discovery_mode redis, static, or k8s_dns redis Node discovery mode
cluster.leader_election_mode redis or k8s_lease redis Leader election mode
cluster.peers string array [] Static peer addresses
cluster.catchup_window_secs seconds 300 Redis Stream catch-up replay window
cluster.stream_max_length integer 100000 Approximate Redis Stream maximum length

password_complexity, buffer_sizes, and cache

Section titled “password_complexity, buffer_sizes, and cache”
Field Type / values Default Meaning
password_complexity.min_length integer 8 Minimum password length
password_complexity.require_uppercase boolean true Require uppercase letters
password_complexity.require_lowercase boolean true Require lowercase letters
password_complexity.require_digit boolean true Require digits
password_complexity.require_special boolean false Require special characters
password_complexity.max_repeated_chars integer 3 Maximum repeated consecutive characters; 0 disables this check
password_complexity.zxcvbn_enabled boolean false Enable zxcvbn entropy scoring for account passwords
password_complexity.zxcvbn_min_score integer 0-4 3 Minimum zxcvbn score when enabled
buffer_sizes.websocket_outbound integer 256 Per-connection WebSocket outbound queue size
buffer_sizes.audit_buffer integer 10000 Audit event buffer capacity
cache.l1_capacity integer 5000 L1 in-memory cache capacity
cache.l1_ttl_seconds seconds 300 L1 in-memory cache TTL
cache.l2_ttl_seconds seconds 300 Redis L2 cache TTL
cache.username_cache_capacity integer 10000 Username cache capacity
cache.username_cache_ttl_seconds seconds 3600 Username cache TTL
proxy_slice_cache.enabled boolean true Enable proxy slice cache at startup
proxy_slice_cache.slice_size_bytes integer 2097152 Individual Range slice size
proxy_slice_cache.max_cache_size_bytes integer 536870912 Maximum total slice cache capacity
proxy_slice_cache.segment_ttl_seconds seconds 300 Fresh slice TTL
proxy_slice_cache.stale_max_age_seconds seconds 60 Time expired slices may be served as stale
proxy_slice_cache.stale_while_revalidate boolean true Refresh expired hits in the background
proxy_slice_cache.file_backend_enabled boolean false Enable file backend for proxy slice cache
proxy_slice_cache.file_cache_dir path "" Proxy slice cache file directory
proxy_slice_cache.eviction_interval_seconds seconds 60 Background eviction check interval
proxy_slice_cache.watermark_ratio float 0.875 Target usage ratio after eviction
Field Type / values Default Meaning
messaging_rate_limits.chat_per_second integer 10 Maximum chat messages per window
messaging_rate_limits.window_seconds seconds 1 Chat rate-limit window
Field Type / values Default Meaning
request_rate_limits.auth_max_requests integer 5 Maximum authentication requests per window
request_rate_limits.auth_window_seconds seconds 60 Authentication request window
request_rate_limits.write_max_requests integer 120 Maximum write requests per window
request_rate_limits.write_window_seconds seconds 60 Write request window
request_rate_limits.read_max_requests integer 600 Maximum read requests per window
request_rate_limits.read_window_seconds seconds 60 Read request window
request_rate_limits.media_max_requests integer 120 Maximum media requests per window
request_rate_limits.media_window_seconds seconds 60 Media request window
request_rate_limits.admin_max_requests integer 180 Maximum admin requests per window
request_rate_limits.admin_window_seconds seconds 60 Admin request window
request_rate_limits.streaming_max_requests integer 1200 Maximum streaming requests per window
request_rate_limits.streaming_window_seconds seconds 60 Streaming request window
request_rate_limits.websocket_max_requests integer 60 Maximum WebSocket connection attempts per window
request_rate_limits.websocket_window_seconds seconds 60 WebSocket connection window